[SmartcardServices-Changes] [2] trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Jan 21 17:00:58 PST 2009


Revision: 2
          http://trac.macosforge.org/projects/smartcardservices/changeset/2
Author:   jhurley at apple.com
Date:     2009-01-21 17:00:58 -0800 (Wed, 21 Jan 2009)
Log Message:
-----------
initial checki

Added Paths:
-----------
    trunk/SmartCardServices/
    trunk/SmartCardServices/APPLE_LICENSE
    trunk/SmartCardServices/Makefile.installPhase
    trunk/SmartCardServices/SmartCardServices.xcodeproj/
    trunk/SmartCardServices/SmartCardServices.xcodeproj/john.mode1v3
    trunk/SmartCardServices/SmartCardServices.xcodeproj/john.pbxuser
    trunk/SmartCardServices/SmartCardServices.xcodeproj/project.pbxproj
    trunk/SmartCardServices/installPhase/
    trunk/SmartCardServices/installPhase/Extensions/
    trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/
    trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/
    trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/Info.plist
    trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/MacOS/
    trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/MacOS/CM4040
    trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/
    trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/
    trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Info.plist
    trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/MacOS/
    trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/MacOS/CRYPTOCardPCCard
    trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Resources/
    trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Resources/English.lproj/
    trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Resources/English.lproj/InfoPlist.strings
    trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/
    trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/
    trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Info.plist
    trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/MacOS/
    trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/MacOS/SCR24X_Apple_Driver
    trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Resources/
    trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Resources/English.lproj/
    trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Resources/English.lproj/InfoPlist.strings
    trunk/SmartCardServices/installPhase/PKCS11/
    trunk/SmartCardServices/installPhase/PKCS11/pkcs11.shlb
    trunk/SmartCardServices/installPhase/drivers/
    trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/
    trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/
    trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/Info.plist
    trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/MacOS/
    trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/MacOS/CC-PC-Card
    trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/
    trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/
    trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/Info.plist
    trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/MacOS/
    trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/MacOS/SCR24XHndlr
    trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/
    trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/
    trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/Info.plist
    trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/MacOS/
    trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/MacOS/ifd-ASEIIIeUSB
    trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/
    trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/
    trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/Info.plist
    trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/MacOS/
    trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/MacOS/ifdok_cm4040_macos-2.0.0.dylib
    trunk/SmartCardServices/installPhase/man/
    trunk/SmartCardServices/installPhase/man/pcscd.8
    trunk/SmartCardServices/installPhase/man/pcsctest.8
    trunk/SmartCardServices/installPhase/man/pcsctool.8
    trunk/SmartCardServices/installPhase/man/sc_auth.8
    trunk/SmartCardServices/installPhase/scripts/
    trunk/SmartCardServices/installPhase/scripts/sc_auth
    trunk/SmartCardServices/pbx/
    trunk/SmartCardServices/pbx/config.h
    trunk/SmartCardServices/src/
    trunk/SmartCardServices/src/CACPlugin/
    trunk/SmartCardServices/src/CACPlugin/commonAccessCard.c
    trunk/SmartCardServices/src/CACPlugin/commonAccessCard.h
    trunk/SmartCardServices/src/CCIDDriver/
    trunk/SmartCardServices/src/CCIDDriver/USB/
    trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/
    trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/usbserial_mosx.c
    trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/usbserial_mosx.h
    trunk/SmartCardServices/src/CCIDDriver/USB/usbserial.h
    trunk/SmartCardServices/src/CCIDDriver/common/
    trunk/SmartCardServices/src/CCIDDriver/common/CCID.c
    trunk/SmartCardServices/src/CCIDDriver/common/CCID.h
    trunk/SmartCardServices/src/CCIDDriver/common/CCIDPropExt.c
    trunk/SmartCardServices/src/CCIDDriver/common/CCIDPropExt.h
    trunk/SmartCardServices/src/CCIDDriver/common/CCIDprivate.h
    trunk/SmartCardServices/src/CCIDDriver/common/Transport.c
    trunk/SmartCardServices/src/CCIDDriver/common/Transport.h
    trunk/SmartCardServices/src/CCIDDriver/common/global.h
    trunk/SmartCardServices/src/CCIDDriver/common/ifdhandler.c
    trunk/SmartCardServices/src/CCIDDriver/common/ifdhandler.h
    trunk/SmartCardServices/src/CCIDDriver/common/pcscdefines.h
    trunk/SmartCardServices/src/CCIDDriver/common/tools.c
    trunk/SmartCardServices/src/CCIDDriver/common/tools.h
    trunk/SmartCardServices/src/CCIDDriver/specific/
    trunk/SmartCardServices/src/CCIDDriver/specific/MacOSX/
    trunk/SmartCardServices/src/CCIDDriver/specific/MacOSX/tools_mosx.c
    trunk/SmartCardServices/src/CFlexPlugin/
    trunk/SmartCardServices/src/CFlexPlugin/cryptoflex.c
    trunk/SmartCardServices/src/CFlexPlugin/cryptoflex.h
    trunk/SmartCardServices/src/GSCISPlugin/
    trunk/SmartCardServices/src/GSCISPlugin/GSCISPlugin.c
    trunk/SmartCardServices/src/GSCISPlugin/GSCISPlugin.h
    trunk/SmartCardServices/src/MCardPlugin/
    trunk/SmartCardServices/src/MCardPlugin/musclecardApplet.c
    trunk/SmartCardServices/src/MCardPlugin/musclecardApplet.h
    trunk/SmartCardServices/src/PCSC/
    trunk/SmartCardServices/src/PCSC/PCSC.exp
    trunk/SmartCardServices/src/PCSC/PCSCDevice.cpp
    trunk/SmartCardServices/src/PCSC/PCSCDevice.h
    trunk/SmartCardServices/src/PCSC/PCSCDriverBundle.cpp
    trunk/SmartCardServices/src/PCSC/PCSCDriverBundle.h
    trunk/SmartCardServices/src/PCSC/PCSCDriverBundles.cpp
    trunk/SmartCardServices/src/PCSC/PCSCDriverBundles.h
    trunk/SmartCardServices/src/PCSC/atrhandler.c
    trunk/SmartCardServices/src/PCSC/atrhandler.h
    trunk/SmartCardServices/src/PCSC/config.h
    trunk/SmartCardServices/src/PCSC/configfile.c
    trunk/SmartCardServices/src/PCSC/configfile.h
    trunk/SmartCardServices/src/PCSC/configfile.l
    trunk/SmartCardServices/src/PCSC/debug.c
    trunk/SmartCardServices/src/PCSC/debug.h
    trunk/SmartCardServices/src/PCSC/debuglog.c
    trunk/SmartCardServices/src/PCSC/debuglog.h
    trunk/SmartCardServices/src/PCSC/driverparser.c
    trunk/SmartCardServices/src/PCSC/driverparser.l
    trunk/SmartCardServices/src/PCSC/dyn_generic.h
    trunk/SmartCardServices/src/PCSC/dyn_macosx.c
    trunk/SmartCardServices/src/PCSC/eventhandler.c
    trunk/SmartCardServices/src/PCSC/eventhandler.cpp
    trunk/SmartCardServices/src/PCSC/eventhandler.h
    trunk/SmartCardServices/src/PCSC/hotplug.h
    trunk/SmartCardServices/src/PCSC/hotplug_macosx.c
    trunk/SmartCardServices/src/PCSC/hotplug_macosx.cpp
    trunk/SmartCardServices/src/PCSC/ifdhandler.h
    trunk/SmartCardServices/src/PCSC/ifdwrapper.c
    trunk/SmartCardServices/src/PCSC/ifdwrapper.h
    trunk/SmartCardServices/src/PCSC/mscdefines.h
    trunk/SmartCardServices/src/PCSC/musclecard.c
    trunk/SmartCardServices/src/PCSC/musclecard.h
    trunk/SmartCardServices/src/PCSC/muscletest.c
    trunk/SmartCardServices/src/PCSC/pcscdaemon.c
    trunk/SmartCardServices/src/PCSC/pcscdmonitor.cpp
    trunk/SmartCardServices/src/PCSC/pcscdmonitor.h
    trunk/SmartCardServices/src/PCSC/pcscdserver.cpp
    trunk/SmartCardServices/src/PCSC/pcscdserver.h
    trunk/SmartCardServices/src/PCSC/pcscexport.h
    trunk/SmartCardServices/src/PCSC/pcsclite.h
    trunk/SmartCardServices/src/PCSC/powermgt_generic.h
    trunk/SmartCardServices/src/PCSC/powermgt_macosx.c
    trunk/SmartCardServices/src/PCSC/prothandler.c
    trunk/SmartCardServices/src/PCSC/prothandler.h
    trunk/SmartCardServices/src/PCSC/reader.cpp
    trunk/SmartCardServices/src/PCSC/reader.h
    trunk/SmartCardServices/src/PCSC/readerfactory.c
    trunk/SmartCardServices/src/PCSC/readerfactory.h
    trunk/SmartCardServices/src/PCSC/readerstate.cpp
    trunk/SmartCardServices/src/PCSC/readerstate.h
    trunk/SmartCardServices/src/PCSC/sys_generic.h
    trunk/SmartCardServices/src/PCSC/sys_macosx.cpp
    trunk/SmartCardServices/src/PCSC/sys_unix.c
    trunk/SmartCardServices/src/PCSC/testpcsc.c
    trunk/SmartCardServices/src/PCSC/thread_generic.h
    trunk/SmartCardServices/src/PCSC/thread_macosx.c
    trunk/SmartCardServices/src/PCSC/tokenfactory.c
    trunk/SmartCardServices/src/PCSC/tokenfactory.h
    trunk/SmartCardServices/src/PCSC/tokenparser.c
    trunk/SmartCardServices/src/PCSC/tokenparser.l
    trunk/SmartCardServices/src/PCSC/utils/
    trunk/SmartCardServices/src/PCSC/utils/bundleTool.c
    trunk/SmartCardServices/src/PCSC/winscard.c
    trunk/SmartCardServices/src/PCSC/winscard.h
    trunk/SmartCardServices/src/PCSC/winscard_clnt.c
    trunk/SmartCardServices/src/PCSC/winscard_msg.c
    trunk/SmartCardServices/src/PCSC/winscard_msg.cpp
    trunk/SmartCardServices/src/PCSC/winscard_msg.h
    trunk/SmartCardServices/src/PCSC/winscard_msg_srv.c
    trunk/SmartCardServices/src/PCSC/winscard_svc.c
    trunk/SmartCardServices/src/PCSC/winscard_svc.h
    trunk/SmartCardServices/src/PCSC/wintypes.h
    trunk/SmartCardServices/src/PCSC/xiodevices.cpp
    trunk/SmartCardServices/src/PCSC/xiodevices.h
    trunk/SmartCardServices/src/PKCS11/
    trunk/SmartCardServices/src/PKCS11/cryptoki.h
    trunk/SmartCardServices/src/PKCS11/cryptoki_unix.h
    trunk/SmartCardServices/src/PKCS11/cryptoki_win32.h
    trunk/SmartCardServices/src/PKCS11/p11_crypt.c
    trunk/SmartCardServices/src/PKCS11/p11_digest.c
    trunk/SmartCardServices/src/PKCS11/p11_dual.c
    trunk/SmartCardServices/src/PKCS11/p11_ext.c
    trunk/SmartCardServices/src/PKCS11/p11_general.c
    trunk/SmartCardServices/src/PKCS11/p11_key.c
    trunk/SmartCardServices/src/PKCS11/p11_object.c
    trunk/SmartCardServices/src/PKCS11/p11_parallel.c
    trunk/SmartCardServices/src/PKCS11/p11_random.c
    trunk/SmartCardServices/src/PKCS11/p11_session.c
    trunk/SmartCardServices/src/PKCS11/p11_sign.c
    trunk/SmartCardServices/src/PKCS11/p11_token.c
    trunk/SmartCardServices/src/PKCS11/p11_verify.c
    trunk/SmartCardServices/src/PKCS11/p11x_async.c
    trunk/SmartCardServices/src/PKCS11/p11x_bio.c
    trunk/SmartCardServices/src/PKCS11/p11x_error.c
    trunk/SmartCardServices/src/PKCS11/p11x_log.c
    trunk/SmartCardServices/src/PKCS11/p11x_msc.c
    trunk/SmartCardServices/src/PKCS11/p11x_msc.h
    trunk/SmartCardServices/src/PKCS11/p11x_object.c
    trunk/SmartCardServices/src/PKCS11/p11x_prefs.c
    trunk/SmartCardServices/src/PKCS11/p11x_session.c
    trunk/SmartCardServices/src/PKCS11/p11x_slot.c
    trunk/SmartCardServices/src/PKCS11/p11x_state.c
    trunk/SmartCardServices/src/PKCS11/p11x_thread.c
    trunk/SmartCardServices/src/PKCS11/p11x_unixdll.c
    trunk/SmartCardServices/src/PKCS11/p11x_util.c
    trunk/SmartCardServices/src/PKCS11/p11x_win32dll.c
    trunk/SmartCardServices/src/PKCS11/pkcs11.h
    trunk/SmartCardServices/src/PKCS11/pkcs11f.h
    trunk/SmartCardServices/src/PKCS11/pkcs11t.h
    trunk/SmartCardServices/src/PKCS11/thread_generic.h

Added: trunk/SmartCardServices/APPLE_LICENSE
===================================================================
--- trunk/SmartCardServices/APPLE_LICENSE	                        (rev 0)
+++ trunk/SmartCardServices/APPLE_LICENSE	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,372 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 1.1 - April 19,1999
+
+Please read this License carefully before downloading this software.
+By downloading and using this software, you are agreeing to be bound
+by the terms of this License.  If you do not or cannot agree to the
+terms of this License, please do not download or use the software.
+
+1. General; Definitions.  This License applies to any program or other
+work which Apple Computer, Inc. ("Apple") publicly announces as
+subject to this Apple Public Source License and which contains a
+notice placed by Apple identifying such program or work as "Original
+Code" and stating that it is subject to the terms of this Apple Public
+Source License version 1.1 (or subsequent version thereof), as it may
+be revised from time to time by Apple ("License").  As used in this
+License:
+
+1.1 "Affected Original Code" means only those specific portions of
+Original Code that allegedly infringe upon any party's intellectual
+property rights or are otherwise the subject of a claim of
+infringement.
+
+1.2 "Applicable Patent Rights" mean: (a) in the case where Apple is
+the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to Apple and (ii) that cover subject
+matter contained in the Original Code, but only to the extent
+necessary to use, reproduce and/or distribute the Original Code
+without infringement; and (b) in the case where You are the grantor of
+rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to You and (ii) that cover subject matter in Your
+Modifications, taken alone or in combination with Original Code.
+
+1.3 "Covered Code" means the Original Code, Modifications, the
+combination of Original Code and any Modifications, and/or any
+respective portions thereof.
+
+1.4 "Deploy" means to use, sublicense or distribute Covered Code other
+than for Your internal research and development (R&D), and includes
+without limitation, any and all internal use or distribution of
+Covered Code within Your business or organization except for R&D use,
+as well as direct or indirect sublicensing or distribution of Covered
+Code by You to any third party in any form or manner.
+
+1.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "Modifications" mean any addition to, deletion from, and/or change
+to, the substance and/or structure of Covered Code.  When code is
+released as a series of files, a Modification is: (a) any addition to
+or deletion from the contents of a file containing Covered Code;
+and/or (b) any new file or other representation of computer program
+statements that contains any part of Covered Code.
+
+1.7 "Original Code" means (a) the Source Code of a program or other
+work as originally made available by Apple under this License,
+including the Source Code of any updates or upgrades to such programs
+or works made available by Apple under this License, and that has been
+expressly identified by Apple as such in the header file(s) of such
+work; and (b) the object code compiled from such Source Code and
+originally made available by Apple under this License.
+
+1.8 "Source Code" means the human readable form of a program or other
+work that is suitable for making modifications to it, including all
+modules it contains, plus any associated interface definition files,
+scripts used to control compilation and installation of an executable
+(object code).
+
+1.9 "You" or "Your" means an individual or a legal entity exercising
+rights under this License.  For legal entities, "You" or "Your"
+includes any entity which controls, is controlled by, or is under
+common control with, You, where "control" means (a) the power, direct
+or indirect, to cause the direction or management of such entity,
+whether by contract or otherwise, or (b) ownership of fifty percent
+(50%) or more of the outstanding shares or beneficial ownership of
+such entity.
+
+2. Permitted Uses; Conditions & Restrictions.  Subject to the terms
+and conditions of this License, Apple hereby grants You, effective on
+the date You accept this License and download the Original Code, a
+world-wide, royalty-free, non- exclusive license, to the extent of
+Apple's Applicable Patent Rights and copyrights covering the Original
+Code, to do the following:
+
+2.1 You may use, copy, modify and distribute Original Code, with or
+without Modifications, solely for Your internal research and
+development, provided that You must in each instance:
+
+(a) retain and reproduce in all copies of Original Code the copyright
+and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code
+that refer to this License;
+
+(b) include a copy of this License with every copy of Source Code of
+Covered Code and documentation You distribute, and You may not offer
+or impose any terms on such Source Code that alter or restrict this
+License or the recipients' rights hereunder, except as permitted under
+Section 6; and
+
+(c) completely and accurately document all Modifications that you have
+made and the date of each such Modification, designate the version of
+the Original Code you used, prominently include a file carrying such
+information with the Modifications, and duplicate the notice in
+Exhibit A in each file of the Source Code of all such Modifications.
+
+2.2 You may Deploy Covered Code, provided that You must in each
+  instance:
+
+(a) satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) make all Your Deployed Modifications publicly available in Source
+Code form via electronic distribution (e.g. download from a web site)
+under the terms of this License and subject to the license grants set
+forth in Section 3 below, and any additional terms You may choose to
+offer under Section 6.  You must continue to make the Source Code of
+Your Deployed Modifications available for as long as you Deploy the
+Covered Code or twelve (12) months from the date of initial
+Deployment, whichever is longer;
+
+(c) if You Deploy Covered Code containing Modifications made by You,
+inform others of how to obtain those Modifications by filling out and
+submitting the information found at
+http://www.apple.com/publicsource/modifications.html, if available;
+and
+
+(d) if You Deploy Covered Code in object code, executable form only,
+include a prominent notice, in the code itself as well as in related
+documentation, stating that Source Code of the Covered Code is
+available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+3. Your Grants.  In consideration of, and as a condition to, the
+licenses granted to You under this License:
+
+(a) You hereby grant to Apple and all third parties a non-exclusive,
+royalty-free license, under Your Applicable Patent Rights and other
+intellectual property rights owned or controlled by You, to use,
+reproduce, modify, distribute and Deploy Your Modifications of the
+same scope and extent as Apple's licenses under Sections 2.1 and 2.2;
+and
+
+(b) You hereby grant to Apple and its subsidiaries a non-exclusive,
+worldwide, royalty-free, perpetual and irrevocable license, under Your
+Applicable Patent Rights and other intellectual property rights owned
+or controlled by You, to use, reproduce, execute, compile, display,
+perform, modify or have modified (for Apple and/or its subsidiaries),
+sublicense and distribute Your Modifications, in any form, through
+multiple tiers of distribution.
+
+4. Larger Works.  You may create a Larger Work by combining Covered
+Code with other code not governed by the terms of this License and
+distribute the Larger Work as a single product.  In each such
+instance, You must make sure the requirements of this License are
+fulfilled for the Covered Code or any portion thereof.
+
+5. Limitations on Patent License.  Except as expressly stated in
+Section 2, no other patent rights, express or implied, are granted by
+Apple herein.  Modifications and/or Larger Works may require
+additional patent licenses from Apple which Apple may grant in its
+sole discretion.
+
+6. Additional Terms.  You may choose to offer, and to charge a fee
+for, warranty, support, indemnity or liability obligations and/or
+other rights consistent with the scope of the license granted herein
+("Additional Terms") to one or more recipients of Covered
+Code. However, You may do so only on Your own behalf and as Your sole
+responsibility, and not on behalf of Apple. You must obtain the
+recipient's agreement that any such Additional Terms are offered by
+You alone, and You hereby agree to indemnify, defend and hold Apple
+harmless for any liability incurred by or claims asserted against
+Apple by reason of any such Additional Terms.
+
+7. Versions of the License.  Apple may publish revised and/or new
+versions of this License from time to time.  Each version will be
+given a distinguishing version number.  Once Original Code has been
+published under a particular version of this License, You may continue
+to use it under the terms of that version. You may also choose to use
+such Original Code under the terms of any subsequent version of this
+License published by Apple.  No one other than Apple has the right to
+modify the terms applicable to Covered Code created under this
+License.
+
+8. NO WARRANTY OR SUPPORT.  The Original Code may contain in whole or
+in part pre-release, untested, or not fully tested works.  The
+Original Code may contain errors that could cause failures or loss of
+data, and may be incomplete or contain inaccuracies.  You expressly
+acknowledge and agree that use of the Original Code, or any portion
+thereof, is at Your sole and entire risk.  THE ORIGINAL CODE IS
+PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND
+AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF SECTIONS 8 AND
+9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY REFERRED TO AS
+"APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+AND/OR CONDITIONS OF MERCHANTABILITY OR SATISFACTORY QUALITY AND
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+RIGHTS.  APPLE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE
+ORIGINAL CODE WILL MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF
+THE ORIGINAL CODE WILL BE UNINTERRUPTED OR ERROR- FREE, OR THAT
+DEFECTS IN THE ORIGINAL CODE WILL BE CORRECTED.  NO ORAL OR WRITTEN
+INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED
+REPRESENTATIVE SHALL CREATE A WARRANTY OR IN ANY WAY INCREASE THE
+SCOPE OF THIS WARRANTY.  You acknowledge that the Original Code is not
+intended for use in the operation of nuclear facilities, aircraft
+navigation, communication systems, or air traffic control machines in
+which case the failure of the Original Code could lead to death,
+personal injury, or severe physical or environmental damage.
+
+9. Liability.
+
+9.1 Infringement.  If any portion of, or functionality implemented by,
+the Original Code becomes the subject of a claim of infringement,
+Apple may, at its option: (a) attempt to procure the rights necessary
+for Apple and You to continue using the Affected Original Code; (b)
+modify the Affected Original Code so that it is no longer infringing;
+or (c) suspend Your rights to use, reproduce, modify, sublicense and
+distribute the Affected Original Code until a final determination of
+the claim is made by a court or governmental administrative agency of
+competent jurisdiction and Apple lifts the suspension as set forth
+below.  Such suspension of rights will be effective immediately upon
+Apple's posting of a notice to such effect on the Apple web site that
+is used for implementation of this License.  Upon such final
+determination being made, if Apple is legally able, without the
+payment of a fee or royalty, to resume use, reproduction,
+modification, sublicensing and distribution of the Affected Original
+Code, Apple will lift the suspension of rights to the Affected
+Original Code by posting a notice to such effect on the Apple web site
+that is used for implementation of this License.  If Apple suspends
+Your rights to Affected Original Code, nothing in this License shall
+be construed to restrict You, at Your option and subject to applicable
+law, from replacing the Affected Original Code with non-infringing
+code or independently negotiating for necessary rights from such third
+party.
+
+9.2 LIMITATION OF LIABILITY.  UNDER NO CIRCUMSTANCES SHALL APPLE BE
+LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR INABILITY TO
+USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER UNDER A THEORY
+OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY
+OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF
+ANY REMEDY.  In no event shall Apple's total liability to You for all
+damages under this License exceed the amount of fifty dollars
+($50.00).
+
+10. Trademarks.  This License does not grant any rights to use the
+trademarks or trade names "Apple", "Apple Computer", "Mac OS X", "Mac
+OS X Server" or any other trademarks or trade names belonging to Apple
+(collectively "Apple Marks") and no Apple Marks may be used to endorse
+or promote products derived from the Original Code other than as
+permitted by and in strict compliance at all times with Apple's third
+party trademark usage guidelines which are posted at
+http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership.  Apple retains all rights, title and interest in and to
+the Original Code and any Modifications made by or on behalf of Apple
+("Apple Modifications"), and such Apple Modifications will not be
+automatically subject to this License.  Apple may, at its sole
+discretion, choose to license such Apple Modifications under this
+License, or on different terms from those contained in this License or
+may choose not to license them at all.  Apple's development, use,
+reproduction, modification, sublicensing and distribution of Covered
+Code will not be subject to this License.
+
+12. Termination.
+
+12.1 Termination.  This License and the rights granted hereunder will
+   terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach; (b) immediately in the event of
+the circumstances described in Section 13.5(b); or (c) automatically
+without notice from Apple if You, at any time during the term of this
+License, commence an action for patent infringement against Apple.
+
+12.2 Effect of Termination.  Upon termination, You agree to
+immediately stop any further use, reproduction, modification,
+sublicensing and distribution of the Covered Code and to destroy all
+copies of the Covered Code that are in your possession or control.
+All sublicenses to the Covered Code which have been properly granted
+prior to termination shall survive any termination of this License.
+Provisions which, by their nature, should remain in effect beyond the
+termination of this License shall survive, including but not limited
+to Sections 3, 5, 8, 9, 10, 11, 12.2 and 13.  Neither party will be
+liable to the other for compensation, indemnity or damages of any sort
+solely as a result of terminating this License in accordance with its
+terms, and termination of this License will be without prejudice to
+any other right or remedy of either party.
+
+13.  Miscellaneous.
+
+13.1 Government End Users.  The Covered Code is a "commercial item" as
+defined in FAR 2.101.  Government software and technical data rights
+in the Covered Code include only those rights customarily provided to
+the public as defined in this License. This customary commercial
+license in technical data and software is provided in accordance with
+FAR 12.211 (Technical Data) and 12.212 (Computer Software) and, for
+Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
+Commercial Items) and 227.7202-3 (Rights in Commercial Computer
+Software or Computer Software Documentation).  Accordingly, all U.S.
+Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2 Relationship of Parties.  This License will not be construed as
+creating an agency, partnership, joint venture or any other form of
+legal association between You and Apple, and You will not represent to
+the contrary, whether expressly, by implication, appearance or
+otherwise.
+
+13.3 Independent Development.  Nothing in this License will impair
+Apple's right to acquire, license, develop, have others develop for
+it, market and/or distribute technology or products that perform the
+same or similar functions as, or otherwise compete with,
+Modifications, Larger Works, technology or products that You may
+develop, produce, market or distribute.
+
+13.4 Waiver; Construction.  Failure by Apple to enforce any provision
+of this License will not be deemed a waiver of future enforcement of
+that or any other provision.  Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+will not apply to this License.
+
+13.5 Severability.  (a) If for any reason a court of competent
+jurisdiction finds any provision of this License, or portion thereof,
+to be unenforceable, that provision of the License will be enforced to
+the maximum extent permissible so as to effect the economic benefits
+and intent of the parties, and the remainder of this License will
+continue in full force and effect.  (b) Notwithstanding the foregoing,
+if applicable law prohibits or restricts You from fully and/or
+specifically complying with Sections 2 and/or 3 or prevents the
+enforceability of either of those Sections, this License will
+immediately terminate and You must immediately discontinue any use of
+the Covered Code and destroy all copies of it that are in your
+possession or control.
+
+13.6 Dispute Resolution.  Any litigation or other dispute resolution
+between You and Apple relating to this License shall take place in the
+Northern District of California, and You and Apple hereby consent to
+the personal jurisdiction of, and venue in, the state and federal
+courts within that District with respect to this License. The
+application of the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded.
+
+13.7 Entire Agreement; Governing Law.  This License constitutes the
+entire agreement between the parties with respect to the subject
+matter hereof.  This License shall be governed by the laws of the
+United States and the State of California, except that body of
+California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999-2000 Apple Computer, Inc.  All Rights
+Reserved.  This file contains Original Code and/or Modifications of
+Original Code as defined in and that are subject to the Apple Public
+Source License Version 1.1 (the "License").  You may not use this file
+except in compliance with the License.  Please obtain a copy of the
+License at http://www.apple.com/publicsource and read it before using
+this file.
+
+The Original Code and all software distributed under the License are
+distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
+License for the specific language governing rights and limitations
+under the License."

Added: trunk/SmartCardServices/Makefile.installPhase
===================================================================
--- trunk/SmartCardServices/Makefile.installPhase	                        (rev 0)
+++ trunk/SmartCardServices/Makefile.installPhase	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,83 @@
+# The other phases do nothing
+
+MAN_DIR=$(DSTROOT)/usr/share/man/man8
+PCSCDIR=$(DSTROOT)/usr/libexec/SmartCardServices
+PKCS11_DIR=$(DSTROOT)/Library/Application\ Support/Mozilla/
+EXTENSIONS_DIR=$(DSTROOT)/System/Library/Extensions
+SCRIPTS_LOCATION=$(DSTROOT)/usr/sbin
+
+build:
+	@echo null build.
+
+debug:
+	@echo null debug.
+
+profile:
+	@echo null profile.
+
+install:
+	mkdir -p $(PCSCDIR)
+	mkdir -p $(PCSCDIR)/drivers
+	mkdir -p $(PCSCDIR)/services
+	chmod 755 $(PCSCDIR)
+	cp -r installPhase/drivers/*.bundle $(PCSCDIR)/drivers/
+	-rm -rf $(PCSCDIR)/drivers/*.bundle/CVS
+	-rm -rf $(PCSCDIR)/drivers/*.bundle/Contents/CVS
+	-rm -rf $(PCSCDIR)/drivers/*.bundle/Contents/MacOS/CVS
+	chmod 755 $(PCSCDIR)/drivers/*.bundle
+	chmod 755 $(PCSCDIR)/drivers/*.bundle/Contents
+	chmod 755 $(PCSCDIR)/drivers/*.bundle/Contents/MacOS
+	chmod 644 $(PCSCDIR)/drivers/*.bundle/Contents/*.*
+	chmod 644 $(PCSCDIR)/drivers/*.bundle/Contents/MacOS/*
+	/usr/bin/strip -S $(PCSCDIR)/drivers/*.bundle/Contents/MacOS/*
+	mkdir -p $(EXTENSIONS_DIR)
+	chmod 755 $(DSTROOT)/System
+	chmod 755 $(DSTROOT)/System/Library
+	chmod 755 $(EXTENSIONS_DIR)
+	cp -r installPhase/Extensions/*.kext $(EXTENSIONS_DIR)/
+	-rm -rf $(EXTENSIONS_DIR)/*.kext/CVS
+	-rm -rf $(EXTENSIONS_DIR)/*.kext/Contents/CVS
+	-rm -rf $(EXTENSIONS_DIR)/*.kext/Contents/MacOS/CVS
+	-rm -rf $(EXTENSIONS_DIR)/*.kext/Contents/Resources/CVS
+	-rm -rf $(EXTENSIONS_DIR)/*.kext/Contents/Resources/*.lproj/CVS
+	chmod 755 $(EXTENSIONS_DIR)/*.kext
+	chmod 755 $(EXTENSIONS_DIR)/*.kext/Contents
+	chmod 755 $(EXTENSIONS_DIR)/*.kext/Contents/MacOS
+	-chmod 755 $(EXTENSIONS_DIR)/*.kext/Contents/Resources
+	-chmod 755 $(EXTENSIONS_DIR)/*.kext/Contents/Resources/*.lproj
+	chmod 644 $(EXTENSIONS_DIR)/*.kext/Contents/*.*
+	chmod 644 $(EXTENSIONS_DIR)/*.kext/Contents/MacOS/*
+	-chmod 644 $(EXTENSIONS_DIR)/*.kext/Contents/Resources/*.lproj/*.*
+	/usr/bin/strip -S $(EXTENSIONS_DIR)/*.kext/Contents/MacOS/*
+
+	mkdir -p $(SCRIPTS_LOCATION)
+
+	cp installPhase/scripts/sc_auth $(SCRIPTS_LOCATION)
+	chown root:admin $(SCRIPTS_LOCATION)/sc_auth
+	chmod 755 $(SCRIPTS_LOCATION)/sc_auth
+
+# Copy over man pages
+
+	mkdir -p $(MAN_DIR)
+	cp installPhase/man/pcscd.8 $(MAN_DIR)
+	cp installPhase/man/pcsctool.8 $(MAN_DIR)
+	cp installPhase/man/pcsctest.8 $(MAN_DIR)
+	cp installPhase/man/sc_auth.8 $(MAN_DIR)
+	chown root:wheel $(MAN_DIR)/sc_auth.8
+
+# Deleting CVS subdirectories from the copy phase
+
+	rm -rf `find $(PCSCDIR)/drivers -name CVS`
+
+	mkdir -p $(PKCS11_DIR)
+	cp installPhase/PKCS11/pkcs11.shlb $(PKCS11_DIR)
+	chmod 755 $(PKCS11_DIR)/pkcs11.shlb
+
+installhdrs:
+	@echo null installhdrs.
+
+installsrc:
+	@echo null installsrc.
+
+clean:
+	@echo null clean.  

Added: trunk/SmartCardServices/SmartCardServices.xcodeproj/john.mode1v3
===================================================================
--- trunk/SmartCardServices/SmartCardServices.xcodeproj/john.mode1v3	                        (rev 0)
+++ trunk/SmartCardServices/SmartCardServices.xcodeproj/john.mode1v3	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1379 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>ActivePerspectiveName</key>
+	<string>Project</string>
+	<key>AllowedModules</key>
+	<array>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXSmartGroupTreeModule</string>
+			<key>Name</key>
+			<string>Groups and Files Outline View</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXNavigatorGroup</string>
+			<key>Name</key>
+			<string>Editor</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCTaskListModule</string>
+			<key>Name</key>
+			<string>Task List</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCDetailModule</string>
+			<key>Name</key>
+			<string>File and Smart Group Detail Viewer</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>1</string>
+			<key>Module</key>
+			<string>PBXBuildResultsModule</string>
+			<key>Name</key>
+			<string>Detailed Build Results Viewer</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>1</string>
+			<key>Module</key>
+			<string>PBXProjectFindModule</string>
+			<key>Name</key>
+			<string>Project Batch Find Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCProjectFormatConflictsModule</string>
+			<key>Name</key>
+			<string>Project Format Conflicts List</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXBookmarksModule</string>
+			<key>Name</key>
+			<string>Bookmarks Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXClassBrowserModule</string>
+			<key>Name</key>
+			<string>Class Browser</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXCVSModule</string>
+			<key>Name</key>
+			<string>Source Code Control Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXDebugBreakpointsModule</string>
+			<key>Name</key>
+			<string>Debug Breakpoints Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCDockableInspector</string>
+			<key>Name</key>
+			<string>Inspector</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXOpenQuicklyModule</string>
+			<key>Name</key>
+			<string>Open Quickly Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>1</string>
+			<key>Module</key>
+			<string>PBXDebugSessionModule</string>
+			<key>Name</key>
+			<string>Debugger</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>1</string>
+			<key>Module</key>
+			<string>PBXDebugCLIModule</string>
+			<key>Name</key>
+			<string>Debug Console</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCSnapshotModule</string>
+			<key>Name</key>
+			<string>Snapshots Tool</string>
+		</dict>
+	</array>
+	<key>BundlePath</key>
+	<string>/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources</string>
+	<key>Description</key>
+	<string>DefaultDescriptionKey</string>
+	<key>DockingSystemVisible</key>
+	<false/>
+	<key>Extension</key>
+	<string>mode1v3</string>
+	<key>FavBarConfig</key>
+	<dict>
+		<key>PBXProjectModuleGUID</key>
+		<string>5221F1A10DE4EAF6001E0235</string>
+		<key>XCBarModuleItemNames</key>
+		<dict/>
+		<key>XCBarModuleItems</key>
+		<array/>
+	</dict>
+	<key>FirstTimeWindowDisplayed</key>
+	<false/>
+	<key>Identifier</key>
+	<string>com.apple.perspectives.project.mode1v3</string>
+	<key>MajorVersion</key>
+	<integer>33</integer>
+	<key>MinorVersion</key>
+	<integer>0</integer>
+	<key>Name</key>
+	<string>Default</string>
+	<key>Notifications</key>
+	<array>
+		<dict>
+			<key>XCObserverAutoDisconnectKey</key>
+			<true/>
+			<key>XCObserverDefintionKey</key>
+			<dict/>
+			<key>XCObserverFactoryKey</key>
+			<string>XCPerspectivesSpecificationIdentifier</string>
+			<key>XCObserverGUIDKey</key>
+			<string>XCObserverProjectIdentifier</string>
+			<key>XCObserverNotificationKey</key>
+			<string>PBXStatusBuildStateMessageNotification</string>
+			<key>XCObserverTargetKey</key>
+			<string>XCMainBuildResultsModuleGUID</string>
+			<key>XCObserverTriggerKey</key>
+			<string>awakenModuleWithObserver:</string>
+			<key>XCObserverValidationKey</key>
+			<dict/>
+		</dict>
+	</array>
+	<key>OpenEditors</key>
+	<array/>
+	<key>PerspectiveWidths</key>
+	<array>
+		<integer>-1</integer>
+		<integer>-1</integer>
+	</array>
+	<key>Perspectives</key>
+	<array>
+		<dict>
+			<key>ChosenToolbarItems</key>
+			<array>
+				<string>active-target-popup</string>
+				<string>active-buildstyle-popup</string>
+				<string>action</string>
+				<string>NSToolbarFlexibleSpaceItem</string>
+				<string>buildOrClean</string>
+				<string>build-and-goOrGo</string>
+				<string>com.apple.ide.PBXToolbarStopButton</string>
+				<string>get-info</string>
+				<string>toggle-editor</string>
+				<string>NSToolbarFlexibleSpaceItem</string>
+				<string>com.apple.pbx.toolbar.searchfield</string>
+			</array>
+			<key>ControllerClassBaseName</key>
+			<string></string>
+			<key>IconName</key>
+			<string>WindowOfProjectWithEditor</string>
+			<key>Identifier</key>
+			<string>perspective.project</string>
+			<key>IsVertical</key>
+			<false/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>BecomeActive</key>
+					<true/>
+					<key>ContentConfiguration</key>
+					<dict>
+						<key>PBXBottomSmartGroupGIDs</key>
+						<array>
+							<string>1C37FBAC04509CD000000102</string>
+							<string>1C37FAAC04509CD000000102</string>
+							<string>1C08E77C0454961000C914BD</string>
+							<string>1C37FABC05509CD000000102</string>
+							<string>1C37FABC05539CD112110102</string>
+							<string>E2644B35053B69B200211256</string>
+							<string>1C37FABC04509CD000100104</string>
+							<string>1CC0EA4004350EF90044410B</string>
+							<string>1CC0EA4004350EF90041110B</string>
+						</array>
+						<key>PBXProjectModuleGUID</key>
+						<string>1CE0B1FE06471DED0097A5F4</string>
+						<key>PBXProjectModuleLabel</key>
+						<string>Files</string>
+						<key>PBXProjectStructureProvided</key>
+						<string>yes</string>
+						<key>PBXSmartGroupTreeModuleColumnData</key>
+						<dict>
+							<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+							<array>
+								<real>315</real>
+							</array>
+							<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+							<array>
+								<string>MainColumn</string>
+							</array>
+						</dict>
+						<key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+						<dict>
+							<key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+							<array>
+								<string>F5294A500090C4CA01CD285A</string>
+								<string>F537A7B50379EB8B01B94948</string>
+								<string>527CF6070AA51881007589FF</string>
+								<string>1C37FBAC04509CD000000102</string>
+								<string>1C08E77C0454961000C914BD</string>
+								<string>1C37FABC05509CD000000102</string>
+							</array>
+							<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+							<array>
+								<array>
+									<integer>0</integer>
+								</array>
+							</array>
+							<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+							<string>{{0, 0}, {315, 856}}</string>
+						</dict>
+						<key>PBXTopSmartGroupGIDs</key>
+						<array/>
+						<key>XCIncludePerspectivesSwitch</key>
+						<true/>
+						<key>XCSharingToken</key>
+						<string>com.apple.Xcode.GFSharingToken</string>
+					</dict>
+					<key>GeometryConfiguration</key>
+					<dict>
+						<key>Frame</key>
+						<string>{{0, 0}, {332, 874}}</string>
+						<key>GroupTreeTableConfiguration</key>
+						<array>
+							<string>MainColumn</string>
+							<real>315</real>
+						</array>
+						<key>RubberWindowFrame</key>
+						<string>653 242 1231 915 0 0 1920 1178 </string>
+					</dict>
+					<key>Module</key>
+					<string>PBXSmartGroupTreeModule</string>
+					<key>Proportion</key>
+					<string>332pt</string>
+				</dict>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CE0B20306471E060097A5F4</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>PCSC.exp</string>
+								<key>PBXSplitModuleInNavigatorKey</key>
+								<dict>
+									<key>Split0</key>
+									<dict>
+										<key>PBXProjectModuleGUID</key>
+										<string>1CE0B20406471E060097A5F4</string>
+										<key>PBXProjectModuleLabel</key>
+										<string>PCSC.exp</string>
+										<key>_historyCapacity</key>
+										<integer>0</integer>
+										<key>bookmark</key>
+										<string>52FF4CE00E95214500BBB5F9</string>
+										<key>history</key>
+										<array>
+											<string>5256DB350E0982EB001D4F37</string>
+										</array>
+									</dict>
+									<key>SplitCount</key>
+									<string>1</string>
+								</dict>
+								<key>StatusBarVisibility</key>
+								<true/>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {894, 0}}</string>
+								<key>RubberWindowFrame</key>
+								<string>653 242 1231 915 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXNavigatorGroup</string>
+							<key>Proportion</key>
+							<string>0pt</string>
+						</dict>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CE0B20506471E060097A5F4</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Detail</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 5}, {894, 869}}</string>
+								<key>RubberWindowFrame</key>
+								<string>653 242 1231 915 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>XCDetailModule</string>
+							<key>Proportion</key>
+							<string>869pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>894pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Project</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCModuleDock</string>
+				<string>PBXSmartGroupTreeModule</string>
+				<string>XCModuleDock</string>
+				<string>PBXNavigatorGroup</string>
+				<string>XCDetailModule</string>
+			</array>
+			<key>TableOfContents</key>
+			<array>
+				<string>52FF4CE10E95214500BBB5F9</string>
+				<string>1CE0B1FE06471DED0097A5F4</string>
+				<string>52FF4CE20E95214500BBB5F9</string>
+				<string>1CE0B20306471E060097A5F4</string>
+				<string>1CE0B20506471E060097A5F4</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.defaultV3</string>
+		</dict>
+		<dict>
+			<key>ControllerClassBaseName</key>
+			<string></string>
+			<key>IconName</key>
+			<string>WindowOfProject</string>
+			<key>Identifier</key>
+			<string>perspective.morph</string>
+			<key>IsVertical</key>
+			<integer>0</integer>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>BecomeActive</key>
+					<integer>1</integer>
+					<key>ContentConfiguration</key>
+					<dict>
+						<key>PBXBottomSmartGroupGIDs</key>
+						<array>
+							<string>1C37FBAC04509CD000000102</string>
+							<string>1C37FAAC04509CD000000102</string>
+							<string>1C08E77C0454961000C914BD</string>
+							<string>1C37FABC05509CD000000102</string>
+							<string>1C37FABC05539CD112110102</string>
+							<string>E2644B35053B69B200211256</string>
+							<string>1C37FABC04509CD000100104</string>
+							<string>1CC0EA4004350EF90044410B</string>
+							<string>1CC0EA4004350EF90041110B</string>
+						</array>
+						<key>PBXProjectModuleGUID</key>
+						<string>11E0B1FE06471DED0097A5F4</string>
+						<key>PBXProjectModuleLabel</key>
+						<string>Files</string>
+						<key>PBXProjectStructureProvided</key>
+						<string>yes</string>
+						<key>PBXSmartGroupTreeModuleColumnData</key>
+						<dict>
+							<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+							<array>
+								<real>186</real>
+							</array>
+							<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+							<array>
+								<string>MainColumn</string>
+							</array>
+						</dict>
+						<key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+						<dict>
+							<key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+							<array>
+								<string>29B97314FDCFA39411CA2CEA</string>
+								<string>1C37FABC05509CD000000102</string>
+							</array>
+							<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+							<array>
+								<array>
+									<integer>0</integer>
+								</array>
+							</array>
+							<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+							<string>{{0, 0}, {186, 337}}</string>
+						</dict>
+						<key>PBXTopSmartGroupGIDs</key>
+						<array/>
+						<key>XCIncludePerspectivesSwitch</key>
+						<integer>1</integer>
+						<key>XCSharingToken</key>
+						<string>com.apple.Xcode.GFSharingToken</string>
+					</dict>
+					<key>GeometryConfiguration</key>
+					<dict>
+						<key>Frame</key>
+						<string>{{0, 0}, {203, 355}}</string>
+						<key>GroupTreeTableConfiguration</key>
+						<array>
+							<string>MainColumn</string>
+							<real>186</real>
+						</array>
+						<key>RubberWindowFrame</key>
+						<string>373 269 690 397 0 0 1440 878 </string>
+					</dict>
+					<key>Module</key>
+					<string>PBXSmartGroupTreeModule</string>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Morph</string>
+			<key>PreferredWidth</key>
+			<integer>300</integer>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCModuleDock</string>
+				<string>PBXSmartGroupTreeModule</string>
+			</array>
+			<key>TableOfContents</key>
+			<array>
+				<string>11E0B1FE06471DED0097A5F4</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.default.shortV3</string>
+		</dict>
+	</array>
+	<key>PerspectivesBarVisible</key>
+	<false/>
+	<key>ShelfIsVisible</key>
+	<false/>
+	<key>SourceDescription</key>
+	<string>file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec'</string>
+	<key>StatusbarIsVisible</key>
+	<true/>
+	<key>TimeStamp</key>
+	<real>244514301.968683</real>
+	<key>ToolbarDisplayMode</key>
+	<integer>1</integer>
+	<key>ToolbarIsVisible</key>
+	<true/>
+	<key>ToolbarSizeMode</key>
+	<integer>1</integer>
+	<key>Type</key>
+	<string>Perspectives</string>
+	<key>UpdateMessage</key>
+	<string>The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature).  You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature.  Do you wish to update to the latest Workspace defaults for project '%@'?</string>
+	<key>WindowJustification</key>
+	<integer>5</integer>
+	<key>WindowOrderList</key>
+	<array>
+		<string>/Volumes/xenos/dev/tla-LeopardSU/SmartCardServices/SmartCardServices.xcodeproj</string>
+		<string>1C530D57069F1CE1000CFCEE</string>
+	</array>
+	<key>WindowString</key>
+	<string>653 242 1231 915 0 0 1920 1178 </string>
+	<key>WindowToolsV3</key>
+	<array>
+		<dict>
+			<key>FirstTimeWindowDisplayed</key>
+			<false/>
+			<key>Identifier</key>
+			<string>windowTool.build</string>
+			<key>IsVertical</key>
+			<true/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CD0528F0623707200166675</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>pcscdmonitor.h</string>
+								<key>StatusBarVisibility</key>
+								<true/>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {1033, 588}}</string>
+								<key>RubberWindowFrame</key>
+								<string>232 230 1033 870 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXNavigatorGroup</string>
+							<key>Proportion</key>
+							<string>588pt</string>
+						</dict>
+						<dict>
+							<key>BecomeActive</key>
+							<true/>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>XCMainBuildResultsModuleGUID</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Build</string>
+								<key>XCBuildResultsTrigger_Collapse</key>
+								<integer>1021</integer>
+								<key>XCBuildResultsTrigger_Open</key>
+								<integer>1010</integer>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 593}, {1033, 236}}</string>
+								<key>RubberWindowFrame</key>
+								<string>232 230 1033 870 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXBuildResultsModule</string>
+							<key>Proportion</key>
+							<string>236pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>829pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Build Results</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXBuildResultsModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<true/>
+			<key>TableOfContents</key>
+			<array>
+				<string>5221F1AD0DE4F19E001E0235</string>
+				<string>5256DB380E0982EB001D4F37</string>
+				<string>1CD0528F0623707200166675</string>
+				<string>XCMainBuildResultsModuleGUID</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.buildV3</string>
+			<key>WindowString</key>
+			<string>232 230 1033 870 0 0 1920 1178 </string>
+			<key>WindowToolGUID</key>
+			<string>5221F1AD0DE4F19E001E0235</string>
+			<key>WindowToolIsVisible</key>
+			<true/>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.debugger</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>Debugger</key>
+								<dict>
+									<key>HorizontalSplitView</key>
+									<dict>
+										<key>_collapsingFrameDimension</key>
+										<real>0.0</real>
+										<key>_indexOfCollapsedView</key>
+										<integer>0</integer>
+										<key>_percentageOfCollapsedView</key>
+										<real>0.0</real>
+										<key>isCollapsed</key>
+										<string>yes</string>
+										<key>sizes</key>
+										<array>
+											<string>{{0, 0}, {317, 164}}</string>
+											<string>{{317, 0}, {377, 164}}</string>
+										</array>
+									</dict>
+									<key>VerticalSplitView</key>
+									<dict>
+										<key>_collapsingFrameDimension</key>
+										<real>0.0</real>
+										<key>_indexOfCollapsedView</key>
+										<integer>0</integer>
+										<key>_percentageOfCollapsedView</key>
+										<real>0.0</real>
+										<key>isCollapsed</key>
+										<string>yes</string>
+										<key>sizes</key>
+										<array>
+											<string>{{0, 0}, {694, 164}}</string>
+											<string>{{0, 164}, {694, 216}}</string>
+										</array>
+									</dict>
+								</dict>
+								<key>LauncherConfigVersion</key>
+								<string>8</string>
+								<key>PBXProjectModuleGUID</key>
+								<string>1C162984064C10D400B95A72</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Debug - GLUTExamples (Underwater)</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>DebugConsoleDrawerSize</key>
+								<string>{100, 120}</string>
+								<key>DebugConsoleVisible</key>
+								<string>None</string>
+								<key>DebugConsoleWindowFrame</key>
+								<string>{{200, 200}, {500, 300}}</string>
+								<key>DebugSTDIOWindowFrame</key>
+								<string>{{200, 200}, {500, 300}}</string>
+								<key>Frame</key>
+								<string>{{0, 0}, {694, 380}}</string>
+								<key>RubberWindowFrame</key>
+								<string>321 238 694 422 0 0 1440 878 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXDebugSessionModule</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Debugger</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXDebugSessionModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>1</integer>
+			<key>TableOfContents</key>
+			<array>
+				<string>1CD10A99069EF8BA00B06720</string>
+				<string>1C0AD2AB069F1E9B00FABCE6</string>
+				<string>1C162984064C10D400B95A72</string>
+				<string>1C0AD2AC069F1E9B00FABCE6</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.debugV3</string>
+			<key>WindowString</key>
+			<string>321 238 694 422 0 0 1440 878 </string>
+			<key>WindowToolGUID</key>
+			<string>1CD10A99069EF8BA00B06720</string>
+			<key>WindowToolIsVisible</key>
+			<integer>0</integer>
+		</dict>
+		<dict>
+			<key>FirstTimeWindowDisplayed</key>
+			<false/>
+			<key>Identifier</key>
+			<string>windowTool.find</string>
+			<key>IsVertical</key>
+			<true/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>Dock</key>
+							<array>
+								<dict>
+									<key>ContentConfiguration</key>
+									<dict>
+										<key>PBXProjectModuleGUID</key>
+										<string>1CDD528C0622207200134675</string>
+										<key>PBXProjectModuleLabel</key>
+										<string>winscard.c</string>
+										<key>StatusBarVisibility</key>
+										<true/>
+									</dict>
+									<key>GeometryConfiguration</key>
+									<dict>
+										<key>Frame</key>
+										<string>{{0, 0}, {948, 748}}</string>
+										<key>RubberWindowFrame</key>
+										<string>553 116 948 1006 0 0 1920 1178 </string>
+									</dict>
+									<key>Module</key>
+									<string>PBXNavigatorGroup</string>
+									<key>Proportion</key>
+									<string>948pt</string>
+								</dict>
+							</array>
+							<key>Proportion</key>
+							<string>748pt</string>
+						</dict>
+						<dict>
+							<key>BecomeActive</key>
+							<true/>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CD0528E0623707200166675</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Project Find</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 753}, {948, 212}}</string>
+								<key>RubberWindowFrame</key>
+								<string>553 116 948 1006 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXProjectFindModule</string>
+							<key>Proportion</key>
+							<string>212pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>965pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Project Find</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXProjectFindModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<true/>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C530D57069F1CE1000CFCEE</string>
+				<string>52FF4CE30E95214500BBB5F9</string>
+				<string>52FF4CE40E95214500BBB5F9</string>
+				<string>1CDD528C0622207200134675</string>
+				<string>1CD0528E0623707200166675</string>
+			</array>
+			<key>WindowString</key>
+			<string>553 116 948 1006 0 0 1920 1178 </string>
+			<key>WindowToolGUID</key>
+			<string>1C530D57069F1CE1000CFCEE</string>
+			<key>WindowToolIsVisible</key>
+			<true/>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>MENUSEPARATOR</string>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.debuggerConsole</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<integer>1</integer>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1C78EAAC065D492600B07095</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Debugger Console</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {650, 250}}</string>
+								<key>RubberWindowFrame</key>
+								<string>516 632 650 250 0 0 1680 1027 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXDebugCLIModule</string>
+							<key>Proportion</key>
+							<string>209pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>209pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Debugger Console</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXDebugCLIModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>1</integer>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C78EAAD065D492600B07095</string>
+				<string>1C78EAAE065D492600B07095</string>
+				<string>1C78EAAC065D492600B07095</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.consoleV3</string>
+			<key>WindowString</key>
+			<string>650 41 650 250 0 0 1280 1002 </string>
+			<key>WindowToolGUID</key>
+			<string>1C78EAAD065D492600B07095</string>
+			<key>WindowToolIsVisible</key>
+			<integer>0</integer>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.snapshots</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>Module</key>
+							<string>XCSnapshotModule</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Snapshots</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCSnapshotModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<string>Yes</string>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.snapshots</string>
+			<key>WindowString</key>
+			<string>315 824 300 550 0 0 1440 878 </string>
+			<key>WindowToolIsVisible</key>
+			<string>Yes</string>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.scm</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1C78EAB2065D492600B07095</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>&lt;No Editor&gt;</string>
+								<key>PBXSplitModuleInNavigatorKey</key>
+								<dict>
+									<key>Split0</key>
+									<dict>
+										<key>PBXProjectModuleGUID</key>
+										<string>1C78EAB3065D492600B07095</string>
+									</dict>
+									<key>SplitCount</key>
+									<string>1</string>
+								</dict>
+								<key>StatusBarVisibility</key>
+								<integer>1</integer>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {452, 0}}</string>
+								<key>RubberWindowFrame</key>
+								<string>743 379 452 308 0 0 1280 1002 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXNavigatorGroup</string>
+							<key>Proportion</key>
+							<string>0pt</string>
+						</dict>
+						<dict>
+							<key>BecomeActive</key>
+							<integer>1</integer>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CD052920623707200166675</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>SCM</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>ConsoleFrame</key>
+								<string>{{0, 259}, {452, 0}}</string>
+								<key>Frame</key>
+								<string>{{0, 7}, {452, 259}}</string>
+								<key>RubberWindowFrame</key>
+								<string>743 379 452 308 0 0 1280 1002 </string>
+								<key>TableConfiguration</key>
+								<array>
+									<string>Status</string>
+									<real>30</real>
+									<string>FileName</string>
+									<real>199</real>
+									<string>Path</string>
+									<real>197.09500122070312</real>
+								</array>
+								<key>TableFrame</key>
+								<string>{{0, 0}, {452, 250}}</string>
+							</dict>
+							<key>Module</key>
+							<string>PBXCVSModule</string>
+							<key>Proportion</key>
+							<string>262pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>266pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>SCM</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXCVSModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>1</integer>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C78EAB4065D492600B07095</string>
+				<string>1C78EAB5065D492600B07095</string>
+				<string>1C78EAB2065D492600B07095</string>
+				<string>1CD052920623707200166675</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.scm</string>
+			<key>WindowString</key>
+			<string>743 379 452 308 0 0 1280 1002 </string>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.breakpoints</string>
+			<key>IsVertical</key>
+			<integer>0</integer>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<integer>1</integer>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXBottomSmartGroupGIDs</key>
+								<array>
+									<string>1C77FABC04509CD000000102</string>
+								</array>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CE0B1FE06471DED0097A5F4</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Files</string>
+								<key>PBXProjectStructureProvided</key>
+								<string>no</string>
+								<key>PBXSmartGroupTreeModuleColumnData</key>
+								<dict>
+									<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+									<array>
+										<real>168</real>
+									</array>
+									<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+									<array>
+										<string>MainColumn</string>
+									</array>
+								</dict>
+								<key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+								<dict>
+									<key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+									<array>
+										<string>1C77FABC04509CD000000102</string>
+									</array>
+									<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+									<array>
+										<array>
+											<integer>0</integer>
+										</array>
+									</array>
+									<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+									<string>{{0, 0}, {168, 350}}</string>
+								</dict>
+								<key>PBXTopSmartGroupGIDs</key>
+								<array/>
+								<key>XCIncludePerspectivesSwitch</key>
+								<integer>0</integer>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {185, 368}}</string>
+								<key>GroupTreeTableConfiguration</key>
+								<array>
+									<string>MainColumn</string>
+									<real>168</real>
+								</array>
+								<key>RubberWindowFrame</key>
+								<string>315 424 744 409 0 0 1440 878 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXSmartGroupTreeModule</string>
+							<key>Proportion</key>
+							<string>185pt</string>
+						</dict>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CA1AED706398EBD00589147</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Detail</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{190, 0}, {554, 368}}</string>
+								<key>RubberWindowFrame</key>
+								<string>315 424 744 409 0 0 1440 878 </string>
+							</dict>
+							<key>Module</key>
+							<string>XCDetailModule</string>
+							<key>Proportion</key>
+							<string>554pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>368pt</string>
+				</dict>
+			</array>
+			<key>MajorVersion</key>
+			<integer>3</integer>
+			<key>MinorVersion</key>
+			<integer>0</integer>
+			<key>Name</key>
+			<string>Breakpoints</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXSmartGroupTreeModule</string>
+				<string>XCDetailModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>1</integer>
+			<key>TableOfContents</key>
+			<array>
+				<string>1CDDB66807F98D9800BB5817</string>
+				<string>1CDDB66907F98D9800BB5817</string>
+				<string>1CE0B1FE06471DED0097A5F4</string>
+				<string>1CA1AED706398EBD00589147</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.breakpointsV3</string>
+			<key>WindowString</key>
+			<string>315 424 744 409 0 0 1440 878 </string>
+			<key>WindowToolGUID</key>
+			<string>1CDDB66807F98D9800BB5817</string>
+			<key>WindowToolIsVisible</key>
+			<integer>1</integer>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.debugAnimator</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>Module</key>
+							<string>PBXNavigatorGroup</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Debug Visualizer</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXNavigatorGroup</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>1</integer>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.debugAnimatorV3</string>
+			<key>WindowString</key>
+			<string>100 100 700 500 0 0 1280 1002 </string>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.bookmarks</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>Module</key>
+							<string>PBXBookmarksModule</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Bookmarks</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXBookmarksModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>0</integer>
+			<key>WindowString</key>
+			<string>538 42 401 187 0 0 1280 1002 </string>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.projectFormatConflicts</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>Module</key>
+							<string>XCProjectFormatConflictsModule</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Project Format Conflicts</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCProjectFormatConflictsModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>0</integer>
+			<key>WindowContentMinSize</key>
+			<string>450 300</string>
+			<key>WindowString</key>
+			<string>50 850 472 307 0 0 1440 877</string>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.classBrowser</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<integer>1</integer>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>OptionsSetName</key>
+								<string>Hierarchy, all classes</string>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CA6456E063B45B4001379D8</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Class Browser - NSObject</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>ClassesFrame</key>
+								<string>{{0, 0}, {374, 96}}</string>
+								<key>ClassesTreeTableConfiguration</key>
+								<array>
+									<string>PBXClassNameColumnIdentifier</string>
+									<real>208</real>
+									<string>PBXClassBookColumnIdentifier</string>
+									<real>22</real>
+								</array>
+								<key>Frame</key>
+								<string>{{0, 0}, {630, 331}}</string>
+								<key>MembersFrame</key>
+								<string>{{0, 105}, {374, 395}}</string>
+								<key>MembersTreeTableConfiguration</key>
+								<array>
+									<string>PBXMemberTypeIconColumnIdentifier</string>
+									<real>22</real>
+									<string>PBXMemberNameColumnIdentifier</string>
+									<real>216</real>
+									<string>PBXMemberTypeColumnIdentifier</string>
+									<real>97</real>
+									<string>PBXMemberBookColumnIdentifier</string>
+									<real>22</real>
+								</array>
+								<key>PBXModuleWindowStatusBarHidden2</key>
+								<integer>1</integer>
+								<key>RubberWindowFrame</key>
+								<string>385 179 630 352 0 0 1440 878 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXClassBrowserModule</string>
+							<key>Proportion</key>
+							<string>332pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>332pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Class Browser</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXClassBrowserModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>0</integer>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C0AD2AF069F1E9B00FABCE6</string>
+				<string>1C0AD2B0069F1E9B00FABCE6</string>
+				<string>1CA6456E063B45B4001379D8</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.classbrowser</string>
+			<key>WindowString</key>
+			<string>385 179 630 352 0 0 1440 878 </string>
+			<key>WindowToolGUID</key>
+			<string>1C0AD2AF069F1E9B00FABCE6</string>
+			<key>WindowToolIsVisible</key>
+			<integer>0</integer>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.refactoring</string>
+			<key>IncludeInToolsMenu</key>
+			<integer>0</integer>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<integer>1</integer>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{0, 0}, {500, 335}</string>
+								<key>RubberWindowFrame</key>
+								<string>{0, 0}, {500, 335}</string>
+							</dict>
+							<key>Module</key>
+							<string>XCRefactoringModule</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Refactoring</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCRefactoringModule</string>
+			</array>
+			<key>WindowString</key>
+			<string>200 200 500 356 0 0 1920 1200 </string>
+		</dict>
+	</array>
+</dict>
+</plist>

Added: trunk/SmartCardServices/SmartCardServices.xcodeproj/john.pbxuser
===================================================================
--- trunk/SmartCardServices/SmartCardServices.xcodeproj/john.pbxuser	                        (rev 0)
+++ trunk/SmartCardServices/SmartCardServices.xcodeproj/john.pbxuser	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,346 @@
+// !$*UTF8*$!
+{
+	2CBB605A06CA6944006AA7C8 /* GSCISPlugin */ = {
+		activeExec = 0;
+	};
+	5221F18C0DE4EAF3001E0235 /* pcscd */ = {
+		isa = PBXExecutable;
+		activeArgIndices = (
+		);
+		argumentStrings = (
+		);
+		autoAttachOnCrash = 1;
+		breakpointsEnabled = 1;
+		configStateDict = {
+		};
+		customDataFormattersEnabled = 1;
+		debuggerPlugin = GDBDebugging;
+		disassemblyDisplayState = 0;
+		enableDebugStr = 1;
+		environmentEntries = (
+		);
+		executableSystemSymbolLevel = 0;
+		executableUserSymbolLevel = 0;
+		libgmallocEnabled = 0;
+		name = pcscd;
+		sourceDirectories = (
+		);
+	};
+	5221F18D0DE4EAF3001E0235 /* pcsctest */ = {
+		isa = PBXExecutable;
+		activeArgIndices = (
+		);
+		argumentStrings = (
+		);
+		autoAttachOnCrash = 1;
+		breakpointsEnabled = 1;
+		configStateDict = {
+		};
+		customDataFormattersEnabled = 1;
+		debuggerPlugin = GDBDebugging;
+		disassemblyDisplayState = 0;
+		enableDebugStr = 1;
+		environmentEntries = (
+		);
+		executableSystemSymbolLevel = 0;
+		executableUserSymbolLevel = 0;
+		libgmallocEnabled = 0;
+		name = pcsctest;
+		sourceDirectories = (
+		);
+	};
+	5221F18E0DE4EAF3001E0235 /* pcsctool */ = {
+		isa = PBXExecutable;
+		activeArgIndices = (
+		);
+		argumentStrings = (
+		);
+		autoAttachOnCrash = 1;
+		breakpointsEnabled = 1;
+		configStateDict = {
+		};
+		customDataFormattersEnabled = 1;
+		debuggerPlugin = GDBDebugging;
+		disassemblyDisplayState = 0;
+		enableDebugStr = 1;
+		environmentEntries = (
+		);
+		executableSystemSymbolLevel = 0;
+		executableUserSymbolLevel = 0;
+		libgmallocEnabled = 0;
+		name = pcsctool;
+		sourceDirectories = (
+		);
+	};
+	5221F1A20DE4EAF6001E0235 /* Source Control */ = {
+		isa = PBXSourceControlManager;
+		fallbackIsa = XCSourceControlManager;
+		isSCMEnabled = 0;
+		scmConfiguration = {
+		};
+	};
+	5221F1A30DE4EAF6001E0235 /* Code sense */ = {
+		isa = PBXCodeSenseManager;
+		indexTemplatePath = "";
+	};
+	5256DB350E0982EB001D4F37 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 52DBCAAE0BB851C8007D06A5 /* PCSC.exp */;
+		name = "PCSC.exp: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 0;
+		vrLoc = 0;
+	};
+	527CF60B0AA5192B007589FF /* pcscdmonitor.h */ = {
+		uiCtxt = {
+			sepNavIntBoundsRect = "{{0, 0}, {972, 2688}}";
+			sepNavSelRange = "{1323, 0}";
+			sepNavVisRange = "{693, 1274}";
+		};
+	};
+	527F79430DE4F84A0024C9D1 /* pcscd (Upgraded) */ = {
+		isa = PBXExecutable;
+		activeArgIndices = (
+		);
+		argumentStrings = (
+		);
+		autoAttachOnCrash = 1;
+		breakpointsEnabled = 1;
+		configStateDict = {
+		};
+		customDataFormattersEnabled = 1;
+		debuggerPlugin = GDBDebugging;
+		disassemblyDisplayState = 0;
+		enableDebugStr = 1;
+		environmentEntries = (
+		);
+		executableSystemSymbolLevel = 0;
+		executableUserSymbolLevel = 0;
+		libgmallocEnabled = 0;
+		name = "pcscd (Upgraded)";
+		sourceDirectories = (
+		);
+	};
+	527F79740DE4F84B0024C9D1 /* pcsctest (Upgraded) */ = {
+		isa = PBXExecutable;
+		activeArgIndices = (
+		);
+		argumentStrings = (
+		);
+		autoAttachOnCrash = 1;
+		breakpointsEnabled = 1;
+		configStateDict = {
+		};
+		customDataFormattersEnabled = 1;
+		debuggerPlugin = GDBDebugging;
+		disassemblyDisplayState = 0;
+		enableDebugStr = 1;
+		environmentEntries = (
+		);
+		executableSystemSymbolLevel = 0;
+		executableUserSymbolLevel = 0;
+		libgmallocEnabled = 0;
+		name = "pcsctest (Upgraded)";
+		sourceDirectories = (
+		);
+	};
+	527F79810DE4F84B0024C9D1 /* pcsctool (Upgraded) */ = {
+		isa = PBXExecutable;
+		activeArgIndices = (
+		);
+		argumentStrings = (
+		);
+		autoAttachOnCrash = 1;
+		breakpointsEnabled = 1;
+		configStateDict = {
+		};
+		customDataFormattersEnabled = 1;
+		debuggerPlugin = GDBDebugging;
+		disassemblyDisplayState = 0;
+		enableDebugStr = 1;
+		environmentEntries = (
+		);
+		executableSystemSymbolLevel = 0;
+		executableUserSymbolLevel = 0;
+		libgmallocEnabled = 0;
+		name = "pcsctool (Upgraded)";
+		sourceDirectories = (
+		);
+	};
+	52DBCAAE0BB851C8007D06A5 /* PCSC.exp */ = {
+		uiCtxt = {
+			sepNavIntBoundsRect = "{{0, 0}, {833, 1050}}";
+			sepNavSelRange = "{0, 0}";
+			sepNavVisRange = "{0, 0}";
+		};
+	};
+	52E0D59D0BA7006D008DFDDF /* winscard.c */ = {
+		uiCtxt = {
+			sepNavIntBoundsRect = "{{0, 0}, {887, 20860}}";
+			sepNavSelRange = "{25857, 12}";
+			sepNavVisRange = "{26242, 1225}";
+		};
+	};
+	52FF4CE00E95214500BBB5F9 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 52DBCAAE0BB851C8007D06A5 /* PCSC.exp */;
+		name = "PCSC.exp: 1";
+		rLen = 0;
+		rLoc = 0;
+		rType = 0;
+		vrLen = 0;
+		vrLoc = 0;
+	};
+	F51121270272F895017BB957 /* pcsctool */ = {
+		activeExec = 0;
+		executables = (
+			5221F18E0DE4EAF3001E0235 /* pcsctool */,
+		);
+	};
+	F5294A4F0090C4CA01CD285A /* Project object */ = {
+		activeArchitecture = ppc;
+		activeBuildConfigurationName = Development;
+		activeExecutable = 527F79430DE4F84A0024C9D1 /* pcscd (Upgraded) */;
+		activeTarget = F5294A510090C54E01CD285A /* World */;
+		addToTargets = (
+			F5294A510090C54E01CD285A /* World */,
+			F52A93D402541D8C01B94B21 /* PCSC */,
+		);
+		codeSenseManager = 5221F1A30DE4EAF6001E0235 /* Code sense */;
+		executables = (
+			5221F18C0DE4EAF3001E0235 /* pcscd */,
+			5221F18D0DE4EAF3001E0235 /* pcsctest */,
+			5221F18E0DE4EAF3001E0235 /* pcsctool */,
+			527F79430DE4F84A0024C9D1 /* pcscd (Upgraded) */,
+			527F79740DE4F84B0024C9D1 /* pcsctest (Upgraded) */,
+			527F79810DE4F84B0024C9D1 /* pcsctool (Upgraded) */,
+		);
+		perUserDictionary = {
+			PBXConfiguration.PBXFileTableDataSource3.PBXErrorsWarningsDataSource = {
+				PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+				PBXFileTableDataSourceColumnSortingKey = PBXErrorsWarningsDataSource_LocationID;
+				PBXFileTableDataSourceColumnWidthsKey = (
+					20,
+					449,
+					396,
+				);
+				PBXFileTableDataSourceColumnsKey = (
+					PBXErrorsWarningsDataSource_TypeID,
+					PBXErrorsWarningsDataSource_MessageID,
+					PBXErrorsWarningsDataSource_LocationID,
+				);
+			};
+			PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
+				PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+				PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
+				PBXFileTableDataSourceColumnWidthsKey = (
+					20,
+					655,
+					20,
+					48,
+					43,
+					43,
+					20,
+				);
+				PBXFileTableDataSourceColumnsKey = (
+					PBXFileDataSource_FiletypeID,
+					PBXFileDataSource_Filename_ColumnID,
+					PBXFileDataSource_Built_ColumnID,
+					PBXFileDataSource_ObjectSize_ColumnID,
+					PBXFileDataSource_Errors_ColumnID,
+					PBXFileDataSource_Warnings_ColumnID,
+					PBXFileDataSource_Target_ColumnID,
+				);
+			};
+			PBXConfiguration.PBXFileTableDataSource3.PBXSymbolsDataSource = {
+				PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+				PBXFileTableDataSourceColumnSortingKey = PBXSymbolsDataSource_SymbolNameID;
+				PBXFileTableDataSourceColumnWidthsKey = (
+					16,
+					200,
+					50,
+					512.20849609375,
+				);
+				PBXFileTableDataSourceColumnsKey = (
+					PBXSymbolsDataSource_SymbolTypeIconID,
+					PBXSymbolsDataSource_SymbolNameID,
+					PBXSymbolsDataSource_SymbolTypeID,
+					PBXSymbolsDataSource_ReferenceNameID,
+				);
+			};
+			PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = {
+				PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+				PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
+				PBXFileTableDataSourceColumnWidthsKey = (
+					20,
+					615,
+					60,
+					20,
+					48,
+					43,
+					43,
+				);
+				PBXFileTableDataSourceColumnsKey = (
+					PBXFileDataSource_FiletypeID,
+					PBXFileDataSource_Filename_ColumnID,
+					PBXTargetDataSource_PrimaryAttribute,
+					PBXFileDataSource_Built_ColumnID,
+					PBXFileDataSource_ObjectSize_ColumnID,
+					PBXFileDataSource_Errors_ColumnID,
+					PBXFileDataSource_Warnings_ColumnID,
+				);
+			};
+			PBXPerProjectTemplateStateSaveDate = 244514301;
+			PBXWorkspaceStateSaveDate = 244514301;
+		};
+		perUserProjectItems = {
+			5256DB350E0982EB001D4F37 /* PBXTextBookmark */ = 5256DB350E0982EB001D4F37 /* PBXTextBookmark */;
+			52FF4CE00E95214500BBB5F9 /* PBXTextBookmark */ = 52FF4CE00E95214500BBB5F9 /* PBXTextBookmark */;
+		};
+		sourceControlManager = 5221F1A20DE4EAF6001E0235 /* Source Control */;
+		userBuildSettings = {
+		};
+	};
+	F5294A510090C54E01CD285A /* World */ = {
+		activeExec = 0;
+	};
+	F5294A800090C73501CD285A /* pcscd */ = {
+		activeExec = 0;
+		executables = (
+			5221F18C0DE4EAF3001E0235 /* pcscd */,
+		);
+	};
+	F5294AD40090CAE601CD285A /* pcsctest */ = {
+		activeExec = 0;
+		executables = (
+			5221F18D0DE4EAF3001E0235 /* pcsctest */,
+		);
+	};
+	F52A93D402541D8C01B94B21 /* PCSC */ = {
+		activeExec = 0;
+	};
+	F52A94D4025424AC01B94B21 /* winscard_clnt.c */ = {
+		uiCtxt = {
+			sepNavIntBoundsRect = "{{0, 0}, {887, 47712}}";
+			sepNavSelRange = "{57603, 121}";
+			sepNavVisRange = "{60792, 1704}";
+		};
+	};
+	F537A7D10379ED7501B94948 /* PKCS11 */ = {
+		activeExec = 0;
+	};
+	F538896903953B79012F6BBF /* InstallPhase */ = {
+		activeExec = 0;
+	};
+	F5448E020379EE2A01B94948 /* MCardPlugin */ = {
+		activeExec = 0;
+	};
+	F5448E090379EE3601B94948 /* CACPlugin */ = {
+		activeExec = 0;
+	};
+	F5448E100379EE6401B94948 /* CFlexPlugin */ = {
+		activeExec = 0;
+	};
+}

Added: trunk/SmartCardServices/SmartCardServices.xcodeproj/project.pbxproj
===================================================================
--- trunk/SmartCardServices/SmartCardServices.xcodeproj/project.pbxproj	                        (rev 0)
+++ trunk/SmartCardServices/SmartCardServices.xcodeproj/project.pbxproj	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,2762 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 42;
+	objects = {
+
+/* Begin PBXAggregateTarget section */
+		F5294A510090C54E01CD285A /* World */ = {
+			isa = PBXAggregateTarget;
+			buildConfigurationList = C27AD1F80987FCDC001272E0 /* Build configuration list for PBXAggregateTarget "World" */;
+			buildPhases = (
+			);
+			dependencies = (
+				F520A5F60257B49C01D97E8A /* PBXTargetDependency */,
+				F520E3A001F6204201B94B28 /* PBXTargetDependency */,
+				F520E3A301F6204201B94B28 /* PBXTargetDependency */,
+				F511213B0272FA1C017BB957 /* PBXTargetDependency */,
+				F5448E810379FE0101B94948 /* PBXTargetDependency */,
+				F5448E820379FE0501B94948 /* PBXTargetDependency */,
+				2CBB607506CA6DDE006AA7C8 /* PBXTargetDependency */,
+				F5448E830379FE0801B94948 /* PBXTargetDependency */,
+				F5448E840379FE0C01B94948 /* PBXTargetDependency */,
+				F54DC28B0397F35F01115D8D /* PBXTargetDependency */,
+			);
+			name = World;
+			productName = World;
+		};
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+		2CBB606506CA69F9006AA7C8 /* GSCISPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 2CBB606306CA69F9006AA7C8 /* GSCISPlugin.c */; };
+		2CBB606606CA69F9006AA7C8 /* GSCISPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CBB606406CA69F9006AA7C8 /* GSCISPlugin.h */; };
+		2CC9AB8406CC02F30048A811 /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5448E630379F08001B94948 /* PCSC.framework */; };
+		5236DD1F0B9DDBD7007CEF56 /* readerstate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5236DD1D0B9DDBD7007CEF56 /* readerstate.h */; };
+		527CF60E0AA5192B007589FF /* pcscdmonitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 527CF60A0AA5192B007589FF /* pcscdmonitor.cpp */; };
+		527CF60F0AA5192B007589FF /* pcscdmonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 527CF60B0AA5192B007589FF /* pcscdmonitor.h */; };
+		527CF6100AA5192B007589FF /* pcscdserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 527CF60C0AA5192B007589FF /* pcscdserver.cpp */; };
+		527CF6110AA5192B007589FF /* pcscdserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 527CF60D0AA5192B007589FF /* pcscdserver.h */; };
+		528629490A87EA8E004FE8DC /* hotplug_macosx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5286293C0A87EA8E004FE8DC /* hotplug_macosx.cpp */; };
+		5286294A0A87EA8E004FE8DC /* PCSCDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5286293D0A87EA8E004FE8DC /* PCSCDevice.cpp */; };
+		5286294B0A87EA8E004FE8DC /* PCSCDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 5286293E0A87EA8E004FE8DC /* PCSCDevice.h */; };
+		5286294C0A87EA8E004FE8DC /* PCSCDriverBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5286293F0A87EA8E004FE8DC /* PCSCDriverBundle.cpp */; };
+		5286294D0A87EA8E004FE8DC /* PCSCDriverBundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 528629400A87EA8E004FE8DC /* PCSCDriverBundle.h */; };
+		5286294E0A87EA8E004FE8DC /* PCSCDriverBundles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 528629410A87EA8E004FE8DC /* PCSCDriverBundles.cpp */; };
+		5286294F0A87EA8E004FE8DC /* PCSCDriverBundles.h in Headers */ = {isa = PBXBuildFile; fileRef = 528629420A87EA8E004FE8DC /* PCSCDriverBundles.h */; };
+		52C3C1480BA5D46900436862 /* readerstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5236DD1C0B9DDBD7007CEF56 /* readerstate.cpp */; };
+		52C3C14D0BA5D54100436862 /* readerstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5236DD1C0B9DDBD7007CEF56 /* readerstate.cpp */; };
+		52C85D900B9FA79F002DA856 /* security_utilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D58C080A87FEA000DC3F19 /* security_utilities.framework */; };
+		52D00D1C0A9252350093277A /* reader.h in Headers */ = {isa = PBXBuildFile; fileRef = 52D00D1A0A9252350093277A /* reader.h */; };
+		52D00D1D0A9252350093277A /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52D00D1B0A9252350093277A /* reader.cpp */; };
+		52D2492D0BA07E1100F9827A /* winscard_msg_srv.c in Sources */ = {isa = PBXBuildFile; fileRef = 52D2492C0BA07E1100F9827A /* winscard_msg_srv.c */; };
+		52D58C090A87FEA000DC3F19 /* security_utilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D58C080A87FEA000DC3F19 /* security_utilities.framework */; };
+		52D58C560A8803A800DC3F19 /* thread_macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94A60254242101B94B21 /* thread_macosx.c */; };
+		52DBCAAF0BB851C8007D06A5 /* PCSC.exp in Sources */ = {isa = PBXBuildFile; fileRef = 52DBCAAE0BB851C8007D06A5 /* PCSC.exp */; };
+		52E0D59E0BA7006D008DFDDF /* winscard.c in Sources */ = {isa = PBXBuildFile; fileRef = 52E0D59D0BA7006D008DFDDF /* winscard.c */; };
+		C2F2094B0662B851001DFD06 /* sys_macosx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F2094A0662B851001DFD06 /* sys_macosx.cpp */; };
+		F503CACF025425E601B94B21 /* testpcsc.c in Sources */ = {isa = PBXBuildFile; fileRef = F503CACD025425E601B94B21 /* testpcsc.c */; };
+		F503CADD025428F601B94B21 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F503CADB025428F601B94B21 /* CoreFoundation.framework */; };
+		F503CADE025428F601B94B21 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F503CADC025428F601B94B21 /* IOKit.framework */; };
+		F503CAE00254294101B94B21 /* libl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F503CADF0254294101B94B21 /* libl.a */; };
+		F503CAE402542A9201B94B21 /* wintypes.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94AD0254242101B94B21 /* wintypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		F503CAE502542A9201B94B21 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F503CADB025428F601B94B21 /* CoreFoundation.framework */; };
+		F511212D0272F8D9017BB957 /* bundleTool.c in Sources */ = {isa = PBXBuildFile; fileRef = F511212C0272F8D9017BB957 /* bundleTool.c */; };
+		F52A94520254232701B94B21 /* atrhandler.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94510254232701B94B21 /* atrhandler.c */; };
+		F52A94AE0254242101B94B21 /* atrhandler.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A948F0254242101B94B21 /* atrhandler.h */; };
+		F52A94AF0254242101B94B21 /* configfile.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94910254242101B94B21 /* configfile.h */; };
+		F52A94B00254242101B94B21 /* debuglog.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94930254242101B94B21 /* debuglog.h */; };
+		F52A94B10254242101B94B21 /* dyn_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94940254242101B94B21 /* dyn_generic.h */; };
+		F52A94B20254242101B94B21 /* eventhandler.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94970254242101B94B21 /* eventhandler.h */; };
+		F52A94B30254242101B94B21 /* hotplug.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94990254242101B94B21 /* hotplug.h */; };
+		F52A94B40254242101B94B21 /* ifdhandler.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A949A0254242101B94B21 /* ifdhandler.h */; };
+		F52A94B50254242101B94B21 /* ifdwrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A949C0254242101B94B21 /* ifdwrapper.h */; };
+		F52A94B60254242101B94B21 /* pcsclite.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A949E0254242101B94B21 /* pcsclite.h */; };
+		F52A94B70254242101B94B21 /* prothandler.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94A00254242101B94B21 /* prothandler.h */; };
+		F52A94B80254242101B94B21 /* readerfactory.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94A20254242101B94B21 /* readerfactory.h */; };
+		F52A94B90254242101B94B21 /* sys_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94A30254242101B94B21 /* sys_generic.h */; };
+		F52A94BA0254242101B94B21 /* thread_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94A50254242101B94B21 /* thread_generic.h */; };
+		F52A94BB0254242101B94B21 /* winscard_msg.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94A80254242101B94B21 /* winscard_msg.h */; };
+		F52A94BC0254242101B94B21 /* winscard_svc.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94AA0254242101B94B21 /* winscard_svc.h */; };
+		F52A94BD0254242101B94B21 /* winscard.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94AC0254242101B94B21 /* winscard.h */; };
+		F52A94BE0254242101B94B21 /* wintypes.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94AD0254242101B94B21 /* wintypes.h */; };
+		F52A94BF0254242101B94B21 /* configfile.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94900254242101B94B21 /* configfile.c */; settings = {COMPILER_FLAGS = "-DYY_NO_UNPUT"; }; };
+		F52A94C00254242101B94B21 /* debuglog.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94920254242101B94B21 /* debuglog.c */; };
+		F52A94C10254242101B94B21 /* dyn_macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94950254242101B94B21 /* dyn_macosx.c */; };
+		F52A94C20254242101B94B21 /* eventhandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52A94960254242101B94B21 /* eventhandler.cpp */; };
+		F52A94C40254242101B94B21 /* ifdwrapper.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A949B0254242101B94B21 /* ifdwrapper.c */; };
+		F52A94C50254242101B94B21 /* pcscdaemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A949D0254242101B94B21 /* pcscdaemon.c */; };
+		F52A94C60254242101B94B21 /* prothandler.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A949F0254242101B94B21 /* prothandler.c */; };
+		F52A94C70254242101B94B21 /* readerfactory.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94A10254242101B94B21 /* readerfactory.c */; };
+		F52A94C90254242101B94B21 /* thread_macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94A60254242101B94B21 /* thread_macosx.c */; };
+		F52A94CA0254242101B94B21 /* winscard_msg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52A94A70254242101B94B21 /* winscard_msg.cpp */; };
+		F52A94CB0254242101B94B21 /* winscard_svc.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94A90254242101B94B21 /* winscard_svc.c */; };
+		F52A94D5025424AC01B94B21 /* thread_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94A50254242101B94B21 /* thread_generic.h */; };
+		F52A94D6025424AC01B94B21 /* pcsclite.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A949E0254242101B94B21 /* pcsclite.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		F52A94D7025424AC01B94B21 /* mscdefines.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94CD025424AC01B94B21 /* mscdefines.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		F52A94D8025424AC01B94B21 /* musclecard.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94CF025424AC01B94B21 /* musclecard.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		F52A94D9025424AC01B94B21 /* winscard_msg.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94A80254242101B94B21 /* winscard_msg.h */; };
+		F52A94DA025424AC01B94B21 /* tokenfactory.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94D1025424AC01B94B21 /* tokenfactory.h */; };
+		F52A94DB025424AC01B94B21 /* winscard.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94AC0254242101B94B21 /* winscard.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		F52A94DC025424AC01B94B21 /* dyn_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94940254242101B94B21 /* dyn_generic.h */; };
+		F52A94DD025424AC01B94B21 /* debuglog.h in Headers */ = {isa = PBXBuildFile; fileRef = F52A94930254242101B94B21 /* debuglog.h */; settings = {ATTRIBUTES = (); }; };
+		F52A94DE025424AC01B94B21 /* musclecard.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94CE025424AC01B94B21 /* musclecard.c */; };
+		F52A94DF025424AC01B94B21 /* dyn_macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94950254242101B94B21 /* dyn_macosx.c */; };
+		F52A94E0025424AC01B94B21 /* tokenfactory.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94D0025424AC01B94B21 /* tokenfactory.c */; };
+		F52A94E1025424AC01B94B21 /* tokenparser.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94D2025424AC01B94B21 /* tokenparser.c */; settings = {COMPILER_FLAGS = "-DYY_NO_UNPUT"; }; };
+		F52A94E3025424AC01B94B21 /* debuglog.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94920254242101B94B21 /* debuglog.c */; };
+		F52A94E4025424AC01B94B21 /* winscard_clnt.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94D4025424AC01B94B21 /* winscard_clnt.c */; };
+		F52A94E5025424F101B94B21 /* winscard_msg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52A94A70254242101B94B21 /* winscard_msg.cpp */; };
+		F52A94E7025424F101B94B21 /* sys_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = F52A94A40254242101B94B21 /* sys_unix.c */; };
+		F537A7B40379EB7B01B94948 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = F537A7B30379EB7B01B94948 /* config.h */; };
+		F5448E140379EEA101B94948 /* musclecardApplet.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E120379EEA101B94948 /* musclecardApplet.c */; };
+		F5448E150379EEA101B94948 /* musclecardApplet.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E130379EEA101B94948 /* musclecardApplet.h */; };
+		F5448E180379EEC301B94948 /* cryptoflex.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E160379EEC301B94948 /* cryptoflex.c */; };
+		F5448E190379EEC301B94948 /* cryptoflex.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E170379EEC301B94948 /* cryptoflex.h */; };
+		F5448E1C0379EEDD01B94948 /* commonAccessCard.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E1A0379EEDD01B94948 /* commonAccessCard.c */; };
+		F5448E1D0379EEDD01B94948 /* commonAccessCard.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E1B0379EEDD01B94948 /* commonAccessCard.h */; };
+		F5448E3F0379EF2501B94948 /* cryptoki_unix.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E1E0379EF2501B94948 /* cryptoki_unix.h */; };
+		F5448E400379EF2501B94948 /* cryptoki.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E1F0379EF2501B94948 /* cryptoki.h */; };
+		F5448E410379EF2501B94948 /* p11_crypt.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E200379EF2501B94948 /* p11_crypt.c */; };
+		F5448E420379EF2501B94948 /* p11_digest.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E210379EF2501B94948 /* p11_digest.c */; };
+		F5448E430379EF2501B94948 /* p11_dual.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E220379EF2501B94948 /* p11_dual.c */; };
+		F5448E440379EF2501B94948 /* p11_ext.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E230379EF2501B94948 /* p11_ext.c */; };
+		F5448E450379EF2501B94948 /* p11_general.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E240379EF2501B94948 /* p11_general.c */; };
+		F5448E460379EF2501B94948 /* p11_key.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E250379EF2501B94948 /* p11_key.c */; };
+		F5448E470379EF2501B94948 /* p11_object.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E260379EF2501B94948 /* p11_object.c */; };
+		F5448E480379EF2501B94948 /* p11_parallel.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E270379EF2501B94948 /* p11_parallel.c */; };
+		F5448E490379EF2501B94948 /* p11_random.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E280379EF2501B94948 /* p11_random.c */; };
+		F5448E4A0379EF2501B94948 /* p11_session.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E290379EF2501B94948 /* p11_session.c */; };
+		F5448E4B0379EF2501B94948 /* p11_sign.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E2A0379EF2501B94948 /* p11_sign.c */; };
+		F5448E4C0379EF2501B94948 /* p11_token.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E2B0379EF2501B94948 /* p11_token.c */; };
+		F5448E4D0379EF2501B94948 /* p11_verify.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E2C0379EF2501B94948 /* p11_verify.c */; };
+		F5448E4E0379EF2501B94948 /* p11x_async.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E2D0379EF2501B94948 /* p11x_async.c */; };
+		F5448E4F0379EF2501B94948 /* p11x_bio.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E2E0379EF2501B94948 /* p11x_bio.c */; };
+		F5448E500379EF2501B94948 /* p11x_error.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E2F0379EF2501B94948 /* p11x_error.c */; };
+		F5448E510379EF2501B94948 /* p11x_log.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E300379EF2501B94948 /* p11x_log.c */; };
+		F5448E520379EF2501B94948 /* p11x_msc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E310379EF2501B94948 /* p11x_msc.c */; };
+		F5448E530379EF2501B94948 /* p11x_msc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E320379EF2501B94948 /* p11x_msc.h */; };
+		F5448E540379EF2501B94948 /* p11x_object.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E330379EF2501B94948 /* p11x_object.c */; };
+		F5448E550379EF2501B94948 /* p11x_prefs.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E340379EF2501B94948 /* p11x_prefs.c */; };
+		F5448E560379EF2501B94948 /* p11x_session.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E350379EF2501B94948 /* p11x_session.c */; };
+		F5448E570379EF2501B94948 /* p11x_slot.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E360379EF2501B94948 /* p11x_slot.c */; };
+		F5448E580379EF2501B94948 /* p11x_state.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E370379EF2501B94948 /* p11x_state.c */; };
+		F5448E590379EF2501B94948 /* p11x_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E380379EF2501B94948 /* p11x_thread.c */; };
+		F5448E5B0379EF2501B94948 /* p11x_util.c in Sources */ = {isa = PBXBuildFile; fileRef = F5448E3A0379EF2501B94948 /* p11x_util.c */; };
+		F5448E5C0379EF2501B94948 /* pkcs11.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E3B0379EF2501B94948 /* pkcs11.h */; };
+		F5448E5D0379EF2501B94948 /* pkcs11f.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E3C0379EF2501B94948 /* pkcs11f.h */; };
+		F5448E5E0379EF2501B94948 /* pkcs11t.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E3D0379EF2501B94948 /* pkcs11t.h */; };
+		F5448E5F0379EF2501B94948 /* thread_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = F5448E3E0379EF2501B94948 /* thread_generic.h */; };
+		F5448E6A0379F08001B94948 /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5448E630379F08001B94948 /* PCSC.framework */; };
+		F5448E6B0379F08001B94948 /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5448E630379F08001B94948 /* PCSC.framework */; };
+		F5448E6C0379F08001B94948 /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5448E630379F08001B94948 /* PCSC.framework */; };
+		F5448E6D0379F08001B94948 /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5448E630379F08001B94948 /* PCSC.framework */; };
+		F5448E6E0379F08001B94948 /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5448E630379F08001B94948 /* PCSC.framework */; };
+		F5448E6F0379F08001B94948 /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5448E630379F08001B94948 /* PCSC.framework */; };
+		F5448E760379F15F01B94948 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F5448E750379F15F01B94948 /* libz.dylib */; };
+		F555DF360274962801D2E99F /* powermgt_macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = F555DF350274962801D2E99F /* powermgt_macosx.c */; };
+		F555DF380274968F01D2E99F /* powermgt_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = F555DF370274968F01D2E99F /* powermgt_generic.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBundleTarget section */
+		2CBB605A06CA6944006AA7C8 /* GSCISPlugin */ = {
+			isa = PBXBundleTarget;
+			buildConfigurationList = C27AD1DF0987FCDC001272E0 /* Build configuration list for PBXBundleTarget "GSCISPlugin" */;
+			buildPhases = (
+				2CBB605506CA6944006AA7C8 /* Headers */,
+				2CBB605606CA6944006AA7C8 /* Resources */,
+				2CBB605706CA6944006AA7C8 /* Sources */,
+				2CBB605806CA6944006AA7C8 /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = GSCISPlugin;
+			productInstallPath = /usr/libexec/SmartCardServices/services;
+			productName = GSCISPlugin;
+			productReference = 2CBB605B06CA6944006AA7C8 /* GSCISPlugin.bundle */;
+			productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>gscisPlugin</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>com.apple.gscisplugin</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>GSCISPLUGIN</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>2.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>
+";
+		};
+		F537A7D10379ED7501B94948 /* PKCS11 */ = {
+			isa = PBXBundleTarget;
+			buildConfigurationList = C27AD1D50987FCDC001272E0 /* Build configuration list for PBXBundleTarget "PKCS11" */;
+			buildPhases = (
+				F537A7CC0379ED7501B94948 /* Headers */,
+				F537A7CD0379ED7501B94948 /* Resources */,
+				F537A7CE0379ED7501B94948 /* Sources */,
+				F537A7CF0379ED7501B94948 /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = PKCS11;
+			productInstallPath = /usr/libexec/SmartCardServices/pkcs11;
+			productName = pkcs11;
+			productReference = F537A7D20379ED7501B94948 /* pkcs11.bundle */;
+			productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string></string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>com.apple.pkcs11</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>PKCS11</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>6.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>
+";
+		};
+		F5448E020379EE2A01B94948 /* MCardPlugin */ = {
+			isa = PBXBundleTarget;
+			buildConfigurationList = C27AD1DA0987FCDC001272E0 /* Build configuration list for PBXBundleTarget "MCardPlugin" */;
+			buildPhases = (
+				F5448DFD0379EE2A01B94948 /* Headers */,
+				F5448DFE0379EE2A01B94948 /* Resources */,
+				F5448DFF0379EE2A01B94948 /* Sources */,
+				F5448E000379EE2A01B94948 /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = MCardPlugin;
+			productInstallPath = /usr/libexec/SmartCardServices/services;
+			productName = MCardPlugin;
+			productReference = F5448E030379EE2A01B94948 /* mscMuscleCard.bundle */;
+			productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>mscMuscleCard</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>com.apple.mcardplugin</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>MCARDPLUGIN</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>6.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>spAtrValue</key>
+	<string>3B751300009C02020102</string>
+	<key>spDefaultApplication</key>
+	<string>A00000000101</string>
+	<key>spProductName</key>
+	<string>MuscleCard Applet</string>
+	<key>spVendorName</key>
+	<string>MUSCLE</string>
+</dict>
+</plist>
+";
+		};
+		F5448E090379EE3601B94948 /* CACPlugin */ = {
+			isa = PBXBundleTarget;
+			buildConfigurationList = C27AD1E40987FCDC001272E0 /* Build configuration list for PBXBundleTarget "CACPlugin" */;
+			buildPhases = (
+				F5448E040379EE3601B94948 /* Headers */,
+				F5448E050379EE3601B94948 /* Resources */,
+				F5448E060379EE3601B94948 /* Sources */,
+				F5448E070379EE3601B94948 /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = CACPlugin;
+			productInstallPath = /usr/libexec/SmartCardServices/services;
+			productName = CACPlugin;
+			productReference = F5448E0A0379EE3601B94948 /* commonAccessCard.bundle */;
+			productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>commonAccessCard</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>com.apple.cacplugin</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>CACPLUGIN</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>6.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>spAtrValue</key>
+	<array>
+		<string>3B6500009C02020102</string>
+		<string>3B7D110000003180718E6486D60100819000</string>
+		<string>3B7F1100000031C053CAC4016452D90400829000</string>
+		<string>3B6500009C02020702</string>
+	</array>
+	<key>spDefaultApplication</key>
+	<string>A0000000790101</string>
+	<key>spProductName</key>
+	<string>Common Access Card</string>
+	<key>spVendorName</key>
+	<string>Department of Defense</string>
+</dict>
+</plist>
+";
+		};
+		F5448E100379EE6401B94948 /* CFlexPlugin */ = {
+			isa = PBXBundleTarget;
+			buildConfigurationList = C27AD1E90987FCDC001272E0 /* Build configuration list for PBXBundleTarget "CFlexPlugin" */;
+			buildPhases = (
+				F5448E0B0379EE6401B94948 /* Headers */,
+				F5448E0C0379EE6401B94948 /* Resources */,
+				F5448E0D0379EE6401B94948 /* Sources */,
+				F5448E0E0379EE6401B94948 /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = CFlexPlugin;
+			productInstallPath = /usr/libexec/SmartCardServices/services;
+			productName = CFlexPlugin;
+			productReference = F5448E110379EE6401B94948 /* slbCryptoflex.bundle */;
+			productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>slbCryptoflex</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>com.apple.cflexplugin</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>CFLEXPLUGIN</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>6.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>spAtrValue</key>
+	<string>3B959440FF6301010201</string>
+	<key>spDefaultApplication</key>
+	<string>A00000000101</string>
+	<key>spProductName</key>
+	<string>Cryptoflex 16K</string>
+	<key>spVendorName</key>
+	<string>SchlumbergerSema</string>
+</dict>
+</plist>
+";
+		};
+/* End PBXBundleTarget section */
+
+/* Begin PBXContainerItemProxy section */
+		2CBB607406CA6DDE006AA7C8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2CBB605A06CA6944006AA7C8;
+			remoteInfo = GSCISPlugin;
+		};
+		4CFE9C05059254C8007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F5448E020379EE2A01B94948;
+			remoteInfo = MCardPlugin;
+		};
+		4CFE9C06059254C9007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F5294A800090C73501CD285A;
+			remoteInfo = pcscd;
+		};
+		4CFE9C07059254C9007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F5448E100379EE6401B94948;
+			remoteInfo = CFlexPlugin;
+		};
+		4CFE9C09059254C9007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F538896903953B79012F6BBF;
+			remoteInfo = InstallPhase;
+		};
+		4CFE9C0A059254C9007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F5448E090379EE3601B94948;
+			remoteInfo = CACPlugin;
+		};
+		4CFE9C0B059254C9007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F537A7D10379ED7501B94948;
+			remoteInfo = PKCS11;
+		};
+		4CFE9C0C059254C9007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F51121270272F895017BB957;
+			remoteInfo = pcsctool;
+		};
+		4CFE9C0D059254C9007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F5294AD40090CAE601CD285A;
+			remoteInfo = pcsctest;
+		};
+		4CFE9C0E059254C9007119DE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F5294A4F0090C4CA01CD285A /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F52A93D402541D8C01B94B21;
+			remoteInfo = PCSC;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+		2CBB605B06CA6944006AA7C8 /* GSCISPlugin.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GSCISPlugin.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+		2CBB606306CA69F9006AA7C8 /* GSCISPlugin.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = GSCISPlugin.c; path = src/GSCISPlugin/GSCISPlugin.c; sourceTree = SOURCE_ROOT; };
+		2CBB606406CA69F9006AA7C8 /* GSCISPlugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = GSCISPlugin.h; path = src/GSCISPlugin/GSCISPlugin.h; sourceTree = SOURCE_ROOT; };
+		2CC9AB9A06CC036D0048A811 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+		2CC9ABC806CC03A10048A811 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
+		4CB55A760592598500B25B27 /* Makefile.installPhase */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.installPhase; sourceTree = "<group>"; };
+		5236DD1C0B9DDBD7007CEF56 /* readerstate.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = readerstate.cpp; path = src/PCSC/readerstate.cpp; sourceTree = "<group>"; };
+		5236DD1D0B9DDBD7007CEF56 /* readerstate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = readerstate.h; path = src/PCSC/readerstate.h; sourceTree = "<group>"; };
+		527CF60A0AA5192B007589FF /* pcscdmonitor.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pcscdmonitor.cpp; path = src/PCSC/pcscdmonitor.cpp; sourceTree = "<group>"; };
+		527CF60B0AA5192B007589FF /* pcscdmonitor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = pcscdmonitor.h; path = src/PCSC/pcscdmonitor.h; sourceTree = "<group>"; };
+		527CF60C0AA5192B007589FF /* pcscdserver.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pcscdserver.cpp; path = src/PCSC/pcscdserver.cpp; sourceTree = "<group>"; };
+		527CF60D0AA5192B007589FF /* pcscdserver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = pcscdserver.h; path = src/PCSC/pcscdserver.h; sourceTree = "<group>"; };
+		5286293C0A87EA8E004FE8DC /* hotplug_macosx.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = hotplug_macosx.cpp; path = src/PCSC/hotplug_macosx.cpp; sourceTree = "<group>"; };
+		5286293D0A87EA8E004FE8DC /* PCSCDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PCSCDevice.cpp; path = src/PCSC/PCSCDevice.cpp; sourceTree = "<group>"; };
+		5286293E0A87EA8E004FE8DC /* PCSCDevice.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PCSCDevice.h; path = src/PCSC/PCSCDevice.h; sourceTree = "<group>"; };
+		5286293F0A87EA8E004FE8DC /* PCSCDriverBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PCSCDriverBundle.cpp; path = src/PCSC/PCSCDriverBundle.cpp; sourceTree = "<group>"; };
+		528629400A87EA8E004FE8DC /* PCSCDriverBundle.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PCSCDriverBundle.h; path = src/PCSC/PCSCDriverBundle.h; sourceTree = "<group>"; };
+		528629410A87EA8E004FE8DC /* PCSCDriverBundles.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PCSCDriverBundles.cpp; path = src/PCSC/PCSCDriverBundles.cpp; sourceTree = "<group>"; };
+		528629420A87EA8E004FE8DC /* PCSCDriverBundles.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PCSCDriverBundles.h; path = src/PCSC/PCSCDriverBundles.h; sourceTree = "<group>"; };
+		52D00D1A0A9252350093277A /* reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reader.h; path = src/PCSC/reader.h; sourceTree = "<group>"; };
+		52D00D1B0A9252350093277A /* reader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reader.cpp; path = src/PCSC/reader.cpp; sourceTree = "<group>"; };
+		52D2492C0BA07E1100F9827A /* winscard_msg_srv.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = winscard_msg_srv.c; path = src/PCSC/winscard_msg_srv.c; sourceTree = "<group>"; };
+		52D58C080A87FEA000DC3F19 /* security_utilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = security_utilities.framework; path = /usr/local/SecurityPieces/Frameworks/security_utilities.framework; sourceTree = "<absolute>"; };
+		52DBCAAE0BB851C8007D06A5 /* PCSC.exp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.exports; name = PCSC.exp; path = src/PCSC/PCSC.exp; sourceTree = "<group>"; };
+		52E0D59D0BA7006D008DFDDF /* winscard.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = winscard.c; path = src/PCSC/winscard.c; sourceTree = "<group>"; };
+		C2F2094A0662B851001DFD06 /* sys_macosx.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = sys_macosx.cpp; path = src/PCSC/sys_macosx.cpp; sourceTree = "<group>"; };
+		F503CACD025425E601B94B21 /* testpcsc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testpcsc.c; path = src/PCSC/testpcsc.c; sourceTree = "<group>"; };
+		F503CACE025425E601B94B21 /* muscletest.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = muscletest.c; path = src/PCSC/muscletest.c; sourceTree = "<group>"; };
+		F503CADB025428F601B94B21 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+		F503CADC025428F601B94B21 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
+		F503CADF0254294101B94B21 /* libl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libl.a; path = /usr/lib/libl.a; sourceTree = "<absolute>"; };
+		F51121260272F895017BB957 /* pcsctool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = pcsctool; sourceTree = BUILT_PRODUCTS_DIR; };
+		F511212C0272F8D9017BB957 /* bundleTool.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bundleTool.c; path = src/PCSC/utils/bundleTool.c; sourceTree = "<group>"; };
+		F5294A7E0090C73501CD285A /* pcscd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = pcscd; sourceTree = BUILT_PRODUCTS_DIR; };
+		F5294AD30090CAE601CD285A /* pcsctest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = pcsctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		F52A93D102541D8C01B94B21 /* PCSC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PCSC.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		F52A94510254232701B94B21 /* atrhandler.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = atrhandler.c; path = src/PCSC/atrhandler.c; sourceTree = SOURCE_ROOT; };
+		F52A948F0254242101B94B21 /* atrhandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = atrhandler.h; path = src/PCSC/atrhandler.h; sourceTree = SOURCE_ROOT; };
+		F52A94900254242101B94B21 /* configfile.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = configfile.c; path = src/PCSC/configfile.c; sourceTree = SOURCE_ROOT; };
+		F52A94910254242101B94B21 /* configfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = configfile.h; path = src/PCSC/configfile.h; sourceTree = SOURCE_ROOT; };
+		F52A94920254242101B94B21 /* debuglog.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = debuglog.c; path = src/PCSC/debuglog.c; sourceTree = SOURCE_ROOT; };
+		F52A94930254242101B94B21 /* debuglog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debuglog.h; path = src/PCSC/debuglog.h; sourceTree = SOURCE_ROOT; };
+		F52A94940254242101B94B21 /* dyn_generic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyn_generic.h; path = src/PCSC/dyn_generic.h; sourceTree = SOURCE_ROOT; };
+		F52A94950254242101B94B21 /* dyn_macosx.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dyn_macosx.c; path = src/PCSC/dyn_macosx.c; sourceTree = SOURCE_ROOT; };
+		F52A94960254242101B94B21 /* eventhandler.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = eventhandler.cpp; path = src/PCSC/eventhandler.cpp; sourceTree = "<group>"; };
+		F52A94970254242101B94B21 /* eventhandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = eventhandler.h; path = src/PCSC/eventhandler.h; sourceTree = SOURCE_ROOT; };
+		F52A94990254242101B94B21 /* hotplug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hotplug.h; path = src/PCSC/hotplug.h; sourceTree = SOURCE_ROOT; };
+		F52A949A0254242101B94B21 /* ifdhandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ifdhandler.h; path = src/PCSC/ifdhandler.h; sourceTree = SOURCE_ROOT; };
+		F52A949B0254242101B94B21 /* ifdwrapper.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ifdwrapper.c; path = src/PCSC/ifdwrapper.c; sourceTree = SOURCE_ROOT; };
+		F52A949C0254242101B94B21 /* ifdwrapper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ifdwrapper.h; path = src/PCSC/ifdwrapper.h; sourceTree = SOURCE_ROOT; };
+		F52A949D0254242101B94B21 /* pcscdaemon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pcscdaemon.c; path = src/PCSC/pcscdaemon.c; sourceTree = "<group>"; };
+		F52A949E0254242101B94B21 /* pcsclite.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = pcsclite.h; path = src/PCSC/pcsclite.h; sourceTree = SOURCE_ROOT; };
+		F52A949F0254242101B94B21 /* prothandler.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = prothandler.c; path = src/PCSC/prothandler.c; sourceTree = SOURCE_ROOT; };
+		F52A94A00254242101B94B21 /* prothandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = prothandler.h; path = src/PCSC/prothandler.h; sourceTree = SOURCE_ROOT; };
+		F52A94A10254242101B94B21 /* readerfactory.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = readerfactory.c; path = src/PCSC/readerfactory.c; sourceTree = "<group>"; };
+		F52A94A20254242101B94B21 /* readerfactory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = readerfactory.h; path = src/PCSC/readerfactory.h; sourceTree = "<group>"; };
+		F52A94A30254242101B94B21 /* sys_generic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = sys_generic.h; path = src/PCSC/sys_generic.h; sourceTree = SOURCE_ROOT; };
+		F52A94A40254242101B94B21 /* sys_unix.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = sys_unix.c; path = src/PCSC/sys_unix.c; sourceTree = SOURCE_ROOT; };
+		F52A94A50254242101B94B21 /* thread_generic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = thread_generic.h; path = src/PCSC/thread_generic.h; sourceTree = SOURCE_ROOT; };
+		F52A94A60254242101B94B21 /* thread_macosx.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = thread_macosx.c; path = src/PCSC/thread_macosx.c; sourceTree = SOURCE_ROOT; };
+		F52A94A70254242101B94B21 /* winscard_msg.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = winscard_msg.cpp; path = src/PCSC/winscard_msg.cpp; sourceTree = "<group>"; };
+		F52A94A80254242101B94B21 /* winscard_msg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = winscard_msg.h; path = src/PCSC/winscard_msg.h; sourceTree = SOURCE_ROOT; };
+		F52A94A90254242101B94B21 /* winscard_svc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = winscard_svc.c; path = src/PCSC/winscard_svc.c; sourceTree = SOURCE_ROOT; };
+		F52A94AA0254242101B94B21 /* winscard_svc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = winscard_svc.h; path = src/PCSC/winscard_svc.h; sourceTree = SOURCE_ROOT; };
+		F52A94AC0254242101B94B21 /* winscard.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = winscard.h; path = src/PCSC/winscard.h; sourceTree = SOURCE_ROOT; };
+		F52A94AD0254242101B94B21 /* wintypes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = wintypes.h; path = src/PCSC/wintypes.h; sourceTree = SOURCE_ROOT; };
+		F52A94CD025424AC01B94B21 /* mscdefines.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = mscdefines.h; path = src/PCSC/mscdefines.h; sourceTree = SOURCE_ROOT; };
+		F52A94CE025424AC01B94B21 /* musclecard.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = musclecard.c; path = src/PCSC/musclecard.c; sourceTree = SOURCE_ROOT; };
+		F52A94CF025424AC01B94B21 /* musclecard.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = musclecard.h; path = src/PCSC/musclecard.h; sourceTree = SOURCE_ROOT; };
+		F52A94D0025424AC01B94B21 /* tokenfactory.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = tokenfactory.c; path = src/PCSC/tokenfactory.c; sourceTree = SOURCE_ROOT; };
+		F52A94D1025424AC01B94B21 /* tokenfactory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = tokenfactory.h; path = src/PCSC/tokenfactory.h; sourceTree = SOURCE_ROOT; };
+		F52A94D2025424AC01B94B21 /* tokenparser.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = tokenparser.c; path = src/PCSC/tokenparser.c; sourceTree = SOURCE_ROOT; };
+		F52A94D4025424AC01B94B21 /* winscard_clnt.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = winscard_clnt.c; path = src/PCSC/winscard_clnt.c; sourceTree = SOURCE_ROOT; };
+		F537A7B30379EB7B01B94948 /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = config.h; path = src/PCSC/config.h; sourceTree = SOURCE_ROOT; };
+		F537A7D20379ED7501B94948 /* pkcs11.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = pkcs11.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+		F5448E030379EE2A01B94948 /* mscMuscleCard.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = mscMuscleCard.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+		F5448E0A0379EE3601B94948 /* commonAccessCard.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = commonAccessCard.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+		F5448E110379EE6401B94948 /* slbCryptoflex.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = slbCryptoflex.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+		F5448E120379EEA101B94948 /* musclecardApplet.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = musclecardApplet.c; path = src/MCardPlugin/musclecardApplet.c; sourceTree = SOURCE_ROOT; };
+		F5448E130379EEA101B94948 /* musclecardApplet.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = musclecardApplet.h; path = src/MCardPlugin/musclecardApplet.h; sourceTree = SOURCE_ROOT; };
+		F5448E160379EEC301B94948 /* cryptoflex.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = cryptoflex.c; path = src/CFlexPlugin/cryptoflex.c; sourceTree = SOURCE_ROOT; };
+		F5448E170379EEC301B94948 /* cryptoflex.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cryptoflex.h; path = src/CFlexPlugin/cryptoflex.h; sourceTree = SOURCE_ROOT; };
+		F5448E1A0379EEDD01B94948 /* commonAccessCard.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = commonAccessCard.c; path = src/CACPlugin/commonAccessCard.c; sourceTree = SOURCE_ROOT; };
+		F5448E1B0379EEDD01B94948 /* commonAccessCard.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = commonAccessCard.h; path = src/CACPlugin/commonAccessCard.h; sourceTree = SOURCE_ROOT; };
+		F5448E1E0379EF2501B94948 /* cryptoki_unix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cryptoki_unix.h; path = src/PKCS11/cryptoki_unix.h; sourceTree = SOURCE_ROOT; };
+		F5448E1F0379EF2501B94948 /* cryptoki.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cryptoki.h; path = src/PKCS11/cryptoki.h; sourceTree = SOURCE_ROOT; };
+		F5448E200379EF2501B94948 /* p11_crypt.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_crypt.c; path = src/PKCS11/p11_crypt.c; sourceTree = SOURCE_ROOT; };
+		F5448E210379EF2501B94948 /* p11_digest.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_digest.c; path = src/PKCS11/p11_digest.c; sourceTree = SOURCE_ROOT; };
+		F5448E220379EF2501B94948 /* p11_dual.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_dual.c; path = src/PKCS11/p11_dual.c; sourceTree = SOURCE_ROOT; };
+		F5448E230379EF2501B94948 /* p11_ext.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_ext.c; path = src/PKCS11/p11_ext.c; sourceTree = SOURCE_ROOT; };
+		F5448E240379EF2501B94948 /* p11_general.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_general.c; path = src/PKCS11/p11_general.c; sourceTree = SOURCE_ROOT; };
+		F5448E250379EF2501B94948 /* p11_key.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_key.c; path = src/PKCS11/p11_key.c; sourceTree = SOURCE_ROOT; };
+		F5448E260379EF2501B94948 /* p11_object.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_object.c; path = src/PKCS11/p11_object.c; sourceTree = SOURCE_ROOT; };
+		F5448E270379EF2501B94948 /* p11_parallel.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_parallel.c; path = src/PKCS11/p11_parallel.c; sourceTree = SOURCE_ROOT; };
+		F5448E280379EF2501B94948 /* p11_random.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_random.c; path = src/PKCS11/p11_random.c; sourceTree = SOURCE_ROOT; };
+		F5448E290379EF2501B94948 /* p11_session.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_session.c; path = src/PKCS11/p11_session.c; sourceTree = SOURCE_ROOT; };
+		F5448E2A0379EF2501B94948 /* p11_sign.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_sign.c; path = src/PKCS11/p11_sign.c; sourceTree = SOURCE_ROOT; };
+		F5448E2B0379EF2501B94948 /* p11_token.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_token.c; path = src/PKCS11/p11_token.c; sourceTree = SOURCE_ROOT; };
+		F5448E2C0379EF2501B94948 /* p11_verify.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11_verify.c; path = src/PKCS11/p11_verify.c; sourceTree = SOURCE_ROOT; };
+		F5448E2D0379EF2501B94948 /* p11x_async.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_async.c; path = src/PKCS11/p11x_async.c; sourceTree = SOURCE_ROOT; };
+		F5448E2E0379EF2501B94948 /* p11x_bio.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_bio.c; path = src/PKCS11/p11x_bio.c; sourceTree = SOURCE_ROOT; };
+		F5448E2F0379EF2501B94948 /* p11x_error.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_error.c; path = src/PKCS11/p11x_error.c; sourceTree = SOURCE_ROOT; };
+		F5448E300379EF2501B94948 /* p11x_log.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_log.c; path = src/PKCS11/p11x_log.c; sourceTree = SOURCE_ROOT; };
+		F5448E310379EF2501B94948 /* p11x_msc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_msc.c; path = src/PKCS11/p11x_msc.c; sourceTree = SOURCE_ROOT; };
+		F5448E320379EF2501B94948 /* p11x_msc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = p11x_msc.h; path = src/PKCS11/p11x_msc.h; sourceTree = SOURCE_ROOT; };
+		F5448E330379EF2501B94948 /* p11x_object.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_object.c; path = src/PKCS11/p11x_object.c; sourceTree = SOURCE_ROOT; };
+		F5448E340379EF2501B94948 /* p11x_prefs.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_prefs.c; path = src/PKCS11/p11x_prefs.c; sourceTree = SOURCE_ROOT; };
+		F5448E350379EF2501B94948 /* p11x_session.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_session.c; path = src/PKCS11/p11x_session.c; sourceTree = SOURCE_ROOT; };
+		F5448E360379EF2501B94948 /* p11x_slot.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_slot.c; path = src/PKCS11/p11x_slot.c; sourceTree = SOURCE_ROOT; };
+		F5448E370379EF2501B94948 /* p11x_state.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_state.c; path = src/PKCS11/p11x_state.c; sourceTree = SOURCE_ROOT; };
+		F5448E380379EF2501B94948 /* p11x_thread.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_thread.c; path = src/PKCS11/p11x_thread.c; sourceTree = SOURCE_ROOT; };
+		F5448E3A0379EF2501B94948 /* p11x_util.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = p11x_util.c; path = src/PKCS11/p11x_util.c; sourceTree = SOURCE_ROOT; };
+		F5448E3B0379EF2501B94948 /* pkcs11.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = pkcs11.h; path = src/PKCS11/pkcs11.h; sourceTree = SOURCE_ROOT; };
+		F5448E3C0379EF2501B94948 /* pkcs11f.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = pkcs11f.h; path = src/PKCS11/pkcs11f.h; sourceTree = SOURCE_ROOT; };
+		F5448E3D0379EF2501B94948 /* pkcs11t.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = pkcs11t.h; path = src/PKCS11/pkcs11t.h; sourceTree = SOURCE_ROOT; };
+		F5448E3E0379EF2501B94948 /* thread_generic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = thread_generic.h; path = src/PKCS11/thread_generic.h; sourceTree = SOURCE_ROOT; };
+		F5448E630379F08001B94948 /* PCSC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PCSC.framework; path = /System/Library/Frameworks/PCSC.framework; sourceTree = "<absolute>"; };
+		F5448E750379F15F01B94948 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.1.1.3.dylib; sourceTree = "<absolute>"; };
+		F555DF350274962801D2E99F /* powermgt_macosx.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = powermgt_macosx.c; path = src/PCSC/powermgt_macosx.c; sourceTree = SOURCE_ROOT; };
+		F555DF370274968F01D2E99F /* powermgt_generic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = powermgt_generic.h; path = src/PCSC/powermgt_generic.h; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworkTarget section */
+		F52A93D402541D8C01B94B21 /* PCSC */ = {
+			isa = PBXFrameworkTarget;
+			buildConfigurationList = C27AD1C10987FCDB001272E0 /* Build configuration list for PBXFrameworkTarget "PCSC" */;
+			buildPhases = (
+				F52A93D502541D8C01B94B21 /* Headers */,
+				F52A93D602541D8C01B94B21 /* Resources */,
+				F52A93D702541D8C01B94B21 /* Sources */,
+				F52A93D802541D8C01B94B21 /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = PCSC;
+			productInstallPath = /System/Library/Frameworks;
+			productName = PCSC;
+			productReference = F52A93D102541D8C01B94B21 /* PCSC.framework */;
+			productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>PCSC</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>com.apple.pcsc</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>7.0</string>
+	<key>CFBundleName</key>
+	<string>PCSC</string>
+	<key>CFBundlePackageType</key>
+	<string>FMWK</string>
+	<key>CFBundleShortVersionString</key>
+	<string>6.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>
+";
+		};
+/* End PBXFrameworkTarget section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		2CBB605806CA6944006AA7C8 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2CC9AB8406CC02F30048A811 /* PCSC.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F511212A0272F895017BB957 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E6E0379F08001B94948 /* PCSC.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5294A830090C73501CD285A /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F503CADD025428F601B94B21 /* CoreFoundation.framework in Frameworks */,
+				F503CADE025428F601B94B21 /* IOKit.framework in Frameworks */,
+				F503CAE00254294101B94B21 /* libl.a in Frameworks */,
+				52D58C090A87FEA000DC3F19 /* security_utilities.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5294AD70090CAE601CD285A /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E6A0379F08001B94948 /* PCSC.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F52A93D802541D8C01B94B21 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				52C85D900B9FA79F002DA856 /* security_utilities.framework in Frameworks */,
+				F503CAE502542A9201B94B21 /* CoreFoundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F537A7CF0379ED7501B94948 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E6D0379F08001B94948 /* PCSC.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E000379EE2A01B94948 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E6C0379F08001B94948 /* PCSC.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E070379EE3601B94948 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E6B0379F08001B94948 /* PCSC.framework in Frameworks */,
+				F5448E760379F15F01B94948 /* libz.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E0E0379EE6401B94948 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E6F0379F08001B94948 /* PCSC.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		2CBB605406CA680F006AA7C8 /* GSCISPlugin */ = {
+			isa = PBXGroup;
+			children = (
+				2CBB606306CA69F9006AA7C8 /* GSCISPlugin.c */,
+				2CBB606406CA69F9006AA7C8 /* GSCISPlugin.h */,
+			);
+			name = GSCISPlugin;
+			sourceTree = "<group>";
+		};
+		527CF6040AA51879007589FF /* pcscd */ = {
+			isa = PBXGroup;
+			children = (
+				5236DD1C0B9DDBD7007CEF56 /* readerstate.cpp */,
+				5236DD1D0B9DDBD7007CEF56 /* readerstate.h */,
+				F52A949D0254242101B94B21 /* pcscdaemon.c */,
+				527CF60A0AA5192B007589FF /* pcscdmonitor.cpp */,
+				527CF60B0AA5192B007589FF /* pcscdmonitor.h */,
+				527CF60C0AA5192B007589FF /* pcscdserver.cpp */,
+				527CF60D0AA5192B007589FF /* pcscdserver.h */,
+				5286293C0A87EA8E004FE8DC /* hotplug_macosx.cpp */,
+				5286293D0A87EA8E004FE8DC /* PCSCDevice.cpp */,
+				5286293E0A87EA8E004FE8DC /* PCSCDevice.h */,
+				5286293F0A87EA8E004FE8DC /* PCSCDriverBundle.cpp */,
+				528629400A87EA8E004FE8DC /* PCSCDriverBundle.h */,
+				528629410A87EA8E004FE8DC /* PCSCDriverBundles.cpp */,
+				528629420A87EA8E004FE8DC /* PCSCDriverBundles.h */,
+				F52A94A10254242101B94B21 /* readerfactory.c */,
+				F52A94A20254242101B94B21 /* readerfactory.h */,
+				52D00D1A0A9252350093277A /* reader.h */,
+				52D00D1B0A9252350093277A /* reader.cpp */,
+			);
+			name = pcscd;
+			sourceTree = "<group>";
+		};
+		527CF6070AA51881007589FF /* framework */ = {
+			isa = PBXGroup;
+			children = (
+				52DBCAAE0BB851C8007D06A5 /* PCSC.exp */,
+			);
+			name = framework;
+			sourceTree = "<group>";
+		};
+		527CF6240AA51B07007589FF /* tools */ = {
+			isa = PBXGroup;
+			children = (
+				F503CACD025425E601B94B21 /* testpcsc.c */,
+				F503CACE025425E601B94B21 /* muscletest.c */,
+				F511212C0272F8D9017BB957 /* bundleTool.c */,
+			);
+			name = tools;
+			sourceTree = "<group>";
+		};
+		F5294A500090C4CA01CD285A = {
+			isa = PBXGroup;
+			children = (
+				52D58C080A87FEA000DC3F19 /* security_utilities.framework */,
+				F538896A0397E93B012F6BBF /* InstallPhase */,
+				F537A7CB0379ECEB01B94948 /* MCardPlugin */,
+				2CBB605406CA680F006AA7C8 /* GSCISPlugin */,
+				F537A7CA0379ECE301B94948 /* CFlexPlugin */,
+				F537A7C90379ECDC01B94948 /* CACPlugin */,
+				F537A7C80379ECD501B94948 /* PKCS11 */,
+				F537A7B50379EB8B01B94948 /* PCSC */,
+				F5294A520090C5DF01CD285A /* Products */,
+				F5448E630379F08001B94948 /* PCSC.framework */,
+				2CC9AB9A06CC036D0048A811 /* CoreFoundation.framework */,
+				2CC9ABC806CC03A10048A811 /* IOKit.framework */,
+			);
+			sourceTree = "<group>";
+		};
+		F5294A520090C5DF01CD285A /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				F5294A7E0090C73501CD285A /* pcscd */,
+				F5294AD30090CAE601CD285A /* pcsctest */,
+				F52A93D102541D8C01B94B21 /* PCSC.framework */,
+				F51121260272F895017BB957 /* pcsctool */,
+				F537A7D20379ED7501B94948 /* pkcs11.bundle */,
+				F5448E030379EE2A01B94948 /* mscMuscleCard.bundle */,
+				F5448E0A0379EE3601B94948 /* commonAccessCard.bundle */,
+				F5448E110379EE6401B94948 /* slbCryptoflex.bundle */,
+				2CBB605B06CA6944006AA7C8 /* GSCISPlugin.bundle */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		F537A7B50379EB8B01B94948 /* PCSC */ = {
+			isa = PBXGroup;
+			children = (
+				527CF6240AA51B07007589FF /* tools */,
+				527CF6070AA51881007589FF /* framework */,
+				527CF6040AA51879007589FF /* pcscd */,
+				F52A94510254232701B94B21 /* atrhandler.c */,
+				F52A948F0254242101B94B21 /* atrhandler.h */,
+				F52A94900254242101B94B21 /* configfile.c */,
+				F52A94910254242101B94B21 /* configfile.h */,
+				F52A94920254242101B94B21 /* debuglog.c */,
+				F52A94930254242101B94B21 /* debuglog.h */,
+				F52A94940254242101B94B21 /* dyn_generic.h */,
+				F52A94950254242101B94B21 /* dyn_macosx.c */,
+				F52A94960254242101B94B21 /* eventhandler.cpp */,
+				F52A94970254242101B94B21 /* eventhandler.h */,
+				F52A94990254242101B94B21 /* hotplug.h */,
+				F52A949A0254242101B94B21 /* ifdhandler.h */,
+				F52A949B0254242101B94B21 /* ifdwrapper.c */,
+				F52A949C0254242101B94B21 /* ifdwrapper.h */,
+				F52A949E0254242101B94B21 /* pcsclite.h */,
+				F52A949F0254242101B94B21 /* prothandler.c */,
+				F52A94A00254242101B94B21 /* prothandler.h */,
+				F52A94A30254242101B94B21 /* sys_generic.h */,
+				F52A94A40254242101B94B21 /* sys_unix.c */,
+				C2F2094A0662B851001DFD06 /* sys_macosx.cpp */,
+				F52A94A50254242101B94B21 /* thread_generic.h */,
+				F52A94A60254242101B94B21 /* thread_macosx.c */,
+				52E0D59D0BA7006D008DFDDF /* winscard.c */,
+				F52A94A70254242101B94B21 /* winscard_msg.cpp */,
+				F52A94A80254242101B94B21 /* winscard_msg.h */,
+				F52A94A90254242101B94B21 /* winscard_svc.c */,
+				52D2492C0BA07E1100F9827A /* winscard_msg_srv.c */,
+				F52A94AA0254242101B94B21 /* winscard_svc.h */,
+				F52A94CD025424AC01B94B21 /* mscdefines.h */,
+				F52A94AC0254242101B94B21 /* winscard.h */,
+				F52A94CF025424AC01B94B21 /* musclecard.h */,
+				F52A94AD0254242101B94B21 /* wintypes.h */,
+				F52A94CE025424AC01B94B21 /* musclecard.c */,
+				F555DF370274968F01D2E99F /* powermgt_generic.h */,
+				F555DF350274962801D2E99F /* powermgt_macosx.c */,
+				F52A94D0025424AC01B94B21 /* tokenfactory.c */,
+				F52A94D1025424AC01B94B21 /* tokenfactory.h */,
+				F52A94D2025424AC01B94B21 /* tokenparser.c */,
+				F52A94D4025424AC01B94B21 /* winscard_clnt.c */,
+				F537A7B30379EB7B01B94948 /* config.h */,
+				F503CADF0254294101B94B21 /* libl.a */,
+				F503CADC025428F601B94B21 /* IOKit.framework */,
+				F503CADB025428F601B94B21 /* CoreFoundation.framework */,
+			);
+			name = PCSC;
+			sourceTree = "<group>";
+		};
+		F537A7C80379ECD501B94948 /* PKCS11 */ = {
+			isa = PBXGroup;
+			children = (
+				F5448E1E0379EF2501B94948 /* cryptoki_unix.h */,
+				F5448E1F0379EF2501B94948 /* cryptoki.h */,
+				F5448E200379EF2501B94948 /* p11_crypt.c */,
+				F5448E210379EF2501B94948 /* p11_digest.c */,
+				F5448E220379EF2501B94948 /* p11_dual.c */,
+				F5448E230379EF2501B94948 /* p11_ext.c */,
+				F5448E240379EF2501B94948 /* p11_general.c */,
+				F5448E250379EF2501B94948 /* p11_key.c */,
+				F5448E260379EF2501B94948 /* p11_object.c */,
+				F5448E270379EF2501B94948 /* p11_parallel.c */,
+				F5448E280379EF2501B94948 /* p11_random.c */,
+				F5448E290379EF2501B94948 /* p11_session.c */,
+				F5448E2A0379EF2501B94948 /* p11_sign.c */,
+				F5448E2B0379EF2501B94948 /* p11_token.c */,
+				F5448E2C0379EF2501B94948 /* p11_verify.c */,
+				F5448E2D0379EF2501B94948 /* p11x_async.c */,
+				F5448E2E0379EF2501B94948 /* p11x_bio.c */,
+				F5448E2F0379EF2501B94948 /* p11x_error.c */,
+				F5448E300379EF2501B94948 /* p11x_log.c */,
+				F5448E310379EF2501B94948 /* p11x_msc.c */,
+				F5448E320379EF2501B94948 /* p11x_msc.h */,
+				F5448E330379EF2501B94948 /* p11x_object.c */,
+				F5448E340379EF2501B94948 /* p11x_prefs.c */,
+				F5448E350379EF2501B94948 /* p11x_session.c */,
+				F5448E360379EF2501B94948 /* p11x_slot.c */,
+				F5448E370379EF2501B94948 /* p11x_state.c */,
+				F5448E380379EF2501B94948 /* p11x_thread.c */,
+				F5448E3A0379EF2501B94948 /* p11x_util.c */,
+				F5448E3B0379EF2501B94948 /* pkcs11.h */,
+				F5448E3C0379EF2501B94948 /* pkcs11f.h */,
+				F5448E3D0379EF2501B94948 /* pkcs11t.h */,
+				F5448E3E0379EF2501B94948 /* thread_generic.h */,
+			);
+			name = PKCS11;
+			sourceTree = "<group>";
+		};
+		F537A7C90379ECDC01B94948 /* CACPlugin */ = {
+			isa = PBXGroup;
+			children = (
+				F5448E1A0379EEDD01B94948 /* commonAccessCard.c */,
+				F5448E1B0379EEDD01B94948 /* commonAccessCard.h */,
+				F5448E750379F15F01B94948 /* libz.dylib */,
+			);
+			name = CACPlugin;
+			sourceTree = "<group>";
+		};
+		F537A7CA0379ECE301B94948 /* CFlexPlugin */ = {
+			isa = PBXGroup;
+			children = (
+				F5448E160379EEC301B94948 /* cryptoflex.c */,
+				F5448E170379EEC301B94948 /* cryptoflex.h */,
+			);
+			name = CFlexPlugin;
+			sourceTree = "<group>";
+		};
+		F537A7CB0379ECEB01B94948 /* MCardPlugin */ = {
+			isa = PBXGroup;
+			children = (
+				F5448E120379EEA101B94948 /* musclecardApplet.c */,
+				F5448E130379EEA101B94948 /* musclecardApplet.h */,
+			);
+			name = MCardPlugin;
+			sourceTree = "<group>";
+		};
+		F538896A0397E93B012F6BBF /* InstallPhase */ = {
+			isa = PBXGroup;
+			children = (
+				4CB55A760592598500B25B27 /* Makefile.installPhase */,
+			);
+			name = InstallPhase;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		2CBB605506CA6944006AA7C8 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2CBB606606CA69F9006AA7C8 /* GSCISPlugin.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F51121280272F895017BB957 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5294A810090C73501CD285A /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F52A94AE0254242101B94B21 /* atrhandler.h in Headers */,
+				F52A94AF0254242101B94B21 /* configfile.h in Headers */,
+				F52A94B00254242101B94B21 /* debuglog.h in Headers */,
+				F52A94B10254242101B94B21 /* dyn_generic.h in Headers */,
+				F52A94B20254242101B94B21 /* eventhandler.h in Headers */,
+				F52A94B30254242101B94B21 /* hotplug.h in Headers */,
+				F52A94B40254242101B94B21 /* ifdhandler.h in Headers */,
+				F52A94B50254242101B94B21 /* ifdwrapper.h in Headers */,
+				F52A94B60254242101B94B21 /* pcsclite.h in Headers */,
+				F52A94B70254242101B94B21 /* prothandler.h in Headers */,
+				F52A94B80254242101B94B21 /* readerfactory.h in Headers */,
+				F52A94B90254242101B94B21 /* sys_generic.h in Headers */,
+				F52A94BA0254242101B94B21 /* thread_generic.h in Headers */,
+				F52A94BB0254242101B94B21 /* winscard_msg.h in Headers */,
+				F52A94BC0254242101B94B21 /* winscard_svc.h in Headers */,
+				F52A94BD0254242101B94B21 /* winscard.h in Headers */,
+				F52A94BE0254242101B94B21 /* wintypes.h in Headers */,
+				F555DF380274968F01D2E99F /* powermgt_generic.h in Headers */,
+				5286294B0A87EA8E004FE8DC /* PCSCDevice.h in Headers */,
+				5286294D0A87EA8E004FE8DC /* PCSCDriverBundle.h in Headers */,
+				5286294F0A87EA8E004FE8DC /* PCSCDriverBundles.h in Headers */,
+				52D00D1C0A9252350093277A /* reader.h in Headers */,
+				527CF60F0AA5192B007589FF /* pcscdmonitor.h in Headers */,
+				527CF6110AA5192B007589FF /* pcscdserver.h in Headers */,
+				5236DD1F0B9DDBD7007CEF56 /* readerstate.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5294AD50090CAE601CD285A /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F52A93D502541D8C01B94B21 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F52A94D5025424AC01B94B21 /* thread_generic.h in Headers */,
+				F52A94D6025424AC01B94B21 /* pcsclite.h in Headers */,
+				F52A94D7025424AC01B94B21 /* mscdefines.h in Headers */,
+				F52A94D8025424AC01B94B21 /* musclecard.h in Headers */,
+				F52A94D9025424AC01B94B21 /* winscard_msg.h in Headers */,
+				F52A94DA025424AC01B94B21 /* tokenfactory.h in Headers */,
+				F52A94DB025424AC01B94B21 /* winscard.h in Headers */,
+				F52A94DC025424AC01B94B21 /* dyn_generic.h in Headers */,
+				F503CAE402542A9201B94B21 /* wintypes.h in Headers */,
+				F52A94DD025424AC01B94B21 /* debuglog.h in Headers */,
+				F537A7B40379EB7B01B94948 /* config.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F537A7CC0379ED7501B94948 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E3F0379EF2501B94948 /* cryptoki_unix.h in Headers */,
+				F5448E400379EF2501B94948 /* cryptoki.h in Headers */,
+				F5448E530379EF2501B94948 /* p11x_msc.h in Headers */,
+				F5448E5C0379EF2501B94948 /* pkcs11.h in Headers */,
+				F5448E5D0379EF2501B94948 /* pkcs11f.h in Headers */,
+				F5448E5E0379EF2501B94948 /* pkcs11t.h in Headers */,
+				F5448E5F0379EF2501B94948 /* thread_generic.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448DFD0379EE2A01B94948 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E150379EEA101B94948 /* musclecardApplet.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E040379EE3601B94948 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E1D0379EEDD01B94948 /* commonAccessCard.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E0B0379EE6401B94948 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E190379EEC301B94948 /* cryptoflex.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXLegacyTarget section */
+		F538896903953B79012F6BBF /* InstallPhase */ = {
+			isa = PBXLegacyTarget;
+			buildArgumentsString = "-f Makefile.installPhase $ALL_SETTINGS $ACTION";
+			buildConfigurationList = C27AD1EE0987FCDC001272E0 /* Build configuration list for PBXLegacyTarget "InstallPhase" */;
+			buildPhases = (
+			);
+			buildToolPath = /usr/bin/gnumake;
+			buildWorkingDirectory = "";
+			dependencies = (
+			);
+			name = InstallPhase;
+			passBuildSettingsInEnvironment = 1;
+			productName = InstallPhase;
+		};
+/* End PBXLegacyTarget section */
+
+/* Begin PBXProject section */
+		F5294A4F0090C4CA01CD285A /* Project object */ = {
+			isa = PBXProject;
+			buildConfigurationList = C27AD1FD0987FCDC001272E0 /* Build configuration list for PBXProject "SmartCardServices" */;
+			compatibilityVersion = "Xcode 2.4";
+			hasScannedForEncodings = 1;
+			mainGroup = F5294A500090C4CA01CD285A;
+			productRefGroup = F5294A520090C5DF01CD285A /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				F5294A510090C54E01CD285A /* World */,
+				F5294A800090C73501CD285A /* pcscd */,
+				F52A93D402541D8C01B94B21 /* PCSC */,
+				F5294AD40090CAE601CD285A /* pcsctest */,
+				F51121270272F895017BB957 /* pcsctool */,
+				F537A7D10379ED7501B94948 /* PKCS11 */,
+				F5448E020379EE2A01B94948 /* MCardPlugin */,
+				F5448E090379EE3601B94948 /* CACPlugin */,
+				F5448E100379EE6401B94948 /* CFlexPlugin */,
+				F538896903953B79012F6BBF /* InstallPhase */,
+				2CBB605A06CA6944006AA7C8 /* GSCISPlugin */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		2CBB605606CA6944006AA7C8 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F52A93D602541D8C01B94B21 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F537A7CD0379ED7501B94948 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448DFE0379EE2A01B94948 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E050379EE3601B94948 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E0C0379EE6401B94948 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		2CBB605706CA6944006AA7C8 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2CBB606506CA69F9006AA7C8 /* GSCISPlugin.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F51121290272F895017BB957 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F511212D0272F8D9017BB957 /* bundleTool.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5294A820090C73501CD285A /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F52A94520254232701B94B21 /* atrhandler.c in Sources */,
+				52C3C14D0BA5D54100436862 /* readerstate.cpp in Sources */,
+				F52A94BF0254242101B94B21 /* configfile.c in Sources */,
+				F52A94C00254242101B94B21 /* debuglog.c in Sources */,
+				F52A94C10254242101B94B21 /* dyn_macosx.c in Sources */,
+				F52A94C20254242101B94B21 /* eventhandler.cpp in Sources */,
+				F52A94C40254242101B94B21 /* ifdwrapper.c in Sources */,
+				F52A94C50254242101B94B21 /* pcscdaemon.c in Sources */,
+				F52A94C60254242101B94B21 /* prothandler.c in Sources */,
+				F52A94C70254242101B94B21 /* readerfactory.c in Sources */,
+				F52A94C90254242101B94B21 /* thread_macosx.c in Sources */,
+				F52A94CA0254242101B94B21 /* winscard_msg.cpp in Sources */,
+				F52A94CB0254242101B94B21 /* winscard_svc.c in Sources */,
+				F555DF360274962801D2E99F /* powermgt_macosx.c in Sources */,
+				C2F2094B0662B851001DFD06 /* sys_macosx.cpp in Sources */,
+				528629490A87EA8E004FE8DC /* hotplug_macosx.cpp in Sources */,
+				5286294A0A87EA8E004FE8DC /* PCSCDevice.cpp in Sources */,
+				5286294C0A87EA8E004FE8DC /* PCSCDriverBundle.cpp in Sources */,
+				5286294E0A87EA8E004FE8DC /* PCSCDriverBundles.cpp in Sources */,
+				52D00D1D0A9252350093277A /* reader.cpp in Sources */,
+				527CF60E0AA5192B007589FF /* pcscdmonitor.cpp in Sources */,
+				527CF6100AA5192B007589FF /* pcscdserver.cpp in Sources */,
+				52D2492D0BA07E1100F9827A /* winscard_msg_srv.c in Sources */,
+				52E0D59E0BA7006D008DFDDF /* winscard.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5294AD60090CAE601CD285A /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F503CACF025425E601B94B21 /* testpcsc.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F52A93D702541D8C01B94B21 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				52C3C1480BA5D46900436862 /* readerstate.cpp in Sources */,
+				52D58C560A8803A800DC3F19 /* thread_macosx.c in Sources */,
+				F52A94DE025424AC01B94B21 /* musclecard.c in Sources */,
+				F52A94DF025424AC01B94B21 /* dyn_macosx.c in Sources */,
+				F52A94E5025424F101B94B21 /* winscard_msg.cpp in Sources */,
+				F52A94E0025424AC01B94B21 /* tokenfactory.c in Sources */,
+				F52A94E7025424F101B94B21 /* sys_unix.c in Sources */,
+				F52A94E1025424AC01B94B21 /* tokenparser.c in Sources */,
+				F52A94E3025424AC01B94B21 /* debuglog.c in Sources */,
+				F52A94E4025424AC01B94B21 /* winscard_clnt.c in Sources */,
+				52DBCAAF0BB851C8007D06A5 /* PCSC.exp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F537A7CE0379ED7501B94948 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E410379EF2501B94948 /* p11_crypt.c in Sources */,
+				F5448E420379EF2501B94948 /* p11_digest.c in Sources */,
+				F5448E430379EF2501B94948 /* p11_dual.c in Sources */,
+				F5448E440379EF2501B94948 /* p11_ext.c in Sources */,
+				F5448E450379EF2501B94948 /* p11_general.c in Sources */,
+				F5448E460379EF2501B94948 /* p11_key.c in Sources */,
+				F5448E470379EF2501B94948 /* p11_object.c in Sources */,
+				F5448E480379EF2501B94948 /* p11_parallel.c in Sources */,
+				F5448E490379EF2501B94948 /* p11_random.c in Sources */,
+				F5448E4A0379EF2501B94948 /* p11_session.c in Sources */,
+				F5448E4B0379EF2501B94948 /* p11_sign.c in Sources */,
+				F5448E4C0379EF2501B94948 /* p11_token.c in Sources */,
+				F5448E4D0379EF2501B94948 /* p11_verify.c in Sources */,
+				F5448E4E0379EF2501B94948 /* p11x_async.c in Sources */,
+				F5448E4F0379EF2501B94948 /* p11x_bio.c in Sources */,
+				F5448E500379EF2501B94948 /* p11x_error.c in Sources */,
+				F5448E510379EF2501B94948 /* p11x_log.c in Sources */,
+				F5448E520379EF2501B94948 /* p11x_msc.c in Sources */,
+				F5448E540379EF2501B94948 /* p11x_object.c in Sources */,
+				F5448E550379EF2501B94948 /* p11x_prefs.c in Sources */,
+				F5448E560379EF2501B94948 /* p11x_session.c in Sources */,
+				F5448E570379EF2501B94948 /* p11x_slot.c in Sources */,
+				F5448E580379EF2501B94948 /* p11x_state.c in Sources */,
+				F5448E590379EF2501B94948 /* p11x_thread.c in Sources */,
+				F5448E5B0379EF2501B94948 /* p11x_util.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448DFF0379EE2A01B94948 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E140379EEA101B94948 /* musclecardApplet.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E060379EE3601B94948 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E1C0379EEDD01B94948 /* commonAccessCard.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F5448E0D0379EE6401B94948 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F5448E180379EEC301B94948 /* cryptoflex.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		2CBB607506CA6DDE006AA7C8 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2CBB605A06CA6944006AA7C8 /* GSCISPlugin */;
+			targetProxy = 2CBB607406CA6DDE006AA7C8 /* PBXContainerItemProxy */;
+		};
+		F511213B0272FA1C017BB957 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F51121270272F895017BB957 /* pcsctool */;
+			targetProxy = 4CFE9C0C059254C9007119DE /* PBXContainerItemProxy */;
+		};
+		F520A5F60257B49C01D97E8A /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F52A93D402541D8C01B94B21 /* PCSC */;
+			targetProxy = 4CFE9C0E059254C9007119DE /* PBXContainerItemProxy */;
+		};
+		F520E3A001F6204201B94B28 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F5294A800090C73501CD285A /* pcscd */;
+			targetProxy = 4CFE9C06059254C9007119DE /* PBXContainerItemProxy */;
+		};
+		F520E3A301F6204201B94B28 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F5294AD40090CAE601CD285A /* pcsctest */;
+			targetProxy = 4CFE9C0D059254C9007119DE /* PBXContainerItemProxy */;
+		};
+		F5448E810379FE0101B94948 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F537A7D10379ED7501B94948 /* PKCS11 */;
+			targetProxy = 4CFE9C0B059254C9007119DE /* PBXContainerItemProxy */;
+		};
+		F5448E820379FE0501B94948 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F5448E020379EE2A01B94948 /* MCardPlugin */;
+			targetProxy = 4CFE9C05059254C8007119DE /* PBXContainerItemProxy */;
+		};
+		F5448E830379FE0801B94948 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F5448E090379EE3601B94948 /* CACPlugin */;
+			targetProxy = 4CFE9C0A059254C9007119DE /* PBXContainerItemProxy */;
+		};
+		F5448E840379FE0C01B94948 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F5448E100379EE6401B94948 /* CFlexPlugin */;
+			targetProxy = 4CFE9C07059254C9007119DE /* PBXContainerItemProxy */;
+		};
+		F54DC28B0397F35F01115D8D /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F538896903953B79012F6BBF /* InstallPhase */;
+			targetProxy = 4CFE9C09059254C9007119DE /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin PBXToolTarget section */
+		F51121270272F895017BB957 /* pcsctool */ = {
+			isa = PBXToolTarget;
+			buildConfigurationList = C27AD1D00987FCDC001272E0 /* Build configuration list for PBXToolTarget "pcsctool" */;
+			buildPhases = (
+				F51121280272F895017BB957 /* Headers */,
+				F51121290272F895017BB957 /* Sources */,
+				F511212A0272F895017BB957 /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = pcsctool;
+			productInstallPath = /usr/bin/;
+			productName = pcsctool;
+			productReference = F51121260272F895017BB957 /* pcsctool */;
+		};
+		F5294A800090C73501CD285A /* pcscd */ = {
+			isa = PBXToolTarget;
+			buildConfigurationList = C27AD1C60987FCDB001272E0 /* Build configuration list for PBXToolTarget "pcscd" */;
+			buildPhases = (
+				F5294A810090C73501CD285A /* Headers */,
+				F5294A820090C73501CD285A /* Sources */,
+				F5294A830090C73501CD285A /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = pcscd;
+			productInstallPath = /usr/sbin;
+			productName = pcscd;
+			productReference = F5294A7E0090C73501CD285A /* pcscd */;
+		};
+		F5294AD40090CAE601CD285A /* pcsctest */ = {
+			isa = PBXToolTarget;
+			buildConfigurationList = C27AD1CB0987FCDB001272E0 /* Build configuration list for PBXToolTarget "pcsctest" */;
+			buildPhases = (
+				F5294AD50090CAE601CD285A /* Headers */,
+				F5294AD60090CAE601CD285A /* Sources */,
+				F5294AD70090CAE601CD285A /* Frameworks */,
+			);
+			dependencies = (
+			);
+			name = pcsctest;
+			productInstallPath = /usr/bin;
+			productName = testpcsc;
+			productReference = F5294AD30090CAE601CD285A /* pcsctest */;
+		};
+/* End PBXToolTarget section */
+
+/* Begin XCBuildConfiguration section */
+		C27AD1C20987FCDB001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				CURRENT_PROJECT_VERSION = 1;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXPORTED_SYMBOLS_FILE = "\"$(SRCROOT)/src/PCSC/PCSC.exp\"";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					/usr/local/SecurityPieces/Frameworks,
+				);
+				FRAMEWORK_VERSION = A;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks";
+				OPTIMIZATION_CFLAGS = "-O0";
+				OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
+				OPT_CPPFLAGS = "$(OPT_CFLAGS)";
+				OPT_INLINEFLAGS = "-finline-functions";
+				OPT_LDFLAGS = "-dead_strip";
+				OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg";
+				OTHER_CFLAGS = (
+					"-DPCSC_DEBUG=1",
+					"-DUSE_SYSLOG=1",
+					"-DUSE_DAEMON=1",
+				);
+				OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CFLAGS_normal = "$(OPT_CFLAGS)  $(OTHER_CFLAGS)";
+				OTHER_CFLAGS_profile = "$(OPT_CFLAGS)  $(OTHER_CFLAGS) -pg";
+				OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
+				OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
+				OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
+				OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
+				OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
+				PRODUCT_NAME = PCSC;
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = framework;
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1C30987FCDB001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = (
+					normal,
+					debug,
+				);
+				CURRENT_PROJECT_VERSION = 1;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXPORTED_SYMBOLS_FILE = "\"$(SRCROOT)/src/PCSC/PCSC.exp\"";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					/usr/local/SecurityPieces/Frameworks,
+				);
+				FRAMEWORK_VERSION = A;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks";
+				OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
+				OPT_CPPFLAGS = "$(OPT_CFLAGS)";
+				OPT_INLINEFLAGS = "-finline-functions";
+				OPT_LDFLAGS = "-dead_strip";
+				OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg";
+				OTHER_CFLAGS = (
+					"-DPCSC_DEBUG=1",
+					"-DUSE_SYSLOG=1",
+					"-DUSE_DAEMON=1",
+				);
+				OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CFLAGS_normal = "$(OPT_CFLAGS)  $(OTHER_CFLAGS)";
+				OTHER_CFLAGS_profile = "$(OPT_CFLAGS)  $(OTHER_CFLAGS) -pg";
+				OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
+				OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
+				OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
+				OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
+				OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
+				PRODUCT_NAME = PCSC;
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = framework;
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1C40987FCDB001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				CURRENT_PROJECT_VERSION = 1;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXPORTED_SYMBOLS_FILE = "\"$(SRCROOT)/src/PCSC/PCSC.exp\"";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					/usr/local/SecurityPieces/Frameworks,
+				);
+				FRAMEWORK_VERSION = A;
+				INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks";
+				OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
+				OPT_CPPFLAGS = "$(OPT_CFLAGS)";
+				OPT_INLINEFLAGS = "-finline-functions";
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg";
+				OTHER_CFLAGS = (
+					"-DPCSC_DEBUG=1",
+					"-DUSE_SYSLOG=1",
+					"-DUSE_DAEMON=1",
+				);
+				OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CFLAGS_profile = "$(OPT_CFLAGS)  $(OTHER_CFLAGS) -pg";
+				OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
+				OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
+				OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
+				OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
+				PREBINDING = NO;
+				PRODUCT_NAME = PCSC;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = framework;
+			};
+			name = "normal with debug";
+		};
+		C27AD1C50987FCDB001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = (
+					normal,
+					debug,
+				);
+				CURRENT_PROJECT_VERSION = 1;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXPORTED_SYMBOLS_FILE = "\"$(SRCROOT)/src/PCSC/PCSC.exp\"";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					/usr/local/SecurityPieces/Frameworks,
+				);
+				FRAMEWORK_VERSION = A;
+				INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks";
+				OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
+				OPT_CPPFLAGS = "$(OPT_CFLAGS)";
+				OPT_INLINEFLAGS = "-finline-functions";
+				OPT_LDFLAGS = "-dead_strip";
+				OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg";
+				OTHER_CFLAGS = (
+					"-DPCSC_DEBUG=1",
+					"-DUSE_SYSLOG=1",
+					"-DUSE_DAEMON=1",
+				);
+				OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CFLAGS_normal = "$(OPT_CFLAGS)  $(OTHER_CFLAGS)";
+				OTHER_CFLAGS_profile = "$(OPT_CFLAGS)  $(OTHER_CFLAGS) -pg";
+				OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
+				OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
+				OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
+				OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
+				OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
+				PRODUCT_NAME = PCSC;
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = framework;
+			};
+			name = Default;
+		};
+		C27AD1C70987FCDB001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = (
+					"${BUILT_PRODUCTS_DIR}",
+					/usr/local/SecurityPieces/Components/Security,
+					/usr/local/SecurityPieces/Frameworks,
+				);
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				HEADER_SEARCH_PATHS = (
+					/System/Library/Frameworks/CoreFoundation.framework/Headers,
+					/System/Library/Frameworks/IOKit.framework/Headers/usb,
+					/System/Library/Frameworks/IOKit.framework/Headers,
+				);
+				INSTALL_PATH = /usr/sbin;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OPT_CPPXFLAGS = "$(OPT_CXFLAGS)";
+				OPT_CXFLAGS = "-DNDEBUG -Os $(OPT_INLINEXFLAGS)";
+				OPT_INLINEXFLAGS = "-finline-functions";
+				OPT_LDXFLAGS = "-dead_strip";
+				OPT_LDXNOPIC = ",_nopic";
+				OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg";
+				OTHER_CFLAGS = (
+					"-DPCSC_DEBUG=1",
+					"-DUSE_SYSLOG=1",
+					"-DUSE_DAEMON=1",
+				);
+				OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CFLAGS_normal = "$(OPT_CXFLAGS) $(OTHER_CFLAGS)";
+				OTHER_CFLAGS_profile = "$(OPT_CXFLAGS) $(OTHER_CFLAGS) -pg";
+				OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CPLUSPLUSFLAGS) -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS)";
+				OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS) -pg";
+				OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS) -framework Security,_debug -framework securityd_client,_debug -framework security_cdsa_client,_debug -framework security_cdsa_utilities,_debug -framework security_utilities,_debug";
+				OTHER_LDFLAGS_normal = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -framework Security -framework securityd_client$(OPT_LDXNOPIC) -framework security_cdsa_client$(OPT_LDXNOPIC) -framework security_cdsa_utilities$(OPT_LDXNOPIC) -framework security_utilities$(OPT_LDXNOPIC)";
+				OTHER_LDFLAGS_profile = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -pg -framework Security,_profile -framework securityd_client,_profile -framework security_cdsa_client,_profile -framework security_cdsa_utilities,_profile -framework security_utilities,_profile";
+				PRODUCT_NAME = pcscd;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1C80987FCDB001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = (
+					normal,
+					debug,
+				);
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = (
+					"${BUILT_PRODUCTS_DIR}",
+					/usr/local/SecurityPieces/Components/Security,
+					/usr/local/SecurityPieces/Frameworks,
+				);
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				HEADER_SEARCH_PATHS = (
+					/System/Library/Frameworks/CoreFoundation.framework/Headers,
+					/System/Library/Frameworks/IOKit.framework/Headers/usb,
+					/System/Library/Frameworks/IOKit.framework/Headers,
+				);
+				INSTALL_PATH = /usr/sbin;
+				OPT_CPPXFLAGS = "$(OPT_CXFLAGS)";
+				OPT_CXFLAGS = "-DNDEBUG -Os $(OPT_INLINEXFLAGS)";
+				OPT_INLINEXFLAGS = "-finline-functions";
+				OPT_LDXFLAGS = "-dead_strip";
+				OPT_LDXNOPIC = ",_nopic";
+				OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg";
+				OTHER_CFLAGS = (
+					"-DPCSC_DEBUG=1",
+					"-DUSE_SYSLOG=1",
+					"-DUSE_DAEMON=1",
+				);
+				OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CFLAGS_normal = "$(OPT_CXFLAGS) $(OTHER_CFLAGS)";
+				OTHER_CFLAGS_profile = "$(OPT_CXFLAGS) $(OTHER_CFLAGS) -pg";
+				OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CPLUSPLUSFLAGS) -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS)";
+				OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS) -pg";
+				OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS) -framework Security,_debug -framework securityd_client,_debug -framework security_cdsa_client,_debug -framework security_cdsa_utilities,_debug -framework security_utilities,_debug";
+				OTHER_LDFLAGS_normal = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -framework Security -framework securityd_client$(OPT_LDXNOPIC) -framework security_cdsa_client$(OPT_LDXNOPIC) -framework security_cdsa_utilities$(OPT_LDXNOPIC) -framework security_utilities$(OPT_LDXNOPIC)";
+				OTHER_LDFLAGS_profile = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -pg -framework Security,_profile -framework securityd_client,_profile -framework security_cdsa_client,_profile -framework security_cdsa_utilities,_profile -framework security_utilities,_profile";
+				PRODUCT_NAME = pcscd;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1C90987FCDB001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = (
+					"${BUILT_PRODUCTS_DIR}",
+					/usr/local/SecurityPieces/Components/Security,
+					/usr/local/SecurityPieces/Frameworks,
+				);
+				HEADER_SEARCH_PATHS = (
+					/System/Library/Frameworks/CoreFoundation.framework/Headers,
+					/System/Library/Frameworks/IOKit.framework/Headers/usb,
+					/System/Library/Frameworks/IOKit.framework/Headers,
+				);
+				INSTALL_PATH = /usr/sbin;
+				OPT_CPPXFLAGS = "$(OPT_CXFLAGS)";
+				OPT_CXFLAGS = "-DNDEBUG -Os $(OPT_INLINEXFLAGS)";
+				OPT_INLINEXFLAGS = "-finline-functions";
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg";
+				OTHER_CFLAGS = (
+					"-DPCSC_DEBUG=1",
+					"-DUSE_SYSLOG=1",
+					"-DUSE_DAEMON=1",
+				);
+				OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CFLAGS_profile = "$(OPT_CXFLAGS) $(OTHER_CFLAGS) -pg";
+				OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CPLUSPLUSFLAGS) -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS) -pg";
+				OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS) -framework Security,_debug -framework securityd_client,_debug -framework security_cdsa_client,_debug -framework security_cdsa_utilities,_debug -framework security_utilities,_debug";
+				OTHER_LDFLAGS_normal = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -framework Security -framework securityd_client$(OPT_LDXNOPIC) -framework security_cdsa_client$(OPT_LDXNOPIC) -framework security_cdsa_utilities$(OPT_LDXNOPIC) -framework security_utilities$(OPT_LDXNOPIC)";
+				OTHER_LDFLAGS_profile = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -pg -framework Security,_profile -framework securityd_client,_profile -framework security_cdsa_client,_profile -framework security_cdsa_utilities,_profile -framework security_utilities,_profile";
+				PREBINDING = NO;
+				PRODUCT_NAME = pcscd;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+			};
+			name = "normal with debug";
+		};
+		C27AD1CA0987FCDB001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = (
+					normal,
+					debug,
+				);
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = (
+					"${BUILT_PRODUCTS_DIR}",
+					/usr/local/SecurityPieces/Components/Security,
+					/usr/local/SecurityPieces/Frameworks,
+				);
+				HEADER_SEARCH_PATHS = (
+					/System/Library/Frameworks/CoreFoundation.framework/Headers,
+					/System/Library/Frameworks/IOKit.framework/Headers/usb,
+					/System/Library/Frameworks/IOKit.framework/Headers,
+				);
+				INSTALL_PATH = /usr/sbin;
+				OPT_CPPXFLAGS = "$(OPT_CXFLAGS)";
+				OPT_CXFLAGS = "-DNDEBUG -Os $(OPT_INLINEXFLAGS)";
+				OPT_INLINEXFLAGS = "-finline-functions";
+				OPT_LDXFLAGS = "-dead_strip";
+				OPT_LDXNOPIC = ",_nopic";
+				OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
+				OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg";
+				OTHER_CFLAGS = (
+					"-DPCSC_DEBUG=1",
+					"-DUSE_SYSLOG=1",
+					"-DUSE_DAEMON=1",
+				);
+				OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
+				OTHER_CFLAGS_normal = "$(OPT_CXFLAGS) $(OTHER_CFLAGS)";
+				OTHER_CFLAGS_profile = "$(OPT_CXFLAGS) $(OTHER_CFLAGS) -pg";
+				OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CPLUSPLUSFLAGS) -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS)";
+				OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS) -pg";
+				OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS) -framework Security,_debug -framework securityd_client,_debug -framework security_cdsa_client,_debug -framework security_cdsa_utilities,_debug -framework security_utilities,_debug";
+				OTHER_LDFLAGS_normal = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -framework Security -framework securityd_client$(OPT_LDXNOPIC) -framework security_cdsa_client$(OPT_LDXNOPIC) -framework security_cdsa_utilities$(OPT_LDXNOPIC) -framework security_utilities$(OPT_LDXNOPIC)";
+				OTHER_LDFLAGS_profile = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -pg -framework Security,_profile -framework securityd_client,_profile -framework security_cdsa_client,_profile -framework security_cdsa_utilities,_profile -framework security_utilities,_profile";
+				PRODUCT_NAME = pcscd;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+			};
+			name = Default;
+		};
+		C27AD1CC0987FCDB001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = /usr/bin;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pcsctest;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1CD0987FCDB001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				INSTALL_PATH = /usr/bin;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pcsctest;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1CE0987FCDB001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = "";
+				INSTALL_PATH = /usr/bin;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS = "";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PREBINDING = NO;
+				PRODUCT_NAME = pcsctest;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+			};
+			name = "normal with debug";
+		};
+		C27AD1CF0987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = "";
+				INSTALL_PATH = /usr/bin;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pcsctest;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+			};
+			name = Default;
+		};
+		C27AD1D10987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = /usr/bin;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pcsctool;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1D20987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				INSTALL_PATH = /usr/bin;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pcsctool;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1D30987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = "";
+				INSTALL_PATH = /usr/bin;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS = "";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PREBINDING = NO;
+				PRODUCT_NAME = pcsctool;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+			};
+			name = "normal with debug";
+		};
+		C27AD1D40987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				FRAMEWORK_SEARCH_PATHS = "";
+				INSTALL_PATH = /usr/bin;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pcsctool;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+			};
+			name = Default;
+		};
+		C27AD1D60987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				CURRENT_PROJECT_VERSION = 1;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/pkcs11;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "-lcrypto";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pkcs11;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1D70987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/pkcs11;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "-lcrypto";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pkcs11;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1D80987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				CURRENT_PROJECT_VERSION = 1;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/pkcs11;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS = "";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_LDFLAGS = "-lcrypto";
+				OTHER_REZFLAGS = "";
+				PREBINDING = NO;
+				PRODUCT_NAME = pkcs11;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = "normal with debug";
+		};
+		C27AD1D90987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/pkcs11;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "-lcrypto";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = pkcs11;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = Default;
+		};
+		C27AD1DB0987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				CURRENT_PROJECT_VERSION = 1;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = mscMuscleCard;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1DC0987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = mscMuscleCard;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1DD0987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				CURRENT_PROJECT_VERSION = 1;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PREBINDING = NO;
+				PRODUCT_NAME = mscMuscleCard;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = "normal with debug";
+		};
+		C27AD1DE0987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = mscMuscleCard;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = Default;
+		};
+		C27AD1E00987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				PRODUCT_NAME = GSCISPlugin;
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1E10987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				PRODUCT_NAME = GSCISPlugin;
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1E20987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				PREBINDING = NO;
+				PRODUCT_NAME = GSCISPlugin;
+				SECTORDER_FLAGS = "";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = "normal with debug";
+		};
+		C27AD1E30987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				PRODUCT_NAME = GSCISPlugin;
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = Default;
+		};
+		C27AD1E50987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				CURRENT_PROJECT_VERSION = 1;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = commonAccessCard;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1E60987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = commonAccessCard;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1E70987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				CURRENT_PROJECT_VERSION = 1;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PREBINDING = NO;
+				PRODUCT_NAME = commonAccessCard;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = "normal with debug";
+		};
+		C27AD1E80987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = commonAccessCard;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = Default;
+		};
+		C27AD1EA0987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				CURRENT_PROJECT_VERSION = 1;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = slbCryptoflex;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1EB0987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = slbCryptoflex;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1EC0987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				CURRENT_PROJECT_VERSION = 1;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PREBINDING = NO;
+				PRODUCT_NAME = slbCryptoflex;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = "normal with debug";
+		};
+		C27AD1ED0987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CURRENT_PROJECT_VERSION = 1;
+				INSTALL_PATH = /usr/libexec/SmartCardServices/services;
+				OTHER_CFLAGS = "-DMSC_TARGET_OSX=1";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = slbCryptoflex;
+				SECTORDER_FLAGS = "";
+				VERSIONING_SYSTEM = "apple-generic";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = Default;
+		};
+		C27AD1EF0987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				OPTIMIZATION_CFLAGS = "-O0";
+				PRODUCT_NAME = InstallPhase;
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1F00987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				PRODUCT_NAME = InstallPhase;
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1F10987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				PREBINDING = NO;
+				PRODUCT_NAME = InstallPhase;
+				SECTORDER_FLAGS = "";
+			};
+			name = "normal with debug";
+		};
+		C27AD1F20987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PRODUCT_NAME = InstallPhase;
+			};
+			name = Default;
+		};
+		C27AD1F90987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = debug;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				OPTIMIZATION_CFLAGS = "-O0";
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = World;
+				SECTORDER_FLAGS = "";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				ZERO_LINK = YES;
+			};
+			name = Development;
+		};
+		C27AD1FA0987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = World;
+				SECTORDER_FLAGS = "";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+				ZERO_LINK = NO;
+			};
+			name = Deployment;
+		};
+		C27AD1FB0987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUILD_VARIANTS = normal;
+				OPT_LDFLAGS = "";
+				OPT_LDXFLAGS = "";
+				OPT_LDXNOPIC = "";
+				OTHER_ASFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG";
+				OTHER_CFLAGS = "";
+				OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CFLAGS) -UNDEBUG -O0 -fno-inline";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PREBINDING = NO;
+				PRODUCT_NAME = World;
+				SECTORDER_FLAGS = "";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+			};
+			name = "normal with debug";
+		};
+		C27AD1FC0987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = World;
+				SECTORDER_FLAGS = "";
+				WARNING_CFLAGS = (
+					"-Wmost",
+					"-Wno-four-char-constants",
+					"-Wno-unknown-pragmas",
+				);
+			};
+			name = Default;
+		};
+		C27AD1FE0987FCDC001272E0 /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+				CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+			};
+			name = Development;
+		};
+		C27AD1FF0987FCDC001272E0 /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+				CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+			};
+			name = Deployment;
+		};
+		C27AD2000987FCDC001272E0 /* normal with debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+				CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+			};
+			name = "normal with debug";
+		};
+		C27AD2010987FCDC001272E0 /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+				CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+			};
+			name = Default;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		C27AD1C10987FCDB001272E0 /* Build configuration list for PBXFrameworkTarget "PCSC" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1C20987FCDB001272E0 /* Development */,
+				C27AD1C30987FCDB001272E0 /* Deployment */,
+				C27AD1C40987FCDB001272E0 /* normal with debug */,
+				C27AD1C50987FCDB001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1C60987FCDB001272E0 /* Build configuration list for PBXToolTarget "pcscd" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1C70987FCDB001272E0 /* Development */,
+				C27AD1C80987FCDB001272E0 /* Deployment */,
+				C27AD1C90987FCDB001272E0 /* normal with debug */,
+				C27AD1CA0987FCDB001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1CB0987FCDB001272E0 /* Build configuration list for PBXToolTarget "pcsctest" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1CC0987FCDB001272E0 /* Development */,
+				C27AD1CD0987FCDB001272E0 /* Deployment */,
+				C27AD1CE0987FCDB001272E0 /* normal with debug */,
+				C27AD1CF0987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1D00987FCDC001272E0 /* Build configuration list for PBXToolTarget "pcsctool" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1D10987FCDC001272E0 /* Development */,
+				C27AD1D20987FCDC001272E0 /* Deployment */,
+				C27AD1D30987FCDC001272E0 /* normal with debug */,
+				C27AD1D40987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1D50987FCDC001272E0 /* Build configuration list for PBXBundleTarget "PKCS11" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1D60987FCDC001272E0 /* Development */,
+				C27AD1D70987FCDC001272E0 /* Deployment */,
+				C27AD1D80987FCDC001272E0 /* normal with debug */,
+				C27AD1D90987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1DA0987FCDC001272E0 /* Build configuration list for PBXBundleTarget "MCardPlugin" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1DB0987FCDC001272E0 /* Development */,
+				C27AD1DC0987FCDC001272E0 /* Deployment */,
+				C27AD1DD0987FCDC001272E0 /* normal with debug */,
+				C27AD1DE0987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1DF0987FCDC001272E0 /* Build configuration list for PBXBundleTarget "GSCISPlugin" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1E00987FCDC001272E0 /* Development */,
+				C27AD1E10987FCDC001272E0 /* Deployment */,
+				C27AD1E20987FCDC001272E0 /* normal with debug */,
+				C27AD1E30987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1E40987FCDC001272E0 /* Build configuration list for PBXBundleTarget "CACPlugin" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1E50987FCDC001272E0 /* Development */,
+				C27AD1E60987FCDC001272E0 /* Deployment */,
+				C27AD1E70987FCDC001272E0 /* normal with debug */,
+				C27AD1E80987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1E90987FCDC001272E0 /* Build configuration list for PBXBundleTarget "CFlexPlugin" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1EA0987FCDC001272E0 /* Development */,
+				C27AD1EB0987FCDC001272E0 /* Deployment */,
+				C27AD1EC0987FCDC001272E0 /* normal with debug */,
+				C27AD1ED0987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1EE0987FCDC001272E0 /* Build configuration list for PBXLegacyTarget "InstallPhase" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1EF0987FCDC001272E0 /* Development */,
+				C27AD1F00987FCDC001272E0 /* Deployment */,
+				C27AD1F10987FCDC001272E0 /* normal with debug */,
+				C27AD1F20987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1F80987FCDC001272E0 /* Build configuration list for PBXAggregateTarget "World" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1F90987FCDC001272E0 /* Development */,
+				C27AD1FA0987FCDC001272E0 /* Deployment */,
+				C27AD1FB0987FCDC001272E0 /* normal with debug */,
+				C27AD1FC0987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		C27AD1FD0987FCDC001272E0 /* Build configuration list for PBXProject "SmartCardServices" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C27AD1FE0987FCDC001272E0 /* Development */,
+				C27AD1FF0987FCDC001272E0 /* Deployment */,
+				C27AD2000987FCDC001272E0 /* normal with debug */,
+				C27AD2010987FCDC001272E0 /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = F5294A4F0090C4CA01CD285A /* Project object */;
+}

Added: trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/Info.plist
===================================================================
--- trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/Info.plist	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/Info.plist	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>CM4040</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.omnikey.cm4040.driver</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>cm4040</string>
+	<key>CFBundlePackageType</key>
+	<string>KEXT</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.2</string>
+	<key>IOKitPersonalities</key>
+	<dict>
+		<key>OKCM4040UC</key>
+		<dict>
+			<key>CFBundleIdentifier</key>
+			<string>com.omnikey.cm4040.driver</string>
+			<key>IOClass</key>
+			<string>com_omnikey_cm4040_driver</string>
+			<key>IOProviderClass</key>
+			<string>IOPCCard16Device</string>
+			<key>IOResourceMatch</key>
+			<string>IOKit</string>
+			<key>IOUserClientClass</key>
+			<string>com_omnikey_cm4040_UserClient</string>
+			<key>VersionOneInfo</key>
+			<array>
+				<string>OMNIKEY</string>
+				<string>CardMan 4040</string>
+			</array>
+		</dict>
+	</dict>
+	<key>OSBundleLibraries</key>
+	<dict>
+		<key>com.apple.iokit.IOPCCardFamily</key>
+		<string>1.1.0</string>
+		<key>com.apple.kernel.iokit</key>
+		<string>1.1</string>
+		<key>com.apple.kernel.libkern</key>
+		<string>1.1</string>
+		<key>com.apple.kernel.mach</key>
+		<string>1.1</string>
+	</dict>
+</dict>
+</plist>

Added: trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/MacOS/CM4040
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/Extensions/CM4040.kext/Contents/MacOS/CM4040
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Info.plist
===================================================================
--- trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Info.plist	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Info.plist	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>CRYPTOCardPCCard</string>
+	<key>CFBundleGetInfoString</key>
+	<string>PC Card Smart Card Reader Driver</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.CRYPTOCard.iokit.SmartCardReader</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>CRYPTOCardPCCard</string>
+	<key>CFBundlePackageType</key>
+	<string>KEXT</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0.1</string>
+	<key>CFBundleSignature</key>
+	<string>CCrd</string>
+	<key>CFBundleVersion</key>
+	<string>1.0.0d2</string>
+	<key>IOKitPersonalities</key>
+	<dict>
+		<key>CRYPTOCardPCCard</key>
+		<dict>
+			<key>CFBundleIdentifier</key>
+			<string>com.CRYPTOCard.iokit.SmartCardReader</string>
+			<key>IOClass</key>
+			<string>com_CRYPTOCard_iokit_SmartCardReader</string>
+			<key>IOKitDebug</key>
+			<integer>65535</integer>
+			<key>IONameMatch</key>
+			<string>pccard2bd,1003</string>
+			<key>IOProbeScore</key>
+			<integer>10000</integer>
+			<key>IOProviderClass</key>
+			<string>IOPCCard16Device</string>
+			<key>IOUserClientClass</key>
+			<string>com_CRYPTOCard_iokit_UserClient</string>
+			<key>VersionOneInfo</key>
+			<array>
+				<string>CRYPTOCard</string>
+				<string>Smart Card Reader Model P1</string>
+			</array>
+		</dict>
+	</dict>
+	<key>OSBundleLibraries</key>
+	<dict>
+		<key>com.apple.iokit.IOPCCardFamily</key>
+		<string>1.1.0</string>
+	</dict>
+</dict>
+</plist>

Added: trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/MacOS/CRYPTOCardPCCard
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/MacOS/CRYPTOCardPCCard
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Resources/English.lproj/InfoPlist.strings
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/Extensions/CRYPTOCardPCCard.kext/Contents/Resources/English.lproj/InfoPlist.strings
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Info.plist
===================================================================
--- trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Info.plist	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Info.plist	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>SCR24X_Apple_Driver</string>
+	<key>CFBundleGetInfoString</key>
+	<string>2.1.0</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.scm.driver.scr24x</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>SCR24X PCMCIA Smart Card Reader</string>
+	<key>CFBundlePackageType</key>
+	<string>KEXT</string>
+	<key>CFBundleShortVersionString</key>
+	<string>2.1.0</string>
+	<key>CFBundleVersion</key>
+	<string>2.1.0</string>
+	<key>IOKitPersonalities</key>
+	<dict>
+		<key>HP</key>
+		<dict>
+			<key>CFBundleIdentifier</key>
+			<string>com.scm.driver.scr24x</string>
+			<key>IOClass</key>
+			<string>com_scm_driver_scr24x</string>
+			<key>IOKitDebug</key>
+			<integer>65535</integer>
+			<key>IOProbeScore</key>
+			<integer>10000</integer>
+			<key>IOProviderClass</key>
+			<string>IOPCCard16Device</string>
+			<key>IOUserClientClass</key>
+			<string>com_scm_driver_scr24xUserClient</string>
+			<key>VersionOneInfo</key>
+			<array>
+				<string>HP</string>
+				<string>PC Card Smart Card Reader</string>
+			</array>
+		</dict>
+		<key>SCR241</key>
+		<dict>
+			<key>CFBundleIdentifier</key>
+			<string>com.scm.driver.scr24x</string>
+			<key>IOClass</key>
+			<string>com_scm_driver_scr24x</string>
+			<key>IOKitDebug</key>
+			<integer>65535</integer>
+			<key>IOProbeScore</key>
+			<integer>10000</integer>
+			<key>IOProviderClass</key>
+			<string>IOPCCard16Device</string>
+			<key>IOUserClientClass</key>
+			<string>com_scm_driver_scr24xUserClient</string>
+			<key>VersionOneInfo</key>
+			<array>
+				<string>SCR241 PCMCIA</string>
+				<string>Smart Card Reader</string>
+			</array>
+		</dict>
+		<key>SCR243</key>
+		<dict>
+			<key>CFBundleIdentifier</key>
+			<string>com.scm.driver.scr24x</string>
+			<key>IOClass</key>
+			<string>com_scm_driver_scr24x</string>
+			<key>IOKitDebug</key>
+			<integer>65535</integer>
+			<key>IOProbeScore</key>
+			<integer>10000</integer>
+			<key>IOProviderClass</key>
+			<string>IOPCCard16Device</string>
+			<key>IOUserClientClass</key>
+			<string>com_scm_driver_scr24xUserClient</string>
+			<key>VersionOneInfo</key>
+			<array>
+				<string>SCR243 PCMCIA</string>
+				<string>Smart Card Reader</string>
+			</array>
+		</dict>
+		<key>SCR24x</key>
+		<dict>
+			<key>CFBundleIdentifier</key>
+			<string>com.scm.driver.scr24x</string>
+			<key>IOClass</key>
+			<string>com_scm_driver_scr24x</string>
+			<key>IOKitDebug</key>
+			<integer>65535</integer>
+			<key>IOProbeScore</key>
+			<integer>10000</integer>
+			<key>IOProviderClass</key>
+			<string>IOPCCard16Device</string>
+			<key>IOUserClientClass</key>
+			<string>com_scm_driver_scr24xUserClient</string>
+			<key>VersionOneInfo</key>
+			<array>
+				<string>SCR24x PCMCIA</string>
+				<string>Smart Card Reader</string>
+			</array>
+		</dict>
+	</dict>
+	<key>Java</key>
+	<dict>
+		<key>Properties</key>
+		<dict/>
+	</dict>
+	<key>OSBundleLibraries</key>
+	<dict>
+		<key>com.apple.iokit.IOPCCardFamily</key>
+		<string>1.1.0</string>
+	</dict>
+</dict>
+</plist>

Added: trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/MacOS/SCR24X_Apple_Driver
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/MacOS/SCR24X_Apple_Driver
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Resources/English.lproj/InfoPlist.strings
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/Extensions/SCR24X_Apple_Driver.kext/Contents/Resources/English.lproj/InfoPlist.strings
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/PKCS11/pkcs11.shlb
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/PKCS11/pkcs11.shlb
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/Info.plist
===================================================================
--- trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/Info.plist	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/Info.plist	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>CC-PC-Card</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>0.0.1d1</string>
+	<key>ifdFriendlyName</key>
+	<string>CRYPTOCard</string>
+	<key>ifdProductID</key>
+	<string>1003</string>
+	<key>ifdVendorID</key>
+	<string>2BD</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.CRYPTOCard.SmartcardReader</string>
+	<key>CFBundleName</key>
+	<string>CRYPTOCardSmartcardDriver</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0.1</string>
+</dict>
+</plist>

Added: trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/MacOS/CC-PC-Card
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/drivers/CC-PC-Card.bundle/Contents/MacOS/CC-PC-Card
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/Info.plist
===================================================================
--- trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/Info.plist	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/Info.plist	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>SCR24XHndlr</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.scm.bundle.scr24xhndlr</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>0.9.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>0.9.0</string>
+        <key>ifdFriendlyName</key>
+        <string>SCR24X</string>
+	<key>ifdProductID</key>
+	<string>0xffff</string>
+	<key>ifdVendorID</key>
+	<string>0x04e6</string>
+</dict>
+</plist>

Added: trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/MacOS/SCR24XHndlr
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/drivers/SCR24XHndlr.bundle/Contents/MacOS/SCR24XHndlr
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/Info.plist
===================================================================
--- trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/Info.plist	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/Info.plist	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>ifd-ASEIIIeUSB</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.athena.AseIIIeUSB</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>CFPlugInDynamicRegisterFunction</key>
+	<string></string>
+	<key>CFPlugInDynamicRegistration</key>
+	<string>NO</string>
+	<key>CFPlugInFactories</key>
+	<dict>
+		<key>00000000-0000-0000-0000-000000000000</key>
+		<string>MyFactoryFunction</string>
+	</dict>
+	<key>CFPlugInTypes</key>
+	<dict>
+		<key>00000000-0000-0000-0000-000000000000</key>
+		<array>
+			<string>00000000-0000-0000-0000-000000000000</string>
+		</array>
+	</dict>
+	<key>CFPlugInUnloadFunction</key>
+	<string></string>
+	<key>NSPrincipalClass</key>
+	<string>0x60000</string>
+	<key>ifdCapabilities</key>
+	<string>0x00000000</string>
+	<key>ifdFriendlyName</key>
+	<string>AseIIIeUSB</string>
+	<key>ifdManufacturerString</key>
+	<string>Athena</string>
+	<key>ifdManufacturerURL</key>
+	<string>http://www.athena-scs.com/</string>
+	<key>ifdMaxSpeed</key>
+	<string>153600</string>
+	<key>ifdProductID</key>
+	<string>0x0802</string>
+	<key>ifdProductString</key>
+	<string>AseIIIeUSB</string>
+	<key>ifdProtocolSupport</key>
+	<string>0x00000001</string>
+	<key>ifdReadTimeOut</key>
+	<string>60000</string>
+	<key>ifdVendorID</key>
+	<string>0x0DC3</string>
+	<key>ifdVersionNumber</key>
+	<string>0x00000001</string>
+</dict>
+</plist>

Added: trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/MacOS/ifd-ASEIIIeUSB
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/drivers/ifd-ASEIIIeUSB.bundle/Contents/MacOS/ifd-ASEIIIeUSB
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/Info.plist
===================================================================
--- trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/Info.plist	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/Info.plist	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>ifdok_cm4040_macos-2.0.0.dylib</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0.0d2</string>
+	<key>CSResourcesFileMapped</key>
+	<true/>
+	<key>ManufacturerString</key>
+		<string>Omnikey AG</string>
+	<key>ManufacturerURL</key>
+	<string>http://www.omnikey.com/</string>
+	<key>ifdCapabilities</key>
+	<string>0x00000000</string>
+	<key>ifdFriendlyName</key>
+		<string>OMNIKEY CardMan 4040</string>
+	<key>ifdMaxSpeed</key>
+	<string>115200</string>
+	<key>ifdProductID</key>
+		<string>0x0200</string>
+	<key>ifdProductString</key>
+		<string>OMNIKEY CardMan 4040</string>
+	<key>ifdProtocolSupport</key>
+	<string>0x00000011</string>
+	<key>ifdVendorID</key>
+		<string>0x0223</string>
+</dict>
+</plist>


Property changes on: trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/Info.plist
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/MacOS/ifdok_cm4040_macos-2.0.0.dylib
===================================================================
(Binary files differ)


Property changes on: trunk/SmartCardServices/installPhase/drivers/ifdok_cm4040_macos-2.0.0.bundle/Contents/MacOS/ifdok_cm4040_macos-2.0.0.dylib
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + application/octet-stream

Added: trunk/SmartCardServices/installPhase/man/pcscd.8
===================================================================
--- trunk/SmartCardServices/installPhase/man/pcscd.8	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/man/pcscd.8	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,149 @@
+.\" Process this file with
+.\" groff -man -Tascii pcscd.txt
+.\"
+.TH PCSCD 8 "March 2002" Linux "User Manual"
+.SH NAME
+pcscd \- PC/SC Smartcard Daemon
+.SH SYNOPSIS
+.BI "pcscd [" options "]"
+.SH OPTIONS
+.TP
+\fB\-a\fR, \fB\-\-apdu\fR
+log APDUs and SW using the debug method (see \fB\-d\fR)
+.TP
+\fB\-c\fR, \fB\-\-config\fR \fIfile\fR
+Specifies the file \fIfile\fR as an alternate location for
+\fIreader.conf\fR
+.TP
+\fB\-d\fR, \fB\-\-debug\fR \fIOUTPUT\fR
+display debug messages.
+
+\fIOUTPUT\fR may be:
+ \fBstdout\fR (imply \fB\-f\fR),
+ \fBstderr\fR (imply \fB\-f\fR),
+ or \fBsyslog\fR
+.TP
+\fB\-f\fR, \fB\-\-foreground\fR
+Runs pcscd in the foreground (no daemon)
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Displays information about the pcscd command line
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Displays the program version number
+.SH DESCRIPTION
+pcscd is the daemon program for pcsc-lite and musclecard framework. It is 
+a resource manager that coordinates communications with smart-card readers 
+and smart cards and cryptographic tokens that are connected to the system.
+
+pcscd is normally started at boot time from 
+.IR /System/Library/StartupItems/SmartCardServices .
+It allows applications to access smart cards and readers without knowing
+details of the card or reader.  
+
+pcscd coordinates the loading of drivers for card readers and plug-ins 
+for different card types.
+
+The purpose of pcsc-lite is to provide both a cross compatible API for
+migrating Windows based PCSC applications to Unix and to provide a 
+pluggable architecture for supporting smartcards and cryptographic tokens 
+through high level API's.
+
+At startup, pcscd loads the smart card reader drivers specified in the 
+.I /etc/reader.conf 
+file (or specified using \fB-c\fR \fIfile\fR).
+
+When a smart card is inserted into a reader, pcscd uses the ATR string from 
+the card to identify this card.  The 
+.I /usr/libexec/SmartCardServices/services 
+directory contains plug-ins for the card.  These plug-ins are searched.  If 
+the ATR string matches, the client library loads that plug-in for that 
+token.
+
+.SH "USB SMART CARD READER DRIVERS"
+USB Smart card reader drivers are placed in the 
+.I /usr/libexec/SmartCardServices/drivers 
+directory. Each driver is simply a 
+bundle.  The bundle contains an XML file Info.plist
+which is parsed by pcscd.  This file contains the vendor
+and product id of the device.  This information allows
+pcscd to automatically determine when a reader is inserted
+or removed.
+
+.SH "SERIAL SMART CARD READER DRIVERS"
+Serial Smart card reader drivers are placed in the 
+.I /usr/libexec/SmartCardServices/drivers 
+directory. Each driver is simply a 
+.I shared object
+file.  The pcscd locates serial drivers with the 
+.I /etc/reader.conf 
+file.  The file has the following format:
+
+ # comment
+ FRIENDLYNAME <Descriptive name>
+ DEVICENAME   <Short name>
+ LIBPATH      <Location of the driver library>
+ CHANNELID    <Hexadecimal channel identificator>
+
+.IP FRIENDLYNAME 
+is a user-friendly name of the reader that is served by this driver.
+This name is displayed to the user when necessary.
+
+.IP DEVICENAME 
+is a driver specific value.  If you do not know this value,
+GEN_SMART_RDR is a good choice.
+	
+.IP LIBPATH 
+is the full path to the shared library. 
+
+.IP CHANNELID 
+is the channel ID for serial-port, smart-card readers.  This could vary 
+depending on the driver in which you are using - check the driver README
+for more information.  Some use the following:
+
+ \fI/dev/ttyS0\fR (COM1) ->  0x0103F8 or 1
+ \fI/dev/ttyS1\fR (COM2) ->  0x0102F8 or 2
+ \fI/dev/ttyS2\fR (COM3) ->  0x0103E8 or 3
+ \fI/dev/ttyS3\fR (COM4) ->  0x0102E8 or 4
+.PP
+Example:
+
+ # Configuration file for pcsc-lite
+ 
+ FRIENDLYNAME "My Smartcard Reader"
+ DEVICENAME   GEN_SMART_RDR
+ LIBPATH      /usr/libexec/SmartCardServices/drivers/my_reader.so
+ CHANNELID    0x0103F8
+ 
+ # End of file
+
+Multiple drivers can be listed in 
+.I /etc/reader.conf.
+
+Drivers are available at \fIhttp://www.musclecard.com/drivers.html\fR.
+.SH "SMART CARD PLUG-INS"
+pcsc-lite uses plug-ins to handle different types of smart cards. There is 
+a plug-in for each smart-card type. Plug-ins are installed in the 
+.I /usr/libexec/SmartCardServices/services 
+directory.  Plug-ins for cards/tokens are available from the MUSCLE
+web site \fIhttp://www.musclecard.com\fR.
+.SH FILES
+.I /etc/reader.conf
+: Reader configuration file
+.br
+.I /System/Library/StartupItems/SmartCardServices
+: pcscd startup script
+.br
+.I /var/run/pcscd.pid
+: process id of the running pcscd
+.br
+.I /usr/libexec/SmartCardServices/drivers/
+: directory containing bundles for USB
+drivers"
+.SH BUGS
+None known.
+.SH "SEE ALSO"
+.BR pcsctool (1),
+.SH AUTHORS
+David Corcoran <corcoran at identityalliance.com> and Ludovic Rousseau
+<ludovic.rousseau at free.fr>

Added: trunk/SmartCardServices/installPhase/man/pcsctest.8
===================================================================
--- trunk/SmartCardServices/installPhase/man/pcsctest.8	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/man/pcsctest.8	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,57 @@
+.\" Process this file with
+.\" groff -man -Tascii pcsctool.8
+.\"
+.TH PCSCTEST 8 "March 2003" MacOSX "User Manual"
+.SH NAME
+pcsctest
+.SH SYNOPSIS
+.B pcsctest
+.SH DESCRPTION
+pcsctest runs a test on pcscd, lists the readers currently connected, and
+displays card information if a card is inserted.
+.SH OPTIONS 
+None
+.SH USAGE
+pcsctest lists the currently connected readers and asks the user
+to choose one.  After choosing the reader, pcsctest will ask the
+user to insert a card into the card reader.  If this happens pcsctest
+will display the cards's ATR and other information.
+
+Example:
+
+The following will occur if no reader is inserted and recognized:
+
+MUSCLE PC/SC Lite Test Program
+
+  Testing SCardEstablishContext    : Command successful.
+  Testing SCardGetStatusChange 
+
+Once a reader is inserted and recognized the following will occur:
+ 
+  MUSCLE PC/SC Lite Test Program
+
+  Testing SCardEstablishContext    : Command successful.
+  Testing SCardGetStatusChange
+  Please insert a working reader   : Command successful.
+  Testing SCardListReaders         : Command successful.
+  Reader 01: SCM SCR-331 CCID 0 0
+  Enter the reader number          : 1
+
+  Waiting for card insertion
+                                   : Command successful.
+  Testing SCardConnect             : Command successful.
+  Testing SCardStatus              : Command successful.
+  Current Reader Name              : CCID USB Reader 0 0
+  Current Reader State             : 34
+  Current Reader Protocol          : 0
+  Current Reader ATR Size          : 9
+  Current Reader ATR Value         : 3B E2 00 00 04 03 00
+  Testing SCardDisconnect          : Command successful.
+  Testing SCardReleaseContext      : Command successful.
+
+  PC/SC Test Completed Successfully !
+
+
+.SH SEE ALSO
+.BR pcscd (8)
+.SH BUGS

Added: trunk/SmartCardServices/installPhase/man/pcsctool.8
===================================================================
--- trunk/SmartCardServices/installPhase/man/pcsctool.8	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/man/pcsctool.8	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,37 @@
+.\" Process this file with
+.\" groff -man -Tascii pcsctool.8
+.\"
+.TH PCSCTOOL 8 "March 2002" Linux "User Manual"
+.SH NAME
+pcsctool
+.SH SYNOPSIS
+.B pcsctool
+.SH DESCRPTION
+pcsctool introduces new smart cards to pcsc-lite and assigns a 
+plugin to service the card.
+.SH OPTIONS 
+None
+.SH USAGE
+pcsctool lists the currently installed bundles and asks you to 
+select one.  You select the plugin bundle that services your 
+smartcard. pcsctool will then ask you to insert the new card.  The 
+application exits and pcsc is now configured to use your card.
+
+Example:
+
+ [root at osx]# pcsctool
+ Select the approprate token driver:
+ -----------------------------------
+   1.     mscMuscleCard.bundle
+ -----------------------------------
+ Enter the number: 1
+ 
+ Insert your token in: My Friendly Reader 0 0
+ 
+ Token support updated successfully !
+ [root at osx]# 
+.SH SEE ALSO
+.BR pcscd (8)
+.SH BUGS
+Plugins MUST reside in 
+.I /usr/libexec/SmartCardServices/services

Added: trunk/SmartCardServices/installPhase/man/sc_auth.8
===================================================================
--- trunk/SmartCardServices/installPhase/man/sc_auth.8	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/man/sc_auth.8	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,91 @@
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.\"See Also:
+.\"man mdoc.samples for a complete listing of options
+.\"man mdoc for the short list of editing options
+.\"/usr/share/misc/mdoc.template
+.Dd December 11, 2006       \" DATE 
+.Dt sc_auth 8       \" Program name and manual section number 
+.Os MacOSX
+.Sh NAME                 \" Section Header - required - don't modify 
+.Nm sc_auth
+.\" The following lines are read in generating the apropos(man -k) database. Use only key
+.\" words here as the database is built based on the words here and in the .ND line. 
+.\" Use .Nm macro to designate other names for the documented program.
+.Nd smart card authorization setup script
+.Sh SYNOPSIS             \" Section Header - required - don't modify
+.Nm
+.Ar accept
+.Op Fl v
+.Op Fl u Ar user 
+.Op Fl d Ar domain 
+.Op Fl k Ar keyname
+.Nm
+.Ar accept
+.Op Fl v
+.Op Fl u Ar user 
+.Op Fl d Ar domain 
+.Fl h Ar hash
+.Nm
+.Ar remove
+.Op Fl v
+.Op Fl u Ar user 
+.Op Fl d Ar domain 
+.Nm
+.Ar hash " "
+.Op Fl k Ar keyname
+.Nm
+.Ar list " "
+.Op Fl v
+.Op Fl u Ar user
+.Op Fl d Ar domain 
+.Sh DESCRIPTION          \" Section Header - required - don't modify
+.Nm
+configures a local user account to permit authentication using a supported 
+smart card.  Authentication is via asymmetric key (also known as 
+public-key) encryption.  
+.Nm
+works with signing keys, but not encryption keys.  
+.Pp
+.Nm
+can perform the following actions:
+.Bl -tag -width -indent  \" Begins a tagged list 
+.It Ar accept
+Associate a user with a public key on a card.  The key to use can be 
+specified either by its name or its hash.  
+.It Ar remove
+Remove all public keys associated with a user.  
+.It Ar hash
+Print the hashes for all keys on all inserted cards.  
+.It Ar list
+List all public keys associated with a user.  
+.El                      \" Ends the list
+.Pp
+.Sh OPTIONS
+.Bl -tag -width -indent  \" Differs from above in tag removed 
+.It Fl u Ar user
+Specifies the user whose account is to be modified
+.It Fl d Ar domain
+Specifies the directory domain containing the user account
+.It Fl k Ar keyname
+Specifies a public key by its name
+.It Fl h Ar hash
+Specifies a public key by its hash
+.It Fl v
+Verbose mode
+.El                      \" Ends the list
+.Sh NOTES
+.Nm
+is a shell script.  It is intended to be modified by administrators to 
+suit their local environments.  
+.Pp
+.Nm
+is only known to work with a local directory.  Consult the script's source
+for some limited guidance to using remote directories.  
+.Sh BUGS
+.Nm
+.Ar hash
+might display the hashes of encryption keys as well as signing keys, even
+though 
+.Nm
+.Ar accept
+does not work with encryption keys.  

Added: trunk/SmartCardServices/installPhase/scripts/sc_auth
===================================================================
--- trunk/SmartCardServices/installPhase/scripts/sc_auth	                        (rev 0)
+++ trunk/SmartCardServices/installPhase/scripts/sc_auth	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,148 @@
+#!/bin/bash
+#
+# sc_auth - smart card authorization setup script
+#
+# You can log in with a smart card if the authentication_authority field
+# of your user record contains an entry of the form
+#	;pubkeyhash;THEHASH
+# where THEHASH is the hex encoding of the SHA1 of the public key to be used.
+# (In keychains, this is the value in the Label attribute of keys, and of
+# the PublicKeyHash # attribute of certificate records.)
+#
+# This script allows you to get the hash from a smartcard, and to create
+# the appropriate authority entry in a user account. It also lets you list
+# and delete them. It works as is for (local) NetInfo directories. If you
+# use LDAP or more exotic directory sources, you'll have to find your own
+# way to store the authentication_authority information, but the workflow
+# is the same. Feel free to hack.
+#
+# This script assumes the Tiger version of the /usr/bin/security command.
+# It will probably not work (without modification) with future versions.
+#
+# This script has been updated to use the dscl command in place of the
+# deprecated nicl command. To use the standard name in the header file:
+#	/System/Library/Frameworks/DirectoryService.framework/Headers/DirServicesConst.h
+# we have replaced "authentication_authority" with "AuthenticationAuthority"
+
+#set -x
+
+# general functions
+die() { echo "$*" 1>&2; exit 1; }
+note() { [ $verbose = yes ] && echo "$*" 1>&2; }
+
+usage() {
+cat <<EOU
+Usage:	$(basename $0) accept [-v] [-u user] [-d domain] [-k keyname] # by key on inserted card(s)
+	$(basename $0) accept [-v] [-u user] [-d domain] -h hash # by known pubkey hash
+	$(basename $0) remove [-v] [-u user] [-d domain] # remove all public keys for this user
+	$(basename $0) hash [-k keyname] # print hashes for keys on inserted card(s)
+	$(basename $0) list [-v] [-u user] [-d domain] # list pubkey hashes that can authenticate this user
+EOU
+exit 2
+}
+
+# first argument is a command word
+[ -n "$1" ] || usage
+command=$1; shift
+
+# parse options
+user=${USER:-$(logname)}
+keyname=
+hash=
+verbose=no
+domain="."
+while getopts d:h:k:u:v arg; do
+  case $arg in
+  d)	domain="$OPTARG";;
+  h)	hash="$OPTARG";;
+  k)	keyname="$OPTARG";;
+  u)	user="$OPTARG";;
+  v)	verbose=yes;;
+  esac
+done
+shift $(($OPTIND - 1))
+
+
+#
+# Using "security dump-keychain", extract the public key hash for a key
+# on a smartcard and print it to stdout.
+# The optional argument is a regular expression to match against the
+# print name of the key.
+# Prints all matching keys; aborts if none are found.
+#
+hash_for_key() {
+  # hash_for_key [string in name]
+  string=${1:-'.*'}
+  HOME=/no/where /usr/bin/security dump-keychain |
+  awk -v RE="$string" '
+	/^    0x00000001/	{
+		if (matched = ($2 ~ RE)) { name=$0; sub("^.*<blob>=\"", "", name); sub("\"$", "", name); count++; }}
+	/^    0x00000006/	{
+		if (matched) { hash=$2; sub("<blob>=0x", "", hash); print hash, name; }}
+  '
+  HOME=/no/where /usr/bin/security dump-keychain |
+  awk -v RE="$string" '
+	/^    0x01000000/	{
+		if (matched = ($2 ~ RE)) { name=$0; sub("^.*<blob>=\"", "", name); sub("\"$", "", name); count++; }}
+	/^    0x06000000/	{
+		if (matched) { hash=$2; sub("<blob>=0x", "", hash); print hash, name; }}
+  '
+}
+
+
+get_hash() {
+  if [ -n "$hash" ]; then	# passed in
+	echo "$hash"
+  else						# find it
+	hash_for_key "$keyname" |
+	(
+	  read hash rest
+	  [ -n "$hash" ] || die "No matching keys found"
+	  [ $verbose = yes ] && note "Using key \"$rest\""
+	  echo $hash
+	)
+  fi
+}
+
+
+accept_user() {
+  local hash="$1"
+  [ -n "$hash" ] || die "No hash specified"
+  dscl "$domain" -append "/Users/$user" AuthenticationAuthority ";pubkeyhash;$hash"
+}
+
+remove_user() {
+  set -- $(dscl "$domain" -read "/Users/$user" AuthenticationAuthority)
+  shift		# skip authentication_authority: header
+  while [ -n "$1" ]; do
+	case "$1" in
+	\;pubkeyhash\;*)
+	  dscl "$domain" -delete "/Users/$user" AuthenticationAuthority "$1"
+	  [ $verbose = yes ] && note "Removed $1"
+	  ;;
+	esac
+	shift
+  done
+}
+
+list_hashes() {
+  set -- $(dscl "$domain" -read "/Users/$user" AuthenticationAuthority)
+  shift		# skip authentication_authority: header
+  while [ -n "$1" ]; do
+	case "$1" in
+	\;pubkeyhash\;*)
+	  echo $1 | sed -e 's/;pubkeyhash;//'
+	  ;;
+	esac
+	shift
+  done
+}
+
+
+case "$command" in
+  hash)		hash_for_key "$keyname";;
+  accept)	accept_user $(get_hash);;
+  remove)	remove_user;;
+  list)		list_hashes;;
+  *)		usage;;
+esac


Property changes on: trunk/SmartCardServices/installPhase/scripts/sc_auth
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/SmartCardServices/pbx/config.h
===================================================================
--- trunk/SmartCardServices/pbx/config.h	                        (rev 0)
+++ trunk/SmartCardServices/pbx/config.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,36 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if you have the daemon function.  */
+#define HAVE_DAEMON 1
+
+/* Name of package */
+#define PACKAGE "PCSC Framework"
+
+/* Version number of package */
+#define VERSION "1.1.1"
+
+/* OSX */
+#define PCSC_TARGET_OSX 1
+#define MSC_TARGET_OSX 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* enable full PCSC debug messaging. */
+  #define PCSC_DEBUG 1
+
+/* enable full musclecard debug messaging. */
+  #define MSC_DEBUG 1
+
+/* display ATR parsing debug messages. */
+/* #define ATR_DEBUG */
+
+/* send messages to syslog instead of stdout */
+/* #define USE_SYSLOG */
+
+/* pcsc runs as a daemon in the background. */
+#define USE_DAEMON 1
+
+/* enable client side thread safety. */
+#define USE_THREAD_SAFETY 1
+


Property changes on: trunk/SmartCardServices/pbx/config.h
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/SmartCardServices/src/CACPlugin/commonAccessCard.c
===================================================================
--- trunk/SmartCardServices/src/CACPlugin/commonAccessCard.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CACPlugin/commonAccessCard.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,2057 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+            Title  : commonAccessCard.c
+            Package: CAC Plugin
+            Author : David Corcoran
+            Date   : 02/06/02
+            License: Copyright (C) 2002 David Corcoran
+                     <corcoran at linuxnet.com>
+
+            Purpose: This abstracts the CAC APDU's
+	             into client side function calls.
+ 
+********************************************************************/
+
+#ifdef WIN32
+#include "../win32/CACPlugin.h"
+#endif
+
+#ifndef __APPLE__
+#include <musclecard.h>
+#else
+#include <PCSC/musclecard.h>
+#endif
+#include "commonAccessCard.h"
+#include <zlib.h>
+#include <string.h>
+#include <stdio.h>
+
+/* Define to turn on APDU debugging */
+/* #define MSC_DEBUG 1 */
+
+static int suppressResponse = 0;
+static int tlvsCached       = 0;
+
+static MSCUShort16 pntbSize = 0;
+static MSCUShort16 pnvbSize = 0;
+static MSCUShort16 pltbSize = 0;
+static MSCUShort16 plvbSize = 0;
+static MSCUShort16 bstbSize = 0;
+static MSCUShort16 bsvbSize = 0;
+static MSCUShort16 obtbSize = 0;
+static MSCUShort16 obvbSize = 0;
+
+typedef struct {
+  MSCUChar8  pBuffer[MAX_BUFFER_SIZE];
+  MSCULong32 bufferSize;
+  MSCUChar8  apduResponse[MAX_BUFFER_SIZE];
+  MSCULong32 apduResponseSize;
+  LPSCARD_IO_REQUEST ioType;
+} MSCTransmitBuffer, *MSCLPTransmitBuffer;
+
+MSC_RV convertPCSC( MSCLong32 );
+MSCUShort16 convertSW( MSCPUChar8 );
+void MemCopy16( MSCPUChar8, MSCPUShort16 );
+void MemCopy32( MSCPUChar8, MSCPULong32 );
+void MemCopyTo16( MSCPUShort16, MSCPUChar8 );
+void MemCopyTo32( MSCPULong32, MSCPUChar8 );
+MSCUShort16 getUShort16( MSCPUChar8 );
+void setUShort16( MSCPUChar8, MSCUShort16 );
+
+MSCLong32 SCardExchangeAPDU( MSCLPTokenConnection pConnection, 
+			                 MSCLPTransmitBuffer transmitBuffer );
+  
+#define CAC_IDCERT_OBJID            "C7"
+#define CAC_ECRYCERT_OBJID          "C3"
+#define CAC_ESIGCERT_OBJID          "C5"
+#define CAC_IDCERTATT_OBJID         "c7"
+#define CAC_ECRYCERTATT_OBJID       "c3"
+#define CAC_ESIGCERTATT_OBJID       "c5"
+#define CAC_IDKEYATT_OBJID          "k7"
+#define CAC_ECRYKEYATT_OBJID        "k3"
+#define CAC_ESIGKEYATT_OBJID        "k5"
+
+#define CAC_PNTB_OBJID             "PNTB"
+#define CAC_PNVB_OBJID             "PNVB"
+
+#define CAC_PLTB_OBJID             "PLTB"
+#define CAC_PLVB_OBJID             "PLVB"
+
+#define CAC_BSTB_OBJID             "BSTB"
+#define CAC_BSVB_OBJID             "BSVB"
+
+#define CAC_OBTB_OBJID             "OBTB"
+#define CAC_OBVB_OBJID             "OBVB"
+
+#define CAC_LABEL_ID               "Identification"
+#define CAC_LABEL_ESIG             "Email Certificate"
+#define CAC_LABEL_ECRY             "Email Certificate"
+#define CAC_MAXSIZE_CERT           4000
+#define CAC_MAXSIZE_SIGNDATA       0x80
+#define CAC_KEYNUM_ID                 7
+#define CAC_KEYNUM_ESIG               5
+#define CAC_KEYNUM_ECRY               3
+
+
+/* ID Applet */
+MSCUChar8 CAC_APPLET_ID_AID[7]       = 
+{0xA0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00}; 
+/* PKI ID Instance */
+MSCUChar8 CAC_APPLET_PKI_ID_AID[7]   = 
+{0xA0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00}; 
+/* PKI Email Signature Instance */
+MSCUChar8 CAC_APPLET_PKI_ESIG_AID[7] = 
+{0xA0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x01}; 
+/* PKI Email Encryption Instance */
+MSCUChar8 CAC_APPLET_PKI_ECRY_AID[7] = 
+{0xA0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x02}; 
+MSCUChar8 CAC_APPLET_CONT_PN_AID[7] = 
+{0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00}; 
+MSCUChar8 CAC_APPLET_CONT_PL_AID[7] = 
+{0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x01}; 
+MSCUChar8 CAC_APPLET_CONT_BS_AID[7] = 
+{0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x02}; 
+MSCUChar8 CAC_APPLET_CONT_OB_AID[7] = 
+{0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x03};
+
+static MSCULong32 cacIDCertAttrSize     = 48;
+static MSCULong32 cacECryptCertAttrSize = 45;
+static MSCULong32 cacESignCertAttrSize  = 45;
+static MSCULong32 cacIDKeyAttrSize      = 245;
+static MSCULong32 cacECryptKeyAttrSize  = 245;
+static MSCULong32 cacESignKeyAttrSize   = 245;
+
+static MSCUChar8 cacIDCertAttr[48] = {
+  0x00, 0x63, 0x37, 0x00, 0x00, 0x00, 0x29,
+  0x00, 0x00, 0x00, 0x80, 0x00, 0x04,
+  0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+  0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x08,
+  'I', 'd', 'e', 'n', 't', 'i', 't', 'y',
+  0x00, 0x00, 0x01, 0x02, 0x00, 0x01,
+  CAC_KEYNUM_ID
+};
+
+static MSCUChar8 cacESignCertAttr[45] = {
+  0x00, 0x63, 0x35, 0x00, 0x00, 0x00, 0x26,
+  0x00, 0x00, 0x00, 0x80, 0x00, 0x04,
+  0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+  0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x05,
+  'E', 'm', 'a', 'i', 'l',
+  0x00, 0x00, 0x01, 0x02, 0x00, 0x01,
+  CAC_KEYNUM_ESIG
+};
+
+static MSCUChar8 cacECryptCertAttr[45] = {
+  0x00, 0x63, 0x33, 0x00, 0x00, 0x00, 0x26,
+  0x00, 0x00, 0x00, 0x80, 0x00, 0x04,
+  0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+  0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x05,
+  'E', 'm', 'a', 'i', 'l',
+  0x00, 0x00, 0x01, 0x02, 0x00, 0x01,
+  CAC_KEYNUM_ECRY
+};
+
+
+static MSCUChar8 cacIDKeyAttr[245] = {
+  0x00,               /* Object type */
+  0x6B, 0x37,         /* Object id   */
+  0x00, 0x00,         /* Next id     */
+  0x00, 0xEE,         /* Data len    */
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x04,  /* CKA_CLASS                */
+  0x03, 0x00, 0x00, 0x00,              /* Value                    */
+
+  0x00, 0x00, 0x01, 0x02, 0x00, 0x01,  /* CKA_ID                   */
+  CAC_KEYNUM_ID,                       /* Value                    */
+
+  0x00, 0x00, 0x01, 0x62, 0x00, 0x01,  /* CKA_EXTRACTABLE          */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x09, 0x00, 0x01,  /* CKA_SIGN_RECOVER         */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x0C, 0x00, 0x01,  /* CKA_DERIVE               */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x70, 0x00, 0x01,  /* CKA_MODIFIABLE           */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x07, 0x00, 0x01,  /* CKA_UNWRAP               */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x05, 0x00, 0x01,  /* CKA_DECRYPT              */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x00, 0x02, 0x00, 0x01,  /* CKA_PRIVATE              */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x08, 0x00, 0x01,  /* CKA_SIGN                 */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x64, 0x00, 0x01,  /* CKA_NEVER_EXTRACTABLE    */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x65, 0x00, 0x01,  /* CKA_ALWAYS_SENSITIVE     */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x03, 0x00, 0x01,  /* CKA_SENSITIVE            */
+  0x01,
+
+  0x00, 0x00, 0x01, 0x00, 0x00, 0x04,  /* CKA_KEY_TYPE             */
+  0x00, 0x00, 0x00, 0x00,              /* Value                    */
+
+  0x00, 0x00, 0x01, 0x20, 0x00, 0x80,  /* CKA_MODULUS              */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+
+};
+
+static MSCUChar8 cacECryptKeyAttr[245] = {
+  0x00,               /* Object type */
+  0x6B, 0x33,         /* Object id   */
+  0x00, 0x00,         /* Next id     */
+  0x00, 0xEE,         /* Data len    */
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x04,  /* CKA_CLASS                */
+  0x03, 0x00, 0x00, 0x00,              /* Value                    */
+
+  0x00, 0x00, 0x01, 0x02, 0x00, 0x01,  /* CKA_ID                   */
+  CAC_KEYNUM_ECRY,                     /* Value                    */
+
+  0x00, 0x00, 0x01, 0x62, 0x00, 0x01,  /* CKA_EXTRACTABLE          */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x09, 0x00, 0x01,  /* CKA_SIGN_RECOVER         */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x0C, 0x00, 0x01,  /* CKA_DERIVE               */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x70, 0x00, 0x01,  /* CKA_MODIFIABLE           */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x07, 0x00, 0x01,  /* CKA_UNWRAP               */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x05, 0x00, 0x01,  /* CKA_DECRYPT              */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x00, 0x02, 0x00, 0x01,  /* CKA_PRIVATE              */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x08, 0x00, 0x01,  /* CKA_SIGN                 */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x64, 0x00, 0x01,  /* CKA_NEVER_EXTRACTABLE    */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x65, 0x00, 0x01,  /* CKA_ALWAYS_SENSITIVE     */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x03, 0x00, 0x01,  /* CKA_SENSITIVE            */
+  0x01,
+
+  0x00, 0x00, 0x01, 0x00, 0x00, 0x04,  /* CKA_KEY_TYPE             */
+  0x00, 0x00, 0x00, 0x00,              /* Value                    */
+
+  0x00, 0x00, 0x01, 0x20, 0x00, 0x80,  /* CKA_MODULUS              */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static MSCUChar8 cacESignKeyAttr[245] = {
+  0x00,               /* Object type */
+  0x6B, 0x35,         /* Object id   */
+  0x00, 0x00,         /* Next id     */
+  0x00, 0xEE,         /* Data len    */
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x04,  /* CKA_CLASS                */
+  0x03, 0x00, 0x00, 0x00,              /* Value                    */
+
+  0x00, 0x00, 0x01, 0x02, 0x00, 0x01,  /* CKA_ID                   */
+  CAC_KEYNUM_ESIG,                     /* Value                    */
+
+  0x00, 0x00, 0x01, 0x62, 0x00, 0x01,  /* CKA_EXTRACTABLE          */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x09, 0x00, 0x01,  /* CKA_SIGN_RECOVER         */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x0C, 0x00, 0x01,  /* CKA_DERIVE               */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x70, 0x00, 0x01,  /* CKA_MODIFIABLE           */
+  0x00,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x07, 0x00, 0x01,  /* CKA_UNWRAP               */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x05, 0x00, 0x01,  /* CKA_DECRYPT              */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x00, 0x02, 0x00, 0x01,  /* CKA_PRIVATE              */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x08, 0x00, 0x01,  /* CKA_SIGN                 */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x64, 0x00, 0x01,  /* CKA_NEVER_EXTRACTABLE    */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x65, 0x00, 0x01,  /* CKA_ALWAYS_SENSITIVE     */
+  0x01,                                /* Value                    */
+  0x00, 0x00, 0x01, 0x03, 0x00, 0x01,  /* CKA_SENSITIVE            */
+  0x01,
+
+  0x00, 0x00, 0x01, 0x00, 0x00, 0x04,  /* CKA_KEY_TYPE             */
+  0x00, 0x00, 0x00, 0x00,              /* Value                    */
+
+  0x00, 0x00, 0x01, 0x20, 0x00, 0x80,  /* CKA_MODULUS              */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static MSCUChar8 cacIDCert[CAC_MAXSIZE_CERT];
+static MSCUChar8 cacESignCert[CAC_MAXSIZE_CERT];
+static MSCUChar8 cacECryptCert[CAC_MAXSIZE_CERT];
+static MSCUChar8 cacCompBuffer[CAC_MAXSIZE_CERT];
+static MSCUShort16 cacIDCertSize     = 0;
+static MSCUShort16 cacESignCertSize  = 0;
+static MSCUShort16 cacECryptCertSize = 0;
+static MSCUChar8 dataIsCached        = 0;
+
+
+MSC_RV CACLoadAndCacheData(MSCLPTokenConnection pConnection);
+
+MSC_RV CACLoadTLVSize(MSCLPTokenConnection pConnection, 
+		      MSCPUChar8 demoPointer,
+		      MSCULong32 demoSize,
+		      MSCPUShort16 tlvSize,
+		      MSCUChar8 tlvType);
+
+MSC_RV CACLoadCertificate(MSCLPTokenConnection pConnection, MSCPUChar8 cert,
+			  MSCPUShort16 certSize);
+
+MSC_RV CACSelectInstance(MSCLPTokenConnection pConnection, MSCPUChar8 aid,
+			 MSCULong32 aidLength);
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteFramework( MSCLPTokenConnection pConnection,
+			     MSCLPInitTokenParams pInitParams ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCGetStatus( MSCLPTokenConnection pConnection, 
+			MSCLPStatusInfo pStatusInfo ) {
+
+  pStatusInfo->appVersion  = 0xFF;
+  pStatusInfo->swVersion   = 0xFF;
+  pStatusInfo->freeMemory  = 0x00;
+  pStatusInfo->totalMemory = 0x00;
+  pStatusInfo->usedPINs    = 1;
+  pStatusInfo->usedKeys    = 3;
+  pStatusInfo->loggedID    = pConnection->loggedIDs;;
+
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCGetCapabilities( MSCLPTokenConnection pConnection, MSCULong32 Tag,
+			      MSCPUChar8 Value, MSCPULong32 Length ) {
+
+  MSCULong32  ulValue;
+  MSCUShort16 usValue;
+  MSCUChar8  ucValue;
+  MSCUChar8  tagType;
+
+  /* 4 - MSCULong32, 2 - MSCUShort16, 1 - MSCUChar8 */
+
+  ulValue = 0; usValue = 0; ucValue = 0; tagType = 0;
+
+  switch(Tag) {
+
+  case MSC_TAG_SUPPORT_FUNCTIONS:
+    ulValue = MSC_SUPPORT_COMPUTECRYPT | MSC_SUPPORT_LISTKEYS |
+      MSC_SUPPORT_VERIFYPIN | MSC_SUPPORT_LISTPINS | MSC_SUPPORT_READOBJECT |
+      MSC_SUPPORT_LISTOBJECTS | MSC_SUPPORT_GETCHALLENGE | 
+      MSC_SUPPORT_CHANGEPIN;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_SUPPORT_CRYPTOALG:
+    ulValue = MSC_SUPPORT_RSA;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_RSA:
+    ulValue = MSC_CAPABLE_RSA_1024 | MSC_CAPABLE_RSA_NOPAD;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_ATTR:
+    ulValue = 0;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_IDSIZE:
+    ucValue = 16;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_AUTH:
+    usValue = MSC_AUT_NONE;
+    tagType = 2;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_MAXNUM:
+    ulValue = 17;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_ATTR:
+    ulValue = 0;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MAXNUM:
+    ucValue = 1;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MINSIZE:
+    ucValue = 8;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MAXSIZE:
+    ucValue = 8;
+    tagType = 1;
+    break;
+    
+  case MSC_TAG_CAPABLE_PIN_CHARSET:
+    ulValue = MSC_CAPABLE_PIN_A_Z | MSC_CAPABLE_PIN_a_z | 
+      MSC_CAPABLE_PIN_0_9 | MSC_CAPABLE_PIN_CALC | MSC_CAPABLE_PIN_NONALPHA;
+    tagType = 4;
+    break;
+
+ case MSC_TAG_CAPABLE_PIN_POLICY:
+   ulValue = 0;
+   tagType = 4;
+   break;
+
+  case MSC_TAG_CAPABLE_ID_STATE:
+    ucValue = 0;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_RANDOM_MAX:
+    ucValue = 8;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_RANDOM_MIN:
+    ucValue = 8;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_KEY_AUTH:
+    usValue = MSC_AUT_NONE;
+    tagType = 2;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_AUTH:
+    usValue = MSC_AUT_NONE;
+    tagType = 2;
+    break;
+
+  default:
+    return MSC_INVALID_PARAMETER;
+  }
+
+  switch(tagType) {
+  case 1:
+    memcpy(Value, &ucValue, 1);
+    break;
+  case 2:
+    memcpy(Value, &usValue, 2);
+    break;
+  case 4:
+    memcpy(Value, &ulValue, 4);
+    break;
+  }
+
+  *Length = tagType;
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCExtendedFeature( MSCLPTokenConnection pConnection, 
+			      MSCULong32 extFeature,
+			      MSCPUChar8 outData, MSCULong32 outLength, 
+			      MSCPUChar8 inData, MSCPULong32 inLength ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCGenerateKeys( MSCLPTokenConnection pConnection, 
+			   MSCUChar8 prvKeyNum, MSCUChar8 pubKeyNum, 
+			   MSCLPGenKeyParams pParams ) {
+ 
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCImportKey( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+                        MSCLPKeyACL pKeyACL, MSCPUChar8 pKeyBlob, 
+			MSCULong32 keyBlobSize, MSCLPKeyPolicy keyPolicy, 
+			MSCPVoid32 pAddParams, MSCUChar8 addParamsSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+ 
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCExportKey( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+			MSCPUChar8 pKeyBlob, MSCPULong32 keyBlobSize, 
+			MSCPVoid32 pAddParams, MSCUChar8 addParamsSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCComputeCrypt( MSCLPTokenConnection pConnection,
+			   MSCLPCryptInit cryptInit, MSCPUChar8 pInputData,
+			   MSCULong32 inputDataSize, MSCPUChar8 pOutputData,
+			   MSCPULong32 outputDataSize ) {
+  MSCLong32 rv;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCPUChar8 pkiPointer;
+  MSCULong32 pkiSize;
+  MSCTransmitBuffer tBuffer;
+
+  rv = CACLoadAndCacheData(pConnection);
+  if (rv != MSC_SUCCESS) return rv;
+
+  if ( inputDataSize != CAC_MAXSIZE_SIGNDATA ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  if ( cryptInit->cipherMode != MSC_MODE_RSA_NOPAD ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  if ( cryptInit->cipherDirection != MSC_DIR_SIGN &&
+       cryptInit->cipherDirection != MSC_DIR_ENCRYPT &&
+	   cryptInit->cipherDirection != MSC_DIR_DECRYPT) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+
+  if ( cryptInit->keyNum == CAC_KEYNUM_ID ) {
+    if ( cacIDCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+    
+      pkiPointer      = CAC_APPLET_PKI_ID_AID;
+      pkiSize         = sizeof(CAC_APPLET_PKI_ID_AID);
+
+  } else if ( cryptInit->keyNum == CAC_KEYNUM_ESIG ) {
+    if ( cacESignCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    pkiPointer      = CAC_APPLET_PKI_ESIG_AID;
+    pkiSize         = sizeof(CAC_APPLET_PKI_ESIG_AID);
+
+  } else if ( cryptInit->keyNum == CAC_KEYNUM_ECRY ) {
+    if ( cacECryptCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    pkiPointer      = CAC_APPLET_PKI_ECRY_AID;
+    pkiSize         = sizeof(CAC_APPLET_PKI_ECRY_AID);
+
+  } else {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  /* Select the instance associated with this key */
+  rv = CACSelectInstance( pConnection, pkiPointer, pkiSize );
+  if ( rv != MSC_SUCCESS )
+    return rv;
+
+  tBuffer.bufferSize = inputDataSize + 5;
+
+  /* Select AID */
+  txBuffer[0] = 0x80; txBuffer[1] = 0x42;  txBuffer[2] = 0x00; 
+  txBuffer[3] = 0x00; txBuffer[4] = inputDataSize;
+
+  memcpy(&txBuffer[5], pInputData, inputDataSize);
+  
+  tBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &tBuffer);
+
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( tBuffer.apduResponseSize != inputDataSize + 2 ) {
+    return MSC_UNSPECIFIED_ERROR;
+  } else if ( rxBuffer[tBuffer.apduResponseSize-2] != 0x90 ) {
+    return MSC_UNSPECIFIED_ERROR;
+  } 
+
+  memcpy(pOutputData, rxBuffer, inputDataSize);
+  *outputDataSize = inputDataSize;
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCExtAuthenticate( MSCLPTokenConnection pConnection, 
+			      MSCUChar8 keyNum, MSCUChar8 cipherMode, 
+			      MSCUChar8 cipherDirection,
+			      MSCPUChar8 pData, MSCULong32 dataSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCListKeys( MSCLPTokenConnection pConnection, 
+		       MSCUChar8 seqOption, MSCLPKeyInfo pKeyInfo ) {
+
+  MSC_RV rv;
+  static int seq = 0;
+
+  rv = CACLoadAndCacheData(pConnection);
+  if (rv != MSC_SUCCESS) return rv;
+
+  if (seqOption == MSC_SEQUENCE_RESET) {
+    seq = 0;
+  }
+
+  switch(seq) {
+
+  case 0:
+    if ( cacECryptCertSize != 0 ) {
+      pKeyInfo->keySize = 1024;
+      pKeyInfo->keyNum  = CAC_KEYNUM_ECRY;
+      pKeyInfo->keyType = MSC_KEY_RSA_PRIVATE;
+      break;
+    } else {
+      seq += 1;
+    }
+  case 1:
+    if ( cacESignCertSize != 0 ) {
+      pKeyInfo->keySize = 1024;
+      pKeyInfo->keyNum  = CAC_KEYNUM_ESIG;
+      pKeyInfo->keyType = MSC_KEY_RSA_PRIVATE;
+      break;
+    } else {
+      seq += 1;
+    }
+  case 2:
+    if ( cacIDCertSize != 0 ) {
+      pKeyInfo->keySize = 1024;
+      pKeyInfo->keyNum  = CAC_KEYNUM_ID;
+      pKeyInfo->keyType = MSC_KEY_RSA_PRIVATE;
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 3:
+    return MSC_SEQUENCE_END;
+
+  }
+
+  /* For keys, use only - pin verification needed, no write */
+  pKeyInfo->keyACL.readPermission  = MSC_AUT_NONE;
+  pKeyInfo->keyACL.writePermission = MSC_AUT_NONE;
+  pKeyInfo->keyACL.usePermission   = MSC_AUT_PIN_1;
+  pKeyInfo->keyPolicy.cipherMode   = MSC_KEYPOLICY_MODE_RSA_NOPAD;
+  pKeyInfo->keyPolicy.cipherDirection = MSC_KEYPOLICY_DIR_SIGN | MSC_KEYPOLICY_DIR_VERIFY |
+    MSC_KEYPOLICY_DIR_ENCRYPT | MSC_KEYPOLICY_DIR_DECRYPT;  
+
+  seq += 1;
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCCreatePIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			MSCUChar8 pinAttempts, MSCPUChar8 pPinCode,
+			MSCULong32 pinCodeSize, MSCPUChar8 pUnblockCode,
+			MSCUChar8 unblockCodeSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCVerifyPIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			MSCPUChar8 pPinCode, MSCULong32 pinCodeSize ) {
+  
+  MSCLong32 rv;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCUChar8 pinPad[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+  MSCTransmitBuffer tBuffer;
+  
+  rv = CACLoadAndCacheData(pConnection);
+  if (rv != MSC_SUCCESS) return rv;  
+  
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+  
+  txBuffer[OFFSET_CLA] = 0x80;
+  txBuffer[OFFSET_INS] = 0x20;
+  txBuffer[OFFSET_P1]  = 0x00;
+  txBuffer[OFFSET_P2]  = 0x00;
+  txBuffer[OFFSET_P3]  = 0x08;
+  
+  if ( pinNum != 1 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  if ( pinCodeSize > 8 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  memcpy(pinPad, pPinCode, pinCodeSize);
+
+#ifdef CAC_PROTECTED_MODE
+  printf("Protected Mode: Injecting default pin\n");
+  memcpy(&txBuffer[OFFSET_DATA], "77777777", 8);
+  tBuffer.bufferSize = 8 + 5;
+#else
+  memcpy(&txBuffer[OFFSET_DATA], pinPad, 8);
+  tBuffer.bufferSize = 8 + 5;
+#endif
+
+  tBuffer.apduResponseSize = MAX_BUFFER_SIZE;
+  rv = SCardExchangeAPDU(pConnection, &tBuffer);
+  
+  if(rv != SCARD_S_SUCCESS) {
+    return convertPCSC(rv);
+  }
+
+  if(tBuffer.apduResponseSize == 2) {
+    if (rxBuffer[0] == 0x90 && rxBuffer[1] == 0x00 ) {
+      pConnection->loggedIDs |= MSC_AUT_PIN_1;
+      return MSC_SUCCESS;
+    } else if ( rxBuffer[0] == 0x63 ) {
+      pConnection->loggedIDs = 0;
+      return MSC_AUTH_FAILED;
+    } else {
+      pConnection->loggedIDs = 0;
+      return convertSW(rxBuffer);
+    }
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCChangePIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			MSCPUChar8 pOldPinCode, MSCUChar8 oldPinCodeSize,
+			MSCPUChar8 pNewPinCode, MSCUChar8 newPinCodeSize ) {
+
+  MSCLong32 rv;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCUChar8 pinPad[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+  MSCUChar8 newPinPad[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+  MSCTransmitBuffer tBuffer;
+  
+    /* Select the instance associated with this key */
+  rv = CACSelectInstance( pConnection, CAC_APPLET_ID_AID, 7 );
+  if ( rv != MSC_SUCCESS ) {
+    return rv;
+  }
+ 
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+  
+  txBuffer[OFFSET_CLA] = 0x80;
+  txBuffer[OFFSET_INS] = 0x24;
+  txBuffer[OFFSET_P1]  = 0x01;
+  txBuffer[OFFSET_P2]  = 0x00;
+  txBuffer[OFFSET_P3]  = 0x10;
+  
+  if ( pinNum != 1 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  if ( oldPinCodeSize > 8 || newPinCodeSize > 8 ||
+       oldPinCodeSize < 4 || newPinCodeSize < 4 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  memcpy(pinPad, pOldPinCode, oldPinCodeSize);
+  memcpy(newPinPad, pNewPinCode, newPinCodeSize);
+
+  memcpy(&txBuffer[OFFSET_DATA], pinPad, 8);
+  memcpy(&txBuffer[OFFSET_DATA+8], newPinPad, 8);
+ 
+  tBuffer.bufferSize = 16 + 5;
+  tBuffer.apduResponseSize = MAX_BUFFER_SIZE;
+    
+  rv = SCardExchangeAPDU(pConnection, &tBuffer);
+  
+  if(rv != SCARD_S_SUCCESS) {
+    return convertPCSC(rv);
+  }
+
+  if(tBuffer.apduResponseSize == 2) {
+    if (rxBuffer[0] == 0x90 && rxBuffer[1] == 0x00 ) {
+      return MSC_SUCCESS;
+    } else if ( rxBuffer[0] == 0x63 ) {
+      return MSC_AUTH_FAILED;
+    } else {
+      return convertSW(rxBuffer);
+    }
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCUnblockPIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			 MSCPUChar8 pUnblockCode, 
+			 MSCULong32 unblockCodeSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCListPINs( MSCLPTokenConnection pConnection, 
+		       MSCPUShort16 pPinBitMask ) {
+
+  
+  *pPinBitMask = 2;  /* Just one pin on CAC */
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCCreateObject( MSCLPTokenConnection pConnection, 
+			   MSCString objectID, MSCULong32 objectSize, 
+			   MSCLPObjectACL pObjectACL ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCDeleteObject( MSCLPTokenConnection pConnection, 
+			   MSCString objectID, MSCUChar8 zeroFlag ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteObject( MSCLPTokenConnection pConnection, 
+			  MSCString objectID, MSCULong32 offset, 
+			  MSCPUChar8 pInputData, MSCUChar8 dataSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCReadObject( MSCLPTokenConnection pConnection, MSCString objectID, 
+			 MSCULong32 offset, MSCPUChar8 pOutputData, 
+			 MSCUChar8 dataSize ) {
+
+  MSCLong32 rv;
+  MSCPUChar8 demoPointer;
+  MSCULong32 demoSize;
+  MSCPUChar8 itemValue;
+  MSCULong32 itemSize;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCTransmitBuffer tBuffer;
+  MSCUChar8 readLocation;
+
+  demoSize     = 0; demoPointer = 0;
+  itemValue    = 0; itemSize    = 0;
+  readLocation = 0;
+
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+
+  rv = CACLoadAndCacheData(pConnection);
+  if (rv != MSC_SUCCESS) return rv;
+
+  if ( strcmp(objectID, CAC_IDCERT_OBJID) == 0 ) {
+      if ( cacIDCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    itemValue = cacIDCert;
+    itemSize  = cacIDCertSize;
+
+  } else if ( strcmp(objectID, CAC_ECRYCERT_OBJID) == 0 ) {
+    if ( cacECryptCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    itemValue = cacECryptCert;
+    itemSize  = cacECryptCertSize;
+
+  } else if ( strcmp(objectID, CAC_ESIGCERT_OBJID) == 0 ) {
+    if ( cacESignCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    itemValue = cacESignCert;
+    itemSize  = cacESignCertSize;
+
+  } else if ( strcmp(objectID, CAC_IDCERTATT_OBJID) == 0 ) {
+    if ( cacIDCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+  
+    itemValue = cacIDCertAttr;
+    itemSize  = cacIDCertAttrSize;
+
+  } else if ( strcmp(objectID, CAC_ECRYCERTATT_OBJID) == 0 ) {
+    if ( cacECryptCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    itemValue = cacECryptCertAttr;
+    itemSize  = cacECryptCertAttrSize;
+
+  } else if ( strcmp(objectID, CAC_ESIGCERTATT_OBJID) == 0 ) {
+    if ( cacESignCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+  
+    itemValue = cacESignCertAttr;
+    itemSize  = cacESignCertAttrSize;
+
+  } else if ( strcmp(objectID, CAC_IDKEYATT_OBJID) == 0 ) {
+    if ( cacIDCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    itemValue = cacIDKeyAttr;
+    itemSize  = cacIDKeyAttrSize;
+
+  } else if ( strcmp(objectID, CAC_ECRYKEYATT_OBJID) == 0 ) {
+    if ( cacECryptCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    itemValue = cacECryptKeyAttr;
+    itemSize  = cacECryptKeyAttrSize;
+
+  } else if ( strcmp(objectID, CAC_ESIGKEYATT_OBJID) == 0 ) {
+    if ( cacESignCertSize == 0 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    itemValue = cacESignKeyAttr;
+    itemSize  = cacESignKeyAttrSize;
+
+  /* For the tags */
+  } else if ( strcmp(objectID, CAC_PNTB_OBJID) == 0 ) {
+    itemSize    = pntbSize;
+    demoPointer = CAC_APPLET_CONT_PN_AID;
+    demoSize    = sizeof(CAC_APPLET_CONT_PN_AID);
+    readLocation = 1; /* T-Buffer */
+  } else if ( strcmp(objectID, CAC_PLTB_OBJID) == 0 ) {
+    itemSize    = pltbSize;
+    demoPointer = CAC_APPLET_CONT_PL_AID;
+    demoSize    = sizeof(CAC_APPLET_CONT_PL_AID);
+    readLocation = 1; /* T-Buffer */
+  } else if ( strcmp(objectID, CAC_BSTB_OBJID) == 0 ) {
+    itemSize    = bstbSize;
+    demoPointer = CAC_APPLET_CONT_BS_AID;
+    demoSize    = sizeof(CAC_APPLET_CONT_BS_AID);
+    readLocation = 1; /* T-Buffer */
+  } else if ( strcmp(objectID, CAC_OBTB_OBJID) == 0 ) {
+    itemSize    = obtbSize;
+    demoPointer = CAC_APPLET_CONT_OB_AID;
+    demoSize    = sizeof(CAC_APPLET_CONT_OB_AID);
+    readLocation = 1; /* T-Buffer */
+
+    /* For the values */
+  } else if ( strcmp(objectID, CAC_PNVB_OBJID) == 0 ) {
+    itemSize    = pnvbSize;
+    demoPointer = CAC_APPLET_CONT_PN_AID;
+    demoSize    = sizeof(CAC_APPLET_CONT_PN_AID);
+    readLocation = 2; /* V-Buffer */
+  } else if ( strcmp(objectID, CAC_PLVB_OBJID) == 0 ) {
+    itemSize    = plvbSize;
+    demoPointer = CAC_APPLET_CONT_PL_AID;
+    demoSize    = sizeof(CAC_APPLET_CONT_PL_AID);
+    readLocation = 2; /* V-Buffer */
+  } else if ( strcmp(objectID, CAC_BSVB_OBJID) == 0 ) {
+    itemSize    = bsvbSize;  
+    demoPointer = CAC_APPLET_CONT_BS_AID;
+    demoSize    = sizeof(CAC_APPLET_CONT_BS_AID);
+    readLocation = 2; /* V-Buffer */
+  } else if ( strcmp(objectID, CAC_OBVB_OBJID) == 0 ) {
+    itemSize    = obvbSize;
+    demoPointer = CAC_APPLET_CONT_OB_AID;
+    demoSize    = sizeof(CAC_APPLET_CONT_OB_AID);
+    readLocation = 2; /* V-Buffer */
+
+  } else {
+    return MSC_OBJECT_NOT_FOUND;
+  }
+  
+  if (itemSize == 0) {
+    return MSC_INVALID_PARAMETER;
+  }
+  
+  if ( (dataSize + offset) > itemSize ) {
+    return MSC_INVALID_PARAMETER;
+  }
+  
+  /* Must be V-Data - this is not cached */
+  if ( readLocation == 1 || readLocation == 2 ) {
+    /* Select the correct applet */
+    rv = CACSelectInstance( pConnection, demoPointer, demoSize );
+    if ( rv != MSC_SUCCESS )
+      return rv;
+      
+    txBuffer[OFFSET_CLA]    = 0x80;
+    txBuffer[OFFSET_INS]    = 0x52;
+    txBuffer[OFFSET_P1]     = (offset/256);
+    txBuffer[OFFSET_P2]     = (offset%256);
+    txBuffer[OFFSET_P3]     = 0x02;
+    txBuffer[OFFSET_DATA]   = readLocation;
+    txBuffer[OFFSET_DATA+1] = dataSize;
+  
+    tBuffer.bufferSize = 7;
+    tBuffer.apduResponseSize = MAX_BUFFER_SIZE;
+    rv = SCardExchangeAPDU(pConnection, &tBuffer);
+    
+    if(rv != SCARD_S_SUCCESS) {
+      return convertPCSC(rv);
+    }
+
+   if (tBuffer.apduResponseSize != (dataSize + 2)) {
+      return convertSW(rxBuffer);
+    } else {
+      itemValue = rxBuffer;
+    }
+  }
+  
+  memcpy(pOutputData, &itemValue[offset], dataSize);
+  return MSC_SUCCESS;
+
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCListObjects( MSCLPTokenConnection pConnection, 
+			  MSCUChar8 seqOption, 
+			  MSCLPObjectInfo pObjectInfo ) {
+
+  static int seq = 0;
+  MSCULong32 rv;
+  MSCULong32 itemSize;
+
+  rv = CACLoadAndCacheData(pConnection);
+  if (rv != MSC_SUCCESS) {
+    return rv;
+  }
+
+  if ( seqOption == MSC_SEQUENCE_RESET ) {
+    seq = 0;
+  }
+
+  switch(seq) {
+
+  case 0:
+    /* Email Encryption Certificate */
+    itemSize = cacECryptCertSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_ECRYCERT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+  case 1:
+    /* Email Signature Certificate */
+    itemSize = cacESignCertSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_ESIGCERT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 2:
+    /* ID Certificate */
+    itemSize = cacIDCertSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_IDCERT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 3:
+    /* ID Certificate attributes */
+    itemSize = cacIDCertAttrSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_IDCERTATT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 4:
+   /* Email Encryption Certificate attributes */
+    itemSize = cacECryptCertAttrSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_ECRYCERTATT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 5:
+   /* Email Signature Certificate attributes */
+    itemSize = cacESignCertAttrSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_ESIGCERTATT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 6:
+    /* ID Key attributes */
+    itemSize = cacIDKeyAttrSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_IDKEYATT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 7:
+   /* Email Encryption Key attributes */
+    itemSize = cacECryptKeyAttrSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_ECRYKEYATT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 8:
+   /* Email Signature Key attributes */
+    itemSize = cacESignKeyAttrSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_ESIGKEYATT_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 9:
+    itemSize   = pntbSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_PNTB_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 10:
+    itemSize   = pnvbSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_PNVB_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 11:
+    itemSize   = pltbSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_PLTB_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 12:
+    itemSize   = plvbSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_PLVB_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 13:
+    itemSize   = bstbSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_BSTB_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 14:
+    itemSize   = bsvbSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_BSVB_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 15:
+    itemSize   = obtbSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_OBTB_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  case 16:
+    itemSize   = obvbSize;
+    if (itemSize != 0) { 
+      strncpy(pObjectInfo->objectID, CAC_OBVB_OBJID, MSC_MAXSIZE_OBJID);
+      break;
+    } else {
+      seq += 1;
+    }
+
+  default:
+    return MSC_SEQUENCE_END;
+  }
+  
+  /* Set the ACL */
+
+  switch(seq) {
+
+  case 0:
+  case 1:
+  case 2:
+    /* For all certificates */
+    pObjectInfo->objectACL.readPermission   = MSC_AUT_ALL;
+    pObjectInfo->objectACL.writePermission  = MSC_AUT_NONE;
+    pObjectInfo->objectACL.deletePermission = MSC_AUT_NONE;    
+    break;
+
+  case 3:
+  case 4:
+  case 5:
+    /* For all certificate attributes */
+    pObjectInfo->objectACL.readPermission   = MSC_AUT_ALL;
+    pObjectInfo->objectACL.writePermission  = MSC_AUT_NONE;
+    pObjectInfo->objectACL.deletePermission = MSC_AUT_NONE;        
+    break;
+
+  case 6:
+  case 7:
+  case 8:
+    /* For all key attributes */
+    pObjectInfo->objectACL.readPermission   = MSC_AUT_ALL;
+    pObjectInfo->objectACL.writePermission  = MSC_AUT_NONE;
+    pObjectInfo->objectACL.deletePermission = MSC_AUT_NONE;  
+    break;
+
+  case 9:
+  case 11:
+  case 13:
+  case 15:
+    /* For all tag buffers */
+    pObjectInfo->objectACL.readPermission   = MSC_AUT_ALL;
+    pObjectInfo->objectACL.writePermission  = MSC_AUT_NONE;
+    pObjectInfo->objectACL.deletePermission = MSC_AUT_NONE;
+    break;
+    
+  case 10:
+  case 12:
+  case 14:
+  case 16:
+    /* For all value buffers */
+    pObjectInfo->objectACL.readPermission   = MSC_AUT_PIN_1;
+    pObjectInfo->objectACL.writePermission  = MSC_AUT_NONE;
+    pObjectInfo->objectACL.deletePermission = MSC_AUT_NONE;
+    break;
+  }
+
+  pObjectInfo->objectSize = itemSize;
+
+  seq += 1;
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCLogoutAll( MSCLPTokenConnection pConnection ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCGetChallenge( MSCLPTokenConnection pConnection, MSCPUChar8 pSeed,
+			   MSCUShort16 seedSize, MSCPUChar8 pRandomData,
+			   MSCUShort16 randomDataSize ) {
+
+  MSCLong32 rv;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCTransmitBuffer tBuffer;
+  
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+
+  txBuffer[OFFSET_CLA] = 0x80;
+  txBuffer[OFFSET_INS] = 0x84;
+  txBuffer[OFFSET_P1]  = 0x00;
+  txBuffer[OFFSET_P2]  = 0x00;
+  txBuffer[OFFSET_P3]  = 0x08;
+  
+  if ( randomDataSize != 8 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+  
+  tBuffer.apduResponseSize = MAX_BUFFER_SIZE;
+  tBuffer.bufferSize       = 5;
+
+  rv = SCardExchangeAPDU(pConnection, &tBuffer);
+  
+  if(rv != SCARD_S_SUCCESS) {
+    return convertPCSC(rv);
+  }
+  
+  if(tBuffer.apduResponseSize == 2) {
+    return convertSW(rxBuffer);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCIdentifyToken( MSCLPTokenConnection pConnection ) {
+
+  MSCLong32 rv;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCTransmitBuffer tBuffer;
+  
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+
+  /* Select AID */
+  txBuffer[0] = 0x00; txBuffer[1] = 0xA4;  txBuffer[2] = 0x04; 
+  txBuffer[3] = 0x00; txBuffer[4] = sizeof(CAC_APPLET_PKI_ESIG_AID);  
+
+  /* Copy PKI Applet */
+  memcpy(&txBuffer[5], CAC_APPLET_PKI_ESIG_AID, 
+	 sizeof(CAC_APPLET_PKI_ESIG_AID));
+
+  tBuffer.bufferSize       = 5 + sizeof(CAC_APPLET_PKI_ESIG_AID); 
+  tBuffer.apduResponseSize = sizeof(CAC_APPLET_PKI_ESIG_AID) + 5;
+
+  suppressResponse = 1;
+  rv = SCardExchangeAPDU( pConnection, &tBuffer );
+  suppressResponse = 0;
+
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( rxBuffer[0] != 0x61 ) {
+    return MSC_UNSUPPORTED_FEATURE;
+  }
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCInitializePlugin( MSCLPTokenConnection pConnection ) {
+
+  /* Clean up and make sure all is shut down. */
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CACPLUGIN_API
+#endif
+MSC_RV PL_MSCFinalizePlugin( MSCLPTokenConnection pConnection ) {
+
+  /* Clean up and make sure all is shut down. */
+
+  tlvsCached = 0;
+  pntbSize = 0;
+  pnvbSize = 0;
+  pltbSize = 0;
+  plvbSize = 0;
+  bstbSize = 0;
+  bsvbSize = 0;
+  obtbSize = 0;
+  obvbSize = 0;
+  cacIDCertSize     = 0;
+  cacESignCertSize  = 0;
+  cacECryptCertSize = 0;
+  dataIsCached      = 0;
+  pConnection->loggedIDs  = 0;
+  
+  return MSC_SUCCESS;
+}
+
+MSC_RV CACLoadTLVSize(MSCLPTokenConnection pConnection, 
+		      MSCPUChar8 demoPointer,
+		      MSCULong32 demoSize,
+		      MSCPUShort16 tlvSize,
+		      MSCUChar8 tlvType) {
+
+  MSCLong32 rv;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCTransmitBuffer tBuffer;
+
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+
+  if ( *tlvSize != 0 ) {
+    /* Data already cached */
+    return MSC_SUCCESS;
+  }
+  
+  rv = CACSelectInstance( pConnection, demoPointer, demoSize );
+
+  if ( rv != MSC_SUCCESS )
+    return rv;
+   
+    txBuffer[OFFSET_CLA]    = 0x80;
+    txBuffer[OFFSET_INS]    = 0x56;
+    txBuffer[OFFSET_P1]     = 0x00;
+    txBuffer[OFFSET_P2]     = 0x00;
+    txBuffer[OFFSET_P3]     = 0x2E;
+    
+    tBuffer.bufferSize = 5;
+    tBuffer.apduResponseSize = MAX_BUFFER_SIZE;
+    rv = SCardExchangeAPDU(pConnection, &tBuffer);
+  
+    if(rv != SCARD_S_SUCCESS) {
+      return convertPCSC(rv);
+    }
+    
+    if ( tBuffer.apduResponseSize == 2 ) {
+      if (rxBuffer[0] == 0x6C) {  
+        /* We requested the wrong length, try again */
+        
+        txBuffer[OFFSET_P3] = rxBuffer[1];
+        tBuffer.apduResponseSize = MAX_BUFFER_SIZE;
+        rv = SCardExchangeAPDU(pConnection, &tBuffer);
+  
+        if(rv != SCARD_S_SUCCESS) {
+          return convertPCSC(rv);
+        }
+        
+      } else {
+        /* Another status return */
+        return convertSW(rxBuffer);
+      }
+
+    } else if (tBuffer.apduResponseSize != (txBuffer[OFFSET_P3] + 2)) {      
+        return MSC_INTERNAL_ERROR;
+    } 
+    
+    if ( tlvType == 0 ) {
+      /* Get the Tag */
+      *tlvSize = rxBuffer[28] + rxBuffer[29]*0x100;
+    } else {
+      /* Get the Value */
+      *tlvSize = rxBuffer[30] + rxBuffer[31]*0x100;
+    }
+      
+    return MSC_SUCCESS;
+
+}
+
+MSC_RV CACLoadCertificate(MSCLPTokenConnection pConnection, MSCPUChar8 cert,
+			  MSCPUShort16 certSize) {
+
+  MSCLong32 rv;
+  MSCULong32 dataPosition;
+  MSCULong32 defLength;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCTransmitBuffer tBuffer;
+  
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+  
+  defLength = 0; dataPosition = 0;
+
+  /* Getting certificate */
+ 
+  txBuffer[0] = 0x80; txBuffer[1] = 0x36; txBuffer[2] = 0x00; 
+  txBuffer[3] = 0x00; txBuffer[4] = 0x64;
+ 
+ /* Reading the certificate */
+ 
+  do {
+    /* Read data in 0x64 byte chunks */
+    tBuffer.bufferSize       = 0x05;
+    tBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+    rv = SCardExchangeAPDU( pConnection, &tBuffer );
+
+    if ( rv != SCARD_S_SUCCESS ) { return convertPCSC(rv); }
+
+    if ( tBuffer.apduResponseSize == 2 ) {
+      if (( rxBuffer[0] == 0x69 ) && ( rxBuffer[1] == 0x81 )) {
+          *certSize = 0;
+          return MSC_OBJECT_NOT_FOUND;
+      } else if (( rxBuffer[0] == 0x69 ) && ( rxBuffer[1] == 0x82 )) {
+          *certSize = 0;
+          return MSC_UNAUTHORIZED;
+
+      }
+    } else if ( tBuffer.apduResponseSize != txBuffer[4] + 2 ) {
+        /* Card was removed during a transaction */
+        return MSC_INTERNAL_ERROR;
+    } else {
+      memcpy(&cacCompBuffer[dataPosition], rxBuffer,
+  	     tBuffer.apduResponseSize - 2); 
+      dataPosition += tBuffer.apduResponseSize - 2;
+      txBuffer[4] = rxBuffer[tBuffer.apduResponseSize-1];
+    }
+  } while ( rxBuffer[tBuffer.apduResponseSize-2] == 0x63 ); 
+
+  /* Done reading certificate */
+
+  if (cacCompBuffer[0] == 0x01) { /* this is compressed */
+    defLength = CAC_MAXSIZE_CERT;
+    rv = uncompress(cert, (uLongf *)&defLength, &cacCompBuffer[1], 
+  		    dataPosition - 1);
+    if ( rv != 0 ) {
+      return MSC_INTERNAL_ERROR;
+    }
+
+    *certSize = defLength;
+
+  } else {
+    memcpy(cert, &cacCompBuffer[1], dataPosition - 1);
+    *certSize = dataPosition - 1;
+  }
+  
+  return MSC_SUCCESS;
+
+}
+
+MSC_RV CACSelectInstance(MSCLPTokenConnection pConnection, MSCPUChar8 aid,
+			 MSCULong32 aidLength) {
+
+  MSCLong32 rv;
+  MSCPUChar8 txBuffer;
+  MSCPUChar8 rxBuffer;
+  MSCTransmitBuffer tBuffer;
+  
+  txBuffer = tBuffer.pBuffer;
+  rxBuffer = tBuffer.apduResponse;
+
+  /* Now we must select the PKI instance, read the 
+     certificate and cache it, updating it's size  */
+
+  tBuffer.bufferSize = aidLength + 5;
+  tBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+
+  /* Select AID */
+  txBuffer[0] = 0x00; txBuffer[1] = 0xA4;  txBuffer[2] = 0x04; 
+  txBuffer[3] = 0x00; txBuffer[4] = aidLength;
+
+   memcpy(&txBuffer[5], aid, aidLength);
+
+  suppressResponse = 1;
+  rv = SCardExchangeAPDU( pConnection, &tBuffer );
+  suppressResponse = 0;
+
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( rxBuffer[0] != 0x61 ) {
+    return MSC_UNSUPPORTED_FEATURE;
+  }
+
+  return MSC_SUCCESS;
+}
+
+MSC_RV CACLoadAndCacheData(MSCLPTokenConnection pConnection) {
+
+  MSCLong32 rv;
+  MSCPUChar8 certPointer;
+  MSCPUChar8 pkiPointer;
+  MSCULong32 pkiSize;
+  MSCPUChar8 demoPointer;
+  MSCULong32 demoSize;
+  MSCPUShort16 itemCache;
+  unsigned short *certSizePointer;
+
+  if ( dataIsCached == 1 ) {
+    return MSC_SUCCESS;
+  }
+
+  pkiPointer      = CAC_APPLET_PKI_ID_AID;
+  pkiSize         = sizeof(CAC_APPLET_PKI_ID_AID);
+  certPointer     = cacIDCert;
+  certSizePointer = &cacIDCertSize;
+  
+  if ( *certSizePointer == 0 ) {
+    rv = CACSelectInstance( pConnection, pkiPointer, pkiSize );
+    if ( rv == MSC_SUCCESS )
+      rv = CACLoadCertificate(pConnection, certPointer, certSizePointer); 
+      if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+      
+    if (*certSizePointer == 0) {
+      cacIDCertAttrSize = 0;
+      cacIDKeyAttrSize  = 0;
+    }        
+  }
+  
+  pkiPointer      = CAC_APPLET_PKI_ECRY_AID;
+  pkiSize         = sizeof(CAC_APPLET_PKI_ECRY_AID);
+  certPointer     = cacECryptCert;
+  certSizePointer = &cacECryptCertSize;
+  if ( *certSizePointer == 0 ) {
+    rv = CACSelectInstance( pConnection, pkiPointer, pkiSize );
+    if ( rv == MSC_SUCCESS )
+      CACLoadCertificate(pConnection, certPointer, certSizePointer); 
+      if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+ 
+    if (*certSizePointer == 0) {
+      cacECryptCertAttrSize = 0;
+      cacECryptKeyAttrSize  = 0;
+    } 
+  }
+  
+  pkiPointer      = CAC_APPLET_PKI_ESIG_AID;
+  pkiSize         = sizeof(CAC_APPLET_PKI_ESIG_AID);
+  certPointer     = cacESignCert;
+  certSizePointer = &cacESignCertSize;
+  if ( *certSizePointer == 0 ) {
+    rv = CACSelectInstance( pConnection, pkiPointer, pkiSize );
+    if ( rv == MSC_SUCCESS )
+      CACLoadCertificate(pConnection, certPointer, certSizePointer); 
+      if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+ 
+    if (*certSizePointer == 0) {
+      cacESignCertAttrSize = 0;
+      cacESignKeyAttrSize  = 0;
+    } 
+
+
+  }
+
+  itemCache   = &pntbSize;
+  demoPointer = CAC_APPLET_CONT_PN_AID;
+  demoSize    = sizeof(CAC_APPLET_CONT_PN_AID);
+  if ( *itemCache == 0 ) {
+    rv = CACLoadTLVSize(pConnection, demoPointer, demoSize, itemCache, 0);
+  }
+
+  itemCache   = &pnvbSize;
+  demoPointer = CAC_APPLET_CONT_PN_AID;
+  demoSize    = sizeof(CAC_APPLET_CONT_PN_AID);
+  if ( *itemCache == 0 ) {
+    rv = CACLoadTLVSize(pConnection, demoPointer, demoSize, itemCache, 1);
+  }
+  
+  itemCache   = &pltbSize;
+  demoPointer = CAC_APPLET_CONT_PL_AID;
+  demoSize    = sizeof(CAC_APPLET_CONT_PL_AID);
+  if ( *itemCache == 0 ) {
+    rv = CACLoadTLVSize(pConnection, demoPointer, demoSize, itemCache, 0);
+    if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+  }
+  
+  itemCache   = &plvbSize;
+  demoPointer = CAC_APPLET_CONT_PL_AID;
+  demoSize    = sizeof(CAC_APPLET_CONT_PL_AID);
+  if ( *itemCache == 0 ) {
+    rv = CACLoadTLVSize(pConnection, demoPointer, demoSize, itemCache, 1);
+    if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+  }
+  
+  itemCache   = &bstbSize;
+  demoPointer = CAC_APPLET_CONT_BS_AID;
+  demoSize    = sizeof(CAC_APPLET_CONT_BS_AID);
+  if ( *itemCache == 0 ) {
+    rv = CACLoadTLVSize(pConnection, demoPointer, demoSize, itemCache, 0);
+    if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+  }
+  
+  itemCache   = &bsvbSize;
+  demoPointer = CAC_APPLET_CONT_BS_AID;
+  demoSize    = sizeof(CAC_APPLET_CONT_BS_AID);
+  if ( *itemCache == 0 ) {
+    rv = CACLoadTLVSize(pConnection, demoPointer, demoSize, itemCache, 1);
+    if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+  }
+  
+  itemCache   = &obtbSize;
+  demoPointer = CAC_APPLET_CONT_OB_AID;
+  demoSize    = sizeof(CAC_APPLET_CONT_OB_AID);
+  if ( *itemCache == 0 ) {
+    rv = CACLoadTLVSize(pConnection, demoPointer, demoSize, itemCache, 0);
+    if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+  }
+  
+  itemCache   = &obvbSize;
+  demoPointer = CAC_APPLET_CONT_OB_AID;
+  demoSize    = sizeof(CAC_APPLET_CONT_OB_AID);
+  if ( *itemCache == 0 ) {
+    rv = CACLoadTLVSize(pConnection, demoPointer, demoSize, itemCache, 1);
+    if ( rv == MSC_INTERNAL_ERROR ) { return rv; }
+  }    
+
+  dataIsCached = 1;
+  return MSC_SUCCESS;
+
+}
+
+
+MSCUShort16 convertSW(MSCPUChar8 pBuffer) {
+  MSCUShort16 retValue;
+  MSCUShort16 newValue;
+
+  retValue  = pBuffer[0] * 0x100;
+  retValue += pBuffer[1];
+
+  switch(retValue) {
+  case CACMSC_SUCCESS:
+    newValue = MSC_SUCCESS;
+    break;
+  case CACMSC_NO_MEMORY_LEFT:
+    newValue = MSC_NO_MEMORY_LEFT;
+    break;
+  case CACMSC_AUTH_FAILED:
+    newValue = MSC_AUTH_FAILED;
+    break;
+  case CACMSC_UNSUPPORTED_FEATURE:
+    newValue = MSC_UNSUPPORTED_FEATURE;
+    break;
+  case CACMSC_UNAUTHORIZED:
+    newValue = MSC_UNAUTHORIZED;
+    break;
+  case CACMSC_OBJECT_NOT_FOUND:
+    newValue = MSC_OBJECT_NOT_FOUND;
+    break;
+  case CACMSC_OBJECT_EXISTS:
+    newValue = MSC_OBJECT_EXISTS;
+    break;
+  case CACMSC_INCORRECT_ALG:
+    newValue = MSC_INCORRECT_ALG;
+    break;
+  case CACMSC_IDENTITY_BLOCKED:
+    newValue = MSC_IDENTITY_BLOCKED;
+    break;
+  case CACMSC_UNSPECIFIED_ERROR:
+    newValue = MSC_UNSPECIFIED_ERROR;
+    break;
+  case CACMSC_INVALID_PARAMETER:
+    newValue = MSC_INVALID_PARAMETER;
+    break;
+  case CACMSC_INTERNAL_ERROR:
+    newValue = MSC_INTERNAL_ERROR;
+    break;
+  default:
+    newValue = retValue;
+    break;
+  }
+
+  return newValue;
+}
+
+void MemCopy16(MSCPUChar8 destValue, MSCPUShort16 srcValue) {
+  destValue[0] = (*srcValue & 0xFF00) >> 8;
+  destValue[1] = (*srcValue & 0x00FF);
+}
+
+void MemCopy32(MSCPUChar8 destValue, MSCPULong32 srcValue) {
+  destValue[0] = (*srcValue >> 24);
+  destValue[1] = (*srcValue & 0x00FF0000) >> 16;
+  destValue[2] = (*srcValue & 0x0000FF00) >> 8;
+  destValue[3] = (*srcValue & 0x000000FF);
+}
+
+void MemCopyTo16(MSCPUShort16 destValue, MSCPUChar8 srcValue) {
+
+  *destValue  = srcValue[0] * 0x100;
+  *destValue += srcValue[1];
+
+}
+
+void MemCopyTo32(MSCPULong32 destValue, MSCPUChar8 srcValue) {
+
+  *destValue  = srcValue[0] * 0x1000000;
+  *destValue += srcValue[1] * 0x10000;
+  *destValue += srcValue[2] * 0x100;
+  *destValue += srcValue[3];
+
+}
+
+MSCUShort16 getUShort16(MSCPUChar8 srcValue) {
+  return ( (((MSCUShort16)srcValue[0]) << 8) || srcValue[1] );
+}
+
+void setUShort16(MSCPUChar8 dstValue, MSCUShort16 srcValue) {
+  MemCopyTo16(&srcValue, dstValue);
+}
+
+MSCLong32 SCardExchangeAPDU( MSCLPTokenConnection pConnection, 
+			     MSCLPTransmitBuffer transmitBuffer ) {
+  
+  MSCLong32 rv, ret;
+  MSCULong32 originalLength;
+  MSCUChar8 getResponse[5] = {0x00, 0xC0, 0x00, 0x00, 0x00};
+  MSCULong32 dwActiveProtocol;
+
+#ifdef MSC_DEBUG
+  int i;
+#endif
+
+  originalLength = transmitBuffer->apduResponseSize;
+
+  while (1) {
+    
+#ifdef MSC_DEBUG
+    printf("[%02d]->: ", transmitBuffer->bufferSize); 
+    
+    for (i=0; i < transmitBuffer->bufferSize; i++) {
+      printf("%02x ", transmitBuffer->pBuffer[i]);
+    } printf("\n");
+#endif
+    
+    while(1) {
+      transmitBuffer->apduResponseSize = originalLength;
+      
+      rv =  SCardTransmit(pConnection->hCard, pConnection->ioType,
+			  transmitBuffer->pBuffer, 
+			  transmitBuffer->bufferSize, 0,
+			  transmitBuffer->apduResponse, 
+			  &transmitBuffer->apduResponseSize );
+      
+      if ( rv == SCARD_S_SUCCESS ) {
+	break;
+	
+      } else if ( rv == SCARD_W_RESET_CARD ) {
+	pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
+	ret = SCardReconnect(pConnection->hCard, pConnection->shareMode, 
+			     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			     SCARD_LEAVE_CARD, &dwActiveProtocol );
+	
+	PL_MSCIdentifyToken(pConnection);
+	
+	if ( ret == SCARD_S_SUCCESS ) {
+	  continue;
+	}
+	
+      } else if ( rv == SCARD_W_REMOVED_CARD ) {
+	/* Push REMOVED_TOKEN back to the application */
+	pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
+	return rv;
+      } else {
+	/* Must be a BIG, BAD, ERROR */
+#ifdef MSC_DEBUG
+	printf("Transmit error: %s\n", pcsc_stringify_error(rv));
+#endif
+	return rv;
+      }
+    }
+    
+#ifdef MSC_DEBUG
+    printf("<-: ");
+    
+    for (i=0; i < transmitBuffer->apduResponseSize; i++) {
+      printf("%02x ", transmitBuffer->apduResponse[i]);
+    } printf("\n");
+#endif
+    
+    if ( suppressResponse == 1 ) {
+      /* Do not do the Get Response */
+      break;
+    }
+
+    if ( transmitBuffer->apduResponseSize == 2 && 
+	 transmitBuffer->apduResponse[0] == 0x61 ) {
+#ifdef MSC_DEBUG
+      printf("->: 0x00 0xC0 0x00 0x00 %02x\n", 
+	     transmitBuffer->apduResponse[1]);
+#endif
+      getResponse[4] = transmitBuffer->apduResponse[1];
+      transmitBuffer->apduResponseSize   = originalLength;
+      rv =  SCardTransmit(pConnection->hCard, pConnection->ioType,
+			  getResponse, 5, 0,
+			  transmitBuffer->apduResponse, 
+			  &transmitBuffer->apduResponseSize );
+      
+      if ( rv == SCARD_S_SUCCESS ) {
+#ifdef MSC_DEBUG	
+	printf("<-: ");
+	
+	for (i=0; i < transmitBuffer->apduResponseSize; i++) {
+	  printf("%02x ", transmitBuffer->apduResponse[i]);
+	} printf("\n");
+#endif
+	break;
+      } else if ( rv == SCARD_W_RESET_CARD ) {
+	pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
+	ret = SCardReconnect(pConnection->hCard, pConnection->shareMode, 
+			     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			     SCARD_LEAVE_CARD, &dwActiveProtocol );
+	
+	PL_MSCIdentifyToken(pConnection);
+	
+	if ( ret == SCARD_S_SUCCESS ) {
+	  continue;
+	}
+	
+      } else if ( rv == SCARD_W_REMOVED_CARD ) {
+	/* Push REMOVED_TOKEN back to the application */
+	pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
+	return rv;
+      } else {
+#ifdef MSC_DEBUG
+	printf("Transmit error: %s\n", pcsc_stringify_error(rv));
+#endif
+	return rv;
+      } 
+    }         
+
+    break;
+  }  /* End of while */
+  
+  
+  return rv;
+}
+
+
+MSC_RV convertPCSC( MSCLong32 pcscCode ) {
+
+  switch(pcscCode) {
+  case SCARD_S_SUCCESS:
+    return MSC_SUCCESS;
+  case SCARD_E_INVALID_HANDLE:
+    return MSC_INVALID_HANDLE;
+  case SCARD_E_SHARING_VIOLATION:
+    return MSC_SHARING_VIOLATION;
+  case SCARD_W_REMOVED_CARD:
+    return MSC_TOKEN_REMOVED;
+  case SCARD_E_NO_SMARTCARD:
+    return MSC_TOKEN_REMOVED;
+  case SCARD_W_RESET_CARD:
+    return MSC_TOKEN_RESET;
+  case SCARD_W_INSERTED_CARD:
+    return MSC_TOKEN_INSERTED;
+  case SCARD_E_NO_SERVICE:
+    return MSC_SERVICE_UNRESPONSIVE;
+  case SCARD_E_UNKNOWN_CARD:
+  case SCARD_W_UNSUPPORTED_CARD:
+  case SCARD_E_CARD_UNSUPPORTED:
+    return MSC_UNRECOGNIZED_TOKEN;
+  case SCARD_E_INVALID_PARAMETER:
+  case SCARD_E_INVALID_VALUE:
+  case SCARD_E_UNKNOWN_READER:
+  case SCARD_E_PROTO_MISMATCH:
+  case SCARD_E_READER_UNAVAILABLE:
+    return MSC_INVALID_PARAMETER;
+  case SCARD_E_CANCELLED:
+    return MSC_CANCELLED;
+  case SCARD_E_TIMEOUT:
+    return MSC_TIMEOUT_OCCURRED;
+
+  default:
+    return MSC_INTERNAL_ERROR;
+  }
+}
+
+


Property changes on: trunk/SmartCardServices/src/CACPlugin/commonAccessCard.c
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/SmartCardServices/src/CACPlugin/commonAccessCard.h
===================================================================
--- trunk/SmartCardServices/src/CACPlugin/commonAccessCard.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CACPlugin/commonAccessCard.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : commonAccessCard.h
+            Package: CACPlugin
+            Author : David Corcoran
+            Date   : 02/06/02
+            License: Copyright (C) 2002 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This abstracts the CAC Interface
+ 
+ 
+********************************************************************/
+
+#ifndef __commonAccessCard_h__
+#define __commonAccessCard_h__
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/* Some useful offsets in the buffer */
+#define OFFSET_CLA	0x00
+#define OFFSET_INS	0x01
+#define OFFSET_P1	0x02
+#define OFFSET_P2	0x03
+#define OFFSET_P3	0x04
+#define OFFSET_DATA	0x05
+
+
+#define CAC_GID_CERTNAME  "C3"
+#define CAC_MID_CERTNAME  "C5"
+#define CAC_ENC_CERTNAME  "C7"
+
+#define MC_1024P_FULLSIZE     140
+#define MC_SIZEOF_COMPSIZE      2
+#define MC_1024_OFFSET_P        4
+#define MC_1024_OFFSET_Q       70
+#define MC_1024_OFFSET_PQ     136
+#define MC_1024_OFFSET_DP1    202
+#define MC_1024_OFFSET_DQ1    268
+
+#define MC_1024P_MOD            4
+#define MC_1024P_EXP          134
+
+#define MC_DES_OFFSET_KEY       4
+
+    /* Sizes of particular objects */
+#define MSC_SIZEOF_OBJECTID               4
+#define MSC_SIZEOF_OBJECTSIZE             4
+#define MSC_SIZEOF_KEYINFO                11
+#define MSC_SIZEOF_STATUS                 16
+#define MSC_SIZEOF_VERSION                2
+#define MSC_SIZEOF_FREEMEM                4
+#define MSC_SIZEOF_LOGIDS                 2
+#define MSC_SIZEOF_ADDINFO                8
+#define MSC_SIZEOF_OPTLEN                 2
+#define MSC_SIZEOF_GENOPTIONS             1
+#define MSC_SIZEOF_KEYSIZE                2
+#define MSC_SIZEOF_KEYNUMBER              1
+#define MSC_SIZEOF_KEYTYPE                1
+#define MSC_SIZEOF_KEYPARTNER             1
+#define MSC_SIZEOF_CIPHERMODE             1
+#define MSC_SIZEOF_CIPHERDIR              1
+#define MSC_SIZEOF_CRYPTLEN               2
+#define MSC_SIZEOF_ALGOTYPE               1
+#define MSC_SIZEOF_IDUSED                 1
+#define MSC_SIZEOF_OFFSET                 4
+#define MSC_SIZEOF_ACLSTRUCT              6
+#define MSC_SIZEOF_RWDATA                 1
+#define MSC_SIZEOF_PINSIZE                1
+#define MSC_SIZEOF_CIPHERMODE             1
+#define MSC_SIZEOF_CIPHERDIR              1
+#define MSC_SIZEOF_DATALOCATION           1
+#define MSC_SIZEOF_ACLVALUE               2
+#define MSC_SIZEOF_SEEDLENGTH             2
+#define MSC_SIZEOF_RANDOMSIZE             2
+
+    /** success */
+#define CACMSC_SUCCESS                        0x9000
+
+    /** There have been memory problems on the card */
+#define CACMSC_NO_MEMORY_LEFT                 0x6A84
+    /** Entered PIN is not correct */
+#define CACMSC_AUTH_FAILED                    0x6300
+    /** Required feature is not (yet) supported */
+#define CACMSC_UNSUPPORTED_FEATURE            0x6D00
+    /** Required operation was not authorized because lack of privileges */
+#define CACMSC_UNAUTHORIZED                   0x6982
+    /** Required object is missing */
+#define CACMSC_OBJECT_NOT_FOUND               0x6A82
+    /** New object ID already in use */
+#define CACMSC_OBJECT_EXISTS                  0x6A80
+    /** Algorithm specified is not correct */
+#define CACMSC_INCORRECT_ALG                  0x6981
+    
+    /** Operation has been blocked for security reason  */
+#define CACMSC_IDENTITY_BLOCKED               0x6983
+    /** Unspecified error */
+#define CACMSC_UNSPECIFIED_ERROR              0x6F00
+    /** PCSC and driver transport errors */
+#define CACMSC_INVALID_PARAMETER              0x6B00
+    /** Incorrect P1 parameter */
+#define CACMSC_INCORRECT_P1                   0x6B00
+    /** Incorrect P2 parameter */
+#define CACMSC_INCORRECT_P2                   0x6B00
+    /** For debugging purposes */
+#define CACMSC_INTERNAL_ERROR                 0x6581
+    
+
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif /* __commonAccessCard_h__ */


Property changes on: trunk/SmartCardServices/src/CACPlugin/commonAccessCard.h
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/usbserial_mosx.c
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/usbserial_mosx.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/usbserial_mosx.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1065 @@
+/*
+ *  usbserial.h
+ *  ifd-CCID
+ *
+ *  Created by JL on Mon Feb 10 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ * Initial implementation from David Corcoran (corcoran at linuxnet.com)
+ * 
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFURL.h>
+#include <CoreFoundation/CFPlugIn.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/usb/IOUSBLib.h>
+
+
+#include <IOKit/IOCFPlugIn.h>
+
+#include <assert.h>
+#include "global.h"
+#include <wintypes.h>
+#include "pcscdefines.h"
+#include "usbserial.h"
+#include "Transport.h"
+
+#include "usbserial_mosx.h"
+#include "tools.h"
+
+#define USBMAX_READERS  (PCSCLITE_MAX_CHANNELS)
+//+++ Should be included from a pcscd header file
+#define PCSCLITE_HP_BASE_PORT       0x200000
+#define PCSCLITE_HP_IFACECLASSKEY_NAME    "ifdInterfaceClass"
+#define PCSCLITE_HP_IFACESUBCLASSKEY_NAME "ifdInterfaceSubClass"
+#define PCSCLITE_HP_IFACEPROTOCOLKEY_NAME "ifdInterfaceProtocol"
+
+
+// Used to read the manufacturer USB strings
+#define LANGUAGE_ID 0x0409
+#define STRING_REQUEST 0x03
+
+
+// Read time out in milliseconds (default value)
+unsigned long ReadTimeOut = 60000;
+
+
+static int                      iInitialized = FALSE;
+
+
+static intrFace intFace[USBMAX_READERS];
+
+
+// Local helper function
+void ReadUSBString(IOUSBDeviceInterface245 **dev, UInt8 bIndex,
+                   const char* pcHeader);
+
+
+TrRv OpenUSB( DWORD lun, DWORD Channel)
+{
+    kern_return_t			kr;
+    IOReturn                ior;
+    CFMutableDictionaryRef  USBMatch = 0;
+    io_iterator_t 			iter = 0;
+    io_service_t            USBDevice = 0;
+    io_service_t 			USBInterface = 0;
+    IOCFPlugInInterface 	**ioPlugin=NULL;
+    HRESULT 				res;
+    SInt32                  score;
+    DWORD                   rdrLun;
+    UInt8                   class, subClass, protocol;
+    CFNumberRef             CFclass = 0;
+    CFNumberRef             CFsubClass = 0; 
+    CFNumberRef             CFprotocol = 0;     
+//+    CFNumberRef             CFUsbAddress = 0; 
+    UInt32   				usbAddr, targetusbAddress;
+    short                   iFound;
+    mach_port_t             masterPort;
+    UInt8                   sleepCount;
+    const char*             cStringValue;
+    UInt16                  i=0;
+
+    LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Entering OpenUSB");
+
+
+    rdrLun = lun >> 16;
+
+    if ( rdrLun >= USBMAX_READERS )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "OpenUSB error: lun too large: %08X", lun);
+        return TrRv_ERR;
+    }
+
+    // Parse the bundle for various information
+    cStringValue =  ParseInfoPlist(BUNDLE_IDENTIFIER, PCSCLITE_HP_IFACECLASSKEY_NAME);
+    if ( cStringValue == NULL )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "OpenUSB error: ifdInterfaceClass not found");
+        return TrRv_ERR;
+    }
+    class = (UInt8) strtoul(cStringValue, 0, 16);
+
+    cStringValue =  ParseInfoPlist(BUNDLE_IDENTIFIER, PCSCLITE_HP_IFACESUBCLASSKEY_NAME);
+    if ( cStringValue == NULL )
+    {
+
+        LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "OpenUSB warning: ifdInterfaceSubClass not found");
+        return TrRv_ERR;
+    }
+    subClass = (UInt8) strtoul(cStringValue, 0, 16);
+
+    
+    cStringValue =  ParseInfoPlist(BUNDLE_IDENTIFIER, PCSCLITE_HP_IFACEPROTOCOLKEY_NAME);
+    if ( cStringValue == NULL )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "OpenUSB warning: ifdInterfaceProtocol not found");
+        return TrRv_ERR;
+    }
+    protocol = (UInt8) strtoul(cStringValue, 0, 16);
+    
+    cStringValue =  ParseInfoPlist(BUNDLE_IDENTIFIER, "ifdReadTimeOut");
+    if ( cStringValue == NULL )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelVerbose, 
+                    "OpenUSB warning: ifdReadTimeOut not found, use default: %ld ms", 
+                    ReadTimeOut);
+    }
+    else
+    {
+       ReadTimeOut = strtoul(cStringValue, 0, 10);
+    }
+    LogMessage( __FILE__,  __LINE__, LogLevelVerbose, 
+                "Driver configured to detect Interface class=%02X, subClass=%02X, protocol=%02X",
+                class, subClass, protocol);    
+    
+    iFound = FALSE;
+    
+    if ( iInitialized == FALSE ) {
+                
+        for (i=0; i < USBMAX_READERS; i++) {
+            (intFace[i]).usbAddr = 0;
+            (intFace[i]).dev = NULL;
+            (intFace[i]).iface = NULL;
+            (intFace[i]).inPipeRef = 0;
+            (intFace[i]).outPipeRef = 0;
+            (intFace[i]).used = 0;
+            (intFace[i]).ready = 0;
+            (intFace[i]).class = 0;
+            (intFace[i]).subClass = 0;            
+        }
+    
+        iInitialized = TRUE;
+
+    }
+    
+    kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
+    if (kr || !masterPort)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Couldn't create a master IOKit Port (0x%08X)", kr);
+        return TrRv_ERR;
+    }
+
+    
+
+    USBMatch = IOServiceMatching(kIOUSBInterfaceClassName);
+    if (!USBMatch)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Can't create a USB matching dictionary");
+        mach_port_deallocate(mach_task_self(), masterPort);
+        return TrRv_ERR;
+    }
+    // Compute target usb Address from Channel ID
+    
+    targetusbAddress = Channel - PCSCLITE_HP_BASE_PORT;
+/*+
+    // Locate device according to USB address
+    CFUsbAddress = CFNumberCreate(kCFAllocatorDefault,
+                                  kCFNumberSInt64Type,
+                                  &targetusbAddress);
+    if (!CFUsbAddress)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Can't create a CFNumber for usb Address");
+        mach_port_deallocate(mach_task_self(), masterPort);
+        return TrRv_ERR;
+    }
+    CFDictionarySetValue(USBMatch,
+                         CFSTR(kUSBDevicePropertyAddress),
+                         CFUsbAddress);
+    CFRelease(CFUsbAddress);
+*/    
+
+    // Prepare CFNumbers for the dictionary 
+    CFclass = CFNumberCreate(kCFAllocatorDefault,
+                             kCFNumberCharType,
+                             &class);
+    if (!CFclass)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Can't create a CFNumber for interface class byte");
+        mach_port_deallocate(mach_task_self(), masterPort);
+        return TrRv_ERR;
+    }
+    CFDictionarySetValue(USBMatch,
+                         CFSTR(kUSBInterfaceClass),
+                         CFclass);
+    CFRelease(CFclass);
+    
+    
+    
+    CFsubClass = CFNumberCreate(kCFAllocatorDefault,
+                                kCFNumberCharType,
+                                &subClass);
+    if (!CFsubClass)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Can't create a CFNumber for interface subclass byte");
+        mach_port_deallocate(mach_task_self(), masterPort);
+        return TrRv_ERR;
+    }
+    CFDictionarySetValue(USBMatch,
+                         CFSTR(kUSBInterfaceSubClass), 
+                         CFsubClass);
+    CFRelease(CFsubClass);
+
+
+    
+    CFprotocol = CFNumberCreate(kCFAllocatorDefault,
+                                kCFNumberCharType,
+                                &protocol);
+    if (!CFprotocol)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Can't create a CFNumber for interface protocol byte");
+        mach_port_deallocate(mach_task_self(), masterPort);
+        return TrRv_ERR;
+    }
+    CFDictionarySetValue(USBMatch,
+                         CFSTR(kUSBInterfaceProtocol), 
+                         CFprotocol);
+    CFRelease(CFprotocol);
+
+    /* Get an iterator over all matching IOService nubs */
+    kr = IOServiceGetMatchingServices(masterPort, USBMatch, &iter);
+    USBMatch = 0; // This was consumed by abbove call (according to USBSimple, main.c)
+    if (kr)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Can't create a USB Service iterator (0x%08X)", kr);
+        mach_port_deallocate(mach_task_self(), masterPort);
+        return TrRv_ERR;
+    }
+
+    // masterPort not used any more
+    mach_port_deallocate(mach_task_self(), masterPort);
+
+    
+    // We loop on all interfaces matching the triplet (class, subclass, protocol)
+    // and identify the right one using the device usb address (or Location ID)
+    // This would not work with USB devices exposing 2 or more CCID interfaces
+    while ( (USBInterface = IOIteratorNext(iter)) )
+    {
+        // Get the IOServices plug-in for the interface
+        kr = IOCreatePlugInInterfaceForService(USBInterface, 
+                                               kIOUSBInterfaceUserClientTypeID,
+                                               kIOCFPlugInInterfaceID, 
+                                               &ioPlugin, &score);
+        IOObjectRelease(USBInterface);	/* done with the interface object now */
+        if (kr || !ioPlugin)
+        {
+            LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                        "unable to create a plugin (0x%08X)", kr);
+            continue;
+        }
+            
+        /* Get the interface */
+        res = (*ioPlugin)->QueryInterface(ioPlugin, 
+                                          CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID245),
+                                          (LPVOID)&(intFace[rdrLun]).iface);
+		IODestroyPlugInInterface(ioPlugin);
+        if (res || !(intFace[rdrLun]).iface)
+        {
+            LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                        "Couldn't create a device interface (0x%08X)", res);
+            continue;
+        }
+        
+        // Get the USB address of the discovered matching interface
+        ior = (*(intFace[rdrLun]).iface)->GetLocationID(((intFace[rdrLun]).iface), &usbAddr);
+        if (ior)
+        {
+            LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Couldn't get the interface location ID (0x%08X)", ior);
+            continue;
+        }
+        LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, 
+                    "Found Interface at usb address 0x%08X (target=0x%08X)", 
+                    usbAddr, targetusbAddress);
+
+        // Check if this interface is on the device given as channel ID
+        if (usbAddr == targetusbAddress)
+        {
+            iFound = TRUE;
+            break;
+        }
+    }
+    
+    
+    
+    // iterator not needed anymore.
+    IOObjectRelease(iter);
+    
+    if (!iFound) 
+    {
+        /* Device not found */
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Unable to locate interface");
+        return TrRv_ERR;
+    }
+    
+    // Device discovered, memorize its properties
+    (intFace[rdrLun]).class = class;
+    (intFace[rdrLun]).subClass = subClass;
+    (intFace[rdrLun]).protocol = protocol;
+    
+    // Get the USB device the intereface is part of
+     ior = (*(intFace[rdrLun]).iface)->GetDevice((intFace[rdrLun]).iface,
+                                                &USBDevice);
+     if (ior)
+     {
+         LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Couldn't get the parent device  (0x%08X)", ior);
+         (*(intFace[rdrLun]).iface)->Release((intFace[rdrLun]).iface);
+         return TrRv_ERR;
+     }        
+     
+     // Get the plug-in for the device
+     
+     kr = IOCreatePlugInInterfaceForService(USBDevice, kIOUSBDeviceUserClientTypeID,
+                                            kIOCFPlugInInterfaceID, 
+                                            &ioPlugin, &score);
+     IOObjectRelease(USBDevice);	/* done with the device object now */
+     if (kr || !ioPlugin)
+     {
+         LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                     "unable to create a plugin for device (0x%08X)", kr);
+         (*(intFace[rdrLun]).iface)->Release((intFace[rdrLun]).iface);
+         return TrRv_ERR;
+     }
+     
+     // Get the device 
+     res = (*ioPlugin)->QueryInterface(ioPlugin, 
+                                       CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245),
+                                       (LPVOID)&(intFace[rdrLun]).dev);
+	IODestroyPlugInInterface(ioPlugin);
+     if (res || !(intFace[rdrLun]).dev)
+     {
+         LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                     "Couldn't create a device  (0x%08X)", res);
+         (*(intFace[rdrLun]).iface)->Release((intFace[rdrLun]).iface);
+         return TrRv_ERR;
+     }
+     
+
+     // Open the device using Apple's KB example to resolve arbitration
+     // issues with Classic
+    for (sleepCount = 5; sleepCount > 0; sleepCount--)
+    {
+        kr = (*(intFace[rdrLun]).dev)->USBDeviceOpen(((intFace[rdrLun]).dev));
+        if (kr == kIOReturnExclusiveAccess)
+        {
+            sleep(1);
+        }
+        else
+        {
+            if ( kr != kIOReturnSuccess)
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                            "unable to open device, not kIOReturnExclusiveAccess: 0x%08X", kr);
+                (*(intFace[rdrLun]).iface)->Release((intFace[rdrLun]).iface);
+                (*(intFace[rdrLun]).dev)->Release(((intFace[rdrLun]).dev));
+                return TrRv_ERR;
+            }
+            else
+            {
+                break;
+            }
+        }
+    }
+    if ( kr != kIOReturnSuccess)
+    {
+        // Some process is still using the device
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to open device, device busy");
+        (*(intFace[rdrLun]).iface)->Release((intFace[rdrLun]).iface);
+        (*(intFace[rdrLun]).dev)->Release(((intFace[rdrLun]).dev));
+        return TrRv_ERR;
+    }
+
+    (intFace[rdrLun]).usbAddr   = usbAddr;
+     // Now the device is used but not set-up yet (pipes,...)
+    (intFace[rdrLun]).used      = 1;
+    
+    
+    
+    // Get and store the device VendorID/ProductID
+    (intFace[rdrLun]).vendorID = 0;
+    ior = (*(intFace[rdrLun]).iface)->GetDeviceVendor(((intFace[rdrLun]).iface),
+                                                (&((intFace[rdrLun]).vendorID)));
+    if (ior)
+    { 
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "unable to get device vendor Id");
+    }                                        
+
+    (intFace[rdrLun]).productID = 0;
+    ior = (*(intFace[rdrLun]).iface)->GetDeviceProduct(((intFace[rdrLun]).iface),
+                                                      (&((intFace[rdrLun]).productID)));
+    if (ior)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "unable to get device product Id");
+    }                                        
+    LogMessage( __FILE__,  __LINE__, LogLevelVerbose, 
+                "Driver captured device with vendor Id  %04X\n", 
+                (intFace[rdrLun]).vendorID);
+    LogMessage( __FILE__,  __LINE__, LogLevelVerbose, 
+                "Driver captured device with product Id  %04X\n", 
+                (intFace[rdrLun]).productID);
+    
+    // Read the USB strings to identify in the logs which reader 
+    // was captured
+    
+    // Index of the manufacturer, product and serial number strings
+    UInt8  manIdx, prodIdx, snIdx;
+    kr = (*(intFace[rdrLun]).dev)->USBGetManufacturerStringIndex((intFace[rdrLun]).dev, 
+                                                                 &manIdx);
+    if (kr)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelVerbose, 
+                    "Could not get Manufacturer string");
+    }       
+    else
+    {
+        ReadUSBString((intFace[rdrLun]).dev, manIdx, "manufacturer");
+    }
+    kr = (*(intFace[rdrLun]).dev)->USBGetProductStringIndex((intFace[rdrLun]).dev, 
+                                                                 &prodIdx);
+    if (kr)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelVerbose, 
+                    "Could not get Product string");
+    }       
+    else
+    {
+        ReadUSBString((intFace[rdrLun]).dev, prodIdx, "product name");
+    }
+
+    kr = (*(intFace[rdrLun]).dev)->USBGetSerialNumberStringIndex((intFace[rdrLun]).dev, 
+                                                                 &snIdx);
+    if (kr)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelVerbose, 
+                    "Could not get Serial Number string");
+    }       
+    else
+    {
+        ReadUSBString((intFace[rdrLun]).dev, snIdx, "serial number");
+    }
+    
+    
+    
+    
+    // Now release the interface as the call to SetConfiguration on
+    // the device in SetupConnectionsUSB() will break it
+    (*(intFace[rdrLun]).iface)->Release((intFace[rdrLun]).iface);
+    (intFace[rdrLun]).iface = 0;
+
+    return TrRv_OK;  
+}
+
+
+TrRv GetConfigDescNumberUSB( DWORD lun, BYTE* pcconfigDescNb )
+{
+    DWORD		rdrLun;
+    IOUSBDeviceInterface245 **dev;
+    IOReturn err;
+
+    rdrLun = lun >> 16;
+    if ( rdrLun >= USBMAX_READERS )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "OpenUSB error: lun too large: %08X", lun);
+        return TrRv_ERR;
+    }
+    
+    // Check if a USB connection is set-up for this lun
+    if ( ! (intFace[rdrLun]).used )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to get class desc: usb not opened for lun %d", lun);
+        return TrRv_ERR;
+    }
+    dev = (intFace[rdrLun]).dev;
+    err = (*dev)->GetNumberOfConfigurations(dev, (UInt8 *) pcconfigDescNb);
+    if (err || !(*pcconfigDescNb))
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to obtain the number of configurations. ret = %08x\n", 
+                    err);
+        return TrRv_ERR;
+    }
+    return TrRv_OK;  
+}
+
+TrRv GetVendorAndProductIDUSB( DWORD lun, DWORD *vendorID, DWORD *productID )
+{
+    DWORD		rdrLun;
+
+    rdrLun = lun >> 16;
+    if ( rdrLun >= USBMAX_READERS )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "OpenUSB error: lun too large: %08X", lun);
+        return TrRv_ERR;
+    }
+    
+    // Check if a USB connection is set-up for this lun
+    if ( ! (intFace[rdrLun]).used )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to get vendor or product ID: usb not opened for lun %d", lun);
+        return TrRv_ERR;
+    }
+    *vendorID  = (intFace[rdrLun]).vendorID;
+    *productID = (intFace[rdrLun]).productID;
+    return TrRv_OK;
+}
+
+
+TrRv GetClassDescUSB( DWORD lun, BYTE configDescNb, BYTE bdescType,
+                      BYTE *pcdesc, BYTE *pcdescLength)
+{
+    IOUSBDeviceInterface245 **dev;
+    IOReturn err;
+    DWORD		rdrLun;
+    IOUSBConfigurationDescriptorPtr     confDesc;
+
+    rdrLun = lun >> 16;
+    if ( rdrLun >= USBMAX_READERS )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "OpenUSB error: lun too large: %08X", lun);
+        return TrRv_ERR;
+    }
+    
+    // Check if a USB connection is set-up for this lun
+    if ( ! (intFace[rdrLun]).used )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to get class desc: usb not opened for lun %d", lun);
+        return TrRv_ERR;
+    }
+    dev = (intFace[rdrLun]).dev;
+    UInt8 numConf;
+    err = (*dev)->GetNumberOfConfigurations(dev, &numConf);
+    if (err || !numConf)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to obtain the number of configurations. ret = %08x\n", err);
+        return TrRv_ERR;
+    }
+    LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, 
+                "found %d configurations\n", numConf);
+    if ( configDescNb >= numConf )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Requested configuration nb too large: %d\n", configDescNb);
+        return TrRv_ERR;
+    }
+    
+    err = (*dev)->GetConfigurationDescriptorPtr(dev, configDescNb, &confDesc);
+    if (err)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to get config descriptor for index %d\n", configDescNb);
+        return TrRv_ERR;
+    }
+    char *ptr;
+    ptr = (char*) confDesc;
+    //+++  NEED TO DO THIS IN A NICER WAY (MIGHT BE FIXED IN LATER MOSX)
+    //+ This is currently done to fix the endianness of the length
+    //+ as the API returns the length in USB endianness
+    unsigned char lsb, msb;
+    lsb = *((char*)&(confDesc->wTotalLength));
+    msb = *((char*)&(confDesc->wTotalLength)+1);
+    UInt16 size, offset, offset_target_desc = 0;
+    UInt8 found_target_desc = 0;
+    
+    size = (msb << 8) +lsb;
+    // Move to beginning of descriptors
+    
+    //+ For some reason, sizeof(IOUSBConfigurationDescriptor)
+    //+ Does not have the right length. It is probably 
+    //+ not "packed" properly in the declaration.
+    offset = 9; //sizeof(IOUSBConfigurationDescriptor);
+    ptr += 9; //sizeof(IOUSBConfigurationDescriptor);
+
+    // Scan all descriptors
+    while ( offset < size )
+    {
+        //-LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Found new descriptor,");
+        //-LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Length = %02Xh,", *(ptr));
+        //-LogMessage( __FILE__,  __LINE__, LogLevelVerbose, " Type= %02X\n", *(ptr+1));
+        if (  *(ptr+1) == bdescType )
+        {
+            offset_target_desc  = offset;
+            found_target_desc = 1;
+        }
+        offset += *ptr;
+        ptr += *ptr;
+    }
+    if (!found_target_desc)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, " unable to find target conf desc %02X\n", bdescType);
+        return TrRv_ERR;
+    }
+    // Reset ptr to start of config desc
+    ptr = (char*) confDesc;
+    UInt8 targetDescLength = *(ptr+offset_target_desc);
+    // Check if called to find out length or to return value
+    if ( pcdesc == NULL )
+    {
+        *pcdescLength = targetDescLength;
+        return TrRv_OK;
+    }
+    // Set length to minimal of buffer or real value
+    if ( *pcdescLength > targetDescLength )
+    {
+        *pcdescLength = targetDescLength;
+    }
+    bcopy(ptr+offset_target_desc, pcdesc, *pcdescLength);
+    return TrRv_OK;
+}
+
+//+++ NEED TO ADD and interruptPipe management
+TrRv SetupConnectionsUSB( DWORD lun, BYTE ConfigDescNb, BYTE interruptPipe)
+{
+    kern_return_t                       kr;
+    int                                 i = 0;
+    IOUSBConfigurationDescriptorPtr     confDesc;
+    UInt8                               intfNumEndpoints;
+    UInt8                               direction, number, transferType, interval;
+    UInt16                              maxPacketSize;    
+    io_service_t                        USBIface = 0;
+    io_iterator_t                       iter = 0;
+    IOUSBFindInterfaceRequest           findInterface;
+    IOCFPlugInInterface                 **iodevB = 0;
+    HRESULT                             res;
+    SInt32                              score;
+    DWORD                               rdrLun;
+    // Check if a USB connection is set-up for this lun
+    rdrLun = lun >> 16;
+
+    if ( rdrLun >= USBMAX_READERS )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "OpenUSB error: lun too large: %08X", lun);
+        return TrRv_ERR;
+    }
+    if ( ! (intFace[rdrLun]).used )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "unable to get set-up connections: usb not opened for lun %d", lun);
+        return TrRv_ERR;
+    }
+    
+
+    kr = (*(intFace[rdrLun]).dev)->GetConfigurationDescriptorPtr(((intFace[rdrLun]).dev),
+                                                                 ConfigDescNb, &confDesc);
+    if (kr)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "ERR: unable to get the configuration: 0x%08X\n", kr);
+        return TrRv_ERR;
+    }
+
+    (*(intFace[rdrLun]).dev)->ResetDevice(((intFace[rdrLun]).dev));
+
+    
+    // This call invalidates any interface currently opened on the device.
+    // Hence the re-opening of the USB interface below (even though it was 
+    // already opened in OpenUSB()
+    kr = (*(intFace[rdrLun]).dev)->SetConfiguration(((intFace[rdrLun]).dev),
+                                                    confDesc->bConfigurationValue);
+    if (kr)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "ERR: unable to set the configuration: 0x%08X\n", kr);
+        return TrRv_ERR;
+    }
+
+
+ 
+    // Time to find the first CCID interface 
+
+    findInterface.bInterfaceClass    = (intFace[rdrLun]).class;
+    findInterface.bInterfaceSubClass = (intFace[rdrLun]).subClass;
+    findInterface.bInterfaceProtocol = (intFace[rdrLun]).protocol;
+    findInterface.bAlternateSetting  = kIOUSBFindInterfaceDontCare;
+
+    kr = (*(intFace[rdrLun]).dev)->CreateInterfaceIterator(((intFace[rdrLun]).dev),
+                                                            &findInterface, &iter);
+    if ( kr )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Can not create interface Iterator");
+        return TrRv_ERR;
+    }
+
+    USBIface = IOIteratorNext(iter);
+    //+++ We do not support a device with 2 CCID interfaces on it as 
+    //++ pcscd does not support it either (Lun management would need to
+    //++ be upgraded).
+    IOObjectRelease(iter);
+    iter = 0;
+    
+    if ( USBIface == 0 ) {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "No interface found");
+        return TrRv_ERR;
+    }
+
+    score = 0;
+
+
+    // Create the plugin for the interface service 
+    kr  = IOCreatePlugInInterfaceForService(USBIface, kIOUSBInterfaceUserClientTypeID,
+                                            kIOCFPlugInInterfaceID, &iodevB, &score);
+    if ( kr || !iodevB )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "No interface found");
+        IOObjectRelease(USBIface);
+        return TrRv_ERR;        
+    }
+
+    // Now get the real interface
+     res = (*iodevB)->QueryInterface(iodevB, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID245),
+                                   (LPVOID)&(intFace[rdrLun]).iface);
+	IODestroyPlugInInterface(iodevB);	// done with this
+    IOObjectRelease(USBIface);
+    if ( res || !(intFace[rdrLun]).iface)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Could not query interface");
+        return TrRv_ERR;
+    }
+
+
+    // Open the interface to open all the pipes 
+    kr = (*(intFace[rdrLun]).iface)->USBInterfaceOpen((intFace[rdrLun]).iface);
+    if ( kr )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "unable to open device: 0x%08X", kr);
+        return TrRv_ERR;
+    }
+
+    
+    
+    // Get nb of end points
+    kr = (*(intFace[rdrLun]).iface)->GetNumEndpoints((intFace[rdrLun]).iface, &intfNumEndpoints);
+    if (kr != kIOReturnSuccess )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "unable to get number of end points: 0x%08X", kr);
+        return TrRv_ERR;
+    }
+    // pipes are one based, since zero is the default control pipe
+    for (i=1; i <= intfNumEndpoints; i++)
+    {
+        kr = (*(intFace[rdrLun]).iface)->GetPipeProperties((intFace[rdrLun]).iface, i,
+                                                           &direction, &number,
+                                                           &transferType, &maxPacketSize,
+                                                           &interval);
+        if (kr != kIOReturnSuccess )
+        {
+            LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                        "unable to get pipe properties: 0x%08X", kr);
+            return TrRv_ERR;
+        }
+        if (transferType != kUSBBulk)
+        {
+            continue;
+        }
+        if ((direction == kUSBIn) && !((intFace[rdrLun]).inPipeRef))
+        {
+            (intFace[rdrLun]).inPipeRef = i;
+        }
+        if ((direction == kUSBOut) && !((intFace[rdrLun]).outPipeRef))
+        {
+            (intFace[rdrLun]).outPipeRef = i;
+        }
+        //+++ Need to add optional management of interrupt pipe
+
+    }
+
+
+    if ( !((intFace[rdrLun]).outPipeRef) )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to get outPipe: 0x%08X", kr);
+        CloseUSB(lun);
+        return TrRv_ERR;
+    }
+
+    if (!( (intFace[rdrLun]).inPipeRef))
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "unable to get inPipe: 0x%08X", kr);
+        CloseUSB(lun);
+        return TrRv_ERR;
+    }
+    LogMessage( __FILE__,  __LINE__, LogLevelImportant,
+                "New reader fully set-up at USB address: %08X\n", 
+                (intFace[rdrLun]).usbAddr);
+    (intFace[rdrLun]).ready = 1;
+    return TrRv_OK;
+}
+
+
+
+TrRv WriteUSB( DWORD lun, DWORD length, unsigned char *buffer )
+{
+    IOReturn		iorv;
+    DWORD		rdrLun;
+     
+    rdrLun = lun >> 16;
+    if ( rdrLun >= USBMAX_READERS )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "OpenUSB error: lun too large: %08X", lun);
+        return TrRv_ERR;
+    }
+    if ( ! (intFace[rdrLun]).ready )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "unable to write to USB: set-up not completed for lun %d", lun);
+        return TrRv_ERR;
+    }
+    
+    LogHexBuffer(__FILE__,  __LINE__, LogLevelVeryVerbose, buffer, length, 
+                 "Attempt to write: ");
+        
+    /* Make sure the pipe is OK */
+    iorv = (*(intFace[rdrLun]).iface)->GetPipeStatus( (intFace[rdrLun]).iface, 
+                                                            (intFace[rdrLun]).outPipeRef );
+    if ( iorv != kIOReturnSuccess )
+    {
+        return TrRv_ERR;
+    }
+
+    /* Write the data */
+    iorv = (*(intFace[rdrLun]).iface)->WritePipe((intFace[rdrLun]).iface,
+                                                  (intFace[rdrLun]).outPipeRef,
+                                                  buffer, length);
+    
+    if ( iorv != kIOReturnSuccess )
+    {
+        return TrRv_ERR;
+    }
+            
+    return TrRv_OK;
+}
+
+TrRv ReadUSB( DWORD lun, DWORD *length, unsigned char *buffer )
+{
+    IOReturn	iorv;
+    UInt32		recvLen;
+    UInt32      noDataTO, completeTO;
+    DWORD		rdrLun;
+
+    
+    rdrLun = lun >> 16;
+    if ( rdrLun >= USBMAX_READERS )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "OpenUSB error: lun too large: %08X", lun);
+        return TrRv_ERR;
+    }
+    if ( ! (intFace[rdrLun]).ready )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "unable to write to USB: set-up not completed for lun %d", lun);
+        return TrRv_ERR;
+    }
+    
+    LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose,
+                "Attempt to read %ld bytes", *length);
+    
+    /* Make sure the pipe is OK */
+    iorv = (*(intFace[rdrLun]).iface)->GetPipeStatus( (intFace[rdrLun]).iface,
+                                                       (intFace[rdrLun]).inPipeRef
+                                                       );
+    if ( iorv != kIOReturnSuccess )
+    {
+        return TrRv_ERR;
+    }
+
+    recvLen = *length;
+    completeTO = ReadTimeOut;
+    noDataTO   = ReadTimeOut;
+
+    iorv = (*(intFace[rdrLun]).iface)->ReadPipeTO( (intFace[rdrLun]).iface,
+                                                    (intFace[rdrLun]).inPipeRef,
+                                                    buffer, &recvLen, noDataTO, completeTO);
+    if ( iorv != 0 )
+    {
+        (*(intFace[rdrLun]).dev)->ResetDevice(((intFace[rdrLun]).dev));
+        return TrRv_ERR;
+    }
+    
+    LogHexBuffer(__FILE__,  __LINE__, LogLevelVeryVerbose, buffer, recvLen, "received: ");
+    
+    *length = recvLen;
+    return TrRv_OK;
+}
+
+TrRv CloseUSB( DWORD lun )
+{
+    IOReturn iorv;
+    DWORD rdrLun;
+    
+    rdrLun = lun >> 16;
+    if ( rdrLun >= USBMAX_READERS )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "CloseUSB error: lun too large: %08X", lun);
+        return TrRv_ERR;
+    }
+    
+    // Reset struct
+    (intFace[rdrLun]).usbAddr = 0;
+    (intFace[rdrLun]).outPipeRef = 0;
+    (intFace[rdrLun]).inPipeRef = 0;
+    (intFace[rdrLun]).used = 0;
+    (intFace[rdrLun]).ready = 0;
+    (intFace[rdrLun]).class = 0;
+    (intFace[rdrLun]).subClass = 0;            
+    
+
+    /* Close the interface */
+    // Check if it was allocated
+    if ( (intFace[rdrLun]).iface )
+    {
+        iorv = (*(intFace[rdrLun]).iface)->USBInterfaceClose( (intFace[rdrLun]).iface );
+        if (iorv)
+        {
+            LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                        "ERR: Couldn't close interface (%08x)\n", (int)iorv);
+        }
+
+        /* Release the interface */
+        (*(intFace[rdrLun]).iface)->Release((intFace[rdrLun]).iface);
+        (intFace[rdrLun]).iface = 0;
+    }
+    if ( (intFace[rdrLun]).dev )
+    {
+        iorv = (*(intFace[rdrLun]).dev)->USBDeviceClose((intFace[rdrLun]).dev);
+        if (iorv) {
+            LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                        "ERR: Couldn't close device (%08x)\n", (int)iorv);
+        }
+
+        (*(intFace[rdrLun]).dev)->Release((intFace[rdrLun]).dev);
+        if ( iorv != kIOReturnSuccess ) {
+            return TrRv_ERR;
+        }
+        (intFace[rdrLun]).dev = 0;
+    }
+    return TrRv_OK;
+}
+
+
+
+
+void ReadUSBString(IOUSBDeviceInterface245 **dev, UInt8 bIndex,
+                   const char* pcHeader)
+{
+    IOUSBDevRequest stDevRequest;
+    unsigned char pcArray[512];    
+    kern_return_t		kr;
+    
+    // Generate the USB request manually
+    stDevRequest.bmRequestType = USBmakebmRequestType( kUSBIn, kUSBStandard, 
+                                                       kUSBDevice );
+    stDevRequest.bRequest      = kUSBRqGetDescriptor;
+    stDevRequest.wValue        = ( kUSBStringDesc << 8 ) | bIndex;
+    // Select language
+    stDevRequest.wIndex        = LANGUAGE_ID;
+    stDevRequest.wLength       = sizeof(pcArray);
+    stDevRequest.pData         = (void *) pcArray;
+    bzero(pcArray, sizeof(pcArray));
+    kr = (*dev)->DeviceRequest(dev, &stDevRequest);
+    if (kr)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "DeviceRequest for USB string failed %08X", kr);
+        return;
+    }
+    
+    // Check that we got what we wanted
+    if ( pcArray[1] != STRING_REQUEST )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "DeviceRequest for USB string did not return expected data");
+        return;
+    }
+    
+    CFStringRef cfstr;
+    UInt8 tmp = pcArray[0];
+    // Add Unicode BOM to the returned string to allow CFString to 
+    // work. array[0:1] stores the length of the Unicode string
+    // and a type byte
+    pcArray[0] = 0xFF;
+    pcArray[1] = 0xFE;
+    
+    cfstr = CFStringCreateWithBytes (
+                                     kCFAllocatorDefault,
+                                     pcArray,
+                                     // Length in BYTES
+                                     tmp,
+                                     kCFStringEncodingUnicode,
+                                     1
+                                     );
+    
+    
+    // Turn the CFString in a standard C string    
+    if ( !CFStringGetCString (
+                              cfstr,
+                              (char *)pcArray,
+                              sizeof(pcArray)-1,
+                              kCFStringEncodingASCII
+                              )
+         )
+    {
+       LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Conversion of USB string to ASCII failed, printing raw data");
+       LogHexBuffer(__FILE__,  __LINE__, LogLevelCritical, pcArray+2, tmp, 
+                    "Raw data: "); 
+       CFRelease(cfstr);
+       return;
+        
+    }
+    // Manually ensure string is terminated
+    pcArray[sizeof(pcArray)-1] = '\0';
+    CFRelease(cfstr);
+    LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                "Captured device %s is %s", pcHeader, pcArray);
+    
+    return;
+}

Added: trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/usbserial_mosx.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/usbserial_mosx.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/USB/MacOSX/usbserial_mosx.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,30 @@
+/*
+ *  usbserial.h
+ *  ifd-CCID
+ *
+ *  Created by JL on Mon Feb 10 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#ifndef _USBSERIAL_MOSX_H_
+#define _USBSERIAL_MOSX_H_
+
+typedef struct _intFace {
+    IOUSBInterfaceInterface245  **iface;
+    IOUSBDeviceInterface245     **dev;
+    UInt32 						usbAddr;
+    UInt8						inPipeRef;
+    UInt8						outPipeRef;
+    UInt8 						used;
+    UInt8 						ready;
+    UInt16	 					vendorID;
+    UInt16                      productID;
+    UInt8                       class;
+    UInt8                       subClass;
+    UInt8                       protocol;
+} intrFace, *pIntrFace;
+
+#endif
+

Added: trunk/SmartCardServices/src/CCIDDriver/USB/usbserial.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/USB/usbserial.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/USB/usbserial.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,34 @@
+/*
+ *  usbserial.h
+ *  ifd-CCID
+ *
+ *  Created by JL on Mon Feb 10 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#ifndef _USBSERIAL_H_
+#define _USBSERIAL_H_
+
+#include "Transport.h"
+
+// Open the base connection
+TrRv OpenUSB( DWORD lun, DWORD channel );
+// returns the number of conifguration descriptors
+TrRv GetConfigDescNumberUSB( DWORD lun, BYTE* pcconfigDescNb );
+// returns product and vendor ID for the USB device connected on LUN lun
+TrRv GetVendorAndProductIDUSB( DWORD lun, DWORD *vendorID, DWORD *productID );
+// Reads Class descriptor  once the device has been successfulle opened
+// Can be called with pcdesc == NULL to find out the length
+TrRv GetClassDescUSB( DWORD lun, BYTE configDescNb, BYTE bdescType,
+                      BYTE *pcdesc, BYTE *pcdescLength);
+// Sets connection to pipes
+TrRv SetupConnectionsUSB( DWORD lun, BYTE ConfigDescNb, BYTE interruptPipe);
+TrRv SetupUSB( DWORD lun,  void* pBuffer, DWORD * pLength);
+TrRv WriteUSB( DWORD lun, DWORD length, BYTE *Buffer );
+TrRv ReadUSB( DWORD lun, DWORD *length, BYTE *Buffer );
+TrRv CloseUSB( DWORD lun );
+
+#endif
+

Added: trunk/SmartCardServices/src/CCIDDriver/common/CCID.c
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/CCID.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/CCID.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1085 @@
+/*
+ *  CCID.c
+ *  ifd-CCID
+ *
+ *  Created by JL on Sat Jun 28 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+#include <CoreFoundation/CoreFoundation.h>
+#include "global.h"
+
+#include "tools.h"
+#include "CCID.h"
+#include "CCIDprivate.h"
+#include "pcscdefines.h"
+#include "CCIDPropExt.h"
+
+
+CCIDReaderState CCIDReaderStates[PCSCLITE_MAX_CHANNELS];
+static BYTE bCCIDInitialised = 0;
+
+void CCIDParseDesc(BYTE * pcbuffer, CCIDClassDescriptor *classDesc)
+{
+
+    bcopy(pcbuffer, classDesc, sizeof(CCIDClassDescriptor));
+    // Correct endianness of relevant fields
+    classDesc->bcdCCID = CCIDToHostWord(classDesc->bcdCCID);
+    classDesc->dwProtocols = CCIDToHostLong(classDesc->dwProtocols);
+    classDesc->dwDefaultClock = CCIDToHostLong(classDesc->dwDefaultClock);
+    classDesc->dwMaximumClock = CCIDToHostLong(classDesc->dwMaximumClock);
+    classDesc->dwDataRate = CCIDToHostLong(classDesc->dwDataRate);
+    classDesc->dwMaxDataRate = CCIDToHostLong(classDesc->dwMaxDataRate);
+    classDesc->dwMaxIFSD = CCIDToHostLong(classDesc->dwMaxIFSD);
+    classDesc->dwSynchProtocols = CCIDToHostLong(classDesc->dwSynchProtocols);
+    classDesc->dwMechanical = CCIDToHostLong(classDesc->dwMechanical);
+    classDesc->dwFeatures = CCIDToHostLong(classDesc->dwFeatures);
+    classDesc->dwMaxCCIDMessageLength = CCIDToHostLong(classDesc->dwMaxCCIDMessageLength);
+    classDesc->wLcdLayout = CCIDToHostWord(classDesc->wLcdLayout);
+}
+
+void CCIDPrintDesc(CCIDClassDescriptor classDesc)
+{
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbLength                = 0x%02X\n", classDesc.bLength);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbDescriptorType        = 0x%02X\n", classDesc.bDescriptorType);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbcdCCID                = 0x%04X\n", classDesc.bcdCCID);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbMaxSlotIndex          = %d\n", classDesc.bMaxSlotIndex);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbVoltageSupport        = 0x%02X\n", classDesc.bVoltageSupport);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwProtocols            = 0x%08X\n", classDesc.dwProtocols);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwDefaultClock         = %ld\n", classDesc.dwDefaultClock);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwMaximumClock         = %ld\n", classDesc.dwMaximumClock);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbNumDataRatesSupported = %d\n", classDesc.bNumCockSupported);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwDataRate             = %ld\n", classDesc.dwDataRate);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwMaxDataRate          = %ld\n", classDesc.dwMaxDataRate);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbNumDataRatesSupported = %d\n", classDesc.bNumDataRatesSupported);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwMaxIFSD              = %ld\n", classDesc.dwMaxIFSD);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwSynchProtocols       = 0x%08X\n", classDesc.dwSynchProtocols);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwMechanical           = 0x%08X\n", classDesc.dwMechanical);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwFeatures             = 0x%08X\n", classDesc.dwFeatures);
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_CONF_ATR )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic conf. according to ATR");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_ACT )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic activation of ICC on insertion");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_VOLT )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic voltage selection");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_CLOCK )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic clock frequency change");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_BAUD )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic baud rate selection (freq, FI, DI)");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_PPS_PROP )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic parameter negociation (proprietary)");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_PPS_CUR )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic parameter negociation (current)");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_CLOCK_STOP )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Can set ICC in stop clock mode");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_NAD_NON_0 )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Non 00 value for NAD suppported");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_IFSD )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic IFSD exchange as first exchange");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_IFSD )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic IFSD exchange as first exchange");
+   }
+   if ( classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_IFSD )
+   {
+       LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Automatic IFSD exchange as first exchange");
+   }
+   switch ( classDesc.dwFeatures & CCID_CLASS_FEAT_EXC_LEVEL_MASK )
+   {
+       case CCID_CLASS_FEAT_EXC_LEVEL_CHAR:
+           LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Character level exchanges");
+           break;
+       case CCID_CLASS_FEAT_EXC_LEVEL_TPDU:
+           LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t TPDU level exchanges");
+           break;
+       case CCID_CLASS_FEAT_EXC_LEVEL_SAPDU:
+           LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Short APDU level exchanges");
+           break;
+       case CCID_CLASS_FEAT_EXC_LEVEL_LAPDU:
+           LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\t\t Short and extended APDU level exchanges");
+           break;
+   }
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tdwMaxCCIDMessageLength = %ld\n", classDesc.dwMaxCCIDMessageLength);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbClassGetResponse      = 0x%02X\n", classDesc.bClassGetResponse);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbClassEnvelope         = 0x%02X\n", classDesc.bClassEnvelope);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\twLcdLayout             = 0x%04X\n", classDesc.wLcdLayout);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbPINSupport            = 0x%02X\n", classDesc.bPINSupport);
+   LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "\tbMaxCCIDBusySlots      = %d\n", classDesc.bMaxCCIDBusySlots); 
+}
+
+
+// Parses the bStatus byte returned in a Bulk-IN
+// message to return bmICCStatus
+BYTE CCIDGetICCStatus(BYTE bStatus)
+{
+    return (((bStatus) & MASK_ICC_STATUS) >> OFFSET_ICC_STATUS);
+}
+// Gets a pointer to a user friendly message
+static const char* ICCStatusMessage[] =
+{
+    "ICC present and active",
+    "ICC present and inactive",
+    "No ICC",
+    "RFU"
+};
+const char *CCIDGetICCStatusMessage(BYTE bICCStatus)
+{
+    if (bICCStatus < (sizeof(ICCStatusMessage)/sizeof(char*)))
+        return ICCStatusMessage[bICCStatus];
+    return "";
+}
+// Parses the bStatus byte returned in a Bulk-IN
+// message to return bmCommandStatus
+BYTE CCIDGetCommandStatus(BYTE bStatus)
+{
+    return (((bStatus) & MASK_COMMAND_STATUS) >> OFFSET_COMMAND_STATUS);
+}
+static const char* CommandStatusMessage[] =
+{
+    "Success",
+    "Failed",
+    "Time extension required",
+    "RFU"
+};
+
+// Gets a pointer to a user friendly message
+const char *CCIDGetCommandStatusMessage(BYTE bCommandStatus)
+{
+    if (bCommandStatus < (sizeof(CommandStatusMessage)/sizeof(char*)))
+        return CommandStatusMessage[bCommandStatus];
+    return "";
+}
+
+CCIDRv CCID_OpenChannel(DWORD Lun, DWORD ChannelID)
+{
+    WORD wRdrLun;
+    TrRv rv;
+    
+    if ( !bCCIDInitialised )
+    {
+        //Intialise structure 
+        bzero(CCIDReaderStates, sizeof(CCIDReaderStates));
+        bCCIDInitialised = 1;
+    }
+
+    wRdrLun = LunToReaderLun(Lun);
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    if ( CCIDReaderStates[wRdrLun].used)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Reader Lun already used: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    CCIDReaderStates[wRdrLun].used = 1;
+    //++ SHOULD CHECK CHANNELID TO SEE WHICH TRANSPORT TO USE
+    //++ This is to support CCID readers over different transport 
+    //++ mechanism (serial or even serial from PCMCIA)
+    CCIDReaderStates[wRdrLun].pTrFunctions = &TrFunctionTable[TrType_USB];
+    // Create an "alias" to the transport functions
+    TrFunctions *pTrFunctions =  CCIDReaderStates[wRdrLun].pTrFunctions;
+    rv = pTrFunctions->Open(Lun, ChannelID);
+    if ( rv != TrRv_OK )
+    {
+        CCIDReaderStates[wRdrLun].used = 0;
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+    
+    BYTE bnbOfDesc;
+
+    rv = pTrFunctions->GetConfigDescNumber(Lun, &bnbOfDesc);
+    if ( rv != TrRv_OK )
+    {
+        CCIDReaderStates[wRdrLun].used = 0;
+        // Call close to reset USB structures
+        CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+    //+++ Configuration descriptor analysis could take place here.
+    //++ For now, use configuration descriptor 0
+    BYTE bSelectedConfDesc = 0;
+    
+    BYTE pcbufferDesc[CCID_DESC_SIZE];
+    BYTE bbufferDescLength = sizeof(pcbufferDesc);
+    rv = pTrFunctions->GetClassDesc(Lun, bSelectedConfDesc, CCID_DESC_TYPE,
+                                    NULL, &bbufferDescLength);
+    if ( rv != TrRv_OK )
+    {
+        CCIDReaderStates[wRdrLun].used = 0;
+        // Call close to reset USB structures
+        CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+    if (bbufferDescLength != CCID_DESC_SIZE)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Incorrect Class Desc size %d ", bbufferDescLength);
+        // Call close to reset USB structures
+        CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+        return CCIDRv_ERR_CLASS_DESC_INVALID;
+    }
+    bbufferDescLength = sizeof(pcbufferDesc);
+    rv = pTrFunctions->GetClassDesc(Lun, bSelectedConfDesc, CCID_DESC_TYPE,
+                                    pcbufferDesc, &bbufferDescLength);
+    if ( rv != TrRv_OK )
+    {
+        CCIDReaderStates[wRdrLun].used = 0;
+        // Call close to reset USB structures
+        CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+    // Convenience pointer
+    CCIDClassDescriptor *pstClassDesc;
+    pstClassDesc = &(CCIDReaderStates[wRdrLun].classDesc);
+    CCIDParseDesc(pcbufferDesc, pstClassDesc);
+    CCIDPrintDesc(CCIDReaderStates[wRdrLun].classDesc);
+
+    // Initialise fields
+    CCIDReaderStates[wRdrLun].bMaxSlotIndex = pstClassDesc->bMaxSlotIndex;
+    CCIDReaderStates[wRdrLun].bMaxCCIDBusySlots = pstClassDesc->bMaxCCIDBusySlots;
+    CCIDReaderStates[wRdrLun].dwMaxCCIDMessageLength = pstClassDesc->dwMaxCCIDMessageLength;
+    CCIDReaderStates[wRdrLun].dwExchangeLevel = (pstClassDesc->dwFeatures)
+        & CCID_CLASS_FEAT_EXC_LEVEL_MASK;
+
+    // Make sure response struct is smaller than command struct
+    assert(sizeof(CCIDMessageBulkOut) >= sizeof(CCIDMessageBulkIn));
+    if ( CCIDReaderStates[wRdrLun].dwMaxCCIDMessageLength < sizeof(CCIDMessageBulkOut) )
+    {
+        // Can't do anything with this reader, its message length is even smaller
+        // than the size of a minimal command
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "Reader dwMaxCCIDMessageLength property is too small: %d", 
+                     CCIDReaderStates[wRdrLun].dwMaxCCIDMessageLength);
+        CCIDReaderStates[wRdrLun].used = 0;
+        // Call close to reset USB structures
+        CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+        return CCIDRv_ERR_UNSPECIFIED;
+        
+    }
+    //+++ Interrupt pipes not supported, hence 0 in parameter
+    rv = pTrFunctions->SetupConnections(Lun, bSelectedConfDesc, 0);
+    if ( rv != TrRv_OK )
+    {
+        CCIDReaderStates[wRdrLun].used = 0;
+        // Call close to reset USB structures
+        CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+    
+    rv = pTrFunctions->GetVendorAndProductID(Lun, & (CCIDReaderStates[wRdrLun].dwVendorID),
+                                             &(CCIDReaderStates[wRdrLun].dwProductID));
+    if ( rv != TrRv_OK )
+    {
+        CCIDReaderStates[wRdrLun].used = 0;
+        // Call close to reset USB structures
+        CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+    CCIDPropExt stCCIDPropExt;
+    rv = CCIDPropExtLookupExt(CCIDReaderStates[wRdrLun].dwVendorID,
+                              CCIDReaderStates[wRdrLun].dwProductID,
+                              &stCCIDPropExt);
+    if ( rv == CCIDRv_OK )
+    {
+        if ( stCCIDPropExt.OpenChannel != NULL )
+        {
+            rv = stCCIDPropExt.OpenChannel(Lun);
+            if ( rv != CCIDRv_OK )
+            {
+                CCIDReaderStates[wRdrLun].used = 0;
+                // Call close to reset USB structures
+                CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+                return rv;
+            }
+        }
+    }
+    
+    return CCIDRv_OK;
+}
+
+CCIDRv CCID_CloseChannel(DWORD Lun)
+{
+    WORD wRdrLun;
+    TrRv rv;
+
+    wRdrLun = LunToReaderLun(Lun);
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    if ( !CCIDReaderStates[wRdrLun].used)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Reader Lun of unused reader: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    // Close USB connection
+    rv = CCIDReaderStates[wRdrLun].pTrFunctions->Close(Lun);
+    // Clean-up the structure
+    bzero(&CCIDReaderStates[wRdrLun], sizeof(CCIDReaderState));
+    if ( rv != TrRv_OK )
+    {
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+
+    return CCIDRv_OK;
+    
+}
+
+
+CCIDRv CCID_Exchange_Command(DWORD Lun, BYTE bMessageTypeCmd,
+                             BYTE *abMessageSpecificCmd,
+                             BYTE *abDataCmd, DWORD dwDataCmdLength,
+                             BYTE *pbMessageTypeResp,
+                             BYTE *pbStatus, BYTE *pbError,
+                             BYTE *pbMessageSpecificResp,
+                             BYTE *abDataResp, DWORD *pdwDataRespLength,
+                             BYTE bTimeExtRetry)
+{
+    CCIDMessageBulkOut *pstmessage;
+    CCIDMessageBulkIn  *pstresponse;
+    WORD wSlot;
+    WORD wRdrLun;
+    TrRv trv = 0;
+    BYTE *pcBuffer;
+    DWORD dwRespLength;
+
+    wRdrLun = LunToReaderLun(Lun);
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    if ( !CCIDReaderStates[wRdrLun].used)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Reader Lun of unused reader: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    wSlot = LunToSlotNb(Lun);
+    if ( wSlot > CCIDReaderStates[wRdrLun].bMaxSlotIndex )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Slot Lun too large: %d", wSlot);
+        return CCIDRv_ERR_SLOT_LUN;
+    }
+    if ( CCIDReaderStates[wRdrLun].bCurrentCCIDBusySlots
+         >= CCIDReaderStates[wRdrLun].bMaxCCIDBusySlots )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Too many slots busy");
+        return CCIDRv_ERR_SLOTS_BUSY;
+    }
+
+    if ( CCIDReaderStates[wRdrLun].dwMaxCCIDMessageLength < dwDataCmdLength )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Command too long for reader");
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+    
+    // Just to make sure buffer will be large enough for the response
+    assert(sizeof(CCIDMessageBulkOut) >= sizeof(CCIDMessageBulkIn));
+
+    // Malloc buffer of size of the message +maximum data for this slot
+    //+++ Could be malloced once and for all at the structure creation
+    pcBuffer = malloc(sizeof(CCIDMessageBulkOut)
+                         + CCIDReaderStates[wRdrLun].dwMaxCCIDMessageLength);
+    if ( pcBuffer == NULL )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Malloc failed");
+        return CCIDRv_ERR_UNSPECIFIED;        
+    }
+    // See if this is a retry after a time extension request
+    // For T=0, this means that we just have to jump to the read
+    // and not attempt to write
+    if (!bTimeExtRetry)
+    {
+        // Not a retry, send the command
+        //++ bCurrentCCIDBusySlots should be here
+        
+        pstmessage = (CCIDMessageBulkOut *) pcBuffer;
+        pstmessage->bMessageType = bMessageTypeCmd;
+        pstmessage->dwLength = HostToCCIDLong(dwDataCmdLength);
+        pstmessage->bSlot = wSlot;
+        pstmessage->bSeq = CCIDReaderStates[wRdrLun].bSeq++;
+        pstmessage->bMessageSpecific1 = abMessageSpecificCmd[0];
+        pstmessage->bMessageSpecific2 = abMessageSpecificCmd[1];
+        pstmessage->bMessageSpecific3 = abMessageSpecificCmd[2];
+        // Copy the command data
+        bcopy(abDataCmd, pcBuffer+sizeof(CCIDMessageBulkOut), dwDataCmdLength);
+        
+        trv = CCIDReaderStates[wRdrLun].pTrFunctions->Write(Lun,
+                                                            sizeof(CCIDMessageBulkOut) +
+                                                            dwDataCmdLength,
+                                                            pcBuffer);
+    }
+    bzero(pcBuffer, sizeof(CCIDMessageBulkOut)+dwDataCmdLength);
+    if ( trv != TrRv_OK )
+    {
+        free(pcBuffer);
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+    dwRespLength =  CCIDReaderStates[wRdrLun].dwMaxCCIDMessageLength;
+    trv = CCIDReaderStates[wRdrLun].pTrFunctions->Read(Lun, &dwRespLength,
+                                                       pcBuffer);
+    if ( trv != TrRv_OK )
+    {
+        free(pcBuffer);
+        return CCIDRv_ERR_TRANSPORT_ERROR;
+    }
+    if ( dwRespLength < sizeof(CCIDMessageBulkIn) )
+    {
+        free(pcBuffer);
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader returned too little data");
+        return CCIDRv_ERR_UNSPECIFIED;        
+    }
+    pstresponse = (CCIDMessageBulkIn *) pcBuffer;
+    // Now parse the returned value and copy it in the parameters
+    *pbMessageTypeResp = pstresponse->bMessageType;
+    *pbStatus = pstresponse->bStatus;
+    *pbError = pstresponse->bError;
+    *pbMessageSpecificResp = pstresponse->bMessageSpecific;
+    dwRespLength -= sizeof(CCIDMessageBulkIn);
+    BYTE bSeq = pstresponse->bSeq;
+    // Check if the returned sequence byte matches that was sent
+    if ( bSeq != ((BYTE)(CCIDReaderStates[wRdrLun].bSeq-1)))
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "CCID sequence byte returned by reader is wrong %d instead of %d",
+                    bSeq, (CCIDReaderStates[wRdrLun].bSeq-1));
+        return CCIDRv_ERR_WRONG_SEQUENCE;
+    }
+    
+    
+    LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "ICCStats: %s", 
+                CCIDGetICCStatusMessage(CCIDGetICCStatus(*pbStatus)));
+    LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "CmdStatus: %s", 
+                CCIDGetCommandStatusMessage(CCIDGetCommandStatus(*pbStatus)));
+    // Check for common errors
+    BYTE bICCStatus = CCIDGetCommandStatus(*pbStatus) ;
+    if ( CCIDGetCommandStatus(*pbStatus) ==  CCID_CMD_STATUS_TIME_REQ )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Reader has requested time extension");
+        return CCIDRv_ERR_TIME_REQUEST;
+    }  
+    // Modify return values only if we did not get a Time Request
+    if (abDataResp != NULL)
+    {
+        if ( dwRespLength > *pdwDataRespLength )
+        {
+            dwRespLength = *pdwDataRespLength;
+        }
+        bcopy(pcBuffer + sizeof(CCIDMessageBulkIn), abDataResp, dwRespLength);
+    }
+    *pdwDataRespLength = dwRespLength;
+
+    bzero(pcBuffer, sizeof(CCIDMessageBulkOut)+dwRespLength);
+    free(pcBuffer);
+    
+    if ( CCIDGetCommandStatus(*pbStatus) ==  CCID_CMD_STATUS_FAILED )
+    {
+        // For all values pbICCStatus but RFU:
+        if ( (bICCStatus != CCID_ICC_STATUS_RFU)
+             &&
+             (*pbError == CCID_ERR_CMD_SLOT_BUSY))
+            return CCIDRv_ERR_SLOT_BUSY;
+        
+        if ( bICCStatus == CCID_ICC_STATUS_ABSENT )
+        {
+            if ( *pbError == CCID_ERR_5 )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Command to inexistant slot");
+                return CCIDRv_ERR_NO_SUCH_SLOT;
+            }
+            if ( *pbError == CCID_ERR_ICC_MUTE )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Card Absent");
+                return CCIDRv_ERR_CARD_ABSENT;
+            }
+        }
+        if ( bICCStatus == CCID_ICC_STATUS_INACTIVE )
+        {
+            if ( *pbError == CCID_ERR_HW_ERROR )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Hardware Error");
+                return CCIDRv_ERR_HW_ERROR;
+            }
+            if ( *pbError == CCID_ERR_CMD_ABORTED )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Command aborted");
+                return CCIDRv_ERR_CMD_ABORTED;
+            }
+            if ( *pbError == CCID_ERR_BUSY_WITH_AUTO_SEQUENCE )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Busy with auto sequence");
+                return CCIDRv_ERR_BUSY_AUTO_SEQ;
+            }
+        }
+        
+        if ( (bICCStatus == CCID_ICC_STATUS_ACTIVE)
+             &&
+             (*pbError == CCID_ERR_0)
+             )
+        {
+            LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Command unsupported");
+            return CCIDRv_ERR_UNSUPPORTED_CMD;
+        }
+
+        // Return an unspecified error code
+        // but higher layers might modify it
+        return CCIDRv_ERR_PRIVATE_ERROR;
+        
+    }
+    return CCIDRv_OK;
+    
+}
+
+
+CCIDRv CCID_IccPowerOn(DWORD Lun, BYTE *abDataResp, DWORD *pdwDataRespLength)
+{
+    CCIDRv rv;
+    WORD wRdrLun;
+    BYTE bMessageTypeResp;
+    BYTE bStatus;
+    BYTE bError;
+    BYTE bMessageSpecificResp;
+    BYTE abMessageSpecificCmd[3] = "\x00\x00\x00";
+    DWORD dwDataRespLengthBuffer;
+
+    // Save value of the buffer size
+    dwDataRespLengthBuffer = *pdwDataRespLength;
+    wRdrLun = LunToReaderLun(Lun);
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    if ( !CCIDReaderStates[wRdrLun].used)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Reader Lun of unused reader: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    
+    // Check if autopower is supported by CCID
+    if (CCIDReaderStates[wRdrLun].classDesc.dwFeatures & CCID_CLASS_FEAT_AUTO_VOLT )
+    {
+        abMessageSpecificCmd[0] = 0x00;
+    }
+    else
+    {
+        // Power-up at 5V
+        //+++ For the proper Power-Up sequence, see 7816-3:1997 section 4.2.2
+        abMessageSpecificCmd[0] = 0x01;        
+    }
+    rv =  CCID_Exchange_Command(Lun, PC_to_RDR_IccPowerOn,
+                                abMessageSpecificCmd,
+                                (BYTE *)"", 0,
+                                &bMessageTypeResp,
+                                &bStatus, &bError,
+                                &bMessageSpecificResp,
+                                abDataResp, pdwDataRespLength, 0);
+    if ( rv == CCIDRv_ERR_PRIVATE_ERROR )
+    {
+        // ICC Power On has a few specific error cases
+        if ( CCIDGetICCStatus(bStatus) == CCID_ICC_STATUS_INACTIVE )
+        {
+            if ( bError == CCID_ERR_7 )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                            "Power On mode not supported: %02X", abMessageSpecificCmd[0]);
+                return CCIDRv_ERR_POWERON_MODE_UNSUPPORTED;
+            }
+
+            if ( bError == CCID_ERR_XFR_PARITY_ERROR )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "ATR Parity error");
+                return CCIDRv_ERR_ATR_PARITY_ERROR;
+            }
+
+            if ( bError == CCID_ERR_BAD_ATR_TS )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Wrong TS in ATR");
+                return CCIDRv_ERR_BAD_ATR_TS;
+            }
+
+            if ( bError == CCID_ERR_BAD_ATR_TCK )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Wrong TCK in ATR");
+                return CCIDRv_ERR_BAD_ATR_TCK;
+            }
+
+            if ( bError == CCID_ERR_ICC_PROTOCOL_NOT_SUPPORTED )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Protocol not supported");
+                return CCIDRv_ERR_PROTOCOL_NOT_SUPPORTED;
+            }
+
+            if ( bError == CCID_ERR_ICC_CLASS_NOT_SUPPORTED )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "ICC Class not supported");
+                return CCIDRv_ERR_CLASS_NOT_SUPPORTED;
+            }
+
+        }
+        if ( CCIDGetICCStatus(bStatus) == CCID_ICC_STATUS_ABSENT)
+        {
+            return CCIDRv_ERR_CARD_ABSENT;
+        }
+        // Might be a proprietary error
+        // Check if there is customed extension
+        CCIDPropExt stCCIDPropExt;
+        rv = CCIDPropExtLookupExt(CCIDReaderStates[wRdrLun].dwVendorID,
+                                  CCIDReaderStates[wRdrLun].dwProductID,
+                                  &stCCIDPropExt);
+        if ( rv != CCIDRv_OK )
+        {
+            return CCIDRv_ERR_UNSPECIFIED;
+        }
+        if ( stCCIDPropExt.PowerOn !=  NULL )
+        {
+            // Restore value of buffer
+            *pdwDataRespLength = dwDataRespLengthBuffer;
+            rv = stCCIDPropExt.PowerOn(Lun, abDataResp, pdwDataRespLength,
+                                       bStatus, bError);
+        }
+    }
+    if (  rv != CCIDRv_OK )
+    {
+        return rv;
+    }
+    if ( bMessageTypeResp != RDR_to_PC_DataBlock )
+    {
+        return CCIDRv_ERR_WRONG_MESG_RESP_TYPE;
+    }
+    return CCIDRv_OK;
+}
+
+CCIDRv CCID_IccPowerOff(DWORD Lun, BYTE *pbClockStatus)
+{
+    CCIDRv rv;
+    WORD wRdrLun;
+    BYTE bMessageTypeResp;
+    BYTE bStatus;
+    BYTE bError;
+    BYTE bMessageSpecificResp;
+    BYTE abMessageSpecificCmd[3] = "\x00\x00\x00";
+    DWORD dwDataRespLength;
+
+    wRdrLun = LunToReaderLun(Lun);
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    rv =  CCID_Exchange_Command(Lun, PC_to_RDR_IccPowerOff,
+                                abMessageSpecificCmd,
+                                (BYTE *)"", 0,
+                                &bMessageTypeResp,
+                                &bStatus, &bError,
+                                &bMessageSpecificResp,
+                                NULL, &dwDataRespLength, 0);
+    if ( rv == CCIDRv_ERR_PRIVATE_ERROR )
+    {
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+    if (  rv != CCIDRv_OK )
+    {
+        return rv;
+    }
+    if ( bMessageTypeResp != RDR_to_PC_SlotStatus )
+    {
+        return CCIDRv_ERR_WRONG_MESG_RESP_TYPE;
+    }
+    *pbClockStatus = bMessageSpecificResp;
+    return CCIDRv_OK;
+    
+}
+
+CCIDRv CCID_GetSlotStatus(DWORD Lun,  BYTE *pbStatus, BYTE *pbClockStatus)
+{
+    CCIDRv rv;
+    WORD wRdrLun;
+    BYTE bMessageTypeResp;
+    BYTE bStatus;
+    BYTE bError;
+    BYTE bMessageSpecificResp;
+    BYTE abMessageSpecificCmd[3] = "\x00\x00\x00";
+    DWORD dwDataRespLength;
+
+    wRdrLun = LunToReaderLun(Lun);
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    rv =  CCID_Exchange_Command(Lun, PC_to_RDR_GetSlotStatus,
+                                abMessageSpecificCmd,
+                                (BYTE *)"", 0,
+                                &bMessageTypeResp,
+                                &bStatus, &bError,
+                                &bMessageSpecificResp,
+                                NULL, &dwDataRespLength, 0);
+    if ( rv == CCIDRv_ERR_PRIVATE_ERROR )
+    {
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+    if (  rv != CCIDRv_OK )
+    {
+        return rv;
+    }
+    if ( bMessageTypeResp != RDR_to_PC_SlotStatus )
+    {
+        return CCIDRv_ERR_WRONG_MESG_RESP_TYPE;
+    }
+    *pbClockStatus = bMessageSpecificResp;
+    *pbStatus = bStatus;
+    return CCIDRv_OK;
+    
+}
+CCIDRv CCID_XfrBlock(DWORD Lun, BYTE bBWI,
+                     DWORD dwRequestedProtocol,
+                     BYTE *abDataCmd, DWORD dwDataCmdLength,
+                     BYTE *abDataResp, DWORD *pdwDataRespLength)
+{
+    WORD wRdrLun;
+    wRdrLun = LunToReaderLun(Lun);
+
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    if ( !CCIDReaderStates[wRdrLun].used)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Reader Lun of unused reader: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    
+    switch ( CCIDReaderStates[wRdrLun].dwExchangeLevel )
+    {
+        case CCID_CLASS_FEAT_EXC_LEVEL_CHAR:
+        case CCID_CLASS_FEAT_EXC_LEVEL_LAPDU:
+            return CCIDRv_ERR_READER_LEVEL_UNSUPPORTED;
+        case CCID_CLASS_FEAT_EXC_LEVEL_TPDU:
+            //+++ 1 for T=1 should be replaced by a #define
+            if (dwRequestedProtocol == 1)
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                            "Protocol type of card (T=1) not supported by this driver for this type of reader (TPDU)");                
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                            "An APDU-level reader should be used");                
+                return CCIDRv_ERR_READER_LEVEL_UNSUPPORTED;
+            }
+            return CCID_XfrBlockTPDU(Lun, bBWI,
+                                      abDataCmd, dwDataCmdLength,
+                                      abDataResp, pdwDataRespLength);            
+        case CCID_CLASS_FEAT_EXC_LEVEL_SAPDU:
+            return CCID_XfrBlockSAPDU(Lun, bBWI,
+                                     abDataCmd, dwDataCmdLength,
+                                     abDataResp, pdwDataRespLength);
+    }
+    return CCIDRv_ERR_UNSPECIFIED;
+}
+
+
+CCIDRv CCID_XfrBlockSAPDU(DWORD Lun, BYTE bBWI,
+                          BYTE *abDataCmd, DWORD dwDataCmdLength,
+                          BYTE *abDataResp, DWORD *pdwDataRespLength)
+{
+    CCIDRv rv;
+    WORD wRdrLun;
+    BYTE bMessageTypeResp;
+    BYTE bStatus;
+    BYTE bError;
+    BYTE bMessageSpecificResp;
+    BYTE abMessageSpecificCmd[3] = "\x00\x00\x00";
+    abMessageSpecificCmd[0] = bBWI;
+    // For Short APDU, no need to change abMessageSpecificCmd[1,2]
+    // as they are RFU at the moment
+    
+    wRdrLun = LunToReaderLun(Lun);
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    if ( !CCIDReaderStates[wRdrLun].used)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical,
+                    "Reader Lun of unused reader: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    
+    //+++ CCID spec not clear on what to do for APDUs where 
+    // length(APDU)+sizeof(CCIDMessageBulkOut) > dwMaxCCIDMessageLength
+    // so we just reject it
+    if ( CCIDReaderStates[wRdrLun].classDesc.dwMaxCCIDMessageLength
+         < (dwDataCmdLength+sizeof(CCIDMessageBulkOut)) )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, 
+                    "dwMaxCCIDMessageLength is too small for supplied data");
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+
+    rv = CCIDRv_ERR_UNSPECIFIED;
+    BYTE bTimeExtRetry = 0;
+    do
+    {
+        rv =  CCID_Exchange_Command(Lun, PC_to_RDR_XfrBlock,
+                                    abMessageSpecificCmd,
+                                    abDataCmd, dwDataCmdLength,
+                                    &bMessageTypeResp,
+                                    &bStatus, &bError,
+                                    &bMessageSpecificResp,
+                                    abDataResp, pdwDataRespLength, bTimeExtRetry);
+        bTimeExtRetry = 1;
+    }
+    while  (rv == CCIDRv_ERR_TIME_REQUEST);
+
+    if ( rv == CCIDRv_ERR_PRIVATE_ERROR )
+    {
+        // ICC Power On has a few specific error cases
+        if ( CCIDGetICCStatus(bStatus) == CCID_ICC_STATUS_INACTIVE )
+        {
+            if ( bError == CCID_ERR_7 )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Power On mode not supported: %02X", abMessageSpecificCmd[0]);
+                return CCIDRv_ERR_POWERON_MODE_UNSUPPORTED;
+            }
+
+            if ( bError == CCID_ERR_XFR_PARITY_ERROR )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Exchange Parity error");
+                return CCIDRv_ERR_XFR_PARITY_ERROR;
+            }
+
+            if ( bError == CCID_ERR_XFR_OVERRUN )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "XFR overrun");
+                return CCIDRv_ERR_XFR_OVERRUN;
+            }
+
+            if ( bError == CCID_ERR_1 )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Wrong dwLength");
+                return CCIDRv_ERR_XFR_WRONG_DWLENGTH;
+            }
+
+            if ( bError == CCID_ERR_8 )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Wrong dwLevelParameter");
+                return CCIDRv_ERR_XFR_WRONG_DWLEVELPARAMETER;
+            }
+
+        }
+        if ( CCIDGetICCStatus(bStatus) == CCID_ICC_STATUS_ABSENT)
+        {
+            return CCIDRv_ERR_CARD_ABSENT;
+        }        
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+    if (  rv != CCIDRv_OK )
+    {
+        return rv;
+    }
+    if ( bMessageTypeResp != RDR_to_PC_DataBlock )
+    {
+        return CCIDRv_ERR_WRONG_MESG_RESP_TYPE;
+    }
+
+    return CCIDRv_OK;    
+    
+}
+
+
+
+
+/*
+ CCIDRv CCID_GetParameters(DWORD Lun,
+                          BYTE *pbProtocolNum,
+                          BYTE *abProtocolDataStructure,
+                          DWORD *dwProtocolDataStructureLength);
+CCIDRv CCID_ResetParameters(DWORD Lun,
+                            BYTE *pbProtocolNum,
+                            BYTE *abProtocolDataStructure,
+                            DWORD *dwProtocolDataStructureLength);
+CCIDRv CCID_SetParameter(DWORD Lun,
+                         BYTE bProtocolNum,
+                         BYTE *abSetProtocolDataStructure,
+                         DWORD dwSetProtocolDataStructureLength,
+                         BYTE *pbProtocolNum,
+                         BYTE *abProtocolDataStructure,
+                         DWORD *dwProtocolDataStructureLength);
+*/
+
+CCIDRv CCID_Escape(DWORD Lun,
+                   BYTE *abDataCmd, DWORD dwDataCmdLength,
+                   BYTE *abDataResp, DWORD *pdwDataRespLength,
+                   BYTE *pbErrorSpecific)
+{
+    CCIDRv rv;
+    BYTE bMessageTypeResp;
+    BYTE bStatus;
+    BYTE bError;
+    BYTE bMessageSpecificResp;
+    *pbErrorSpecific = 0;
+    rv =  CCID_Exchange_Command(Lun, PC_to_RDR_Escape,
+                                (BYTE *)"\x00\x00\x00",
+                                abDataCmd, dwDataCmdLength,
+                                &bMessageTypeResp,
+                                &bStatus, &bError,
+                                &bMessageSpecificResp,
+                                abDataResp, pdwDataRespLength, 0);
+    if ( rv == CCIDRv_ERR_PRIVATE_ERROR )
+    {
+        if ( CCIDGetICCStatus(bStatus) == CCID_ICC_STATUS_ACTIVE )
+        {
+            *pbErrorSpecific = bError;
+            return CCIDRv_ERR_MANUFACTURER_ERROR;
+        }
+
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+    if (  rv != CCIDRv_OK )
+    {
+        return rv;
+    }
+    if ( bMessageTypeResp != RDR_to_PC_Escape )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Wrong response type from reader");
+        return CCIDRv_ERR_WRONG_MESG_RESP_TYPE;
+    }
+
+    return CCIDRv_OK;
+}
+
+//++ TPDU mode will only work with T=0 cards
+CCIDRv CCID_XfrBlockTPDU(DWORD Lun, BYTE bBWI,
+                          BYTE *abDataCmd, DWORD dwDataCmdLength,
+                          BYTE *abDataResp, DWORD *pdwDataRespLength)
+{
+    DWORD dwDataRespLengthBuffer;
+    CCIDRv rv;
+    BYTE abGetResponse[] = {0x00, 0xC0, 0x00, 0x00, 0x00};
+    BYTE bLe;
+    DWORD dwAPDULength;
+    
+    // Save the value of the buffer length in a get response needs to be run
+    dwDataRespLengthBuffer = *pdwDataRespLength;
+    
+    //++ For now, use the SAPDU call
+    rv = CCID_XfrBlockSAPDU(Lun, bBWI,
+                            abDataCmd, dwDataCmdLength,
+                            abDataResp, pdwDataRespLength);
+
+    if ( rv == CCIDRv_OK )
+    {
+        // Check if we did not just get a 4-byte Case 0 APDU
+        if ( dwDataCmdLength < 5 )
+        {
+            // No Lc was provided
+            return rv;
+        }
+        //++ This will not work for extended APDUs
+        // Check if we received a fully qualified APDU Case 4 APDU
+        // Size of the command should be
+        // CLA + INS + P1 + P2 + Lc + value(Lc) + Le
+        dwAPDULength = 1 + 1 + 1 + 1 + 1 + abDataCmd[4] + 1;
+        if ( dwDataCmdLength ==  dwAPDULength )
+        {
+            bLe = abDataCmd[dwAPDULength-1];
+            // This is really a Case 4 
+            // Check if a Get response should be placed
+            // Case 4S.3 : "Command accepted with information added"
+            if ( (*pdwDataRespLength == 2)
+                 && (abDataResp[0] = 0x61))
+            {
+                // Card sent a 61 Lx
+                // Send get response with P3 = min(Le, Lx)
+                // minimum is a bit odd as L? = 00 means 256 (0x100)
+                if ( bLe == 0x00 )
+                {
+                    // abDataResp[1] can only be smaller that bLe
+                    // so change value before the test
+                    bLe = abDataResp[1];
+                }
+                if ( abDataResp[1] == 0x00 )
+                {
+                    // abDataResp[1] can only be smaller that bLe
+                    // so change value before the test
+                    abDataResp[1] = bLe;
+                }
+                abGetResponse[4] = (bLe < abDataResp[1]) ? bLe: abDataResp[1];
+                // Set-up buffer response to initial value
+                *pdwDataRespLength = dwDataRespLengthBuffer;
+                rv = CCID_XfrBlockSAPDU(Lun, bBWI,
+                                        abGetResponse, sizeof(abGetResponse),
+                                        abDataResp, pdwDataRespLength);
+                goto end;
+            }
+            // Case 4S.2 : "Command accepted"
+            if ( (*pdwDataRespLength == 2)
+                 && (abDataResp[0] = 0x90)
+                 && (abDataResp[0] = 0x00))
+            {
+                // Card sent a 9000
+                // Send a Get Response with the length
+                // included in the APDU
+                abGetResponse[4] = bLe;
+                // Set-up buffer response to initial value
+                *pdwDataRespLength = dwDataRespLengthBuffer;
+                rv = CCID_XfrBlockSAPDU(Lun, bBWI,
+                                        abGetResponse, sizeof(abGetResponse),
+                                        abDataResp, pdwDataRespLength);
+            }
+        }
+    }
+end:
+    return rv;    
+}
+
+/*
+
+ CCIDRv CCID_IccClock(DWORD Lun, BYTE bClockCommand,
+                      BYTE *pbClockStatus);
+ CCIDRv CCID_T0APDU(DWORD Lun, BYTE bmChanges, BYTE bClassGetResponse
+                    BYTE bClassEnvelope,
+                    BYTE *pbClockStatus);
+ // CCID_Secure IS CURRENTLY NOT SUPPORTED
+ // FUNCTION PROTOTYPE WILL CHANGE WHEN IT IS
+ CCIDRv CCID_Secure(DWORD Lun);
+ CCIDRv CCID_Mechanical(DWORD Lun, BYTE bFunction,
+                        BYTE *pbClockStatus);
+ CCIDRv CCID_Abort(DWORD Lun, BYTE *pbClockStatus);
+ CCIDRv CCID_SetDataRateAndClockFrequency(DWORD Lun,
+                                          DWORD dwClockFrequencyCmd,
+                                          DWORD dwDataRateCmd,
+                                          DWORD *pdwClockFrequencyResp,
+                                          DWORD *pdwDataRateResp);
+*/ 

Added: trunk/SmartCardServices/src/CCIDDriver/common/CCID.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/CCID.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/CCID.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,377 @@
+/*
+ *
+ *  Created by JL Giraud <jlgiraud at mac.com>.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#ifndef __CCID_H__
+#define __CCID_H__
+#include <CoreFoundation/CoreFoundation.h>
+#include "wintypes.h"
+#include "pcscdefines.h"
+#include "transport.h"
+
+#define CCID_DESC_TYPE (0x21)
+#define CCID_DESC_SIZE (0x36)
+// Data strutuctures definitions
+typedef struct
+{
+    UInt8  bLength                __attribute__ ((packed));
+    UInt8  bDescriptorType        __attribute__ ((packed));
+    UInt16 bcdCCID                __attribute__ ((packed));
+    UInt8  bMaxSlotIndex          __attribute__ ((packed));
+    UInt8  bVoltageSupport        __attribute__ ((packed));
+    UInt32 dwProtocols            __attribute__ ((packed));
+    UInt32 dwDefaultClock         __attribute__ ((packed));
+    UInt32 dwMaximumClock         __attribute__ ((packed));
+    UInt8  bNumCockSupported      __attribute__ ((packed));
+    UInt32 dwDataRate             __attribute__ ((packed));
+    UInt32 dwMaxDataRate          __attribute__ ((packed));
+    UInt8  bNumDataRatesSupported __attribute__ ((packed));
+    UInt32 dwMaxIFSD              __attribute__ ((packed));
+    UInt32 dwSynchProtocols       __attribute__ ((packed));
+    UInt32 dwMechanical           __attribute__ ((packed));
+    UInt32 dwFeatures             __attribute__ ((packed));
+    UInt32 dwMaxCCIDMessageLength __attribute__ ((packed));
+    UInt8  bClassGetResponse      __attribute__ ((packed));
+    UInt8  bClassEnvelope         __attribute__ ((packed));
+    UInt16 wLcdLayout             __attribute__ ((packed));
+    UInt8  bPINSupport            __attribute__ ((packed));
+    UInt8  bMaxCCIDBusySlots      __attribute__ ((packed));
+} CCIDClassDescriptor;
+
+
+#define OFFSET_bLength                  0
+#define OFFSET_bDescriptorType          1
+#define OFFSET_bcdCCID                  2
+#define OFFSET_bMaxSlotIndex            4
+#define OFFSET_bVoltageSupport          5
+#define OFFSET_dwProtocols              6
+#define OFFSET_dwDefaultClock          10
+#define OFFSET_dwMaximumClock          14
+#define OFFSET_bNumCockSupported       18
+#define OFFSET_dwDataRate              19
+#define OFFSET_dwMaxDataRate           23
+#define OFFSET_bNumDataRatesSupported  27
+#define OFFSET_dwMaxIFSD               28
+#define OFFSET_dwSynchProtocols        32
+#define OFFSET_dwMechanical            36
+#define OFFSET_dwFeatures              40
+#define OFFSET_dwMaxCCIDMessageLength  44
+#define OFFSET_bClassGetResponse       48
+#define OFFSET_bClassEnvelope          49
+#define OFFSET_wLcdLayout              50
+#define OFFSET_bPINSupport             52
+#define OFFSET_bMaxCCIDBusySlots       53
+
+
+/*
+     From CCID spec:
+     offset, name, size
+     0 bLength 1 
+     1 bDescriptorType 1 
+     2 bcdCCID 2 
+     4 bMaxSlotIndex 1
+     5 bVoltageSupport 1
+     6 dwProtocols 4 
+     10 dwDefaultClock 4
+     14 dwMaximumClock 4
+     18 bNumCockSupported 1
+     19 dwDataRate 4 
+     23 dwMaxDataRate 4
+     27 bNumDataRatesSupported 1 
+     28 dwMaxIFSD 4 
+     32 dwSynchProtocols 4
+     36 dwMechanical 4 
+     40 dwFeatures 4
+     44 dwMaxCCIDMessageLength 4 
+     48 bClassGetResponse 1
+     49 bClassEnvelope 1  
+     50 wLcdLayout 2 
+     52 bPINSupport 1
+     53 bMaxCCIDBusySlots 1
+     
+     */
+
+
+// Standard CCID message descriptor
+typedef struct
+{
+    BYTE bMessageType                  __attribute__ ((packed));
+    DWORD dwLength                     __attribute__ ((packed));
+    BYTE bSlot                         __attribute__ ((packed));
+    BYTE bSeq                          __attribute__ ((packed));
+    BYTE bMessageSpecific1             __attribute__ ((packed));
+    BYTE bMessageSpecific2             __attribute__ ((packed));
+    BYTE bMessageSpecific3             __attribute__ ((packed));
+} CCIDMessageBulkOut;
+
+typedef struct
+{
+    BYTE bMessageType                  __attribute__ ((packed));
+    DWORD dwLength                     __attribute__ ((packed));
+    BYTE bSlot                         __attribute__ ((packed));
+    BYTE bSeq                          __attribute__ ((packed));
+    BYTE bStatus                       __attribute__ ((packed));
+    BYTE bError                        __attribute__ ((packed));
+    BYTE bMessageSpecific              __attribute__ ((packed));
+} CCIDMessageBulkIn;
+
+#define CCID_CLASS_PROTOCOL_T0  0x00000001
+#define CCID_CLASS_PROTOCOL_T1  0x00000002
+
+
+
+// Related to dwFeatures in Class Desc.
+#define CCID_CLASS_FEAT_AUTO_CONF_ATR  0x00000002
+#define CCID_CLASS_FEAT_AUTO_ACT       0x00000004
+#define CCID_CLASS_FEAT_AUTO_VOLT      0x00000008
+#define CCID_CLASS_FEAT_AUTO_CLOCK     0x00000010
+#define CCID_CLASS_FEAT_AUTO_BAUD      0x00000020
+#define CCID_CLASS_FEAT_AUTO_PPS_PROP  0x00000040
+#define CCID_CLASS_FEAT_AUTO_PPS_CUR   0x00000080
+#define CCID_CLASS_FEAT_CLOCK_STOP     0x00000100
+#define CCID_CLASS_FEAT_NAD_NON_0      0x00000200
+#define CCID_CLASS_FEAT_AUTO_IFSD      0x00000400
+// MASk to get value of Exchange level
+#define CCID_CLASS_FEAT_EXC_LEVEL_MASK  0x00070000
+#define CCID_CLASS_FEAT_EXC_LEVEL_CHAR  0x00000000
+#define CCID_CLASS_FEAT_EXC_LEVEL_TPDU  0x00010000
+#define CCID_CLASS_FEAT_EXC_LEVEL_SAPDU 0x00020000
+#define CCID_CLASS_FEAT_EXC_LEVEL_LAPDU 0x00040000
+
+
+// Used to store the state of a slot for a reader
+typedef struct {
+    DWORD dwProtocol;
+    DWORD nATRLength;
+    UCHAR pcATRBuffer[MAX_ATR_SIZE];
+    UCHAR bPowerFlags;    
+} CCIDSlotState;
+
+typedef struct {
+    BYTE used;
+    CCIDClassDescriptor classDesc;
+    TrFunctions *pTrFunctions;
+    BYTE bSeq;
+    BYTE bMaxSlotIndex;
+    BYTE bMaxCCIDBusySlots;
+    BYTE bCurrentCCIDBusySlots;
+    DWORD dwProductID;
+    DWORD dwVendorID;
+    DWORD dwMaxCCIDMessageLength;
+    // Use this instead of class Desc as it maybe
+    // modified in initialisation of some readers
+    DWORD dwExchangeLevel;
+    CCIDSlotState *slotStates;
+} tIo;
+// Used to store the state of a reader (per reader Lun)
+typedef struct {
+    BYTE used;
+    CCIDClassDescriptor classDesc;
+    TrFunctions *pTrFunctions;
+    BYTE bSeq;
+    BYTE bMaxSlotIndex;
+    BYTE bMaxCCIDBusySlots;
+    BYTE bCurrentCCIDBusySlots;
+    DWORD dwProductID;
+    DWORD dwVendorID;
+    DWORD dwMaxCCIDMessageLength;
+    // Use this instead of class Desc as it maybe
+    // modified in initialisation of some readers
+    DWORD dwExchangeLevel;
+    CCIDSlotState *slotStates;
+} CCIDReaderState;
+
+
+// values of bMessageType
+#define PC_to_RDR_IccPowerOn                   0x62
+#define PC_to_RDR_IccPowerOff                  0x63
+#define PC_to_RDR_GetSlotStatus                0x65
+#define PC_to_RDR_XfrBlock                     0x6F
+#define PC_to_RDR_GetParameters                0x6C
+#define PC_to_RDR_ResetParameters              0x6D
+#define PC_to_RDR_SetParameter                 0x61
+#define PC_to_RDR_Escape                       0x6B
+#define PC_to_RDR_IccClock                     0x6E
+#define PC_to_RDR_T0APDU                       0x6A
+#define PC_to_RDR_Secure                       0x69
+#define PC_to_RDR_Mechanical                   0x71
+#define PC_to_RDR_Abort                        0x72
+#define PC_to_RDR_SetDataRateAndClockFrequency 0x73
+#define RDR_to_PC_DataBlock                    0x80
+#define RDR_to_PC_SlotStatus                   0x81
+#define RDR_to_PC_Parameters                   0x82
+#define RDR_to_PC_Escape                       0x83
+#define RDR_to_PC_DataRateAndClockFrequency    0x84
+
+typedef enum {
+    CCIDRv_OK                                 = 0x00,
+    CCIDRv_ERR_UNSPECIFIED                    = 0x01,
+    CCIDRv_ERR_NO_IMPLEMENTED                 = 0x02,
+    CCIDRv_ERR_READER_LUN                     = 0x03,
+    CCIDRv_ERR_SLOT_LUN                       = 0x04,
+    CCIDRv_ERR_SLOTS_BUSY                     = 0x05,
+    CCIDRv_ERR_CLASS_DESC_INVALID             = 0x06,
+    CCIDRv_ERR_TRANSPORT_ERROR                = 0x07,
+    CCIDRv_ERR_VALUE_NOT_FOUND                = 0x08,
+    CCIDRv_ERR_WRONG_MESG_RESP_TYPE           = 0x09,
+    CCIDRv_ERR_TIME_REQUEST                   = 0x0A,
+    CCIDRv_ERR_NO_SUCH_SLOT                   = 0x0B,
+    CCIDRv_ERR_UNSUPPORTED_CMD                = 0x0C,
+    CCIDRv_ERR_SLOT_BUSY                      ,
+    //CCIDRv_ERR_NO_ICC_PRESENT               ,
+    CCIDRv_ERR_CARD_ABSENT                    ,
+    CCIDRv_ERR_HW_ERROR                       ,
+    CCIDRv_ERR_CMD_ABORTED                    ,
+    CCIDRv_ERR_BUSY_AUTO_SEQ                  ,
+    CCIDRv_ERR_POWERON_MODE_UNSUPPORTED       ,
+    CCIDRv_ERR_ICC_MUTE                       ,
+    CCIDRv_ERR_ATR_PARITY_ERROR               ,
+    CCIDRv_ERR_BAD_ATR_TS                     ,
+    CCIDRv_ERR_BAD_ATR_TCK                    ,
+    CCIDRv_ERR_PROTOCOL_NOT_SUPPORTED         ,
+    CCIDRv_ERR_CLASS_NOT_SUPPORTED            ,
+    CCIDRv_ERR_MANUFACTURER_ERROR             ,
+    CCIDRv_ERR_READER_LEVEL_UNSUPPORTED       ,
+    CCIDRv_ERR_XFR_PARITY_ERROR               ,
+    CCIDRv_ERR_XFR_OVERRUN                    ,
+    CCIDRv_ERR_XFR_WRONG_DWLENGTH             ,
+    CCIDRv_ERR_XFR_WRONG_DWLEVELPARAMETER     ,
+    CCIDRv_ERR_WRONG_SEQUENCE                 ,
+    //    CCIDRv_ERR_
+    //    CCIDRv_ERR_
+    // Error code below means that higher CCID layer
+    // should try to parse the status and error
+    // returned by the reder.
+    // This code should not be returned by any
+    // non private CCID function
+    CCIDRv_ERR_PRIVATE_ERROR
+} CCIDRv;
+
+
+
+void CCIDParseDesc(BYTE * pcbuffer, CCIDClassDescriptor *classDesc);
+void CCIDPrintDesc(CCIDClassDescriptor classDesc);
+
+// Parses the bStatus byte returned in a Bulk-IN
+// message to return bmICCStatus
+BYTE CCIDGetICCStatus(BYTE bStatus);
+// Gets a pointer to a user friendly message
+const char *CCIDGetICCStatusMessage(BYTE bICCStatus);
+// Parses the bStatus byte returned in a Bulk-IN
+// message to return bmCommandStatus
+BYTE CCIDGetCommandStatus(BYTE bStatus);
+// Gets a pointer to a user friendly message
+const char *CCIDGetCommandStatusMessage(BYTE bCommandStatus);
+
+
+CCIDRv CCID_OpenChannel(DWORD Lun, DWORD ChannelID);
+CCIDRv CCID_CloseChannel(DWORD Lun);
+
+                             
+
+CCIDRv CCID_IccPowerOn(DWORD Lun, BYTE *abDataResp, DWORD *pdwDataRespLength);
+CCIDRv CCID_IccPowerOff(DWORD Lun, BYTE *pbClockStatus);                
+CCIDRv CCID_GetSlotStatus(DWORD Lun, BYTE *pbStatus, BYTE *pbClockStatus);
+// XfrBlock expects to receive APDU level commands
+// and manages the communication with the CCID reader
+// transparently according to the reader communication level
+CCIDRv CCID_XfrBlock(DWORD Lun, BYTE bBWI,
+                     DWORD dwRequestedProtocol,
+                     BYTE *abDataCmd, DWORD dwDataCmdLength,
+                     BYTE *abDataResp, DWORD *pdwDataRespLength);
+CCIDRv CCID_GetParameters(DWORD Lun,
+                          BYTE *pbProtocolNum,
+                          BYTE *abProtocolDataStructure,
+                          DWORD *dwProtocolDataStructureLength);
+CCIDRv CCID_ResetParameters(DWORD Lun,
+                            BYTE *pbProtocolNum,
+                            BYTE *abProtocolDataStructure,
+                            DWORD *dwProtocolDataStructureLength);
+CCIDRv CCID_SetParameter(DWORD Lun,
+                         BYTE bProtocolNum,
+                         BYTE *abSetProtocolDataStructure,
+                         DWORD dwSetProtocolDataStructureLength,
+                         BYTE *pbProtocolNum,
+                         BYTE *abProtocolDataStructure,
+                         DWORD *dwProtocolDataStructureLength);
+
+
+CCIDRv CCID_Escape(DWORD Lun,
+                   BYTE *abDataCmd, DWORD dwDataCmdLength,
+                   BYTE *abDataResp, DWORD *pdwDataRespLength,
+                   BYTE *pbErrorSpecific);
+
+CCIDRv CCID_IccClock(DWORD Lun, BYTE bClockCommand,
+                     BYTE *pbClockStatus);
+CCIDRv CCID_T0APDU(DWORD Lun, BYTE bmChanges, BYTE bClassGetResponse,
+                   BYTE bClassEnvelope,
+                   BYTE *pbClockStatus);
+// CCID_Secure IS CURRENTLY NOT SUPPORTED
+// FUNCTION PROTOTYPE WILL CHANGE WHEN IT IS
+CCIDRv CCID_Secure(DWORD Lun);
+CCIDRv CCID_Mechanical(DWORD Lun, BYTE bFunction,
+                       BYTE *pbClockStatus);
+CCIDRv CCID_Abort(DWORD Lun, BYTE *pbClockStatus);
+CCIDRv CCID_SetDataRateAndClockFrequency(DWORD Lun,
+                                         DWORD dwClockFrequencyCmd,
+                                         DWORD dwDataRateCmd,
+                                         DWORD *pdwClockFrequencyResp,
+                                         DWORD *pdwDataRateResp);
+
+
+
+
+#define CCID_ERR_CMD_ABORTED                   0xFF
+#define CCID_ERR_ICC_MUTE                      0xFE
+#define CCID_ERR_XFR_PARITY_ERROR              0xFD
+#define CCID_ERR_XFR_OVERRUN                   0xFC
+#define CCID_ERR_HW_ERROR                      0xFB
+#define CCID_ERR_BAD_ATR_TS                    0xF8
+#define CCID_ERR_BAD_ATR_TCK                   0xF7
+#define CCID_ERR_ICC_PROTOCOL_NOT_SUPPORTED    0xF6
+#define CCID_ERR_ICC_CLASS_NOT_SUPPORTED       0xF5
+#define CCID_ERR_PROCEDURE_BYTE_CONFLICT       0xF4
+#define CCID_ERR_DEACTIVATED_PROTOCOL          0xF3
+#define CCID_ERR_BUSY_WITH_AUTO_SEQUENCE       0xF2
+#define CCID_ERR_PIN_TIMEOUT                   0xF0
+#define CCID_ERR_PIN_CANCELLED                 0xEF
+#define CCID_ERR_CMD_SLOT_BUSY                 0xE0
+
+// Errors with no officla names in spec
+#define CCID_ERR_0                             0x00
+#define CCID_ERR_1                             0x01
+#define CCID_ERR_5                             0x05
+#define CCID_ERR_7                             0x07
+#define CCID_ERR_8                             0x08
+
+
+#define CCID_CMD_STATUS_SUCCESS                0
+#define CCID_CMD_STATUS_FAILED                 1
+#define CCID_CMD_STATUS_TIME_REQ               2
+#define CCID_CMD_STATUS_RFU                    3
+
+#define CCID_ICC_STATUS_ACTIVE                 0
+#define CCID_ICC_STATUS_INACTIVE               1
+#define CCID_ICC_STATUS_ABSENT                 2
+#define CCID_ICC_STATUS_RFU                    3
+
+#define CCID_SLOT_STATUS_CLK_RUNNING           0x00
+#define CCID_SLOT_STATUS_CLK_STOPPED_H         0x01
+#define CCID_SLOT_STATUS_CLK_STOPPED_L         0x02
+#define CCID_SLOT_STATUS_CLK_STOPPED_UNKNOWN   0x03
+
+
+
+#define MASK_ICC_STATUS (0x03)
+#define OFFSET_ICC_STATUS (0)
+#define MASK_COMMAND_STATUS (0xC0)
+#define OFFSET_COMMAND_STATUS (6)
+
+
+
+
+#endif
\ No newline at end of file

Added: trunk/SmartCardServices/src/CCIDDriver/common/CCIDPropExt.c
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/CCIDPropExt.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/CCIDPropExt.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,191 @@
+/*
+ *  CCIDPropExt.c
+ *  ifd-CCID
+ *
+ *  Created by JL on Sun Jul 20 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#include "global.h"
+
+#include "tools.h"
+#include "CCID.h"
+#include "CCIDprivate.h"
+#include "pcscdefines.h"
+#include "CCIDPropExt.h"
+
+typedef struct {
+    DWORD dwVendorID;
+    DWORD dwProductID;
+    CCIDPropExt stPropExt;
+} CCIDExtendedPropExt;
+
+CCIDRv CCIDPropExtOpenChannelGemPCKeyTwin(DWORD lun);
+CCIDRv CCIDPropExtOpenChannelGemPC433(DWORD lun);
+CCIDRv CCIDPropExtIccPowerOnGemPC433(DWORD Lun, BYTE *abDataResp, DWORD *pdwDataRespLength, BYTE bStatus, BYTE bError);
+
+
+static CCIDExtendedPropExt astCCIDPropExt[] =
+{
+    // GemPC433
+    {0x8E6, 0x4433, {NULL, NULL, CCIDPropExtIccPowerOnGemPC433}},    
+    // GemPCKey
+    {0x8E6, 0x3438, {CCIDPropExtOpenChannelGemPCKeyTwin, NULL, NULL}},
+    // GemPCTwin
+    {0x8E6, 0x3437, {CCIDPropExtOpenChannelGemPCKeyTwin, NULL, NULL}},    
+    
+};
+
+
+CCIDRv CCIDPropExtLookupExt(DWORD dwVendorID, DWORD dwProductID, CCIDPropExt *pstCCIDPropExt)
+{
+    WORD wIndex;
+
+    for (wIndex = 0; wIndex < (sizeof(astCCIDPropExt)/sizeof(CCIDExtendedPropExt)); wIndex++)
+    {
+        if ( (astCCIDPropExt[wIndex].dwVendorID == dwVendorID)
+             && (astCCIDPropExt[wIndex].dwProductID == dwProductID)
+             )
+        {
+            pstCCIDPropExt->OpenChannel = astCCIDPropExt[wIndex].stPropExt.OpenChannel;
+            pstCCIDPropExt->CloseChannel = astCCIDPropExt[wIndex].stPropExt.CloseChannel;
+            pstCCIDPropExt->PowerOn = astCCIDPropExt[wIndex].stPropExt.PowerOn;
+            return CCIDRv_OK;
+        }
+    }
+    return CCIDRv_ERR_VALUE_NOT_FOUND;
+}
+
+
+// Used to set the GemPCKey and the GemPCTwin in APDU mode
+// Connections need to be set-up before this call
+CCIDRv CCIDPropExtOpenChannelGemPCKeyTwin(DWORD Lun)
+{
+    CCIDRv rv;
+
+    //BYTE abGemPCTwinSetAPDUMode[] = {0xA0, 0x01}; (from FB)
+    BYTE abGemPCTwinSetAPDUMode[] = {0xA0, 0x02};
+    BYTE pcBuffer[100];
+    BYTE bSpecificErrorCode;
+    DWORD dwBufferLength = sizeof(pcBuffer);
+    rv = CCID_Escape(Lun, abGemPCTwinSetAPDUMode, sizeof(abGemPCTwinSetAPDUMode),
+                     pcBuffer, &dwBufferLength, &bSpecificErrorCode);
+    if ( rv != CCIDRv_OK )
+        return rv;
+    // Successfull initialisation, update Exchange Level
+    CCIDReaderStates[ LunToReaderLun(Lun)].dwExchangeLevel = CCID_CLASS_FEAT_EXC_LEVEL_SAPDU;
+    return CCIDRv_OK;
+}
+
+
+// Used to set the GemPC433 in APDU mode
+// Connections need to be set-up before this call
+CCIDRv CCIDPropExtOpenChannelGemPC433(DWORD Lun)
+{
+    CCIDRv rv;
+    BYTE abGemPC433SetISOMode[] = {0x1F, 0x01};
+    BYTE pcBuffer[100];
+    BYTE bSpecificErrorCode;
+    DWORD dwBufferLength = sizeof(pcBuffer);
+    rv = CCID_Escape(Lun, abGemPC433SetISOMode, sizeof(abGemPC433SetISOMode),
+                     pcBuffer, &dwBufferLength, &bSpecificErrorCode);
+    if ( rv != CCIDRv_OK )
+        return rv;
+    // Successfull initialisation, update Exchange Level
+    CCIDReaderStates[ LunToReaderLun(Lun)].dwExchangeLevel = CCID_CLASS_FEAT_EXC_LEVEL_SAPDU;
+    return CCIDRv_OK;
+}
+
+// Perform second power-up in ISO mode for the GemPC433
+CCIDRv CCIDPropExtIccPowerOnGemPC433(DWORD Lun, BYTE *abDataResp, DWORD *pdwDataRespLength,
+                                     BYTE bStatus, BYTE bError)
+{
+    CCIDRv rv;
+    WORD wRdrLun;
+    BYTE bMessageTypeResp;
+    BYTE bMessageSpecificResp;
+    BYTE abMessageSpecificCmd[3] = "\x00\x00\x00";
+
+    // Check if it is a non EMV-compliant ATR issue
+    if ( bError != 0xBB )
+    {
+        // Other error, exit
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+    wRdrLun = LunToReaderLun(Lun);
+    if ( wRdrLun >= PCSCLITE_MAX_CHANNELS)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Reader Lun too large: %d", wRdrLun);
+        return CCIDRv_ERR_READER_LUN;
+    }
+    // First set reader in ISO mode
+    if ( CCIDPropExtOpenChannelGemPC433(Lun) != CCIDRv_OK )
+    {
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+    // Power-up at 5V
+    //+++ For the proper Power-Up sequence, see 7816-3:1997 section 4.2.2
+    abMessageSpecificCmd[0] = 0x01;
+    rv =  CCID_Exchange_Command(Lun, PC_to_RDR_IccPowerOn,
+                                abMessageSpecificCmd,
+                                (BYTE *)"", 0,
+                                &bMessageTypeResp,
+                                &bStatus, &bError,
+                                &bMessageSpecificResp,
+                                abDataResp, pdwDataRespLength, 0);
+    if ( rv == CCIDRv_ERR_PRIVATE_ERROR )
+    {
+        // ICC Power On has a few specific error cases
+        if ( CCIDGetICCStatus(bStatus) == CCID_ICC_STATUS_INACTIVE )
+        {
+            if ( bError == CCID_ERR_7 )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Power On mode not supported: %02X", abMessageSpecificCmd[0]);
+                return CCIDRv_ERR_POWERON_MODE_UNSUPPORTED;
+            }
+
+            if ( bError == CCID_ERR_XFR_PARITY_ERROR )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "ATR Parity error");
+                return CCIDRv_ERR_ATR_PARITY_ERROR;
+            }
+
+            if ( bError == CCID_ERR_BAD_ATR_TS )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Wrong TS in ATR");
+                return CCIDRv_ERR_BAD_ATR_TS;
+            }
+
+            if ( bError == CCID_ERR_BAD_ATR_TCK )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Wrong TCK in ATR");
+                return CCIDRv_ERR_BAD_ATR_TCK;
+            }
+
+            if ( bError == CCID_ERR_ICC_PROTOCOL_NOT_SUPPORTED )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Protocol not supported");
+                return CCIDRv_ERR_PROTOCOL_NOT_SUPPORTED;
+            }
+
+            if ( bError == CCID_ERR_ICC_CLASS_NOT_SUPPORTED )
+            {
+                LogMessage( __FILE__,  __LINE__, LogLevelCritical, "ICC Class not supported");
+                return CCIDRv_ERR_CLASS_NOT_SUPPORTED;
+            }
+
+        }
+        if ( CCIDGetICCStatus(bStatus) == CCID_ICC_STATUS_ABSENT)
+        {
+            return CCIDRv_ERR_CARD_ABSENT;
+        }
+        return CCIDRv_ERR_UNSPECIFIED;
+    }
+    if ( bMessageTypeResp != RDR_to_PC_DataBlock )
+    {
+        return CCIDRv_ERR_WRONG_MESG_RESP_TYPE;
+    }
+    return CCIDRv_OK;    
+}

Added: trunk/SmartCardServices/src/CCIDDriver/common/CCIDPropExt.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/CCIDPropExt.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/CCIDPropExt.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,30 @@
+/*
+ *  CCIDPropExt.h
+ *  ifd-CCID
+ *
+ *  Created by JL on Sun Jul 20 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+// CCID Proprietary extension management
+
+#ifndef __CCIDPROPEXT_H__
+#define __CCIDPROPEXT_H__
+
+#include "CCID.h"
+
+typedef struct {
+    CCIDRv (*OpenChannel)(DWORD lun);
+    CCIDRv (*CloseChannel)(DWORD lun);
+    CCIDRv (*PowerOn)(DWORD Lun, BYTE *abDataResp, DWORD *pdwDataRespLength,
+                      BYTE bStatus, BYTE bError);
+} CCIDPropExt;
+
+// Looks-up for a proprietary extension structure according to vendorID/ProductID
+CCIDRv CCIDPropExtLookupExt(DWORD dwVendorID, DWORD dwProductID, CCIDPropExt *pstCCIDPropExt);
+
+
+
+#endif
\ No newline at end of file

Added: trunk/SmartCardServices/src/CCIDDriver/common/CCIDprivate.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/CCIDprivate.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/CCIDprivate.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,39 @@
+/*
+ *  CCIDprivate.h
+ *  ifd-CCID
+ *
+ *  Created by JL on Mon Jul 21 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#ifndef __CCIDPRIVATE_H__
+#define __CCIDPRIVATE_H__
+extern CCIDReaderState CCIDReaderStates[PCSCLITE_MAX_CHANNELS];
+
+// Performs a Bulk-IN/Bluk-Out exchange with reader
+// Seq and Slot are automatically managed
+// "TimeExtension" messages can be handled through bTimeExtRetry:
+// If set to 1, CCID_Exchange_Command does not send the command and reads
+// directly
+// If set to 0, CCID_Exchange_Command sends the command (used for a normal call
+// or time extension management in T=1)
+CCIDRv CCID_Exchange_Command(DWORD Lun, BYTE bMessageTypeCmd,
+                             BYTE *abMessageSpecificCmd,
+                             BYTE *abDataCmd, DWORD dwDataCmdLength,
+                             BYTE *pbMessageTypeResp,
+                             BYTE *pbStatus, BYTE *pbError,
+                             BYTE *pbMessageSpecificResp,
+                             BYTE *abDataResp, DWORD *pdwDataRespLength,
+                             BYTE bTimeExtRetry);
+CCIDRv CCID_XfrBlockSAPDU(DWORD Lun, BYTE bBWI,
+                         BYTE *abDataCmd, DWORD dwDataCmdLength,
+                         BYTE *abDataResp, DWORD *pdwDataRespLength);
+
+CCIDRv CCID_XfrBlockTPDU(DWORD Lun, BYTE bBWI,
+                         BYTE *abDataCmd, DWORD dwDataCmdLength,
+                         BYTE *abDataResp, DWORD *pdwDataRespLength);
+
+
+#endif

Added: trunk/SmartCardServices/src/CCIDDriver/common/Transport.c
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/Transport.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/Transport.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,32 @@
+/*
+ *  Transport.c
+ *  ifd-CCID
+ *
+ *  Created by JL on Sat Jun 14 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+#include "pcscdefines.h"
+
+#include "Transport.h"
+#include "usbserial.h"
+
+
+// MAKE SURE VALUES AND ORDER MATCH ENUM IN Transport.h
+TrFunctions TrFunctionTable[] =
+{
+  {
+      OpenUSB,
+      GetConfigDescNumberUSB,
+      GetVendorAndProductIDUSB,
+      GetClassDescUSB,
+      SetupConnectionsUSB,
+      WriteUSB,
+      ReadUSB,
+      CloseUSB
+  }
+    
+};
+
+

Added: trunk/SmartCardServices/src/CCIDDriver/common/Transport.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/Transport.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/Transport.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,53 @@
+/*
+ *  Transport.h
+ *  ifd-CCID
+ *
+ *  Created by JL on Sat Jun 14 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#ifndef __TRANSPORT_H__
+#define __TRANSPORT_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "wintypes.h"
+
+
+typedef enum {
+  TrRv_OK                     = 0x00,
+  TrRv_ERR                    = 0x01,
+} TrRv;
+
+
+typedef struct {
+    TrRv (*Open)( DWORD lun, DWORD channel );
+    // returns the number of conifguration descriptors once the device has been successfully opened
+    TrRv (*GetConfigDescNumber)( DWORD lun, BYTE* pcconfigDescNb );
+    TrRv (*GetVendorAndProductID)( DWORD lun, DWORD *vendorID, DWORD *productID );
+    // Reads the class descriptor once the device has been successfully opened
+    TrRv (*GetClassDesc)(  DWORD lun, BYTE configDescNb, BYTE bdescType,
+                           BYTE *pcdesc, BYTE *pcdescLength);
+    TrRv (*SetupConnections)( DWORD lun, BYTE ConfigDescNb, BYTE interruptPipe);
+    TrRv (*Write)( DWORD lun, DWORD length, BYTE *Buffer );
+    TrRv (*Read)( DWORD lun, DWORD *length, BYTE *Buffer );
+    TrRv (*Close)( DWORD lun );
+} TrFunctions;
+
+// MAKE SURE VALUES AND ORDER MATCH TABLE IN Transport.c
+typedef enum {
+  TrType_USB                     = 0x00,
+  TrType_SERIAL                  = 0x01,
+} TrType;
+
+extern TrFunctions TrFunctionTable[];
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
\ No newline at end of file

Added: trunk/SmartCardServices/src/CCIDDriver/common/global.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/global.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/global.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,15 @@
+/*
+ *  global.h
+ *  ifd-CCID
+ *
+ *  Created by JL on Mon Feb 10 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ */
+
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+
+#define BUNDLE_IDENTIFIER "com.apple.ccidclassdriver"
+
+#endif

Added: trunk/SmartCardServices/src/CCIDDriver/common/ifdhandler.c
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/ifdhandler.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/ifdhandler.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,637 @@
+/*****************************************************************
+/
+/ File   :   ifdhandler.c
+/ Authors :   David Corcoran <corcoran at linuxnet.com>
+/             Jean-Luc Giraud <jlgiraud at mac.com>
+/ Date   :   April 9, 2003
+/ Purpose:   This provides reader specific low-level calls
+/            for the GemPC family of Gemplus. The function
+/            stubs were written by D. Corcoran, the CCID
+/            +specific code was added by JL Giraud.
+/            See http://www.linuxnet.com for more information.
+/ License:   See file COPYING
+/
+/
+******************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "wintypes.h"
+#include "pcscdefines.h"
+#include "ifdhandler.h"
+#include "global.h"
+
+#include "tools.h"
+#include "CCID.h"
+
+#define POWERFLAGS_RAZ 0x00
+//Flag set when a power up has been requested
+#define MASK_POWERFLAGS_PUP 0x01
+//Flag set when a power down is requested
+#define MASK_POWERFLAGS_PDWN 0x02
+
+//+++ NEEDS TO BE READ FROM CCID DESC
+#define MAX_SLOT_NB 2
+
+enum
+{
+    T_0                    = 0,
+    T_1                    = 1
+};
+
+
+
+
+typedef struct 
+{
+    DWORD nATRLength;
+    UCHAR pcATRBuffer[MAX_ATR_SIZE];
+    UCHAR bPowerFlags;
+} IFDDesc;
+
+int iLunCheck(DWORD Lun)
+{
+    if ((LunToReaderLun(Lun) >= PCSCLITE_MAX_CHANNELS))
+        return TRUE;
+
+    return FALSE;
+} /* iLunCheck */
+
+
+// Array of structures to hold the ATR and other state value of each slot
+static IFDDesc pstIFDDescs[PCSCLITE_MAX_CHANNELS][MAX_SLOT_NB];
+static int iLogValue = LogLevelCritical;
+
+BYTE bLogPeriodic = 0;
+
+RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel)
+{
+	/*
+	 * Lun - Logical Unit Number, use this for multiple card slots or
+	 * multiple readers. 0xXXXXYYYY - XXXX multiple readers, YYYY multiple
+	 * slots. The resource manager will set these automatically.  By
+	 * default the resource manager loads a new instance of the driver so
+	 * if your reader does not have more than one smartcard slot then
+	 * ignore the Lun in all the functions. Future versions of PC/SC might
+	 * support loading multiple readers through one instance of the driver
+	 * in which XXXX would be important to implement if you want this.
+	 */
+
+	/*
+	 * Channel - Channel ID.  This is denoted by the following: 0x000001 -
+	 * /dev/pcsc/1 0x000002 - /dev/pcsc/2 0x000003 - /dev/pcsc/3
+	 *
+	 * USB readers may choose to ignore this parameter and query the bus
+	 * for the particular reader.
+	 */
+
+	/*
+	 * This function is required to open a communications channel to the
+	 * port listed by Channel.  For example, the first serial reader on
+	 * COM1 would link to /dev/pcsc/1 which would be a sym link to
+	 * /dev/ttyS0 on some machines This is used to help with intermachine
+	 * independance.
+	 *
+	 * Once the channel is opened the reader must be in a state in which
+	 * it is possible to query IFDHICCPresence() for card status.
+	 *
+	 * returns:
+	 *
+	 * IFD_SUCCESS IFD_COMMUNICATION_ERROR
+	 */
+    const char *pcStringValue;
+
+    StartLogging();
+    SetLogType(LogTypeSysLog);
+    pcStringValue =  ParseInfoPlist(BUNDLE_IDENTIFIER, "ifdLogType");
+    if ( pcStringValue == NULL )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Could not get ifdLogType info, use syslog");
+    }
+    else
+    {
+        if (!strncmp(pcStringValue, "stderr", strlen("stderr")))
+        {
+            SetLogType(LogTypeStderr);            
+        }
+        else
+        {
+            SetLogType(LogTypeSysLog);
+        }
+    }
+    
+    
+    pcStringValue =  ParseInfoPlist(BUNDLE_IDENTIFIER, "ifdLogLevel");
+    if ( pcStringValue == NULL )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Could not get ifdLogLevel info, use minimal level");
+        SetLogLevel(LogLevelCritical);
+    }
+    else
+    {
+        iLogValue = atoi(pcStringValue);
+        SetLogLevel((BYTE)iLogValue);
+    }
+
+    bLogPeriodic = 0;
+    pcStringValue =  ParseInfoPlist(BUNDLE_IDENTIFIER, "ifdLogPeriodic");
+    if ( pcStringValue == NULL )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Could not get ifdLogPeriodic info, will not log periodic info");
+    }
+    else
+    {
+        if ( toupper(*pcStringValue) == 'Y' )
+            bLogPeriodic = 1;
+    }
+    
+
+    LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "Entering IFDHCreateChannel");
+
+	if (iLunCheck(Lun))
+		return IFD_COMMUNICATION_ERROR;
+
+	// Reset ATR buffer
+	pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].nATRLength = 0;
+	*pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].pcATRBuffer = '\0';
+
+	// Reset PowerFlags
+	pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].bPowerFlags =
+		POWERFLAGS_RAZ;
+
+	if (CCID_OpenChannel(Lun, Channel) != CCIDRv_OK)
+	{
+		LogMessage( __FILE__,  __LINE__, LogLevelCritical, "OpenReader failed");
+		return IFD_COMMUNICATION_ERROR;
+	}
+
+	return IFD_SUCCESS;
+} /* IFDHCreateChannel */
+
+
+RESPONSECODE IFDHCloseChannel(DWORD Lun)
+{
+	/*
+	 * This function should close the reader communication channel for the
+	 * particular reader.  Prior to closing the communication channel the
+	 * reader should make sure the card is powered down and the terminal
+	 * is also powered down.
+	 *
+	 * returns:
+	 *
+	 * IFD_SUCCESS IFD_COMMUNICATION_ERROR
+	 */
+    BYTE bClockStatus;
+	LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "entering IFDHCloseChannel");
+
+	if (iLunCheck(Lun))
+		return IFD_COMMUNICATION_ERROR;
+
+	CCID_IccPowerOff(Lun, &bClockStatus);
+	// No error status check, if it failed, what can you do ? :)
+
+	CCID_CloseChannel(Lun);
+	return IFD_SUCCESS;
+} /* IFDHCloseChannel */
+
+
+RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag,
+	PDWORD Length, PUCHAR Value)
+{
+	/*
+	 * This function should get the slot/card capabilities for a
+	 * particular slot/card specified by Lun.  Again, if you have only 1
+	 * card slot and don't mind loading a new driver for each reader then
+	 * ignore Lun.
+	 *
+	 * Tag - the tag for the information requested example: TAG_IFD_ATR -
+	 * return the Atr and it's size (required). these tags are defined in
+	 * ifdhandler.h
+	 *
+	 * Length - the length of the returned data Value - the value of the
+	 * data
+	 *
+	 * returns:
+	 *
+	 * IFD_SUCCESS IFD_ERROR_TAG
+	 */
+
+	LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "entering IFDHGetCapabilities\n");
+
+	if (iLunCheck(Lun))
+		return IFD_COMMUNICATION_ERROR;
+
+	switch (Tag)
+	{
+		case TAG_IFD_ATR:
+			// If Length is not zero, powerICC has been performed.
+			// Otherwise, return NULL pointer
+			// Buffer size is stored in *Length
+			*Length = (*Length < pstIFDDescs[LunToReaderLun(Lun)]
+				[LunToSlotNb(Lun)].nATRLength) ?
+				*Length : pstIFDDescs[LunToReaderLun(Lun)]
+				[LunToSlotNb(Lun)].nATRLength;
+
+			if (*Length)
+				memcpy(Value, pstIFDDescs[LunToReaderLun(Lun)]
+					[LunToSlotNb(Lun)].pcATRBuffer, *Length);
+			break;
+
+		case TAG_IFD_SIMULTANEOUS_ACCESS:
+			if (*Length >= 1)
+			{
+				*Length =1;
+				*Value = PCSCLITE_MAX_CHANNELS;
+				break;
+			}
+
+		default:
+			return IFD_ERROR_TAG;
+	}
+	return IFD_SUCCESS;
+} /* IFDHGetCapabilities */
+
+
+RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag,
+	DWORD Length, PUCHAR Value)
+{
+	/*
+	 * This function should set the slot/card capabilities for a
+	 * particular slot/card specified by Lun.  Again, if you have only 1
+	 * card slot and don't mind loading a new driver for each reader then
+	 * ignore Lun.
+	 *
+	 * Tag - the tag for the information needing set
+	 *
+	 * Length - the length of the returned data Value - the value of the
+	 * data
+	 *
+	 * returns:
+	 *
+	 * IFD_SUCCESS IFD_ERROR_TAG IFD_ERROR_SET_FAILURE
+	 * IFD_ERROR_VALUE_READ_ONLY
+	 */
+
+	// By default, say it worked
+
+	LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, "entering IFDHSetCapabilities");
+
+	if (iLunCheck(Lun))
+		return IFD_COMMUNICATION_ERROR;
+
+	return IFD_SUCCESS;
+} /* IFDHSetCapabilities */
+
+
+RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol,
+	UCHAR Flags, UCHAR PTS1, UCHAR PTS2, UCHAR PTS3)
+{
+	/*
+	 * This function should set the PTS of a particular card/slot using
+	 * the three PTS parameters sent
+	 *
+	 * Protocol - 0 .... 14 T=0 .... T=14 Flags - Logical OR of possible
+	 * values: IFD_NEGOTIATE_PTS1 IFD_NEGOTIATE_PTS2 IFD_NEGOTIATE_PTS3 to
+	 * determine which PTS values to negotiate. PTS1,PTS2,PTS3 - PTS
+	 * Values.
+	 *
+	 * returns:
+	 *
+	 * IFD_SUCCESS IFD_ERROR_PTS_FAILURE IFD_COMMUNICATION_ERROR
+	 * IFD_PROTOCOL_NOT_SUPPORTED
+	 */
+
+	LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "entering IFDHSetProtocolParameters");
+
+	if (iLunCheck(Lun))
+		return IFD_COMMUNICATION_ERROR;
+
+	return IFD_SUCCESS;
+} /* IFDHSetProtocolParameters */
+
+
+RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action,
+	PUCHAR Atr, PDWORD AtrLength)
+{
+	/*
+	 * This function controls the power and reset signals of the smartcard
+	 * reader at the particular reader/slot specified by Lun.
+	 *
+	 * Action - Action to be taken on the card.
+	 *
+	 * IFD_POWER_UP - Power and reset the card if not done so (store the
+	 * ATR and return it and it's length).
+	 *
+	 * IFD_POWER_DOWN - Power down the card if not done already
+	 * (Atr/AtrLength should be zero'd)
+	 *
+	 * IFD_RESET - Perform a quick reset on the card.  If the card is not
+	 * powered power up the card.  (Store and return the Atr/Length)
+	 *
+	 * Atr - Answer to Reset of the card.  The driver is responsible for
+	 * caching this value in case IFDHGetCapabilities is called requesting
+	 * the ATR and it's length.  This should not exceed MAX_ATR_SIZE.
+	 *
+	 * AtrLength - Length of the Atr.  This should not exceed
+	 * MAX_ATR_SIZE.
+	 *
+	 * Notes:
+	 *
+	 * Memory cards without an ATR should return IFD_SUCCESS on reset but
+	 * the Atr should be zero'd and the length should be zero
+	 *
+	 * Reset errors should return zero for the AtrLength and return
+	 * IFD_ERROR_POWER_ACTION.
+	 *
+	 * returns:
+	 *
+	 * IFD_SUCCESS IFD_ERROR_POWER_ACTION IFD_COMMUNICATION_ERROR
+	 * IFD_NOT_SUPPORTED
+	 */
+
+    DWORD nlength;
+    CCIDRv rv;
+    BYTE bClockStatus;
+    BYTE pcbuffer[200];
+	LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "entering IFDHPowerICC");
+
+	// By default, assume it won't work :)
+	*AtrLength = 0;
+
+	if (iLunCheck(Lun))
+		return IFD_COMMUNICATION_ERROR;
+
+	switch (Action)
+	{
+		case IFD_POWER_UP:
+		case IFD_RESET:
+			nlength = sizeof(pcbuffer);
+			if ((rv = CCID_IccPowerOn(Lun, pcbuffer, &nlength)) != CCIDRv_OK)
+			{
+				LogMessage( __FILE__,  __LINE__, LogLevelCritical, "PowerUp failed");
+				return IFD_ERROR_POWER_ACTION;
+			}
+                
+			// Power up successful, set state variable to memorise it
+			pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				bPowerFlags |= MASK_POWERFLAGS_PUP;
+			pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				bPowerFlags &= ~MASK_POWERFLAGS_PDWN;
+
+			// Reset is returned, even if TCK is wrong
+			pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				nATRLength = *AtrLength =
+				(nlength < MAX_ATR_SIZE) ? nlength : MAX_ATR_SIZE;
+			memcpy(Atr, pcbuffer, *AtrLength);
+			memcpy(pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				pcATRBuffer, pcbuffer, *AtrLength);
+
+			break;
+
+		case IFD_POWER_DOWN:
+			// Clear ATR buffer
+			pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].nATRLength =
+				0;
+			*pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				pcATRBuffer = '\0';
+			// Memorise the request
+			pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].bPowerFlags
+				|= MASK_POWERFLAGS_PDWN;
+			// send the command
+			rv = CCID_IccPowerOff(Lun, &bClockStatus);
+            if (rv != CCIDRv_OK)
+            {
+                return IFD_ERROR_POWER_ACTION;
+            }
+            break;
+
+		default:
+			LogMessage( __FILE__,  __LINE__, LogLevelCritical, "IFDHPowerICC Action not supported");
+			return IFD_NOT_SUPPORTED;
+	}
+	return IFD_SUCCESS;
+} /* IFDHPowerICC */
+
+
+RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci,
+	PUCHAR TxBuffer, DWORD TxLength,
+	PUCHAR RxBuffer, PDWORD RxLength, PSCARD_IO_HEADER RecvPci)
+{
+	/*
+	 * This function performs an APDU exchange with the card/slot
+	 * specified by Lun.  The driver is responsible for performing any
+	 * protocol specific exchanges such as T=0/1 ... differences.  Calling
+	 * this function will abstract all protocol differences.
+	 *
+	 * SendPci Protocol - 0, 1, .... 14 Length - Not used.
+	 *
+	 * TxBuffer - Transmit APDU example (0x00 0xA4 0x00 0x00 0x02 0x3F
+	 * 0x00) TxLength - Length of this buffer. RxBuffer - Receive APDU
+	 * example (0x61 0x14) RxLength - Length of the received APDU.  This
+	 * function will be passed the size of the buffer of RxBuffer and this
+	 * function is responsible for setting this to the length of the
+	 * received APDU.  This should be ZERO on all errors.  The resource
+	 * manager will take responsibility of zeroing out any temporary APDU
+	 * buffers for security reasons.
+	 *
+	 * RecvPci Protocol - 0, 1, .... 14 Length - Not used.
+	 *
+	 * Notes: The driver is responsible for knowing what type of card it
+	 * has.  If the current slot/card contains a memory card then this
+	 * command should ignore the Protocol and use the MCT style commands
+	 * for support for these style cards and transmit them appropriately.
+	 * If your reader does not support memory cards or you don't want to
+	 * then ignore this.
+	 *
+	 * RxLength should be set to zero on error.
+	 *
+	 * returns:
+	 *
+	 * IFD_SUCCESS IFD_COMMUNICATION_ERROR IFD_RESPONSE_TIMEOUT
+	 * IFD_ICC_NOT_PRESENT IFD_PROTOCOL_NOT_SUPPORTED
+	 */
+
+	RESPONSECODE return_value = IFD_SUCCESS;	// Assume it will work
+    CCIDRv rv;
+
+	LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "entering IFDHTransmitToICC");
+	if (iLunCheck(Lun))
+		return IFD_COMMUNICATION_ERROR;
+
+	LogHexBuffer(__FILE__,  __LINE__, LogLevelVeryVerbose, TxBuffer, TxLength, "APDU sent: ");
+
+	switch (SendPci.Protocol)
+	{
+		case T_0:
+		case T_1:
+            rv = CCID_XfrBlock(Lun, 0, SendPci.Protocol, TxBuffer, TxLength,
+                               RxBuffer, RxLength);
+            if ( rv != CCIDRv_OK)
+            {
+                switch (rv)
+                {
+                    case CCIDRv_ERR_ICC_MUTE:
+                        return_value = IFD_RESPONSE_TIMEOUT;
+                        break;
+                    case CCIDRv_ERR_CARD_ABSENT:
+                        return_value = IFD_ICC_NOT_PRESENT;
+                        break;
+                    default:
+                        return_value = IFD_COMMUNICATION_ERROR;
+                }
+            }
+            
+			break;
+
+		default:
+			return_value = IFD_PROTOCOL_NOT_SUPPORTED;
+	}
+
+	if (return_value != CCIDRv_OK)
+		*RxLength = 0;
+
+	if (*RxLength)
+		LogHexBuffer(__FILE__,  __LINE__, LogLevelVeryVerbose, RxBuffer, *RxLength, "APDU response: ");
+
+	return return_value;
+
+} /* IFDHTransmitToICC */
+
+
+RESPONSECODE IFDHControl(DWORD Lun, PUCHAR TxBuffer,
+	DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength)
+{
+	/*
+	 * This function performs a data exchange with the reader (not the
+	 * card) specified by Lun.  Here XXXX will only be used. It is
+	 * responsible for abstracting functionality such as PIN pads,
+	 * biometrics, LCD panels, etc.  You should follow the MCT, CTBCS
+	 * specifications for a list of accepted commands to implement.
+	 *
+	 * TxBuffer - Transmit data TxLength - Length of this buffer. RxBuffer
+	 * - Receive data RxLength - Length of the received data.  This
+	 * function will be passed the length of the buffer RxBuffer and it
+	 * must set this to the length of the received data.
+	 *
+	 * Notes: RxLength should be zero on error.
+	 */
+
+	LogMessage( __FILE__,  __LINE__, LogLevelVerbose, "entering IFDHControl");
+
+	if (iLunCheck(Lun))
+		return IFD_COMMUNICATION_ERROR;
+
+	return IFD_SUCCESS;
+} /* IFDHControl */
+
+
+RESPONSECODE IFDHICCPresence(DWORD Lun)
+{
+	/*
+	 * This function returns the status of the card inserted in the
+	 * reader/slot specified by Lun.  It will return either:
+	 *
+	 * returns: IFD_ICC_PRESENT IFD_ICC_NOT_PRESENT
+	 * IFD_COMMUNICATION_ERROR
+	 */
+    BYTE bStatus, bClockStatus;
+    BYTE bICCStatus;
+    // Set log level to only critical
+    if ( !bLogPeriodic )
+    {
+        SetLogLevel((BYTE)LogLevelCritical);
+    }
+	LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, "entering IFDHICCPresence");
+
+	if (iLunCheck(Lun))
+    {
+        SetLogLevel((BYTE)iLogValue);
+		return IFD_COMMUNICATION_ERROR;
+    }
+	if (CCID_GetSlotStatus(Lun, &bStatus, &bClockStatus) != CCIDRv_OK)
+	{
+		LogMessage( __FILE__,  __LINE__, LogLevelCritical, "GCCmdCardStatus failed");
+        {
+            SetLogLevel((BYTE)iLogValue);
+            return IFD_COMMUNICATION_ERROR;
+        }
+	}
+    bICCStatus = CCIDGetICCStatus(bStatus);
+	if ( bICCStatus == CCID_ICC_STATUS_ABSENT )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, "Card absent");
+        // Clear ATR buffer
+        pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].nATRLength = 0;
+        *pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+            pcATRBuffer = '\0';
+        // Card removed, clear the flags
+        pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].bPowerFlags =
+            POWERFLAGS_RAZ;
+        SetLogLevel((BYTE)iLogValue);
+        return IFD_ICC_NOT_PRESENT;
+    }
+    else
+	{
+		// Card is present, but is it powered-up?
+		if (bICCStatus == CCID_ICC_STATUS_ACTIVE)
+		{
+			LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, "Card present and powered");
+			// Powered, so the ressource manager did not miss a quick
+			// removal/re-insertion
+            SetLogLevel((BYTE)iLogValue);
+			return IFD_ICC_PRESENT;
+		}
+		else
+		{
+			// Card present but not powered up
+			// Check if a power down has been requested
+			if (pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				bPowerFlags & MASK_POWERFLAGS_PDWN)
+			{
+				LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, "Card present not powered, power down requested");
+				// Powerdown requested, so situation is normal
+                SetLogLevel((BYTE)iLogValue);
+				return IFD_ICC_PRESENT;
+			}
+
+			// Card inserted, not powered on but power down has not been
+			// requested
+			// Has the card been powered up already?
+			if (pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				bPowerFlags & MASK_POWERFLAGS_PUP)
+			{
+				LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, "Card pull-out+re-insert detected CARD OUT SIMULATION");
+				// Power-up has been requested, but not power down and power is
+				// down.  This should happen only if the card has been pulled
+				// out and reinserted too quickly for the resource manager to
+				// realise. A card out event is therefore simulated. Clear ATR
+				// buffer
+				pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+					nATRLength = 0;
+				*pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+					pcATRBuffer = '\0';
+				// reset power flags
+				pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+					bPowerFlags = POWERFLAGS_RAZ;
+                SetLogLevel((BYTE)iLogValue);
+				return IFD_ICC_NOT_PRESENT;
+			}
+
+			LogMessage( __FILE__,  __LINE__, LogLevelVeryVerbose, "Card present, just inserted");
+			// If control gets here, the card is in, not powered on, with
+			// no power down request and no previous power up request
+			// it is therefore a card insertion event
+			pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				nATRLength = 0;
+			*pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				pcATRBuffer = '\0';
+			// reset power flags
+			pstIFDDescs[LunToReaderLun(Lun)][LunToSlotNb(Lun)].
+				bPowerFlags = POWERFLAGS_RAZ;
+            SetLogLevel((BYTE)iLogValue);
+			return IFD_ICC_PRESENT;
+		}
+	}
+} /* IFDHICCPresence */
+

Added: trunk/SmartCardServices/src/CCIDDriver/common/ifdhandler.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/ifdhandler.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/ifdhandler.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,140 @@
+/*****************************************************************
+/
+/ File   :   ifdhandler.h
+/ Author :   David Corcoran <corcoran at linuxnet.com>
+/ Date   :   June 15, 2000
+/ Purpose:   This provides reader specific low-level calls.
+/            See http://www.linuxnet.com for more information.
+/ License:   See file COPYING.BSD
+/
+/ $Id: ifdhandler.h,v 1.2 2004/08/16 17:50:35 stuartha Exp $
+/
+******************************************************************/
+
+#ifndef _ifd_handler_h_
+#define _ifd_handler_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif 
+  
+  /* List of data structures available to ifdhandler */
+  
+  typedef struct _DEVICE_CAPABILITIES {
+    
+    LPSTR Vendor_Name;          /* Tag 0x0100        */
+    LPSTR IFD_Type;		/* Tag 0x0101        */
+    DWORD IFD_Version;		/* Tag 0x0102        */
+    LPSTR IFD_Serial;		/* Tag 0x0103        */
+    DWORD IFD_Channel_ID;  	/* Tag 0x0110        */
+    
+    DWORD Asynch_Supported;	/* Tag 0x0120        */
+    DWORD Default_Clock;	/* Tag 0x0121        */
+    DWORD Max_Clock;		/* Tag 0x0122        */
+    DWORD Default_Data_Rate;	/* Tag 0x0123        */
+    DWORD Max_Data_Rate;	/* Tag 0x0124        */
+    DWORD Max_IFSD;		/* Tag 0x0125        */
+    DWORD Synch_Supported;	/* Tag 0x0126        */
+    DWORD Power_Mgmt;		/* Tag 0x0131        */
+    DWORD Card_Auth_Devices;	/* Tag 0x0140        */
+    DWORD User_Auth_Device;	/* Tag 0x0142        */
+    DWORD Mechanics_Supported;	/* Tag 0x0150        */
+    DWORD Vendor_Features;	/* Tag 0x0180 - 0x01F0   User Defined. */
+    
+  } DEVICE_CAPABILITIES, *PDEVICE_CAPABILITIES;
+  
+  typedef struct _ICC_STATE {
+    
+    UCHAR ICC_Presence;		/* Tag 0x0300        */
+    UCHAR ICC_Interface_Status;	/* Tag 0x0301        */
+    UCHAR ATR[MAX_ATR_SIZE];	/* Tag 0x0303        */
+    UCHAR ICC_Type;		/* Tag 0x0304        */
+    
+  } ICC_STATE, *PICC_STATE;
+  
+  typedef struct _PROTOCOL_OPTIONS {
+    
+    DWORD Protocol_Type;	/* Tag 0x0201        */
+    DWORD Current_Clock;	/* Tag 0x0202        */
+    DWORD Current_F;		/* Tag 0x0203        */
+    DWORD Current_D;		/* Tag 0x0204        */
+    DWORD Current_N;		/* Tag 0x0205        */
+    DWORD Current_W;		/* Tag 0x0206        */
+    DWORD Current_IFSC;		/* Tag 0x0207        */
+    DWORD Current_IFSD;		/* Tag 0x0208        */
+    DWORD Current_BWT;		/* Tag 0x0209        */
+    DWORD Current_CWT;		/* Tag 0x020A        */
+    DWORD Current_EBC;		/* Tag 0x020B        */
+  } PROTOCOL_OPTIONS, *PPROTOCOL_OPTIONS;
+  
+  typedef struct _SCARD_IO_HEADER {
+    DWORD Protocol;
+    DWORD Length;
+  } SCARD_IO_HEADER, *PSCARD_IO_HEADER;
+  
+  /* End of structure list */
+
+
+  
+  /* The list of tags should be alot more but
+     this is all I use in the meantime        */
+  
+#define TAG_IFD_ATR					0x0303
+#define TAG_IFD_SLOTNUM				0x0180
+#define TAG_IFD_SLOTS_NUMBER		0x0FAE
+#define TAG_IFD_SIMULTANEOUS_ACCESS	0x0FAF
+  
+  /* End of tag list                          */
+
+
+    
+  /* List of defines available to ifdhandler */
+  
+#define IFD_POWER_UP			500
+#define IFD_POWER_DOWN			501
+#define IFD_RESET			502
+  
+#define IFD_NEGOTIATE_PTS1		1
+#define IFD_NEGOTIATE_PTS2		2
+#define IFD_NEGOTIATE_PTS3              4
+
+#define	IFD_SUCCESS			0
+#define IFD_ERROR_TAG			600
+#define IFD_ERROR_SET_FAILURE		601
+#define IFD_ERROR_VALUE_READ_ONLY	602
+#define IFD_ERROR_PTS_FAILURE		605
+#define IFD_ERROR_NOT_SUPPORTED		606
+#define IFD_PROTOCOL_NOT_SUPPORTED	607
+#define IFD_ERROR_POWER_ACTION		608
+#define IFD_ERROR_SWALLOW		609
+#define IFD_ERROR_EJECT			610
+#define IFD_ERROR_CONFISCATE		611
+#define IFD_COMMUNICATION_ERROR		612
+#define IFD_RESPONSE_TIMEOUT		613
+#define IFD_NOT_SUPPORTED		614
+#define IFD_ICC_PRESENT			615
+#define IFD_ICC_NOT_PRESENT		616
+  
+  /* List of Defined Functions Available to IFD_Handler */
+  
+  RESPONSECODE IFDHCreateChannel ( DWORD, DWORD );
+  RESPONSECODE IFDHCloseChannel ( DWORD );
+  RESPONSECODE IFDHGetCapabilities ( DWORD, DWORD, PDWORD, 
+				     PUCHAR );
+  RESPONSECODE IFDHSetCapabilities ( DWORD, DWORD, DWORD, PUCHAR );
+  RESPONSECODE IFDHSetProtocolParameters ( DWORD, DWORD, UCHAR, 
+					   UCHAR, UCHAR, UCHAR );
+  RESPONSECODE IFDHPowerICC ( DWORD, DWORD, PUCHAR, PDWORD );
+  RESPONSECODE IFDHTransmitToICC ( DWORD, SCARD_IO_HEADER, PUCHAR, 
+				   DWORD, PUCHAR, PDWORD, 
+				   PSCARD_IO_HEADER );
+  RESPONSECODE IFDHControl ( DWORD, PUCHAR, DWORD, 
+			     PUCHAR, PDWORD );
+  RESPONSECODE IFDHICCPresence( DWORD );
+  
+#ifdef __cplusplus
+}
+#endif 
+
+#endif /* _ifd_hander_h_ */
+

Added: trunk/SmartCardServices/src/CCIDDriver/common/pcscdefines.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/pcscdefines.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/pcscdefines.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,38 @@
+/*****************************************************************
+/
+/ File   :   pcscdefines.h
+/ Author :   David Corcoran <corcoran at linuxnet.com>
+/ Date   :   June 15, 2000
+/ Purpose:   This provides PC/SC shared defines.
+/            See http://www.linuxnet.com for more information.
+/ License:   See file COPYING.BSD
+/
+/
+******************************************************************/
+
+#ifndef _pcscdefines_h_
+#define _pcscdefines_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif 
+
+
+  // do not use RESPONSECODE (long, 64 bits) when 32 bits are enough
+  typedef int ifd_t;
+
+  typedef enum {
+    STATUS_SUCCESS               = 0xFA,
+    STATUS_UNSUCCESSFUL          = 0xFB,
+    STATUS_COMM_ERROR            = 0xFC,
+    STATUS_DEVICE_PROTOCOL_ERROR = 0xFD
+  } status_t;
+
+  #define MAX_RESPONSE_SIZE  264
+  #define MAX_ATR_SIZE       33
+  #define PCSCLITE_MAX_CHANNELS           16      /* Maximum channels     */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _pcscdefines_h_ */

Added: trunk/SmartCardServices/src/CCIDDriver/common/tools.c
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/tools.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/tools.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,146 @@
+/*
+ *  tools.c
+ *  ifd-CCID
+ *
+ *  Created by JL on Mon Feb 10 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#include "tools.h"
+#include "global.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+LogLevel bGlobalLogLevel = LogLevelMaximum;
+BYTE bLogging =  1;
+LogType bGlobalLogType =  LogTypeStderr;	//LogTypeStderr;LogTypeSysLog
+
+// Logging tools
+void LogMessage(const char * pcFile, WORD wLine, BYTE bLogLevel, const char* pcFormat,...)
+{
+    va_list ap;
+    int rv;
+    char *pcLogMessage = NULL;
+    
+    // Do not log if log level > 0 and logging is disabled
+    if ( (!bLogging) &&  bGlobalLogLevel )
+    {
+        return;
+    }
+    if ( bGlobalLogLevel >= bLogLevel )
+    {
+
+        va_start(ap, pcFormat);
+        rv = vasprintf(&pcLogMessage, pcFormat, ap);
+        if ( rv == -1 )
+        {
+            pcLogMessage = "Could not allocate buffer for vasprintf";
+        }
+        va_end(ap);
+        
+        if ( bGlobalLogType == LogTypeSysLog)
+        {
+            syslog(LOG_INFO, "%s (%d): %s",  pcFile, (int)wLine, pcLogMessage);
+        }
+        else
+        {
+            fprintf(stderr, "%s (%d): %s\n",  pcFile, (int)wLine, pcLogMessage);
+        }
+        if ( rv != -1 )
+        {
+            free(pcLogMessage);
+        }
+    }
+}
+void LogHexBuffer(const char * pcFile, WORD wLine, BYTE bLogLevel,
+                  BYTE * pbData, WORD wLength, const char* pcFormat,...)
+{
+    WORD index;
+    va_list ap;
+    int rv, rvHex = -1;
+    char *pcLogMessage = NULL;
+    char *pcLogHexData = NULL;
+    char *pcLogHexCurrent;
+    
+    if ( (!bLogging) &&  bGlobalLogLevel )
+    {
+        return;
+    }
+    if ( bGlobalLogLevel >= bLogLevel )
+    {
+        va_start(ap, pcFormat);
+        rv = vasprintf(&pcLogMessage, pcFormat, ap);
+        if ( rv == -1 )
+        {
+            pcLogMessage = "Could not allocate buffer for vasprintf";
+            
+        }
+        else
+        {
+            // Allocate buffer string for printing of data
+            // Each byte is 3 chars (1 per nibble + space)
+            // Plus 1 for NULL byte
+            pcLogHexData = malloc(wLength * 3 * sizeof(char) + 1);
+            rvHex = 0;
+            if ( pcLogHexData == NULL )
+            {
+                rvHex = -1;
+                pcLogHexData = "Could not allocate buffer to print binary buffer";
+            }
+            else
+            {
+                pcLogHexCurrent = pcLogHexData;
+                for (index = 0; index < wLength; index++)
+                {
+                    sprintf(pcLogHexCurrent, "%02X ", pbData[index]);
+                    pcLogHexCurrent += 3 * sizeof(char);
+                }
+            }
+        }
+        va_end(ap);
+
+        if ( bGlobalLogType == LogTypeSysLog)
+        {
+            syslog(LOG_INFO, "%s (%d): %s : %s",  pcFile, (int)wLine, pcLogMessage,
+                   pcLogHexData);
+        }
+        else
+        {
+            fprintf(stderr, "%s (%d): %s : %s\n",  pcFile, (int)wLine, pcLogMessage,
+                    pcLogHexData);
+        }
+        if ( rv != -1 )
+        {
+            free(pcLogMessage);
+        }
+        if ( rvHex != -1 )
+        {
+            free(pcLogHexData);
+        }
+    }
+}
+
+void SetLogLevel(BYTE bLogLevel)
+{
+    bGlobalLogLevel = bLogLevel;
+}
+
+void SetLogType(LogType bLogtype)
+{
+    bGlobalLogType = bLogtype;
+}
+
+void StartLogging()
+{
+    bLogging =  1;
+}
+
+void StopLogging()
+{
+    bLogging =  0;
+}
+

Added: trunk/SmartCardServices/src/CCIDDriver/common/tools.h
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/common/tools.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/common/tools.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,58 @@
+/*
+ *  tools.h
+ *  ifd-CCID
+ *
+ *  Created by JL on Mon Feb 10 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#ifndef __TOOLS_H__
+#define __TOOLS_H__
+#include "wintypes.h"
+
+
+// Get the value of a key in a bundle according to its identifier
+// This function is not time-optimal if many keys are to be searched
+// on the same bundle (the bundle is re-opened and re-parsed at
+// every call
+const char* ParseInfoPlist(const char *bundleIdentifier, const char *keyName);
+
+
+DWORD CCIDToHostLong(DWORD dword);
+DWORD HostToCCIDLong(DWORD dword);
+WORD CCIDToHostWord(WORD word);
+WORD HostToCCIDWord(WORD word);
+
+#define LunToSlotNb(Lun)     ((WORD)((Lun) & 0x0000FFFF))
+#define LunToReaderLun(Lun)  ((WORD)((Lun) >> 16))
+
+typedef enum {
+    LogTypeSysLog = 0x00,
+    LogTypeStderr = 0x01
+} LogType;
+typedef enum {
+    LogLevelCritical    = 0x00,
+    LogLevelImportant   = 0x01,
+    LogLevelVerbose     = 0x02,
+    LogLevelVeryVerbose = 0x03,
+    LogLevelMaximum     = 0xFF    
+} LogLevel;
+
+
+// Logging tools
+// pcLine should be called as __FILE__
+// wLine should be called as __LINE__
+// LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Move failed, rv = %08X", rv);
+void LogMessage(const char * pcFile, WORD wLine, BYTE bLogLevel, const char* pcFormat,...);
+void LogHexBuffer(const char * pcFile, WORD wLine, BYTE bLogLevel,
+                  BYTE * pbData, WORD wLength, const char* pcFormat,...);
+
+void SetLogLevel(BYTE bLogLevel);
+void SetLogType(LogType bLogtype);
+// Logging is only stopped for log levels > 0
+void StartLogging();
+void StopLogging();
+
+#endif
\ No newline at end of file

Added: trunk/SmartCardServices/src/CCIDDriver/specific/MacOSX/tools_mosx.c
===================================================================
--- trunk/SmartCardServices/src/CCIDDriver/specific/MacOSX/tools_mosx.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CCIDDriver/specific/MacOSX/tools_mosx.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,88 @@
+/*
+ *  tools_mosx.c
+ *  ifd-CCID
+ *
+ *  Created by JL on Mon Feb 10 2003.
+ *  Copyright (c) 2003 Jean-Luc Giraud. All rights reserved.
+ *  See COPYING file for license.
+ *
+ */
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFURL.h>
+#include <CoreFoundation/CFPlugIn.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/usb/IOUSBLib.h>
+
+
+#include "tools.h"
+
+
+
+const char* ParseInfoPlist(const char *bundleIdentifier, const char *keyName)
+{
+    CFBundleRef myBundle;
+    CFStringRef propertyString;
+    CFDictionaryRef bundleInfoDict;
+    const char *cStringValue;
+    CFStringRef stringCF;
+    
+    stringCF = CFStringCreateWithCString ( NULL, bundleIdentifier, kCFStringEncodingASCII);
+    if (stringCF == NULL)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "bundleIdentiferCF error");
+        return NULL;
+    }
+    
+    
+    // Look for a bundle using its identifier
+    myBundle = CFBundleGetBundleWithIdentifier(stringCF);
+    if ( !myBundle )
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Bundle Identifier not found: %s", bundleIdentifier);
+        return NULL;
+    }
+    bundleInfoDict = CFBundleGetInfoDictionary(myBundle);
+    if (bundleInfoDict == NULL)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Bundle InfoDic error");
+        return NULL;
+    }
+
+    stringCF = CFStringCreateWithCString ( NULL, keyName, kCFStringEncodingASCII);
+    if (stringCF == NULL)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "keyName error");
+        return NULL;
+    }
+
+    propertyString = CFDictionaryGetValue(bundleInfoDict, stringCF);
+    CFRelease(stringCF);
+    if (propertyString == NULL)
+    {
+        LogMessage( __FILE__,  __LINE__, LogLevelCritical, "Bundle InfoDic error: %s not found", keyName);
+        return NULL;
+    }
+
+    cStringValue = CFStringGetCStringPtr(propertyString,
+                                         CFStringGetSystemEncoding());
+    return cStringValue;
+}
+
+
+DWORD CCIDToHostLong(DWORD dword)
+{
+    return (USBToHostLong((UInt32) dword));
+}
+DWORD HostToCCIDLong(DWORD dword)
+{
+    return (HostToUSBLong((UInt32) dword));
+}
+WORD CCIDToHostWord(WORD word)
+{
+    return (USBToHostWord((UInt16) word));
+}
+WORD HostToCCIDWord(WORD word)
+{
+    return (USBToHostWord((UInt16) word));
+}

Added: trunk/SmartCardServices/src/CFlexPlugin/cryptoflex.c
===================================================================
--- trunk/SmartCardServices/src/CFlexPlugin/cryptoflex.c	                        (rev 0)
+++ trunk/SmartCardServices/src/CFlexPlugin/cryptoflex.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,3040 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : cryptoflex.c
+            Package: Cryptoflex Plugin
+            Author : David Corcoran
+		     Piotr Gorak
+            Date   : 09/26/01
+            License: Copyright (C) 2001 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This abstracts the Card Edge Interface APDU's
+	             into client side function calls.
+ 
+********************************************************************/
+
+#ifdef WIN32
+#include "../win32/CFlexPlugin.h"
+#endif
+
+#ifndef __APPLE__
+#include <musclecard.h>
+#else
+#include <PCSC/musclecard.h>
+#endif
+
+#include "cryptoflex.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define CRYPTOFLEX_RSA_KEYSTART     -1
+#define CRYPTOFLEX_DES_KEYSTART     1
+#define CRYPTOFLEX_OBJ_DIR          0x3FCE
+#define CRYPTOFLEX_MSC_KEY_DIR      0x3FCF
+#define CRYPTOFLEX_INFOBJ_ID        "#FFFE"
+#define CRYPTOFLEX_INFOBJ_LEN       0x0080  /* 128 bytes */
+#define CRYPTOFLEX_MAXMSC_KEY_NUM   0x0005  /* 3 public, 3 private 0-5 */
+#define CRYPTOFLEX_MAX_KEYS         0x0006
+
+typedef struct {
+  MSCUChar8  pBuffer[MAX_BUFFER_SIZE];
+  MSCULong32 bufferSize;
+  MSCUChar8  apduResponse[MAX_BUFFER_SIZE];
+  MSCULong32 apduResponseSize;
+  LPSCARD_IO_REQUEST ioType;
+} MSCTransmitBuffer, *MSCLPTransmitBuffer;
+
+
+static MSCUChar8 keyInfoBytes[CRYPTOFLEX_INFOBJ_LEN];
+static int suppressResponse = 0;
+
+/* Some local function definitions */
+
+MSC_RV convertPCSC( MSCLong32 );
+int idToString( MSCString, MSCULong32 );
+int stringToID( MSCPUShort16, MSCString );
+int bytesToString( MSCString, MSCPUChar8 );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCSelect(MSCLPTokenConnection, MSCULong32 );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCGetResponse(MSCLPTokenConnection, MSCUChar8, MSCPUChar8 );
+MSCUShort16 convertSW( MSCPUChar8 );
+void MemCopy16( MSCPUChar8, MSCPUShort16 );
+void MemCopy32( MSCPUChar8, MSCPULong32 );
+void MemCopyTo16( MSCPUShort16, MSCPUChar8 );
+void MemCopyTo32( MSCPULong32, MSCPUChar8 );
+MSCUShort16 getUShort16( MSCPUChar8 );
+void setUShort16( MSCPUChar8, MSCUShort16 );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSCLong32 SCardExchangeAPDU( MSCLPTokenConnection, MSCLPTransmitBuffer );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCReadAllocateObject( MSCLPTokenConnection, MSCString, 
+				 MSCPUChar8*, MSCPULong32 );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCReadLargeObjectOffCB( MSCLPTokenConnection, 
+				   MSCString, MSCULong32, 
+				   MSCPUChar8, MSCULong32,
+				   LPRWEventCallback rwCallback, 
+				   MSCPVoid32 addParams );
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteLargeObjectOffCB( MSCLPTokenConnection, 
+				    MSCString,  MSCULong32, MSCPUChar8, 
+				    MSCULong32, LPRWEventCallback rwCallback, 
+				    MSCPVoid32 addParams );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCListKeys( MSCLPTokenConnection, MSCUChar8, MSCLPKeyInfo);
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteObject( MSCLPTokenConnection, MSCString, 
+			  MSCULong32, MSCPUChar8, MSCUChar8 );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCReadObject( MSCLPTokenConnection, MSCString, 
+			 MSCULong32, MSCPUChar8, MSCUChar8 );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCListObjects( MSCLPTokenConnection, 
+			  MSCUChar8, MSCLPObjectInfo );
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCIdentifyToken( MSCLPTokenConnection );
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV mapCryptoflexKeys(MSCLPTokenConnection pConnection, MSCUChar8 keyType,
+			 MSCUShort16 keySize, MSCUChar8 mscKeyNum,
+			 MSCPUChar8 cflKeyNum);
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCCreateObject( MSCLPTokenConnection, 
+			   MSCString, MSCULong32,
+			   MSCLPObjectACL );
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCDeleteObject( MSCLPTokenConnection, 
+			   MSCString, MSCUChar8 );
+
+MSC_RV mapCryptoflexKeys(MSCLPTokenConnection pConnection, MSCUChar8 keyType,
+			 MSCUShort16 keySize, MSCUChar8 mscKeyNum,
+			 MSCPUChar8 cflKeyNum) {
+
+  MSCLong32 rv;
+  MSCKeyInfo keyStruct;
+  MSCUChar8 targetCFNum;
+  char highestKey;
+  int i;
+  
+  typedef struct {
+    MSCUChar8 keyNumCF;
+    MSCUChar8 keyType;
+  } _keyMask;
+
+  _keyMask keyMask[MSC_MAX_KEYS];
+
+  targetCFNum = 0xFF; 
+
+  if ( keyType == MSC_KEY_DES || keyType == MSC_KEY_3DES || 
+       keyType == MSC_KEY_3DES3 ) {
+    highestKey = CRYPTOFLEX_DES_KEYSTART;  /* Des keys start from 2 */
+  } else if ( keyType == MSC_KEY_RSA_PUBLIC || 
+	      keyType == MSC_KEY_RSA_PRIVATE ||
+	      keyType == MSC_KEY_RSA_PRIVATE_CRT ) {
+    highestKey = CRYPTOFLEX_RSA_KEYSTART;  /* RSA keys start from 0 */
+  } else {
+    return MSC_INVALID_PARAMETER;
+  }
+
+
+  for (i=0; i < MSC_MAX_KEYS; i++) {
+    keyMask[i].keyNumCF = 0xFF;
+    keyMask[i].keyType  = 0xFF;
+  }
+
+
+  /* Algorithm:
+
+     List keys 
+
+     If a match on numbers occurs:
+
+     Errors:  
+     - If they key type/size doesn't match the existing key.
+
+     Otherwise:
+
+     - Find the next available spot and generate the keys
+  */
+
+  rv = PL_MSCListKeys(pConnection, MSC_SEQUENCE_RESET, &keyStruct);
+
+  if ( rv != MSC_SEQUENCE_END ) {
+    
+    do {
+      
+      if ( keyStruct.keyNum == mscKeyNum ) {
+	
+	if ( targetCFNum != 0xFF ) {
+	  /* 2 keys with the same number, ouch */
+	  return MSC_INTERNAL_ERROR;
+	}
+	
+	if ( keyStruct.keyType == keyType &&
+	     keyStruct.keySize == keySize ) {
+	  targetCFNum = keyStruct.keyPartner;
+	} else {
+	  return MSC_INVALID_PARAMETER;
+	}
+      }
+      
+      /* Caching - indice in mask is MSC key num, keyNumCF is
+	 the cryptoflex key number, and type is the key type */
+      
+      keyMask[keyStruct.keyNum].keyNumCF = keyStruct.keyPartner;
+      keyMask[keyStruct.keyNum].keyType  = keyStruct.keyType;
+      
+      rv = PL_MSCListKeys(pConnection, MSC_SEQUENCE_NEXT, &keyStruct);
+    } while ( rv != MSC_SEQUENCE_END );
+  }
+
+  if (targetCFNum != 0xFF) {
+    /* matching key num, type, and size - regenerate */
+    *cflKeyNum = targetCFNum;
+    return MSC_SUCCESS;
+  } else {
+    /* No matching number - lets find one for that type of key */
+
+    for (i=0; i < MSC_MAX_KEYS; i++) {
+      if ( keyMask[i].keyType == keyType ) {
+	if ( keyMask[i].keyNumCF > highestKey ) {
+	  highestKey = keyMask[i].keyNumCF;
+	}
+      }
+    }
+
+    /* Only support one more DES key, for now */
+    
+    if (keyType == MSC_KEY_DES || keyType == MSC_KEY_3DES || 
+	keyType == MSC_KEY_3DES3) {
+      if  (highestKey != CRYPTOFLEX_DES_KEYSTART) {
+	return MSC_UNSUPPORTED_FEATURE;
+      }
+    }
+    
+    *cflKeyNum = highestKey + 1;
+    return MSC_SUCCESS;
+  }
+
+  return MSC_INVALID_PARAMETER;
+}
+
+
+void MemCopyReverse(unsigned char *output, unsigned char *input, int length) {
+
+  int i, j;
+
+  j=0;
+
+  for (i=length-1; i >=0; i--) {
+    output[j++] = input[i];
+  }
+
+}
+
+/* Private helpers */
+
+unsigned char ACL2Byte(MSCLPObjectACL pObjectACL)
+{
+
+  unsigned char retByte;
+
+  retByte = 0x00;
+
+  if ( pObjectACL->readPermission == MSC_AUT_ALL ) {
+    retByte = 0x00;
+  } else if ( pObjectACL->readPermission == MSC_AUT_NONE ) {
+    retByte |= 0xF0;
+  }
+
+  if ( pObjectACL->writePermission == MSC_AUT_ALL ) {
+    retByte |= 0x00;
+  } else if (  pObjectACL->writePermission == MSC_AUT_NONE ) {
+    retByte |= 0x0F;
+  }
+
+  /* Check for CHV 1 */
+  if ( pObjectACL->readPermission & MSC_AUT_PIN_1 ) {
+    retByte |= 0x10;
+  }
+
+  if ( pObjectACL->writePermission & MSC_AUT_PIN_1 ) {
+    retByte |= 0x01;
+  }
+
+  /* Check for AUT */
+  if ( pObjectACL->readPermission & MSC_AUT_PIN_0 ) {
+    retByte |= 0x40;
+  }
+
+  if ( pObjectACL->writePermission & MSC_AUT_PIN_0 ) {
+    retByte |= 0x04;
+  }
+
+  return retByte;
+}
+
+void Byte2ACL(unsigned char inByte, MSCLPObjectACL pObjectACL)
+{
+
+  pObjectACL->readPermission   = 0;
+  pObjectACL->writePermission  = 0;
+  pObjectACL->deletePermission = 0;  
+
+  if ( (inByte/256) == 0x00 ) {
+    pObjectACL->readPermission = MSC_AUT_ALL;
+  } else if ((inByte/256) == 0xF ) {
+    pObjectACL->readPermission = MSC_AUT_NONE;
+  }
+
+  if ( (inByte%256) == 0x00 ) {
+    pObjectACL->writePermission = MSC_AUT_ALL;
+  } else if ((inByte%256) == 0xF ) {
+    pObjectACL->writePermission = MSC_AUT_NONE;
+  }
+
+  /* Check for CHV 1 */
+  if ( inByte & 0x10 ) {
+    pObjectACL->readPermission |= MSC_AUT_PIN_1;
+  }
+
+  if ( inByte & 0x01 ) {
+    pObjectACL->writePermission |= MSC_AUT_PIN_1;
+  }
+
+  /* Check for AUT */
+  if ( inByte & 0x40 ) {
+    pObjectACL->readPermission |= MSC_AUT_PIN_0;
+  }
+
+  if ( inByte & 0x04 ) {
+    pObjectACL->writePermission |= MSC_AUT_PIN_0;
+  }
+
+  /* Delete permission is static */
+  pObjectACL->deletePermission = MSC_AUT_PIN_1;
+
+}
+
+
+
+MSC_RV PL_MSCReadKeyInfo( MSCLPTokenConnection pConnection, 
+			  MSCLPKeyInfo keyInfo ) {
+  MSCLong32 rv;
+  MSCUChar8 currentPointer;
+
+  /* Read the whole file and cache it until it is reset */
+  /* Must do this for performance reasons               */
+
+  if ( keyInfo == 0 ) {
+    rv = PL_MSCReadObject(pConnection, CRYPTOFLEX_INFOBJ_ID, 
+			  0, keyInfoBytes, 
+			  MSC_SIZEOF_KEYINFO*CRYPTOFLEX_MAX_KEYS);
+    return rv;
+  }
+
+
+  currentPointer = MSC_SIZEOF_KEYINFO * keyInfo->keyNum;
+
+  keyInfo->keyNum  = keyInfoBytes[currentPointer];
+  currentPointer += MSC_SIZEOF_KEYNUMBER;
+  keyInfo->keyType = keyInfoBytes[currentPointer];
+  currentPointer += MSC_SIZEOF_KEYTYPE;
+  keyInfo->keyPartner = keyInfoBytes[currentPointer];
+  currentPointer += MSC_SIZEOF_KEYPARTNER;
+  keyInfo->keyMapping = keyInfoBytes[currentPointer];
+  currentPointer += MSC_SIZEOF_KEYMAPPING;
+  MemCopyTo16(&keyInfo->keySize, &keyInfoBytes[currentPointer]);
+  currentPointer += MSC_SIZEOF_KEYSIZE;
+  
+  /* copy the policy */
+
+  MemCopyTo16(&keyInfo->keyPolicy.cipherMode, 
+	      &keyInfoBytes[currentPointer]);
+  currentPointer += MSC_SIZEOF_POLICYVALUE;
+  MemCopyTo16(&keyInfo->keyPolicy.cipherDirection, 
+	      &keyInfoBytes[currentPointer]);
+  currentPointer += MSC_SIZEOF_POLICYVALUE;
+
+  /* copy the ACL */
+
+  MemCopyTo16(&keyInfo->keyACL.readPermission, &keyInfoBytes[currentPointer]);
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+  MemCopyTo16(&keyInfo->keyACL.writePermission, &keyInfoBytes[currentPointer]);
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+  MemCopyTo16(&keyInfo->keyACL.usePermission, &keyInfoBytes[currentPointer]);
+  currentPointer += MSC_SIZEOF_ACLVALUE;  
+
+  return MSC_SUCCESS;
+}
+
+
+MSC_RV PL_MSCWriteKeyInfo( MSCLPTokenConnection pConnection, MSCUChar8 keyNum, 
+			   MSCUChar8 keyType, MSCUChar8 keyPartner,
+			   MSCUChar8 keyMapping, MSCUShort16 keySize,
+			   MSCLPKeyPolicy keyPolicy, MSCLPKeyACL keyACL ) {
+
+  MSCLong32 rv;
+
+  MSCUChar8 keyInfoBytes[MSC_SIZEOF_KEYINFO];
+  MSCUChar8 currentPointer;
+
+  currentPointer = 0;
+  keyInfoBytes[currentPointer] = keyNum;
+  currentPointer += MSC_SIZEOF_KEYNUMBER;
+  keyInfoBytes[currentPointer] = keyType;
+  currentPointer += MSC_SIZEOF_KEYTYPE;
+  keyInfoBytes[currentPointer] = keyPartner;
+  currentPointer += MSC_SIZEOF_KEYPARTNER;
+  keyInfoBytes[currentPointer] = keyMapping;
+  currentPointer += MSC_SIZEOF_KEYMAPPING;
+  MemCopy16(&keyInfoBytes[currentPointer], &keySize);
+  currentPointer += MSC_SIZEOF_KEYSIZE;
+  
+  /* copy the policy */
+  
+  MemCopy16(&keyInfoBytes[currentPointer], &keyPolicy->cipherMode);
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+  MemCopy16(&keyInfoBytes[currentPointer], &keyPolicy->cipherDirection);
+  currentPointer += MSC_SIZEOF_ACLVALUE;  
+
+  /* copy the acl */
+
+  MemCopy16(&keyInfoBytes[currentPointer], &keyACL->readPermission);
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+  MemCopy16(&keyInfoBytes[currentPointer], &keyACL->writePermission);
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+  MemCopy16(&keyInfoBytes[currentPointer], &keyACL->usePermission);
+  currentPointer += MSC_SIZEOF_ACLVALUE;  
+
+  rv = PL_MSCWriteObject(pConnection, CRYPTOFLEX_INFOBJ_ID, 
+			 MSC_SIZEOF_KEYINFO*keyNum, 
+			 keyInfoBytes, MSC_SIZEOF_KEYINFO);
+  return rv;
+}
+
+
+MSC_RV PL_MSCVerifyKey(MSCLPTokenConnection pConnection,
+                    MSCPUChar8 key, MSCUChar8 key_length) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+
+  pBuffer      = transmitBuffer.pBuffer;
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA] = CLA_F0;
+  pBuffer[OFFSET_INS] = 0x2A;
+  pBuffer[OFFSET_P1]  = 0x00;
+  pBuffer[OFFSET_P2]  = 0x01;
+  pBuffer[OFFSET_P3]  = key_length;
+
+  memcpy(&pBuffer[OFFSET_DATA], key, key_length);
+  transmitBuffer.bufferSize = pBuffer[OFFSET_P3] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+
+  if(rv != SCARD_S_SUCCESS) {
+    return convertPCSC(rv);
+  }
+
+  if(transmitBuffer.apduResponseSize == 2) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteFramework( MSCLPTokenConnection pConnection,
+			  MSCLPInitTokenParams pInitParams ) {
+
+  MSCLong32 rv;
+  MSCULong32 rCV;
+  MSCUChar8 rx[200];
+
+  MSCUChar8 deleteObjDir[7]   = {0xF0, 0xE4, 0x00, 0x00, 0x02, 0x3F, 0xCE};
+  MSCUChar8 deleteInfFile[7]  = {0xF0, 0xE4, 0x00, 0x00, 0x02, 0xFF, 0xFE};
+  MSCUChar8 deleteKeyDir[7]   = {0xF0, 0xE4, 0x00, 0x00, 0x02, 0x3F, 0xCF};
+  MSCUChar8 deletePubFile[7]  = {0xF0, 0xE4, 0x00, 0x00, 0x02, 0x10, 0x12};
+  MSCUChar8 deletePrvFile[7]  = {0xF0, 0xE4, 0x00, 0x00, 0x02, 0x00, 0x12};
+  MSCUChar8 deletePinFile[7]  = {0xF0, 0xE4, 0x00, 0x00, 0x02, 0x00, 0x00};
+
+  MSCUChar8 verifyKey[13]     = {0xF0, 0x2A, 0x00, 0x01, 0x08, 0x2C, 0x15, 
+				 0xE5, 0x26, 0xE9, 0x3E, 0x8A, 0x19};
+  
+  MSCUChar8 createObjDir[21]  = {0xF0, 0xE0, 0x00, 0x00, 0x10, 0xFF, 0xFF, 
+				 0x61, 0xA8, 0x3F, 0xCE, 0x38, 0x00, 0x00, 
+				 0x10, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00};
+
+  MSCUChar8 createInfFile[21] = {0xF0, 0xE0, 0x00, 0x01, 0x10, 0xFF, 0xFF, 
+				 0x00, 0x80, 0xFF, 0xFE, 0x01, 0x00, 0x01,
+				 0x44, 0x44, 0x01, 0x03, 0x00, 0x00, 0x00};
+  
+  MSCUChar8 createKeyDir[21]  = {0xF0, 0xE0, 0x00, 0x00, 0x10, 0xFF, 0xFF, 
+				 0x05, 0x50, 0x3F, 0xCF, 0x38, 0x00, 0x00, 
+				 0x44, 0x00, 0x01, 0x03, 0x00, 0x11, 0x00};
+  
+  /* Note: the Write Binary 8 LSB should be changed for AUT0 */
+  
+  MSCUChar8 createPrivFile[21] = {0xF0, 0xE0, 0x00, 0x01, 0x10, 0xFF, 0xFF, 
+				  0x02, 0x98, 0x00, 0x12, 0x01, 0x00, 0xF1, 
+				  0xFF, 0x11, 0x01, 0x03, 0x00, 0x00, 0x00};
+  
+  MSCUChar8 createPubFile[21] = { 0xF0, 0xE0, 0x00, 0x01, 0x10, 0xF1, 0xFF, 
+				  0x02, 0x98, 0x10, 0x12, 0x01, 0x00, 0x01, 
+				  0xFF, 0x44, 0x01, 0x03, 0x00, 0x00, 0x00};
+
+  MSCUChar8 createPinFile[21] = { 0xF0, 0xE0, 0x00, 0x01, 0x10, 0xFF, 0xFF, 
+				  0x00, 0x17, 0x00, 0x00, 0x01, 0x00, 0xF0,
+				  0xFF, 0x44, 0x01, 0x03, 0x00, 0x00, 0x00};
+  
+  MSCUChar8 writeDefaultPin[28] = { 0xC0, 0xD6, 0x00, 0x00, 0x17, 0xFF, 0xFF, 
+				    0xFF, 'M', 'u', 's', 'c', 'l', 'e', 
+				    '0', '0', 0x05, 0x05, 'M', 'u', 's', 'c', 
+				    'l', 'e', '0', '1', 0x05, 0x05};
+
+  MSCUChar8 writeDefaultAAK[17] = { 0xC0, 0xD6, 0x00, 0x0D, 0x0C, 0x08, 0x00,
+				    'M', 'u', 's', 'c', 'l', 'e', '0', '0',
+				    0x0A, 0x0A };
+  
+  /* FIX :: Add support for alternative transport keys */
+
+  if ( pInitParams->transportBehavior == MSC_INIT_DEFAULT_KEY ) {
+    /* Do nothing */
+  } else if ( pInitParams->transportBehavior == MSC_INIT_IGNORE_KEY ) {
+    /* Do nothing */
+  } else if ( pInitParams->transportBehavior == MSC_INIT_USE_KEY ) {
+    if ( pInitParams->transportKeyLen != 8 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+    memcpy(&verifyKey[5], pInitParams->transportKey, 8);
+  }
+    
+  if ( pInitParams->objectMemory == 0 ) {
+    pInitParams->objectMemory = 8500;
+  } 
+  
+  if (pInitParams->newTransportKeyLen == 8) {
+    memcpy(&writeDefaultAAK[7], pInitParams->newTransportKey, 8);
+  }
+
+  if (pInitParams->defaultCHVTries != 0) {
+    writeDefaultPin[16] = pInitParams->defaultCHVTries;
+    writeDefaultPin[17] = pInitParams->defaultCHVTries;
+  }
+
+  if (pInitParams->defaultCHVUnblockTries != 0) {
+    writeDefaultPin[26] = pInitParams->defaultCHVUnblockTries;
+    writeDefaultPin[27] = pInitParams->defaultCHVUnblockTries;
+  }
+
+  if (pInitParams->defaultCHVLen == 8) {
+    memcpy(&writeDefaultPin[8], pInitParams->defaultCHV, 8);
+  }
+
+  if (pInitParams->defaultCHVUnblockSize == 8) {
+    memcpy(&writeDefaultPin[18], pInitParams->defaultCHVUnblock, 8);
+  }
+
+  createObjDir[7] = pInitParams->objectMemory / 256;
+  createObjDir[8] = pInitParams->objectMemory % 256;
+  
+  if ( pInitParams->transportBehavior != MSC_INIT_IGNORE_KEY ) {
+    rv = PL_MSCSelect(pConnection, 0x3F00);
+    if ( rv != MSC_SUCCESS ) return rv;
+    
+    rCV = 100;
+    rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		       verifyKey, 13, 0, rx, &rCV); 
+    if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+    if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+  }
+  
+  /*************************************/
+  /* Delete this file structure off of */
+  /* the card if it already exists     */
+  /*************************************/
+  
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, 0x3FCE);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     deleteInfFile, 7, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, 0x3FCF);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     deletePrvFile, 7, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     deletePinFile, 7, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, 0x3FCF);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     deletePubFile, 7, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     deleteKeyDir, 7, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     deleteObjDir, 7, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+
+
+ /*************************************/
+ /* Add the new file structure        */
+ /*************************************/
+
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     createObjDir, 21, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+  if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, 0x3FCE);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     createInfFile, 21, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+  if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);  
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     createKeyDir, 21, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+  if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, 0x3FCF);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     createPubFile, 21, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+  if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, 0x3FCF);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     createPrivFile, 21, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+  if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     createPinFile, 21, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+  if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, 0x0000);
+
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     writeDefaultPin, 28, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+  if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+
+/*************************************************************************/
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, 0x0011);
+  
+  rCV = 100;
+  rv = SCardTransmit(pConnection->hCard, SCARD_PCI_T0, 
+		     writeDefaultAAK, 17, 0, rx, &rCV); 
+  if ( rv != SCARD_S_SUCCESS ) return convertPCSC(rv);
+  if ( convertSW(rx) != MSC_SUCCESS ) return convertSW(rx);
+
+  return MSC_SUCCESS;
+}
+
+/* MSC Functions */
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCGetStatus( MSCLPTokenConnection pConnection, 
+		     MSCLPStatusInfo pStatusInfo ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+  MSCObjectInfo objInfo;
+  MSCULong32 totalMemory, freeMemory;
+
+  PL_MSCSelect(pConnection, 0x3F00);
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_C0;
+  pBuffer[OFFSET_INS]    = 0xA4;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_P3]     = 0x02;
+  pBuffer[OFFSET_DATA]   = 0x3F;
+  pBuffer[OFFSET_DATA+1] = 0xCE;
+ 
+  transmitBuffer.bufferSize = 7;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  }
+
+  
+  freeMemory  = apduResponse[2] * 0x100 + apduResponse[3];
+  totalMemory = freeMemory;
+
+  pStatusInfo->appVersion  = 0xFF;
+  pStatusInfo->swVersion   = 0xFF;
+  pStatusInfo->usedPINs    = 0x01;
+  pStatusInfo->usedKeys    = 0x00;
+  pStatusInfo->loggedID    = pConnection->loggedIDs;
+
+  rv = PL_MSCListObjects( pConnection, MSC_SEQUENCE_RESET, &objInfo );
+
+  while (rv == MSC_SUCCESS) {
+    totalMemory += objInfo.objectSize;
+    rv = PL_MSCListObjects( pConnection, MSC_SEQUENCE_NEXT, &objInfo );
+  }
+
+  pStatusInfo->totalMemory = totalMemory;
+  pStatusInfo->freeMemory  = freeMemory - CRYPTOFLEX_INFOBJ_LEN - 16;
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCGetCapabilities( MSCLPTokenConnection pConnection, MSCULong32 Tag,
+			   MSCPUChar8 Value, MSCPULong32 Length ) {
+
+  MSCULong32  ulValue;
+  MSCUShort16 usValue;
+  MSCUChar8  ucValue;
+  MSCUChar8  tagType;
+
+  /* 4 - MSCULong32, 2 - MSCUShort16, 1 - MSCUChar8 */
+
+  ulValue = 0; usValue = 0; ucValue = 0; tagType = 0;
+
+  switch(Tag) {
+
+  case MSC_TAG_SUPPORT_FUNCTIONS:
+    ulValue = MSC_SUPPORT_GENKEYS | MSC_SUPPORT_EXPORTKEY | 
+      MSC_SUPPORT_COMPUTECRYPT | MSC_SUPPORT_LISTKEYS | MSC_SUPPORT_IMPORTKEY |
+      MSC_SUPPORT_VERIFYPIN | MSC_SUPPORT_CHANGEPIN | 
+      MSC_SUPPORT_UNBLOCKPIN | MSC_SUPPORT_LISTPINS |
+      MSC_SUPPORT_CREATEOBJECT | MSC_SUPPORT_DELETEOBJECT | 
+      MSC_SUPPORT_WRITEOBJECT | MSC_SUPPORT_READOBJECT |
+      MSC_SUPPORT_LISTOBJECTS | MSC_SUPPORT_LOGOUTALL |
+      MSC_SUPPORT_GETCHALLENGE;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_SUPPORT_CRYPTOALG:
+    ulValue = MSC_SUPPORT_RSA;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_RSA:
+    ulValue = MSC_CAPABLE_RSA_1024 | MSC_CAPABLE_RSA_NOPAD | 
+              MSC_CAPABLE_RSA_KEYGEN;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_ATTR:
+    ulValue = 0;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_IDSIZE:
+    ucValue = 2;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_AUTH:
+    usValue = MSC_AUT_ALL;
+    tagType = 2;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_MAXNUM:
+    ulValue = 100;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_ATTR:
+    ulValue = MSC_CAPABLE_PIN_RESET;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MAXNUM:
+    ucValue = 2;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MINSIZE:
+    ucValue = 1;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MAXSIZE:
+    ucValue = 8;
+    tagType = 1;
+    break;
+    
+  case MSC_TAG_CAPABLE_PIN_CHARSET:
+    ulValue = MSC_CAPABLE_PIN_A_Z | MSC_CAPABLE_PIN_a_z | 
+      MSC_CAPABLE_PIN_0_9 | MSC_CAPABLE_PIN_CALC | MSC_CAPABLE_PIN_NONALPHA;
+    tagType = 4;
+    break;
+
+ case MSC_TAG_CAPABLE_PIN_POLICY:
+   ulValue = 0;
+   tagType = 4;
+   break;
+
+  case MSC_TAG_CAPABLE_ID_STATE:
+    ucValue = 0;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_RANDOM_MAX:
+    ucValue = 32;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_RANDOM_MIN:
+    ucValue = 8;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_KEY_AUTH:
+    usValue = MSC_AUT_PIN_1;
+    tagType = 2;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_AUTH:
+    usValue = MSC_AUT_NONE;
+    tagType = 2;
+    break;
+
+  default:
+    return MSC_INVALID_PARAMETER;
+  }
+
+  switch(tagType) {
+  case 1:
+    memcpy(Value, &ucValue, 1);
+    break;
+  case 2:
+    memcpy(Value, &usValue, 2);
+    break;
+  case 4:
+    memcpy(Value, &ulValue, 4);
+    break;
+  }
+
+  *Length = tagType;
+
+  return MSC_SUCCESS;
+
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCExtendedFeature( MSCLPTokenConnection pConnection, 
+			   MSCULong32 extFeature, MSCPUChar8 outData, 
+			   MSCULong32 outLength, MSCPUChar8 inData,
+			   MSCPULong32 inLength ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCGenerateKeys( MSCLPTokenConnection pConnection, 
+			   MSCUChar8 prvKeyNum, MSCUChar8 pubKeyNum, 
+			   MSCLPGenKeyParams pParams ) {
+  
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCUChar8 pubKeyNumBak;
+  MSCUChar8 prvKeyNumBak;
+  MSCKeyACL privACL;
+  MSCKeyACL pubACL;
+  MSCPUChar8 pBuffer;
+
+  /* PG: a common key pair number can only be set in Cryptoflex,
+     so enforce that pubKeyNum and prvKeyNum match. */
+
+  /* DC: Musclecard has each key number as a unique number but
+     keys should be in sequence - priv 0, pub 1 ... 
+     Here we will set the pubKeyNum to be the same as the 
+     private key number, but public keys will be one + the
+     private key number
+  */
+
+  if ( pubKeyNum > CRYPTOFLEX_MAXMSC_KEY_NUM ||
+       prvKeyNum > CRYPTOFLEX_MAXMSC_KEY_NUM ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  if ( pParams->algoType != MSC_GEN_ALG_RSA_CRT ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  prvKeyNumBak = prvKeyNum;
+  pubKeyNumBak = pubKeyNum;
+
+  rv = mapCryptoflexKeys(pConnection, MSC_KEY_RSA_PRIVATE_CRT,
+			 pParams->keySize, prvKeyNumBak,
+			 &prvKeyNum);
+  
+  if ( rv != MSC_SUCCESS ) return rv;
+
+  rv = mapCryptoflexKeys(pConnection, MSC_KEY_RSA_PUBLIC,
+			 pParams->keySize, pubKeyNumBak,
+			 &pubKeyNum);
+
+  if ( rv != MSC_SUCCESS ) return rv;
+
+  rv = PL_MSCSelect(pConnection, 0x3F00);
+  rv = PL_MSCSelect(pConnection, 0x3FCF);
+
+  if ( rv != MSC_SUCCESS ) {
+    return MSC_UNSUPPORTED_FEATURE;
+  }
+
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_F0;
+  pBuffer[OFFSET_INS]    = INS_MSC_GEN_KEYPAIR;
+  pBuffer[OFFSET_P1]     = prvKeyNum;
+
+  switch(pParams->keySize) {
+  case 1024:
+    pBuffer[OFFSET_P2] = 0x80;
+    break;
+  case 768:
+    pBuffer[OFFSET_P2] = 0x60;
+    break;
+  case 512:
+    pBuffer[OFFSET_P2] = 0x40;
+    break;
+  default:
+    return MSC_INVALID_PARAMETER;
+  }
+
+  /* PG: length of the public exponent, e */
+  
+  if ( pParams->keyGenOptions != MSC_OPT_DEFAULT ) {
+    pBuffer[OFFSET_P3] = pParams->keyGenOptions;
+    /* PG: the public exponent value */
+    memcpy(&pBuffer[OFFSET_DATA], pParams->pOptParams, 
+	   pParams->optParamsSize);
+    
+    transmitBuffer.bufferSize = 5 + pParams->keyGenOptions;
+    
+  } else {
+    /* Take the defaults */
+    pBuffer[OFFSET_P3]     = 0x04; /* Length of the following */
+    pBuffer[OFFSET_DATA]   = 0x01; /* Common public exponent  */
+    pBuffer[OFFSET_DATA+1] = 0x00;
+    pBuffer[OFFSET_DATA+2] = 0x01;
+    pBuffer[OFFSET_DATA+3] = 0x00;
+    transmitBuffer.bufferSize = 9;    
+  }
+
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+
+    if ( convertSW(apduResponse) == MSC_SUCCESS ) {
+
+      privACL.readPermission  = MSC_AUT_NONE;
+      privACL.writePermission = MSC_AUT_PIN_1;
+      privACL.usePermission   = MSC_AUT_PIN_1;
+
+      rv = PL_MSCWriteKeyInfo( pConnection, prvKeyNumBak, 
+			       MSC_KEY_RSA_PRIVATE_CRT, 
+			       prvKeyNum, pubKeyNumBak,
+			       pParams->keySize, &pParams->privateKeyPolicy, 
+			       &privACL );
+
+      if ( rv != MSC_SUCCESS ) return rv;
+
+      pubACL.readPermission  = MSC_AUT_ALL;
+      pubACL.writePermission = MSC_AUT_PIN_1;
+      pubACL.usePermission   = MSC_AUT_PIN_1;
+
+      rv = PL_MSCWriteKeyInfo( pConnection, pubKeyNumBak, MSC_KEY_RSA_PUBLIC, 
+			       pubKeyNum, prvKeyNumBak, pParams->keySize, 
+			       &pParams->publicKeyPolicy, &pubACL );
+      return rv;
+    }
+
+
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCImportKey( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+                        MSCLPKeyACL pKeyACL, 
+			MSCPUChar8 pKeyBlob, MSCULong32 keyBlobSize, 
+			MSCLPKeyPolicy keyPolicy, MSCPVoid32 pAddParams, 
+			MSCUChar8 addParamsSize ) {
+
+  MSCLong32 rv;
+  MSCUChar8 keyBlobCryptoflex[2500];
+  MSCULong32 currentPointer;
+  MSCKeyACL currentACL;
+  MSCUChar8 keyType;
+  MSCUChar8 keyNumBak;
+  MSCUShort16 keySize;
+  MSCULong32 expSize;
+
+  keyNumBak = keyNum;
+  keyType   = pKeyBlob[OFFSET_KEYTYPE];
+  MemCopyTo16(&keySize, &pKeyBlob[OFFSET_KEYSIZE]);
+
+
+  if ( keyType != MSC_KEY_RSA_PRIVATE_CRT && 
+       keyType != MSC_KEY_DES &&
+       keyType != MSC_KEY_RSA_PUBLIC ) 
+    {
+      return MSC_UNSUPPORTED_FEATURE;
+    }
+
+  rv = mapCryptoflexKeys(pConnection, keyType,
+			 keySize, keyNumBak, &keyNum);
+
+  if ( rv != MSC_SUCCESS ) return rv;
+
+  if ( keyType == MSC_KEY_RSA_PRIVATE_CRT ) {
+    
+    if ( keySize != 1024 ) {
+      return MSC_UNSUPPORTED_FEATURE;
+    }
+
+    rv = PL_MSCSelect(pConnection, 0x3F00);
+    rv = PL_MSCSelect(pConnection, 0x3FCF);
+    
+    if ( rv != MSC_SUCCESS ) {
+      return MSC_UNSUPPORTED_FEATURE;
+    }
+
+    /* Place the key in bytes in Cryptoflex style */
+    
+    currentPointer = 0;
+    keyBlobCryptoflex[currentPointer] = CF_1024_FULLSIZE_1;
+    currentPointer += CF_SIZEOF_MSBLEN;
+    keyBlobCryptoflex[currentPointer] = CF_1024_FULLSIZE_2;
+    currentPointer += CF_SIZEOF_LSBLEN;
+    keyBlobCryptoflex[currentPointer] = keyNum + 1;
+    currentPointer += CF_SIZEOF_KEYNUM;
+    
+    /* Copy P */
+    
+    MemCopyReverse(&keyBlobCryptoflex[currentPointer], 
+		   &pKeyBlob[MC_1024_OFFSET_P+2], CF_1024_COMPSIZE);
+    
+    currentPointer += CF_1024_COMPSIZE;
+    
+    /* Copy Q */
+    
+    MemCopyReverse(&keyBlobCryptoflex[currentPointer], 
+		   &pKeyBlob[MC_1024_OFFSET_Q+2], CF_1024_COMPSIZE);
+    
+    currentPointer += CF_1024_COMPSIZE;
+    
+    /* Copy PQ */
+    
+    MemCopyReverse(&keyBlobCryptoflex[currentPointer], 
+		   &pKeyBlob[MC_1024_OFFSET_PQ+2], CF_1024_COMPSIZE);
+    
+    currentPointer += CF_1024_COMPSIZE;
+    
+    /* Copy DP1 */
+    
+    MemCopyReverse(&keyBlobCryptoflex[currentPointer], 
+		   &pKeyBlob[MC_1024_OFFSET_DP1+2], CF_1024_COMPSIZE);
+    
+    currentPointer += CF_1024_COMPSIZE;
+    
+    /* Copy DQ1 */
+    
+    MemCopyReverse(&keyBlobCryptoflex[currentPointer], 
+		   &pKeyBlob[MC_1024_OFFSET_DQ1+2], CF_1024_COMPSIZE);
+    
+    currentPointer += CF_1024_COMPSIZE;
+    
+    rv = PL_MSCWriteLargeObjectOffCB( pConnection, "#0x0012",
+				      keyNum * CF_1024_FULLSIZE,
+				      keyBlobCryptoflex, CF_1024_FULLSIZE,
+				      0, 0 ); 
+
+    if ( rv != MSC_SUCCESS ) {
+      return rv;
+    }     
+
+  } else if ( keyType == MSC_KEY_RSA_PUBLIC ) {
+    
+    if ( keySize != 1024 ) {
+      return MSC_UNSUPPORTED_FEATURE;
+    }
+
+    rv = PL_MSCSelect(pConnection, 0x3F00);
+    rv = PL_MSCSelect(pConnection, 0x3FCF);
+    
+    if ( rv != MSC_SUCCESS ) {
+      return MSC_UNSUPPORTED_FEATURE;
+    }
+
+    /* Place the key in bytes in Cryptoflex style */
+    
+    currentPointer = 0;
+    keyBlobCryptoflex[currentPointer] = 0x01;
+    currentPointer += CF_SIZEOF_MSBLEN;
+    keyBlobCryptoflex[currentPointer] = 0x47;
+    currentPointer += CF_SIZEOF_LSBLEN;
+    keyBlobCryptoflex[currentPointer] = keyNum + 1;
+    currentPointer += CF_SIZEOF_KEYNUM;
+    
+    /* Copy N */
+    memset(&keyBlobCryptoflex[currentPointer], 
+	   0x00, MC_1024P_MODSIZE);
+    
+    currentPointer += MC_1024P_MODSIZE;
+    
+    /* Skip J0 + H */
+    memset(&keyBlobCryptoflex[currentPointer], 0x00, 192);
+    currentPointer += 192;
+
+    /* Copy E */
+    expSize = (pKeyBlob[MC_1024P_EXP] * 256)+pKeyBlob[MC_1024P_EXP+1];
+    memset(&keyBlobCryptoflex[currentPointer], 0x00, 0x04);
+
+    MemCopyReverse(&keyBlobCryptoflex[currentPointer], 
+		   &pKeyBlob[MC_1024P_EXP+2], expSize);
+    
+    rv = PL_MSCWriteLargeObjectOffCB( pConnection, "#0x1012",
+				      keyNum * 0x0147,
+				      keyBlobCryptoflex, 0x0147,
+				      0, 0 ); 
+
+    if ( rv != MSC_SUCCESS ) {
+      return rv;
+    }     
+
+  } else if ( keyType == MSC_KEY_DES ) {
+
+    if ( keySize != 64 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    /* FIX :: Must be careful here - old manual list an RFU byte first
+              but the new manual lists no RFU byte at all
+    */
+    
+    keyBlobCryptoflex[0] = 0x08; /* key size */
+    keyBlobCryptoflex[1] = 0x00; /* key type */
+    memcpy(&keyBlobCryptoflex[2], &pKeyBlob[MC_DES_OFFSET_KEY+2], 8);
+    keyBlobCryptoflex[10] = 0x0A;
+    keyBlobCryptoflex[11] = 0x0A;
+
+    rv = PL_MSCWriteObject( pConnection, "#0x0011", CF_DES_OFFSET_UKEY,
+			    keyBlobCryptoflex, 0x0C );
+			 
+    if ( rv != MSC_SUCCESS ) return rv;
+    
+  } else {    
+    /* RSA public would go here */
+    
+    rv =  MSC_UNSUPPORTED_FEATURE;
+  }
+
+  switch(keyType) {
+  case MSC_KEY_RSA_PRIVATE_CRT:
+  case MSC_KEY_RSA_PRIVATE:
+    currentACL.readPermission  = MSC_AUT_NONE;
+    currentACL.writePermission = MSC_AUT_PIN_1;
+    currentACL.usePermission   = MSC_AUT_PIN_1;	
+    break;
+    
+  case MSC_KEY_RSA_PUBLIC:
+    currentACL.readPermission  = MSC_AUT_ALL;
+    currentACL.writePermission = MSC_AUT_PIN_1;
+    currentACL.usePermission   = MSC_AUT_PIN_1;
+    break;
+    
+  case MSC_KEY_DES:
+  case MSC_KEY_3DES:
+  case MSC_KEY_3DES3:
+    currentACL.readPermission  = MSC_AUT_PIN_0;
+    currentACL.writePermission = MSC_AUT_PIN_0;
+    currentACL.usePermission   = MSC_AUT_ALL;
+    break;
+    
+  default:
+    return MSC_UNSUPPORTED_FEATURE;
+  }
+  
+  rv = PL_MSCWriteKeyInfo( pConnection, keyNumBak, keyType, 
+			   keyNum, 0xFF, keySize, keyPolicy, 
+			   &currentACL );
+    
+  return rv;
+}
+ 
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCExportKey( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+		     MSCPUChar8 pKeyBlob, MSCPULong32 keyBlobSize, 
+		     MSCPVoid32 pAddParams, MSCUChar8 addParamsSize ) {
+
+  MSCLong32 rv;
+  MSCUChar8 keyBuffer[2500];
+  MSCKeyInfo keyStruct;
+  MSCULong32 currentPointer;
+  MSCULong32 blobSize;
+  MSCUShort16 currentVal;
+  MSCUChar8 keyNumCF;
+  int i;
+
+  i=0; blobSize=0; rv=0; currentPointer=0; keyNumCF=0; currentVal=0;
+
+  if ( pConnection == 0 || keyBlobSize == 0 || pKeyBlob == 0 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  keyStruct.keyNum = 0xFF;
+  rv = MSCListKeys(pConnection, MSC_SEQUENCE_RESET, &keyStruct);
+
+  if ( rv != MSC_SEQUENCE_END ) {
+    do {
+      if ( keyStruct.keyNum == keyNum ) {
+	break;
+      }
+      rv = MSCListKeys(pConnection, MSC_SEQUENCE_NEXT, &keyStruct);
+      /* FIX :: potential problem if error occurs ... */
+    } while ( rv != MSC_SEQUENCE_END );
+  }
+
+  /* Match not found */
+  if ( keyStruct.keyNum == 0xFF ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  if ( keyStruct.keyType != MSC_KEY_RSA_PUBLIC ) {
+    return MSC_UNSUPPORTED_FEATURE;
+  }
+    
+  keyNumCF = keyStruct.keyPartner;
+  
+  /* not sure if this is right */
+
+  rv =  PL_MSCReadLargeObjectOffCB( pConnection, "#0x1012", 
+				    keyNumCF*CF_1024P_FULLSIZE, 
+				    keyBuffer,  CF_1024P_FULLSIZE, 0, 0);   
+
+  if ( rv != MSC_SUCCESS ) return rv;
+
+  /* Copy to a MuscleCard defined RSA_PUB key blob as defined
+      in the protocol spec 
+  */
+  
+  pKeyBlob[OFFSET_ENCODING] = MSC_BLOB_ENC_PLAIN;
+  pKeyBlob[OFFSET_KEYTYPE]  = MSC_KEY_RSA_PUBLIC;  
+
+  currentVal = CF_1024_KEYSIZE;
+  MemCopy16(&pKeyBlob[OFFSET_KEYSIZE], &currentVal);
+
+  currentVal = CF_1024P_MODSIZE;
+  MemCopy16(&pKeyBlob[MC_1024P_MOD], &currentVal);
+  MemCopyReverse(&pKeyBlob[MC_1024P_MOD + 2], 
+		 &keyBuffer[CF_1024P_MOD], CF_1024P_MODSIZE);
+
+  currentVal = CF_1024P_EXPSIZE;
+  MemCopy16(&pKeyBlob[MC_1024P_EXP], &currentVal);
+  MemCopyReverse(&pKeyBlob[MC_1024P_EXP + 2], 
+		 &keyBuffer[CF_1024P_EXP], CF_1024P_EXPSIZE);
+
+  *keyBlobSize = MC_1024P_FULLSIZE; 
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCComputeCrypt( MSCLPTokenConnection pConnection,
+			MSCLPCryptInit cryptInit, MSCPUChar8 pInputData,
+			MSCULong32 inputDataSize, MSCPUChar8 pOutputData,
+			MSCPULong32 outputDataSize ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+  MSCUChar8 cflKeyNum;
+
+  if ( cryptInit->cipherMode == MSC_MODE_RSA_NOPAD ) {
+    /* Some RSA */
+    rv = mapCryptoflexKeys(pConnection, MSC_KEY_RSA_PRIVATE_CRT,
+			   1024, cryptInit->keyNum,
+			   &cflKeyNum);
+
+
+    if ( rv != MSC_SUCCESS ) return rv;
+  } else if ( cryptInit->cipherMode == MSC_MODE_DES_ECB_NOPAD ) {
+    /* Some DES */
+    rv = mapCryptoflexKeys(pConnection, MSC_KEY_DES,
+			   64, cryptInit->keyNum,
+			   &cflKeyNum);			   
+    if ( rv != MSC_SUCCESS ) return rv;
+  } else {
+    return MSC_UNSUPPORTED_FEATURE;
+  }
+
+  rv = PL_MSCSelect(pConnection, 0x3F00);
+  rv = PL_MSCSelect(pConnection, CRYPTOFLEX_MSC_KEY_DIR);
+
+  if ( rv != MSC_SUCCESS ) return rv;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_C0;
+  pBuffer[OFFSET_INS]    = INS_COMPUTE_CRYPT;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = cflKeyNum;
+
+  /* PG: 0x40, 0x60, 0x80 - possible lengths of the cryptogram */
+  /* DC: Only support for 1023 bit RSA for now */
+  if(inputDataSize != 8 && inputDataSize != 128)
+    return MSC_INVALID_PARAMETER;
+
+  pBuffer[OFFSET_P3]     = inputDataSize;
+
+  /* PG: 64, 96 or 128 bytes (respectively) to be encrypted
+     NOTE: you must enter the data in LSB format */
+  MemCopyReverse(&pBuffer[OFFSET_DATA], pInputData, inputDataSize);
+
+  transmitBuffer.bufferSize = 5 + inputDataSize;
+
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if(rv != SCARD_S_SUCCESS) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == inputDataSize + 2 ) {
+    *outputDataSize = transmitBuffer.apduResponseSize - 2;
+    MemCopyReverse(pOutputData, apduResponse,
+		   *outputDataSize);
+
+    return MSC_SUCCESS;
+  } else if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCExtAuthenticate( MSCLPTokenConnection pConnection, 
+			      MSCUChar8 keyNum,
+			      MSCUChar8 cipherMode, 
+			      MSCUChar8 cipherDirection,
+			      MSCPUChar8 pData, 
+			      MSCULong32 dataSize )
+{
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+
+  /* PG: Cryptoflex uses DES for external authentication */
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_C0;
+  pBuffer[OFFSET_INS]    = INS_EXT_AUTH;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  /* PG: the length of the input data
+     (a 1-byte key number plus a 6-byte truncated cryptogram) */
+  pBuffer[OFFSET_P3]     = 0x07;
+
+  pBuffer[OFFSET_DATA] = keyNum;
+
+  /* The cryptogram must be 6 bytes long  */
+  memcpy(&pBuffer[OFFSET_DATA + 1], pData, 6);
+
+  transmitBuffer.bufferSize =  pBuffer[OFFSET_P3] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    /* dumpBinary(apduResponse, transmitBuffer.apduResponseSize); */
+    return convertSW(&apduResponse[transmitBuffer.apduResponseSize-2]);
+  }
+
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCListKeys( MSCLPTokenConnection pConnection, MSCUChar8 seqOption,
+		       MSCLPKeyInfo pKeyInfo ) {
+
+    /* PG: Since we don't provide neither AUT nor PRO protection
+       it's useless to give information about these keys */
+
+  /* Dave: One key pair is by default in directory 3FCF 
+     more work needs to be done here
+  */
+
+
+  MSCLong32 rv;
+  static MSCUChar8 keyByteMask[CRYPTOFLEX_MAXMSC_KEY_NUM+1];
+  static int sequenceNumber = 0;
+  int i, j;
+
+  if ( seqOption == MSC_SEQUENCE_RESET ) {
+    rv = PL_MSCReadKeyInfo(pConnection, 0);
+    if ( rv != MSC_SUCCESS ) return rv;
+
+    for (i=0; i <= CRYPTOFLEX_MAXMSC_KEY_NUM; i++) {
+      pKeyInfo->keyNum = i;
+      rv = PL_MSCReadKeyInfo(pConnection, pKeyInfo);
+
+      if ( rv != MSC_SUCCESS ) return rv;
+      
+      /* Check if the key entry is present or missing */
+      if ( pKeyInfo->keyNum == 0 && pKeyInfo->keyType == 0 &&
+	   pKeyInfo->keyPartner == 0 && pKeyInfo->keySize == 0 ) {
+	keyByteMask[i] = 0;
+      } else {
+	keyByteMask[i] = 1;
+      }
+
+    }
+    
+    sequenceNumber = 1;
+  } else {
+    sequenceNumber += 1;
+  }
+
+  j = 0;
+
+  for (i=0; i < sequenceNumber; i++) {
+    do {
+      if ( keyByteMask[j] == 1 ) {
+	j += 1;
+	break;
+      }
+
+      j += 1;
+
+      if ( j > CRYPTOFLEX_MAXMSC_KEY_NUM ) 
+	return MSC_SEQUENCE_END;
+
+    } while (1);
+  }
+
+
+  pKeyInfo->keyNum = j - 1;
+  rv = PL_MSCReadKeyInfo(pConnection, pKeyInfo);
+  
+  return rv;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCCreatePIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+		     MSCUChar8 pinAttempts, MSCPUChar8 pPinCode,
+		     MSCULong32 pinCodeSize, MSCPUChar8 pUnblockCode,
+		     MSCUChar8 unblockCodeSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCVerifyPIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+		     MSCPUChar8 pPinCode, MSCULong32 pinCodeSize ) {
+  
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+
+  /*
+    if ( pinCodeSize != 8 ) {
+    return MSC_INVALID_PARAMETER;
+    }
+  */
+
+  rv = PL_MSCSelect(pConnection, 0x3F00);
+
+  if ( pinNum == 0 ) {
+    rv = PL_MSCVerifyKey(pConnection, pPinCode, pinCodeSize);
+    if ( rv == MSC_SUCCESS ) { pConnection->loggedIDs |= MSC_AUT_PIN_0; }
+    return rv;
+  }
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_C0;
+  pBuffer[OFFSET_INS]    = INS_VERIFY_PIN;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = pinNum;
+  /* PIN code size is enforced by Cryptoflex */
+  pBuffer[OFFSET_P3]     = 0x08;
+
+
+  memset(&pBuffer[OFFSET_DATA], 0xFF, 8);
+  memcpy(&pBuffer[OFFSET_DATA], pPinCode, pinCodeSize);
+  
+  transmitBuffer.bufferSize =  pBuffer[OFFSET_P3] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    if ( convertSW(apduResponse) == MSC_SUCCESS ) { 
+      /* FIX :: Only did 4 PINs */
+      switch(pinNum) {
+	case 1:
+	  pConnection->loggedIDs |= MSC_AUT_PIN_1;
+	break;
+	case 2:
+	  pConnection->loggedIDs |= MSC_AUT_PIN_2;
+	break;
+	case 3:
+	  pConnection->loggedIDs |= MSC_AUT_PIN_3;
+	break;
+	case 4:
+	  pConnection->loggedIDs |= MSC_AUT_PIN_4;
+	break;
+      };
+    }
+
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCChangePIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			MSCPUChar8 pOldPinCode, MSCUChar8 oldPinCodeSize,
+			MSCPUChar8 pNewPinCode, MSCUChar8 newPinCodeSize ) {
+
+  MSCLong32 rv, rvb;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  if ( pinNum == 0 ) {
+
+    if ( oldPinCodeSize != 8 || newPinCodeSize != 8 ) {
+      return MSC_INVALID_PARAMETER;
+    }
+
+    rv = PL_MSCVerifyKey(pConnection, pOldPinCode, oldPinCodeSize);
+
+    if ( rv != MSC_SUCCESS ) {
+      return rv;
+    }
+
+    rv = PL_MSCSelect(pConnection, 0x3F00);
+    rv = PL_MSCSelect(pConnection, 0x0011);
+    
+    if ( rv != MSC_SUCCESS ) {
+      return MSC_UNSUPPORTED_FEATURE;
+    }
+
+    pBuffer[OFFSET_CLA]    = CLA_C0;
+    pBuffer[OFFSET_INS]    = INS_WRITE_OBJ;
+    pBuffer[OFFSET_P1]     = 0x00;
+    pBuffer[OFFSET_P2]     = 0x0D; /* offset for key 1 */
+    pBuffer[OFFSET_P3]     = 0x0C;
+
+    pBuffer[OFFSET_DATA]    = 0x08;
+    pBuffer[OFFSET_DATA+1]  = 0x00;
+    memcpy(&pBuffer[OFFSET_DATA+2], pNewPinCode, 8);
+
+    pBuffer[OFFSET_DATA+10] = 0x05;
+    pBuffer[OFFSET_DATA+11] = 0x05;
+    transmitBuffer.bufferSize = pBuffer[OFFSET_P3] + 5;
+
+  } else {
+    /* FIX: Add support for additional PINs */
+    /* PG: PIN code size is enforced by Cryptoflex */
+
+    rv = PL_MSCVerifyPIN(pConnection, pinNum, pOldPinCode, oldPinCodeSize);
+
+    if ( rv != MSC_SUCCESS ) {
+      return rv;
+    }
+
+    rv = PL_MSCSelect(pConnection, 0x3F00);
+    rv = PL_MSCSelect(pConnection, 0x0000);
+
+    if ( rv != MSC_SUCCESS ) {
+      return rv;
+    }
+
+    pBuffer[OFFSET_CLA]    = CLA_C0;
+    pBuffer[OFFSET_INS]    = INS_WRITE_OBJ;
+    pBuffer[OFFSET_P1]     = 0x00;
+    pBuffer[OFFSET_P2]     = 0x00;
+    pBuffer[OFFSET_P3]     = 0x0B;
+    pBuffer[OFFSET_DATA]   = 0xFF;
+    pBuffer[OFFSET_DATA+1] = 0xFF;
+    pBuffer[OFFSET_DATA+2] = 0xFF;
+
+
+    memset(&pBuffer[OFFSET_DATA+3], 0xFF, 8);
+    memcpy(&pBuffer[OFFSET_DATA+3], pNewPinCode, newPinCodeSize);
+
+    transmitBuffer.bufferSize = pBuffer[OFFSET_P3] + 5;
+  }
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  rvb = PL_MSCSelect(pConnection, 0x3F00);
+  rvb = PL_MSCSelect(pConnection, CRYPTOFLEX_OBJ_DIR);
+  
+  if ( rvb != MSC_SUCCESS ) {
+    return rvb;
+  }
+
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCUnblockPIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+		      MSCPUChar8 pUnblockCode, MSCULong32 unblockCodeSize ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_F0;
+  pBuffer[OFFSET_INS]    = INS_UNBLOCK_PIN;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = pinNum;
+  pBuffer[OFFSET_P3]     = 0x10;
+
+  /* PG: Code length is enforced by Cryptoflex */
+  memcpy(&pBuffer[OFFSET_DATA], pUnblockCode, 8);
+
+  /* PG: API PROBLEM: Cryptoflex requires that after the
+     unblocking code the new PIN code must be entered */
+
+  memcpy(&pBuffer[OFFSET_DATA + 8], "Muscle00", 8);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_P3] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCListPINs( MSCLPTokenConnection pConnection, MSCPUShort16 pPinBitMask ) {
+
+    /* PG: There are only two well-known PINs on Cryptoflex card */
+  *pPinBitMask = 0x00000003;
+  return MSC_SUCCESS;
+}
+
+MSC_RV PL_MSCCreateObject( MSCLPTokenConnection pConnection, 
+			   MSCString objectID, MSCULong32 objectSize,
+			   MSCLPObjectACL pObjectACL ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+  MSCULong32 currentPointer;
+  MSCUShort16 _objectSize;
+  MSCUShort16 _objectID;
+
+  /* PG: conversions */
+  _objectSize = 256 * ((objectSize & 0xFF00) >> 8 ) + (objectSize & 0x00FF);
+
+  if ( stringToID(&_objectID, objectID) ) 
+    return MSC_INVALID_PARAMETER;
+
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, CRYPTOFLEX_OBJ_DIR);
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_F0;
+  pBuffer[OFFSET_INS]    = INS_CREATE_OBJ;
+  pBuffer[OFFSET_P1]     = 0x00;
+  /* PG: Number of records - used only for linear EFs */
+  pBuffer[OFFSET_P2]     = 0x00;
+  /* PG: Assumption: transparent EF not protected by PRO AC */
+  pBuffer[OFFSET_P3]     = 0x10;
+
+  currentPointer = 0;
+
+  /* PG: RFU */
+  pBuffer[OFFSET_DATA]   = 0xFF;
+  pBuffer[OFFSET_DATA+1] = 0xFF;
+  currentPointer = 2;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], &_objectSize);
+  currentPointer += 2;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], &_objectID);
+  currentPointer += 2;
+
+  /* PG: Assumption: transparent EF */
+  pBuffer[OFFSET_DATA+currentPointer] = 0x01;
+  currentPointer++;
+
+  /* PG: Access conditions */
+  /* PG: Availibility of Increase and Decrease commands
+     - 0x00 since these commands do not apply to transparent EFs*/
+  pBuffer[OFFSET_DATA+currentPointer] = 0x00;
+  currentPointer++;
+
+  /* PG: Read/Write permissions */
+  pBuffer[OFFSET_DATA+currentPointer] = ACL2Byte(pObjectACL);
+  currentPointer++;
+
+  /* PG: RFU */
+  pBuffer[OFFSET_DATA+currentPointer] = 0xFF;
+  currentPointer++;
+
+  /* PG: Rehabilitate/Invalidate - never possible, since
+     we cannot invoke these commands with this API */
+  pBuffer[OFFSET_DATA+currentPointer] = 0xFF;
+  currentPointer++;
+
+  /* PG: Validation status - activated */
+  pBuffer[OFFSET_DATA+currentPointer] = 0x01;
+  currentPointer++;
+
+  /* PG: Length of the input data from byte 14 to EOF
+     in case of transparent EF must be 0x03 */
+  pBuffer[OFFSET_DATA+currentPointer] = 0x03;
+  currentPointer++;
+
+  /* PG: Key numbers for AC */
+  pBuffer[OFFSET_DATA+currentPointer] = 0x11;
+  currentPointer++;
+  pBuffer[OFFSET_DATA+currentPointer] = 0x11;
+  currentPointer++;
+  pBuffer[OFFSET_DATA+currentPointer] = 0x11;
+  currentPointer++;
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_P3] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCDeleteObject( MSCLPTokenConnection pConnection, 
+			   MSCString objectID, MSCUChar8 zeroFlag ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+  MSCULong32 currentPointer;
+  MSCUShort16 _objectID;
+
+  /* PG: conversions */
+  if ( stringToID(&_objectID, objectID) ) 
+    return MSC_INVALID_PARAMETER;
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  PL_MSCSelect(pConnection, CRYPTOFLEX_OBJ_DIR);
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_F0;
+  pBuffer[OFFSET_INS]    = INS_DELETE_OBJ;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_P3]     = 0x02;
+
+  currentPointer = 0;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], &_objectID);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_P3] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteObject( MSCLPTokenConnection pConnection, 
+			  MSCString objectID, 
+			  MSCULong32 offset, MSCPUChar8 pInputData, 
+			  MSCUChar8 dataSize ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+  MSCULong32 currentPointer;
+  MSCUShort16 _objectID;
+
+  if ( stringToID(&_objectID, objectID) ) 
+    return MSC_INVALID_PARAMETER;
+
+  PL_MSCSelect(pConnection, 0x3F00);
+  if(_objectID == 0x0012) {
+    PL_MSCSelect(pConnection, CRYPTOFLEX_MSC_KEY_DIR);
+  } else if (_objectID == 0x1012 ) {
+    PL_MSCSelect(pConnection, CRYPTOFLEX_MSC_KEY_DIR);
+  } else if ( _objectID == 0x0011 ) {
+    /* stay in root */
+  } else {
+    PL_MSCSelect(pConnection, CRYPTOFLEX_OBJ_DIR);
+  }
+
+  PL_MSCSelect(pConnection, _objectID);
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_C0;
+  pBuffer[OFFSET_INS]    = INS_WRITE_OBJ;
+  pBuffer[OFFSET_P1]     = (offset & 0xFF00) >> 8;
+  pBuffer[OFFSET_P2]     = offset & 0x00FF;
+  pBuffer[OFFSET_P3]     = dataSize;
+  
+  currentPointer = 0;
+  
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pInputData, dataSize);
+  transmitBuffer.bufferSize = pBuffer[OFFSET_P3] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCReadObject( MSCLPTokenConnection pConnection, MSCString objectID, 
+			 MSCULong32 offset, MSCPUChar8 pOutputData, 
+			 MSCUChar8 dataSize ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+  MSCUShort16 _objectID;
+
+
+  if ( stringToID(&_objectID, objectID) ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  PL_MSCSelect(pConnection, 0x3F00);
+
+  if ( _objectID == 0x1012 ) {
+    PL_MSCSelect(pConnection, CRYPTOFLEX_MSC_KEY_DIR);
+  } else {
+    PL_MSCSelect(pConnection, CRYPTOFLEX_OBJ_DIR);
+  }
+
+  PL_MSCSelect(pConnection, _objectID);
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_C0;
+  pBuffer[OFFSET_INS]    = INS_READ_OBJ;
+  pBuffer[OFFSET_P1]     = (offset & 0xFF00) >> 8;
+  pBuffer[OFFSET_P2]     = offset & 0x00FF;
+  pBuffer[OFFSET_P3]     = dataSize;
+
+  transmitBuffer.bufferSize = 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else if (transmitBuffer.apduResponseSize == dataSize + 2 ) {
+    memcpy(pOutputData, apduResponse, dataSize);
+    return convertSW(&apduResponse[dataSize]);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCListObjects( MSCLPTokenConnection pConnection, 
+			  MSCUChar8 seqOption, 
+			  MSCLPObjectInfo pObjectInfo ) {
+
+  MSCLong32 rv;
+  static int sequenceNumber;
+  MSCTransmitBuffer transmitBuffer;
+  MSCTransmitBuffer transmitBufferB;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 apduResponseB;
+  MSCPUChar8 pBuffer;
+  MSCPUChar8 pBufferB;
+  MSCULong32 currentPointer;
+  MSCUChar8 cTemp[2];
+  int i;
+
+  rv=0; currentPointer=0;
+
+  if ( seqOption == MSC_SEQUENCE_RESET ) {
+    sequenceNumber = 1;
+
+  } else {
+    sequenceNumber += 1;
+  }
+
+  while (1) {
+
+    rv = PL_MSCSelect(pConnection, 0x3F00);
+    rv = PL_MSCSelect(pConnection, CRYPTOFLEX_OBJ_DIR);
+
+    if ( rv != MSC_SUCCESS ) {
+      return MSC_UNSUPPORTED_FEATURE;
+    }
+    
+    pBuffer = transmitBuffer.pBuffer; 
+    apduResponse = transmitBuffer.apduResponse;
+    
+    pBuffer[OFFSET_CLA]    = CLA_F0;
+    pBuffer[OFFSET_INS]    = INS_LIST_OBJECTS;
+    pBuffer[OFFSET_P1]     = 0x00;
+    pBuffer[OFFSET_P2]     = 0x00;
+    pBuffer[OFFSET_P3]     = 0x09;
+    
+    transmitBuffer.bufferSize = 5;
+
+    for (i=0; i < sequenceNumber; i++ ) {
+      /* Set up the APDU exchange */
+      transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+      rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+      
+      if ( rv != SCARD_S_SUCCESS ) {
+	return convertPCSC(rv);
+      }
+      
+      if ( transmitBuffer.apduResponseSize == 2 ) {
+	/* PG: TODO: define a constant here */
+	if ( convertSW(apduResponse) == MSC_OBJECT_NOT_FOUND ) {  /* Vinnie 1740 */
+	  /* Must have finished */
+	  return MSC_SEQUENCE_END;
+	} else {
+	  return convertSW(apduResponse);
+	}	
+      } 
+    }   /* End of for ... loop */
+    
+    if (transmitBuffer.apduResponseSize == pBuffer[OFFSET_P3] + 2 ) {
+
+      /* PG: Omit 8 most significant 8 bytes which  are only used
+	 to indicate whether the size of an object was rounded up */
+      
+      memcpy(cTemp, &apduResponse[2], 2);
+      bytesToString(pObjectInfo->objectID, cTemp);
+
+      if ( strcmp(pObjectInfo->objectID, CRYPTOFLEX_INFOBJ_ID) == 0 ) {
+	sequenceNumber += 1;
+	continue;
+      }
+
+      /* PG: skipping to byte 7, where access conditions begin */
+      
+      Byte2ACL(apduResponse[6], &pObjectInfo->objectACL);
+      
+      /* Whoever did Cryptoflex mask is an idiot - I can't believe they
+	 round to the nearest 4 bytes on the size for Dir Next 
+      */
+      
+      apduResponseB = transmitBufferB.apduResponse;
+      pBufferB      = transmitBufferB.pBuffer;
+
+      pBufferB[OFFSET_CLA]    = CLA_C0;
+      pBufferB[OFFSET_INS]    = 0xA4;
+      pBufferB[OFFSET_P1]     = 0x00;
+      pBufferB[OFFSET_P2]     = 0x00;
+      pBufferB[OFFSET_P3]     = 0x02;
+      pBufferB[OFFSET_DATA]   = cTemp[0];
+      pBufferB[OFFSET_DATA+1] = cTemp[1];
+      
+      transmitBufferB.bufferSize = 7;
+      
+      /* Set up the APDU exchange */
+      transmitBufferB.apduResponseSize = MSC_MAXSIZE_BUFFER;
+      rv = SCardExchangeAPDU( pConnection, &transmitBufferB );
+      
+      if ( rv != SCARD_S_SUCCESS ) {
+	return convertPCSC(rv);
+      }
+      
+      if ( transmitBufferB.apduResponseSize == 2 ) {
+	return convertSW(apduResponse);
+      }
+      
+      pObjectInfo->objectSize = apduResponseB[2] * 0x100 + apduResponseB[3];
+       
+      return convertSW(&apduResponseB[15]);
+
+    } else {
+      return MSC_UNSPECIFIED_ERROR;
+    }
+
+
+    break;
+  }
+
+  return MSC_UNSPECIFIED_ERROR;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCLogoutAll( MSCLPTokenConnection pConnection ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CLA_F0;
+  pBuffer[OFFSET_INS]    = INS_LOGOUT_ALL;
+  /* PG: Cryptoflex Logout AC command can be used to reset
+     multiple access conditions - however, setting P1 to 0x07
+     simply means "Logout All" */
+  pBuffer[OFFSET_P1]     = 0x07;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_P3]     = 0x00;
+
+  transmitBuffer.bufferSize = 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    rv = convertSW(apduResponse);
+
+    if ( rv == MSC_SUCCESS ) {
+      pConnection->loggedIDs = 0;
+    }
+
+    return rv;
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCGetChallenge( MSCLPTokenConnection pConnection, MSCPUChar8 pSeed,
+			MSCUShort16 seedSize, MSCPUChar8 pRandomData,
+			MSCUShort16 randomDataSize ) {
+
+  MSCLong32 rv;
+  MSCULong32 currentPointer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+
+  /* PG: randomDataSize is the only parameter
+     that can be passed to Cryptoflex */
+
+  if ( pRandomData == 0 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  if ( randomDataSize == 0 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA] = CLA_C0;
+  pBuffer[OFFSET_INS] = INS_GET_CHALLENGE;
+  pBuffer[OFFSET_P1]  = 0x00;
+  pBuffer[OFFSET_P2]  = 0x00;
+  pBuffer[OFFSET_P3]  = randomDataSize;
+
+  currentPointer = 0;
+
+  transmitBuffer.bufferSize = 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  /* PG: or randomDataSize + 4 ??? */
+  if(transmitBuffer.apduResponseSize == randomDataSize + 2)
+  {
+    memcpy(pRandomData, apduResponse, randomDataSize);
+    return convertSW(&apduResponse[transmitBuffer.apduResponseSize-2]);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCGetObjectAttributes( MSCLPTokenConnection pConnection,
+				  MSCString objectID,
+				  MSCLPObjectInfo pObjectInfo ) {
+
+  MSC_RV rv;
+  MSCObjectInfo objInfo;
+
+  if ( pConnection == NULL ) return MSC_INVALID_PARAMETER; 
+
+  rv = PL_MSCListObjects( pConnection, MSC_SEQUENCE_RESET, &objInfo );
+
+  if ( rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS) {
+    return rv;
+  }
+
+  if ( rv == MSC_SEQUENCE_END ) {
+    return MSC_OBJECT_NOT_FOUND;
+  }
+
+  if (strncmp(objectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0 ) {
+    pObjectInfo->objectSize = objInfo.objectSize;
+    pObjectInfo->objectACL.readPermission = 
+      objInfo.objectACL.readPermission;
+    pObjectInfo->objectACL.writePermission = 
+      objInfo.objectACL.writePermission;
+    pObjectInfo->objectACL.deletePermission = 
+      objInfo.objectACL.deletePermission;
+    strncpy(pObjectInfo->objectID, objectID, MSC_MAXSIZE_OBJID);
+    return MSC_SUCCESS;
+  }
+  
+  do {
+    rv = PL_MSCListObjects( pConnection, MSC_SEQUENCE_NEXT, &objInfo );
+    if (strncmp(objectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0 ) 
+      break;
+  } while ( rv == MSC_SUCCESS );
+  
+  if ( rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS ) {
+    return rv;
+  }
+
+  if ( rv == MSC_SEQUENCE_END ) {
+    return MSC_OBJECT_NOT_FOUND;
+  }
+
+  pObjectInfo->objectSize = objInfo.objectSize;
+  pObjectInfo->objectACL.readPermission = 
+    objInfo.objectACL.readPermission;
+  pObjectInfo->objectACL.writePermission = 
+    objInfo.objectACL.writePermission;
+  pObjectInfo->objectACL.deletePermission = 
+    objInfo.objectACL.deletePermission;
+  strncpy(pObjectInfo->objectID, objectID, MSC_MAXSIZE_OBJID);
+
+  return MSC_SUCCESS;  
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCReadAllocateObject( MSCLPTokenConnection pConnection, 
+				 MSCString objectID, MSCPUChar8 *pOutputData, 
+				 MSCPULong32 dataSize ) {
+
+  MSC_RV rv;
+  MSCObjectInfo objInfo;
+
+  if ( pConnection == NULL ) return MSC_INVALID_PARAMETER; 
+
+  if ( pOutputData == 0 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  rv = PL_MSCGetObjectAttributes( pConnection, objectID, &objInfo );
+  
+  if ( rv != MSC_SUCCESS ) {
+    *dataSize = 0;
+    *pOutputData = 0;
+    return rv;
+  }
+
+  *pOutputData = (MSCPUChar8)malloc(sizeof(MSCUChar8)*objInfo.objectSize);
+
+  return PL_MSCReadLargeObjectOffCB( pConnection, objectID, 0,
+				     *pOutputData, objInfo.objectSize,
+				     0, 0 );
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteLargeObjectOffCB( MSCLPTokenConnection pConnection, 
+				    MSCString objectID, MSCULong32 offSet, 
+				    MSCPUChar8 pInputData, 
+				    MSCULong32 dataSize, 
+				    LPRWEventCallback rwCallback,
+				    MSCPVoid32 addParams ) {
+  MSC_RV rv;
+  MSCULong32 objectSize;
+  int totalSteps, stepInterval;
+  MSC_RV (*callBackFunction)(void*, int);
+  int i;
+   
+  callBackFunction = (MSC_RV(*)(void*, int)) rwCallback;
+  objectSize       = dataSize;
+  rv               = MSC_UNSPECIFIED_ERROR;
+
+
+  /* Figure out the number of steps total and present this
+     in a percent step basis 
+  */
+
+  totalSteps = objectSize/MSC_SIZEOF_KEYPACKET + 1;
+  stepInterval = MSC_PERCENT_STEPSIZE / totalSteps;
+
+
+  for (i=0; i < objectSize/MSC_SIZEOF_KEYPACKET; i++) {
+    rv = PL_MSCWriteObject( pConnection, objectID, 
+			    i*MSC_SIZEOF_KEYPACKET + offSet, 
+			    &pInputData[i*MSC_SIZEOF_KEYPACKET], 
+			    MSC_SIZEOF_KEYPACKET );
+    if ( rv != MSC_SUCCESS ) { return rv; }
+
+    if ( rwCallback ) {    
+      if ((*callBackFunction)(addParams, stepInterval*i) == MSC_CANCELLED) {
+	return MSC_CANCELLED;
+      }
+    }
+    
+  }
+  
+  
+  if ( objectSize%MSC_SIZEOF_KEYPACKET ) {
+    rv = PL_MSCWriteObject( pConnection, objectID, 
+			    i*MSC_SIZEOF_KEYPACKET + offSet, 
+			    &pInputData[i*MSC_SIZEOF_KEYPACKET], 
+			    objectSize%MSC_SIZEOF_KEYPACKET );
+    
+    if ( rv != MSC_SUCCESS ) { return rv; }
+  }    
+  
+  if ( rwCallback ) {
+    (*callBackFunction)(addParams, MSC_PERCENT_STEPSIZE); 
+  }  
+  return rv;
+}
+
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCReadLargeObjectOffCB( MSCLPTokenConnection pConnection, 
+				   MSCString objectID, MSCULong32 offSet, 
+				   MSCPUChar8 pOutputData, 
+				   MSCULong32 dataSize, 
+				   LPRWEventCallback rwCallback,
+				   MSCPVoid32 addParams ) {
+  
+  MSC_RV rv;
+  MSCULong32 objectSize;
+  int totalSteps, stepInterval;
+  MSC_RV (*callBackFunction)(void*, int);
+  int i;
+  
+  callBackFunction = (MSC_RV(*)(void*, int)) rwCallback;
+  objectSize       = dataSize;
+  rv               = MSC_UNSPECIFIED_ERROR;
+  
+  /* Figure out the number of steps total and present this
+     in a percent step basis 
+  */
+  
+  totalSteps = objectSize/MSC_SIZEOF_KEYPACKET + 1;
+  stepInterval = MSC_PERCENT_STEPSIZE / totalSteps;
+  
+  for (i=0; i < objectSize/MSC_SIZEOF_KEYPACKET; i++) {
+    rv = PL_MSCReadObject( pConnection, objectID, 
+                        i*MSC_SIZEOF_KEYPACKET + offSet, 
+                        &pOutputData[i*MSC_SIZEOF_KEYPACKET], 
+                        MSC_SIZEOF_KEYPACKET );
+    if ( rv != MSC_SUCCESS ) { return rv; }
+    
+    if ( rwCallback ) {
+      if ((*callBackFunction)(addParams, stepInterval*i) == MSC_CANCELLED) {
+	return MSC_CANCELLED;
+      }
+    }
+  }
+  
+  if ( objectSize%MSC_SIZEOF_KEYPACKET ) {
+    rv = PL_MSCReadObject( pConnection, objectID, 
+                        i*MSC_SIZEOF_KEYPACKET + offSet, 
+                        &pOutputData[i*MSC_SIZEOF_KEYPACKET], 
+                        objectSize%MSC_SIZEOF_KEYPACKET );
+    
+    if ( rv != MSC_SUCCESS ) { return rv; }
+  }    
+
+  if ( rwCallback ) {  
+    (*callBackFunction)(addParams, MSC_PERCENT_STEPSIZE); 
+  }
+
+  return rv;
+}
+
+int bytesToString( MSCString objectString, MSCPUChar8 objBytes ) {
+
+  MSCUShort16 objInt;
+  
+  /* Cryptoflex must truncate objectID's to 16 bits */
+
+  MemCopyTo16(&objInt, objBytes);
+
+  if ( objBytes[0] == 0xFF && objBytes[1] == 0xFE ) {
+    snprintf(objectString, MSC_MAXSIZE_OBJID, "#%X", objInt);
+    return 0;
+  }
+
+  snprintf(objectString, MSC_MAXSIZE_OBJID, "%c%c", objBytes[0],
+	   objBytes[1]);
+  
+  return 0;
+}
+
+int idToString( MSCString objectString, MSCULong32 objectID ) {
+
+  MSCUShort16 objInt;
+  MSCUChar8 objBytes[MSC_MAXSIZE_OBJID];
+
+  objInt = (MSCUShort16)objectID;
+  MemCopy16(objBytes, &objInt);
+
+
+  if ( objBytes[0] == 0xFF && objBytes[1] == 0xFE ) {
+    snprintf(objectString, MSC_MAXSIZE_OBJID, "#%X", objInt);
+    return 0;
+  }
+
+  /* Cryptoflex must truncate objectID's to 16 bits */
+
+  snprintf(objectString, MSC_MAXSIZE_OBJID, "%c%c", objBytes[0],
+	   objBytes[1]);
+
+  return 0;
+}
+
+int stringToID( MSCPUShort16 objectID, MSCString objectString ) {
+
+  MSCUShort16 localID;
+  MSCUChar8 objBytes[MSC_MAXSIZE_OBJID];
+
+  localID = 0;
+
+  if ( strncmp(CRYPTOFLEX_INFOBJ_ID, objectString, 
+	       MSC_MAXSIZE_OBJID) == 0 ) {
+    *objectID = 0xFFFE;
+    return 0;
+  } else if ( strncmp("#0x0011", objectString,
+	       MSC_MAXSIZE_OBJID) == 0 ) { 
+    *objectID = 0x0011;
+    return 0;
+  } else if ( strncmp("#0x0012", objectString,
+		      MSC_MAXSIZE_OBJID) == 0 ) { 
+    *objectID = 0x0012;
+    return 0;
+  } else if ( strncmp("#0x1012", objectString,
+		      MSC_MAXSIZE_OBJID) == 0 ) { 
+    *objectID = 0x1012;
+    return 0;
+  } 
+
+  if (strlen(objectString) > CF_SIZEOF_OBJID) {
+    return -1;
+  }
+
+  objBytes[0] = objectString[0];
+  objBytes[1] = objectString[1];
+    
+  if (strlen(objectString) == 1) {
+    objBytes[1] = 0x00; /* PAD with 0x00 */
+  }
+
+  MemCopyTo16(&localID, objBytes);
+
+  if ( localID == 0 ) {
+    return -1;
+  }
+
+  *objectID = (MSCUShort16)localID;
+  return 0;
+}
+
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCSelect(MSCLPTokenConnection pConnection,
+                 MSCULong32 fileID) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+  MSCULong32 currentPointer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA] = CLA_C0;
+  pBuffer[OFFSET_INS] = 0xA4;
+  pBuffer[OFFSET_P1]  = 0x00;
+  pBuffer[OFFSET_P2]  = 0x00;
+  pBuffer[OFFSET_P3]  = 0x02;
+
+  currentPointer = 0;
+
+  pBuffer[OFFSET_DATA+currentPointer] = fileID / 256;
+  currentPointer++;
+  pBuffer[OFFSET_DATA+currentPointer] = fileID % 256;
+  currentPointer++;
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_P3] + 5;
+  
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+
+  suppressResponse = 1;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  suppressResponse = 0;
+
+  if(rv != SCARD_S_SUCCESS) {
+    return convertPCSC(rv);
+  }
+
+  if(transmitBuffer.apduResponseSize == 2) {
+    if(apduResponse[0] == 0x61) {
+      return MSC_SUCCESS;
+    } else {
+      return convertSW(apduResponse);
+    }
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCGetResponse(MSCLPTokenConnection pConnection, MSCUChar8 len, 
+		      MSCPUChar8 buf)
+{
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse;
+  MSCPUChar8 pBuffer;
+  MSCULong32 currentPointer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA] = CLA_C0;
+  pBuffer[OFFSET_INS] = 0xC0;
+  pBuffer[OFFSET_P1]  = 0x00;
+  pBuffer[OFFSET_P2]  = 0x00;
+  pBuffer[OFFSET_P3]  = len;
+
+  currentPointer = 0;
+
+  transmitBuffer.bufferSize = 5;
+
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU(pConnection, &transmitBuffer);
+  
+  if(rv != SCARD_S_SUCCESS) {
+    return convertPCSC(rv);
+  }
+
+  if(transmitBuffer.apduResponseSize == 2) {
+    return convertSW(apduResponse);
+  } else if(transmitBuffer.apduResponseSize == len + 2){
+    memcpy(buf, apduResponse, len);
+    currentPointer += len;
+    return convertSW(&apduResponse[currentPointer]);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+MSCUShort16 convertSW(MSCPUChar8 pBuffer) {
+  MSCUShort16 retValue;
+  MSCUShort16 newValue;
+
+  retValue  = pBuffer[0] * 0x100;
+  retValue += pBuffer[1];
+
+  switch(retValue) {
+  case CFMSC_SUCCESS:
+    newValue = MSC_SUCCESS;
+    break;
+  case CFMSC_NO_MEMORY_LEFT:
+  case CFMSC_NO_MEMORY_LEFT_1:
+    newValue = MSC_NO_MEMORY_LEFT;
+    break;
+  case CFMSC_AUTH_FAILED:
+    newValue = MSC_AUTH_FAILED;
+    break;
+  case CFMSC_OPERATION_NOT_ALLOWED:
+    newValue = MSC_OPERATION_NOT_ALLOWED;
+    break;
+  case CFMSC_INCONSISTENT_STATUS:
+    newValue = MSC_INCONSISTENT_STATUS;
+    break;
+  case CFMSC_UNSUPPORTED_FEATURE:
+    newValue = MSC_UNSUPPORTED_FEATURE;
+    break;
+  case CFMSC_UNAUTHORIZED:
+    newValue = MSC_UNAUTHORIZED;
+    break;
+  case CFMSC_OBJECT_NOT_FOUND:
+    newValue = MSC_OBJECT_NOT_FOUND;
+    break;
+  case CFMSC_OBJECT_EXISTS:
+    newValue = MSC_OBJECT_EXISTS;
+    break;
+  case CFMSC_INCORRECT_ALG:
+    newValue = MSC_INCORRECT_ALG;
+    break;
+  case CFMSC_SIGNATURE_INVALID:
+    newValue = MSC_SIGNATURE_INVALID;
+    break;
+  case CFMSC_IDENTITY_BLOCKED:
+    newValue = MSC_IDENTITY_BLOCKED;
+    break;
+  case CFMSC_UNSPECIFIED_ERROR:
+    newValue = MSC_UNSPECIFIED_ERROR;
+    break;
+  case CFMSC_TRANSPORT_ERROR:
+    newValue = MSC_TRANSPORT_ERROR;
+    break;
+  case CFMSC_INVALID_PARAMETER:
+    newValue = MSC_INVALID_PARAMETER;
+    break;
+  case CFMSC_SEQUENCE_END:
+    newValue = MSC_SEQUENCE_END;
+    break;
+  case CFMSC_INTERNAL_ERROR:
+    newValue = MSC_INTERNAL_ERROR;
+    break;
+  case CFMSC_CANCELLED:
+    newValue = MSC_CANCELLED;
+    break;
+  default:
+    newValue = retValue;
+    break;
+  }
+
+  return newValue;
+}
+
+void MemCopy16(MSCPUChar8 destValue, MSCPUShort16 srcValue) {
+  destValue[0] = (*srcValue & 0xFF00) >> 8;
+  destValue[1] = (*srcValue & 0x00FF);
+}
+
+void MemCopy32(MSCPUChar8 destValue, MSCPULong32 srcValue) {
+  destValue[0] = (*srcValue >> 24);
+  destValue[1] = (*srcValue & 0x00FF0000) >> 16;
+  destValue[2] = (*srcValue & 0x0000FF00) >> 8;
+  destValue[3] = (*srcValue & 0x000000FF);
+}
+
+void MemCopyTo16(MSCPUShort16 destValue, MSCPUChar8 srcValue) {
+
+  *destValue  = srcValue[0] * 0x100;
+  *destValue += srcValue[1];
+
+}
+
+void MemCopyTo32(MSCPULong32 destValue, MSCPUChar8 srcValue) {
+
+  *destValue  = srcValue[0] * 0x1000000;
+  *destValue += srcValue[1] * 0x10000;
+  *destValue += srcValue[2] * 0x100;
+  *destValue += srcValue[3];
+
+}
+
+MSCUShort16 getUShort16(MSCPUChar8 srcValue) {
+  return ( (((MSCUShort16)srcValue[0]) << 8) || srcValue[1] );
+}
+
+void setUShort16(MSCPUChar8 dstValue, MSCUShort16 srcValue) {
+  MemCopyTo16(&srcValue, dstValue);
+}
+
+
+MSCLong32 SCardExchangeAPDU( MSCLPTokenConnection pConnection, 
+			     MSCLPTransmitBuffer transmitBuffer ) {
+  
+  MSCLong32 rv, ret;
+  MSCULong32 originalLength;
+  MSCUChar8 getResponse[5] = {0xC0, 0xC0, 0x00, 0x00, 0x00};
+  MSCULong32 dwActiveProtocol;
+
+#ifdef MSC_DEBUG
+  int i;
+#endif
+
+  originalLength = transmitBuffer->apduResponseSize;
+
+  while (1) {
+    
+#ifdef MSC_DEBUG
+    printf("->: ");
+    
+    for (i=0; i < transmitBuffer->bufferSize; i++) {
+      printf("%02x ", transmitBuffer->pBuffer[i]);
+    } printf("\n");
+#endif
+    
+    while(1) {
+      transmitBuffer->apduResponseSize = originalLength;
+      
+      rv =  SCardTransmit(pConnection->hCard, pConnection->ioType,
+			  transmitBuffer->pBuffer, 
+			  transmitBuffer->bufferSize, 0,
+			  transmitBuffer->apduResponse, 
+			  &transmitBuffer->apduResponseSize );
+      
+      if ( rv == SCARD_S_SUCCESS ) {
+	break;
+	
+      } else if ( rv == SCARD_W_RESET_CARD ) {
+	pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
+	ret = SCardReconnect(pConnection->hCard, pConnection->shareMode, 
+			     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			     SCARD_LEAVE_CARD, &dwActiveProtocol );
+	
+	PL_MSCIdentifyToken(pConnection);
+	
+	if ( ret == SCARD_S_SUCCESS ) {
+	  continue;
+	}
+	
+      } else if ( rv == SCARD_W_REMOVED_CARD ) {
+	/* Push REMOVED_TOKEN back to the application */
+	pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
+	return rv;
+      } else {
+	/* Must be a BIG, BAD, ERROR */
+#ifdef MSC_DEBUG
+	printf("Transmit error: %s\n", pcsc_stringify_error(rv));
+#endif
+	return rv;
+      }
+    }
+    
+#ifdef MSC_DEBUG
+    printf("<-: ");
+    
+    for (i=0; i < transmitBuffer->apduResponseSize; i++) {
+      printf("%02x ", transmitBuffer->apduResponse[i]);
+    } printf("\n");
+#endif
+    
+    if ( suppressResponse == 1 ) {
+      /* Do not do the Get Response */
+      break;
+    }
+
+    if ( transmitBuffer->apduResponseSize == 2 && 
+	 transmitBuffer->apduResponse[0] == 0x61 ) {
+#ifdef MSC_DEBUG
+      printf("->: 0xC0 0xC0 0x00 0x00 %02x\n", 
+	     transmitBuffer->apduResponse[1]);
+#endif
+      getResponse[4] = transmitBuffer->apduResponse[1];
+      transmitBuffer->apduResponseSize   = originalLength;
+      rv =  SCardTransmit(pConnection->hCard, pConnection->ioType,
+			  getResponse, 5, 0,
+			  transmitBuffer->apduResponse, 
+			  &transmitBuffer->apduResponseSize );
+      
+      if ( rv == SCARD_S_SUCCESS ) {
+#ifdef MSC_DEBUG	
+	printf("<-: ");
+	
+	for (i=0; i < transmitBuffer->apduResponseSize; i++) {
+	  printf("%02x ", transmitBuffer->apduResponse[i]);
+	} printf("\n");
+#endif
+	break;
+      } else if ( rv == SCARD_W_RESET_CARD ) {
+	pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
+	ret = SCardReconnect(pConnection->hCard, pConnection->shareMode, 
+			     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			     SCARD_LEAVE_CARD, &dwActiveProtocol );
+	
+	PL_MSCIdentifyToken(pConnection);
+	
+	if ( ret == SCARD_S_SUCCESS ) {
+	  continue;
+	}
+	
+      } else if ( rv == SCARD_W_REMOVED_CARD ) {
+	/* Push REMOVED_TOKEN back to the application */
+	pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
+	return rv;
+      } else {
+#ifdef MSC_DEBUG
+	printf("Transmit error: %s\n", pcsc_stringify_error(rv));
+#endif
+	return rv;
+      } 
+    }         
+
+    break;
+  }  /* End of while */
+  
+  
+  return rv;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCIdentifyToken( MSCLPTokenConnection pConnection ) {
+
+  MSCLong32 rv;
+ 
+  rv = PL_MSCSelect(pConnection, 0x3F00);
+  rv = PL_MSCSelect(pConnection, 0x3FCE);
+
+  pConnection->loggedIDs = 0;
+
+  return rv;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCFinalizePlugin( MSCLPTokenConnection pConnection ) {
+
+  return MSC_SUCCESS;
+}
+
+#ifdef WIN32
+CFLEXPLUGIN_API
+#endif
+MSC_RV PL_MSCInitializePlugin( MSCLPTokenConnection pConnection ) {
+
+  return MSC_SUCCESS;
+}
+
+
+MSC_RV convertPCSC( MSCLong32 pcscCode ) {
+
+  switch(pcscCode) {
+  case SCARD_S_SUCCESS:
+    return MSC_SUCCESS;
+  case SCARD_E_INVALID_HANDLE:
+    return MSC_INVALID_HANDLE;
+  case SCARD_E_SHARING_VIOLATION:
+    return MSC_SHARING_VIOLATION;
+  case SCARD_W_REMOVED_CARD:
+    return MSC_TOKEN_REMOVED;
+  case SCARD_E_NO_SMARTCARD:
+    return MSC_TOKEN_REMOVED;
+  case SCARD_W_RESET_CARD:
+    return MSC_TOKEN_RESET;
+  case SCARD_W_INSERTED_CARD:
+    return MSC_TOKEN_INSERTED;
+  case SCARD_E_NO_SERVICE:
+    return MSC_SERVICE_UNRESPONSIVE;
+  case SCARD_E_UNKNOWN_CARD:
+  case SCARD_W_UNSUPPORTED_CARD:
+  case SCARD_E_CARD_UNSUPPORTED:
+    return MSC_UNRECOGNIZED_TOKEN;
+  case SCARD_E_INVALID_PARAMETER:
+  case SCARD_E_INVALID_VALUE:
+  case SCARD_E_UNKNOWN_READER:
+  case SCARD_E_PROTO_MISMATCH:
+  case SCARD_E_READER_UNAVAILABLE:
+    return MSC_INVALID_PARAMETER;
+  case SCARD_E_CANCELLED:
+    return MSC_CANCELLED;
+  case SCARD_E_TIMEOUT:
+    return MSC_TIMEOUT_OCCURRED;
+
+  default:
+    return MSC_INTERNAL_ERROR;
+  }
+}

Added: trunk/SmartCardServices/src/CFlexPlugin/cryptoflex.h
===================================================================
--- trunk/SmartCardServices/src/CFlexPlugin/cryptoflex.h	                        (rev 0)
+++ trunk/SmartCardServices/src/CFlexPlugin/cryptoflex.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : cryptoflex.h
+            Package: card edge
+            Author : David Corcoran
+            Date   : 10/02/01
+            License: Copyright (C) 2001 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This abstracts the MUSCLE Card Edge Inteface
+ 
+ 
+********************************************************************/
+
+#ifndef __cryptoflex_h__
+#define __cryptoflex_h__
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+#define CLA_F0          0xF0
+#define CLA_C0          0xC0
+
+/* Some useful offsets in the buffer */
+#define OFFSET_CLA	0x00
+#define OFFSET_INS	0x01
+#define OFFSET_P1	0x02
+#define OFFSET_P2	0x03
+#define OFFSET_P3	0x04
+#define OFFSET_DATA	0x05
+
+#define OFFSET_ENCODING 0x00
+#define OFFSET_KEYTYPE  0x01
+#define OFFSET_KEYSIZE  0x02
+#define OFFSET_KEYDATA  0x04
+
+#define CF_SIZEOF_MSBLEN        1
+#define CF_SIZEOF_LSBLEN        1
+#define CF_SIZEOF_KEYNUM        1
+#define CF_SIZEOF_OBJID         2
+
+/* Defines for 1024 bit RSA keys */
+#define CF_1024_FULLSIZE    0x143
+#define CF_1024_FULLSIZE_1   0x01
+#define CF_1024_FULLSIZE_2   0x43
+#define CF_1024P_FULLSIZE   0x147
+
+#define CF_1024_COMPSIZE     0x40
+
+#define CF_1024_KEYSIZE      1024
+#define CF_1024P_MODSIZE      128
+#define CF_1024P_EXPSIZE        4
+#define CF_1024P_MOD            3
+#define CF_1024P_EXP          323
+
+#define MC_1024P_FULLSIZE     140
+#define MC_SIZEOF_COMPSIZE      2
+#define MC_1024_OFFSET_P        4
+#define MC_1024_OFFSET_Q       70
+#define MC_1024_OFFSET_PQ     136
+#define MC_1024_OFFSET_DP1    202
+#define MC_1024_OFFSET_DQ1    268
+
+
+#define MC_1024P_MOD            4
+#define MC_1024P_EXP          134
+#define MC_1024P_MODSIZE      128
+
+
+#define CF_DES_OFFSET_UKEY   0x19
+#define MC_DES_OFFSET_KEY       4
+
+    /* Sizes of particular objects */
+#define MSC_SIZEOF_OBJECTID               4
+#define MSC_SIZEOF_OBJECTSIZE             4
+#define MSC_SIZEOF_KEYINFO                16
+#define MSC_SIZEOF_STATUS                 16
+#define MSC_SIZEOF_VERSION                2
+#define MSC_SIZEOF_FREEMEM                4
+#define MSC_SIZEOF_LOGIDS                 2
+#define MSC_SIZEOF_ADDINFO                8
+#define MSC_SIZEOF_OPTLEN                 2
+#define MSC_SIZEOF_GENOPTIONS             1
+#define MSC_SIZEOF_KEYSIZE                2
+#define MSC_SIZEOF_KEYNUMBER              1
+#define MSC_SIZEOF_KEYTYPE                1
+#define MSC_SIZEOF_KEYPARTNER             1
+#define MSC_SIZEOF_POLICYVALUE            2
+#define MSC_SIZEOF_KEYMAPPING             1
+#define MSC_SIZEOF_CIPHERMODE             1
+#define MSC_SIZEOF_CIPHERDIR              1
+#define MSC_SIZEOF_CRYPTLEN               2
+#define MSC_SIZEOF_ALGOTYPE               1
+#define MSC_SIZEOF_IDUSED                 1
+#define MSC_SIZEOF_OFFSET                 4
+#define MSC_SIZEOF_ACLSTRUCT              6
+#define MSC_SIZEOF_RWDATA                 1
+#define MSC_SIZEOF_PINSIZE                1
+#define MSC_SIZEOF_CIPHERMODE             1
+#define MSC_SIZEOF_CIPHERDIR              1
+#define MSC_SIZEOF_DATALOCATION           1
+#define MSC_SIZEOF_ACLVALUE               2
+#define MSC_SIZEOF_SEEDLENGTH             2
+#define MSC_SIZEOF_RANDOMSIZE             2
+
+    // Keys' use and management
+#define INS_MSC_GEN_KEYPAIR     0x46
+#define INS_IMPORT_KEY      0x32
+#define INS_EXPORT_KEY      0x34
+#define INS_COMPUTE_CRYPT   0x88
+
+    // External authentication
+#define INS_CREATE_PIN      0x40
+#define INS_VERIFY_PIN      0x20
+#define INS_CHANGE_PIN      0x24
+#define INS_UNBLOCK_PIN     0x2C
+#define INS_LOGOUT_ALL      0x22
+#define INS_GET_CHALLENGE   0x84
+#define INS_EXT_AUTH        0x82
+
+    // Objects' use and management
+#define INS_CREATE_OBJ      0xE0
+#define INS_DELETE_OBJ      0xE4
+#define INS_READ_OBJ        0xB0
+#define INS_WRITE_OBJ       0xD6
+
+    // Status information
+#define INS_LIST_OBJECTS    0xA8
+#define INS_LIST_PINS       0x48
+#define INS_LIST_KEYS       0x3A
+#define INS_GET_STATUS      0x3C
+
+    /** success */
+#define CFMSC_SUCCESS                        0x9000
+
+    /** There have been memory problems on the card */
+#define CFMSC_NO_MEMORY_LEFT                 0x6A84
+#define CFMSC_NO_MEMORY_LEFT_1               0x6A83
+    /** Entered PIN is not correct */
+#define CFMSC_AUTH_FAILED                    0x6300
+    /** Required operation is not allowed in actual circumstances */
+#define CFMSC_OPERATION_NOT_ALLOWED          0x9C03
+    /** Required operation is inconsistent with memory contents */
+#define CFMSC_INCONSISTENT_STATUS            0x9C04
+    /** Required feature is not (yet) supported */
+#define CFMSC_UNSUPPORTED_FEATURE            0x6D00
+    /** Required operation was not authorized because of a lack of privileges */
+#define CFMSC_UNAUTHORIZED                   0x6982
+    /** Required object is missing */
+#define CFMSC_OBJECT_NOT_FOUND               0x6A82
+    /** New object ID already in use */
+#define CFMSC_OBJECT_EXISTS                  0x6A80
+    /** Algorithm specified is not correct */
+#define CFMSC_INCORRECT_ALG                  0x6981
+    
+    /** Verify operation detected an invalid signature */
+#define CFMSC_SIGNATURE_INVALID              0x9C0B
+    /** Operation has been blocked for security reason  */
+#define CFMSC_IDENTITY_BLOCKED               0x6983
+    /** Unspecified error */
+#define CFMSC_UNSPECIFIED_ERROR              0x6F00
+    /** PCSC and driver transport errors */
+#define CFMSC_TRANSPORT_ERROR                0x9C0E
+    /** Invalid parameter given */
+#define CFMSC_INVALID_PARAMETER              0x6B00
+    /** Incorrect P1 parameter */
+#define CFMSC_INCORRECT_P1                   0x6B00
+    /** Incorrect P2 parameter */
+#define CFMSC_INCORRECT_P2                   0x6B00
+    /** End of sequence */
+#define CFMSC_SEQUENCE_END                   0x9C12
+    /** For debugging purposes */
+#define CFMSC_INTERNAL_ERROR                 0x6581
+    
+
+#define CFMSC_CANCELLED                      0x9C50
+
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif /* __cryptoflex_h__ */

Added: trunk/SmartCardServices/src/GSCISPlugin/GSCISPlugin.c
===================================================================
--- trunk/SmartCardServices/src/GSCISPlugin/GSCISPlugin.c	                        (rev 0)
+++ trunk/SmartCardServices/src/GSCISPlugin/GSCISPlugin.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,372 @@
+/******************************************************************
+ GSCIS
+        MUSCLE SmartCard Development ( http://www.musclecard.com )
+            Title  : GSCISPlugin.c
+            Package: GSCISPlugin
+            Author : David Corcoran
+            Date   : 02/19/02
+            License: Copyright (C) 2002 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: A MuscleCard plugin for GSCIS compliant cards.
+	             
+ 
+********************************************************************/
+
+#ifndef __APPLE__
+#include <musclecard.h>
+#else
+#include <PCSC/musclecard.h>
+#endif
+
+#include "GSCISPlugin.h"
+#include <string.h>
+#include <stdio.h>
+
+
+typedef struct {
+  MSCUChar8  pBuffer[MAX_BUFFER_SIZE];
+  MSCULong32 bufferSize;
+  MSCUChar8  apduResponse[MAX_BUFFER_SIZE];
+  MSCULong32 apduResponseSize;
+  LPSCARD_IO_REQUEST ioType;
+} MSCTransmitBuffer, *MSCLPTransmitBuffer;
+
+/* internal function */
+MSCLong32 SCardExchangeAPDU( MSCLPTokenConnection, MSCLPTransmitBuffer );
+MSC_RV convertPCSC( MSCLong32 );
+
+MSC_RV PL_MSCWriteFramework( MSCLPTokenConnection pConnection,
+			  MSCLPInitTokenParams pInitParams ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCSelectAID( MSCLPTokenConnection pConnection, MSCPUChar8 aidValue,
+  	             MSCULong32 aidSize ) {
+
+  /* Make sure the right card is there, select the specified applet
+     if needed.  If no applet specified, select the default applet
+  */
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCInitializePlugin( MSCLPTokenConnection pConnection ) {
+
+  return MSC_SUCCESS;
+}
+
+MSC_RV PL_MSCFinalizePlugin( MSCLPTokenConnection pConnection ) {
+
+  return MSC_SUCCESS;
+}
+
+MSC_RV PL_MSCIdentifyToken( MSCLPTokenConnection pConnection ) {
+
+  return MSC_SUCCESS;
+}
+
+MSC_RV PL_MSCGetStatus( MSCLPTokenConnection pConnection, 
+		     MSCLPStatusInfo pStatusInfo ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCGetCapabilities( MSCLPTokenConnection pConnection, MSCULong32 Tag,
+			   MSCPUChar8 Value, MSCPULong32 Length ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCExtendedFeature( MSCLPTokenConnection pConnection, 
+			   MSCULong32 extFeature,
+			   MSCPUChar8 outData, MSCULong32 outLength, 
+			   MSCPUChar8 inData, MSCPULong32 inLength ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCGenerateKeys( MSCLPTokenConnection pConnection, MSCUChar8 prvKeyNum,
+			MSCUChar8 pubKeyNum, MSCLPGenKeyParams pParams ) {
+ 
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCImportKey( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+		     MSCLPKeyACL pKeyACL, MSCPUChar8 pKeyBlob, 
+		     MSCULong32 keyBlobSize, MSCLPKeyPolicy keyPolicy,
+		     MSCPVoid32 pAddParams, MSCUChar8 addParamsSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+ 
+MSC_RV PL_MSCExportKey( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+		     MSCPUChar8 pKeyBlob, MSCPULong32 keyBlobSize, 
+		     MSCPVoid32 pAddParams, MSCUChar8 addParamsSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCComputeCrypt( MSCLPTokenConnection pConnection,
+			MSCLPCryptInit cryptInit, MSCPUChar8 pInputData,
+			MSCULong32 inputDataSize, MSCPUChar8 pOutputData,
+			MSCPULong32 outputDataSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCExtAuthenticate( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+			   MSCUChar8 cipherMode, MSCUChar8 cipherDirection,
+			   MSCPUChar8 pData, MSCULong32 dataSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCListKeys( MSCLPTokenConnection pConnection, MSCUChar8 seqOption,
+		    MSCLPKeyInfo pKeyInfo ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCCreatePIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+		     MSCUChar8 pinAttempts, MSCPUChar8 pPinCode,
+		     MSCULong32 pinCodeSize, MSCPUChar8 pUnblockCode,
+		     MSCUChar8 unblockCodeSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCVerifyPIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+		     MSCPUChar8 pPinCode, MSCULong32 pinCodeSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCChangePIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+		     MSCPUChar8 pOldPinCode, MSCUChar8 oldPinCodeSize,
+		     MSCPUChar8 pNewPinCode, MSCUChar8 newPinCodeSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCUnblockPIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+		      MSCPUChar8 pUnblockCode, MSCULong32 unblockCodeSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCListPINs( MSCLPTokenConnection pConnection, 
+		    MSCPUShort16 pPinBitMask ) {
+
+  
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCCreateObject( MSCLPTokenConnection pConnection, MSCString objectID,
+			MSCULong32 objectSize, MSCLPObjectACL pObjectACL ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCDeleteObject( MSCLPTokenConnection pConnection, 
+			MSCString objectID, MSCUChar8 zeroFlag ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCWriteObject( MSCLPTokenConnection pConnection, MSCString objectID, 
+		       MSCULong32 offset, MSCPUChar8 pInputData, 
+		       MSCUChar8 dataSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCReadObject( MSCLPTokenConnection pConnection, MSCString objectID, 
+		      MSCULong32 offset, MSCPUChar8 pOutputData, 
+		      MSCUChar8 dataSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCListObjects( MSCLPTokenConnection pConnection, MSCUChar8 seqOption, 
+                       MSCLPObjectInfo pObjectInfo ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCLogoutAll( MSCLPTokenConnection pConnection ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCGetChallenge( MSCLPTokenConnection pConnection, MSCPUChar8 pSeed,
+			MSCUShort16 seedSize, MSCPUChar8 pRandomData,
+			MSCUShort16 randomDataSize ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+
+
+MSCLong32 SCardExchangeAPDU( MSCLPTokenConnection pConnection, 
+			     MSCLPTransmitBuffer transmitBuffer ) {
+  
+  MSCLong32 rv, ret;
+  MSCULong32 originalLength;
+  MSCUChar8 getResponse[5] = {0x00, 0xC0, 0x00, 0x00, 0x00};
+  MSCULong32 dwActiveProtocol;
+
+  originalLength = transmitBuffer->apduResponseSize;
+
+  while (1) {
+    
+#ifdef MSC_DEBUG
+    printf("->: ");
+    for (i=0; i < transmitBuffer->bufferSize; i++) {
+      printf("%02x ", transmitBuffer->pBuffer[i]);
+    } printf("\n");
+#endif
+    
+    while(1) {
+      transmitBuffer->apduResponseSize = originalLength;
+      
+      rv =  SCardTransmit(pConnection->hCard, pConnection->ioType,
+			  transmitBuffer->pBuffer, 
+			  transmitBuffer->bufferSize, 0,
+			  transmitBuffer->apduResponse, 
+			  &transmitBuffer->apduResponseSize );
+      
+      if ( rv == SCARD_S_SUCCESS ) {
+	break;
+	
+      } else if ( rv == SCARD_W_RESET_CARD ) {
+	pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
+	ret = SCardReconnect(pConnection->hCard, pConnection->shareMode, 
+			     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			     SCARD_LEAVE_CARD, &dwActiveProtocol );
+	
+	PL_MSCIdentifyToken(pConnection);
+	
+	if ( ret == SCARD_S_SUCCESS ) {
+	  continue;
+	}
+	
+      } else if ( rv == SCARD_W_REMOVED_CARD ) {
+	/* Push REMOVED_TOKEN back to the application */
+	pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
+	return rv;
+      } else {
+	/* Must be a BIG, BAD, ERROR */
+#ifdef MSC_DEBUG
+	printf("Transmit error: %s\n", pcsc_stringify_error(rv));
+#endif
+	return rv;
+      }
+    }
+    
+#ifdef MSC_DEBUG
+    printf("<-: ");
+    
+    for (i=0; i < transmitBuffer->apduResponseSize; i++) {
+      printf("%02x ", transmitBuffer->apduResponse[i]);
+    } printf("\n");
+#endif
+
+#ifdef MSC_NOT_DEFINED    
+    if ( suppressResponse == 1 ) {
+      /* Do not do the Get Response */
+      break;
+    }
+#endif
+
+    if ( transmitBuffer->apduResponseSize == 2 && 
+	 transmitBuffer->apduResponse[0] == 0x61 ) {
+#ifdef MSC_DEBUG
+      printf("->: 0x00 0xC0 0x00 0x00 %02x\n", 
+	     transmitBuffer->apduResponse[1]);
+#endif
+      getResponse[4] = transmitBuffer->apduResponse[1];
+      transmitBuffer->apduResponseSize   = originalLength;
+      rv =  SCardTransmit(pConnection->hCard, pConnection->ioType,
+			  getResponse, 5, 0,
+			  transmitBuffer->apduResponse, 
+			  &transmitBuffer->apduResponseSize );
+      
+      if ( rv == SCARD_S_SUCCESS ) {
+#ifdef MSC_DEBUG	
+	printf("<-: ");
+	
+	for (i=0; i < transmitBuffer->apduResponseSize; i++) {
+	  printf("%02x ", transmitBuffer->apduResponse[i]);
+	} printf("\n");
+#endif
+	break;
+      } else if ( rv == SCARD_W_RESET_CARD ) {
+	pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
+	ret = SCardReconnect(pConnection->hCard, pConnection->shareMode, 
+			     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			     SCARD_LEAVE_CARD, &dwActiveProtocol );
+
+	PL_MSCIdentifyToken(pConnection);	
+	
+	if ( ret == SCARD_S_SUCCESS ) {
+	  continue;
+	}
+	
+      } else if ( rv == SCARD_W_REMOVED_CARD ) {
+	/* Push REMOVED_TOKEN back to the application */
+	pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
+	return rv;
+      } else {
+#ifdef MSC_DEBUG
+	printf("Transmit error: %s\n", pcsc_stringify_error(rv));
+#endif
+	return rv;
+      } 
+    }         
+
+    break;
+  }  /* End of while */
+  
+  
+  return rv;
+}
+
+MSC_RV convertPCSC( MSCLong32 pcscCode ) {
+
+  switch(pcscCode) {
+  case SCARD_S_SUCCESS:
+    return MSC_SUCCESS;
+  case SCARD_E_INVALID_HANDLE:
+    return MSC_INVALID_HANDLE;
+  case SCARD_E_SHARING_VIOLATION:
+    return MSC_SHARING_VIOLATION;
+  case SCARD_W_REMOVED_CARD:
+    return MSC_TOKEN_REMOVED;
+  case SCARD_E_NO_SMARTCARD:
+    return MSC_TOKEN_REMOVED;
+  case SCARD_W_RESET_CARD:
+    return MSC_TOKEN_RESET;
+  case SCARD_W_INSERTED_CARD:
+    return MSC_TOKEN_INSERTED;
+  case SCARD_E_NO_SERVICE:
+    return MSC_SERVICE_UNRESPONSIVE;
+  case SCARD_E_UNKNOWN_CARD:
+  case SCARD_W_UNSUPPORTED_CARD:
+  case SCARD_E_CARD_UNSUPPORTED:
+    return MSC_UNRECOGNIZED_TOKEN;
+  case SCARD_E_INVALID_PARAMETER:
+  case SCARD_E_INVALID_VALUE:
+  case SCARD_E_UNKNOWN_READER:
+  case SCARD_E_PROTO_MISMATCH:
+  case SCARD_E_READER_UNAVAILABLE:
+    return MSC_INVALID_PARAMETER;
+  case SCARD_E_CANCELLED:
+    return MSC_CANCELLED;
+  case SCARD_E_TIMEOUT:
+    return MSC_TIMEOUT_OCCURRED;
+
+  default:
+    return MSC_INTERNAL_ERROR;
+  }
+}

Added: trunk/SmartCardServices/src/GSCISPlugin/GSCISPlugin.h
===================================================================
--- trunk/SmartCardServices/src/GSCISPlugin/GSCISPlugin.h	                        (rev 0)
+++ trunk/SmartCardServices/src/GSCISPlugin/GSCISPlugin.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,35 @@
+/******************************************************************
+ GSCIS
+        MUSCLE SmartCard Development ( http://www.musclecard.com )
+            Title  : GSCISPlugin.h
+            Package: GSCISPlugin
+            Author : David Corcoran
+            Date   : 02/19/02
+            License: Copyright (C) 2002 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: A MuscleCard plugin for GSCIS compliant cards.
+ 
+ 
+********************************************************************/
+
+#ifndef __GSCISPlugin_h__
+#define __GSCISPlugin_h__
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/* Some useful offsets in the buffer */
+#define OFFSET_CLA	0x00
+#define OFFSET_INS	0x01
+#define OFFSET_P1	0x02
+#define OFFSET_P2	0x03
+#define OFFSET_P3	0x04
+#define OFFSET_DATA	0x05
+
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif /* __GSCISPlugin_h__ */

Added: trunk/SmartCardServices/src/MCardPlugin/musclecardApplet.c
===================================================================
--- trunk/SmartCardServices/src/MCardPlugin/musclecardApplet.c	                        (rev 0)
+++ trunk/SmartCardServices/src/MCardPlugin/musclecardApplet.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,2214 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : musclecardApplet.c
+            Package: MuscleCard Plugin
+            Author : David Corcoran
+	             Tommaso Cucinotta
+            Date   : 09/26/01
+            License: Copyright (C) 2001-2002 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This abstracts the Card Edge Interface APDU's
+	             into client side function calls.
+ 
+********************************************************************/
+#ifdef WIN32
+#include "../win32/MCardPlugin.h"
+#endif
+
+#ifndef __APPLE__
+#include <musclecard.h>
+#else
+#include <PCSC/musclecard.h>
+#endif
+
+#include "musclecardApplet.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MSC_DEBUG 1
+
+/* Local transport structure */
+typedef struct {
+  MSCUChar8  pBuffer[MAX_BUFFER_SIZE];
+  MSCULong32 bufferSize;
+  MSCUChar8  apduResponse[MAX_BUFFER_SIZE];
+  MSCULong32 apduResponseSize;
+  LPSCARD_IO_REQUEST ioType;
+} MSCTransmitBuffer, *MSCLPTransmitBuffer;
+
+/* Some locally defined functions */
+
+MSC_RV convertPCSC( MSCLong32 );
+int idToString( char*, MSCULong32 );
+int stringToID( MSCPULong32, char* );
+MSCUShort16 convertSW( MSCPUChar8 );
+void MemCopy16( MSCPUChar8, MSCPUShort16 );
+void MemCopy32( MSCPUChar8, MSCPULong32 );
+void MemCopyTo16( MSCPUShort16, MSCPUChar8 ); 
+void MemCopyTo32( MSCPULong32, MSCPUChar8 );
+MSCUShort16 getUShort16( MSCPUChar8 );
+void setUShort16( MSCPUChar8, MSCUShort16 );
+MSCLong32 SCardExchangeAPDU( MSCLPTokenConnection, MSCLPTransmitBuffer );
+MSC_RV lcMSCGetObjectAttributes( MSCLPTokenConnection, 
+				 MSCString, MSCLPObjectInfo );
+
+/* MSC Functions */
+
+
+MSC_RV PL_MSCGetStatus( MSCLPTokenConnection pConnection, 
+			MSCLPStatusInfo pStatusInfo ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+
+  MSCULong32 currentPointer;
+
+  rv=0; currentPointer=0;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_GET_STATUS;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_STATUS;
+
+  transmitBuffer.bufferSize = 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else if (transmitBuffer.apduResponseSize == pBuffer[OFFSET_LC] + 2 ) {
+    currentPointer = 0;
+    MemCopyTo16(&pStatusInfo->appVersion, &apduResponse[currentPointer]);
+    currentPointer += MSC_SIZEOF_VERSION;
+
+    MemCopyTo16(&pStatusInfo->swVersion, &apduResponse[currentPointer]);
+    currentPointer += MSC_SIZEOF_VERSION;
+    
+    MemCopyTo32(&pStatusInfo->totalMemory, &apduResponse[currentPointer]); 
+    currentPointer += MSC_SIZEOF_FREEMEM;
+
+    MemCopyTo32(&pStatusInfo->freeMemory, &apduResponse[currentPointer]); 
+    currentPointer += MSC_SIZEOF_FREEMEM;
+
+    pStatusInfo->usedPINs = apduResponse[currentPointer];
+    currentPointer += MSC_SIZEOF_IDUSED;
+
+    pStatusInfo->usedKeys = apduResponse[currentPointer];
+    currentPointer += MSC_SIZEOF_IDUSED;
+
+    MemCopyTo16(&pStatusInfo->loggedID, &apduResponse[currentPointer]);
+    currentPointer += MSC_SIZEOF_LOGIDS;
+    
+    return convertSW(&apduResponse[currentPointer]);
+
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCGetCapabilities( MSCLPTokenConnection pConnection, MSCULong32 Tag,
+			      MSCPUChar8 Value, MSCPULong32 Length ) {
+ 
+  MSCULong32  ulValue;
+  MSCUShort16 usValue;
+  MSCUChar8  ucValue;
+  MSCUChar8  tagType;
+
+  /* 4 - MSCULong32, 2 - MSCUShort16, 1 - MSCUChar8 */
+
+  ulValue = 0; usValue = 0; ucValue = 0; tagType = 0;
+
+  switch(Tag) {
+
+  case MSC_TAG_SUPPORT_FUNCTIONS:
+    ulValue = MSC_SUPPORT_GENKEYS | MSC_SUPPORT_IMPORTKEY |
+      MSC_SUPPORT_EXPORTKEY | MSC_SUPPORT_COMPUTECRYPT | 
+      MSC_SUPPORT_EXTAUTH | MSC_SUPPORT_LISTKEYS |
+      MSC_SUPPORT_CREATEPIN |
+      MSC_SUPPORT_VERIFYPIN | MSC_SUPPORT_CHANGEPIN | 
+      MSC_SUPPORT_UNBLOCKPIN | MSC_SUPPORT_LISTPINS | 
+      MSC_SUPPORT_CREATEOBJECT | MSC_SUPPORT_DELETEOBJECT | 
+      MSC_SUPPORT_WRITEOBJECT | MSC_SUPPORT_READOBJECT |
+      MSC_SUPPORT_LISTOBJECTS | MSC_SUPPORT_LOGOUTALL |
+      MSC_SUPPORT_GETCHALLENGE;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_SUPPORT_CRYPTOALG:
+    ulValue = MSC_SUPPORT_RSA | 
+      MSC_SUPPORT_DES | MSC_SUPPORT_3DES;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_RSA:
+    ulValue = MSC_CAPABLE_RSA_1024 | MSC_CAPABLE_RSA_768 |
+      MSC_CAPABLE_RSA_NOPAD | MSC_CAPABLE_RSA_KEYGEN;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_DES:
+    ulValue = MSC_CAPABLE_DES_ECB;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_3DES:
+    ulValue = 0;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_ATTR:
+    ulValue = MSC_CAPABLE_OBJ_ZERO;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_IDSIZE:
+    ucValue = 4;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_AUTH:
+    usValue = MSC_AUT_ALL;
+    tagType = 2;
+    break;
+
+  case MSC_TAG_CAPABLE_OBJ_MAXNUM:
+    ulValue = 100;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_ATTR:
+    ulValue = MSC_CAPABLE_PIN_LEAVE;
+    tagType = 4;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MAXNUM:
+    ucValue = 8;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MINSIZE:
+    ucValue = 4;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_MAXSIZE:
+    ucValue = 8;
+    tagType = 1;
+    break;
+    
+  case MSC_TAG_CAPABLE_PIN_CHARSET:
+    ulValue = MSC_CAPABLE_PIN_A_Z | MSC_CAPABLE_PIN_a_z | 
+      MSC_CAPABLE_PIN_0_9 | MSC_CAPABLE_PIN_CALC | MSC_CAPABLE_PIN_NONALPHA;
+    tagType = 4;
+    break;
+
+ case MSC_TAG_CAPABLE_PIN_POLICY:
+   ulValue = 0;
+   tagType = 4;
+   break;
+
+  case MSC_TAG_CAPABLE_ID_STATE:
+    ucValue = MSC_CAPABLE_ID_STATE;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_RANDOM_MAX:
+    ucValue = 128;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_RANDOM_MIN:
+    ucValue = 8;
+    tagType = 1;
+    break;
+
+  case MSC_TAG_CAPABLE_KEY_AUTH:
+    usValue = MSC_AUT_PIN_1;
+    tagType = 2;
+    break;
+
+  case MSC_TAG_CAPABLE_PIN_AUTH:
+    usValue = MSC_AUT_ALL;
+    tagType = 2;
+    break;
+
+
+  default:
+    return MSC_INVALID_PARAMETER;
+  }
+
+  switch(tagType) {
+  case 1:
+    memcpy(Value, &ucValue, 1);
+    break;
+  case 2:
+    memcpy(Value, &usValue, 2);
+    break;
+  case 4:
+    memcpy(Value, &ulValue, 4);
+    break;
+  }
+
+  *Length = tagType;
+
+  return MSC_SUCCESS;
+}
+
+MSC_RV PL_MSCWriteFramework( MSCLPTokenConnection pConnection,
+			     MSCLPInitTokenParams pInitParams ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+
+  pBuffer = transmitBuffer.pBuffer; apduResponse = transmitBuffer.apduResponse;
+
+  if (pInitParams->transportKeyLen > 8 || 
+      pInitParams->newTransportKeyLen > 8 ||
+      pInitParams->defaultCHVLen > 8 || 
+      pInitParams->defaultCHVUnblockSize > 8 ) {
+    
+    return MSC_INVALID_PARAMETER;
+  }
+
+  /* Select the applet */
+  PL_MSCIdentifyToken(pConnection); 
+
+  if (pInitParams->newTransportKeyLen == 0) {
+    /* Just use the old transport key */
+    memcpy(pInitParams->newTransportKey, pInitParams->transportKey, 
+	   pInitParams->transportKeyLen);
+    pInitParams->newTransportKeyLen = pInitParams->transportKeyLen;
+  }
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_WRITE_FRAMEWORK;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = 
+    MSC_SIZEOF_PINSIZE + pInitParams->transportKeyLen + 
+    MSC_SIZEOF_PINTRIES + MSC_SIZEOF_PINTRIES + 
+    MSC_SIZEOF_PINSIZE + pInitParams->newTransportKeyLen +
+    MSC_SIZEOF_PINSIZE + pInitParams->newTransportKeyLen + 
+    MSC_SIZEOF_PINTRIES + MSC_SIZEOF_PINTRIES +
+    MSC_SIZEOF_PINSIZE + pInitParams->defaultCHVLen +
+    MSC_SIZEOF_PINSIZE + pInitParams->defaultCHVUnblockSize +
+    MSC_SIZEOF_OBJECTSIZE + MSC_SIZEOF_MINIACL + MSC_SIZEOF_MINIACL +
+    MSC_SIZEOF_MINIACL;
+
+  currentPointer = 0;
+
+  /* Transport key to verify */
+
+  pBuffer[OFFSET_DATA+currentPointer] = pInitParams->transportKeyLen;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pInitParams->transportKey, 
+	 pInitParams->transportKeyLen);
+  
+  currentPointer += pInitParams->transportKeyLen;
+
+  /* New transport key and attributes */
+  
+  pBuffer[OFFSET_DATA+currentPointer] = 4;
+  currentPointer += MSC_SIZEOF_PINTRIES;    
+  pBuffer[OFFSET_DATA+currentPointer] = 1;  /* One chance to unblock */ 
+  currentPointer += MSC_SIZEOF_PINTRIES;    
+
+  pBuffer[OFFSET_DATA+currentPointer] = pInitParams->newTransportKeyLen;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pInitParams->newTransportKey, 
+	 pInitParams->newTransportKeyLen);
+  
+  currentPointer += pInitParams->newTransportKeyLen;
+
+  /* Write Admin Pin Unblock (Same as Admin) */
+
+  pBuffer[OFFSET_DATA+currentPointer] = pInitParams->newTransportKeyLen;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pInitParams->newTransportKey, 
+	 pInitParams->newTransportKeyLen);
+  
+  currentPointer += pInitParams->newTransportKeyLen;
+
+  /* Write User PIN */
+
+  pBuffer[OFFSET_DATA+currentPointer] = pInitParams->defaultCHVTries;
+  currentPointer += MSC_SIZEOF_PINTRIES;    
+  pBuffer[OFFSET_DATA+currentPointer] = pInitParams->defaultCHVUnblockTries; 
+  currentPointer += MSC_SIZEOF_PINTRIES;    
+
+  pBuffer[OFFSET_DATA+currentPointer] = pInitParams->defaultCHVLen;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pInitParams->defaultCHV, 
+	 pInitParams->defaultCHVLen);
+  
+  currentPointer += pInitParams->defaultCHVLen;
+
+  /* Write User Pin Unblock */
+
+  pBuffer[OFFSET_DATA+currentPointer] = pInitParams->defaultCHVUnblockSize;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pInitParams->defaultCHVUnblock, 
+	 pInitParams->defaultCHVUnblockSize);
+  
+  currentPointer += pInitParams->defaultCHVUnblockSize;
+
+  
+  MemCopy32(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pInitParams->objectMemory);
+  
+  currentPointer += MSC_SIZEOF_OBJECTSIZE;
+
+
+  /* Anyone can create objects */
+  pBuffer[OFFSET_DATA+currentPointer] = 0x00;
+  currentPointer += MSC_SIZEOF_MINIACL;
+  /* Keys only after user pin verified */
+  pBuffer[OFFSET_DATA+currentPointer] = 0x02;
+  currentPointer += MSC_SIZEOF_MINIACL;
+  /* Pins only after admin pin verified */
+  pBuffer[OFFSET_DATA+currentPointer] = 0x01;
+  currentPointer += MSC_SIZEOF_MINIACL;
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCExtendedFeature( MSCLPTokenConnection pConnection, 
+			      MSCULong32 extFeature, MSCPUChar8 outData, 
+			      MSCULong32 outLength, MSCPUChar8 inData,
+			      MSCPULong32 inLength ) {
+
+  return MSC_UNSUPPORTED_FEATURE;
+}
+
+MSC_RV PL_MSCGenerateKeys( MSCLPTokenConnection pConnection, 
+			   MSCUChar8 prvKeyNum, MSCUChar8 pubKeyNum, 
+			   MSCLPGenKeyParams pParams ) {
+  
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_MSC_GEN_KEYPAIR;
+  pBuffer[OFFSET_P1]     = prvKeyNum;
+  pBuffer[OFFSET_P2]     = pubKeyNum;
+  pBuffer[OFFSET_LC]     = 16 + pParams->optParamsSize;
+
+  currentPointer  = 0;
+
+  /* Algorithm Type */
+  pBuffer[OFFSET_DATA] = pParams->algoType;
+  currentPointer += MSC_SIZEOF_ALGOTYPE;
+
+  /* Key Size */
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], &pParams->keySize);
+  currentPointer += MSC_SIZEOF_KEYSIZE;
+
+  /* Private Key ACL */
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pParams->privateKeyACL.readPermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pParams->privateKeyACL.writePermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pParams->privateKeyACL.usePermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  /* Public Key ACL */
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pParams->publicKeyACL.readPermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pParams->publicKeyACL.writePermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pParams->publicKeyACL.usePermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  /* Key Generation Options */
+  pBuffer[OFFSET_DATA+currentPointer] = pParams->keyGenOptions;
+  currentPointer += MSC_SIZEOF_GENOPTIONS;
+
+
+  /* Key Generation Options Data */
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pParams->pOptParams, 
+	 pParams->optParamsSize);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );		
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+MSC_RV PL_MSCImportKey( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+                        MSCLPKeyACL pKeyACL, 
+			MSCPUChar8 pKeyBlob, MSCULong32 keyBlobSize, 
+			MSCLPKeyPolicy keyPolicy, 
+			MSCPVoid32 pAddParams, MSCUChar8 addParamsSize ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+  int i; MSCObjectACL acl;
+  
+  acl.readPermission   = MSC_AUT_PIN_1;
+  acl.writePermission  = MSC_AUT_PIN_1;
+  acl.deletePermission = MSC_AUT_PIN_1;
+
+  rv = PL_MSCCreateObject(pConnection, IN_OBJECT_ID,
+			  keyBlobSize, &acl);
+  if (rv != MSC_SUCCESS)
+    return rv;
+
+  i=0;
+
+  /* Take the key and write it to the default object */
+  for (i=0; i < keyBlobSize/MSC_SIZEOF_KEYPACKET; i++) {
+    rv = PL_MSCWriteObject( pConnection, IN_OBJECT_ID, 
+			    i*MSC_SIZEOF_KEYPACKET, 
+			    &pKeyBlob[i*MSC_SIZEOF_KEYPACKET], 
+			    MSC_SIZEOF_KEYPACKET );
+    if ( rv != MSC_SUCCESS ) { return rv; }
+  }
+
+  if ( keyBlobSize%MSC_SIZEOF_KEYPACKET ) {
+    rv = PL_MSCWriteObject( pConnection, IN_OBJECT_ID, 
+			    i*MSC_SIZEOF_KEYPACKET, 
+			    &pKeyBlob[i*MSC_SIZEOF_KEYPACKET], 
+			    keyBlobSize%MSC_SIZEOF_KEYPACKET );
+    if ( rv != MSC_SUCCESS ) {
+      PL_MSCDeleteObject(pConnection, IN_OBJECT_ID, MSC_ZF_WRITE_ZERO);
+      return rv;
+    }
+  }    
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_IMPORT_KEY;
+  pBuffer[OFFSET_P1]     = keyNum;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_ACLSTRUCT + addParamsSize;
+
+  currentPointer = 0;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pKeyACL->readPermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pKeyACL->writePermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pKeyACL->usePermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pAddParams, addParamsSize);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+
+  PL_MSCDeleteObject(pConnection, IN_OBJECT_ID, MSC_ZF_WRITE_ZERO);
+
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCExportKey( MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+			MSCPUChar8 pKeyBlob, MSCPULong32 keyBlobSize, 
+			MSCPVoid32 pAddParams,
+			MSCUChar8 addParamsSize ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+  MSCULong32 blobSize;
+  MSCObjectInfo objInfo;
+  int i;
+
+  i=0; blobSize=0; rv=0; currentPointer=0;
+
+  if ( pConnection == 0 || keyBlobSize == 0 || pKeyBlob == 0 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  pBuffer = transmitBuffer.pBuffer; apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_EXPORT_KEY;
+  pBuffer[OFFSET_P1]     = keyNum;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = addParamsSize + 1;
+
+  pBuffer[OFFSET_DATA]   = MSC_BLOB_ENC_PLAIN;
+
+  if ( pAddParams != 0 ) {
+    memcpy(&pBuffer[OFFSET_DATA+1], pAddParams, addParamsSize);
+  }
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize != 2 ) {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+  if ( convertSW(apduResponse) != MSC_SUCCESS ) {
+    return convertSW(apduResponse);
+  }
+
+  do {
+    
+    /* Get the objects size */
+    rv = lcMSCGetObjectAttributes( pConnection, OUT_OBJECT_ID, &objInfo );
+
+    if ( rv != MSC_SUCCESS ) { break; }
+    
+    if ( objInfo.objectSize > *keyBlobSize ) {
+      *keyBlobSize = objInfo.objectSize;
+      rv = MSC_NO_MEMORY_LEFT;
+      break;
+    }
+    
+    *keyBlobSize = objInfo.objectSize;
+    blobSize = objInfo.objectSize;
+    
+    /* Read the key from the default object */
+    for (i=0; i < blobSize/MSC_SIZEOF_KEYPACKET; i++) {
+      rv = PL_MSCReadObject( pConnection, OUT_OBJECT_ID, 
+			     i*MSC_SIZEOF_KEYPACKET, 
+			     &pKeyBlob[i*MSC_SIZEOF_KEYPACKET], 
+			     MSC_SIZEOF_KEYPACKET );
+      if ( rv != MSC_SUCCESS ) { break; }
+    }
+    
+    if ( blobSize%MSC_SIZEOF_KEYPACKET ) {
+      rv = PL_MSCReadObject( pConnection, OUT_OBJECT_ID, 
+			     i*MSC_SIZEOF_KEYPACKET, 
+			     &pKeyBlob[i*MSC_SIZEOF_KEYPACKET], 
+			     blobSize%MSC_SIZEOF_KEYPACKET );
+      
+      if ( rv != MSC_SUCCESS ) { break; }
+    }    
+
+  } while (0);
+
+  /* Delete the default output object */
+  PL_MSCDeleteObject( pConnection, OUT_OBJECT_ID, MSC_ZF_WRITE_ZERO );
+
+  return rv;
+}
+
+MSC_RV PL_MSCComputeCrypt( MSCLPTokenConnection pConnection,
+			   MSCLPCryptInit cryptInit, MSCPUChar8 pInputData,
+			   MSCULong32 inputDataSize, MSCPUChar8 pOutputData,
+			   MSCPULong32 outputDataSize ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCUShort16 outSize;
+  MSCUChar8 dataLocation;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 ppRecvBuffer;
+  MSCULong32 currentPointer;
+  MSCObjectACL objACL;
+
+  pBuffer = transmitBuffer.pBuffer; apduResponse = transmitBuffer.apduResponse;
+
+  /******************************************/
+  /* Do the MSC_CIPHER_INIT portion of the code */
+  /******************************************/
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_COMPUTE_CRYPT;
+  pBuffer[OFFSET_P1]     = cryptInit->keyNum;
+  pBuffer[OFFSET_P2]     = MSC_CIPHER_INIT;
+  
+  /* Store init in object */
+  if ( cryptInit->optParamsSize + MSC_SIZEOF_CIPHERMODE + 
+       MSC_SIZEOF_CIPHERDIR + MSC_SIZEOF_DATALOCATION > 
+       MSC_MAXSIZEOF_APDU_DATALEN + MSC_SIZEOF_OPTLEN) 
+    {
+      
+      pBuffer[OFFSET_LC]     = MSC_SIZEOF_CIPHERMODE + 
+	MSC_SIZEOF_CIPHERDIR + MSC_SIZEOF_DATALOCATION +
+	MSC_SIZEOF_OPTLEN;
+      
+      dataLocation = DL_OBJECT;
+      
+    /* Store init in apdu */
+    } else {
+      pBuffer[OFFSET_LC]     = cryptInit->optParamsSize + 
+	MSC_SIZEOF_CIPHERMODE + MSC_SIZEOF_CIPHERDIR + 
+	MSC_SIZEOF_DATALOCATION + MSC_SIZEOF_OPTLEN;
+      
+      dataLocation = DL_APDU;
+    }
+  
+  currentPointer  = 0;
+
+  /* Cipher mode */
+  pBuffer[OFFSET_DATA] = cryptInit->cipherMode;
+  currentPointer += MSC_SIZEOF_CIPHERMODE;
+
+  /* Cipher direction */
+  pBuffer[OFFSET_DATA+currentPointer] = cryptInit->cipherDirection;
+
+  /* FIX - Forcing Encrypt Mode */
+  if (cryptInit->cipherDirection == MSC_DIR_SIGN) {
+    pBuffer[OFFSET_DATA+currentPointer] = MSC_DIR_ENCRYPT;
+  }
+
+  currentPointer += MSC_SIZEOF_CIPHERDIR;  
+
+  pBuffer[OFFSET_DATA+currentPointer] = dataLocation;
+  currentPointer += MSC_SIZEOF_DATALOCATION;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], &cryptInit->optParamsSize);
+  currentPointer += MSC_SIZEOF_OPTLEN;
+
+  /* TODO: memcopy and MSCCreateObject/WriteObject needed here */
+  /* Opt Parameters are not used in this version of the spec */
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize != 2 ) {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+  if ( convertSW(apduResponse) != MSC_SUCCESS ) {
+    return convertSW(apduResponse);
+  }
+
+
+  if ( (inputDataSize + MSC_SIZEOF_CIPHERMODE + MSC_SIZEOF_CIPHERDIR
+	+ MSC_SIZEOF_DATALOCATION) > MSC_MAXSIZEOF_APDU_DATALEN ) {
+
+    /*********************************************/
+    /* Do the MSC_CIPHER_PROCESS portion of the code */
+    /*********************************************/
+
+    /* TODO : I don't want to do this now */
+
+    pBuffer[OFFSET_P2]     = MSC_CIPHER_PROCESS;
+    pBuffer[OFFSET_LC]     = 0; /* TODO */
+    
+    currentPointer  = 0;
+        
+    return MSC_UNSUPPORTED_FEATURE;
+
+  } else {
+
+    /*******************************************/
+    /* Do the MSC_CIPHER_FINAL portion of the code */
+    /*******************************************/
+
+    pBuffer[OFFSET_P2]        = MSC_CIPHER_FINAL;
+    currentPointer            = 0;
+
+    if ( inputDataSize + MSC_SIZEOF_DATALOCATION > 
+	 MSC_MAXSIZEOF_APDU_DATALEN ) 
+      {
+	/* Too big, put in object first */
+	pBuffer[OFFSET_LC]    = MSC_SIZEOF_DATALOCATION;
+	pBuffer[OFFSET_DATA]  = DL_OBJECT;
+	dataLocation          = DL_OBJECT;
+
+	objACL.readPermission   = MSC_AUT_PIN_1;
+	objACL.writePermission  = MSC_AUT_PIN_1;
+	objACL.deletePermission = MSC_AUT_PIN_1;
+
+	rv = PL_MSCCreateObject(pConnection, IN_OBJECT_ID, inputDataSize,
+				&objACL);
+
+	if ( rv != MSC_SUCCESS ) {
+	  return rv;
+	}
+
+	rv = PL_MSCWriteLargeObject(pConnection, IN_OBJECT_ID, pInputData,
+				 inputDataSize);
+
+	if ( rv != MSC_SUCCESS ) {
+	  return rv;
+	}
+
+      } else {
+	/* Can be placed into an apdu */
+	pBuffer[OFFSET_LC]    = MSC_SIZEOF_DATALOCATION + 2 + inputDataSize;
+	pBuffer[OFFSET_DATA]  = DL_APDU;
+	dataLocation          = DL_APDU;
+	currentPointer       += MSC_SIZEOF_DATALOCATION;
+	{
+	  // I'm not sure if inputDataSize has the right length for MemCopy16()
+	  MSCUShort16 value = inputDataSize;
+	  MemCopy16(&pBuffer[OFFSET_DATA + currentPointer], &value);
+	  currentPointer	     += 2;
+	}
+	memcpy(&pBuffer[OFFSET_DATA+currentPointer], pInputData, 
+	       inputDataSize);
+      }    
+
+    transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+    /* Set up the APDU exchange */
+    transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+    rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+
+    if ( rv != SCARD_S_SUCCESS ) {
+      return convertPCSC(rv);
+    }
+
+    /* Operation must have failed */
+    if ( (transmitBuffer.apduResponseSize == 2)&&
+	 (dataLocation == DL_APDU) ) {
+      return convertSW(apduResponse);
+
+      /* Output stored into apdu */
+    } else if ( (transmitBuffer.apduResponseSize > 2)&&
+		(dataLocation == DL_APDU) ) {
+      MemCopyTo16(&outSize, apduResponse);
+      memcpy(pOutputData, &apduResponse[MSC_SIZEOF_CRYPTLEN], outSize);
+      *outputDataSize = outSize;
+      return convertSW(&apduResponse[MSC_SIZEOF_CRYPTLEN+outSize]);
+
+      /* Output stored into an object */
+    } else if ( (transmitBuffer.apduResponseSize == 2)&&
+		(dataLocation == DL_OBJECT) ) {
+      rv = PL_MSCReadAllocateObject( pConnection, OUT_OBJECT_ID,
+				     &ppRecvBuffer, outputDataSize );
+      if ( rv == MSC_SUCCESS ) {
+	/* Write Data Chunk Size */
+	setUShort16(ppRecvBuffer, *outputDataSize);
+	/* Write Data */
+	memcpy(pOutputData, &ppRecvBuffer[MSC_SIZEOF_CRYPTLEN], 
+	       getUShort16(ppRecvBuffer));
+      }
+
+      if ( ppRecvBuffer ) {
+	free(ppRecvBuffer);
+      }
+
+      return rv;
+    } else {
+      return MSC_UNSPECIFIED_ERROR;
+    }
+  } 
+}
+
+MSC_RV PL_MSCExtAuthenticate( MSCLPTokenConnection pConnection, 
+			      MSCUChar8 keyNum,
+			      MSCUChar8 cipherMode, MSCUChar8 cipherDirection,
+			      MSCPUChar8 pData, MSCULong32 dataSize )
+{
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+  unsigned char dataLocation;
+
+  pBuffer = transmitBuffer.pBuffer; apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_EXT_AUTH;
+  pBuffer[OFFSET_P1]     = keyNum;
+  pBuffer[OFFSET_P2]     = 0x00;
+
+  if (dataSize + MSC_SIZEOF_CIPHERMODE + MSC_SIZEOF_CIPHERDIR +
+      MSC_SIZEOF_DATALOCATION < MSC_MAXSIZEOF_APDU_DATALEN ) {
+    dataLocation = DL_APDU;
+    pBuffer[OFFSET_LC] = MSC_SIZEOF_CIPHERMODE + MSC_SIZEOF_CIPHERDIR +
+      MSC_SIZEOF_DATALOCATION + 2 + dataSize;
+  } else {
+    dataLocation = DL_OBJECT;
+    pBuffer[OFFSET_LC] = MSC_SIZEOF_CIPHERMODE + MSC_SIZEOF_CIPHERDIR +
+      MSC_SIZEOF_DATALOCATION;
+  }
+
+  pBuffer[OFFSET_DATA+MSC_SIZEOF_CIPHERMODE] = dataLocation;
+
+  currentPointer = 0;
+
+  pBuffer[OFFSET_DATA+currentPointer] = cipherMode;
+
+  currentPointer += MSC_SIZEOF_CIPHERMODE;
+
+  pBuffer[OFFSET_DATA+currentPointer] = cipherDirection;
+  
+  currentPointer += MSC_SIZEOF_CIPHERDIR;
+
+  pBuffer[OFFSET_DATA+currentPointer] = dataLocation;
+  
+  currentPointer += MSC_SIZEOF_DATALOCATION;
+
+  {
+    MSCUShort16 ush = dataSize;
+    MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], &ush);
+    currentPointer += 2;
+  }
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pData, 
+	 dataSize);
+  
+  transmitBuffer.bufferSize =  pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    /* dumpBinary(apduResponse, transmitBuffer.apduResponseSize); */
+    return convertSW(&apduResponse[transmitBuffer.apduResponseSize-2]);
+  }
+
+}
+
+MSC_RV PL_MSCListKeys( MSCLPTokenConnection pConnection, MSCUChar8 seqOption,
+		       MSCLPKeyInfo pKeyInfo ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCULong32 currentPointer;
+  MSCTransmitBuffer transmitBuffer;
+
+  pBuffer = transmitBuffer.pBuffer; apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_LIST_KEYS;
+  pBuffer[OFFSET_P1]     = seqOption;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_KEYINFO;
+
+  transmitBuffer.bufferSize = 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    if ( convertSW(apduResponse) == MSC_SUCCESS ) {
+      /* Must have finished */
+      return MSC_SEQUENCE_END;
+    } else {
+      return convertSW(apduResponse);
+    }
+  } else if (transmitBuffer.apduResponseSize == MSC_SIZEOF_KEYINFO + 2 ) {
+    
+    currentPointer = 0;
+
+    /* Key Number */
+    pKeyInfo->keyNum  = apduResponse[currentPointer];
+    currentPointer += MSC_SIZEOF_KEYNUMBER;
+
+    /* Key Type */
+    pKeyInfo->keyType = apduResponse[currentPointer];
+    currentPointer += MSC_SIZEOF_KEYTYPE;
+
+    /* Key Partner */
+    pKeyInfo->keyPartner = apduResponse[currentPointer];
+    currentPointer += MSC_SIZEOF_KEYPARTNER;
+
+    /* Key Size */
+    MemCopyTo16(&pKeyInfo->keySize, 
+		&apduResponse[currentPointer]);
+
+    currentPointer += MSC_SIZEOF_KEYSIZE;
+
+    /* Key ACL */
+    MemCopyTo16(&pKeyInfo->keyACL.readPermission, 
+		&apduResponse[currentPointer]);
+
+    currentPointer += MSC_SIZEOF_ACLVALUE;
+    
+    MemCopyTo16(&pKeyInfo->keyACL.writePermission, 
+		&apduResponse[currentPointer]);
+    
+    currentPointer += MSC_SIZEOF_ACLVALUE;
+
+    MemCopyTo16(&pKeyInfo->keyACL.usePermission, 
+		&apduResponse[currentPointer]);
+
+    currentPointer += MSC_SIZEOF_ACLVALUE;
+    
+    switch(pKeyInfo->keyType)
+    {
+        case MSC_KEY_RSA_PUBLIC:
+        case MSC_KEY_RSA_PRIVATE:
+        case MSC_KEY_RSA_PRIVATE_CRT:
+            pKeyInfo->keyPolicy.cipherMode = MSC_KEYPOLICY_MODE_RSA_NOPAD;
+            pKeyInfo->keyPolicy.cipherDirection = MSC_KEYPOLICY_DIR_SIGN | MSC_KEYPOLICY_DIR_VERIFY |
+                MSC_KEYPOLICY_DIR_ENCRYPT | MSC_KEYPOLICY_DIR_DECRYPT;
+            break;
+        case MSC_KEY_DES:
+        case MSC_KEY_3DES:
+        case MSC_KEY_3DES3:
+            pKeyInfo->keyPolicy.cipherMode = MSC_KEYPOLICY_MODE_DES_ECB_NOPAD;
+            pKeyInfo->keyPolicy.cipherDirection = MSC_KEYPOLICY_DIR_ENCRYPT | MSC_KEYPOLICY_DIR_DECRYPT;
+            break;
+            
+        default:
+            pKeyInfo->keyPolicy.cipherMode = 0;
+            pKeyInfo->keyPolicy.cipherDirection = 0;
+            break;
+    }
+
+    return convertSW(&apduResponse[currentPointer]);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCCreatePIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			MSCUChar8 pinAttempts, MSCPUChar8 pPinCode,
+			MSCULong32 pinCodeSize, MSCPUChar8 pUnblockCode,
+			MSCUChar8 unblockCodeSize ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+
+  pBuffer = transmitBuffer.pBuffer; apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_CREATE_PIN;
+  pBuffer[OFFSET_P1]     = pinNum;
+  pBuffer[OFFSET_P2]     = pinAttempts;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_PINSIZE + MSC_SIZEOF_PINSIZE + 
+    pinCodeSize + unblockCodeSize;
+
+  currentPointer = 0;
+
+  pBuffer[OFFSET_DATA+currentPointer] = pinCodeSize;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pPinCode, 
+	 pinCodeSize);
+  
+  currentPointer += pinCodeSize;
+
+  pBuffer[OFFSET_DATA+currentPointer] = unblockCodeSize;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pUnblockCode,
+	 unblockCodeSize);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCVerifyPIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			MSCPUChar8 pPinCode, MSCULong32 pinCodeSize ) {
+  
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+
+  pBuffer = transmitBuffer.pBuffer; apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_VERIFY_PIN;
+  pBuffer[OFFSET_P1]     = pinNum;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = pinCodeSize;
+
+  memcpy(&pBuffer[OFFSET_DATA], pPinCode, pinCodeSize);
+  
+  transmitBuffer.bufferSize =  pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCChangePIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			MSCPUChar8 pOldPinCode, MSCUChar8 oldPinCodeSize,
+			MSCPUChar8 pNewPinCode, MSCUChar8 newPinCodeSize ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_CHANGE_PIN;
+  pBuffer[OFFSET_P1]     = pinNum;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_PINSIZE + MSC_SIZEOF_PINSIZE + 
+    oldPinCodeSize + newPinCodeSize;
+
+  currentPointer = 0;
+
+  pBuffer[OFFSET_DATA+currentPointer] = oldPinCodeSize;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pOldPinCode, 
+	 oldPinCodeSize);
+  
+  currentPointer += oldPinCodeSize;
+
+  pBuffer[OFFSET_DATA+currentPointer] = newPinCodeSize;
+
+  currentPointer += MSC_SIZEOF_PINSIZE;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pNewPinCode,
+	 newPinCodeSize);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCUnblockPIN( MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+			 MSCPUChar8 pUnblockCode, 
+			 MSCULong32 unblockCodeSize ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_UNBLOCK_PIN;
+  pBuffer[OFFSET_P1]     = pinNum;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = unblockCodeSize;
+
+  memcpy(&pBuffer[OFFSET_DATA], pUnblockCode, unblockCodeSize);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+MSC_RV PL_MSCListPINs( MSCLPTokenConnection pConnection, 
+		       MSCPUShort16 pPinBitMask ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_LIST_PINS;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = 0x02;
+
+  transmitBuffer.bufferSize = 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else if ( transmitBuffer.apduResponseSize == 4 ) {
+    *pPinBitMask  = 0x100 * apduResponse[0];
+    *pPinBitMask += apduResponse[1];
+    return convertSW(&apduResponse[2]);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCCreateObject( MSCLPTokenConnection pConnection, 
+			   MSCString objectID, MSCULong32 objectSize, 
+			   MSCLPObjectACL pObjectACL ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+  MSCULong32 _objectID;
+
+  if ( stringToID(&_objectID, objectID) ) 
+    return MSC_INVALID_PARAMETER;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_CREATE_OBJ;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_OBJECTID + MSC_SIZEOF_OBJECTSIZE +
+    MSC_SIZEOF_ACLSTRUCT;
+
+  currentPointer = 0;
+
+  MemCopy32(&pBuffer[OFFSET_DATA+currentPointer], &_objectID);
+  
+  currentPointer += MSC_SIZEOF_OBJECTID;
+  
+  MemCopy32(&pBuffer[OFFSET_DATA+currentPointer], &objectSize);
+  
+  currentPointer += MSC_SIZEOF_OBJECTSIZE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pObjectACL->readPermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pObjectACL->writePermission);
+
+  currentPointer += MSC_SIZEOF_ACLVALUE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], 
+	    &pObjectACL->deletePermission);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCDeleteObject( MSCLPTokenConnection pConnection, 
+			   MSCString objectID, MSCUChar8 zeroFlag ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+  MSCULong32 _objectID;
+
+  if ( stringToID(&_objectID, objectID) ) 
+    return MSC_INVALID_PARAMETER;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_DELETE_OBJ;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = zeroFlag;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_OBJECTID;
+
+  currentPointer = 0;
+
+  MemCopy32(&pBuffer[OFFSET_DATA+currentPointer], &_objectID);
+
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCWriteObject( MSCLPTokenConnection pConnection, 
+			  MSCString objectID, 
+			  MSCULong32 offset, MSCPUChar8 pInputData, 
+			  MSCUChar8 dataSize ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+  MSCULong32 _objectID;
+
+  if ( stringToID(&_objectID, objectID) ) 
+    return MSC_INVALID_PARAMETER;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_WRITE_OBJ;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_OBJECTID + MSC_SIZEOF_OFFSET +
+    MSC_SIZEOF_RWDATA + dataSize;
+  
+  currentPointer = 0;
+  
+  MemCopy32(&pBuffer[OFFSET_DATA+currentPointer], &_objectID);
+  
+  currentPointer = MSC_SIZEOF_OBJECTID;
+  
+  MemCopy32(&pBuffer[OFFSET_DATA+currentPointer], &offset);
+  
+  currentPointer += MSC_SIZEOF_OFFSET;
+
+  pBuffer[OFFSET_DATA+currentPointer] =  dataSize;
+  currentPointer += MSC_SIZEOF_RWDATA;
+
+  memcpy(&pBuffer[OFFSET_DATA+currentPointer], pInputData, dataSize);
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCReadObject( MSCLPTokenConnection pConnection, MSCString objectID, 
+			 MSCULong32 offset, MSCPUChar8 pOutputData, 
+			 MSCUChar8 dataSize ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+  MSCULong32 _objectID;
+
+  if ( stringToID(&_objectID, objectID) ) 
+    return MSC_INVALID_PARAMETER;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_READ_OBJ;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_OBJECTID + MSC_SIZEOF_OFFSET +
+    MSC_SIZEOF_RWDATA;
+
+  currentPointer = 0;
+
+  MemCopy32(&pBuffer[OFFSET_DATA+currentPointer], &_objectID);
+
+  currentPointer = MSC_SIZEOF_OBJECTID;
+
+  MemCopy32(&pBuffer[OFFSET_DATA+currentPointer], &offset);
+  
+  currentPointer += MSC_SIZEOF_OFFSET;
+  pBuffer[OFFSET_DATA+currentPointer] =  dataSize;
+  transmitBuffer.bufferSize = pBuffer[OFFSET_LC] + 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else if (transmitBuffer.apduResponseSize == dataSize + 2 ) {
+    memcpy(pOutputData, apduResponse, dataSize);
+    return convertSW(&apduResponse[dataSize]);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+}
+
+MSC_RV PL_MSCListObjects( MSCLPTokenConnection pConnection, 
+			  MSCUChar8 seqOption, 
+			  MSCLPObjectInfo pObjectInfo ) {
+  
+  MSCLong32 rv;
+  
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCULong32 currentPointer;
+  MSCULong32 _objectID;
+  
+  rv=0; currentPointer=0;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_LIST_OBJECTS;
+  pBuffer[OFFSET_P1]     = seqOption;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = MSC_SIZEOF_OBJECTID + MSC_SIZEOF_OBJECTSIZE
+    + MSC_SIZEOF_ACLSTRUCT;
+
+  transmitBuffer.bufferSize = 5;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    if ( convertSW(apduResponse) == MSC_SUCCESS ) {
+      /* Must have finished */
+      return MSC_SEQUENCE_END;
+    } else {
+      return convertSW(apduResponse);
+    }
+  } else if (transmitBuffer.apduResponseSize == pBuffer[OFFSET_LC] + 2 ) {
+    currentPointer = 0;
+    MemCopyTo32(&_objectID, &apduResponse[currentPointer]);
+    idToString(pObjectInfo->objectID, _objectID);
+
+    currentPointer += MSC_SIZEOF_OBJECTID;
+
+    MemCopyTo32(&pObjectInfo->objectSize, &apduResponse[currentPointer]); 
+
+    currentPointer += MSC_SIZEOF_OBJECTSIZE;
+
+    MemCopyTo16(&pObjectInfo->objectACL.readPermission, 
+		&apduResponse[currentPointer]);
+
+    currentPointer += MSC_SIZEOF_ACLVALUE;
+    
+    MemCopyTo16(&pObjectInfo->objectACL.writePermission, 
+		&apduResponse[currentPointer]);
+    
+    currentPointer += MSC_SIZEOF_ACLVALUE;
+
+    MemCopyTo16(&pObjectInfo->objectACL.deletePermission, 
+		&apduResponse[currentPointer]);
+
+    currentPointer += MSC_SIZEOF_ACLVALUE;
+
+    return convertSW(&apduResponse[currentPointer]);
+
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCLogoutAll( MSCLPTokenConnection pConnection ) {
+
+  MSCLong32 rv;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA]    = CardEdge_CLA;
+  pBuffer[OFFSET_INS]    = INS_LOGOUT_ALL;
+  pBuffer[OFFSET_P1]     = 0x00;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = 0x02;
+  pBuffer[OFFSET_DATA]   = 0x00;
+  pBuffer[OFFSET_DATA+1] = 0x00;
+
+  transmitBuffer.bufferSize = 7;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(apduResponse);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV PL_MSCGetChallenge( MSCLPTokenConnection pConnection, MSCPUChar8 pSeed,
+			MSCUShort16 seedSize, MSCPUChar8 pRandomData,
+			MSCUShort16 randomDataSize ) {
+
+  MSCLong32 rv;
+  MSCULong32 currentPointer;
+
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+  MSCTransmitBuffer transmitBuffer;
+  MSCUShort16 chall_size;
+
+  if ( pRandomData == 0 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  if ( randomDataSize == 0 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  pBuffer = transmitBuffer.pBuffer; 
+  apduResponse = transmitBuffer.apduResponse;
+
+  pBuffer[OFFSET_CLA] = CardEdge_CLA;
+  pBuffer[OFFSET_INS] = INS_GET_CHALLENGE;
+  pBuffer[OFFSET_P1]  = 0x00;
+
+  /* We must dump the random to an object if it is too large */
+  if ( randomDataSize > 255 ) {
+    pBuffer[OFFSET_P2]  = DL_OBJECT;
+  } else {
+    pBuffer[OFFSET_P2]  = DL_APDU;
+  }
+
+  /* Short + Short + size of seed */
+  pBuffer[OFFSET_LC] = MSC_SIZEOF_RANDOMSIZE +
+    MSC_SIZEOF_SEEDLENGTH + seedSize;
+
+  currentPointer = 0;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], &randomDataSize);
+
+  currentPointer = MSC_SIZEOF_RANDOMSIZE;
+
+  MemCopy16(&pBuffer[OFFSET_DATA+currentPointer], &seedSize);
+  
+  currentPointer += MSC_SIZEOF_SEEDLENGTH;
+  
+  if (seedSize > 0)
+    memcpy(&pBuffer[OFFSET_DATA+currentPointer], pSeed, 
+	   seedSize);
+  
+  transmitBuffer.bufferSize = 5 + MSC_SIZEOF_RANDOMSIZE +
+    MSC_SIZEOF_SEEDLENGTH + seedSize;
+
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+  
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+
+  /* dumpBinary(apduResponse, transmitBuffer.apduResponseSize); */
+  MemCopyTo16(&chall_size, apduResponse);
+
+  if (( transmitBuffer.apduResponseSize == randomDataSize + 4 ) && 
+      (chall_size == randomDataSize)) {
+    memcpy(pRandomData, apduResponse + 2, randomDataSize);
+    return convertSW(&apduResponse[transmitBuffer.apduResponseSize-2]);
+  } else if ( transmitBuffer.apduResponseSize == 2 ) {
+    return convertSW(&apduResponse[transmitBuffer.apduResponseSize-2]);
+  } else {
+    return MSC_UNSPECIFIED_ERROR;
+  }
+
+}
+
+MSC_RV lcMSCGetObjectAttributes( MSCLPTokenConnection pConnection, 
+				 MSCString objectID, 
+				 MSCLPObjectInfo pObjectInfo ) {
+  MSC_RV rv;
+  MSCString pObjectID;
+  MSCChar8 pStringID[MSC_MAXSIZE_OBJID];
+  MSCObjectInfo objInfo;
+
+  if ( pConnection == NULL ) return MSC_INVALID_PARAMETER; 
+
+  rv = PL_MSCListObjects( pConnection, MSC_SEQUENCE_RESET, &objInfo );
+
+  if ( rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS) {
+    return rv;
+  }
+
+  if ( rv == MSC_SEQUENCE_END ) {
+    return MSC_OBJECT_NOT_FOUND;
+  }
+
+  if ( strcmp(objectID, IN_OBJECT_ID) == 0 ) {
+    idToString( pStringID, 0xFFFFFFFE );
+    pObjectID = pStringID;
+  } else if ( strcmp(objectID, OUT_OBJECT_ID) == 0 ) {
+    idToString( pStringID, 0xFFFFFFFF );
+    pObjectID = pStringID;
+  } else {
+    pObjectID = objectID;
+  }
+
+  if (strncmp(pObjectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0 ) {
+    pObjectInfo->objectSize = objInfo.objectSize;
+    pObjectInfo->objectACL.readPermission = 
+      objInfo.objectACL.readPermission;
+    pObjectInfo->objectACL.writePermission = 
+      objInfo.objectACL.writePermission;
+    pObjectInfo->objectACL.deletePermission = 
+      objInfo.objectACL.deletePermission;
+    strncpy(pObjectInfo->objectID, pObjectID, MSC_MAXSIZE_OBJID);
+    return MSC_SUCCESS;
+  }
+  
+  do {
+    rv = PL_MSCListObjects( pConnection, MSC_SEQUENCE_NEXT, &objInfo );
+    if (strncmp(pObjectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0 ) 
+      break;
+  } while ( rv == MSC_SUCCESS );
+  
+  if ( rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS ) {
+    return rv;
+  }
+
+  if ( rv == MSC_SEQUENCE_END ) {
+    return MSC_OBJECT_NOT_FOUND;
+  }
+
+  pObjectInfo->objectSize = objInfo.objectSize;
+  pObjectInfo->objectACL.readPermission = 
+    objInfo.objectACL.readPermission;
+  pObjectInfo->objectACL.writePermission = 
+    objInfo.objectACL.writePermission;
+  pObjectInfo->objectACL.deletePermission = 
+    objInfo.objectACL.deletePermission;
+  strncpy(pObjectInfo->objectID, pObjectID, MSC_MAXSIZE_OBJID);
+
+  return MSC_SUCCESS;  
+}
+
+MSC_RV PL_MSCReadAllocateObject( MSCLPTokenConnection pConnection, 
+				 MSCString objectID, MSCPUChar8 *pOutputData, 
+				 MSCPULong32 dataSize ) {
+
+  MSC_RV rv;
+  MSCObjectInfo objInfo;
+
+  MSCULong32 objectSize;
+
+  if ( pOutputData == 0 ) {
+    return MSC_INVALID_PARAMETER;
+  }
+
+  rv = lcMSCGetObjectAttributes( pConnection, objectID, &objInfo );
+
+  if ( rv != MSC_SUCCESS ) {
+    *dataSize = 0;
+    *pOutputData = 0;
+    return rv;
+  }
+  
+  objectSize   = objInfo.objectSize;
+  *dataSize    = objectSize;
+  *pOutputData = (MSCPUChar8)malloc(sizeof(MSCUChar8)*objectSize);
+
+  return PL_MSCReadLargeObject( pConnection, objectID, *pOutputData, 
+				objectSize );
+
+}
+
+MSC_RV PL_MSCReadLargeObject( MSCLPTokenConnection pConnection, 
+			      MSCString objectID, MSCPUChar8 pOutputData, 
+			      MSCULong32 dataSize ) {
+
+  MSC_RV rv;
+  MSCULong32 objectSize;
+  int i;
+
+  objectSize = dataSize;
+  rv         = MSC_UNSPECIFIED_ERROR;
+
+  /* Read the key from the default object */
+  for (i=0; i < objectSize/MSC_SIZEOF_KEYPACKET; i++) {
+    rv = PL_MSCReadObject( pConnection, objectID, 
+			   i*MSC_SIZEOF_KEYPACKET, 
+			   &pOutputData[i*MSC_SIZEOF_KEYPACKET], 
+			   MSC_SIZEOF_KEYPACKET );
+    if ( rv != MSC_SUCCESS ) { return rv; }
+  }
+  
+  if ( objectSize%MSC_SIZEOF_KEYPACKET ) {
+    rv = PL_MSCReadObject( pConnection, objectID, 
+			   i*MSC_SIZEOF_KEYPACKET, 
+			   &pOutputData[i*MSC_SIZEOF_KEYPACKET], 
+			   objectSize%MSC_SIZEOF_KEYPACKET );
+
+    if ( rv != MSC_SUCCESS ) { return rv; }
+  }    
+
+  return rv;
+}
+
+MSC_RV PL_MSCWriteLargeObject( MSCLPTokenConnection pConnection, 
+			       MSCString objectID, MSCPUChar8 pInputData, 
+			       MSCULong32 dataSize ) {
+  MSC_RV rv;
+  MSCULong32 objectSize;
+  int i;
+
+  objectSize = dataSize;
+  rv         = MSC_UNSPECIFIED_ERROR;
+
+  /* Read the key from the default object */
+  for (i=0; i < objectSize/MSC_SIZEOF_KEYPACKET; i++) {
+    rv = PL_MSCWriteObject( pConnection, objectID, 
+			    i*MSC_SIZEOF_KEYPACKET, 
+			    &pInputData[i*MSC_SIZEOF_KEYPACKET], 
+			    MSC_SIZEOF_KEYPACKET );
+    if ( rv != MSC_SUCCESS ) { return rv; }
+  }
+
+  
+  if ( objectSize%MSC_SIZEOF_KEYPACKET ) {
+    rv = PL_MSCWriteObject( pConnection, objectID, 
+			    i*MSC_SIZEOF_KEYPACKET, 
+			    &pInputData[i*MSC_SIZEOF_KEYPACKET], 
+			    objectSize%MSC_SIZEOF_KEYPACKET );
+    
+    if ( rv != MSC_SUCCESS ) { return rv; }
+  }    
+  
+  return rv;
+}
+
+int idToString( char *objectString, MSCULong32 objectID ) {
+
+  MSCUChar8 objBytes[MSC_MAXSIZE_OBJID];
+
+  MemCopy32(objBytes, &objectID);
+
+  snprintf(objectString, MSC_MAXSIZE_OBJID, "%c%c%c%c", objBytes[0],
+	   objBytes[1], objBytes[2], objBytes[3]);
+  return 0;
+}
+
+int stringToID( MSCPULong32 objectID, char *objectString ) {
+
+  MSCULong32 localID;
+  MSCUChar8 objBytes[MSC_MAXSIZE_OBJID];
+  int i;
+
+  localID = 0;
+
+  if ( strcmp(objectString, IN_OBJECT_ID) == 0 ) {
+    *objectID = 0xFFFFFFFE;
+    return 0;
+  } else if ( strcmp(objectString, OUT_OBJECT_ID) == 0 ) {
+    *objectID = 0xFFFFFFFF;
+    return 0;
+  }
+
+  if (strlen(objectString) > MSC_SIZEOF_OBJECTID) {
+    return -1;
+  }
+
+  objBytes[0] = objectString[0];
+  objBytes[1] = objectString[1];
+  objBytes[2] = objectString[2];
+  objBytes[3] = objectString[3];
+   
+  for (i=strlen(objectString); i < 4; i++) {
+    objBytes[i] = 0x00; /* Pad with NULL */
+  }
+
+  MemCopyTo32(&localID, objBytes);
+
+  if ( localID == 0 ) {
+    return -1;
+  }
+
+  *objectID = localID;
+  return 0;
+}
+
+
+/* Some local helper functions */
+
+MSCUShort16 convertSW(MSCPUChar8 pBuffer) {
+  MSCUShort16 retValue;
+
+  retValue  = pBuffer[0] * 0x100;
+  retValue += pBuffer[1];
+
+  return retValue;
+}
+
+void MemCopy16(MSCPUChar8 destValue, MSCPUShort16 srcValue) {
+  destValue[0] = (*srcValue & 0xFF00) >> 8;
+  destValue[1] = (*srcValue & 0x00FF);
+}
+
+void MemCopy32(MSCPUChar8 destValue, MSCPULong32 srcValue) {
+  destValue[0] = (*srcValue >> 24);
+  destValue[1] = (*srcValue & 0x00FF0000) >> 16;
+  destValue[2] = (*srcValue & 0x0000FF00) >> 8;
+  destValue[3] = (*srcValue & 0x000000FF);
+}
+
+void MemCopyTo16(MSCPUShort16 destValue, MSCPUChar8 srcValue) {
+
+  *destValue  = srcValue[0] * 0x100;
+  *destValue += srcValue[1];
+
+}
+
+void MemCopyTo32(MSCPULong32 destValue, MSCPUChar8 srcValue) {
+
+  *destValue  = srcValue[0] * 0x1000000;
+  *destValue += srcValue[1] * 0x10000;
+  *destValue += srcValue[2] * 0x100;
+  *destValue += srcValue[3];
+
+}
+
+MSCUShort16 getUShort16(MSCPUChar8 srcValue) {
+  return ( (((MSCUShort16)srcValue[0]) << 8) || srcValue[1] );
+}
+
+void setUShort16(MSCPUChar8 dstValue, MSCUShort16 srcValue) {
+  MemCopyTo16(&srcValue, dstValue);
+}
+
+
+MSCLong32 SCardExchangeAPDU( MSCLPTokenConnection pConnection, 
+			     MSCLPTransmitBuffer transmitBuffer ) {
+  
+  MSCLong32 rv, ret;
+  MSCULong32 originalLength;
+  MSCUChar8 getResponse[5] = {0x00, 0xC0, 0x00, 0x00, 0x00};
+  MSCULong32 dwActiveProtocol;
+  int i;
+
+  originalLength = transmitBuffer->apduResponseSize;
+
+  while (1) {
+    
+#ifdef MSC_DEBUG
+    printf("->: ");
+    
+#define DEBUG_INS(a, b) if ((a) == (b)) printf("[" #b "] ");
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_MSC_GEN_KEYPAIR);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_IMPORT_KEY);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_EXPORT_KEY);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_COMPUTE_CRYPT);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_CREATE_PIN);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_VERIFY_PIN);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_CHANGE_PIN);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_UNBLOCK_PIN);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_LOGOUT_ALL);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_GET_CHALLENGE);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_EXT_AUTH);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_CREATE_OBJ);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_DELETE_OBJ);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_READ_OBJ);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_WRITE_OBJ);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_LIST_OBJECTS);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_LIST_PINS);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_LIST_KEYS);
+    DEBUG_INS(transmitBuffer->pBuffer[OFFSET_INS], INS_GET_STATUS);
+    
+    for (i=0; i < transmitBuffer->bufferSize; i++) {
+      printf("%02x ", transmitBuffer->pBuffer[i]);
+    } printf("\n");
+#endif
+    
+    while(1) {
+      transmitBuffer->apduResponseSize = originalLength;
+      
+      rv =  SCardTransmit(pConnection->hCard, pConnection->ioType,
+			  transmitBuffer->pBuffer, 
+			  transmitBuffer->bufferSize, 0,
+			  transmitBuffer->apduResponse, 
+			  &transmitBuffer->apduResponseSize );
+      
+      if ( rv == SCARD_S_SUCCESS ) {
+	break;
+	
+      } else if ( rv == SCARD_W_RESET_CARD ) {
+	pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
+	ret = SCardReconnect(pConnection->hCard, pConnection->shareMode, 
+			     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			     SCARD_LEAVE_CARD, &dwActiveProtocol );
+	
+	PL_MSCIdentifyToken(pConnection);
+
+	
+	if ( ret == SCARD_S_SUCCESS ) {
+	  continue;
+	}
+	
+      } else if ( rv == SCARD_W_REMOVED_CARD ) {
+	/* Push REMOVED_TOKEN back to the application */
+	pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
+	return rv;
+      } else {
+	/* Must be a BIG, BAD, ERROR */
+#ifdef MSC_DEBUG
+	printf("Transmit error: %x\n", (unsigned int) rv);
+#endif
+	return rv;
+      }
+    }
+    
+#ifdef MSC_DEBUG
+    printf("<-: ");
+    
+    for (i=0; i < transmitBuffer->apduResponseSize; i++) {
+      printf("%02x ", transmitBuffer->apduResponse[i]);
+    } printf("\n");
+#endif
+    
+    if ( transmitBuffer->apduResponseSize == 2 && 
+	 transmitBuffer->apduResponse[0] == 0x61 ) {
+#ifdef MSC_DEBUG
+      printf("->: 0x00 0xC0 0x00 0x00 %02x\n", 
+	     transmitBuffer->apduResponse[1]);
+#endif
+      getResponse[4] = transmitBuffer->apduResponse[1];
+      transmitBuffer->apduResponseSize   = originalLength;
+      rv =  SCardTransmit(pConnection->hCard, pConnection->ioType,
+			  getResponse, 5, 0,
+			  transmitBuffer->apduResponse, 
+			  &transmitBuffer->apduResponseSize );
+      
+      if ( rv == SCARD_S_SUCCESS ) {
+#ifdef MSC_DEBUG	
+	printf("<-: ");
+	
+	for (i=0; i < transmitBuffer->apduResponseSize; i++) {
+	  printf("%02x ", transmitBuffer->apduResponse[i]);
+	} printf("\n");
+#endif
+	break;
+      } else if ( rv == SCARD_W_RESET_CARD ) {
+	pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
+	ret = SCardReconnect(pConnection->hCard, pConnection->shareMode, 
+			     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			     SCARD_LEAVE_CARD, &dwActiveProtocol );
+	
+	PL_MSCIdentifyToken(pConnection); 
+
+	
+	if ( ret == SCARD_S_SUCCESS ) {
+	  continue;
+	}
+	
+      } else if ( rv == SCARD_W_REMOVED_CARD ) {
+	/* Push REMOVED_TOKEN back to the application */
+	pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
+	return rv;
+      } else {
+#ifdef MSC_DEBUG
+	printf("Transmit error: %x\n", (unsigned int) rv);
+#endif
+	return rv;
+      } 
+
+    } /* if needs get response */        
+
+    break;
+  }  /* End of while */
+  
+  
+  return rv;
+}
+
+MSC_RV PL_MSCIdentifyToken( MSCLPTokenConnection pConnection ) {
+
+  MSCLong32 rv;
+  MSCTransmitBuffer transmitBuffer;
+  MSCPUChar8 apduResponse; MSCPUChar8 pBuffer;
+ 
+  pBuffer = transmitBuffer.pBuffer;
+  apduResponse = transmitBuffer.apduResponse;
+ 
+  pBuffer[OFFSET_CLA]    = 0x00;
+  pBuffer[OFFSET_INS]    = 0xA4;
+  pBuffer[OFFSET_P1]     = 0x04;
+  pBuffer[OFFSET_P2]     = 0x00;
+  pBuffer[OFFSET_LC]     = pConnection->tokenInfo.tokenAppLen;
+ 
+  memcpy(&pBuffer[OFFSET_DATA], pConnection->tokenInfo.tokenApp, 
+	 pConnection->tokenInfo.tokenAppLen);
+ 
+  transmitBuffer.bufferSize = 5 + pConnection->tokenInfo.tokenAppLen;
+ 
+  /* Set up the APDU exchange */
+  transmitBuffer.apduResponseSize = MSC_MAXSIZE_BUFFER;
+  rv = SCardExchangeAPDU( pConnection, &transmitBuffer );
+ 
+  if ( rv != SCARD_S_SUCCESS ) {
+    return convertPCSC(rv);
+  }
+ 
+  if ( transmitBuffer.apduResponseSize == 2 && apduResponse[0] == 0x90 ) {
+    return MSC_SUCCESS;
+  } else {
+    return MSC_UNSUPPORTED_FEATURE;
+  }
+}
+
+MSC_RV PL_MSCInitializePlugin( MSCLPTokenConnection pConnection ) {
+
+  return MSC_SUCCESS;
+}
+
+MSC_RV PL_MSCFinalizePlugin( MSCLPTokenConnection pConnection ) {
+
+  return MSC_SUCCESS;
+}
+
+MSC_RV convertPCSC( MSCLong32 pcscCode ) {
+
+  switch(pcscCode) {
+  case SCARD_S_SUCCESS:
+    return MSC_SUCCESS;
+  case SCARD_E_INVALID_HANDLE:
+    return MSC_INVALID_HANDLE;
+  case SCARD_E_SHARING_VIOLATION:
+    return MSC_SHARING_VIOLATION;
+  case SCARD_W_REMOVED_CARD:
+    return MSC_TOKEN_REMOVED;
+  case SCARD_E_NO_SMARTCARD:
+    return MSC_TOKEN_REMOVED;
+  case SCARD_W_RESET_CARD:
+    return MSC_TOKEN_RESET;
+  case SCARD_W_INSERTED_CARD:
+    return MSC_TOKEN_INSERTED;
+  case SCARD_E_NO_SERVICE:
+    return MSC_SERVICE_UNRESPONSIVE;
+  case SCARD_E_UNKNOWN_CARD:
+  case SCARD_W_UNSUPPORTED_CARD:
+  case SCARD_E_CARD_UNSUPPORTED:
+    return MSC_UNRECOGNIZED_TOKEN;
+  case SCARD_E_INVALID_PARAMETER:
+  case SCARD_E_INVALID_VALUE:
+  case SCARD_E_UNKNOWN_READER:
+  case SCARD_E_PROTO_MISMATCH:
+  case SCARD_E_READER_UNAVAILABLE:
+    return MSC_INVALID_PARAMETER;
+  case SCARD_E_CANCELLED:
+    return MSC_CANCELLED;
+  case SCARD_E_TIMEOUT:
+    return MSC_TIMEOUT_OCCURRED;
+
+  default:
+    return MSC_INTERNAL_ERROR;
+  }
+}

Added: trunk/SmartCardServices/src/MCardPlugin/musclecardApplet.h
===================================================================
--- trunk/SmartCardServices/src/MCardPlugin/musclecardApplet.h	                        (rev 0)
+++ trunk/SmartCardServices/src/MCardPlugin/musclecardApplet.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : musclecardApplet.h
+            Package: Musclecard Plugin
+            Author : David Corcoran
+            Date   : 10/02/01
+            License: Copyright (C) 2001 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This abstracts the MUSCLE Card Edge Inteface
+ 
+ 
+********************************************************************/
+
+#ifndef __musclecardApplet_h__
+#define __musclecardApplet_h__
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+// Data Locations admitted in ComputeCrypt()
+#define DL_APDU          0x01
+#define DL_OBJECT        0x02
+
+/* Some useful offsets in the buffer */
+#define OFFSET_CLA	0x00
+#define OFFSET_INS	0x01
+#define OFFSET_P1	0x02
+#define OFFSET_P2	0x03
+#define OFFSET_P3	0x04
+#define OFFSET_LC       0x04
+#define OFFSET_DATA	0x05
+
+    // Import/Export Object ID
+#define IN_OBJECT_ID   "0xFFFFFFFE"
+#define OUT_OBJECT_ID  "0xFFFFFFFF"
+
+    // code of CLA byte in the command APDU header
+#define CardEdge_CLA   0xB0
+
+    /****************************************
+     *          Instruction codes           *
+     ****************************************/
+
+#define INS_WRITE_FRAMEWORK  0x2A
+    // Keys' use and management
+#define INS_MSC_GEN_KEYPAIR      0x30
+#define INS_IMPORT_KEY           0x32
+#define INS_EXPORT_KEY           0x34
+#define INS_COMPUTE_CRYPT        0x36
+
+    // External authentication
+#define INS_CREATE_PIN      0x40
+#define INS_VERIFY_PIN      0x42
+#define INS_CHANGE_PIN      0x44
+#define INS_UNBLOCK_PIN     0x46
+#define INS_LOGOUT_ALL      0x60
+#define INS_GET_CHALLENGE   0x62
+#define INS_EXT_AUTH        0x38
+
+    // Objects' use and management
+#define INS_CREATE_OBJ      0x5A
+#define INS_DELETE_OBJ      0x52
+#define INS_READ_OBJ        0x56
+#define INS_WRITE_OBJ       0x54
+
+    // Status information
+#define INS_LIST_OBJECTS    0x58
+#define INS_LIST_PINS       0x48
+#define INS_LIST_KEYS       0x3A
+#define INS_GET_STATUS      0x3C
+
+    /* Sizes of particular objects */
+#define MSC_SIZEOF_OBJECTID               4
+#define MSC_SIZEOF_OBJECTSIZE             4
+#define MSC_SIZEOF_KEYINFO                11
+#define MSC_SIZEOF_STATUS                 16
+#define MSC_SIZEOF_VERSION                2
+#define MSC_SIZEOF_FREEMEM                4
+#define MSC_SIZEOF_LOGIDS                 2
+#define MSC_SIZEOF_ADDINFO                8
+#define MSC_SIZEOF_OPTLEN                 2
+#define MSC_SIZEOF_GENOPTIONS             1
+#define MSC_SIZEOF_KEYSIZE                2
+#define MSC_SIZEOF_KEYNUMBER              1
+#define MSC_SIZEOF_KEYTYPE                1
+#define MSC_SIZEOF_KEYPARTNER             1
+#define MSC_SIZEOF_CIPHERMODE             1
+#define MSC_SIZEOF_CIPHERDIR              1
+#define MSC_SIZEOF_CRYPTLEN               2
+#define MSC_SIZEOF_ALGOTYPE               1
+#define MSC_SIZEOF_IDUSED                 1
+#define MSC_SIZEOF_OFFSET                 4
+#define MSC_SIZEOF_ACLSTRUCT              6
+#define MSC_SIZEOF_RWDATA                 1
+#define MSC_SIZEOF_PINSIZE                1
+#define MSC_SIZEOF_PINTRIES               1
+#define MSC_SIZEOF_CIPHERMODE             1
+#define MSC_SIZEOF_CIPHERDIR              1
+#define MSC_SIZEOF_DATALOCATION           1
+#define MSC_SIZEOF_ACLVALUE               2
+#define MSC_SIZEOF_SEEDLENGTH             2
+#define MSC_SIZEOF_RANDOMSIZE             2
+#define MSC_SIZEOF_MINIACL                1
+
+    /* Selects applet - Not to be used by applications */
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCInitializePlugin( 
+  MSCLPTokenConnection  pConnection
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCFinalizePlugin( 
+  MSCLPTokenConnection  pConnection 
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCIdentifyToken( 
+  MSCLPTokenConnection  pConnection 
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteFramework( 
+  MSCLPTokenConnection  pConnection, 
+  MSCLPInitTokenParams  pInitParams 
+);
+
+    /*****************************************************************/
+    /* Core Musclecard functions                                      */
+    /* These functions coorespond directly to internal library        */
+    /* functions.                                                     */
+    /*****************************************************************/
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCGetStatus(
+  MSCLPTokenConnection  pConnection, 
+  MSCLPStatusInfo       pStatusInfo
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCGetCapabilities(
+  MSCLPTokenConnection  pConnection,
+  MSCULong32            Tag,
+  MSCPUChar8            Value,
+  MSCPULong32           Length
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCExtendedFeature( 
+  MSCLPTokenConnection  pConnection, 
+  MSCULong32            extFeature,
+  MSCPUChar8            outData, 
+  MSCULong32            outLength, 
+  MSCPUChar8            inData,
+  MSCPULong32           inLength 
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCGenerateKeys(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		prvKeyNum,
+  MSCUChar8		pubKeyNum,
+  MSCLPGenKeyParams	pParams
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCImportKey(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		keyNum,
+  MSCLPKeyACL		pKeyACL,
+  MSCPUChar8	        pKeyBlob,
+  MSCULong32            keyBlobSize,
+  MSCLPKeyPolicy        keyPolicy,
+  MSCPVoid32		pAddParams,
+  MSCUChar8		addParamsSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCExportKey(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		keyNum,
+  MSCPUChar8	        pKeyBlob,
+  MSCPULong32           keyBlobSize,
+  MSCPVoid32		pAddParams,
+  MSCUChar8		addParamsSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCComputeCrypt( 
+  MSCLPTokenConnection  pConnection,
+  MSCLPCryptInit        cryptInit, 
+  MSCPUChar8            pInputData,
+  MSCULong32            inputDataSize, 
+  MSCPUChar8            pOutputData,
+  MSCPULong32           outputDataSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCExtAuthenticate(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8	        keyNum,
+  MSCUChar8             cipherMode, 
+  MSCUChar8             cipherDirection,
+  MSCPUChar8	        pData,
+  MSCULong32	        dataSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCListKeys(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		seqOption,
+  MSCLPKeyInfo		pKeyInfo
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCCreatePIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCUChar8		pinAttempts,
+  MSCPUChar8	        pPinCode,
+  MSCULong32		pinCodeSize,
+  MSCPUChar8	        pUnblockCode,
+  MSCUChar8		unblockCodeSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCVerifyPIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pPinCode,
+  MSCULong32		pinCodeSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCChangePIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pOldPinCode,
+  MSCUChar8		oldPinCodeSize,
+  MSCPUChar8	        pNewPinCode,
+  MSCUChar8		newPinCodeSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCUnblockPIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pUnblockCode,
+  MSCULong32		unblockCodeSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCListPINs(
+  MSCLPTokenConnection	pConnection,
+  MSCPUShort16	        pPinBitMask
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCCreateObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 	        objectID,
+  MSCULong32		objectSize,
+  MSCLPObjectACL	pObjectACL
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCDeleteObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString  		objectID,
+  MSCUChar8		zeroFlag
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCWriteObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 		objectID,
+  MSCULong32		offset,
+  MSCPUChar8	        pInputData,
+  MSCUChar8		dataSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCReadObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 		objectID,
+  MSCULong32		offset,
+  MSCPUChar8	        pOutputData,
+  MSCUChar8		dataSize
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCListObjects(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		seqOption,
+  MSCLPObjectInfo	pObjectInfo
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCLogoutAll(
+  MSCLPTokenConnection	pConnection
+);
+
+#ifdef WIN32
+MCARDPLUGIN_API
+#endif
+MSC_RV PL_MSCGetChallenge(
+  MSCLPTokenConnection	pConnection,
+  MSCPUChar8	        pSeed,
+  MSCUShort16	        seedSize,
+  MSCPUChar8	        pRandomData,
+  MSCUShort16	        randomDataSize
+);
+
+    /*****************************************************************/
+    /* Extended Musclecard functions                                  */
+    /* These functions do not coorespond to internal library funcions */
+    /* but rather use them to provide some extended functionality.    */
+    /*****************************************************************/
+
+MSC_RV PL_MSCGetKeyAttributes( 
+  MSCLPTokenConnection  pConnection, 
+  MSCUChar8             keyNumber,
+  MSCLPKeyInfo          pKeyInfo 
+);
+
+MSC_RV PL_MSCGetObjectAttributes( 
+  MSCLPTokenConnection  pConnection, 
+  MSCString             objectID,
+  MSCLPObjectInfo       pObjectInfo 
+);
+
+MSC_RV PL_MSCWriteLargeObject( 
+  MSCLPTokenConnection  pConnection, 
+  MSCString             objectID,
+  MSCPUChar8            pInputData, 
+  MSCULong32            dataSize 
+);
+
+MSC_RV PL_MSCReadLargeObject( 
+  MSCLPTokenConnection  pConnection, 
+  MSCString             objectID,
+  MSCPUChar8            pOutputData, 
+  MSCULong32            dataSize 
+);
+
+MSC_RV PL_MSCReadAllocateObject( 
+  MSCLPTokenConnection  pConnection, 
+  MSCString             objectID,
+  MSCPUChar8*           pOutputData, 
+  MSCPULong32           dataSize 
+);
+
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif /* __musclecardApplet_h__ */

Added: trunk/SmartCardServices/src/PCSC/PCSC.exp
===================================================================
--- trunk/SmartCardServices/src/PCSC/PCSC.exp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/PCSC.exp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,71 @@
+_DebugLogSetLevel
+_DebugLogSetLogType
+_MSCBeginTransaction
+_MSCCancelEventWait
+_MSCChangePIN
+_MSCClearReset
+_MSCComputeCrypt
+_MSCCreateObject
+_MSCCreatePIN
+_MSCDeleteObject
+_MSCEndTransaction
+_MSCEstablishConnection
+_MSCExportKey
+_MSCExtAuthenticate
+_MSCExtendedFeature
+_MSCGenerateKeys
+_MSCGetCapabilities
+_MSCGetChallenge
+_MSCGetKeyAttributes
+_MSCGetObjectAttributes
+_MSCGetStatus
+_MSCImportKey
+_MSCIsTokenChanged
+_MSCIsTokenKnown
+_MSCIsTokenMoved
+_MSCIsTokenReset
+_MSCListKeys
+_MSCListObjects
+_MSCListPINs
+_MSCListTokens
+_MSCLogoutAll
+_MSCReEstablishConnection
+_MSCReadAllocateObject
+_MSCReadObject
+_MSCReleaseConnection
+_MSCUnblockPIN
+_MSCVerifyPIN
+_MSCWaitForTokenEvent
+_MSCWriteFramework
+_MSCWriteObject
+_PCSCVersionNumber
+_PCSCVersionString
+_SCardBeginTransaction
+_SCardCancel
+_SCardCancelTransaction
+_SCardConnect
+_SCardControl
+_SCardControl132
+_SCardDisconnect
+_SCardEndTransaction
+_SCardEstablishContext
+_SCardGetAttrib
+_SCardGetStatusChange
+_SCardIsValidContext
+_SCardListReaderGroups
+_SCardListReaders
+_SCardReconnect
+_SCardReleaseContext
+_SCardSetAttrib
+_SCardSetTimeout
+_SCardStatus
+_SCardTransmit
+_SCardUnload
+_TPSvcDropdir
+_mscLockThread
+_mscUnLockThread
+_msc_error
+_pcsc_stringify_error
+_g_rgSCardT0Pci
+_g_rgSCardT1Pci
+_g_rgSCardRawPci

Added: trunk/SmartCardServices/src/PCSC/PCSCDevice.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/PCSCDevice.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/PCSCDevice.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  PCSCDevice.cpp
+ *  SmartCardServices
+ *
+ */
+
+#include "PCSCDevice.h"
+#include <security_utilities/debugging.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/usb/IOUSBLib.h>
+
+namespace PCSCD {
+
+Device::~Device()  throw()
+{
+}
+
+void Device::dump()
+{
+	//, serial: %s", // always empty for known readers, mSerialNumber.c_str());
+	secdebug("device", "  Service: 0x%04X, Address: 0x%08X, vendor/product: 0x%04X/0x%04X, vendor/product: %s/%s", 
+		ioObject(), mAddress, mVendorid, mProductid, mVendorName.c_str(), mProductName.c_str());
+	secdebug("device", "     path: %s", path().c_str());
+}
+
+/*
+Device::Device(const Device& x) throw()				// copy constructor
+{
+	*this = x;
+}
+
+Device& Device::operator= (const Device& x) throw()	// assignment operator
+{
+	mAddress = x.mAddress;
+	mName = x.mName;
+	mLibPath = x.mLibPath;
+	return *this;
+}
+*/
+
+} // end namespace PCSCD
+

Added: trunk/SmartCardServices/src/PCSC/PCSCDevice.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/PCSCDevice.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/PCSCDevice.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  PCSCDevice.h
+ *  SmartCardServices
+ *
+ */
+
+#ifndef _H_PCSCDEVICE
+#define _H_PCSCDEVICE
+
+#include <security_utilities/iodevices.h>
+#include <security_utilities/refcount.h>
+
+#if defined(__cplusplus)
+
+namespace PCSCD {
+
+class Device : public IOKit::Device, public RefCount
+{
+public:
+//	Device() :  { }
+	Device(io_service_t d) : IOKit::Device(d) { }
+
+	virtual ~Device() throw();
+
+	bool operator < (const Device &other) const { return this->address() < other.address(); }
+
+	void setAddress(uint32_t address)  { mAddress = address; }
+	void setInterfaceClass(uint32_t interfaceClass)  { mInterfaceClass = interfaceClass; }
+	void setDeviceClass(uint32_t deviceClass)  { mDeviceClass = deviceClass; }
+	void setVendorid(uint32_t vendorid)  { mVendorid = vendorid; }
+	void setProductid(uint32_t productid)  { mProductid = productid; }
+	void setPath(const std::string path)  { mLibPath = path; }
+	void setName(const std::string name)  { mName = name; }
+	void setIsPCCard(bool isPCCard)  { mIsPCCard = isPCCard; }
+
+	uint32_t address() const { return mAddress; }
+	uint32_t interfaceClass() const { return mInterfaceClass; }
+	uint32_t deviceClass() const { return mDeviceClass; }
+	uint32_t vendorid() const { return mVendorid; }
+	uint32_t productid() const { return mProductid; }
+	std::string path() const { return mLibPath; }
+	std::string name() const { return mName; }
+	bool isPCCard() const { return mIsPCCard; }
+	
+	std::string vendorName() const { return mVendorName; }
+	std::string productName() const { return mProductName; }
+	std::string serialNumber() const { return mSerialNumber; }
+
+	void setDebugParams(const std::string vendorName, const std::string productName,
+		const std::string serialNumber)
+		{ mVendorName = vendorName; mProductName = productName; mSerialNumber = serialNumber;}
+	
+	void dump();
+	
+private:
+
+	uint32_t mAddress;
+
+	std::string mName;			// Manufacturer's name for device
+	std::string mLibPath;		// path to driver bundle from PCSCDriverBundle
+
+	uint32_t mInterfaceClass;	// If present, one of kUSBChipSmartCardInterfaceClass/kUSBVendorSpecificInterfaceClass
+	uint32_t mDeviceClass;		// If == kUSBVendorSpecificClass, check vendor/product
+	uint32_t mVendorid;
+	uint32_t mProductid;
+
+	bool mIsPCCard;
+
+	// Mainly for debugging
+	std::string mVendorName, mProductName, mSerialNumber;
+};
+
+} // end namespace PCSCD
+
+#endif /* __cplusplus__ */
+
+#endif // _H_PCSCDEVICE

Added: trunk/SmartCardServices/src/PCSC/PCSCDriverBundle.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/PCSCDriverBundle.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/PCSCDriverBundle.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  PCSCDriverBundle.cpp
+ *  SmartCardServices
+ */
+
+/*
+	A driver bundle is a standard Mac OS X bundle that usually lives in the directory:
+	
+		/usr/libexec/SmartCardServices/drivers/
+	
+	The two major components of this bundle are the executable and the Info.plist. A single
+	driver bundle may provide support for multiple readers. See
+	
+		<rdar://problem/4432039> pcscd crash for multiple VID/PIDs
+	and
+		<http://pcsclite.alioth.debian.org/ifdhandler-3/node7.html>
+
+	The key that determines if a driver supports only one reader or multiple readers is
+	"ifdVendorID", sometimes referred to as the manufacturer name. If this is a
+	CFStringRef, then only one reader is supported; if it is a CFArrayRef, then
+	multiple readers are supports. There are three fields for each reader:
+	
+		VendorID		uint32_t
+		ProductID		uint32_t
+		Friendly name	string
+
+	See e.g. http://pcsclite.alioth.debian.org/ccid.html for a working driver with multiple IDs.
+
+*/
+
+#include "PCSCDriverBundle.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/debugging.h>
+#include <security_utilities/errors.h>
+#include <IOKit/usb/USBSpec.h>
+#include <IOKit/usb/USB.h>
+
+#define DEBUG_BUNDLE_MATCHES 1
+
+namespace PCSCD {
+
+// Keys in CFDictionary for bundle's Info.plist
+static const CFStringRef kManufacturerName	= CFSTR("ifdVendorID");
+static const CFStringRef kProductName		= CFSTR("ifdProductID");
+static const CFStringRef kFriendlyName		= CFSTR("ifdFriendlyName");
+static const CFStringRef kInterfaceClass	= CFSTR("ifdInterfaceClass");
+static const CFStringRef kInterfaceSubClass	= CFSTR("ifdInterfaceSubClass");
+static const CFStringRef kInterfaceProtocol	= CFSTR("ifdInterfaceProtocol");
+
+DriverBundle::DriverBundle(CFBundleRef bundle) : LoadableBundle(bundle)
+{
+	initialize(CFBundleGetInfoDictionary(bundle));
+}
+
+void DriverBundle::initialize(CFDictionaryRef dict)
+{
+	const int radix = 16;
+
+	try
+	{
+		CFTypeRef vend = CFDictionaryGetValue(dict, kManufacturerName);
+		if (!vend)
+		{
+			// Must be a class driver
+			secdebug("pcscd", "Class Driver: %s", path().c_str());
+			std::string istr(getStringAttr(dict,kInterfaceClass));
+			uint8_t dclass = strtoul(istr.c_str(), NULL, radix);
+			std::string sstr(getStringAttr(dict,kInterfaceSubClass));
+			uint8_t dsubclass = strtoul(sstr.c_str(), NULL, radix);
+			std::string pstr(getStringAttr(dict,kInterfaceProtocol));
+			uint8_t dprotocol = strtoul(pstr.c_str(), NULL, radix);
+			std::string name(getStringAttr(dict,kFriendlyName));
+			DeviceDescription *dev = new DeviceDescription(dclass, dsubclass, dprotocol, name);
+			addProduct(dev);
+		}
+		else
+		if (CFGetTypeID(vend) == CFArrayGetTypeID())
+		{
+			secdebug("pcscd", "Driver with aliases: %s", path().c_str());
+			CFTypeRef xprod = CFDictionaryGetValue(dict, kProductName);
+			CFTypeRef xname = CFDictionaryGetValue(dict, kFriendlyName);
+			if (!xprod || !xname || 
+				(CFGetTypeID(xprod) != CFArrayGetTypeID()) || (CFGetTypeID(xname) != CFArrayGetTypeID()))
+				CFError::throwMe();
+			CFRef<CFArrayRef> products(reinterpret_cast<CFArrayRef>(xprod));
+			CFRef<CFArrayRef> names   (reinterpret_cast<CFArrayRef>(xname));
+			const int productCount = CFArrayGetCount(reinterpret_cast<CFArrayRef>(vend));
+			// Make sure parallel arrays vendor, product, name are same size
+			if ((productCount != CFArrayGetCount(products)) ||
+				(productCount != CFArrayGetCount(names)))
+				CFError::throwMe();
+
+			for (int ix=0;ix<productCount;++ix)
+			{
+				std::string vstr(getStringAttr(reinterpret_cast<CFArrayRef>(vend), ix));
+				uint16_t vendor = strtoul(vstr.c_str(), NULL, radix);
+				std::string pstr(getStringAttr(products, ix));
+				uint16_t product = strtoul(pstr.c_str(), NULL, radix);
+				std::string name(getStringAttr(names, ix));
+				DeviceDescription *dev = new DeviceDescription(vendor, product, name);
+				addProduct(dev);
+			}
+		}
+		else
+		if (CFGetTypeID(vend) == CFStringGetTypeID())
+		{
+			secdebug("pcscd", "Driver for single product: %s", path().c_str());
+			std::string vstr(cfString(reinterpret_cast<CFStringRef>(vend)));
+			uint16_t vendor = strtoul(vstr.c_str(), NULL, radix);
+			std::string pstr(getStringAttr(dict,kProductName));
+			uint16_t product = strtoul(pstr.c_str(), NULL, radix);
+			std::string name(getStringAttr(dict,kFriendlyName));
+			DeviceDescription *dev = new DeviceDescription(vendor, product, name);
+			addProduct(dev);
+		}
+		else
+			CFError::throwMe();
+	}
+	catch (...)
+	{
+		secdebug("pcscd", "Malformed Info.plist for: %s", path().c_str());
+        secdebug("pcscd", "error getting plugin directory bundles");
+		return;
+	}
+
+	dump();
+}
+
+std::string DriverBundle::getStringAttr(CFDictionaryRef dict, CFStringRef key)
+{
+	// Do some sanity checking on potential string values in the plist
+	CFTypeRef attr = CFDictionaryGetValue(dict, key);
+	if (!attr)
+		return std::string();
+	if (CFGetTypeID(attr) != CFStringGetTypeID())
+		CFError::throwMe();
+	
+	return std::string(cfString(static_cast<CFStringRef>(attr)));
+}
+
+std::string DriverBundle::getStringAttr(CFArrayRef arr, CFIndex idx)
+{
+	// Do some sanity checking on potential string values in the plist
+	CFTypeRef attr = CFArrayGetValueAtIndex(arr, idx);
+	if (!attr)
+		return std::string();
+	if (CFGetTypeID(attr) != CFStringGetTypeID())
+		CFError::throwMe();
+	
+	return std::string(cfString(static_cast<CFStringRef>(attr)));
+}
+
+DriverBundle::~DriverBundle() throw()
+{
+	// delete supported devices objects
+}
+
+uint32_t DriverBundle::matches(const PCSCD::Device &device, std::string &name) const
+{
+	// Searches for a driver bundle that matches device. If found,
+	// it sets the libpath for the device and returns true.
+
+#ifdef DEBUG_BUNDLE_MATCHES
+	secdebug("device", " DEVICE: vendor/product: 0x%04X/0x%04X, interfaceClass: 0x%04X, vendor/product:  %s/%s", 
+		device.vendorid(), device.productid(), device.interfaceClass(),
+		device.vendorName().c_str(), device.productName().c_str());
+#endif
+
+	// Look for a manufacturer-specific driver first
+	for (ConstDeviceDescriptionIterator it=mDeviceDescriptions.begin();it!=mDeviceDescriptions.end();++it)
+	{
+		const DeviceDescription *desc = static_cast<DeviceDescription *>(*it);
+#ifdef DEBUG_BUNDLE_MATCHES
+		secdebug("device", "   DESC: vendor/product: 0x%04X/0x%04X, interfaceClass: 0x%04X, path: %s", 
+			desc->vendorid(), desc->productid(), desc->interfaceClass(), path().c_str());
+#endif
+		if (desc->vendorid()  && (desc->vendorid()==device.vendorid()) &&
+			desc->productid() && (desc->productid()==device.productid()))
+		{
+			name = desc->name();
+			return eMatchVendorSpecific;
+		}
+	}
+
+	if (device.interfaceClass())
+		for (ConstDeviceDescriptionIterator it=mDeviceDescriptions.begin();it!=mDeviceDescriptions.end();++it)
+		{
+			const DeviceDescription *desc = static_cast<DeviceDescription *>(*it);
+			if (desc->interfaceClass() && (desc->interfaceClass()==device.interfaceClass()))
+			{
+				name = desc->name();
+				return eMatchInterfaceClass;
+			}
+		}
+
+	return eMatchNone;
+}		
+
+#pragma mark -------------------- Operators --------------------
+
+bool DriverBundle::operator < (const DriverBundle &other) const throw()
+{
+	return this->path() < other.path();
+}
+
+bool DeviceDescription::operator < (const DeviceDescription &other) const throw()
+{
+    if (this->mVendor >= other.mVendor)
+		return false;
+
+    return (this->mProduct < other.mProduct);
+}
+
+#pragma mark -------------------- Debugging Routines --------------------
+
+void DriverBundle::dump()
+{
+#ifndef NDEBUG
+	secdebug("pcscd", "Driver at path: %s", path().c_str());
+	for (DeviceDescriptionIterator it = mDeviceDescriptions.begin(); it != mDeviceDescriptions.end();++it)
+		(*it)->dump();
+#endif
+}
+
+void DeviceDescription::dump()
+{
+#ifndef NDEBUG
+	secdebug("pcscd", "   Friendly name: %s", mFriendlyName.c_str());
+	if (interfaceClass())
+		secdebug("pcscd", "   Class: 0x%02X  SubClass: 0x%02X  Protocol: 0x%02X",
+			mDeviceClass,mDeviceSubClass,mDeviceProtocol);
+	else
+		secdebug("pcscd", "   VendorID: 0x%04X  ProductID: 0x%04X", mVendor, mProduct);
+#endif
+}
+
+} // end namespace PCSCD

Added: trunk/SmartCardServices/src/PCSC/PCSCDriverBundle.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/PCSCDriverBundle.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/PCSCDriverBundle.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  PCSCDriverBundle.h
+ *  SmartCardServices
+ */
+
+#ifndef _H_XPCSCDRIVERBUNDLE
+#define _H_XPCSCDRIVERBUNDLE
+
+#include <string>
+#include <vector>
+#include <security_utilities/refcount.h>
+#include <security_utilities/osxcode.h>
+#include "PCSCDevice.h"
+
+#if defined(__cplusplus)
+
+namespace PCSCD {
+
+class DeviceDescription
+{
+public:
+
+	DeviceDescription() { }
+	DeviceDescription(uint16_t vendor, uint16_t product, std::string name) :
+		mVendor(vendor), mProduct(product),
+		mDeviceClass(0), mDeviceSubClass(0), mDeviceProtocol(0),
+		mFriendlyName(name) {}
+	DeviceDescription(uint8_t deviceClass, uint8_t deviceSubClass, uint8_t protocol, std::string name) :
+		mVendor(0), mProduct(0),
+		mDeviceClass(deviceClass), mDeviceSubClass(deviceSubClass), mDeviceProtocol(protocol),
+		mFriendlyName(name) {}
+
+	bool operator < (const DeviceDescription &other) const throw();
+
+	uint8_t interfaceClass() const	{ return mDeviceClass; }
+	uint16_t vendorid() const { return mVendor; }
+	uint16_t productid() const { return mProduct; }
+	std::string name() const { return mFriendlyName; }
+
+	void dump();
+
+protected:
+	// Match types from <IOKit/USB.h> for IOUSBDeviceDescriptor
+	
+	uint16_t mVendor;			// Unique vendor's manufacturer code assigned by the USB-IF
+	uint16_t mProduct;			// Manufacturer's unique product code
+
+	uint8_t mDeviceClass;
+	uint8_t mDeviceSubClass;
+	uint8_t mDeviceProtocol;
+
+	std::string mFriendlyName;	// Manufacturer's name for device
+};
+
+/*
+ * An aggregation of useful information on a driver bundle in the
+ * drop directory.
+ */
+
+class DriverBundle : public LoadableBundle
+{
+private:
+	DriverBundle(const char *pathname) : LoadableBundle(pathname) { }
+
+public:
+	DriverBundle(CFBundleRef bundle);
+
+	virtual ~DriverBundle() throw();
+
+	bool operator < (const DriverBundle &other) const throw();
+
+	void addProduct(DeviceDescription *dev) { mDeviceDescriptions.push_back(dev); }
+
+	uint32_t matches(const Device &device, std::string &name) const;
+	
+	enum 
+	{
+		eMatchNone = 0,
+		eMatchInterfaceClass,	// must be less than eMatchVendorSpecific
+		eMatchVendorSpecific
+	};
+
+protected:
+	void initialize(CFDictionaryRef dict);
+
+private:
+
+	typedef std::vector<DeviceDescription *> DeviceDescriptions;
+    typedef DeviceDescriptions::iterator DeviceDescriptionIterator;
+    typedef DeviceDescriptions::const_iterator ConstDeviceDescriptionIterator;
+	DeviceDescriptions mDeviceDescriptions;
+
+	std::string getStringAttr(CFDictionaryRef dict, CFStringRef key);
+	std::string getStringAttr(CFArrayRef arr, CFIndex idx);
+	void dump();
+};
+
+} // end namespace PCSCD
+
+#endif /* __cplusplus__ */
+
+#endif /* _H_XPCSCDRIVERBUNDLE */

Added: trunk/SmartCardServices/src/PCSC/PCSCDriverBundles.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/PCSCDriverBundles.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/PCSCDriverBundles.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/*
+ *  PCSCDriverBundles.cpp
+ *  SmartCardServices
+ */
+
+/*
+	Creates a vector of driver bundle info structures from the hot-plug driver
+	directory.
+
+	Returns NULL on error and a pointer to an allocated HPDriver vector on
+	success.  The caller must free the HPDriver with a call to HPDriversRelease().
+ 
+	See http://developer.apple.com/documentation/CoreFoundation/Reference/CFArrayRef/index.html#//apple_ref/doc/uid/20001192
+	for information about CFArrayApplyFunction
+*/
+
+#include "PCSCDriverBundles.h"
+#include <security_utilities/debugging.h>
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/errors.h>
+#include <map>
+
+namespace PCSCD {
+
+static const char *kPCSCLITE_HP_DROPDIR = "/usr/libexec/SmartCardServices/drivers/";
+static const char *kENV_PCSC_DEBUG_DRIVER = "PCSC_DEBUG_DRIVER_DIR";	// environment var
+
+DriverBundles::DriverBundles()
+{
+	// If debugging, look in build directory
+#if !defined(NDEBUG)
+	const char *envar = kENV_PCSC_DEBUG_DRIVER;
+	if (envar)
+		if (const char *envPath = getenv(envar))
+		{
+			// treat envPath as a classic colon-separated list of directories
+			secdebug("pathlist", "%p configuring from env(\"%s\")", this, envar);
+			while (const char *p = strchr(envPath, ':'))
+			{
+				addDirectory(string(envPath, p - envPath));
+				envPath = p + 1;
+			}
+			addDirectory(envPath);
+		}
+#endif
+	addDirectory(kPCSCLITE_HP_DROPDIR);
+}
+
+bool DriverBundles::find(PCSCD::Device &device)  const
+{
+	// Searches for a driver bundle that matches device. If found,
+	// it sets the libpath for the device and returns true.
+
+	ProductMatchMap matchingProducts;
+
+	for (DriverBundles::const_iterator it=this->begin();it!=this->end();++it)
+	{
+		std::string name;
+		const DriverBundle *bndl = static_cast<DriverBundle *>((*it).get());
+		if (int32_t score = bndl->matches(device, name))
+		{
+			ProductMatchInfo *mi =  new ProductMatchInfo(bndl->path(),name);
+			matchingProducts.push_back(make_pair(score, mi));
+		}
+	}
+	
+	if (matchingProducts.empty())
+		return false;
+	
+	sort(matchingProducts.begin(), matchingProducts.end());
+	const ProductMatchInfo *mi = (*matchingProducts.rbegin()).second;
+	device.setName(mi->name());
+	device.setPath(mi->path());
+	// clean up
+	for (ProductMatchMap::iterator it = matchingProducts.begin();it!=matchingProducts.end();++it)
+		delete (*it).second;
+	return true;
+}
+
+} // end namespace PCSCD

Added: trunk/SmartCardServices/src/PCSC/PCSCDriverBundles.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/PCSCDriverBundles.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/PCSCDriverBundles.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  PCSCDriverBundles.h
+ *  SmartCardServices
+ */
+
+#ifndef _H_XPCSCDRIVERBUNDLES
+#define _H_XPCSCDRIVERBUNDLES
+
+#include "PCSCDriverBundle.h"
+#include "PCSCDevice.h"
+#include <security_utilities/threading.h>
+#include <security_utilities/coderepository.h>
+#include <security_utilities/osxcode.h>
+#include <set>
+	
+#if defined(__cplusplus)
+
+namespace PCSCD {
+
+class DriverBundles : public CodeRepository<DriverBundle>
+{
+	friend class DriverBundle;
+
+public:
+	DriverBundles();
+	~DriverBundles() {}
+	
+	bool find(Device &device) const;
+	
+	// These are the things we need to know about which part of
+	// bundle we are matched up with
+
+	class ProductMatchInfo
+	{
+	public:
+		ProductMatchInfo(std::string path, std::string name) : mPath(path), mName(name) {}
+		
+		std::string path() const { return mPath; }
+		std::string name() const { return mName; }
+
+	private:
+		std::string mPath;
+		std::string mName;
+	};
+
+	typedef std::vector< pair<int32_t, ProductMatchInfo * > > ProductMatchMap; 
+};
+
+} // end namespace PCSCD
+
+#endif /* __cplusplus__ */
+
+#endif /* _H_XPCSCDRIVERBUNDLE */

Added: trunk/SmartCardServices/src/PCSC/atrhandler.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/atrhandler.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/atrhandler.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : atrhandler.c
+            Author : David Corcoran
+            Date   : 7/27/99
+            License: Copyright (C) 1999 David Corcoran
+                     <corcoran at linuxnet.com> 
+            Purpose: This keeps track of smartcard protocols,
+                     timing issues, and atr handling.
+ 
+********************************************************************/
+
+#include <syslog.h>
+#include <string.h>
+
+#include "config.h"
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "atrhandler.h"
+
+/*
+ * Uncomment the following for ATR debugging 
+ */
+/*
+ * #define ATR_DEBUG 1 
+ */
+
+short ATRDecodeAtr(PSMARTCARD_EXTENSION psExtension,
+	const unsigned char *pucAtr, DWORD dwLength)
+{
+
+	USHORT p;
+	UCHAR K, TCK;				/* MSN of T0/Check Sum */
+	UCHAR Y1i, T;				/* MSN/LSN of TDi */
+	short TAi, TBi, TCi, TDi;	/* Interface characters */
+
+	/*
+	 * Zero out everything 
+	 */
+	p = K = TCK = Y1i = T = TAi = TBi = TCi = TDi = 0;
+
+	if (dwLength < 2)
+	{
+		return 0;	/* Atr must have TS and T0 */
+	}
+
+	/*
+	 * Zero out the bitmasks 
+	 */
+
+	psExtension->CardCapabilities.AvailableProtocols = 0x00;
+	psExtension->CardCapabilities.CurrentProtocol = 0x00;
+
+	/*
+	 * Decode the TS byte 
+	 */
+
+	if (pucAtr[0] == 0x3F)
+	{	/* Inverse convention used */
+		psExtension->CardCapabilities.Convention =
+			SCARD_CONVENTION_INVERSE;
+	} else if (pucAtr[0] == 0x3B)
+	{	/* Direct convention used */
+		psExtension->CardCapabilities.Convention = SCARD_CONVENTION_DIRECT;
+	} else
+	{
+		memset(psExtension, 0x00, sizeof(SMARTCARD_EXTENSION));
+		return 0;
+	}
+
+	/*
+	 * Here comes the platform dependant stuff 
+	 */
+
+	/*
+	 * Decode the T0 byte 
+	 */
+	Y1i = pucAtr[1] >> 4;	/* Get the MSN in Y1 */
+	K = pucAtr[1] & 0x0F;	/* Get the LSN in K */
+
+	p = 2;
+
+#ifdef ATR_DEBUG
+	debug_msg("Conv %02X, Y1 %02X, K %02X",
+		psExtension->CardCapabilities.Convention, Y1i, K);
+#endif
+
+	/*
+	 * Examine Y1 
+	 */
+
+	do
+	{
+
+		TAi = (Y1i & 0x01) ? pucAtr[p++] : -1;
+		TBi = (Y1i & 0x02) ? pucAtr[p++] : -1;
+		TCi = (Y1i & 0x04) ? pucAtr[p++] : -1;
+		TDi = (Y1i & 0x08) ? pucAtr[p++] : -1;
+
+#ifdef ATR_DEBUG
+		debug_msg("T's %02X %02X %02X %02X", TAi, TBi, TCi, TDi);
+		debug_msg("P %02X", p);
+#endif
+
+		/*
+		 * Examine TDi to determine protocol and more 
+		 */
+		if (TDi >= 0)
+		{
+			Y1i = TDi >> 4;	/* Get the MSN in Y1 */
+			T = TDi & 0x0F;	/* Get the LSN in K */
+
+			/*
+			 * Set the current protocol TD1 
+			 */
+			if (psExtension->CardCapabilities.CurrentProtocol == 0x00)
+			{
+				switch (T)
+				{
+				case 0:
+					psExtension->CardCapabilities.CurrentProtocol =
+						SCARD_PROTOCOL_T0;
+					break;
+				case 1:
+					psExtension->CardCapabilities.CurrentProtocol =
+						SCARD_PROTOCOL_T1;
+					break;
+				default:
+					return 0;
+				}
+			}
+
+			if (T == 0)
+			{
+#ifdef ATR_DEBUG
+				debug_msg("T=0 Protocol Found");
+#endif
+				psExtension->CardCapabilities.AvailableProtocols |=
+					SCARD_PROTOCOL_T0;
+				psExtension->CardCapabilities.T0.BGT = 0;
+				psExtension->CardCapabilities.T0.BWT = 0;
+				psExtension->CardCapabilities.T0.CWT = 0;
+				psExtension->CardCapabilities.T0.CGT = 0;
+				psExtension->CardCapabilities.T0.WT = 0;
+			} else if (T == 1)
+			{
+#ifdef ATR_DEBUG
+				debug_msg("T=1 Protocol Found");
+#endif
+				psExtension->CardCapabilities.AvailableProtocols |=
+					SCARD_PROTOCOL_T1;
+				psExtension->CardCapabilities.T1.BGT = 0;
+				psExtension->CardCapabilities.T1.BWT = 0;
+				psExtension->CardCapabilities.T1.CWT = 0;
+				psExtension->CardCapabilities.T1.CGT = 0;
+				psExtension->CardCapabilities.T1.WT = 0;
+			} else
+			{
+				psExtension->CardCapabilities.AvailableProtocols |= T;
+				/*
+				 * Do nothing for now since other protocols are not
+				 * supported at this time 
+				 */
+			}
+
+		} else
+		{
+			Y1i = 0;
+		}
+
+		if (p > MAX_ATR_SIZE)
+		{
+			memset(psExtension, 0x00, sizeof(SMARTCARD_EXTENSION));
+			return 0;
+		}
+
+	}
+	while (Y1i != 0);
+
+	/*
+	 * If TDx is not set then the current must be T0 
+	 */
+	if (psExtension->CardCapabilities.CurrentProtocol == 0x00)
+	{
+		psExtension->CardCapabilities.CurrentProtocol = SCARD_PROTOCOL_T0;
+		psExtension->CardCapabilities.AvailableProtocols |=
+			SCARD_PROTOCOL_T0;
+	}
+
+	/*
+	 * Take care of the historical characters 
+	 */
+
+	psExtension->ATR.HistoryLength = K;
+	memcpy(psExtension->ATR.HistoryValue, &pucAtr[p], K);
+
+	p = p + K;
+
+	/*
+	 * Check to see if TCK character is included It will be included if
+	 * more than T=0 is supported 
+	 */
+
+	if (psExtension->CardCapabilities.AvailableProtocols &
+		SCARD_PROTOCOL_T1)
+	{
+		TCK = pucAtr[p++];
+	}
+
+	memcpy(psExtension->ATR.Value, pucAtr, p);
+	psExtension->ATR.Length = p;	/* modified from p-1 */
+
+	return 1;
+}

Added: trunk/SmartCardServices/src/PCSC/atrhandler.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/atrhandler.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/atrhandler.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : atrhandler.h
+            Author : David Corcoran
+            Date   : 7/27/99
+	    License: Copyright (C) 1999 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This keeps track of smartcard protocols,
+                     timing issues, and atr handling.
+ 
+********************************************************************/
+
+#ifndef __atrhandler_h__
+#define __atrhandler_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define SCARD_CONVENTION_DIRECT  0x0001
+#define SCARD_CONVENTION_INVERSE 0x0002
+
+	typedef struct _SMARTCARD_EXTENSION
+	{
+
+		struct _ATR
+		{
+			DWORD Length;
+			UCHAR Value[MAX_ATR_SIZE];
+			DWORD HistoryLength;
+			UCHAR HistoryValue[MAX_ATR_SIZE];
+		}
+		ATR;
+
+		DWORD ReadTimeout;
+
+		struct _CardCapabilities
+		{
+			UCHAR AvailableProtocols;
+			UCHAR CurrentProtocol;
+			UCHAR Convention;
+			USHORT ETU;
+
+			struct _PtsData
+			{
+				UCHAR F1;
+				UCHAR D1;
+				UCHAR I1;
+				UCHAR P1;
+				UCHAR N1;
+			}
+			PtsData;
+
+			struct _T1
+			{
+				USHORT BGT;
+				USHORT BWT;
+				USHORT CWT;
+				USHORT CGT;
+				USHORT WT;
+			}
+			T1;
+
+			struct _T0
+			{
+				USHORT BGT;
+				USHORT BWT;
+				USHORT CWT;
+				USHORT CGT;
+				USHORT WT;
+			}
+			T0;
+
+		}
+		CardCapabilities;
+
+		/*
+		 * PREADER_CONNECTION psReaderConnection; 
+		 */
+
+	}
+	SMARTCARD_EXTENSION, *PSMARTCARD_EXTENSION;
+
+	/*
+	 * Decodes the ATR and fills the structure 
+	 */
+
+	short ATRDecodeAtr(PSMARTCARD_EXTENSION psExtension,
+		const unsigned char *pucAtr, DWORD dwLength);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __smclib_h__ */

Added: trunk/SmartCardServices/src/PCSC/config.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/config.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/config.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,200 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  config.h
+ *  SmartCardServices
+ */
+
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* display ATR parsing debug messages. */
+/* #undef ATR_DEBUG */
+
+/* Define to 1 if you have the `daemon' function. */
+#define HAVE_DAEMON 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <dl.h> header file. */
+/* #undef HAVE_DL_H */
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `flock' function. */
+#define HAVE_FLOCK 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Libusb is available */
+/* #undef HAVE_LIBUSB */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `nanosleep' function. */
+#define HAVE_NANOSLEEP 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Define to 1 if `stat' has the bug that it succeeds when given the
+   zero-length file name argument. */
+/* #undef HAVE_STAT_EMPTY_STRING_BUG */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <usb.h> header file. */
+/* #undef HAVE_USB_H */
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+   slash. */
+/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
+
+/* Name of package */
+#define PACKAGE "PCSC Framework"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "pcsc-lite"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "pcsc-lite 1.4.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pcsc-lite"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.4.0"
+
+/* directory containing USB drivers */
+//#define PCSCLITE_HP_DROPDIR "/usr/local/pcsc/drivers"
+
+/* PC/SC target architecture */
+#define PCSC_ARCH "MacOS"
+
+/* Define to the necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* directory containing IPC files (default /var/run) */
+/* #undef USE_IPCDIR */
+
+/* file containing pcscd pid */
+#define USE_RUN_PID "/var/run/pcscd"
+
+/* Version number of package */
+#define VERSION "1.4.0"
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#define YYTEXT_POINTER 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* enable full musclecard debug messaging. */
+  #define MSC_DEBUG 1
+


Property changes on: trunk/SmartCardServices/src/PCSC/config.h
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/SmartCardServices/src/PCSC/configfile.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/configfile.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/configfile.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1781 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/*
+ * A lexical scanner generated by flex 
+ */
+
+/*
+ * Scanner skeleton version: $Header:
+ * /home/cvsroot/muscle/PCSC/src/configfile.c,v 1.3 2002/03/31 07:05:07
+ * corcoran Exp $ 
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+/*
+ * cfront 1.2 defines "c_plusplus" instead of "__cplusplus" 
+ */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * Use prototypes in function declarations. 
+ */
+#define YY_USE_PROTOS
+
+/*
+ * The "const" storage-class-modifier is valid. 
+ */
+#define YY_USE_CONST
+
+#else							/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif							/* __STDC__ */
+#endif							/* ! __cplusplus */
+
+#ifdef __TURBOC__
+#pragma warn -rch
+#pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/*
+ * Returned upon end-of-file. 
+ */
+#define YY_NULL 0
+
+/*
+ * Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative, we
+ * want to instead treat it as an 8-bit unsigned char, hence the double
+ * cast. 
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/*
+ * Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN. 
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/*
+ * Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility. 
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/*
+ * Action number for EOF rule of a given start state. 
+ */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/*
+ * Special action meaning "start processing a new file". 
+ */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/*
+ * Size of default input buffer. 
+ */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/*
+ * The funky do-while in the following #define is used to turn the
+ * definition int a single C statement (which needs a semi-colon
+ * terminator).  This avoids problems with code like: if (
+ * condition_holds ) yyless( 5 ); else do_something_else(); Prior to
+ * using the do-while the compiler would get upset at the "else" because
+ * it interpreted the "if" statement as being all done when it reached the 
+ * ';' after the yyless() call. 
+ */
+
+/*
+ * Return all but the first 'n' matched characters back to the input
+ * stream. 
+ */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/*
+ * The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own). 
+ */
+typedef unsigned int yy_size_t;
+
+struct yy_buffer_state
+{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;			/* input buffer */
+	char *yy_buf_pos;			/* current position in input buffer */
+
+	/*
+	 * Size of input buffer in bytes, not including room for EOB
+	 * characters. 
+	 */
+	yy_size_t yy_buf_size;
+
+	/*
+	 * Number of characters read into yy_ch_buf, not including EOB
+	 * characters. 
+	 */
+	int yy_n_chars;
+
+	/*
+	 * Whether we "own" the buffer - i.e., we know we created it, and can
+	 * realloc() it to grow it, and should free() it to delete it. 
+	 */
+	int yy_is_our_buffer;
+
+	/*
+	 * Whether this is an "interactive" input source; if so, and if we're
+	 * using stdio for input, then we want to use getc() instead of
+	 * fread(), to make sure we stop fetching input after each newline. 
+	 */
+	int yy_is_interactive;
+
+	/*
+	 * Whether we're considered to be at the beginning of a line. If so,
+	 * '^' rules will be active on the next match, otherwise not. 
+	 */
+	int yy_at_bol;
+
+	/*
+	 * Whether to try to fill the input buffer when we reach the end of
+	 * it. 
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/*
+	 * When an EOF's been seen but there's still some text to process then 
+	 * we mark the buffer as YY_EOF_PENDING, to indicate that we shouldn't 
+	 * try reading from the input source any more.  We might still have a
+	 * bunch of tokens to match, though, because of possible backing-up.
+	 * When we actually see the EOF, we change the status to "new" (via
+	 * yyrestart()), so that the user can continue scanning by just
+	 * pointing yyin at a new input file. 
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/*
+ * We provide macros for accessing buffer states in case in the future we
+ * want to put the buffer states in a more general "scanner state". 
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+/*
+ * yy_hold_char holds the character lost when yytext is formed. 
+ */
+static char yy_hold_char;
+
+static int yy_n_chars;			/* number of characters read into
+								 * yy_ch_buf */
+
+int yyleng;
+
+/*
+ * Points to current character in buffer. 
+ */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;			/* whether we need to initialize */
+static int yy_start = 0;		/* start state number */
+
+/*
+ * Flag which is used to allow yywrap()'s to do buffer switches instead of 
+ * setting up a fresh yyin.  A bit of a hack ... 
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO((FILE * input_file));
+
+void yy_switch_to_buffer YY_PROTO((YY_BUFFER_STATE new_buffer));
+void yy_load_buffer_state YY_PROTO((void));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO((FILE * file, int size));
+void yy_delete_buffer YY_PROTO((YY_BUFFER_STATE b));
+void yy_init_buffer YY_PROTO((YY_BUFFER_STATE b, FILE * file));
+void yy_flush_buffer YY_PROTO((YY_BUFFER_STATE b));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO((char *base, yy_size_t size));
+YY_BUFFER_STATE yy_scan_string YY_PROTO((yyconst char *yy_str));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO((yyconst char *bytes, int len));
+
+static void *yy_flex_alloc YY_PROTO((yy_size_t));
+static void *yy_flex_realloc YY_PROTO((void *, yy_size_t));
+static void yy_flex_free YY_PROTO((void *));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO((void));
+static yy_state_type yy_try_NUL_trans YY_PROTO((yy_state_type
+		current_state));
+static int yy_get_next_buffer YY_PROTO((void));
+static void yy_fatal_error YY_PROTO((yyconst char msg[]));
+
+/*
+ * Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext. 
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 7
+#define YY_END_OF_BUFFER 8
+static yyconst short int yy_accept[17] = { 0,
+	0, 0, 8, 6, 4, 2, 6, 1, 6, 5,
+	0, 3, 1, 0, 5, 0
+};
+
+static yyconst int yy_ec[256] = { 0,
+	1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 2, 1, 4, 5, 1, 1, 1, 6, 1,
+	1, 1, 1, 1, 7, 7, 7, 8, 8, 8,
+	8, 8, 8, 8, 8, 8, 8, 1, 1, 1,
+	1, 1, 1, 7, 9, 9, 9, 9, 9, 9,
+	9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+	9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+	1, 7, 1, 1, 7, 1, 10, 10, 10, 10,
+
+	10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	10, 10, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1
+};
+
+static yyconst int yy_meta[11] = { 0,
+	1, 1, 2, 1, 1, 1, 1, 1, 1, 1
+};
+
+static yyconst short int yy_base[20] = { 0,
+	0, 0, 15, 31, 31, 31, 8, 0, 10, 10,
+	18, 31, 0, 20, 0, 31, 26, 13, 28
+};
+
+static yyconst short int yy_def[20] = { 0,
+	16, 1, 16, 16, 16, 16, 17, 18, 19, 16,
+	17, 16, 18, 19, 10, 0, 16, 16, 16
+};
+
+static yyconst short int yy_nxt[42] = { 0,
+	4, 5, 6, 7, 8, 9, 10, 10, 10, 10,
+	12, 12, 12, 13, 16, 12, 15, 15, 15, 15,
+	12, 12, 12, 16, 16, 12, 11, 11, 14, 14,
+	3, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	16
+};
+
+static yyconst short int yy_chk[42] = { 0,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	7, 7, 9, 18, 3, 9, 10, 10, 10, 10,
+	11, 11, 14, 0, 0, 14, 17, 17, 19, 19,
+	16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	16
+};
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/*
+ * The intent behind this definition is that it'll catch any uses of
+ * REJECT which flex missed. 
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "configfile.l"
+#define INITIAL 0
+/*****************************************************************
+
+  File   :   configfile.ll
+  Author :   David Corcoran
+  Date   :   February 12, 1999 modified 7/28/99
+  Purpose:   Reads lexical config files and updates database.
+             See http://www.linuxnet.com for more information.
+  License:   Copyright (C) 1999 David Corcoran
+             <corcoran at linuxnet.com>
+
+******************************************************************/
+#line 14 "configfile.l"
+int evaluatetoken(char *pcToken);
+
+static int iLinenumber = 1;
+static char *pcPrevious = 0;
+static char *pcCurrent = 0;
+static char *pcFriendlyname = 0;
+static char *pcDevicename = 0;
+static char *pcLibpath = 0;
+static char *pcChannelid = 0;
+static int badError = 0;
+
+void tok_error(char *pcToken_error);
+
+#line 399 "lex.yy.c"
+
+/*
+ * Macros after this point can all be overridden by user definitions in
+ * section 1. 
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO((void));
+#else
+extern int yywrap YY_PROTO((void));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO((int c, char *buf_ptr));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO((char *, yyconst char *, int));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO((yyconst char *));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO((void));
+#else
+static int input YY_PROTO((void));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO((int new_state));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO((void));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO((void));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/*
+ * Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int). 
+ */
+#endif
+#endif
+
+/*
+ * Amount of stuff to slurp up with each read. 
+ */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/*
+ * Copy whatever the last rule matched to the standard output. 
+ */
+
+#ifndef ECHO
+/*
+ * This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite(). 
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/*
+ * Gets input and stuffs it into "buf".  number of characters read, or
+ * YY_NULL, is returned in "result". 
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/*
+ * No semi-colon after return; correct usage is to write "yyterminate();"
+ * - we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements. 
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/*
+ * Number of entries by which start-condition stack grows. 
+ */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/*
+ * Report a fatal error. 
+ */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/*
+ * Default declaration of generated scanner - a define so the user can
+ * easily add parameters. 
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/*
+ * Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up. 
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/*
+ * Code executed at the end of each rule. 
+ */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 29 "configfile.l"
+
+#line 553 "lex.yy.c"
+
+	if (yy_init)
+	{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if (!yy_start)
+			yy_start = 1;	/* first start state */
+
+		if (!yyin)
+			yyin = stdin;
+
+		if (!yyout)
+			yyout = stdout;
+
+		if (!yy_current_buffer)
+			yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
+
+		yy_load_buffer_state();
+	}
+
+	while (1)	/* loops until end-of-file is reached */
+	{
+		yy_cp = yy_c_buf_p;
+
+		/*
+		 * Support of yytext. 
+		 */
+		*yy_cp = yy_hold_char;
+
+		/*
+		 * yy_bp points to the position in yy_ch_buf of the start of the
+		 * current run. 
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+	  yy_match:
+		do
+		{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if (yy_accept[yy_current_state])
+			{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+			}
+			while (yy_chk[yy_base[yy_current_state] + yy_c] !=
+				yy_current_state)
+			{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if (yy_current_state >= 17)
+					yy_c = yy_meta[(unsigned int) yy_c];
+			}
+			yy_current_state =
+				yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+		}
+		while (yy_base[yy_current_state] != 31);
+
+	  yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if (yy_act == 0)
+		{	/* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+		}
+
+		YY_DO_BEFORE_ACTION;
+
+	  do_action:	/* This label is used only to access EOF actions. */
+
+		switch (yy_act)
+		{	/* beginning of action switch */
+		case 0:	/* must back up */
+			/*
+			 * undo the effects of YY_DO_BEFORE_ACTION 
+			 */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+		case 1:
+			YY_RULE_SETUP
+#line 31 "configfile.l"
+			{
+			}
+		YY_BREAK case 2:
+			YY_RULE_SETUP
+#line 32 "configfile.l"
+			{
+				iLinenumber++;
+			}
+		YY_BREAK case 3:
+			YY_RULE_SETUP
+#line 33 "configfile.l"
+			{
+				evaluatetoken(yytext);
+			}
+		YY_BREAK case 4:
+			YY_RULE_SETUP
+#line 34 "configfile.l"
+			{
+			}
+		YY_BREAK case 5:
+			YY_RULE_SETUP
+#line 35 "configfile.l"
+			{
+				evaluatetoken(yytext);
+			}
+		YY_BREAK case 6:
+			YY_RULE_SETUP
+#line 36 "configfile.l"
+			{
+				tok_error(yytext);
+			}
+		YY_BREAK case 7:
+			YY_RULE_SETUP
+#line 37 "configfile.l"
+				ECHO;
+			YY_BREAK
+#line 671 "lex.yy.c"
+		case YY_STATE_EOF(INITIAL):
+			yyterminate();
+
+		case YY_END_OF_BUFFER:
+			{
+				/*
+				 * Amount of text matched not including the EOB char. 
+				 */
+				int yy_amount_of_matched_text =
+					(int) (yy_cp - yytext_ptr) - 1;
+
+				/*
+				 * Undo the effects of YY_DO_BEFORE_ACTION. 
+				 */
+				*yy_cp = yy_hold_char;
+				YY_RESTORE_YY_MORE_OFFSET
+					if (yy_current_buffer->yy_buffer_status ==
+					YY_BUFFER_NEW)
+				{
+					/*
+					 * We're scanning a new file or input source.  It's
+					 * possible that this happened because the user just
+					 * pointed yyin at a new source and called yylex().
+					 * If so, then we have to assure consistency between
+					 * yy_current_buffer and our globals.  Here is the
+					 * right place to do so, because this is the first
+					 * action (other than possibly a back-up) that will
+					 * match for the new input source. 
+					 */
+					yy_n_chars = yy_current_buffer->yy_n_chars;
+					yy_current_buffer->yy_input_file = yyin;
+					yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+				}
+
+				/*
+				 * Note that here we test for yy_c_buf_p "<=" to the
+				 * position of the first EOB in the buffer, since
+				 * yy_c_buf_p will already have been incremented past the
+				 * NUL character (since all states make transitions on EOB 
+				 * to the end-of-buffer state).  Contrast this with the
+				 * test in input(). 
+				 */
+				if (yy_c_buf_p <=
+					&yy_current_buffer->yy_ch_buf[yy_n_chars])
+				{	/* This was really a NUL. */
+					yy_state_type yy_next_state;
+
+					yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+					yy_current_state = yy_get_previous_state();
+
+					/*
+					 * Okay, we're now positioned to make the NUL
+					 * transition.  We couldn't have
+					 * yy_get_previous_state() go ahead and do it for us
+					 * because it doesn't know how to deal with the
+					 * possibility of jamming (and we don't want to build
+					 * jamming into it because then it will run more
+					 * slowly). 
+					 */
+
+					yy_next_state = yy_try_NUL_trans(yy_current_state);
+
+					yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+					if (yy_next_state)
+					{
+						/*
+						 * Consume the NUL. 
+						 */
+						yy_cp = ++yy_c_buf_p;
+						yy_current_state = yy_next_state;
+						goto yy_match;
+					}
+
+					else
+					{
+						yy_cp = yy_c_buf_p;
+						goto yy_find_action;
+					}
+				}
+
+				else
+					switch (yy_get_next_buffer())
+					{
+					case EOB_ACT_END_OF_FILE:
+						{
+							yy_did_buffer_switch_on_eof = 0;
+
+							if (yywrap())
+							{
+								/*
+								 * Note: because we've taken care in
+								 * yy_get_next_buffer() to have set up
+								 * yytext, we can now set up yy_c_buf_p so 
+								 * that if some total hoser (like flex
+								 * itself) wants to call the scanner after 
+								 * we return the YY_NULL, it'll still work 
+								 * - another YY_NULL will get returned. 
+								 */
+								yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+								yy_act = YY_STATE_EOF(YY_START);
+								goto do_action;
+							}
+
+							else
+							{
+								if (!yy_did_buffer_switch_on_eof)
+									YY_NEW_FILE;
+							}
+							break;
+						}
+
+					case EOB_ACT_CONTINUE_SCAN:
+						yy_c_buf_p =
+							yytext_ptr + yy_amount_of_matched_text;
+
+						yy_current_state = yy_get_previous_state();
+
+						yy_cp = yy_c_buf_p;
+						yy_bp = yytext_ptr + YY_MORE_ADJ;
+						goto yy_match;
+
+					case EOB_ACT_LAST_MATCH:
+						yy_c_buf_p =
+							&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+						yy_current_state = yy_get_previous_state();
+
+						yy_cp = yy_c_buf_p;
+						yy_bp = yytext_ptr + YY_MORE_ADJ;
+						goto yy_find_action;
+					}
+				break;
+			}
+
+		default:
+			YY_FATAL_ERROR
+				("fatal flex scanner internal error--no action found");
+		}	/* end of action switch */
+	}	/* end of scanning one token */
+}	/* end of yylex */
+
+/*
+ * yy_get_next_buffer - try to read in a new buffer Returns a code
+ * representing an action: EOB_ACT_LAST_MATCH - EOB_ACT_CONTINUE_SCAN -
+ * continue scanning from current position EOB_ACT_END_OF_FILE - end of
+ * file 
+ */
+
+static int yy_get_next_buffer()
+{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
+		YY_FATAL_ERROR
+			("fatal flex scanner internal error--end of buffer missed");
+
+	if (yy_current_buffer->yy_fill_buffer == 0)
+	{	/* Don't try to fill the buffer, so this is an EOF. */
+		if (yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1)
+		{
+			/*
+			 * We matched a single character, the EOB, so treat this as a
+			 * final EOF. 
+			 */
+			return EOB_ACT_END_OF_FILE;
+		}
+
+		else
+		{
+			/*
+			 * We matched some text prior to the EOB, first process it. 
+			 */
+			return EOB_ACT_LAST_MATCH;
+		}
+	}
+
+	/*
+	 * Try to read more data. 
+	 */
+
+	/*
+	 * First move last chars to start of buffer. 
+	 */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for (i = 0; i < number_to_move; ++i)
+		*(dest++) = *(source++);
+
+	if (yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING)
+		/*
+		 * don't do the read, it's not guaranteed to return an EOF, just
+		 * force an EOF 
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+	{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while (num_to_read <= 0)
+		{	/* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR
+				("input buffer overflow, can't enlarge buffer because scanner uses REJECT");
+#else
+
+			/*
+			 * just a shorter name for the current buffer 
+			 */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset = (int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if (b->yy_is_our_buffer)
+			{
+				int new_size = b->yy_buf_size * 2;
+
+				if (new_size <= 0)
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/*
+					 * Include room in for 2 EOB chars. 
+					 */
+					yy_flex_realloc((void *) b->yy_ch_buf,
+					b->yy_buf_size + 2);
+			} else
+				/*
+				 * Can't grow it, we don't own it. 
+				 */
+				b->yy_ch_buf = 0;
+
+			if (!b->yy_ch_buf)
+				YY_FATAL_ERROR
+					("fatal error - scanner input buffer overflow");
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+				number_to_move - 1;
+#endif
+		}
+
+		if (num_to_read > YY_READ_BUF_SIZE)
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/*
+		 * Read in more data. 
+		 */
+		YY_INPUT((&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read);
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+	}
+
+	if (yy_n_chars == 0)
+	{
+		if (number_to_move == YY_MORE_ADJ)
+		{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart(yyin);
+		}
+
+		else
+		{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_EOF_PENDING;
+		}
+	}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/*
+ * yy_get_previous_state - get the state just before the EOB char was
+ * reached 
+ */
+
+static yy_state_type yy_get_previous_state()
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp)
+	{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if (yy_accept[yy_current_state])
+		{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+		}
+		while (yy_chk[yy_base[yy_current_state] + yy_c] !=
+			yy_current_state)
+		{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if (yy_current_state >= 17)
+				yy_c = yy_meta[(unsigned int) yy_c];
+		}
+		yy_current_state =
+			yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	}
+
+	return yy_current_state;
+}
+
+/*
+ * yy_try_NUL_trans - try to make a transition on the NUL character
+ * synopsis next_state = yy_try_NUL_trans( current_state ); 
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state)
+#else
+static yy_state_type yy_try_NUL_trans(yy_current_state)
+	yy_state_type yy_current_state;
+#endif
+{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if (yy_accept[yy_current_state])
+	{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+	}
+	while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state)
+	{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if (yy_current_state >= 17)
+			yy_c = yy_meta[(unsigned int) yy_c];
+	}
+	yy_current_state =
+		yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 16);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput(int c, register char *yy_bp)
+#else
+static void yyunput(c, yy_bp)
+	int c;
+	register char *yy_bp;
+#endif
+{
+	register char *yy_cp = yy_c_buf_p;
+
+	/*
+	 * undo effects of setting up yytext 
+	 */
+	*yy_cp = yy_hold_char;
+
+	if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
+	{	/* need to shift things up to make room */
+		/*
+		 * +2 for EOB chars. 
+		 */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest =
+			&yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size +
+			2];
+		register char *source =
+			&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while (source > yy_current_buffer->yy_ch_buf)
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
+			YY_FATAL_ERROR("flex scanner push-back overflow");
+	}
+
+	*--yy_cp = (char) c;
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+}
+#endif							/* ifndef YY_NO_UNPUT */
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if (*yy_c_buf_p == YY_END_OF_BUFFER_CHAR)
+	{
+		/*
+		 * yy_c_buf_p now points to the character we want to return. If
+		 * this occurs *before* the EOB characters, then it's a valid NUL; 
+		 * if not, then we've hit the end of the buffer. 
+		 */
+		if (yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars])
+			/*
+			 * This was really a NUL. 
+			 */
+			*yy_c_buf_p = '\0';
+
+		else
+		{	/* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch (yy_get_next_buffer())
+			{
+			case EOB_ACT_LAST_MATCH:
+				/*
+				 * This happens because yy_g_n_b() sees that we've
+				 * accumulated a token and flags that we need to try
+				 * matching the token before proceeding.  But for input(),
+				 * there's no matching to consider. So convert the
+				 * EOB_ACT_LAST_MATCH to EOB_ACT_END_OF_FILE. 
+				 */
+
+				/*
+				 * Reset buffer status. 
+				 */
+				yyrestart(yyin);
+
+				/*
+				 * fall through 
+				 */
+
+			case EOB_ACT_END_OF_FILE:
+				{
+					if (yywrap())
+						return EOF;
+
+					if (!yy_did_buffer_switch_on_eof)
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p = yytext_ptr + offset;
+				break;
+			}
+		}
+	}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+	return c;
+}
+
+#ifdef YY_USE_PROTOS
+void yyrestart(FILE * input_file)
+#else
+void yyrestart(input_file)
+	FILE *input_file;
+#endif
+{
+	if (!yy_current_buffer)
+		yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
+
+	yy_init_buffer(yy_current_buffer, input_file);
+	yy_load_buffer_state();
+}
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer)
+#else
+void yy_switch_to_buffer(new_buffer)
+	YY_BUFFER_STATE new_buffer;
+#endif
+{
+	if (yy_current_buffer == new_buffer)
+		return;
+
+	if (yy_current_buffer)
+	{
+		/*
+		 * Flush out information for old buffer. 
+		 */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+	}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/*
+	 * We don't actually know whether we did this switch during EOF
+	 * (yywrap()) processing, but the only time this flag is looked at is
+	 * after yywrap() is called, so it's safe to go ahead and always set
+	 * it. 
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+}
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state(void)
+#else
+void yy_load_buffer_state()
+#endif
+{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+}
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer(FILE * file, int size)
+#else
+YY_BUFFER_STATE yy_create_buffer(file, size)
+	FILE *file;
+	int size;
+#endif
+{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc(sizeof(struct yy_buffer_state));
+	if (!b)
+		YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
+
+	b->yy_buf_size = size;
+
+	/*
+	 * yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters. 
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc(b->yy_buf_size + 2);
+	if (!b->yy_ch_buf)
+		YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer(b, file);
+
+	return b;
+}
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer(YY_BUFFER_STATE b)
+#else
+void yy_delete_buffer(b)
+	YY_BUFFER_STATE b;
+#endif
+{
+	if (!b)
+		return;
+
+	if (b == yy_current_buffer)
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if (b->yy_is_our_buffer)
+		yy_flex_free((void *) b->yy_ch_buf);
+
+	yy_flex_free((void *) b);
+}
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO((int));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer(YY_BUFFER_STATE b, FILE * file)
+#else
+void yy_init_buffer(b, file)
+	YY_BUFFER_STATE b;
+	FILE *file;
+#endif
+
+{
+	yy_flush_buffer(b);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty(fileno(file)) > 0) : 0;
+#endif
+#endif
+}
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer(YY_BUFFER_STATE b)
+#else
+void yy_flush_buffer(b)
+	YY_BUFFER_STATE b;
+#endif
+
+{
+	if (!b)
+		return;
+
+	b->yy_n_chars = 0;
+
+	/*
+	 * We always need two end-of-buffer characters.  The first causes a
+	 * transition to the end-of-buffer state.  The second causes a jam in
+	 * that state. 
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if (b == yy_current_buffer)
+		yy_load_buffer_state();
+}
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size)
+#else
+YY_BUFFER_STATE yy_scan_buffer(base, size)
+	char *base;
+	yy_size_t size;
+#endif
+{
+	YY_BUFFER_STATE b;
+
+	if (size < 2 ||
+		base[size - 2] != YY_END_OF_BUFFER_CHAR ||
+		base[size - 1] != YY_END_OF_BUFFER_CHAR)
+		/*
+		 * They forgot to leave room for the EOB's. 
+		 */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc(sizeof(struct yy_buffer_state));
+	if (!b)
+		YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()");
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer(b);
+
+	return b;
+}
+#endif
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string(yyconst char *yy_str)
+#else
+YY_BUFFER_STATE yy_scan_string(yy_str)
+	yyconst char *yy_str;
+#endif
+{
+	int len;
+	for (len = 0; yy_str[len]; ++len)
+		;
+
+	return yy_scan_bytes(yy_str, len);
+}
+#endif
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes(yyconst char *bytes, int len)
+#else
+YY_BUFFER_STATE yy_scan_bytes(bytes, len)
+	yyconst char *bytes;
+	int len;
+#endif
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/*
+	 * Get memory for full buffer, including space for trailing EOB's. 
+	 */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc(n);
+	if (!buf)
+		YY_FATAL_ERROR("out of dynamic memory in yy_scan_bytes()");
+
+	for (i = 0; i < len; ++i)
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len + 1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer(buf, n);
+	if (!b)
+		YY_FATAL_ERROR("bad buffer in yy_scan_bytes()");
+
+	/*
+	 * It's okay to grow etc. this buffer, and we should throw it away
+	 * when we're done. 
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+#endif
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state(int new_state)
+#else
+static void yy_push_state(new_state)
+	int new_state;
+#endif
+{
+	if (yy_start_stack_ptr >= yy_start_stack_depth)
+	{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof(int);
+
+		if (!yy_start_stack)
+			yy_start_stack = (int *) yy_flex_alloc(new_size);
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+				(void *) yy_start_stack, new_size);
+
+		if (!yy_start_stack)
+			YY_FATAL_ERROR
+				("out of memory expanding start-condition stack");
+	}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+}
+#endif
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+{
+	if (--yy_start_stack_ptr < 0)
+		YY_FATAL_ERROR("start-condition stack underflow");
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+}
+#endif
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error(yyconst char msg[])
+#else
+static void yy_fatal_error(msg)
+	char msg[];
+#endif
+{
+	(void) fprintf(stderr, "%s\n", msg);
+	exit(YY_EXIT_FAILURE);
+}
+
+/*
+ * Redefine yyless() so it works in section 3 code. 
+ */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+/*
+ * Internal utility routines. 
+ */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy(char *s1, yyconst char *s2, int n)
+#else
+static void yy_flex_strncpy(s1, s2, n)
+	char *s1;
+	yyconst char *s2;
+	int n;
+#endif
+{
+	register int i;
+	for (i = 0; i < n; ++i)
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen(yyconst char *s)
+#else
+static int yy_flex_strlen(s)
+	yyconst char *s;
+#endif
+{
+	register int n;
+	for (n = 0; s[n]; ++n)
+		;
+
+	return n;
+}
+#endif
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc(yy_size_t size)
+#else
+static void *yy_flex_alloc(size)
+	yy_size_t size;
+#endif
+{
+	return (void *) malloc(size);
+}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc(void *ptr, yy_size_t size)
+#else
+static void *yy_flex_realloc(ptr, size)
+	void *ptr;
+	yy_size_t size;
+#endif
+{
+	/*
+	 * The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those that use 
+	 * void* generic pointers.  It works with the latter because both ANSI 
+	 * C and C++ allow castless assignment from any pointer type to void*, 
+	 * and deal with argument conversions as though doing an assignment. 
+	 */
+	return (void *) realloc((char *) ptr, size);
+}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free(void *ptr)
+#else
+static void yy_flex_free(ptr)
+	void *ptr;
+#endif
+{
+	free(ptr);
+}
+
+#if YY_MAIN
+int main()
+{
+	yylex();
+	return 0;
+}
+#endif
+#line 37 "configfile.l"
+
+#include <stdio.h>
+#include <string.h>
+#include <wintypes.h>
+
+#include "pcsclite.h"
+#include "sys_generic.h"
+#include "readerfactory.h"
+#include "debuglog.h"
+
+int evaluatetoken(char *pcToken)
+{
+
+	DWORD dwChannelId = 0;
+	int p = 0;
+	int n = 0;
+
+	if (pcPrevious == 0)
+	{	/* This is the key */
+		pcPrevious = strdup(pcToken);
+	} else
+	{
+		pcCurrent = pcToken;
+		if (strcmp(pcPrevious, "FRIENDLYNAME") == 0)
+		{
+			if (pcFriendlyname == 0)
+			{
+				pcFriendlyname = (char *) malloc(strlen(pcCurrent) - 1);
+				for (n = 0; n < strlen(pcCurrent); n++)
+				{
+					if (pcCurrent[n] != '"')
+					{	/* Strip off the quotes */
+						pcFriendlyname[p++] = pcCurrent[n];
+					}
+				}
+				pcFriendlyname[p++] = 0;
+			} else
+			{
+				tok_error(pcPrevious);
+				return 1;
+			}
+		} else if (strcmp(pcPrevious, "DEVICENAME") == 0)
+		{
+			if (pcDevicename == 0)
+			{
+				pcDevicename = strdup(pcCurrent);
+			} else
+			{
+				tok_error(pcPrevious);
+				return 1;
+			}
+		} else if (strcmp(pcPrevious, "LIBPATH") == 0)
+		{
+			if (pcLibpath == 0)
+			{
+				pcLibpath = strdup(pcCurrent);
+			} else
+			{
+				tok_error(pcPrevious);
+				return 1;
+			}
+		} else if (strcmp(pcPrevious, "CHANNELID") == 0)
+		{
+			if (pcChannelid == 0)
+			{
+				pcChannelid = strdup(pcCurrent);
+			} else
+			{
+				tok_error(pcPrevious);
+				return 1;
+			}
+		} else
+		{
+			tok_error(pcPrevious);
+			return 1;
+		}
+
+		free(pcPrevious);
+		pcPrevious = 0;
+	}
+
+	if (pcFriendlyname != 0 && pcDevicename != 0 &&
+		pcLibpath != 0 && pcChannelid != 0)
+	{
+
+		dwChannelId = strtoul(pcChannelid, 0, 16);
+		RFAddReader(pcFriendlyname, dwChannelId, pcLibpath, pcDevicename);
+
+		free(pcFriendlyname);
+		free(pcDevicename);
+		free(pcLibpath);
+		free(pcChannelid);
+		pcFriendlyname = 0;
+		pcDevicename = 0;
+		pcLibpath = 0;
+		pcChannelid = 0;
+	}
+
+	return 0;
+}
+
+void tok_error(char *token_error)
+{
+	log_msg(PCSC_LOG_ERROR, "%s:%d tok_error: invalid value in reader.conf",
+		__FILE__, __LINE__);
+	badError = 1;
+}
+
+int DBUpdateReaders(char *readerconf)
+{
+
+	FILE *configFile;
+	configFile = 0;
+
+	configFile = fopen(readerconf, "r");
+
+	if (configFile == 0)
+	{
+		return 1;
+	}
+
+	yyin = configFile;
+
+	do
+	{
+		yylex();
+	}
+	while (!feof(configFile));
+
+	fclose(configFile);
+
+	if (badError == 1)
+	{
+		return -1;
+	} else
+	{
+		return 0;
+	}
+}	/* End of configfile.c */

Added: trunk/SmartCardServices/src/PCSC/configfile.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/configfile.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/configfile.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/*****************************************************************
+/
+/ File   :   configfile.h
+/ Author :   David Corcoran
+/ Date   :   February 12, 1999 modified 7/28/99
+/ License:   Copyright (C) 1999 David Corcoran
+/	     <corcoran at linuxnet.com>
+/ Purpose:   Header file for reading lexical config files.
+/            See http://www.linuxnet.com for more information.
+/
+******************************************************************/
+
+#ifndef __configfile_h__
+#define __configfile_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	int DBUpdateReaders(char *readerconf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __configfile_h__ */

Added: trunk/SmartCardServices/src/PCSC/configfile.l
===================================================================
--- trunk/SmartCardServices/src/PCSC/configfile.l	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/configfile.l	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,142 @@
+/*****************************************************************
+
+  File   :   configfile.ll
+  Author :   David Corcoran
+  Date   :   February 12, 1999 modified 7/28/99
+  Purpose:   Reads lexical config files and updates database.
+             See http://www.linuxnet.com for more information.
+  License:   Copyright (C) 1999 David Corcoran
+             <corcoran at linuxnet.com>
+
+******************************************************************/
+
+%{
+int evaluatetoken( char *pcToken );
+
+static int iLinenumber      = 1;
+static char *pcPrevious     = 0;
+static char *pcCurrent      = 0;
+static char *pcFriendlyname = 0;
+static char *pcDevicename   = 0;
+static char *pcLibpath      = 0;
+static char *pcChannelid    = 0;
+static int   badError       = 0;
+
+void tok_error ( char *pcToken_error );
+
+%}
+
+%%
+
+#.*                                       {}
+"\n"                                      { iLinenumber++; }
+(\"[^"\n]*["\n])|(\'[^'\n]*['\n])         { evaluatetoken( yytext); } 
+[ \t]                     {}
+([A-Z]|[a-z]|[0-9]|[\\\/\-\.\_\@])+       { evaluatetoken( yytext ); } 
+.                                         { tok_error( yytext ); }
+%%
+
+#include <stdio.h>
+#include <string.h>
+#include <wintypes.h>
+
+#include "pcsclite.h"
+#include "sys_generic.h"
+#include "readerfactory.h"
+#include "debuglog.h"
+
+int evaluatetoken( char *pcToken ) {
+
+  DWORD dwChannelId = 0;
+  int p             = 0;
+  int n             = 0;
+
+  if ( pcPrevious == 0 ) {       /* This is the key */
+    pcPrevious = strdup( pcToken );
+  } else {
+    pcCurrent = pcToken;
+    if ( strcmp( pcPrevious, "FRIENDLYNAME" ) == 0 ) {
+       if ( pcFriendlyname == 0 ) {
+         pcFriendlyname = (char *)malloc(strlen(pcCurrent)-1);
+        for ( n = 0; n < strlen(pcCurrent); n++ ) {
+           if ( pcCurrent[n] != '"' ) { /* Strip off the quotes */
+             pcFriendlyname[p++] = pcCurrent[n];         
+           }
+         }
+         pcFriendlyname[p++] = 0;
+       } else {
+         tok_error( pcPrevious ); return 1;
+       }
+    } else if ( strcmp( pcPrevious, "DEVICENAME" ) == 0 ) {
+       if ( pcDevicename == 0 ) {
+         pcDevicename = strdup( pcCurrent );
+       } else {
+         tok_error( pcPrevious ); return 1;
+       }
+    } else if ( strcmp( pcPrevious, "LIBPATH" ) == 0 ) {
+       if ( pcLibpath == 0 ) {
+         pcLibpath = strdup( pcCurrent );
+       } else {
+         tok_error( pcPrevious ); return 1;
+       }
+    } else if ( strcmp( pcPrevious, "CHANNELID" ) == 0 ) {
+       if ( pcChannelid == 0 ) {
+         pcChannelid = strdup( pcCurrent );
+       } else {
+         tok_error( pcPrevious ); return 1;
+       }
+    } else {
+       tok_error( pcPrevious ); return 1;
+    }
+
+    free( pcPrevious ); pcPrevious = 0;
+  }
+
+  if ( pcFriendlyname != 0 && pcDevicename != 0 &&
+       pcLibpath      != 0 && pcChannelid != 0 ) {
+     
+       dwChannelId = strtoul( pcChannelid, 0, 16 );
+       RFAddReader( pcFriendlyname, dwChannelId, pcLibpath, pcDevicename );
+
+       free( pcFriendlyname ); free( pcDevicename );
+       free( pcLibpath);       free( pcChannelid );
+       pcFriendlyname = 0;     pcDevicename = 0;
+       pcLibpath      = 0;     pcChannelid  = 0;
+  }
+
+  return 0;
+}
+
+void tok_error ( char *token_error ) {
+  debug_msg("%s:%d tok_error: invalid value in reader.conf", 
+             __FILE__, __LINE__);
+  badError = 1;
+}
+
+int DBUpdateReaders ( char *readerconf ) {
+
+  FILE *configFile;
+  configFile = 0;	
+
+  configFile = fopen( readerconf, "r");
+
+  if (configFile == 0) {
+    return 1;
+  }
+
+  yyin = configFile;
+
+  do {
+    yylex();
+  }
+  while (!feof(configFile));
+
+  fclose(configFile);
+
+  if (badError == 1) {
+    return -1;
+  } else {
+    return 0;
+  }
+} /* End of configfile.c */
+

Added: trunk/SmartCardServices/src/PCSC/debug.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/debug.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/debug.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,160 @@
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2002
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 1999-2005
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: debuglog.c 1953 2006-03-21 13:46:28Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles debugging for libpcsclite.
+ */
+
+#include "config.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "debug.h"
+//#include "strlcpycat.h"
+
+#define DEBUG_BUF_SIZE 2048
+
+/* default level is a bit verbose to be backward compatible */
+static char LogLevel = PCSC_LOG_ERROR;
+
+static signed char LogDoColor = 0;	/* no color by default */
+void log_init(void);
+
+void log_init(void)
+{
+	char *e;
+
+#ifdef LIBPCSCLITE
+	e = getenv("PCSCLITE_DEBUG");
+#else
+	e = getenv("MUSCLECARD_DEBUG");
+#endif
+	if (e)
+		LogLevel = atoi(e);
+
+	/* no color under Windows */
+#ifndef WIN32
+	/* log to stderr and stderr is a tty? */
+	if (isatty(fileno(stderr)))
+	{
+		const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode" };
+		char *term;
+
+		term = getenv("TERM");
+		if (term)
+		{
+			unsigned int i;
+
+			/* for each known color terminal */
+			for (i = 0; i < sizeof(terms) / sizeof(terms[0]); i++)
+			{
+				/* we found a supported term? */
+				if (0 == strcmp(terms[i], term))
+				{
+					LogDoColor = 1;
+					break;
+				}
+			}
+		}
+	}
+#endif
+} /* log_init */
+
+void log_msg(const int priority, const char *fmt, ...)
+{
+	char DebugBuffer[DEBUG_BUF_SIZE];
+	va_list argptr;
+	static int is_initialized = 0;
+
+	if (!is_initialized)
+	{
+		log_init();
+		is_initialized = 1;
+	}
+
+	if (priority < LogLevel) /* log priority lower than threshold? */
+		return;
+
+	va_start(argptr, fmt);
+#ifndef WIN32
+	vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
+#else
+#if HAVE_VSNPRINTF
+	vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
+#else
+	vsprintf(DebugBuffer, fmt, argptr);
+#endif
+#endif
+	va_end(argptr);
+
+#ifndef WIN32
+	{
+		if (LogDoColor)
+		{
+			const char *color_pfx = "", *color_sfx = "\33[0m";
+
+			switch (priority)
+			{
+				case PCSC_LOG_CRITICAL:
+					color_pfx = "\33[01;31m"; /* bright + Red */
+					break;
+
+				case PCSC_LOG_ERROR:
+					color_pfx = "\33[35m"; /* Magenta */
+					break;
+
+				case PCSC_LOG_INFO:
+					color_pfx = "\33[34m"; /* Blue */
+					break;
+
+				case PCSC_LOG_DEBUG:
+					color_pfx = ""; /* normal (black) */
+					color_sfx = "";
+					break;
+			}
+			fprintf(stderr, "%s%s%s\n", color_pfx, DebugBuffer, color_sfx);
+		}
+		else
+			fprintf(stderr, "%s\n", DebugBuffer);
+	}
+#else
+	fprintf(stderr, "%s\n", DebugBuffer);
+#endif
+} /* log_msg */
+
+void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
+	const int len)
+{
+	char DebugBuffer[DEBUG_BUF_SIZE];
+	int i;
+	char *c;
+	char *debug_buf_end;
+
+	if (priority < LogLevel) /* log priority lower than threshold? */
+		return;
+
+	debug_buf_end = DebugBuffer + DEBUG_BUF_SIZE - 5;
+
+	strlcpy(DebugBuffer, msg, sizeof(DebugBuffer));
+	c = DebugBuffer + strlen(DebugBuffer);
+
+	for (i = 0; (i < len) && (c < debug_buf_end); ++i)
+	{
+		sprintf(c, "%02X ", buffer[i]);
+		c += strlen(c);
+	}
+
+	fprintf(stderr, "%s\n", DebugBuffer);
+} /* log_xxd */
+

Added: trunk/SmartCardServices/src/PCSC/debug.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/debug.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/debug.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,78 @@
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 1999-2005
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: debuglog.h 1835 2006-01-25 10:42:23Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles debugging.
+ *
+ * @note log message is sent to syslog or stderr depending on --foreground
+ * command line argument
+ *
+ * @test
+ * @code
+ * Log1(priority, "text");
+ *  log "text" with priority level priority
+ * Log2(priority, "text: %d", 1234);
+ *  log "text: 1234"
+ * the format string can be anything printf() can understand
+ * Log3(priority, "text: %d %d", 1234, 5678);
+ *  log "text: 1234 5678"
+ * the format string can be anything printf() can understand
+ * LogXxd(priority, msg, buffer, size);
+ *  log "msg" + a hex dump of size bytes of buffer[]
+ * @endcode
+ */
+
+#ifndef __debug_h__
+#define __debug_h__
+
+#ifdef PCSC
+/* use syslog, etc. if we are included from a file for pcscd */
+#include "debuglog.h"
+#else
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+enum {
+	PCSC_LOG_DEBUG = 0,
+	PCSC_LOG_INFO,
+	PCSC_LOG_ERROR,
+	PCSC_LOG_CRITICAL
+};
+
+#include <stdio.h>
+
+/* You can't do #ifndef __FUNCTION__ */
+#if !defined(__GNUC__) && !defined(__IBMC__)
+#define __FUNCTION__ ""
+#endif
+
+#define Log0(priority) log_msg(priority, "%s:%d:%s()", __FILE__, __LINE__, __FUNCTION__)
+#define Log1(priority, fmt) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__)
+#define Log2(priority, fmt, data) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data)
+#define Log3(priority, fmt, data1, data2) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data1, data2)
+#define LogXxd(priority, msg, buffer, size) log_xxd(priority, msg, buffer, size)
+
+void log_msg(const int priority, const char *fmt, ...);
+void log_xxd(const int priority, const char *msg,
+	const unsigned char *buffer, const int size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif							/* __debug_h__ */
+

Added: trunk/SmartCardServices/src/PCSC/debuglog.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/debuglog.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/debuglog.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,452 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  debuglog.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2002
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 1999-2005
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: debuglog.c 2302 2007-01-06 17:57:58Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles debugging for pcscd.
+ */
+
+#include "config.h"
+
+#ifndef WIN32
+#include <syslog.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <sys/types.h>
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "debuglog.h"
+#include "sys_generic.h"
+//#include "strlcpy.h"
+
+/**
+ * Max string size when dumping a 256 bytes longs APDU
+ * Should be bigger than 256*3+30
+ */
+#define DEBUG_BUF_SIZE 2048
+
+static char LogSuppress = DEBUGLOG_LOG_ENTRIES;
+static char LogMsgType = DEBUGLOG_NO_DEBUG;
+static char LogCategory = DEBUG_CATEGORY_NOTHING;
+
+/* default level is a bit verbose to be backward compatible */
+static char LogLevel = PCSC_LOG_INFO;
+
+static signed char LogDoColor = 0;	/* no color by default */
+
+void log_msg(const int priority, const char *fmt, ...)
+{
+	char DebugBuffer[DEBUG_BUF_SIZE];
+	va_list argptr;
+
+	if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
+		|| (priority < LogLevel) /* log priority lower than threshold? */
+		|| (DEBUGLOG_NO_DEBUG == LogMsgType))
+		return;
+
+	va_start(argptr, fmt);
+#ifndef WIN32
+	vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
+#else
+#if HAVE_VSNPRINTF
+	vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
+#else
+	vsprintf(DebugBuffer, fmt, argptr);
+#endif
+#endif
+	va_end(argptr);
+
+#ifndef WIN32
+	if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
+		syslog(LOG_INFO, "%s", DebugBuffer);
+	else
+	{
+		if (LogDoColor)
+		{
+			const char *color_pfx = "", *color_sfx = "\33[0m";
+
+			switch (priority)
+			{
+				case PCSC_LOG_CRITICAL:
+					color_pfx = "\33[01;31m"; /* bright + Red */
+					break;
+
+				case PCSC_LOG_ERROR:
+					color_pfx = "\33[35m"; /* Magenta */
+					break;
+
+				case PCSC_LOG_INFO:
+					color_pfx = "\33[34m"; /* Blue */
+					break;
+
+				case PCSC_LOG_DEBUG:
+					color_pfx = ""; /* normal (black) */
+					color_sfx = "";
+					break;
+			}
+			fprintf(stderr, "%s%s%s\n", color_pfx, DebugBuffer, color_sfx);
+		}
+		else
+			fprintf(stderr, "%s\n", DebugBuffer);
+	}
+#else
+	fprintf(stderr, "%s\n", DebugBuffer);
+#endif
+} /* log_msg */
+
+void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
+	const int len)
+{
+	char DebugBuffer[DEBUG_BUF_SIZE];
+	int i;
+	char *c;
+	char *debug_buf_end;
+
+	if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
+		|| (priority < LogLevel) /* log priority lower than threshold? */
+		|| (DEBUGLOG_NO_DEBUG == LogMsgType))
+		return;
+
+	debug_buf_end = DebugBuffer + DEBUG_BUF_SIZE - 5;
+
+	strlcpy(DebugBuffer, msg, sizeof(DebugBuffer));
+	c = DebugBuffer + strlen(DebugBuffer);
+
+	for (i = 0; (i < len) && (c < debug_buf_end); ++i)
+	{
+		sprintf(c, "%02X ", buffer[i]);
+		c += 3;
+	}
+
+	/* the buffer is too small so end it with "..." */
+	if ((c >= debug_buf_end) && (i < len))
+		c[-3] = c[-2] = c[-1] = '.';
+
+#ifndef WIN32
+	if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
+		syslog(LOG_INFO, "%s", DebugBuffer);
+	else
+#endif
+		fprintf(stderr, "%s\n", DebugBuffer);
+} /* log_xxd */
+
+#ifdef PCSCD
+void DebugLogSuppress(const int lSType)
+{
+	LogSuppress = lSType;
+}
+#endif
+
+void DebugLogSetLogType(const int dbgtype)
+{
+	switch (dbgtype)
+	{
+		case DEBUGLOG_NO_DEBUG:
+		case DEBUGLOG_SYSLOG_DEBUG:
+		case DEBUGLOG_STDERR_DEBUG:
+			LogMsgType = dbgtype;
+			break;
+		default:
+			Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stderr",
+				dbgtype);
+			LogMsgType = DEBUGLOG_STDERR_DEBUG;
+	}
+
+	/* no color under Windows */
+#ifndef WIN32
+	/* log to stderr and stderr is a tty? */
+	if (DEBUGLOG_STDERR_DEBUG == LogMsgType && isatty(fileno(stderr)))
+	{
+		const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode" };
+		char *term;
+
+		term = getenv("TERM");
+		if (term)
+		{
+			unsigned int i;
+
+			/* for each known color terminal */
+			for (i = 0; i < sizeof(terms) / sizeof(terms[0]); i++)
+			{
+				/* we found a supported term? */
+				if (0 == strcmp(terms[i], term))
+				{
+					LogDoColor = 1;
+					break;
+				}
+			}
+		}
+	}
+#endif
+}
+
+void DebugLogSetLevel(const int level)
+{
+	LogLevel = level;
+	switch (level)
+	{
+		case PCSC_LOG_CRITICAL:
+		case PCSC_LOG_ERROR:
+			/* do not log anything */
+			break;
+
+		case PCSC_LOG_INFO:
+			Log1(PCSC_LOG_INFO, "debug level=notice");
+			break;
+
+		case PCSC_LOG_DEBUG:
+			Log1(PCSC_LOG_DEBUG, "debug level=debug");
+			break;
+
+		default:
+			LogLevel = PCSC_LOG_INFO;
+			Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=notice",
+				level);
+	}
+}
+
+INTERNAL int DebugLogSetCategory(const int dbginfo)
+{
+#define DEBUG_INFO_LENGTH 80
+	char text[DEBUG_INFO_LENGTH];
+
+	/* use a negative number to UNset
+	 * typically use ~DEBUG_CATEGORY_APDU
+	 */
+	if (dbginfo < 0)
+		LogCategory &= dbginfo;
+	else
+		LogCategory |= dbginfo;
+
+	/* set to empty string */
+	text[0] = '\0';
+
+	if (LogCategory & DEBUG_CATEGORY_APDU)
+		strlcat(text, " APDU", sizeof(text));
+
+	Log2(PCSC_LOG_INFO, "Debug options:%s", text);
+
+	return LogCategory;
+}
+
+INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
+	const int len)
+{
+	if ((category & DEBUG_CATEGORY_APDU)
+		&& (LogCategory & DEBUG_CATEGORY_APDU))
+		log_xxd(PCSC_LOG_INFO, "APDU: ", (const unsigned char *)buffer, len);
+
+	if ((category & DEBUG_CATEGORY_SW)
+		&& (LogCategory & DEBUG_CATEGORY_APDU))
+		log_xxd(PCSC_LOG_INFO, "SW: ", (const unsigned char *)buffer, len);
+}
+
+/*
+ * old function supported for backward object code compatibility
+ * defined only for pcscd
+ */
+#ifdef PCSCD
+void debug_msg(const char *fmt, ...)
+{
+	char DebugBuffer[DEBUG_BUF_SIZE];
+	va_list argptr;
+
+	if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
+		|| (DEBUGLOG_NO_DEBUG == LogMsgType))
+		return;
+
+	va_start(argptr, fmt);
+#ifndef WIN32
+	vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
+#else
+#if HAVE_VSNPRINTF
+	vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
+#else
+	vsprintf(DebugBuffer, fmt, argptr);
+#endif
+#endif
+	va_end(argptr);
+
+#ifndef WIN32
+	if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
+		syslog(LOG_INFO, "%s", DebugBuffer);
+	else
+#endif
+		fprintf(stderr, "%s\n", DebugBuffer);
+} /* debug_msg */
+
+void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
+{
+	log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
+} /* debug_xxd */
+#endif
+
+char *pcsc_stringify_error(const int32_t Error)
+{
+
+	static char strError[75];
+
+	switch (Error)
+	{
+	case SCARD_S_SUCCESS:
+		strcpy(strError, "Command successful.");
+		break;
+	case SCARD_E_CANCELLED:
+		strcpy(strError, "Command cancelled.");
+		break;
+	case SCARD_E_CANT_DISPOSE:
+		strcpy(strError, "Cannot dispose handle.");
+		break;
+	case SCARD_E_INSUFFICIENT_BUFFER:
+		strcpy(strError, "Insufficient buffer.");
+		break;
+	case SCARD_E_INVALID_ATR:
+		strcpy(strError, "Invalid ATR.");
+		break;
+	case SCARD_E_INVALID_HANDLE:
+		strcpy(strError, "Invalid handle.");
+		break;
+	case SCARD_E_INVALID_PARAMETER:
+		strcpy(strError, "Invalid parameter given.");
+		break;
+	case SCARD_E_INVALID_TARGET:
+		strcpy(strError, "Invalid target given.");
+		break;
+	case SCARD_E_INVALID_VALUE:
+		strcpy(strError, "Invalid value given.");
+		break;
+	case SCARD_E_NO_MEMORY:
+		strcpy(strError, "Not enough memory.");
+		break;
+	case SCARD_F_COMM_ERROR:
+		strcpy(strError, "RPC transport error.");
+		break;
+	case SCARD_F_INTERNAL_ERROR:
+		strcpy(strError, "Unknown internal error.");
+		break;
+	case SCARD_F_UNKNOWN_ERROR:
+		strcpy(strError, "Unknown internal error.");
+		break;
+	case SCARD_F_WAITED_TOO_LONG:
+		strcpy(strError, "Waited too long.");
+		break;
+	case SCARD_E_UNKNOWN_READER:
+		strcpy(strError, "Unknown reader specified.");
+		break;
+	case SCARD_E_TIMEOUT:
+		strcpy(strError, "Command timeout.");
+		break;
+	case SCARD_E_SHARING_VIOLATION:
+		strcpy(strError, "Sharing violation.");
+		break;
+	case SCARD_E_NO_SMARTCARD:
+		strcpy(strError, "No smartcard inserted.");
+		break;
+	case SCARD_E_UNKNOWN_CARD:
+		strcpy(strError, "Unknown card.");
+		break;
+	case SCARD_E_PROTO_MISMATCH:
+		strcpy(strError, "Card protocol mismatch.");
+		break;
+	case SCARD_E_NOT_READY:
+		strcpy(strError, "Subsystem not ready.");
+		break;
+	case SCARD_E_SYSTEM_CANCELLED:
+		strcpy(strError, "System cancelled.");
+		break;
+	case SCARD_E_NOT_TRANSACTED:
+		strcpy(strError, "Transaction failed.");
+		break;
+	case SCARD_E_READER_UNAVAILABLE:
+		strcpy(strError, "Reader/s is unavailable.");
+		break;
+	case SCARD_W_UNSUPPORTED_CARD:
+		strcpy(strError, "Card is not supported.");
+		break;
+	case SCARD_W_UNRESPONSIVE_CARD:
+		strcpy(strError, "Card is unresponsive.");
+		break;
+	case SCARD_W_UNPOWERED_CARD:
+		strcpy(strError, "Card is unpowered.");
+		break;
+	case SCARD_W_RESET_CARD:
+		strcpy(strError, "Card was reset.");
+		break;
+	case SCARD_W_REMOVED_CARD:
+		strcpy(strError, "Card was removed.");
+		break;
+	case SCARD_W_INSERTED_CARD:
+		strcpy(strError, "Card was inserted.");
+		break;
+	case SCARD_E_UNSUPPORTED_FEATURE:
+		strcpy(strError, "Feature not supported.");
+		break;
+	case SCARD_E_PCI_TOO_SMALL:
+		strcpy(strError, "PCI struct too small.");
+		break;
+	case SCARD_E_READER_UNSUPPORTED:
+		strcpy(strError, "Reader is unsupported.");
+		break;
+	case SCARD_E_DUPLICATE_READER:
+		strcpy(strError, "Reader already exists.");
+		break;
+	case SCARD_E_CARD_UNSUPPORTED:
+		strcpy(strError, "Card is unsupported.");
+		break;
+	case SCARD_E_NO_SERVICE:
+		strcpy(strError, "Service not available.");
+		break;
+	case SCARD_E_SERVICE_STOPPED:
+		strcpy(strError, "Service was stopped.");
+		break;
+	default:
+		sprintf(strError, "Unknown PCSC error: %d [0x%08X]", Error, Error);
+		break;
+
+	};
+
+	return strError;
+}
+

Added: trunk/SmartCardServices/src/PCSC/debuglog.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/debuglog.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/debuglog.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,124 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  debuglog.h
+ *  SmartCardServices
+ */
+ 
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 1999-2005
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: debuglog.h 2151 2006-09-06 20:02:47Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles debugging.
+ *
+ * @note log message is sent to syslog or stderr depending on --foreground
+ * command line argument
+ *
+ * @test
+ * @code
+ * Log1(priority, "text");
+ *  log "text" with priority level priority
+ * Log2(priority, "text: %d", 1234);
+ *  log "text: 1234"
+ * the format string can be anything printf() can understand
+ * Log3(priority, "text: %d %d", 1234, 5678);
+ *  log "text: 1234 5678"
+ * the format string can be anything printf() can understand
+ * LogXxd(priority, msg, buffer, size);
+ *  log "msg" + a hex dump of size bytes of buffer[]
+ * @endcode
+ */
+
+#ifndef __debuglog_h__
+#define __debuglog_h__
+
+#include "pcscexport.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define DEBUGLOG_LOG_ENTRIES    1
+#define DEBUGLOG_IGNORE_ENTRIES 2
+
+enum {
+	DEBUGLOG_NO_DEBUG = 0,
+	DEBUGLOG_SYSLOG_DEBUG,
+	DEBUGLOG_STDERR_DEBUG
+};
+
+#define DEBUG_CATEGORY_NOTHING  0
+#define DEBUG_CATEGORY_APDU     1
+#define DEBUG_CATEGORY_SW       2
+
+enum {
+	PCSC_LOG_DEBUG = 0,
+	PCSC_LOG_INFO,
+	PCSC_LOG_ERROR,
+	PCSC_LOG_CRITICAL
+};
+
+/* You can't do #ifndef __FUNCTION__ */
+#if !defined(__GNUC__) && !defined(__IBMC__)
+#define __FUNCTION__ ""
+#endif
+
+#define Log0(priority) log_msg(priority, "%s:%d:%s()", __FILE__, __LINE__, __FUNCTION__)
+#define Log1(priority, fmt) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__)
+#define Log2(priority, fmt, data) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data)
+#define Log3(priority, fmt, data1, data2) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data1, data2)
+#define Log4(priority, fmt, data1, data2, data3) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data1, data2, data3)
+#define Log9(priority, fmt, data1, data2, data3, data4, data5, data6, data7, data8) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data1, data2, data3, data4, data5, data6, data7, data8)
+#define LogXxd(priority, msg, buffer, size) log_xxd(priority, msg, buffer, size)
+
+#define DebugLogA(a) Log1(PCSC_LOG_INFO, a)
+#define DebugLogB(a, b) Log2(PCSC_LOG_INFO, a, b)
+#define DebugLogC(a, b,c) Log3(PCSC_LOG_INFO, a, b, c)
+
+PCSC_API void log_msg(const int priority, const char *fmt, ...);
+PCSC_API void log_xxd(const int priority, const char *msg,
+	const unsigned char *buffer, const int size);
+
+void DebugLogSuppress(const int);
+void DebugLogSetLogType(const int);
+int DebugLogSetCategory(const int);
+void DebugLogCategory(const int, const unsigned char *, const int);
+PCSC_API void DebugLogSetLevel(const int level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __debuglog_h__ */
+

Added: trunk/SmartCardServices/src/PCSC/driverparser.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/driverparser.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/driverparser.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1735 @@
+#define yy_create_buffer bp_create_buffer
+#define yy_delete_buffer bp_delete_buffer
+#define yy_scan_buffer bp_scan_buffer
+#define yy_scan_string bp_scan_string
+#define yy_scan_bytes bp_scan_bytes
+#define yy_flex_debug bp_flex_debug
+#define yy_init_buffer bp_init_buffer
+#define yy_flush_buffer bp_flush_buffer
+#define yy_load_buffer_state bp_load_buffer_state
+#define yy_switch_to_buffer bp_switch_to_buffer
+#define yyin bpin
+#define yyleng bpleng
+#define yylex bplex
+#define yyout bpout
+#define yyrestart bprestart
+#define yytext bptext
+#define yywrap bpwrap
+
+/*
+ * A lexical scanner generated by flex 
+ */
+
+/*
+ * Scanner skeleton version: $Header:
+ * /home/cvsroot/muscle/PCSC/src/driverparser.c,v 1.1.1.1 2002/03/30
+ * 18:15:03 corcoran Exp $ 
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+/*
+ * cfront 1.2 defines "c_plusplus" instead of "__cplusplus" 
+ */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * Use prototypes in function declarations. 
+ */
+#define YY_USE_PROTOS
+
+/*
+ * The "const" storage-class-modifier is valid. 
+ */
+#define YY_USE_CONST
+
+#else							/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif							/* __STDC__ */
+#endif							/* ! __cplusplus */
+
+#ifdef __TURBOC__
+#pragma warn -rch
+#pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/*
+ * Returned upon end-of-file. 
+ */
+#define YY_NULL 0
+
+/*
+ * Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative, we
+ * want to instead treat it as an 8-bit unsigned char, hence the double
+ * cast. 
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/*
+ * Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN. 
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/*
+ * Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility. 
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/*
+ * Action number for EOF rule of a given start state. 
+ */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/*
+ * Special action meaning "start processing a new file". 
+ */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/*
+ * Size of default input buffer. 
+ */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/*
+ * The funky do-while in the following #define is used to turn the
+ * definition int a single C statement (which needs a semi-colon
+ * terminator).  This avoids problems with code like: if (
+ * condition_holds ) yyless( 5 ); else do_something_else(); Prior to
+ * using the do-while the compiler would get upset at the "else" because
+ * it interpreted the "if" statement as being all done when it reached the 
+ * ';' after the yyless() call. 
+ */
+
+/*
+ * Return all but the first 'n' matched characters back to the input
+ * stream. 
+ */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/*
+ * The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own). 
+ */
+typedef unsigned int yy_size_t;
+
+struct yy_buffer_state
+{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;			/* input buffer */
+	char *yy_buf_pos;			/* current position in input buffer */
+
+	/*
+	 * Size of input buffer in bytes, not including room for EOB
+	 * characters. 
+	 */
+	yy_size_t yy_buf_size;
+
+	/*
+	 * Number of characters read into yy_ch_buf, not including EOB
+	 * characters. 
+	 */
+	int yy_n_chars;
+
+	/*
+	 * Whether we "own" the buffer - i.e., we know we created it, and can
+	 * realloc() it to grow it, and should free() it to delete it. 
+	 */
+	int yy_is_our_buffer;
+
+	/*
+	 * Whether this is an "interactive" input source; if so, and if we're
+	 * using stdio for input, then we want to use getc() instead of
+	 * fread(), to make sure we stop fetching input after each newline. 
+	 */
+	int yy_is_interactive;
+
+	/*
+	 * Whether we're considered to be at the beginning of a line. If so,
+	 * '^' rules will be active on the next match, otherwise not. 
+	 */
+	int yy_at_bol;
+
+	/*
+	 * Whether to try to fill the input buffer when we reach the end of
+	 * it. 
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/*
+	 * When an EOF's been seen but there's still some text to process then 
+	 * we mark the buffer as YY_EOF_PENDING, to indicate that we shouldn't 
+	 * try reading from the input source any more.  We might still have a
+	 * bunch of tokens to match, though, because of possible backing-up.
+	 * When we actually see the EOF, we change the status to "new" (via
+	 * yyrestart()), so that the user can continue scanning by just
+	 * pointing yyin at a new input file. 
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/*
+ * We provide macros for accessing buffer states in case in the future we
+ * want to put the buffer states in a more general "scanner state". 
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+/*
+ * yy_hold_char holds the character lost when yytext is formed. 
+ */
+static char yy_hold_char;
+
+static int yy_n_chars;			/* number of characters read into
+								 * yy_ch_buf */
+
+int yyleng;
+
+/*
+ * Points to current character in buffer. 
+ */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;			/* whether we need to initialize */
+static int yy_start = 0;		/* start state number */
+
+/*
+ * Flag which is used to allow yywrap()'s to do buffer switches instead of 
+ * setting up a fresh yyin.  A bit of a hack ... 
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO((FILE * input_file));
+
+void yy_switch_to_buffer YY_PROTO((YY_BUFFER_STATE new_buffer));
+void yy_load_buffer_state YY_PROTO((void));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO((FILE * file, int size));
+void yy_delete_buffer YY_PROTO((YY_BUFFER_STATE b));
+void yy_init_buffer YY_PROTO((YY_BUFFER_STATE b, FILE * file));
+void yy_flush_buffer YY_PROTO((YY_BUFFER_STATE b));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO((char *base, yy_size_t size));
+YY_BUFFER_STATE yy_scan_string YY_PROTO((yyconst char *yy_str));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO((yyconst char *bytes, int len));
+
+static void *yy_flex_alloc YY_PROTO((yy_size_t));
+static void *yy_flex_realloc YY_PROTO((void *, yy_size_t));
+static void yy_flex_free YY_PROTO((void *));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO((void));
+static yy_state_type yy_try_NUL_trans YY_PROTO((yy_state_type
+		current_state));
+static int yy_get_next_buffer YY_PROTO((void));
+static void yy_fatal_error YY_PROTO((yyconst char msg[]));
+
+/*
+ * Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext. 
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 7
+#define YY_END_OF_BUFFER 8
+static yyconst short int yy_accept[39] = { 0,
+	0, 0, 8, 6, 4, 2, 1, 6, 1, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+	0, 0, 0, 0, 0, 0, 5, 0
+};
+
+static yyconst int yy_ec[256] = { 0,
+	1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 2, 4, 4, 5, 4, 4, 4, 4, 4,
+	4, 4, 4, 4, 4, 4, 6, 7, 7, 7,
+	7, 7, 7, 7, 7, 7, 7, 4, 1, 8,
+	4, 9, 4, 4, 10, 10, 10, 10, 10, 10,
+	10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	1, 1, 1, 4, 4, 1, 11, 11, 11, 11,
+
+	12, 11, 13, 11, 14, 11, 15, 11, 11, 16,
+	11, 11, 11, 17, 18, 19, 11, 11, 11, 11,
+	20, 11, 1, 1, 1, 4, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1
+};
+
+static yyconst int yy_meta[21] = { 0,
+	1, 2, 3, 4, 4, 4, 2, 1, 1, 2,
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+static yyconst short int yy_base[43] = { 0,
+	0, 7, 49, 50, 50, 50, 0, 1, 0, 36,
+	28, 26, 28, 35, 29, 0, 26, 33, 27, 33,
+	29, 22, 0, 24, 27, 14, 27, 23, 13, 50,
+	10, 9, 4, 1, 0, 2, 50, 50, 19, 23,
+	2, 26
+};
+
+static yyconst short int yy_def[43] = { 0,
+	39, 39, 38, 38, 38, 38, 40, 38, 40, 38,
+	38, 38, 38, 38, 38, 41, 38, 41, 38, 38,
+	38, 38, 42, 38, 42, 38, 38, 38, 38, 38,
+	38, 38, 38, 38, 38, 38, 38, 0, 38, 38,
+	38, 38
+};
+
+static yyconst short int yy_nxt[71] = { 0,
+	38, 5, 6, 18, 7, 38, 38, 8, 5, 6,
+	37, 7, 36, 38, 8, 10, 35, 34, 11, 4,
+	4, 4, 4, 9, 9, 33, 9, 25, 32, 25,
+	31, 30, 29, 28, 27, 26, 24, 23, 22, 21,
+	20, 19, 17, 16, 15, 14, 13, 12, 38, 3,
+	38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+	38, 38, 38, 38, 38, 38, 38, 38, 38, 38
+};
+
+static yyconst short int yy_chk[71] = { 0,
+	0, 1, 1, 41, 1, 0, 0, 1, 2, 2,
+	36, 2, 35, 0, 2, 8, 34, 33, 8, 39,
+	39, 39, 39, 40, 40, 32, 40, 42, 31, 42,
+	29, 28, 27, 26, 25, 24, 22, 21, 20, 19,
+	18, 17, 15, 14, 13, 12, 11, 10, 3, 38,
+	38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+	38, 38, 38, 38, 38, 38, 38, 38, 38, 38
+};
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/*
+ * The intent behind this definition is that it'll catch any uses of
+ * REJECT which flex missed. 
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "bundleparser.l"
+#define INITIAL 0
+/*****************************************************************
+
+  File   :   configfile.ll
+  Author :   David Corcoran
+  Date   :   February 12, 1999 modified 7/28/99
+  Purpose:   Reads lexical config files and updates database.
+             See http://www.linuxnet.com for more information.
+  License:   Copyright (C) 1999 David Corcoran
+             <corcoran at linuxnet.com>
+
+******************************************************************/
+#line 14 "bundleparser.l"
+
+void evalToken(char *pcToken, int tokType);
+
+static char *pcDesiredKey = 0;
+static char pcKey[200];
+static char pcValue[200];
+static char pcFinValue[200];
+
+void errorCheck(char *pcToken_error);
+
+#line 427 "lex.bp.c"
+
+/*
+ * Macros after this point can all be overridden by user definitions in
+ * section 1. 
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO((void));
+#else
+extern int yywrap YY_PROTO((void));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO((int c, char *buf_ptr));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO((char *, yyconst char *, int));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO((yyconst char *));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO((void));
+#else
+static int input YY_PROTO((void));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO((int new_state));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO((void));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO((void));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/*
+ * Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int). 
+ */
+#endif
+#endif
+
+/*
+ * Amount of stuff to slurp up with each read. 
+ */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/*
+ * Copy whatever the last rule matched to the standard output. 
+ */
+
+#ifndef ECHO
+/*
+ * This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite(). 
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/*
+ * Gets input and stuffs it into "buf".  number of characters read, or
+ * YY_NULL, is returned in "result". 
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/*
+ * No semi-colon after return; correct usage is to write "yyterminate();"
+ * - we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements. 
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/*
+ * Number of entries by which start-condition stack grows. 
+ */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/*
+ * Report a fatal error. 
+ */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/*
+ * Default declaration of generated scanner - a define so the user can
+ * easily add parameters. 
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/*
+ * Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up. 
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/*
+ * Code executed at the end of each rule. 
+ */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 26 "bundleparser.l"
+
+#line 581 "lex.bp.c"
+
+	if (yy_init)
+	{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if (!yy_start)
+			yy_start = 1;	/* first start state */
+
+		if (!yyin)
+			yyin = stdin;
+
+		if (!yyout)
+			yyout = stdout;
+
+		if (!yy_current_buffer)
+			yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
+
+		yy_load_buffer_state();
+	}
+
+	while (1)	/* loops until end-of-file is reached */
+	{
+		yy_cp = yy_c_buf_p;
+
+		/*
+		 * Support of yytext. 
+		 */
+		*yy_cp = yy_hold_char;
+
+		/*
+		 * yy_bp points to the position in yy_ch_buf of the start of the
+		 * current run. 
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+	  yy_match:
+		do
+		{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if (yy_accept[yy_current_state])
+			{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+			}
+			while (yy_chk[yy_base[yy_current_state] + yy_c] !=
+				yy_current_state)
+			{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if (yy_current_state >= 39)
+					yy_c = yy_meta[(unsigned int) yy_c];
+			}
+			yy_current_state =
+				yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+		}
+		while (yy_base[yy_current_state] != 50);
+
+	  yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if (yy_act == 0)
+		{	/* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+		}
+
+		YY_DO_BEFORE_ACTION;
+
+	  do_action:	/* This label is used only to access EOF actions. */
+
+		switch (yy_act)
+		{	/* beginning of action switch */
+		case 0:	/* must back up */
+			/*
+			 * undo the effects of YY_DO_BEFORE_ACTION 
+			 */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+		case 1:
+			YY_RULE_SETUP
+#line 28 "bundleparser.l"
+			{
+			}
+		YY_BREAK case 2:
+			YY_RULE_SETUP
+#line 29 "bundleparser.l"
+			{
+			}
+		YY_BREAK case 3:
+			YY_RULE_SETUP
+#line 30 "bundleparser.l"
+			{
+				evalToken(bptext, 1);
+			}
+		YY_BREAK case 4:
+			YY_RULE_SETUP
+#line 31 "bundleparser.l"
+			{
+			}
+		YY_BREAK case 5:
+			YY_RULE_SETUP
+#line 32 "bundleparser.l"
+			{
+				evalToken(bptext, 2);
+			}
+		YY_BREAK case 6:
+			YY_RULE_SETUP
+#line 33 "bundleparser.l"
+			{
+				errorCheck(bptext);
+			}
+		YY_BREAK case 7:
+			YY_RULE_SETUP
+#line 34 "bundleparser.l"
+				ECHO;
+			YY_BREAK
+#line 699 "lex.bp.c"
+		case YY_STATE_EOF(INITIAL):
+			yyterminate();
+
+		case YY_END_OF_BUFFER:
+			{
+				/*
+				 * Amount of text matched not including the EOB char. 
+				 */
+				int yy_amount_of_matched_text =
+					(int) (yy_cp - yytext_ptr) - 1;
+
+				/*
+				 * Undo the effects of YY_DO_BEFORE_ACTION. 
+				 */
+				*yy_cp = yy_hold_char;
+				YY_RESTORE_YY_MORE_OFFSET
+					if (yy_current_buffer->yy_buffer_status ==
+					YY_BUFFER_NEW)
+				{
+					/*
+					 * We're scanning a new file or input source.  It's
+					 * possible that this happened because the user just
+					 * pointed yyin at a new source and called yylex().
+					 * If so, then we have to assure consistency between
+					 * yy_current_buffer and our globals.  Here is the
+					 * right place to do so, because this is the first
+					 * action (other than possibly a back-up) that will
+					 * match for the new input source. 
+					 */
+					yy_n_chars = yy_current_buffer->yy_n_chars;
+					yy_current_buffer->yy_input_file = yyin;
+					yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+				}
+
+				/*
+				 * Note that here we test for yy_c_buf_p "<=" to the
+				 * position of the first EOB in the buffer, since
+				 * yy_c_buf_p will already have been incremented past the
+				 * NUL character (since all states make transitions on EOB 
+				 * to the end-of-buffer state).  Contrast this with the
+				 * test in input(). 
+				 */
+				if (yy_c_buf_p <=
+					&yy_current_buffer->yy_ch_buf[yy_n_chars])
+				{	/* This was really a NUL. */
+					yy_state_type yy_next_state;
+
+					yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+					yy_current_state = yy_get_previous_state();
+
+					/*
+					 * Okay, we're now positioned to make the NUL
+					 * transition.  We couldn't have
+					 * yy_get_previous_state() go ahead and do it for us
+					 * because it doesn't know how to deal with the
+					 * possibility of jamming (and we don't want to build
+					 * jamming into it because then it will run more
+					 * slowly). 
+					 */
+
+					yy_next_state = yy_try_NUL_trans(yy_current_state);
+
+					yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+					if (yy_next_state)
+					{
+						/*
+						 * Consume the NUL. 
+						 */
+						yy_cp = ++yy_c_buf_p;
+						yy_current_state = yy_next_state;
+						goto yy_match;
+					}
+
+					else
+					{
+						yy_cp = yy_c_buf_p;
+						goto yy_find_action;
+					}
+				}
+
+				else
+					switch (yy_get_next_buffer())
+					{
+					case EOB_ACT_END_OF_FILE:
+						{
+							yy_did_buffer_switch_on_eof = 0;
+
+							if (yywrap())
+							{
+								/*
+								 * Note: because we've taken care in
+								 * yy_get_next_buffer() to have set up
+								 * yytext, we can now set up yy_c_buf_p so 
+								 * that if some total hoser (like flex
+								 * itself) wants to call the scanner after 
+								 * we return the YY_NULL, it'll still work 
+								 * - another YY_NULL will get returned. 
+								 */
+								yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+								yy_act = YY_STATE_EOF(YY_START);
+								goto do_action;
+							}
+
+							else
+							{
+								if (!yy_did_buffer_switch_on_eof)
+									YY_NEW_FILE;
+							}
+							break;
+						}
+
+					case EOB_ACT_CONTINUE_SCAN:
+						yy_c_buf_p =
+							yytext_ptr + yy_amount_of_matched_text;
+
+						yy_current_state = yy_get_previous_state();
+
+						yy_cp = yy_c_buf_p;
+						yy_bp = yytext_ptr + YY_MORE_ADJ;
+						goto yy_match;
+
+					case EOB_ACT_LAST_MATCH:
+						yy_c_buf_p =
+							&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+						yy_current_state = yy_get_previous_state();
+
+						yy_cp = yy_c_buf_p;
+						yy_bp = yytext_ptr + YY_MORE_ADJ;
+						goto yy_find_action;
+					}
+				break;
+			}
+
+		default:
+			YY_FATAL_ERROR
+				("fatal flex scanner internal error--no action found");
+		}	/* end of action switch */
+	}	/* end of scanning one token */
+}	/* end of yylex */
+
+/*
+ * yy_get_next_buffer - try to read in a new buffer Returns a code
+ * representing an action: EOB_ACT_LAST_MATCH - EOB_ACT_CONTINUE_SCAN -
+ * continue scanning from current position EOB_ACT_END_OF_FILE - end of
+ * file 
+ */
+
+static int yy_get_next_buffer()
+{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
+		YY_FATAL_ERROR
+			("fatal flex scanner internal error--end of buffer missed");
+
+	if (yy_current_buffer->yy_fill_buffer == 0)
+	{	/* Don't try to fill the buffer, so this is an EOF. */
+		if (yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1)
+		{
+			/*
+			 * We matched a single character, the EOB, so treat this as a
+			 * final EOF. 
+			 */
+			return EOB_ACT_END_OF_FILE;
+		}
+
+		else
+		{
+			/*
+			 * We matched some text prior to the EOB, first process it. 
+			 */
+			return EOB_ACT_LAST_MATCH;
+		}
+	}
+
+	/*
+	 * Try to read more data. 
+	 */
+
+	/*
+	 * First move last chars to start of buffer. 
+	 */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for (i = 0; i < number_to_move; ++i)
+		*(dest++) = *(source++);
+
+	if (yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING)
+		/*
+		 * don't do the read, it's not guaranteed to return an EOF, just
+		 * force an EOF 
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+	{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while (num_to_read <= 0)
+		{	/* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR
+				("input buffer overflow, can't enlarge buffer because scanner uses REJECT");
+#else
+
+			/*
+			 * just a shorter name for the current buffer 
+			 */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset = (int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if (b->yy_is_our_buffer)
+			{
+				int new_size = b->yy_buf_size * 2;
+
+				if (new_size <= 0)
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/*
+					 * Include room in for 2 EOB chars. 
+					 */
+					yy_flex_realloc((void *) b->yy_ch_buf,
+					b->yy_buf_size + 2);
+			} else
+				/*
+				 * Can't grow it, we don't own it. 
+				 */
+				b->yy_ch_buf = 0;
+
+			if (!b->yy_ch_buf)
+				YY_FATAL_ERROR
+					("fatal error - scanner input buffer overflow");
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+				number_to_move - 1;
+#endif
+		}
+
+		if (num_to_read > YY_READ_BUF_SIZE)
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/*
+		 * Read in more data. 
+		 */
+		YY_INPUT((&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read);
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+	}
+
+	if (yy_n_chars == 0)
+	{
+		if (number_to_move == YY_MORE_ADJ)
+		{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart(yyin);
+		}
+
+		else
+		{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_EOF_PENDING;
+		}
+	}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/*
+ * yy_get_previous_state - get the state just before the EOB char was
+ * reached 
+ */
+
+static yy_state_type yy_get_previous_state()
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp)
+	{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if (yy_accept[yy_current_state])
+		{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+		}
+		while (yy_chk[yy_base[yy_current_state] + yy_c] !=
+			yy_current_state)
+		{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if (yy_current_state >= 39)
+				yy_c = yy_meta[(unsigned int) yy_c];
+		}
+		yy_current_state =
+			yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	}
+
+	return yy_current_state;
+}
+
+/*
+ * yy_try_NUL_trans - try to make a transition on the NUL character
+ * synopsis next_state = yy_try_NUL_trans( current_state ); 
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state)
+#else
+static yy_state_type yy_try_NUL_trans(yy_current_state)
+	yy_state_type yy_current_state;
+#endif
+{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if (yy_accept[yy_current_state])
+	{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+	}
+	while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state)
+	{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if (yy_current_state >= 39)
+			yy_c = yy_meta[(unsigned int) yy_c];
+	}
+	yy_current_state =
+		yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 38);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput(int c, register char *yy_bp)
+#else
+static void yyunput(c, yy_bp)
+	int c;
+	register char *yy_bp;
+#endif
+{
+	register char *yy_cp = yy_c_buf_p;
+
+	/*
+	 * undo effects of setting up yytext 
+	 */
+	*yy_cp = yy_hold_char;
+
+	if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
+	{	/* need to shift things up to make room */
+		/*
+		 * +2 for EOB chars. 
+		 */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest =
+			&yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size +
+			2];
+		register char *source =
+			&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while (source > yy_current_buffer->yy_ch_buf)
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
+			YY_FATAL_ERROR("flex scanner push-back overflow");
+	}
+
+	*--yy_cp = (char) c;
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+}
+#endif							/* ifndef YY_NO_UNPUT */
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if (*yy_c_buf_p == YY_END_OF_BUFFER_CHAR)
+	{
+		/*
+		 * yy_c_buf_p now points to the character we want to return. If
+		 * this occurs *before* the EOB characters, then it's a valid NUL; 
+		 * if not, then we've hit the end of the buffer. 
+		 */
+		if (yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars])
+			/*
+			 * This was really a NUL. 
+			 */
+			*yy_c_buf_p = '\0';
+
+		else
+		{	/* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch (yy_get_next_buffer())
+			{
+			case EOB_ACT_LAST_MATCH:
+				/*
+				 * This happens because yy_g_n_b() sees that we've
+				 * accumulated a token and flags that we need to try
+				 * matching the token before proceeding.  But for input(),
+				 * there's no matching to consider. So convert the
+				 * EOB_ACT_LAST_MATCH to EOB_ACT_END_OF_FILE. 
+				 */
+
+				/*
+				 * Reset buffer status. 
+				 */
+				yyrestart(yyin);
+
+				/*
+				 * fall through 
+				 */
+
+			case EOB_ACT_END_OF_FILE:
+				{
+					if (yywrap())
+						return EOF;
+
+					if (!yy_did_buffer_switch_on_eof)
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p = yytext_ptr + offset;
+				break;
+			}
+		}
+	}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+	return c;
+}
+
+#ifdef YY_USE_PROTOS
+void yyrestart(FILE * input_file)
+#else
+void yyrestart(input_file)
+	FILE *input_file;
+#endif
+{
+	if (!yy_current_buffer)
+		yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
+
+	yy_init_buffer(yy_current_buffer, input_file);
+	yy_load_buffer_state();
+}
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer)
+#else
+void yy_switch_to_buffer(new_buffer)
+	YY_BUFFER_STATE new_buffer;
+#endif
+{
+	if (yy_current_buffer == new_buffer)
+		return;
+
+	if (yy_current_buffer)
+	{
+		/*
+		 * Flush out information for old buffer. 
+		 */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+	}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/*
+	 * We don't actually know whether we did this switch during EOF
+	 * (yywrap()) processing, but the only time this flag is looked at is
+	 * after yywrap() is called, so it's safe to go ahead and always set
+	 * it. 
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+}
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state(void)
+#else
+void yy_load_buffer_state()
+#endif
+{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+}
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer(FILE * file, int size)
+#else
+YY_BUFFER_STATE yy_create_buffer(file, size)
+	FILE *file;
+	int size;
+#endif
+{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc(sizeof(struct yy_buffer_state));
+	if (!b)
+		YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
+
+	b->yy_buf_size = size;
+
+	/*
+	 * yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters. 
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc(b->yy_buf_size + 2);
+	if (!b->yy_ch_buf)
+		YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer(b, file);
+
+	return b;
+}
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer(YY_BUFFER_STATE b)
+#else
+void yy_delete_buffer(b)
+	YY_BUFFER_STATE b;
+#endif
+{
+	if (!b)
+		return;
+
+	if (b == yy_current_buffer)
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if (b->yy_is_our_buffer)
+		yy_flex_free((void *) b->yy_ch_buf);
+
+	yy_flex_free((void *) b);
+}
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO((int));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer(YY_BUFFER_STATE b, FILE * file)
+#else
+void yy_init_buffer(b, file)
+	YY_BUFFER_STATE b;
+	FILE *file;
+#endif
+
+{
+	yy_flush_buffer(b);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty(fileno(file)) > 0) : 0;
+#endif
+#endif
+}
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer(YY_BUFFER_STATE b)
+#else
+void yy_flush_buffer(b)
+	YY_BUFFER_STATE b;
+#endif
+
+{
+	if (!b)
+		return;
+
+	b->yy_n_chars = 0;
+
+	/*
+	 * We always need two end-of-buffer characters.  The first causes a
+	 * transition to the end-of-buffer state.  The second causes a jam in
+	 * that state. 
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if (b == yy_current_buffer)
+		yy_load_buffer_state();
+}
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size)
+#else
+YY_BUFFER_STATE yy_scan_buffer(base, size)
+	char *base;
+	yy_size_t size;
+#endif
+{
+	YY_BUFFER_STATE b;
+
+	if (size < 2 ||
+		base[size - 2] != YY_END_OF_BUFFER_CHAR ||
+		base[size - 1] != YY_END_OF_BUFFER_CHAR)
+		/*
+		 * They forgot to leave room for the EOB's. 
+		 */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc(sizeof(struct yy_buffer_state));
+	if (!b)
+		YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()");
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer(b);
+
+	return b;
+}
+#endif
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string(yyconst char *yy_str)
+#else
+YY_BUFFER_STATE yy_scan_string(yy_str)
+	yyconst char *yy_str;
+#endif
+{
+	int len;
+	for (len = 0; yy_str[len]; ++len)
+		;
+
+	return yy_scan_bytes(yy_str, len);
+}
+#endif
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes(yyconst char *bytes, int len)
+#else
+YY_BUFFER_STATE yy_scan_bytes(bytes, len)
+	yyconst char *bytes;
+	int len;
+#endif
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/*
+	 * Get memory for full buffer, including space for trailing EOB's. 
+	 */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc(n);
+	if (!buf)
+		YY_FATAL_ERROR("out of dynamic memory in yy_scan_bytes()");
+
+	for (i = 0; i < len; ++i)
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len + 1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer(buf, n);
+	if (!b)
+		YY_FATAL_ERROR("bad buffer in yy_scan_bytes()");
+
+	/*
+	 * It's okay to grow etc. this buffer, and we should throw it away
+	 * when we're done. 
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+#endif
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state(int new_state)
+#else
+static void yy_push_state(new_state)
+	int new_state;
+#endif
+{
+	if (yy_start_stack_ptr >= yy_start_stack_depth)
+	{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof(int);
+
+		if (!yy_start_stack)
+			yy_start_stack = (int *) yy_flex_alloc(new_size);
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+				(void *) yy_start_stack, new_size);
+
+		if (!yy_start_stack)
+			YY_FATAL_ERROR
+				("out of memory expanding start-condition stack");
+	}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+}
+#endif
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+{
+	if (--yy_start_stack_ptr < 0)
+		YY_FATAL_ERROR("start-condition stack underflow");
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+}
+#endif
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error(yyconst char msg[])
+#else
+static void yy_fatal_error(msg)
+	char msg[];
+#endif
+{
+	(void) fprintf(stderr, "%s\n", msg);
+	exit(YY_EXIT_FAILURE);
+}
+
+/*
+ * Redefine yyless() so it works in section 3 code. 
+ */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+/*
+ * Internal utility routines. 
+ */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy(char *s1, yyconst char *s2, int n)
+#else
+static void yy_flex_strncpy(s1, s2, n)
+	char *s1;
+	yyconst char *s2;
+	int n;
+#endif
+{
+	register int i;
+	for (i = 0; i < n; ++i)
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen(yyconst char *s)
+#else
+static int yy_flex_strlen(s)
+	yyconst char *s;
+#endif
+{
+	register int n;
+	for (n = 0; s[n]; ++n)
+		;
+
+	return n;
+}
+#endif
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc(yy_size_t size)
+#else
+static void *yy_flex_alloc(size)
+	yy_size_t size;
+#endif
+{
+	return (void *) malloc(size);
+}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc(void *ptr, yy_size_t size)
+#else
+static void *yy_flex_realloc(ptr, size)
+	void *ptr;
+	yy_size_t size;
+#endif
+{
+	/*
+	 * The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those that use 
+	 * void* generic pointers.  It works with the latter because both ANSI 
+	 * C and C++ allow castless assignment from any pointer type to void*, 
+	 * and deal with argument conversions as though doing an assignment. 
+	 */
+	return (void *) realloc((char *) ptr, size);
+}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free(void *ptr)
+#else
+static void yy_flex_free(ptr)
+	void *ptr;
+#endif
+{
+	free(ptr);
+}
+
+#if YY_MAIN
+int main()
+{
+	yylex();
+	return 0;
+}
+#endif
+#line 34 "bundleparser.l"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "wintypes.h"
+#include "debuglog.h"
+
+int bpwrap()
+{
+	return 1;
+}
+
+void evalToken(char *pcToken, int tokType)
+{
+
+	int len;
+	len = 0;
+
+	if (tokType == 1)
+	{
+		for (len = 5; pcToken[len] != '<'; len++) ;
+		strncpy(pcKey, &pcToken[5], len - 5);
+		pcKey[len - 5] = 0;
+	}
+
+	if (tokType == 2)
+	{
+		for (len = 8; pcToken[len] != '<'; len++) ;
+		strncpy(pcValue, &pcToken[8], len - 8);
+		pcValue[len - 8] = 0;
+		if (strcmp(pcKey, pcDesiredKey) == 0)
+		{
+			strcpy(pcFinValue, pcValue);
+		}
+	}
+
+}
+
+void errorCheck(char *token_error)
+{
+}
+
+int LCFBundleFindValueWithKey(char *fileName, char *tokenKey,
+	char *tokenValue)
+{
+
+	FILE *file;
+	file = 0;
+
+	pcDesiredKey = tokenKey;
+	pcFinValue[0] = 0;
+
+	file = fopen(fileName, "r");
+
+	if (!file)
+	{
+		DebugLogB("Could not open bundle file : %s", fileName);
+		return 1;
+	}
+
+	bpin = file;
+
+	do
+	{
+		bplex();
+	}
+	while (!feof(file));
+
+	if (pcFinValue[0] == 0)
+	{
+		DebugLogB("Value/Key not defined for: %s", tokenKey);
+		fclose(file);
+		return -1;
+	} else
+	{
+		strcpy(tokenValue, pcFinValue);
+		fclose(file);
+		return 0;
+	}
+
+	fclose(file);
+	return 0;
+}

Added: trunk/SmartCardServices/src/PCSC/driverparser.l
===================================================================
--- trunk/SmartCardServices/src/PCSC/driverparser.l	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/driverparser.l	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,108 @@
+/*****************************************************************
+
+  File   :   configfile.ll
+  Author :   David Corcoran
+  Date   :   February 12, 1999 modified 7/28/99
+  Purpose:   Reads lexical config files and updates database.
+             See http://www.linuxnet.com for more information.
+  License:   Copyright (C) 1999 David Corcoran
+             <corcoran at linuxnet.com>
+
+******************************************************************/
+
+%{
+
+void evalToken( char *pcToken, int tokType );
+
+static char *pcDesiredKey   = 0;
+static char pcKey[200];
+static char pcValue[200];
+static char pcFinValue[200];
+
+void errorCheck ( char *pcToken_error );
+
+%}
+
+%%
+
+#.*                                             {}
+"\n"                                            {}
+\<key\>([A-Z]|[a-z]|[0-9]|[ \t])+\<\/key\>      { evalToken(bptext, 1); } 
+[ \t]                     		        {}
+\<string\>([A-Z]|[a-z]|[0-9]|[ \t]|[!@#$%^&*()\-+/_\:?.,=~'"])+\<\/string\> { evalToken(bptext, 2); } 
+.                                               { errorCheck( bptext ); }
+%%
+
+#include <stdio.h>
+#include <string.h>
+
+#include "wintypes.h"
+#include "debuglog.h"
+
+int bpwrap() {
+  return 1;
+}
+
+
+void evalToken( char *pcToken, int tokType ) {
+
+  int len;
+  len = 0;
+
+  if ( tokType == 1 ) {
+   for (len=5; pcToken[len] != '<'; len++);
+   strncpy(pcKey, &pcToken[5], len - 5);
+   pcKey[len-5] = 0;
+  }
+
+  if ( tokType == 2 ) {
+   for (len=8; pcToken[len] != '<'; len++);
+   strncpy(pcValue, &pcToken[8], len - 8);
+   pcValue[len-8] = 0;
+    if ( strcmp(pcKey, pcDesiredKey) == 0 ) {
+      strcpy(pcFinValue, pcValue);
+    }
+  }
+
+
+}
+
+void errorCheck ( char *token_error ) { }
+
+int LCFBundleFindValueWithKey(char *fileName, char *tokenKey, 
+                              char *tokenValue ) {
+
+  FILE *file;
+  file = 0;
+ 
+  pcDesiredKey  = tokenKey;
+  pcFinValue[0] = 0;
+
+  file = fopen(fileName, "r");
+ 
+  if (!file) {
+    DebugLogB( "Could not open bundle file : %s", fileName );
+    return 1;
+  }
+ 
+  bpin = file;
+ 
+  do {
+    bplex();
+  }
+  while (!feof(file));
+
+  if ( pcFinValue[0] == 0 ) {
+    DebugLogB( "Value/Key not defined for: %s", tokenKey );
+    fclose(file);
+    return -1;
+  } else {
+    strcpy(tokenValue, pcFinValue);
+    fclose(file);
+    return 0;
+  }
+ 
+  fclose(file);  
+  return 0;    
+}
+

Added: trunk/SmartCardServices/src/PCSC/dyn_generic.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/dyn_generic.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/dyn_generic.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : dyn_generic.h
+	    Package: pcsc lite
+            Author : David Corcoran
+            Date   : 8/12/99
+	    License: Copyright (C) 1999 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This abstracts dynamic library loading 
+                     functions. 
+
+********************************************************************/
+
+#ifndef __dyn_generic_h__
+#define __dyn_generic_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	int DYN_LoadLibrary(void **, char *);
+	int DYN_CloseLibrary(void **);
+	int DYN_GetAddress(void *, void **, char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PCSC/dyn_macosx.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/dyn_macosx.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/dyn_macosx.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : dyn_macosx.c
+	    Package: pcsc lite
+            Author : David Corcoran
+            Date   : 3/15/00
+            License: Copyright (C) 2000 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This abstracts dynamic library loading 
+                     functions and timing. 
+
+********************************************************************/
+
+#include <CoreFoundation/CFBundle.h>
+#include <CoreFoundation/CFString.h>
+#include <CoreFoundation/CFURL.h>
+
+#include "config.h"
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "dyn_generic.h"
+#include "debuglog.h"
+
+/*
+ * / Load a module (if needed) 
+ */
+int DYN_LoadLibrary(void **pvLHandle, char *pcLibrary)
+{
+
+	CFStringRef bundlePath;
+	CFURLRef bundleURL;
+	CFBundleRef bundle;
+
+	*pvLHandle = 0;
+
+	/*
+	 * @@@ kCFStringEncodingMacRoman might be wrong on non US systems. 
+	 */
+
+	bundlePath = CFStringCreateWithCString(NULL, pcLibrary,
+		kCFStringEncodingMacRoman);
+	if (bundlePath == NULL)
+	{
+		return SCARD_E_NO_MEMORY;
+
+	} else
+	{
+	}
+
+	bundleURL = CFURLCreateWithFileSystemPath(NULL, bundlePath,
+		kCFURLPOSIXPathStyle, TRUE);
+	CFRelease(bundlePath);
+	if (bundleURL == NULL)
+	{
+		return SCARD_E_NO_MEMORY;
+	} else
+	{
+	}
+
+	bundle = CFBundleCreate(NULL, bundleURL);
+	CFRelease(bundleURL);
+	if (bundle == NULL)
+	{
+		return SCARD_F_UNKNOWN_ERROR;
+	} else
+	{
+	}
+
+	if (!CFBundleLoadExecutable(bundle))
+	{
+		CFRelease(bundle);
+		return SCARD_F_UNKNOWN_ERROR;
+	} else
+	{
+	}
+
+	*pvLHandle = (void *) bundle;
+
+	return SCARD_S_SUCCESS;
+}
+
+int DYN_CloseLibrary(void **pvLHandle)
+{
+
+	CFBundleRef bundle = (CFBundleRef) * pvLHandle;
+
+	if (CFBundleIsExecutableLoaded(bundle) == TRUE)
+	{
+		CFBundleUnloadExecutable(bundle);
+		CFRelease(bundle);
+	} else
+	{
+		DebugLogA("DYN_CloseLibrary: Cannot unload library.");
+	}
+
+	*pvLHandle = 0;
+	return SCARD_S_SUCCESS;
+}
+
+int DYN_GetAddress(void *pvLHandle, void **pvFHandle, char *pcFunction)
+{
+
+	CFBundleRef bundle = (CFBundleRef) pvLHandle;
+	CFStringRef cfName = CFStringCreateWithCString(NULL, pcFunction,
+		kCFStringEncodingMacRoman);
+	if (cfName == NULL)
+		return SCARD_E_NO_MEMORY;
+
+	*pvFHandle = CFBundleGetFunctionPointerForName(bundle, cfName);
+	CFRelease(cfName);
+	if (*pvFHandle == NULL)
+		return SCARD_F_UNKNOWN_ERROR;
+
+	return SCARD_S_SUCCESS;
+}

Added: trunk/SmartCardServices/src/PCSC/eventhandler.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/eventhandler.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/eventhandler.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : eventhandler.c
+	    Package: pcsc lite
+            Author : David Corcoran
+            Date   : 3/13/00
+	    License: Copyright (C) 2000 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This keeps track of card insertion/removal events
+	    and updates ATR, protocol, and status information.
+
+********************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+
+#include "config.h"
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "thread_generic.h"
+#include "readerfactory.h"
+#include "eventhandler.h"
+#include "dyn_generic.h"
+#include "sys_generic.h"
+#include "ifdhandler.h"
+#include "ifdwrapper.h"
+#include "debuglog.h"
+#include "prothandler.h"
+
+#include <security_utilities/debugging.h>
+
+static PREADER_STATES readerStates[PCSCLITE_MAX_CONTEXTS];
+
+void EHStatusHandlerThread(PREADER_CONTEXT);
+
+LONG EHInitializeEventStructures()
+{
+
+	int fd, i, pageSize;
+
+	fd = 0;
+	i = 0;
+	pageSize = 0;
+
+	SYS_RemoveFile(PCSCLITE_PUBSHM_FILE);
+
+	fd = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDWR | O_CREAT, 00644);
+	if (fd < 0)
+	{
+		DebugLogA("Error: Cannot open public shared file");
+		exit(1);
+	}
+
+	SYS_Chmod(PCSCLITE_PUBSHM_FILE,
+		S_IRGRP | S_IREAD | S_IWRITE | S_IROTH);
+
+	pageSize = SYS_GetPageSize();
+
+	/*
+	 * Jump to end of file space and allocate zero's 
+	 */
+	SYS_SeekFile(fd, pageSize * PCSCLITE_MAX_CONTEXTS);
+	SYS_WriteFile(fd, "", 1);
+
+	/*
+	 * Allocate each reader structure 
+	 */
+	for (i = 0; i < PCSCLITE_MAX_CONTEXTS; i++)
+	{
+		readerStates[i] = (PREADER_STATES)
+			SYS_MemoryMap(sizeof(READER_STATES), fd, (i * pageSize));
+		if (readerStates[i] == 0)
+		{
+			DebugLogA("Error: Cannot public memory map");
+			exit(1);
+		}
+
+		/*
+		 * Zero out each value in the struct 
+		 */
+		memset((readerStates[i])->readerName, 0, MAX_READERNAME);
+		memset((readerStates[i])->cardAtr, 0, MAX_ATR_SIZE);
+		(readerStates[i])->readerID = 0;
+		(readerStates[i])->readerState = 0;
+		(readerStates[i])->lockState = 0;
+		(readerStates[i])->readerSharing = 0;
+		(readerStates[i])->cardAtrLength = 0;
+		(readerStates[i])->cardProtocol = 0;
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG EHDestroyEventHandler(PREADER_CONTEXT rContext)
+{
+
+	LONG rv;
+	int i;
+
+	i = 0;
+	rv = 0;
+        
+        
+	i = rContext->dwPublicID;
+        if ((readerStates[i])->readerName[0] == 0)
+        {
+                DebugLogA("EHDestroyEventHandler: Thread already stomped.");
+                return SCARD_S_SUCCESS;
+        }
+
+	/*
+	 * Set the thread to 0 to exit thread 
+	 */
+	rContext->dwLockId = 0xFFFF;
+
+	DebugLogA("EHDestroyEventHandler: Stomping thread.");
+
+	do
+	{
+		/*
+		 * Wait 0.05 seconds for the child to respond 
+		 */
+		SYS_USleep(50000);
+	}
+	while (rContext->dwLockId == 0xFFFF);
+
+	/*
+	 * Zero out the public status struct to allow it to be recycled and
+	 * used again 
+	 */
+
+	memset((readerStates[i])->readerName, 0, MAX_READERNAME);
+	memset((readerStates[i])->cardAtr, 0, MAX_ATR_SIZE);
+	(readerStates[i])->readerID = 0;
+	(readerStates[i])->readerState = 0;
+	(readerStates[i])->lockState = 0;
+	(readerStates[i])->readerSharing = 0;
+	(readerStates[i])->cardAtrLength = 0;
+	(readerStates[i])->cardProtocol = 0;
+
+	SYS_MMapSynchronize((void *) readerStates[i], SYS_GetPageSize());
+
+	/* Zero the thread */
+	rContext->pthThread = 0;
+
+	DebugLogA("EHDestroyEventHandler: Thread stomped.");
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG EHSpawnEventHandler(PREADER_CONTEXT rContext)
+{
+	LONG rv;
+	LPCSTR lpcReader;
+	DWORD dwStatus, dwProtocol;
+	int i;
+
+	/*
+	 * Zero out everything 
+	 */
+	rv = 0;
+	lpcReader = 0;
+	dwStatus = 0;
+	dwProtocol = 0;
+	i = 0;
+
+	lpcReader = rContext->lpcReader;
+
+	rv = IFDStatusICC(rContext, &dwStatus,
+		&dwProtocol, rContext->ucAtr, &rContext->dwAtrLen);
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		DebugLogB("EHSpawnEventHandler: Initial Check Failed on %s",
+			lpcReader);
+		return SCARD_F_UNKNOWN_ERROR;
+	}
+
+	/*
+	 * Find an empty reader slot and insert the new reader 
+	 */
+	for (i = 0; i < PCSCLITE_MAX_CONTEXTS; i++)
+	{
+		if ((readerStates[i])->readerID == 0)
+		{
+			break;
+		}
+	}
+
+	if (i == PCSCLITE_MAX_CONTEXTS)
+	{
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	/*
+	 * Set all the attributes to this reader 
+	 */
+	strcpy((readerStates[i])->readerName, rContext->lpcReader);
+	memcpy((readerStates[i])->cardAtr, rContext->ucAtr,
+		rContext->dwAtrLen);
+	(readerStates[i])->readerID = htonl(i + 100);
+	(readerStates[i])->readerState = htonl(rContext->dwStatus);
+	(readerStates[i])->readerSharing = htonl(rContext->dwContexts);
+	(readerStates[i])->cardAtrLength = htonl(rContext->dwAtrLen);
+	(readerStates[i])->cardProtocol = htonl(rContext->dwProtocol);
+	/*
+	 * So the thread can access this array indice 
+	 */
+	rContext->dwPublicID = i;
+
+	rv = SYS_ThreadCreate(&rContext->pthThread, NULL,
+		(LPVOID) EHStatusHandlerThread, (LPVOID) rContext);
+	secdebug("pcscd", "EHSpawnEventHandler after thread create: %d [%04X]", rv, rv);
+	if (rv == 1)
+	{
+		return SCARD_S_SUCCESS;
+	} else
+	{
+		return SCARD_E_NO_MEMORY;
+	}
+
+}
+
+void EHStatusHandlerThread(PREADER_CONTEXT rContext)
+{
+
+	LONG rv;
+	LPCSTR lpcReader;
+	DWORD dwStatus, dwProtocol, dwReaderSharing;
+	DWORD dwErrorCount, dwCurrentState;
+	int i, pageSize;
+
+	/*
+	 * Zero out everything 
+	 */
+	rv = 0;
+	lpcReader = 0;
+	dwStatus = 0;
+	dwProtocol = 0;
+	dwReaderSharing = 0;
+	dwCurrentState = 0;
+	dwErrorCount = 0;
+	i = 0;
+	pageSize = 0;
+
+	lpcReader = rContext->lpcReader;
+	i = rContext->dwPublicID;
+
+	pageSize = SYS_GetPageSize();
+
+	rv = IFDStatusICC(rContext, &dwStatus,
+		&dwProtocol, rContext->ucAtr, &rContext->dwAtrLen);
+	secdebug("pcscd", "EHStatusHandlerThread: initial call to IFDStatusICC: %d [%04X]", rv, rv);
+
+	if (dwStatus & SCARD_PRESENT)
+	{
+		rv = IFDPowerICC(rContext, IFD_POWER_UP,
+			rContext->ucAtr, &rContext->dwAtrLen);
+		secdebug("pcscd", "EHStatusHandlerThread: initial call to IFDPowerICC: %d [%04X]", rv, rv);
+
+		if (rv == IFD_SUCCESS)
+		{
+			rContext->dwProtocol = PHGetDefaultProtocol(rContext->ucAtr,
+				rContext->dwAtrLen);
+			rContext->dwStatus |= SCARD_PRESENT;
+			rContext->dwStatus &= ~SCARD_ABSENT;
+			rContext->dwStatus |= SCARD_POWERED;
+			rContext->dwStatus |= SCARD_NEGOTIABLE;
+			rContext->dwStatus &= ~SCARD_SPECIFIC;
+			rContext->dwStatus &= ~SCARD_SWALLOWED;
+			rContext->dwStatus &= ~SCARD_UNKNOWN;
+		} else
+		{
+			rContext->dwStatus |= SCARD_PRESENT;
+			rContext->dwStatus &= ~SCARD_ABSENT;
+			rContext->dwStatus |= SCARD_SWALLOWED;
+			rContext->dwStatus &= ~SCARD_POWERED;
+			rContext->dwStatus &= ~SCARD_NEGOTIABLE;
+			rContext->dwStatus &= ~SCARD_SPECIFIC;
+			rContext->dwStatus &= ~SCARD_UNKNOWN;
+			rContext->dwProtocol = 0;
+			rContext->dwAtrLen = 0;
+		}
+
+		dwCurrentState = SCARD_PRESENT;
+
+	} else
+	{
+		dwCurrentState = SCARD_ABSENT;
+		rContext->dwStatus |= SCARD_ABSENT;
+		rContext->dwStatus &= ~SCARD_PRESENT;
+		rContext->dwStatus &= ~SCARD_POWERED;
+		rContext->dwStatus &= ~SCARD_NEGOTIABLE;
+		rContext->dwStatus &= ~SCARD_SPECIFIC;
+		rContext->dwStatus &= ~SCARD_SWALLOWED;
+		rContext->dwStatus &= ~SCARD_UNKNOWN;
+		rContext->dwAtrLen = 0;
+		rContext->dwProtocol = 0;
+	}
+
+	/*
+	 * Set all the public attributes to this reader 
+	 */
+	(readerStates[i])->readerState = htonl(rContext->dwStatus);
+	(readerStates[i])->cardAtrLength = htonl(rContext->dwAtrLen);
+	(readerStates[i])->cardProtocol = htonl(rContext->dwProtocol);
+	dwReaderSharing = rContext->dwContexts;
+	(readerStates[i])->readerSharing = htonl(dwReaderSharing);	
+	memcpy((readerStates[i])->cardAtr, rContext->ucAtr,
+		rContext->dwAtrLen);
+
+	SYS_MMapSynchronize((void *) readerStates[i], pageSize);
+
+	while (1)
+	{
+
+		dwStatus = 0;
+
+		rv = IFDStatusICC(rContext, &dwStatus,
+			&dwProtocol, rContext->ucAtr, &rContext->dwAtrLen);
+//		secdebug("pcscd", "EHStatusHandlerThread: loop call to IFDStatusICC: %d [%04X]", rv, rv);
+
+		if (rv != SCARD_S_SUCCESS)
+		{
+			DebugLogB("EHSpawnEventHandler: Error communicating to: %s",
+				lpcReader);
+
+			/*
+			 * Set error status on this reader while errors occur 
+			 */
+
+			rContext->dwStatus &= ~SCARD_ABSENT;
+			rContext->dwStatus &= ~SCARD_PRESENT;
+			rContext->dwStatus &= ~SCARD_POWERED;
+			rContext->dwStatus &= ~SCARD_NEGOTIABLE;
+			rContext->dwStatus &= ~SCARD_SPECIFIC;
+			rContext->dwStatus &= ~SCARD_SWALLOWED;
+			rContext->dwStatus |= SCARD_UNKNOWN;
+			rContext->dwAtrLen = 0;
+			rContext->dwProtocol = 0;
+
+			dwCurrentState = SCARD_UNKNOWN;
+
+			/*
+			 * Set all the public attributes to this reader 
+			 */
+			(readerStates[i])->readerState = htonl(rContext->dwStatus);
+			(readerStates[i])->cardAtrLength = htonl(rContext->dwAtrLen);
+			(readerStates[i])->cardProtocol = htonl(rContext->dwProtocol);
+			memcpy((readerStates[i])->cardAtr, rContext->ucAtr,
+				rContext->dwAtrLen);
+			SYS_MMapSynchronize((void *) readerStates[i], pageSize);
+
+			/*
+			 * This code causes race conditions on G4's with USB
+			 * insertion 
+			 */
+			/*
+			 * dwErrorCount += 1; SYS_Sleep(1); 
+			 */
+			/*
+			 * After 10 seconds of errors, try to reinitialize the reader
+			 * This sometimes helps bring readers out of *crazy* states. 
+			 */
+			/*
+			 * if ( dwErrorCount == 10 ) { RFUnInitializeReader( rContext
+			 * ); RFInitializeReader( rContext ); dwErrorCount = 0; } 
+			 */
+
+			/*
+			 * End of race condition code block 
+			 */
+
+		}
+
+		if (dwStatus & SCARD_ABSENT)
+		{
+			if (dwCurrentState == SCARD_PRESENT ||
+				dwCurrentState == SCARD_UNKNOWN)
+			{
+
+				/*
+				 * Change the status structure 
+				 */
+				DebugLogB("EHSpawnEventHandler: Card Removed From %s",
+					lpcReader);
+				/*
+				 * Notify the card has been removed 
+				 */
+				RFSetReaderEventState(rContext, SCARD_REMOVED);
+
+				rContext->dwAtrLen = 0;
+				rContext->dwProtocol = 0;
+				rContext->dwStatus |= SCARD_ABSENT;
+				rContext->dwStatus &= ~SCARD_UNKNOWN;
+				rContext->dwStatus &= ~SCARD_PRESENT;
+				rContext->dwStatus &= ~SCARD_POWERED;
+				rContext->dwStatus &= ~SCARD_NEGOTIABLE;
+				rContext->dwStatus &= ~SCARD_SWALLOWED;
+				rContext->dwStatus &= ~SCARD_SPECIFIC;
+				dwCurrentState = SCARD_ABSENT;
+
+				/*
+				 * Set all the public attributes to this reader 
+				 */
+				(readerStates[i])->readerState = htonl(rContext->dwStatus);
+				(readerStates[i])->cardAtrLength = htonl(rContext->dwAtrLen);
+				(readerStates[i])->cardProtocol = htonl(rContext->dwProtocol);
+				memcpy((readerStates[i])->cardAtr, rContext->ucAtr,
+					rContext->dwAtrLen);
+
+				SYS_MMapSynchronize((void *) readerStates[i], pageSize);
+			}
+
+		} else if (dwStatus & SCARD_PRESENT)
+		{
+			if (dwCurrentState == SCARD_ABSENT ||
+				dwCurrentState == SCARD_UNKNOWN)
+			{
+
+				/*
+				 * Power and reset the card 
+				 */
+				SYS_USleep(PCSCLITE_STATUS_WAIT);
+				rv = IFDPowerICC(rContext, IFD_POWER_UP,
+					rContext->ucAtr, &rContext->dwAtrLen);
+				secdebug("pcscd", "EHStatusHandlerThread: power-and-reset call to IFDPowerICC: %d [%04X]", rv, rv);
+
+				if (rv == IFD_SUCCESS)
+				{
+					rContext->dwProtocol =
+						PHGetDefaultProtocol(rContext->ucAtr,
+						rContext->dwAtrLen);
+					rContext->dwStatus |= SCARD_PRESENT;
+					rContext->dwStatus &= ~SCARD_ABSENT;
+					rContext->dwStatus |= SCARD_POWERED;
+					rContext->dwStatus |= SCARD_NEGOTIABLE;
+					rContext->dwStatus &= ~SCARD_SPECIFIC;
+					rContext->dwStatus &= ~SCARD_UNKNOWN;
+					rContext->dwStatus &= ~SCARD_SWALLOWED;
+
+					/*
+					 * Notify the card has been reset 
+					 */
+					/*
+					 * RFSetReaderEventState( rContext, SCARD_RESET ); 
+					 */
+				} else
+				{
+					rContext->dwStatus |= SCARD_PRESENT;
+					rContext->dwStatus &= ~SCARD_ABSENT;
+					rContext->dwStatus |= SCARD_SWALLOWED;
+					rContext->dwStatus &= ~SCARD_POWERED;
+					rContext->dwStatus &= ~SCARD_NEGOTIABLE;
+					rContext->dwStatus &= ~SCARD_SPECIFIC;
+					rContext->dwStatus &= ~SCARD_UNKNOWN;
+					rContext->dwAtrLen = 0;
+					rContext->dwProtocol = 0;
+				}
+
+				dwCurrentState = SCARD_PRESENT;
+
+				/*
+				 * Set all the public attributes to this reader 
+				 */
+				(readerStates[i])->readerState = htonl(rContext->dwStatus);
+				(readerStates[i])->cardAtrLength = htonl(rContext->dwAtrLen);
+				(readerStates[i])->cardProtocol = htonl(rContext->dwProtocol);
+				memcpy((readerStates[i])->cardAtr, rContext->ucAtr,
+					rContext->dwAtrLen);
+
+				SYS_MMapSynchronize((void *) readerStates[i], pageSize);
+
+				DebugLogB("EHSpawnEventHandler: Card inserted into %s",
+					lpcReader);
+
+				if (rv == IFD_SUCCESS)
+				{
+					if (rContext->dwAtrLen > 0)
+					{
+						DebugXxd("EHSpawnEventHandler: Card ATR: ",
+							rContext->ucAtr, rContext->dwAtrLen);
+					} else
+					{
+						DebugLogA("EHSpawnEventHandler: Card ATR: (NULL)");
+					}
+
+				} else
+				{
+					DebugLogA
+						("EHSpawnEventHandler: Error powering up card.");
+				}
+			}
+		}
+
+		if (rContext->dwLockId == 0xFFFF)
+		{
+			/*
+			 * Exit and notify the caller 
+			 */
+				secdebug("pcscd", "EHStatusHandlerThread: lockid is -1?? - exiting");
+			rContext->dwLockId = 0;
+			SYS_ThreadDetach(rContext->pthThread);
+			SYS_ThreadExit(0);
+		}
+
+		/*
+		 * Sharing may change w/o an event pass it on 
+		 */
+
+		if (dwReaderSharing != rContext->dwContexts)
+		{
+			dwReaderSharing = rContext->dwContexts;
+			(readerStates[i])->readerSharing = htonl(dwReaderSharing);
+			SYS_MMapSynchronize((void *) readerStates[i], pageSize);
+		}
+
+		SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
+	}
+}
+
+void EHSetSharingEvent(PREADER_CONTEXT rContext, DWORD dwValue)
+{
+
+	(readerStates[rContext->dwPublicID])->lockState = htonl(dwValue);
+
+}

Added: trunk/SmartCardServices/src/PCSC/eventhandler.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/eventhandler.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/eventhandler.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,533 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  eventhandler.cpp
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2000
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 2004
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: eventhandler.c 2377 2007-02-05 13:13:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This keeps track of card insertion/removal events
+ * and updates ATR, protocol, and status information.
+ */
+
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "ifdhandler.h"
+#include "debuglog.h"
+#include "thread_generic.h"
+#include "readerfactory.h"
+#include "eventhandler.h"
+#include "dyn_generic.h"
+#include "sys_generic.h"
+#include "ifdwrapper.h"
+#include "prothandler.h"
+#include "readerstate.h"
+
+#include <security_utilities/debugging.h>
+
+static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
+
+void EHStatusHandlerThread(PREADER_CONTEXT);
+
+LONG EHInitializeEventStructures(void)
+{
+	int fd, i, pageSize;
+
+	fd = 0;
+	i = 0;
+	pageSize = 0;
+
+	/*
+		Do not truncate to avoid possible SIGSEG on clients
+		Do not remove the file to allow long-term clients such as securityd to 
+			stay connected to the same file
+	*/
+	fd = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDWR | O_CREAT , 00644);
+	if (fd < 0)
+	{
+		Log3(PCSC_LOG_CRITICAL, "Cannot create public shared file %s: %s",
+			PCSCLITE_PUBSHM_FILE, strerror(errno));
+		exit(1);
+	}
+
+	SYS_Chmod(PCSCLITE_PUBSHM_FILE,
+		S_IRGRP | S_IREAD | S_IWRITE | S_IROTH);
+
+	pageSize = SYS_GetPageSize();
+
+	int rx = ftruncate(fd, pageSize * PCSCLITE_MAX_READERS_CONTEXTS);
+	if (rx)
+		Log3(PCSC_LOG_CRITICAL, "Cannot truncate public shared file %d: %s",
+				errno, strerror(errno));
+	/*
+	 * Jump to end of file space and allocate zero's
+	 */
+	SYS_SeekFile(fd, pageSize * PCSCLITE_MAX_READERS_CONTEXTS);
+	SYS_WriteFile(fd, "", 1);
+
+	/*
+	 * Allocate each reader structure
+	 */
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		readerStates[i] = (PREADER_STATE)
+			SYS_MemoryMap(sizeof(READER_STATE), fd, (i * pageSize));
+		if (readerStates[i] == MAP_FAILED)
+		{
+			Log3(PCSC_LOG_CRITICAL, "Cannot memory map public shared file %s: %s",
+				PCSCLITE_PUBSHM_FILE, strerror(errno));
+			exit(1);
+		}
+
+		/*
+		 * Zero out each value in the struct
+		 */
+		memset((readerStates[i])->readerName, 0, MAX_READERNAME);
+		memset((readerStates[i])->cardAtr, 0, MAX_ATR_SIZE);
+		(readerStates[i])->readerID = 0;
+		(readerStates[i])->readerState = 0;
+		(readerStates[i])->lockState = 0;
+		(readerStates[i])->readerSharing = 0;
+		(readerStates[i])->cardAtrLength = 0;
+		(readerStates[i])->cardProtocol = SCARD_PROTOCOL_UNSET;	// ok since this is 0
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG EHDestroyEventHandler(PREADER_CONTEXT rContext)
+{
+	if (NULL == rContext->readerState)
+	{
+		Log1(PCSC_LOG_ERROR, "Thread never started (reader init failed?)");
+		return SCARD_S_SUCCESS;
+	}
+
+	PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(rContext->readerState);
+	if ((rContext->pthThread == 0) || !rs || (rs->readerNameLength() == 0))
+	{
+		Log1(PCSC_LOG_INFO, "Thread already stomped.");
+		return SCARD_S_SUCCESS;
+	}
+
+	secdebug("pcscd", "EHDestroyEventHandler: pthThread: %p, reader name len: %ld",
+		rContext->pthThread, rs->readerNameLength());
+
+	/*
+	 * Zero out the public status struct to allow it to be recycled and
+	 * used again
+	 */
+
+	rs->xreaderNameClear();
+	rs->xcardAtrClear();
+	rs->xreaderID(0);
+	rs->xreaderState(0);
+	rs->xlockState(0);
+	rs->sharing(0);
+	rs->xcardAtrLength(0);
+	rs->xcardProtocol(SCARD_PROTOCOL_UNSET);		// we only set this one to write to memory cache
+
+	/*
+	 * Set the thread to 0 to exit thread
+	 */
+	ReaderContextLock(rContext);
+
+	Log1(PCSC_LOG_INFO, "Stomping thread.");
+
+	int ix;
+	for (ix = 0; (ix < 100) && ReaderContextIsLocked(rContext); ++ix)
+	{
+		/*
+		 * Wait 0.05 seconds for the child to respond
+		 */
+		SYS_USleep(50000);
+	}
+
+	secdebug("pcscd", "EHDestroyEventHandler: post-stop dwLockId: %d", rContext->dwLockId);
+
+
+	/* Zero the thread */
+	rContext->pthThread = 0;
+
+	Log1(PCSC_LOG_INFO, "Thread stomped.");
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG EHSpawnEventHandler(PREADER_CONTEXT rContext)
+{
+	LONG rv;
+	DWORD dwStatus = 0;
+	int i;
+	UCHAR ucAtr[MAX_ATR_SIZE];
+	DWORD dwAtrLen = 0;
+
+	secdebug("pcscd", "EHSpawnEventHandler: rContext: 0x%08X", rContext);
+	rv = IFDStatusICC(rContext, &dwStatus, ucAtr, &dwAtrLen);
+	if (rv != SCARD_S_SUCCESS)
+	{
+		Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s", rContext->lpcReader);
+		return SCARD_F_UNKNOWN_ERROR;
+	}
+
+	/*
+	 * Find an empty reader slot and insert the new reader
+	 */
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		PCSCD::SharedReaderState *rstmp = PCSCD::SharedReaderState::overlay(readerStates[i]);
+		if (rstmp->xreaderID() == 0)
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+		return SCARD_F_INTERNAL_ERROR;
+
+	/*
+	 * Set all the attributes to this reader
+	 */
+	PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(readerStates[i]);
+	rContext->readerState = readerStates[i];
+	rs->xreaderName(rContext->lpcReader);
+	rs->xcardAtr(ucAtr, dwAtrLen);	// also sets cardAtrLength
+
+	rs->xreaderID(i + 100);
+	rs->xreaderState(dwStatus);
+	rs->sharing(rContext->dwContexts);
+	rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
+	
+	rv = SYS_ThreadCreate(&rContext->pthThread, THREAD_ATTR_DETACHED,
+		(PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
+	secdebug("pcscd", "EHSpawnEventHandler after thread create: %d [%04X]", rv, rv);
+	if (rv == 1)
+		return SCARD_S_SUCCESS;
+	else
+		return SCARD_E_NO_MEMORY;
+}
+
+void EHStatusHandlerThread(PREADER_CONTEXT rContext)
+{
+	LONG rv;
+	LPCSTR lpcReader;
+	DWORD dwStatus, dwReaderSharing;
+	DWORD dwCurrentState;
+	int pageSize = SYS_GetPageSize();
+
+	/*
+	 * Zero out everything
+	 */
+	dwStatus = 0;
+	dwReaderSharing = 0;
+	dwCurrentState = 0;
+
+	secdebug("pcscd", "EHStatusHandlerThread: rContext: 0x%08X", rContext);
+	lpcReader = rContext->lpcReader;
+
+	PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(rContext->readerState);
+
+	DWORD tmpCardAtrLength = MAX_ATR_SIZE;
+	rv = IFDStatusICC(rContext, &dwStatus, rs->xcardAtr(), &tmpCardAtrLength);
+	secdebug("pcscd", "EHStatusHandlerThread: initial call to IFDStatusICC: %d [%04X]", rv, rv);
+
+	if (dwStatus & SCARD_PRESENT)
+	{
+		tmpCardAtrLength = MAX_ATR_SIZE;
+		rv = IFDPowerICC(rContext, IFD_POWER_UP, rs->xcardAtr(), &tmpCardAtrLength);
+
+		/* the protocol is unset after a power on */
+		rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
+
+		secdebug("pcscd", "EHStatusHandlerThread: initial call to IFDPowerICC: %d [%04X]", rv, rv);
+
+		if (rv == IFD_SUCCESS)
+		{
+			rs->xcardAtrLength(tmpCardAtrLength);
+
+			dwStatus |= SCARD_PRESENT;
+			dwStatus &= ~SCARD_ABSENT;
+			dwStatus |= SCARD_POWERED;
+			dwStatus |= SCARD_NEGOTIABLE;
+			dwStatus &= ~SCARD_SPECIFIC;
+			dwStatus &= ~SCARD_SWALLOWED;
+			dwStatus &= ~SCARD_UNKNOWN;
+
+			if (rs->xcardAtrLength() > 0)
+			{
+				LogXxd(PCSC_LOG_INFO, "Card ATR: ",
+					rs->xcardAtr(),
+					rs->xcardAtrLength());
+			}
+			else
+				Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
+		}
+		else
+		{
+			dwStatus |= SCARD_PRESENT;
+			dwStatus &= ~SCARD_ABSENT;
+			dwStatus |= SCARD_SWALLOWED;
+			dwStatus &= ~SCARD_POWERED;
+			dwStatus &= ~SCARD_NEGOTIABLE;
+			dwStatus &= ~SCARD_SPECIFIC;
+			dwStatus &= ~SCARD_UNKNOWN;
+			Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
+		}
+
+		dwCurrentState = SCARD_PRESENT;
+	}
+	else
+	{
+		dwStatus |= SCARD_ABSENT;
+		dwStatus &= ~SCARD_PRESENT;
+		dwStatus &= ~SCARD_POWERED;
+		dwStatus &= ~SCARD_NEGOTIABLE;
+		dwStatus &= ~SCARD_SPECIFIC;
+		dwStatus &= ~SCARD_SWALLOWED;
+		dwStatus &= ~SCARD_UNKNOWN;
+		rs->xcardAtrLength(0);
+		rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
+
+		dwCurrentState = SCARD_ABSENT;
+	}
+
+	/*
+	 * Set all the public attributes to this reader
+	 */
+	rs->xreaderState(dwStatus);
+	dwReaderSharing = rContext->dwContexts;
+	rs->sharing(dwReaderSharing);
+
+	SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
+
+	while (1)
+	{
+		dwStatus = 0;
+
+		// Defensive measure
+		if (!rContext->vHandle)
+		{
+			// Exit and notify the caller
+			secdebug("pcscd", "EHStatusHandlerThread: lost dynamic callbacks ??");
+			ReaderContextUnlock(rContext);
+			SYS_ThreadDetach(rContext->pthThread);
+			SYS_ThreadExit(0);
+		}
+
+		DWORD tmpCardAtrLength = MAX_ATR_SIZE;
+		rv = IFDStatusICC(rContext, &dwStatus, rs->xcardAtr(), &tmpCardAtrLength);
+
+		if (rv != SCARD_S_SUCCESS)
+		{
+			Log2(PCSC_LOG_ERROR, "Error communicating to: %s", lpcReader);
+
+			/*
+			 * Set error status on this reader while errors occur
+			 */
+
+			DWORD readerStateTmp = rs->xreaderState();
+			readerStateTmp &= ~SCARD_ABSENT;
+			readerStateTmp &= ~SCARD_PRESENT;
+			readerStateTmp &= ~SCARD_POWERED;
+			readerStateTmp &= ~SCARD_NEGOTIABLE;
+			readerStateTmp &= ~SCARD_SPECIFIC;
+			readerStateTmp &= ~SCARD_SWALLOWED;
+			readerStateTmp |= SCARD_UNKNOWN;
+			rs->xcardAtrLength(0);
+			rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
+			rs->xreaderState(readerStateTmp);
+
+			dwCurrentState = SCARD_UNKNOWN;
+
+			SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
+
+			/*
+			 * This code causes race conditions on G4's with USB
+			 * insertion
+			 */
+			/*
+			 * dwErrorCount += 1; SYS_Sleep(1);
+			 */
+			/*
+			 * After 10 seconds of errors, try to reinitialize the reader
+			 * This sometimes helps bring readers out of *crazy* states.
+			 */
+			/*
+			 * if ( dwErrorCount == 10 ) { RFUnInitializeReader( rContext
+			 * ); RFInitializeReader( rContext ); dwErrorCount = 0; }
+			 */
+
+			/*
+			 * End of race condition code block
+			 */
+		}
+
+		if (dwStatus & SCARD_ABSENT)
+		{
+			if (dwCurrentState == SCARD_PRESENT ||
+				dwCurrentState == SCARD_UNKNOWN)
+			{
+				/*
+				 * Change the status structure
+				 */
+				Log2(PCSC_LOG_INFO, "Card Removed From %s", lpcReader);
+				/*
+				 * Notify the card has been removed
+				 */
+				RFSetReaderEventState(rContext, SCARD_REMOVED);
+
+				rs->xcardAtrLength(0);
+				rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
+				DWORD readerStateTmp = rs->xreaderState();
+				readerStateTmp |= SCARD_ABSENT;
+				readerStateTmp &= ~SCARD_UNKNOWN;
+				readerStateTmp &= ~SCARD_PRESENT;
+				readerStateTmp &= ~SCARD_POWERED;
+				readerStateTmp &= ~SCARD_NEGOTIABLE;
+				readerStateTmp &= ~SCARD_SWALLOWED;
+				readerStateTmp &= ~SCARD_SPECIFIC;
+				rs->xreaderState(readerStateTmp);
+				dwCurrentState = SCARD_ABSENT;
+
+				SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
+			}
+
+		}
+		else if (dwStatus & SCARD_PRESENT)
+		{
+			if (dwCurrentState == SCARD_ABSENT ||
+				dwCurrentState == SCARD_UNKNOWN)
+			{
+				/*
+				 * Power and reset the card
+				 */
+				SYS_USleep(PCSCLITE_STATUS_WAIT);
+				DWORD tmpCardAtrLength = MAX_ATR_SIZE;
+				rv = IFDPowerICC(rContext, IFD_POWER_UP, rs->xcardAtr(), &tmpCardAtrLength);
+
+				/* the protocol is unset after a power on */
+				rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
+
+				secdebug("pcscd", "EHStatusHandlerThread: power-and-reset call to IFDPowerICC: %d [%04X]", rv, rv);
+
+				DWORD readerStateTmp = rs->xreaderState();
+				if (rv == IFD_SUCCESS)
+				{
+					rs->xcardAtrLength(tmpCardAtrLength);
+
+					readerStateTmp |= SCARD_PRESENT;
+					readerStateTmp &= ~SCARD_ABSENT;
+					readerStateTmp |= SCARD_POWERED;
+					readerStateTmp |= SCARD_NEGOTIABLE;
+					readerStateTmp &= ~SCARD_SPECIFIC;
+					readerStateTmp &= ~SCARD_UNKNOWN;
+					readerStateTmp &= ~SCARD_SWALLOWED;
+					rs->xreaderState(readerStateTmp);
+
+					/*
+					 * Notify the card has been reset
+					 */
+					RFSetReaderEventState(rContext, SCARD_RESET);
+				}
+				else
+				{
+					readerStateTmp |= SCARD_PRESENT;
+					readerStateTmp &= ~SCARD_ABSENT;
+					readerStateTmp |= SCARD_SWALLOWED;
+					readerStateTmp &= ~SCARD_POWERED;
+					readerStateTmp &= ~SCARD_NEGOTIABLE;
+					readerStateTmp &= ~SCARD_SPECIFIC;
+					readerStateTmp &= ~SCARD_UNKNOWN;
+					rs->xreaderState(readerStateTmp);
+					rs->xcardAtrLength(0);
+				}
+
+				dwCurrentState = SCARD_PRESENT;
+
+				SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
+
+				Log2(PCSC_LOG_INFO, "Card inserted into %s", lpcReader);
+
+				if (rv == IFD_SUCCESS)
+				{
+					if (rs->xcardAtrLength() > 0)
+						LogXxd(PCSC_LOG_INFO, "Card ATR: ", rs->xcardAtr(), rs->xcardAtrLength());
+					else
+						Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
+				}
+				else
+					Log1(PCSC_LOG_ERROR,"Error powering up card.");
+			}
+		}
+
+		if (ReaderContextIsLocked(rContext))
+		{
+			/*
+			 * Exit and notify the caller
+			 */
+			secdebug("pcscd", "EHStatusHandlerThread: parent requested shutdown");
+			ReaderContextUnlock(rContext);
+			SYS_ThreadDetach(rContext->pthThread);
+			SYS_ThreadExit(0);
+		}
+
+		/*
+		 * Sharing may change w/o an event pass it on
+		 */
+
+		if (dwReaderSharing != (uint32_t)rContext->dwContexts)
+		{
+			dwReaderSharing = rContext->dwContexts;
+			rs->sharing(dwReaderSharing);
+			SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
+		}
+
+		SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
+	}
+}
+
+void EHSetSharingEvent(PREADER_CONTEXT rContext, DWORD dwValue)
+{
+	PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(rContext->readerState);
+	rs->xlockState(dwValue);
+}

Added: trunk/SmartCardServices/src/PCSC/eventhandler.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/eventhandler.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/eventhandler.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,81 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  eventhandler.h
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 2004
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: eventhandler.h 2151 2006-09-06 20:02:47Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles card insertion/removal events, updates ATR,
+ * protocol, and status information.
+ */
+
+#ifndef __eventhandler_h__
+#define __eventhandler_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	/**
+	 * Define an exported public reader state structure so each
+	 * application gets instant notification of changes in state.
+	 */
+	typedef struct pubReaderStatesList
+	{
+		LONG readerID;
+		char readerName[MAX_READERNAME];
+		DWORD readerState;
+		LONG readerSharing;
+		DWORD lockState;
+
+		UCHAR cardAtr[MAX_ATR_SIZE];
+		DWORD cardAtrLength;
+		DWORD cardProtocol;
+	}
+	READER_STATE, *PREADER_STATE;
+
+	LONG EHInitializeEventStructures(void);
+	LONG EHSpawnEventHandler(PREADER_CONTEXT);
+	LONG EHDestroyEventHandler(PREADER_CONTEXT);
+	void EHSetSharingEvent(PREADER_CONTEXT, DWORD);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __eventhandler_h__ */

Added: trunk/SmartCardServices/src/PCSC/hotplug.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/hotplug.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/hotplug.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  hotplug.h
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2000-2003
+ *  David Corcoran <corcoran at linuxnet.com>
+ *
+ * $Id: hotplug.h 2310 2007-01-06 21:14:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This provides a search API for hot pluggble devices.
+ */
+
+#ifndef __hotplug_h__
+#define __hotplug_h__
+
+#include "pthread.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define PCSCLITE_HP_BASE_PORT		0x200000
+
+	LONG HPSearchHotPluggables();
+ 	LONG HPRegisterForHotplugEvents();
+	LONG HPStopHotPluggables(void);
+	void HPReCheckSerialReaders(void);
+	int SendHotplugSignal(void);
+        
+	LONG HPRegisterForHotplugEventsT(pthread_t *wthread);
+
+	void systemAwakeAndReadyCheck();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PCSC/hotplug_macosx.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/hotplug_macosx.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/hotplug_macosx.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : hotplug_macosx.c
+	    Package: pcsc lite
+      Author : Stephen M. Webb <stephenw at cryptocard.com>
+      Date   : 03 Dec 2002
+	    License: Copyright (C) 2002 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This provides a search API for hot pluggble
+	             devices.
+	            
+********************************************************************/
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "debuglog.h"
+#include "hotplug.h"
+#include "readerfactory.h"
+#include "thread_generic.h"
+
+#define PCSCLITE_HP_DROPDIR          "/usr/libexec/SmartCardServices/drivers/"
+#define PCSCLITE_HP_MANUKEY_NAME     "ifdVendorID"
+#define PCSCLITE_HP_PRODKEY_NAME     "ifdProductID"
+#define PCSCLITE_HP_NAMEKEY_NAME     "ifdFriendlyName"
+#define PCSCLITE_HP_IFACECLASSKEY_NAME    "ifdInterfaceClass"
+#define PCSCLITE_HP_IFACESUBCLASSKEY_NAME "ifdInterfaceSubClass"
+#define PCSCLITE_HP_IFACEPROTOCOLKEY_NAME "ifdInterfaceProtocol"
+#define PCSCLITE_HP_BASE_PORT       0x200000
+
+
+/*
+ * Defines the type of driver in the driver vector
+ */
+typedef enum 
+{
+    PCSCLITE_HP_Proprietary      = 0,
+    PCSCLITE_HP_InterfaceClass   = 1,
+    // * Could accomodate more types */
+} HPDriverType;
+
+
+
+/*
+ * An aggregation of useful information on a driver bundle in the
+ * drop directory.
+ */
+typedef struct HPDriver
+{
+    UInt8        m_NotEOV;           /* set to 1 for any driver before the end */
+    UInt8        m_initialized;      /* set to 1 on successful intialization */
+    HPDriverType m_type;             /* type of the driver in this element */
+    UInt32       m_vendorId;         /* unique vendor's manufacturer code */
+    UInt32       m_productId;        /* manufacturer's unique product code */
+    UInt8        m_class;            /* class of a non product specific driver */
+    UInt8        m_subClass;         /* subClass of a non product specific driver */
+    UInt8        m_protocol;         /* protocol of a non product specific driver */
+    char*        m_friendlyName;     /* bundle friendly name */
+    char*        m_libPath;          /* bundle's plugin library location */
+} HPDriver, *HPDriverVector;
+
+/*
+ * An aggregation on information on currently active reader drivers.
+ */
+typedef struct HPDevice
+{
+    HPDriver*         m_driver;   /* driver bundle information */
+    UInt32            m_address;  /* unique system address of device */
+    struct HPDevice*  m_next;     /* next device in list */
+} HPDevice, *HPDeviceList;
+
+/*
+ * Pointer to a list of (currently) known hotplug reader devices (and their
+                                                                  * drivers).
+ */
+static HPDeviceList				sDeviceList			= NULL;
+static IONotificationPortRef	sNotificationPort	= NULL;
+static io_iterator_t			sUSBAppearedIter	= NULL;
+static io_iterator_t			sUSBRemovedIter		= NULL;
+static io_iterator_t			sPCCardAppearedIter	= NULL;
+static io_iterator_t			sPCCardRemovedIter	= NULL;
+
+/*
+ * A callback to handle the asynchronous appearance of new devices that are
+ * candidates for PCSC readers.
+ */
+static void
+HPDeviceAppeared(void* refCon, io_iterator_t iterator)
+{
+    kern_return_t kret;
+    io_service_t  obj;
+    while ((obj = IOIteratorNext(iterator)))
+    {
+        kret = IOObjectRelease(obj);
+    }
+    
+    HPSearchHotPluggables();
+}
+
+/*
+ * A callback to handle the asynchronous disappearance of devices that are
+ * possibly PCSC readers.
+ */
+static void
+HPDeviceDisappeared(void* refCon, io_iterator_t iterator)
+{
+    kern_return_t kret;
+    io_service_t  obj;
+    while ((obj = IOIteratorNext(iterator)))
+    {
+        kret = IOObjectRelease(obj);
+    }
+    HPSearchHotPluggables();
+}
+
+
+/*
+ * Creates a vector of driver bundle info structures from the hot-plug driver
+ * directory.
+ *
+ * Returns NULL on error and a pointer to an allocated HPDriver vector on
+ * success.  The caller must free the HPDriver with a call to
+ * HPDriversRelease().
+ */
+static HPDriverVector
+HPDriversGetFromDirectory(const char* driverBundlePath)
+{
+    HPDriverVector bundleVector = NULL;
+    CFArrayRef bundleArray;
+    CFStringRef driverBundlePathString; 
+    driverBundlePathString = CFStringCreateWithCString(kCFAllocatorDefault,
+                                                       driverBundlePath,
+                                                       kCFStringEncodingMacRoman);
+    CFURLRef pluginUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
+                                                       driverBundlePathString,
+                                                       kCFURLPOSIXPathStyle, TRUE);
+    CFRelease(driverBundlePathString);
+    if (!pluginUrl)
+    {
+        DebugLogA("error getting plugin directory URL");
+        return bundleVector;
+    }
+    bundleArray = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault,
+                                                     pluginUrl,
+                                                     NULL);
+    if (!bundleArray)
+    {
+        DebugLogA("error getting plugin directory bundles");
+        return bundleVector;
+    }
+    CFRelease(pluginUrl);
+    
+    size_t bundleArraySize = CFArrayGetCount(bundleArray);
+    // bundleArraySize + 1 <- because the last vector element is 
+    // blank and is used to determine the length (m_NotEOV == 0)
+    bundleVector = (HPDriver*)calloc(bundleArraySize + 1, sizeof(HPDriver));
+    if (!bundleVector)
+    {
+        DebugLogA("memory allocation failure");
+        return bundleVector;
+    }
+    
+    int i = 0;
+    for (; i < bundleArraySize; ++i)
+    {
+        HPDriver* driverBundle = bundleVector + i;
+        // This is not the last 
+        driverBundle->m_NotEOV = 1;
+        CFBundleRef currBundle = (CFBundleRef)CFArrayGetValueAtIndex(bundleArray, i);
+        CFDictionaryRef dict   = CFBundleGetInfoDictionary(currBundle);
+        
+        CFURLRef bundleUrl      = CFBundleCopyBundleURL(currBundle);
+        CFStringRef bundlePath  = CFURLCopyPath(bundleUrl);
+        driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath,
+                                                               CFStringGetSystemEncoding()));
+        if (driverBundle->m_libPath == NULL)
+        {
+            DebugLogA("memory allocation failure");
+            return bundleVector;            
+        }
+        UInt32 vendorId     = 0;
+        UInt8  gotVendorId  = 0;
+        UInt32 productId    = 0;  
+        UInt8  gotProductId = 0;
+
+        CFStringRef strValue   = (CFStringRef)CFDictionaryGetValue(dict,
+                                                                   CFSTR(PCSCLITE_HP_MANUKEY_NAME));
+        if (strValue)
+        {
+            gotVendorId = 1;
+            vendorId = strtoul(CFStringGetCStringPtr(strValue,
+                                                     CFStringGetSystemEncoding()),
+                                                     NULL, 16);  
+
+            strValue = (CFStringRef)CFDictionaryGetValue(dict,
+                                                         CFSTR(PCSCLITE_HP_PRODKEY_NAME));
+            if (strValue)
+            {
+                gotProductId = 1;
+                productId = strtoul(CFStringGetCStringPtr(strValue,
+                                                          CFStringGetSystemEncoding()),
+                                                          NULL, 16);
+            }
+        }
+        if (gotVendorId && gotProductId)
+        {
+            /* This is a product-specific driver */
+            driverBundle->m_productId   = productId;
+            driverBundle->m_vendorId    = vendorId;
+            driverBundle->m_type        = PCSCLITE_HP_Proprietary;
+        }
+        else
+        {
+            /* If not a product-specific driver, it must be */
+            /* an interface class-specifc driver            */
+            UInt8 class;
+            UInt8 subClass;
+            UInt8 protocol;
+            
+            strValue = (CFStringRef)CFDictionaryGetValue(dict,
+                                                         CFSTR(PCSCLITE_HP_IFACECLASSKEY_NAME));
+            if (strValue)
+            {
+                class = (UInt8) strtoul(CFStringGetCStringPtr(strValue,
+                                                              CFStringGetSystemEncoding()),
+                                        NULL, 16);
+                driverBundle->m_class     = class;
+            } 
+            else
+            {
+                DebugLogB("Malformed bundle (class absent) in driver folder: %s. Will be ignored", 
+                          driverBundle->m_libPath);
+                free(driverBundle->m_libPath);
+                driverBundle->m_libPath = NULL;
+                continue;
+            }
+            strValue = (CFStringRef)CFDictionaryGetValue(dict,
+                                                         CFSTR(PCSCLITE_HP_IFACESUBCLASSKEY_NAME));
+            if (strValue)
+            {
+                subClass = (UInt8) strtoul(CFStringGetCStringPtr(strValue,
+                                                                 CFStringGetSystemEncoding()),
+                                           NULL, 16);
+                driverBundle->m_subClass  = subClass;
+            }
+            else
+            {
+                DebugLogB("Malformed bundle (subClass absent) in driver folder: %s. Will be ignored", 
+                          driverBundle->m_libPath);
+                free(driverBundle->m_libPath);
+                driverBundle->m_libPath = NULL;
+                continue;
+            }
+            strValue = (CFStringRef)CFDictionaryGetValue(dict,
+                                                         CFSTR(PCSCLITE_HP_IFACEPROTOCOLKEY_NAME));
+            if (strValue)
+            {
+                protocol = (UInt8) strtoul(CFStringGetCStringPtr(strValue,
+                                                                 CFStringGetSystemEncoding()),
+                                           NULL, 16);
+                driverBundle->m_protocol  = protocol;
+            }
+            else
+            {
+                DebugLogB("Malformed bundle (protocol absent) in driver folder: %s. Will be ignored", 
+                          driverBundle->m_libPath);
+                free(driverBundle->m_libPath);
+                driverBundle->m_libPath = NULL;
+                continue;
+            }
+            driverBundle->m_type = PCSCLITE_HP_InterfaceClass;
+        }
+        strValue = (CFStringRef)CFDictionaryGetValue(dict,
+                                                     CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
+        if (!strValue)
+        {
+            DebugLogB("Product friendly name absent in driver folder: %s.",
+				driverBundle->m_libPath);
+            driverBundle->m_friendlyName = strdup("unnamed device");
+        }
+        else
+        {
+            const char* cstr = CFStringGetCStringPtr(strValue,
+                                                     CFStringGetSystemEncoding());
+            driverBundle->m_friendlyName = strdup(cstr);
+        }
+        driverBundle->m_initialized = 1;
+    }
+    CFRelease(bundleArray);
+    return bundleVector;
+}
+
+/*
+ * Copies a driver bundle instance.
+ */
+static HPDriver*
+HPDriverCopy(HPDriver* rhs)
+{
+    if (!rhs)
+    {
+        return NULL;
+    }
+    HPDriver* newDriverBundle = (HPDriver*)calloc(1, sizeof(HPDriver));
+    if (!newDriverBundle)
+    {
+        return NULL;
+    }
+    
+    newDriverBundle->m_initialized  = rhs->m_initialized;
+    newDriverBundle->m_type         = rhs->m_type;
+    newDriverBundle->m_vendorId     = rhs->m_vendorId;
+    newDriverBundle->m_productId    = rhs->m_productId;
+    
+    newDriverBundle->m_class        = rhs->m_class;
+    newDriverBundle->m_subClass     = rhs->m_subClass;
+    newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName);
+    newDriverBundle->m_libPath      = strdup(rhs->m_libPath);
+    if (newDriverBundle->m_friendlyName == NULL)
+    {
+        if (newDriverBundle->m_libPath != NULL)
+        {
+            free(newDriverBundle->m_libPath);
+        }
+        free(newDriverBundle);
+        return NULL;
+    }
+        
+    if (newDriverBundle->m_libPath == NULL)
+    {
+        if (newDriverBundle->m_friendlyName != NULL)
+        {
+            free(newDriverBundle->m_friendlyName);
+        }
+        free(newDriverBundle);
+        return NULL;
+    }
+    return newDriverBundle;
+}
+
+/*
+ * Releases resources allocated to a driver bundle vector.
+ */
+static void
+HPDriverRelease(HPDriver* driverBundle)
+{
+    if (driverBundle)
+    {
+        free(driverBundle->m_friendlyName);
+        free(driverBundle->m_libPath);
+    }
+}
+
+/*
+ * Releases resources allocated to a driver bundle vector.
+ */
+static void
+HPDriverVectorRelease(HPDriverVector driverBundleVector)
+{
+    if (driverBundleVector)
+    {
+        HPDriver* b = driverBundleVector;
+        for (; b->m_initialized; ++b)
+        {
+            HPDriverRelease(b);
+        }
+        free(driverBundleVector);
+    }
+}
+
+/*
+ * Inserts a new reader device in the list.
+ */
+static HPDeviceList
+HPDeviceListInsert(HPDeviceList list, HPDriver* bundle, UInt32 address)
+{
+    HPDevice* newReader = (HPDevice*)calloc(1, sizeof(HPDevice));
+    if (!newReader)
+    {
+        DebugLogA("memory allocation failure");
+        return list;
+    }
+    newReader->m_driver  = HPDriverCopy(bundle);
+    newReader->m_address = address;
+    newReader->m_next    = list;
+    return newReader;
+}
+
+/*
+ * Frees resources allocated to a HPDeviceList.
+ */
+static void
+HPDeviceListRelease(HPDeviceList list)
+{
+    HPDevice* p = list;
+    for (; p; p = p->m_next)
+    {
+        HPDriverRelease(p->m_driver);
+    }
+}
+
+/*
+ * Compares two driver bundle instances for equality.
+ */
+static int
+HPDeviceEquals(HPDevice* a, HPDevice* b)
+{
+    int res;
+    if (a->m_driver->m_type == b->m_driver->m_type)
+    {
+        if (a->m_driver->m_type == PCSCLITE_HP_Proprietary)
+        {
+            // a and b have same vendor and product id
+            res = (a->m_driver->m_vendorId == b->m_driver->m_vendorId)
+                && (a->m_driver->m_productId == b->m_driver->m_productId);
+        }
+        else
+        {
+            // a and b have same class
+            res = (a->m_driver->m_subClass == b->m_driver->m_subClass)
+                && (a->m_driver->m_class == b->m_driver->m_class);
+        }
+        // AND have the same address
+        res = res && (a->m_address == b->m_address);
+        
+        return res;
+    }
+    return 0;
+}
+
+/*
+ * Finds USB devices currently registered in the system that match any of
+ * the drivers detected in the driver bundle vector.
+ */
+static int
+HPDriversMatchUSBDevices(HPDriverVector driverBundle, HPDeviceList* readerList)
+{
+    CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice");
+    if (0 == usbMatch)
+    {
+        DebugLogA("error getting USB match from IOServiceMatching()");
+        return 1;
+    }
+    
+    io_iterator_t usbIter;
+    kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault,
+                                                      usbMatch,
+                                                      &usbIter);
+    if (kret != 0)
+    {
+        DebugLogA("error getting iterator from IOServiceGetMatchingServices()");
+        return 1;
+    }
+    
+    io_object_t usbDevice = 0;
+    while ((usbDevice = IOIteratorNext(usbIter)))
+    {
+        IOCFPlugInInterface** iodev;
+        SInt32                score;
+        kret = IOCreatePlugInInterfaceForService(usbDevice,
+                                                 kIOUSBDeviceUserClientTypeID, 
+                                                 kIOCFPlugInInterfaceID,
+                                                 &iodev,
+                                                 &score);
+        IOObjectRelease(usbDevice);
+        if (kret != 0)
+        {
+            DebugLogA("error getting plugin interface from IOCreatePlugInInterfaceForService()");
+            continue;
+        }
+        
+        IOUSBDeviceInterface245** usbdev;
+        HRESULT hres = (*iodev)->QueryInterface(iodev,
+                                                CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245),
+                                                (LPVOID*)&usbdev);
+        if (hres)
+        {
+            DebugLogA("error querying interface in QueryInterface()");
+            IODestroyPlugInInterface ( iodev );
+            continue;
+        }
+        
+        else
+		{
+        
+			UInt16 vendorId  = 0;
+			UInt16 productId = 0;
+			UInt32 usbAddress = 0;
+			kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId);
+			kret = (*usbdev)->GetDeviceProduct(usbdev, &productId);
+			kret = (*usbdev)->GetLocationID(usbdev, &usbAddress);
+			
+			HPDriver* driver = driverBundle;
+			int match = 0;
+			for (; driver->m_NotEOV; ++driver)
+			{
+				if (!driver->m_initialized)
+				{
+					// Malformed driver, skip
+					continue;
+				}
+				if ( (driver->m_type == PCSCLITE_HP_Proprietary)
+					&& (driver->m_vendorId == vendorId)
+					&& (driver->m_productId == productId))
+				{
+					*readerList = HPDeviceListInsert(*readerList, driver, usbAddress);
+					match = 1;
+				}
+			}
+			if (!match)
+			{
+				// Now try to locate Interfaces with supported classes
+				// We create an interface iterator for each of the 
+				// classes supported by drivers of PCSCLITE_HP_InterfaceClass
+				// type.
+	
+				// Using IOServiceMatching(kIOUSBInterfaceClassName)
+				// does not seem feasible as there does not seem to be a 
+				// way to limit the search to the device we are currently 
+				// analysing
+	
+				// Another option would be to iterate on all interfaces
+				// and get the class of each of them. This is probably
+				// not interesting as the list of PCSCLITE_HP_InterfaceClass
+				// type of readers should only have one element (CCID)
+				
+				// Restart scan at the begining of the array
+				driver = driverBundle;     
+				// Iterate on PCSCLITE_HP_InterfaceClass driver types
+				for (; driver->m_NotEOV; ++driver)
+				{
+					if (!driver->m_initialized)
+					{
+						// Malformed driver, skip
+						continue;
+					}
+					if ( driver->m_type == PCSCLITE_HP_InterfaceClass)
+					{
+						// Iterate on interfaces of the current device
+						IOUSBFindInterfaceRequest interfaceClassRequest;
+						io_iterator_t			  interfaceIterator;
+						io_service_t			  interface;
+						
+						interfaceClassRequest.bInterfaceClass = driver->m_class;
+						interfaceClassRequest.bInterfaceSubClass = driver->m_subClass;	
+						interfaceClassRequest.bInterfaceProtocol = driver->m_protocol;	
+						interfaceClassRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+						hres = (*usbdev)->CreateInterfaceIterator(usbdev, 
+																  &interfaceClassRequest, 
+																  &interfaceIterator);
+						if (hres)
+						{
+							// Continue to next driver class
+							continue;
+						}
+						
+						while ( (interface = IOIteratorNext(interfaceIterator)) )
+						{
+							// Found a matching device
+							*readerList = HPDeviceListInsert(*readerList, driver, usbAddress);
+							match = 1;
+							IOObjectRelease ( interface );
+						}
+						
+						IOObjectRelease ( interfaceIterator );
+						
+					}
+				}
+				// Add another if (!match) for other driver types
+			}   
+			(*usbdev)->Release(usbdev);
+			IODestroyPlugInInterface ( iodev );
+		}
+    }
+    
+    IOObjectRelease(usbIter);
+    return 0;
+}
+
+/*
+ * Finds PC Card devices currently registered in the system that match any of
+ * the drivers detected in the driver bundle vector.
+ */
+static int
+HPDriversMatchPCCardDevices(HPDriver* driverBundle, HPDeviceList* readerList)
+{
+    CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device");
+    if (0 == pccMatch)
+    {
+        DebugLogA("error getting PCCard match from IOServiceMatching()");
+        return 1;
+    }
+    
+    io_iterator_t pccIter;
+    kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch, &pccIter);
+    if (kret != 0)
+    {
+        DebugLogA("error getting iterator from IOServiceGetMatchingServices()");
+        return 1;
+    }
+    
+    io_object_t pccDevice = 0;
+    while ((pccDevice = IOIteratorNext(pccIter)))
+    {
+        
+        UInt32 vendorId   = 0;
+        UInt32 productId  = 0;
+        UInt32 pccAddress = 0;
+        CFTypeRef valueRef = IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"),
+                                                             kCFAllocatorDefault, 0);
+        if (!valueRef)
+        {
+            DebugLogA("error getting vendor");
+        }
+        else
+        {
+            CFNumberGetValue((CFNumberRef)valueRef, kCFNumberSInt32Type, &vendorId);
+            CFRelease ( valueRef );
+        }
+        valueRef = IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"),
+                                                   kCFAllocatorDefault, 0);
+        if (!valueRef)
+        {
+            DebugLogA("error getting device");
+        }
+        else
+        {
+            CFNumberGetValue((CFNumberRef)valueRef, kCFNumberSInt32Type, &productId);
+            CFRelease ( valueRef );
+        }
+        valueRef = IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"),
+                                                   kCFAllocatorDefault, 0);
+        if (!valueRef)
+        {
+            DebugLogA("error getting PC Card socket");
+        }
+        else
+        {
+            CFNumberGetValue((CFNumberRef)valueRef, kCFNumberSInt32Type, &pccAddress);
+            CFRelease ( valueRef );
+        }
+        HPDriver* driver = driverBundle;
+        for (; driver->m_vendorId; ++driver)
+        {
+            if ((driver->m_vendorId == vendorId)
+                && (driver->m_productId == productId))
+            {
+                *readerList = HPDeviceListInsert(*readerList, driver, pccAddress);
+            }
+        }
+        
+        IOObjectRelease ( pccDevice );
+        
+    }
+    IOObjectRelease(pccIter);
+    return 0;
+}
+
+
+static void
+HPEstablishUSBNotification()
+{
+
+    CFMutableDictionaryRef  matchingDictionary;
+    IOReturn                kret;
+    
+    if ( sNotificationPort == NULL )
+		sNotificationPort = IONotificationPortCreate(kIOMasterPortDefault);
+	
+    CFRunLoopAddSource(CFRunLoopGetCurrent(),
+                       IONotificationPortGetRunLoopSource(sNotificationPort),
+                       kCFRunLoopDefaultMode);
+    
+    matchingDictionary = IOServiceMatching("IOUSBDevice");
+    if (!matchingDictionary)
+    {
+        DebugLogB("IOServiceMatching() failed", 0);
+    }
+    matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary);
+    
+    kret = IOServiceAddMatchingNotification(sNotificationPort,
+                                            kIOMatchedNotification,
+                                            matchingDictionary,
+                                            HPDeviceAppeared, NULL,
+                                            &sUSBAppearedIter);
+    if (kret)
+    {
+        DebugLogB("IOServiceAddMatchingNotification()-1 failed with code %d", kret);
+    }
+	
+    HPDeviceAppeared(NULL, sUSBAppearedIter);
+    
+    kret = IOServiceAddMatchingNotification(sNotificationPort,
+                                            kIOTerminatedNotification,
+                                            matchingDictionary,
+                                            HPDeviceDisappeared, NULL,
+                                            &sUSBRemovedIter);
+    if (kret)
+    {
+        DebugLogB("IOServiceAddMatchingNotification()-2 failed with code %d", kret);
+    }
+    HPDeviceDisappeared(NULL, sUSBRemovedIter);
+}
+
+static void
+HPEstablishPCCardNotification()
+{
+	
+	CFMutableDictionaryRef  matchingDictionary;
+    IOReturn                kret;
+
+	if ( sNotificationPort == NULL )
+		sNotificationPort = IONotificationPortCreate(kIOMasterPortDefault);
+	
+    CFRunLoopAddSource(CFRunLoopGetCurrent(),
+                       IONotificationPortGetRunLoopSource(sNotificationPort),
+                       kCFRunLoopDefaultMode);
+    
+    matchingDictionary = IOServiceMatching("IOPCCard16Device");
+    if (!matchingDictionary)
+    {
+        DebugLogB("IOServiceMatching() failed", 0);
+    }
+    matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary);
+    
+    kret = IOServiceAddMatchingNotification(sNotificationPort,
+                                            kIOMatchedNotification,
+                                            matchingDictionary,
+                                            HPDeviceAppeared, NULL,
+                                            &sPCCardAppearedIter);
+    if (kret)
+    {
+        DebugLogB("IOServiceAddMatchingNotification()-1 failed with code %d", kret);
+    }
+    HPDeviceAppeared(NULL, sPCCardAppearedIter);
+    
+    kret = IOServiceAddMatchingNotification(sNotificationPort,
+                                            kIOTerminatedNotification,
+                                            matchingDictionary,
+                                            HPDeviceDisappeared, NULL,
+                                            &sPCCardRemovedIter);
+    if (kret)
+    {
+        DebugLogB("IOServiceAddMatchingNotification()-2 failed with code %d", kret);
+    }
+    HPDeviceDisappeared(NULL, sPCCardRemovedIter);
+}
+
+/*
+ * Thread runner (does not return).
+ */
+static void
+HPDeviceNotificationThread()
+{
+    HPEstablishUSBNotification();
+    HPEstablishPCCardNotification();
+    CFRunLoopRun();
+}
+
+/*
+ * Scans the hotplug driver directory and looks in the system for matching devices.
+ * Adds or removes matching readers as necessary.
+ */
+LONG
+HPSearchHotPluggables()
+{
+    HPDriver* drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR);
+    if (!drivers) return 1;
+    
+    HPDeviceList devices = NULL;
+    int istat;
+    istat = HPDriversMatchUSBDevices(drivers, &devices);
+    if (istat)
+    {
+        return -1;
+    }
+    istat = HPDriversMatchPCCardDevices(drivers, &devices);
+    if (istat)
+    {
+        return -1;
+    }
+    
+    HPDevice* a = devices;
+    for (; a; a = a->m_next)
+    {
+        int found = 0;
+        HPDevice* b = sDeviceList;
+        for (; b; b = b->m_next)
+        {
+            if (HPDeviceEquals(a, b))
+            {
+                found = 1;
+                break;
+            }
+        }
+        if (!found)
+        {
+            RFAddReader(a->m_driver->m_friendlyName,
+                        PCSCLITE_HP_BASE_PORT + a->m_address,
+                        a->m_driver->m_libPath);
+        }
+    }
+    
+    a = sDeviceList;
+    for (; a; a = a->m_next)
+    {
+        int found = 0;
+        HPDevice* b = devices;
+        for (; b; b = b->m_next)
+        {
+            if (HPDeviceEquals(a, b))
+            {
+                found = 1;
+                break;
+            }
+        }
+        if (!found)
+        {
+            RFRemoveReader(a->m_driver->m_friendlyName,
+                           PCSCLITE_HP_BASE_PORT + a->m_address);
+        }
+    }
+    
+    HPDeviceListRelease(sDeviceList);
+    sDeviceList = devices;
+    HPDriverVectorRelease(drivers);
+    return 0;
+}
+
+
+PCSCLITE_THREAD_T sHotplugWatcherThread;
+
+/*
+ * Sets up callbacks for device hotplug events.
+ */
+LONG
+HPRegisterForHotplugEvents()
+{
+    LONG sstat;
+    sstat = SYS_ThreadCreate(&sHotplugWatcherThread,
+                             NULL,
+                             (LPVOID)HPDeviceNotificationThread,
+                             NULL);
+    return 0;
+}

Added: trunk/SmartCardServices/src/PCSC/hotplug_macosx.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/hotplug_macosx.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/hotplug_macosx.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2000-2006 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : hotplug_macosx.c
+	    Package: pcsc lite
+      Author : Stephen M. Webb <stephenw at cryptocard.com>
+      Date   : 03 Dec 2002
+	    License: Copyright (C) 2002 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This provides a search API for hot pluggble
+	             devices.
+	            
+********************************************************************/
+
+#include "wintypes.h"
+
+#include "hotplug.h"
+#include "pthread.h"
+#include "PCSCDriverBundles.h"
+#include "pcscdserver.h"
+#include "pcscdmonitor.h"
+#include <security_utilities/debugging.h>
+
+const uint32_t kPCSCLITE_HP_BASE_PORT = 0x200000;
+PCSCDMonitor *gPCSCDMonitor = NULL;
+
+#ifndef HOTPLUGTEST
+	#include "readerfactory.h"
+#else
+LONG RFAddReader(LPSTR, DWORD, LPSTR)
+{
+	return 0;
+}
+
+LONG RFRemoveReader(LPSTR, DWORD)
+{
+	return 0;
+}
+#endif
+
+// See PCSCDMonitor::addDevice for where this is actually called
+
+int32_t WrapRFAddReader(const char *name, uint32_t address, const char *pathLibrary, const char *deviceName)
+{
+	secdebug("device", "RFAddReader: name: %s, address: %04X, pathLibrary: %s, pathDevice: %s", name, address, pathLibrary, deviceName);
+	return RFAddReader(const_cast<char *>(name), kPCSCLITE_HP_BASE_PORT+address, const_cast<char *>(pathLibrary), const_cast<char *>(deviceName));
+}
+
+int32_t WrapRFRemoveReader(const char *name, uint32_t address)
+{
+	secdebug("device", "RFRemoveReader: name: %s, address: %04X", name, address);
+	return RFRemoveReader(const_cast<char *>(name), kPCSCLITE_HP_BASE_PORT+address);
+}
+
+int32_t WrapRFAwakeAllReaders()
+{
+	secdebug("device", "RFAwakeAllReaders");
+	RFAwakeAllReaders();
+	return 0;
+}
+
+int32_t WrapRFSuspendAllReaders()
+{
+	secdebug("device", "RFSuspendAllReaders");
+	RFSuspendAllReaders();
+	return 0;
+}
+
+static void *HPDeviceNotificationThread(void *foo)
+{
+	try
+	{
+		// Thread runner (does not return)
+		PCSCD::DriverBundles bdls;
+		PCSCD::Server myserv("hotplug");
+		PCSCDMonitor xmon(myserv,bdls);
+		gPCSCDMonitor = &xmon;
+		xmon.setCallbacks(WrapRFAddReader, WrapRFRemoveReader, WrapRFSuspendAllReaders, WrapRFAwakeAllReaders);
+		bdls.update();
+		myserv.run();
+	}
+	catch (Security::MachPlusPlus::Error e)
+	{
+		char *perr = (char *)mach_error_string(e.error);
+		if (perr)
+			secdebug("device", "Caught error in xx: %s, error: %04lX", perr, e.osStatus());
+		else
+			secdebug("device", "Caught error in xx: %04X", e.error);
+	}
+	catch (...)
+	{
+	}
+	exit(0);
+	return NULL;	// never gets here
+}
+
+void systemAwakeAndReadyCheck()
+{
+	gPCSCDMonitor->systemAwakeAndReadyCheck();
+}
+
+/*
+ * Scans the hotplug driver directory and looks in the system for matching devices.
+ * Adds or removes matching readers as necessary.
+ */
+int32_t HPSearchHotPluggables()
+{
+	// this function is a no-op now
+    return 0;
+}
+
+static pthread_t sHotplugWatcherThread;
+
+int32_t HPRegisterForHotplugEvents()
+{
+	return HPRegisterForHotplugEventsT(&sHotplugWatcherThread);
+}
+
+int32_t HPRegisterForHotplugEventsT(pthread_t *wthread)
+{
+	// Sets up callbacks for device hotplug events
+	int rx = pthread_create(wthread, NULL, HPDeviceNotificationThread, NULL);
+    return rx;
+}
+
+LONG HPStopHotPluggables(void)
+{
+	return 0;
+}
+
+void HPReCheckSerialReaders(void)
+{
+}
+

Added: trunk/SmartCardServices/src/PCSC/ifdhandler.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/ifdhandler.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/ifdhandler.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,240 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  ifdhandler.h
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Damien Sauveron <damien.sauveron at labri.fr>
+ *
+ * $Id: ifdhandler.h 2348 2007-01-20 15:12:19Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This provides reader specific low-level calls.
+ */
+
+#ifndef _ifd_handler_h_
+#define _ifd_handler_h_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	/*
+	 * List of data structures available to ifdhandler
+	 */
+
+	typedef struct _DEVICE_CAPABILITIES
+	{
+		LPSTR Vendor_Name;		/* Tag 0x0100 */
+		LPSTR IFD_Type;			/* Tag 0x0101 */
+		DWORD IFD_Version;		/* Tag 0x0102 */
+		LPSTR IFD_Serial;		/* Tag 0x0103 */
+		DWORD IFD_Channel_ID;	/* Tag 0x0110 */
+
+		DWORD Asynch_Supported;	/* Tag 0x0120 */
+		DWORD Default_Clock;	/* Tag 0x0121 */
+		DWORD Max_Clock;		/* Tag 0x0122 */
+		DWORD Default_Data_Rate;	/* Tag 0x0123 */
+		DWORD Max_Data_Rate;	/* Tag 0x0124 */
+		DWORD Max_IFSD;			/* Tag 0x0125 */
+		DWORD Synch_Supported;	/* Tag 0x0126 */
+		DWORD Power_Mgmt;		/* Tag 0x0131 */
+		DWORD Card_Auth_Devices;	/* Tag 0x0140 */
+		DWORD User_Auth_Device;	/* Tag 0x0142 */
+		DWORD Mechanics_Supported;	/* Tag 0x0150 */
+		DWORD Vendor_Features;	/* Tag 0x0180 - 0x01F0 User Defined. */
+	}
+	DEVICE_CAPABILITIES, *PDEVICE_CAPABILITIES;
+
+	typedef struct _ICC_STATE
+	{
+		UCHAR ICC_Presence;		/* Tag 0x0300 */
+		UCHAR ICC_Interface_Status;	/* Tag 0x0301 */
+		UCHAR ATR[MAX_ATR_SIZE];	/* Tag 0x0303 */
+		UCHAR ICC_Type;			/* Tag 0x0304 */
+	}
+	ICC_STATE, *PICC_STATE;
+
+	typedef struct _PROTOCOL_OPTIONS
+	{
+		DWORD Protocol_Type;	/* Tag 0x0201 */
+		DWORD Current_Clock;	/* Tag 0x0202 */
+		DWORD Current_F;		/* Tag 0x0203 */
+		DWORD Current_D;		/* Tag 0x0204 */
+		DWORD Current_N;		/* Tag 0x0205 */
+		DWORD Current_W;		/* Tag 0x0206 */
+		DWORD Current_IFSC;		/* Tag 0x0207 */
+		DWORD Current_IFSD;		/* Tag 0x0208 */
+		DWORD Current_BWT;		/* Tag 0x0209 */
+		DWORD Current_CWT;		/* Tag 0x020A */
+		DWORD Current_EBC;		/* Tag 0x020B */
+	}
+	PROTOCOL_OPTIONS, *PPROTOCOL_OPTIONS;
+
+	typedef struct _SCARD_IO_HEADER
+	{
+		DWORD Protocol;
+		DWORD Length;
+	}
+	SCARD_IO_HEADER, *PSCARD_IO_HEADER;
+
+	/*
+	 * End of structure list
+	 */
+
+	/*
+	 * The list of tags should be alot more but this is all I use in the
+	 * meantime
+	 */
+
+#define TAG_IFD_ATR                     0x0303
+#define TAG_IFD_SLOTNUM                 0x0180
+#define TAG_IFD_SLOT_THREAD_SAFE        0x0FAC
+#define TAG_IFD_THREAD_SAFE             0x0FAD
+#define TAG_IFD_SLOTS_NUMBER            0x0FAE
+#define TAG_IFD_SIMULTANEOUS_ACCESS     0x0FAF
+
+	/*
+	 * End of tag list
+	 */
+
+	/*
+	 * IFD Handler version number enummerations
+	 */
+#define IFD_HVERSION_1_0               0x00010000
+#define IFD_HVERSION_2_0               0x00020000
+#define IFD_HVERSION_3_0               0x00030000
+	/*
+	 * End of version number enummerations
+	 */
+
+	/*
+	 * List of defines available to ifdhandler
+	 */
+
+#define IFD_POWER_UP			500
+#define IFD_POWER_DOWN			501
+#define IFD_RESET			502
+
+#define IFD_NEGOTIATE_PTS1		1
+#define IFD_NEGOTIATE_PTS2		2
+#define IFD_NEGOTIATE_PTS3              4
+
+#define	IFD_SUCCESS			0
+#define IFD_ERROR_TAG			600
+#define IFD_ERROR_SET_FAILURE		601
+#define IFD_ERROR_VALUE_READ_ONLY	602
+#define IFD_ERROR_PTS_FAILURE		605
+#define IFD_ERROR_NOT_SUPPORTED		606
+#define IFD_PROTOCOL_NOT_SUPPORTED	607
+#define IFD_ERROR_POWER_ACTION		608
+#define IFD_ERROR_SWALLOW		609
+#define IFD_ERROR_EJECT			610
+#define IFD_ERROR_CONFISCATE		611
+#define IFD_COMMUNICATION_ERROR		612
+#define IFD_RESPONSE_TIMEOUT		613
+#define IFD_NOT_SUPPORTED		614
+#define IFD_ICC_PRESENT			615
+#define IFD_ICC_NOT_PRESENT		616
+#define IFD_NO_SUCH_DEVICE		617
+
+//	typedef long RESPONSECODE;
+
+	/*
+	 * If you want to compile a V2.0 IFDHandler, define IFDHANDLERv2 before you
+	 * include this file.
+	 *
+	 * By default it is setup for for most recent version of the API (V3.0)
+	 */
+
+#ifndef IFDHANDLERv2
+
+	/*
+	 * List of Defined Functions Available to IFD_Handler 3.0
+	 *
+	 * All the functions of IFD_Handler 2.0 are available
+	 * IFDHCreateChannelByName() is new
+	 * IFDHControl() API changed
+	 */
+
+	RESPONSECODE IFDHCreateChannelByName(DWORD, LPSTR);
+	RESPONSECODE IFDHControl(DWORD, DWORD, PUCHAR, DWORD, PUCHAR,
+		DWORD, LPDWORD);
+#else
+
+	/*
+	 * List of Defined Functions Available to IFD_Handler 2.0
+	 */
+
+	RESPONSECODE IFDHControl(DWORD, PUCHAR, DWORD, PUCHAR, PDWORD);
+
+#endif
+
+	/*
+	 * common functions in IFD_Handler 2.0 and 3.0
+	 */
+	RESPONSECODE IFDHCreateChannel(DWORD, DWORD);
+	RESPONSECODE IFDHCloseChannel(DWORD);
+	RESPONSECODE IFDHGetCapabilities(DWORD, DWORD, PDWORD, PUCHAR);
+	RESPONSECODE IFDHSetCapabilities(DWORD, DWORD, DWORD, PUCHAR);
+	RESPONSECODE IFDHSetProtocolParameters(DWORD, DWORD, UCHAR,
+		UCHAR, UCHAR, UCHAR);
+	RESPONSECODE IFDHPowerICC(DWORD, DWORD, PUCHAR, PDWORD);
+	RESPONSECODE IFDHTransmitToICC(DWORD, SCARD_IO_HEADER, PUCHAR,
+		DWORD, PUCHAR, PDWORD, PSCARD_IO_HEADER);
+	RESPONSECODE IFDHICCPresence(DWORD);
+
+	/*
+	 * List of Defined Functions Available to IFD_Handler 1.0
+	 */
+
+	RESPONSECODE IO_Create_Channel(DWORD);
+	RESPONSECODE IO_Close_Channel();
+	RESPONSECODE IFD_Get_Capabilities(DWORD, PUCHAR);
+	RESPONSECODE IFD_Set_Capabilities(DWORD, PUCHAR);
+	RESPONSECODE IFD_Set_Protocol_Parameters(DWORD, UCHAR, UCHAR,
+		UCHAR, UCHAR);
+	RESPONSECODE IFD_Power_ICC(DWORD);
+	RESPONSECODE IFD_Swallow_ICC();
+	RESPONSECODE IFD_Eject_ICC();
+	RESPONSECODE IFD_Confiscate_ICC();
+	RESPONSECODE IFD_Transmit_to_ICC(SCARD_IO_HEADER, PUCHAR, DWORD,
+		PUCHAR, PDWORD, PSCARD_IO_HEADER);
+	RESPONSECODE IFD_Is_ICC_Present();
+	RESPONSECODE IFD_Is_ICC_Absent();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PCSC/ifdwrapper.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/ifdwrapper.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/ifdwrapper.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,807 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  ifdwrapper.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Damien Sauveron <damien.sauveron at labri.fr>
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: ifdwrapper.c 2377 2007-02-05 13:13:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This wraps the dynamic ifdhandler functions.
+ */
+
+#include "config.h"
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "ifdhandler.h"
+#include "debuglog.h"
+#include "readerfactory.h"
+#include "ifdwrapper.h"
+#include "atrhandler.h"
+#include "dyn_generic.h"
+#include "sys_generic.h"
+
+#include <security_utilities/debugging.h>
+
+#undef PCSCLITE_STATIC_DRIVER
+
+/*
+ * Function: IFDSetPTS Purpose : To set the protocol type selection (PTS).
+ * This function sets the appropriate protocol to be used on the card.
+ */
+
+LONG IFDSetPTS(PREADER_CONTEXT rContext, DWORD dwProtocol, UCHAR ucFlags,
+	UCHAR ucPTS1, UCHAR ucPTS2, UCHAR ucPTS3)
+{
+	RESPONSECODE rv = IFD_SUCCESS;
+	UCHAR ucValue[1];
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IFD_set_protocol_parameters) (DWORD, UCHAR, UCHAR,
+		UCHAR, UCHAR) = NULL;
+	RESPONSECODE(*IFDH_set_protocol_parameters) (DWORD, DWORD, UCHAR,
+		UCHAR, UCHAR, UCHAR) = NULL;
+
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		IFD_set_protocol_parameters = (RESPONSECODE(*)(DWORD, UCHAR, UCHAR,
+			UCHAR, UCHAR)) rContext->psFunctions.psFunctions_v1.pvfSetProtocolParameters;
+
+		if (NULL == IFD_set_protocol_parameters)
+			return SCARD_E_UNSUPPORTED_FEATURE;
+	}
+	else
+	{
+		IFDH_set_protocol_parameters = (RESPONSECODE(*)(DWORD, DWORD, UCHAR,
+			UCHAR, UCHAR, UCHAR))
+			rContext->psFunctions.psFunctions_v2.pvfSetProtocolParameters;
+
+		if (NULL == IFDH_set_protocol_parameters)
+			return SCARD_E_UNSUPPORTED_FEATURE;
+	}
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+	SYS_MutexLock(rContext->mMutex);
+
+	ucValue[0] = rContext->dwSlot;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+	        ucValue[0] = rContext->dwSlot;
+	        IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+	        rv = (*IFD_set_protocol_parameters) (dwProtocol,
+			ucFlags, ucPTS1, ucPTS2, ucPTS3);
+	}
+	else
+	{
+		rv = (*IFDH_set_protocol_parameters) (rContext->dwSlot,
+						      dwProtocol,
+						      ucFlags, ucPTS1,
+						      ucPTS2, ucPTS3);
+	}
+#else
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+	        ucValue[0] = rContext->dwSlot;
+	        IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+		rv = IFD_Set_Protocol_Parameters(dwProtocol, ucFlags, ucPTS1,
+			ucPTS2, ucPTS3);
+	}
+	else
+	{
+		rv = IFDHSetProtocolParameters(rContext->dwSlot, dwProtocol,
+			ucFlags, ucPTS1, ucPTS2, ucPTS3);
+	}
+#endif
+
+	SYS_MutexUnLock(rContext->mMutex);
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	return rv;
+}
+
+/*
+ * Function: IFDOpenIFD Purpose : This function opens a communication
+ * channel to the IFD.
+ */
+
+LONG IFDOpenIFD(PREADER_CONTEXT rContext)
+{
+	RESPONSECODE rv = 0;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IO_create_channel) (DWORD) = NULL;
+	RESPONSECODE(*IFDH_create_channel) (DWORD, DWORD) = NULL;
+	RESPONSECODE(*IFDH_create_channel_by_name) (DWORD, LPSTR) = NULL;
+
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		IO_create_channel =
+			rContext->psFunctions.psFunctions_v1.pvfCreateChannel;
+	else
+		if (rContext->dwVersion == IFD_HVERSION_2_0)
+			IFDH_create_channel =
+				rContext->psFunctions.psFunctions_v2.pvfCreateChannel;
+		else
+		{
+			IFDH_create_channel =
+				rContext->psFunctions.psFunctions_v3.pvfCreateChannel;
+			IFDH_create_channel_by_name =
+				rContext->psFunctions.psFunctions_v3.pvfCreateChannelByName;
+		}
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+
+	SYS_MutexLock(rContext->mMutex);
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		rv = (*IO_create_channel) (rContext->dwPort);
+	} else if (rContext->dwVersion == IFD_HVERSION_2_0)
+	{
+		rv = (*IFDH_create_channel) (rContext->dwSlot, rContext->dwPort);
+	} else
+	{
+		/* use device name only if defined */
+		if (rContext->lpcDevice[0] != '\0')
+			rv = (*IFDH_create_channel_by_name) (rContext->dwSlot, rContext->lpcDevice);
+		else
+			rv = (*IFDH_create_channel) (rContext->dwSlot, rContext->dwPort);
+	}
+#else
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		rv = IO_Create_Channel(rContext->dwPort);
+	} else if (rContext->dwVersion == IFD_HVERSION_2_0)
+	{
+		rv = IFDHCreateChannel(rContext->dwSlot, rContext->dwPort);
+	} else
+	{
+		/* Use device name only if defined */
+		if (rContext->lpcDevice[0] != '\0')
+			rv = IFDHCreateChannelByName(rContext->dwSlot, rContext->lpcDevice);
+		else
+			rv = IFDHCreateChannel(rContext->dwSlot, rContext->dwPort);
+	}
+#endif
+	SYS_MutexUnLock(rContext->mMutex);
+
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	return rv;
+}
+
+/*
+ * Function: IFDCloseIFD Purpose : This function closes a communication
+ * channel to the IFD.
+ */
+
+LONG IFDCloseIFD(PREADER_CONTEXT rContext)
+{
+	RESPONSECODE rv = IFD_SUCCESS;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IO_close_channel) () = NULL;
+	RESPONSECODE(*IFDH_close_channel) (DWORD) = NULL;
+
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		IO_close_channel = rContext->psFunctions.psFunctions_v1.pvfCloseChannel;
+	else
+		IFDH_close_channel = rContext->psFunctions.psFunctions_v2.pvfCloseChannel;
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+
+	SYS_MutexLock(rContext->mMutex);
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+
+		rv = (*IO_close_channel) ();
+	else
+		rv = (*IFDH_close_channel) (rContext->dwSlot);
+#else
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		rv = IO_Close_Channel();
+	else
+		rv = IFDHCloseChannel(rContext->dwSlot);
+#endif
+	SYS_MutexUnLock(rContext->mMutex);
+
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	return rv;
+}
+
+/*
+ * Function: IFDSetCapabilites Purpose : This function set's capabilities
+ * in the reader.
+ */
+
+LONG IFDSetCapabilities(PREADER_CONTEXT rContext, DWORD dwTag,
+			DWORD dwLength, PUCHAR pucValue)
+{
+	RESPONSECODE rv = IFD_SUCCESS;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IFD_set_capabilities) (DWORD, PUCHAR) = NULL;
+	RESPONSECODE(*IFDH_set_capabilities) (DWORD, DWORD, DWORD, PUCHAR) = NULL;
+
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		IFD_set_capabilities = rContext->psFunctions.psFunctions_v1.pvfSetCapabilities;
+	else
+		IFDH_set_capabilities = rContext->psFunctions.psFunctions_v2.pvfSetCapabilities;
+#endif
+
+	/*
+	 * Let the calling function lock this otherwise a deadlock will
+	 * result
+	 */
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		rv = (*IFD_set_capabilities) (dwTag, pucValue);
+	else
+		rv = (*IFDH_set_capabilities) (rContext->dwSlot, dwTag,
+			dwLength, pucValue);
+#else
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		rv = IFD_Set_Capabilities(dwTag, pucValue);
+	else
+		rv = IFDHSetCapabilities(rContext->dwSlot, dwTag, dwLength,
+			pucValue);
+#endif
+
+	return rv;
+}
+
+/*
+ * Function: IFDGetCapabilites Purpose : This function get's capabilities
+ * in the reader. Other functions int this file will call the driver
+ * directly to not cause a deadlock.
+ */
+
+LONG IFDGetCapabilities(PREADER_CONTEXT rContext, DWORD dwTag,
+	PDWORD pdwLength, PUCHAR pucValue)
+{
+	RESPONSECODE rv = IFD_SUCCESS;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IFD_get_capabilities) (DWORD, PUCHAR) = NULL;
+	RESPONSECODE(*IFDH_get_capabilities) (DWORD, DWORD, PDWORD, PUCHAR) = NULL;
+
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		IFD_get_capabilities =
+			rContext->psFunctions.psFunctions_v1.pvfGetCapabilities;
+	else
+		IFDH_get_capabilities =
+			rContext->psFunctions.psFunctions_v2.pvfGetCapabilities;
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+
+	SYS_MutexLock(rContext->mMutex);
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		rv = (*IFD_get_capabilities) (dwTag, pucValue);
+	else
+		rv = (*IFDH_get_capabilities) (rContext->dwSlot, dwTag,
+			pdwLength, pucValue);
+#else
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		rv = IFD_Get_Capabilities(dwTag, pucValue);
+	else
+		rv = IFDHGetCapabilities(rContext->dwSlot, dwTag, pdwLength,
+			pucValue);
+#endif
+
+	SYS_MutexUnLock(rContext->mMutex);
+
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	return rv;
+}
+
+/*
+ * Function: IFDPowerICC Purpose : This function powers up/down or reset's
+ * an ICC located in the IFD.
+ */
+
+LONG IFDPowerICC(PREADER_CONTEXT rContext, DWORD dwAction,
+	const unsigned char *pucAtr, PDWORD pdwAtrLen)
+{
+	RESPONSECODE rv;
+	short ret;
+	SMARTCARD_EXTENSION sSmartCard;
+	DWORD dwStatus;
+	UCHAR ucValue[1];
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IFD_power_icc) (DWORD) = NULL;
+	RESPONSECODE(*IFDH_power_icc) (DWORD, DWORD, PUCHAR, PDWORD) = NULL;
+#endif
+
+	/*
+	 * Zero out everything
+	 */
+	rv = IFD_SUCCESS;
+	dwStatus = 0;
+	ucValue[0] = 0;
+
+	/*
+	 * Check that the card is inserted first
+	 */
+	IFDStatusICC(rContext, &dwStatus, pucAtr, pdwAtrLen);
+
+	if (dwStatus & SCARD_ABSENT)
+		return SCARD_W_REMOVED_CARD;
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		IFD_power_icc = rContext->psFunctions.psFunctions_v1.pvfPowerICC;
+	else
+		IFDH_power_icc = rContext->psFunctions.psFunctions_v2.pvfPowerICC;
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+
+	SYS_MutexLock(rContext->mMutex);
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		ucValue[0] = rContext->dwSlot;
+		IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+		rv = (*IFD_power_icc) (dwAction);
+	}
+	else
+	{
+		rv = (*IFDH_power_icc) (rContext->dwSlot, dwAction,
+			pucAtr, pdwAtrLen);
+
+		ret = ATRDecodeAtr(&sSmartCard, pucAtr, *pdwAtrLen);
+	}
+#else
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		ucValue[0] = rContext->dwSlot;
+		IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+		rv = IFD_Power_ICC(dwAction);
+	}
+	else
+		rv = IFDHPowerICC(rContext->dwSlot, dwAction, pucAtr, pdwAtrLen);
+#endif
+	SYS_MutexUnLock(rContext->mMutex);
+
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	/* use clean values in case of error */
+	if (rv != IFD_SUCCESS)
+	{
+		*pdwAtrLen = 0;
+//		pucAtr[0] = '\0';
+
+		if (rv == IFD_NO_SUCH_DEVICE)
+		{
+		//	SendHotplugSignal();
+			return SCARD_E_READER_UNAVAILABLE;
+		}
+
+		return SCARD_E_NOT_TRANSACTED;
+	}
+
+	/*
+	 * Get the ATR and it's length
+	 */
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		IFDStatusICC(rContext, &dwStatus, pucAtr, pdwAtrLen);
+
+	return rv;
+}
+
+/*
+ * Function: IFDStatusICC Purpose : This function provides statistical
+ * information about the IFD and ICC including insertions, atr, powering
+ * status/etc.
+ */
+
+LONG IFDStatusICC(PREADER_CONTEXT rContext, PDWORD pdwStatus,
+	const unsigned char *pucAtr, PDWORD pdwAtrLen)
+{
+	RESPONSECODE rv = IFD_SUCCESS;
+	DWORD dwTag = 0, dwCardStatus = 0;
+	SMARTCARD_EXTENSION sSmartCard;
+	UCHAR ucValue[1] = "\x00";
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IFD_is_icc_present) () = NULL;
+	RESPONSECODE(*IFDH_icc_presence) (DWORD) = NULL;
+	RESPONSECODE(*IFD_get_capabilities) (DWORD, PUCHAR) = NULL;
+
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		IFD_is_icc_present =
+			rContext->psFunctions.psFunctions_v1.pvfICCPresence;
+		IFD_get_capabilities =
+			rContext->psFunctions.psFunctions_v1.pvfGetCapabilities;
+	}
+	else
+	{
+		IFDH_icc_presence = rContext->psFunctions.psFunctions_v2.pvfICCPresence;
+		// Defensive measure
+		if (!IFDH_icc_presence)
+			return SCARD_E_SYSTEM_CANCELLED;
+	}
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+
+	SYS_MutexLock(rContext->mMutex);
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		ucValue[0] = rContext->dwSlot;
+		IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+		rv = (*IFD_is_icc_present) ();
+	}
+	else
+		rv = (*IFDH_icc_presence) (rContext->dwSlot);
+#else
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		ucValue[0] = rContext->dwSlot;
+		IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+		rv = IFD_Is_ICC_Present();
+	}
+	else
+		rv = IFDHICCPresence(rContext->dwSlot);
+#endif
+	SYS_MutexUnLock(rContext->mMutex);
+
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	if (rv == IFD_SUCCESS || rv == IFD_ICC_PRESENT)
+		dwCardStatus |= SCARD_PRESENT;
+	else
+		if (rv == IFD_ICC_NOT_PRESENT)
+			dwCardStatus |= SCARD_ABSENT;
+		else
+		{
+			Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
+			*pdwStatus = SCARD_UNKNOWN;
+
+			if (rv == IFD_NO_SUCH_DEVICE)
+			{
+			//	SendHotplugSignal();
+				return SCARD_E_READER_UNAVAILABLE;
+			}
+
+			return SCARD_E_NOT_TRANSACTED;
+		}
+
+	/*
+	 * Now lets get the ATR and process it if IFD Handler version 1.0.
+	 * IFD Handler version 2.0 does this immediately after reset/power up
+	 * to conserve resources
+	 */
+
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		if (rv == IFD_SUCCESS || rv == IFD_ICC_PRESENT)
+		{
+			short ret;
+
+			dwTag = TAG_IFD_ATR;
+
+			/*
+			 * LOCK THIS CODE REGION
+			 */
+
+			SYS_MutexLock(rContext->mMutex);
+
+			ucValue[0] = rContext->dwSlot;
+			IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+
+#ifndef PCSCLITE_STATIC_DRIVER
+			rv = (*IFD_get_capabilities) (dwTag, pucAtr);
+#else
+			rv = IFD_Get_Capabilities(dwTag, pucAtr);
+#endif
+			SYS_MutexUnLock(rContext->mMutex);
+
+			/*
+			 * END OF LOCKED REGION
+			 */
+
+			/*
+			 * FIX :: This is a temporary way to return the correct size
+			 * of the ATR since most of the drivers return MAX_ATR_SIZE
+			 */
+
+			ret = ATRDecodeAtr(&sSmartCard, pucAtr, MAX_ATR_SIZE);
+
+			/*
+			 * Might be a memory card without an ATR
+			 */
+			if (ret == 0)
+				*pdwAtrLen = 0;
+			else
+				*pdwAtrLen = sSmartCard.ATR.Length;
+		}
+		else
+		{
+			/*
+			 * No card is inserted - Atr length is 0
+			 */
+			*pdwAtrLen = 0;
+		}
+		/*
+		 * End of FIX
+		 */
+	}
+
+	*pdwStatus = dwCardStatus;
+
+	return SCARD_S_SUCCESS;
+}
+
+/*
+ * Function: IFDControl Purpose : This function provides a means for
+ * toggling a specific action on the reader such as swallow, eject,
+ * biometric.
+ */
+
+/*
+ * Valid only for IFDHandler version 2.0
+ */
+
+LONG IFDControl_v2(PREADER_CONTEXT rContext, PUCHAR TxBuffer,
+	DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength)
+{
+	RESPONSECODE rv = IFD_SUCCESS;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IFDH_control_v2) (DWORD, PUCHAR, DWORD, PUCHAR, PDWORD);
+#endif
+
+	if (rContext->dwVersion != IFD_HVERSION_2_0)
+		return SCARD_E_UNSUPPORTED_FEATURE;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	IFDH_control_v2 = rContext->psFunctions.psFunctions_v2.pvfControl;
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+	SYS_MutexLock(rContext->mMutex);
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	rv = (*IFDH_control_v2) (rContext->dwSlot, TxBuffer, TxLength,
+		RxBuffer, RxLength);
+#else
+	rv = IFDHControl_v2(rContext->dwSlot, TxBuffer, TxLength,
+		RxBuffer, RxLength);
+#endif
+	SYS_MutexUnLock(rContext->mMutex);
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	if (rv == IFD_SUCCESS)
+		return SCARD_S_SUCCESS;
+	else
+	{
+		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
+		return SCARD_E_NOT_TRANSACTED;
+	}
+}
+
+/*
+ * Function: IFDControl Purpose : This function provides a means for
+ * toggling a specific action on the reader such as swallow, eject,
+ * biometric.
+ */
+
+/*
+ * Valid only for IFDHandler version 3.0 and up
+ */
+
+LONG IFDControl(PREADER_CONTEXT rContext, DWORD ControlCode,
+	LPCVOID TxBuffer, DWORD TxLength, LPVOID RxBuffer, DWORD RxLength,
+	LPDWORD BytesReturned)
+{
+	RESPONSECODE rv = IFD_SUCCESS;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IFDH_control) (DWORD, DWORD, LPCVOID, DWORD, LPVOID, DWORD, LPDWORD);
+#endif
+
+	if (rContext->dwVersion < IFD_HVERSION_3_0)
+		return SCARD_E_UNSUPPORTED_FEATURE;
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	IFDH_control = rContext->psFunctions.psFunctions_v3.pvfControl;
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+
+	SYS_MutexLock(rContext->mMutex);
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	rv = (*IFDH_control) (rContext->dwSlot, ControlCode, TxBuffer,
+		TxLength, RxBuffer, RxLength, BytesReturned);
+#else
+	rv = IFDHControl(rContext->dwSlot, ControlCode, TxBuffer,
+		TxLength, RxBuffer, RxLength, BytesReturned);
+#endif
+	SYS_MutexUnLock(rContext->mMutex);
+
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	if (rv == IFD_SUCCESS)
+		return SCARD_S_SUCCESS;
+	else
+	{
+		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
+
+		if (rv == IFD_NO_SUCH_DEVICE)
+		{
+//			SendHotplugSignal();
+			return SCARD_E_READER_UNAVAILABLE;
+		}
+
+		return SCARD_E_NOT_TRANSACTED;
+	}
+}
+
+/*
+ * Function: IFDTransmit Purpose : This function transmits an APDU to the
+ * ICC.
+ */
+
+LONG IFDTransmit(PREADER_CONTEXT rContext, SCARD_IO_HEADER pioTxPci,
+	PUCHAR pucTxBuffer, DWORD dwTxLength, PUCHAR pucRxBuffer,
+	PDWORD pdwRxLength, PSCARD_IO_HEADER pioRxPci)
+{
+	RESPONSECODE rv = IFD_SUCCESS;
+	UCHAR ucValue[1] = "\x00";
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	RESPONSECODE(*IFD_transmit_to_icc) (SCARD_IO_HEADER, PUCHAR, DWORD,
+		PUCHAR, PDWORD, PSCARD_IO_HEADER) = NULL;
+	RESPONSECODE(*IFDH_transmit_to_icc) (DWORD, SCARD_IO_HEADER, PUCHAR,
+		DWORD, PUCHAR, PDWORD, PSCARD_IO_HEADER) = NULL;
+#endif
+
+	/* log the APDU */
+	DebugLogCategory(DEBUG_CATEGORY_APDU, pucTxBuffer, dwTxLength);
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+		IFD_transmit_to_icc =
+			rContext->psFunctions.psFunctions_v1.pvfTransmitToICC;
+	else
+		IFDH_transmit_to_icc =
+			rContext->psFunctions.psFunctions_v2.pvfTransmitToICC;
+#endif
+
+	/*
+	 * LOCK THIS CODE REGION
+	 */
+
+	SYS_MutexLock(rContext->mMutex);
+
+
+#ifndef PCSCLITE_STATIC_DRIVER
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		ucValue[0] = rContext->dwSlot;
+		IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+		rv = (*IFD_transmit_to_icc) (pioTxPci, (LPBYTE) pucTxBuffer,
+			dwTxLength, pucRxBuffer, pdwRxLength, pioRxPci);
+	}
+	else
+		rv = (*IFDH_transmit_to_icc) (rContext->dwSlot, pioTxPci,
+			(LPBYTE) pucTxBuffer, dwTxLength,
+			pucRxBuffer, pdwRxLength, pioRxPci);
+#else
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		ucValue[0] = rContext->dwSlot;
+		IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
+		rv = IFD_Transmit_to_ICC(pioTxPci, (LPBYTE) pucTxBuffer,
+			dwTxLength, pucRxBuffer, pdwRxLength, pioRxPci);
+	}
+	else
+		rv = IFDHTransmitToICC(rContext->dwSlot, pioTxPci,
+			(LPBYTE) pucTxBuffer, dwTxLength,
+			pucRxBuffer, pdwRxLength, pioRxPci);
+#endif
+	SYS_MutexUnLock(rContext->mMutex);
+
+	/*
+	 * END OF LOCKED REGION
+	 */
+
+	/* log the returned status word */
+	DebugLogCategory(DEBUG_CATEGORY_SW, pucRxBuffer, *pdwRxLength);
+
+	if (rv == IFD_SUCCESS)
+		return SCARD_S_SUCCESS;
+	else
+	{
+		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
+
+		if (rv == IFD_NO_SUCH_DEVICE)
+		{
+	//		SendHotplugSignal();
+			return SCARD_E_READER_UNAVAILABLE;
+		}
+
+		return SCARD_E_NOT_TRANSACTED;
+	}
+}
+

Added: trunk/SmartCardServices/src/PCSC/ifdwrapper.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/ifdwrapper.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/ifdwrapper.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  ifdwrapper.h
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Ludovic Rousseau <ludovic.rouseau at free.fr>
+ *
+ * $Id: ifdwrapper.h 2151 2006-09-06 20:02:47Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This wraps the dynamic ifdhandler functions. The abstraction will
+ * eventually allow multiple card slots in the same terminal.
+ */
+
+#ifndef __ifdwrapper_h__
+#define __ifdwrapper_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	LONG IFDOpenIFD(PREADER_CONTEXT);
+	LONG IFDCloseIFD(PREADER_CONTEXT);
+	LONG IFDPowerICC(PREADER_CONTEXT, DWORD, const unsigned char *, PDWORD);
+	LONG IFDStatusICC(PREADER_CONTEXT, PDWORD, const unsigned char *, PDWORD);
+	LONG IFDControl_v2(PREADER_CONTEXT, PUCHAR, DWORD, PUCHAR, PDWORD);
+	LONG IFDControl(PREADER_CONTEXT, DWORD, LPCVOID, DWORD, LPVOID,
+		DWORD, LPDWORD);
+	LONG IFDTransmit(PREADER_CONTEXT, SCARD_IO_HEADER,
+		PUCHAR, DWORD, PUCHAR, PDWORD, PSCARD_IO_HEADER);
+	LONG IFDSetPTS(PREADER_CONTEXT, DWORD, UCHAR, UCHAR, UCHAR, UCHAR);
+	LONG IFDSetCapabilities(PREADER_CONTEXT, DWORD, DWORD, PUCHAR);
+	LONG IFDGetCapabilities(PREADER_CONTEXT, DWORD, PDWORD, PUCHAR);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __ifdwrapper_h__ */

Added: trunk/SmartCardServices/src/PCSC/mscdefines.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/mscdefines.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/mscdefines.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/******************************************************************
+
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : mscdefines.h
+            Package: MuscleCard Framework
+            Author : David Corcoran
+            Date   : 10/02/01
+            License: Copyright (C) 2001-2002 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This provides high level definitions for
+                     data types, structures.
+
+	    You may not remove this header from this file
+	    without prior permission from the author.
+   
+********************************************************************/
+
+#ifndef __mscdefines_h__
+#define __mscdefines_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef WIN32
+#include "../win32/win32_pcsclite.h"
+#else
+#include "pcsclite.h"
+#endif
+
+#ifndef __APPLE__
+#include <winscard.h>
+#else
+#include <PCSC/winscard.h>
+#endif
+
+#include <stdint.h>
+
+#ifdef MSC_ARCH_WIN32
+#define MAX_BUFFER_SIZE		265
+#endif
+
+	/*
+	 * Some type defines used in MuscleCard 
+	 */
+
+	typedef uint32_t MSC_RV;
+	typedef char MSCChar8;
+	typedef uint8_t *MSCPUChar8;
+	typedef const uint8_t *MSCPCUChar8;
+	typedef uint8_t MSCUChar8;
+	typedef uint16_t *MSCPUShort16;
+	typedef uint16_t MSCUShort16;
+	typedef int16_t *MSCPShort16;
+	typedef int16_t MSCShort16;
+	typedef uint32_t *MSCPULong32;
+	typedef uint32_t MSCULong32;
+	typedef int32_t *MSCPLong32;
+	typedef int32_t MSCLong32;
+	typedef const void *MSCPCVoid32;
+	typedef void *MSCPVoid32;
+	typedef const char *MSCCString;
+	typedef char *MSCString;
+
+	typedef struct
+	{
+		MSCPVoid32 pvfWriteFramework;
+		MSCPVoid32 pvfInitializePlugin;
+		MSCPVoid32 pvfIdentifyToken;
+		MSCPVoid32 pvfFinalizePlugin;
+		MSCPVoid32 pvfGetStatus;
+		MSCPVoid32 pvfGetCapabilities;
+		MSCPVoid32 pvfExtendedFeature;
+		MSCPVoid32 pvfGenerateKeys;
+		MSCPVoid32 pvfImportKey;
+		MSCPVoid32 pvfExportKey;
+		MSCPVoid32 pvfComputeCrypt;
+		MSCPVoid32 pvfExtAuthenticate;
+		MSCPVoid32 pvfListKeys;
+		MSCPVoid32 pvfCreatePIN;
+		MSCPVoid32 pvfVerifyPIN;
+		MSCPVoid32 pvfChangePIN;
+		MSCPVoid32 pvfUnblockPIN;
+		MSCPVoid32 pvfListPINs;
+		MSCPVoid32 pvfCreateObject;
+		MSCPVoid32 pvfDeleteObject;
+		MSCPVoid32 pvfWriteObject;
+		MSCPVoid32 pvfReadObject;
+		MSCPVoid32 pvfListObjects;
+		MSCPVoid32 pvfLogoutAll;
+		MSCPVoid32 pvfGetChallenge;
+
+	}
+	CFDyLibPointers, *LPCFDyLibPointers;
+
+#define MSC_MAXSIZE_TOKENAME      150
+#define MSC_MAXSIZE_SVCPROV       200
+#define MSC_MAXSIZE_OBJID          16
+#define MSC_MAXSIZE_AID            64
+#define MSC_MAXSIZE_MAC           128
+#define MSC_MAXSIZE_LABEL          32
+#define MSC_MAXSIZE_CERT_ISSUER    512
+#define MSC_MAXSIZE_CERT_SUBJECT   512
+#define MSC_MAXSIZE_CERT_SERIAL    512
+#define MSC_MAXSIZE_BUFFER     MAX_BUFFER_SIZE
+
+	typedef struct
+	{
+	        MSCChar8 tokenName[MSC_MAXSIZE_TOKENAME]; /* Token name */ 
+                MSCChar8 slotName[MAX_READERNAME];	/* Slot/reader name */
+		MSCChar8 svProvider[MSC_MAXSIZE_SVCPROV]; /* Library */
+		MSCUChar8 tokenId[MAX_ATR_SIZE];     /* Token ID (ATR) */
+		MSCUChar8 tokenApp[MSC_MAXSIZE_AID]; /* Default app ID */
+		MSCULong32 tokenAppLen;	  /* Default AID Length */
+		MSCULong32 tokenIdLength; /* ID Length (ATR Length) */
+		MSCULong32 tokenState;	  /* State (dwEventState) */
+		MSCULong32 tokenType;	  /* Type - RFU */
+		MSCPVoid32 addParams;	  /* Additional Data */
+		MSCULong32 addParamsSize; /* Size of additional data */
+	}
+	MSCTokenInfo, *MSCLPTokenInfo;
+
+	/*
+	 * Callback function definitions 
+	 */
+
+	typedef MSCULong32(*MSCCallBack) (MSCLPTokenInfo, MSCULong32,
+					  MSCPVoid32);
+
+	typedef struct
+	{
+		MSCULong32 arraySize;
+		MSCLPTokenInfo tokenArray;
+		MSCPVoid32 appData;
+		MSCCallBack callBack;
+	}
+	MSCEventWaitInfo, *MSCLPEventWaitInfo;
+
+	typedef MSC_RV(*LPRWEventCallback) (MSCPVoid32, int);
+
+	typedef struct
+	{
+		MSCLong32 hContext;	      /* Handle to resource manager */
+		MSCLong32 hCard;	      /* Handle to the connection */
+		LPSCARD_IO_REQUEST ioType;    /* Type of protocol */
+		MSCUChar8 pMac[MSC_MAXSIZE_MAC];  /* MAC code */
+		MSCULong32 macSize;	      /* Size of the MAC code */
+		MSCPVoid32 tokenLibHandle;    /* Handle to token library */
+		CFDyLibPointers libPointers;  /* Function pointers */
+		MSCTokenInfo tokenInfo;	/* token information */
+		MSCUChar8 loggedIDs;	/* Verification bit mask */
+		MSCULong32 shareMode;	/* Sharing mode for this */
+		LPRWEventCallback rwCallback;	/* Registered callback */
+	}
+	MSCTokenConnection, *MSCLPTokenConnection;
+
+#define MSC_OK MSC_SUCCESS
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __mscdefines_h__ */

Added: trunk/SmartCardServices/src/PCSC/musclecard.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/musclecard.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/musclecard.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,2285 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : musclecard.c
+            Package: MuscleCard Framework
+            Author : David Corcoran
+            Date   : 09/26/01
+            License: Copyright (C) 2001-2002 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This loads MuscleCard plug-ins and provides
+	    functions for applications.
+
+	    You may not remove this header from this file without 
+	    prior permission from the author.
+  
+********************************************************************/
+
+#ifndef WIN32
+#include "config.h"
+#else
+#include "../win32/win32_config.h"
+#endif
+
+#include "musclecard.h"
+#include "tokenfactory.h"
+#include "debuglog.h"
+
+#ifdef USE_THREAD_SAFETY
+#ifndef WIN32
+#include "wintypes.h"
+#endif
+#include "thread_generic.h"
+#include "sys_generic.h"
+#endif
+
+#ifdef USE_THREAD_SAFETY
+static PCSCLITE_MUTEX mcardMutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static SCARDCONTEXT localHContext = 0;
+
+#ifdef USE_THREAD_SAFETY
+static PCSCLITE_THREAD_T callbackThread;
+#endif
+
+/*
+ * internal function 
+ */
+MSC_RV pcscToMSC(MSCLong32);
+MSC_RV MSCReEstablishConnection(MSCLPTokenConnection);
+
+void mscLockThread()
+{
+#ifdef USE_THREAD_SAFETY
+	SYS_MutexLock(&mcardMutex);
+#endif
+}
+
+void mscUnLockThread()
+{
+#ifdef USE_THREAD_SAFETY
+	SYS_MutexUnLock(&mcardMutex);
+#endif
+}
+
+/**************** MSC Connection Functions **************************/
+
+MSC_RV MSCListTokens(MSCULong32 listScope, MSCLPTokenInfo tokenArray,
+		     MSCPULong32 arrayLength)
+{
+
+	MSCLong32 rv;
+	SCARD_READERSTATE_A rgReaderStates;
+	MSCTokenInfo tokenInfo;
+	MSCLPTokenInfo currentToken;
+	MSCULong32 tokensFound;
+	MSCULong32 readerLength;
+	char *readerList;
+	int i, strLoc;
+
+	readerLength = 0;
+	tokensFound = 0;
+	readerList = 0;
+	strLoc = 0;
+	i = 0;
+
+	if (arrayLength == 0)
+		return MSC_INVALID_PARAMETER;
+	if (listScope != MSC_LIST_KNOWN &&
+		listScope != MSC_LIST_ALL && listScope != MSC_LIST_SLOTS)
+	{
+		return MSC_INVALID_PARAMETER;
+	}
+
+	mscLockThread();
+	if (localHContext == 0)
+	{
+		rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0,
+			&localHContext);
+		if (pcscToMSC(rv) != MSC_SUCCESS)
+		{
+			localHContext = 0;
+			mscUnLockThread();
+			return pcscToMSC(rv);
+		}
+	}
+	mscUnLockThread();
+
+	/*
+	 * Get the reader list size 
+	 */
+	rv = SCardListReaders(localHContext, 0, readerList, &readerLength);
+
+	if (pcscToMSC(rv) != MSC_SUCCESS)
+	{
+		return pcscToMSC(rv);
+	}
+
+	readerList = (char *) malloc(sizeof(char) * readerLength);
+
+	if (readerList == 0)
+	{
+		return MSC_INTERNAL_ERROR;
+	}
+
+	rv = SCardListReaders(localHContext, 0, readerList, &readerLength);
+
+	/*
+	 * Now that we have the readers, lets check their status 
+	 */
+	for (i = 0; i < readerLength - 1; i++)
+	{
+		rgReaderStates.szReader = &readerList[i];
+		rgReaderStates.dwCurrentState = SCARD_STATE_UNAWARE;
+
+		rv = SCardGetStatusChange(localHContext, INFINITE, 
+					  &rgReaderStates,
+					  1);
+
+		if (pcscToMSC(rv) != MSC_SUCCESS)
+		{
+			if (readerList)
+				free(readerList);
+			return pcscToMSC(rv);
+		}
+
+		/*
+		 * We only care about slots with a token unless stated 
+		 */
+		if ((rgReaderStates.dwEventState & SCARD_STATE_PRESENT) ||
+			(listScope == MSC_LIST_SLOTS))
+		{
+
+			if (rgReaderStates.dwEventState & SCARD_STATE_PRESENT)
+			{
+				/*
+				 * We only care about supported tokens 
+				 */
+				rv = TPSearchBundlesForAtr(rgReaderStates.rgbAtr,
+					rgReaderStates.cbAtr, &tokenInfo);
+			}
+
+			/*
+			 * Success for this function 
+			 */
+			if ((rv == 0) || (listScope == MSC_LIST_SLOTS) ||
+				(listScope == MSC_LIST_ALL))
+			{
+
+				/*
+				 * We found something interesting to the application 
+				 */
+				tokensFound += 1;
+
+				if ((tokensFound <= *arrayLength) && (tokenArray != 0))
+				{
+					currentToken = &tokenArray[tokensFound - 1];
+					currentToken->addParams     = 0;
+					currentToken->addParamsSize = 0;
+                                        currentToken->tokenType     = 0;  /* Vinnie 1693 */
+
+					if (rgReaderStates.dwEventState & SCARD_STATE_EMPTY)
+					{
+						currentToken->tokenType |= MSC_TOKEN_TYPE_REMOVED;
+						strncpy(currentToken->tokenName,
+							MSC_TOKEN_EMPTY_STR, MSC_MAXSIZE_TOKENAME);
+					} else if (rv == 0)
+					{
+						currentToken->tokenType |= MSC_TOKEN_TYPE_KNOWN;
+						strncpy(currentToken->tokenName,
+							tokenInfo.tokenName, MSC_MAXSIZE_TOKENAME);
+					} else
+					{
+						currentToken->tokenType |= MSC_TOKEN_TYPE_UNKNOWN;
+						strncpy(currentToken->tokenName,
+							MSC_TOKEN_UNKNOWN_STR, MSC_MAXSIZE_TOKENAME);
+					}
+
+					strncpy(currentToken->slotName,
+						rgReaderStates.szReader, MAX_READERNAME);
+
+					if (rgReaderStates.dwEventState & SCARD_STATE_PRESENT)
+					{
+						memcpy(currentToken->tokenId,
+							rgReaderStates.rgbAtr, rgReaderStates.cbAtr);
+						currentToken->tokenIdLength = rgReaderStates.cbAtr;
+					}
+					else
+					{
+						memset(currentToken->tokenId, 0x00, MAX_ATR_SIZE);
+						currentToken->tokenIdLength = 0x00;
+					}
+
+					if (rv == 0)
+					{
+						memcpy(currentToken->tokenApp,
+							tokenInfo.tokenApp, tokenInfo.tokenAppLen);
+							currentToken->tokenAppLen = tokenInfo.tokenAppLen;
+
+						strncpy(currentToken->svProvider,
+							tokenInfo.svProvider, MSC_MAXSIZE_SVCPROV);
+					} else
+					{
+						memset(currentToken->tokenApp, 0x00, MSC_MAXSIZE_AID);
+						currentToken->tokenAppLen = 0x00;
+						memset(currentToken->svProvider, 0x00, MSC_MAXSIZE_SVCPROV);
+					}
+
+					currentToken->tokenState = rgReaderStates.dwEventState;
+
+				}
+			}
+			/*
+			 * End of TPSearch success 
+			 */
+		}
+		/*
+		 * End of if token present 
+		 */
+		while (readerList[++i] != 0) ;
+	}	/* End of for .. readers */
+
+	if (readerList)
+		free(readerList);
+
+	/*
+	 * Application provides null requesting length 
+	 */
+	if (tokenArray == 0)
+	{
+		*arrayLength = tokensFound;
+		return MSC_SUCCESS;
+	}
+
+	/*
+	 * Provided length is too small 
+	 */
+	if (*arrayLength < tokensFound)
+	{
+		*arrayLength = tokensFound;
+		return MSC_INSUFFICIENT_BUFFER;
+	}
+
+	*arrayLength = tokensFound;
+	return MSC_SUCCESS;
+}
+
+MSC_RV MSCEstablishConnection(MSCLPTokenInfo tokenStruct,
+			      MSCULong32 sharingMode,
+			      MSCPUChar8 applicationName,
+			      MSCULong32 nameSize, 
+			      MSCLPTokenConnection pConnection)
+{
+	MSCLong32 rv;
+	MSCULong32 tokenSize;
+	MSCLPTokenInfo tokenList;
+	MSCPVoid32 vInitFunction;
+	MSCPVoid32 vIdFunction;
+	MSCLong32(*libPL_MSCInitializePlugin) (MSCLPTokenConnection);
+	MSCLong32(*libPL_MSCIdentifyToken) (MSCLPTokenConnection);
+	MSCULong32 dwActiveProtocol;
+	int selectedIFD;
+	char slotName[MAX_READERNAME];
+	MSCULong32 slotNameSize, slotState, slotProtocol;
+	MSCUChar8 tokenId[MAX_ATR_SIZE];
+	MSCULong32 tokenIdLength;
+
+	tokenSize = 0;
+	tokenList = 0;
+	tokenSize = 0;
+	selectedIFD = -1;
+	tokenIdLength = sizeof(tokenId);
+	slotState = 0;
+	slotProtocol = 0;
+	slotNameSize = sizeof(slotName);
+	vIdFunction = 0;
+	vInitFunction = 0;
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (tokenStruct == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (nameSize > MSC_MAXSIZE_AID)
+		return MSC_INVALID_PARAMETER;
+
+	pConnection->tokenLibHandle = 0;
+	pConnection->hContext = 0;
+	pConnection->tokenInfo.tokenIdLength = 0;
+	pConnection->shareMode = 0;
+
+	/*
+	 * Check the token name strings 
+	 */
+	if (sharingMode != MSC_SHARE_DIRECT)
+	{
+		if (strcmp(tokenStruct->tokenName, MSC_TOKEN_EMPTY_STR) == 0)
+		{
+			return MSC_TOKEN_REMOVED;
+		} else if (strcmp(tokenStruct->tokenName,
+				MSC_TOKEN_UNKNOWN_STR) == 0)
+		{
+			return MSC_UNRECOGNIZED_TOKEN;
+		}
+	}
+
+	/*
+	 * Set up the initial connection to the resource manager 
+	 */
+
+	mscLockThread();
+	if (localHContext == 0)
+	{
+		rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0,
+			&localHContext);
+#ifdef MSC_DEBUG
+		DebugLogB("SCardEstablishContext returns %s\n",
+			pcsc_stringify_error(rv));
+#endif
+		if (pcscToMSC(rv) != MSC_SUCCESS)
+		{
+			localHContext = 0;
+			mscUnLockThread();
+			return pcscToMSC(rv);
+		}
+
+		pConnection->hContext = localHContext;
+	} else
+	{
+		pConnection->hContext = localHContext;
+	}
+	mscUnLockThread();
+
+#ifdef WIN32
+	rv = SCardConnect(pConnection->hContext, tokenStruct->slotName,
+		SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+		&pConnection->hCard, &dwActiveProtocol);
+#else
+	rv = SCardConnect(pConnection->hContext, tokenStruct->slotName,
+		sharingMode, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+		&pConnection->hCard, &dwActiveProtocol);
+#endif
+
+#ifdef MSC_DEBUG
+	DebugLogB("SCardConnect returns %s\n", pcsc_stringify_error(rv));
+#endif
+
+	if (pcscToMSC(rv) != MSC_SUCCESS)
+	{
+		return pcscToMSC(rv);
+	}
+
+	/*
+	 * Set the sendPCI value based on the ActiveProtocol 
+	 */
+	switch (dwActiveProtocol)
+	{
+	case SCARD_PROTOCOL_T0:
+		pConnection->ioType = SCARD_PCI_T0;
+		break;
+	case SCARD_PROTOCOL_T1:
+		pConnection->ioType = SCARD_PCI_T1;
+		break;
+	default:
+		pConnection->ioType = SCARD_PCI_RAW;
+		break;
+	}
+
+	/*
+	 * Call SCardStatus, make sure the card information matches if it does 
+	 * not return an error.  If it does, copy it 
+	 */
+
+	rv = SCardStatus(pConnection->hCard, slotName,
+		&slotNameSize, &slotState, &slotProtocol, tokenId, &tokenIdLength);
+
+#ifdef MSC_DEBUG
+	DebugLogB("SCardStatus returns %s\n", pcsc_stringify_error(rv));
+#endif
+
+	if (pcscToMSC(rv) != MSC_SUCCESS)
+	{
+		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
+		pConnection->hCard = 0;
+		return pcscToMSC(rv);
+	}
+
+	if ((sharingMode == MSC_SHARE_DIRECT) && (slotState & SCARD_ABSENT))
+	{
+
+		/*
+		 * They asked for direct mode and no card is inserted so we are
+		 * done with this 
+		 */
+		pConnection->shareMode = sharingMode;
+		return MSC_SUCCESS;
+	}
+
+	if ((tokenIdLength != tokenStruct->tokenIdLength) ||
+		(strcmp(slotName, tokenStruct->slotName) != 0) ||
+		(memcmp(tokenId, tokenStruct->tokenId, tokenIdLength) != 0))
+	{
+	        DebugLogA("Internal inconsistent values, ID, slotName\n");
+		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
+		pConnection->hCard = 0;
+		return MSC_INCONSISTENT_STATUS;
+	}
+
+	memcpy(pConnection->tokenInfo.tokenId, tokenId, tokenIdLength);
+	pConnection->tokenInfo.tokenIdLength = tokenIdLength;
+	strncpy(pConnection->tokenInfo.slotName, tokenStruct->slotName,
+		MAX_READERNAME);
+	strncpy(pConnection->tokenInfo.tokenName, tokenStruct->tokenName,
+		MSC_MAXSIZE_TOKENAME);
+
+	/*
+	 * Load the library for the token 
+	 */
+	rv = TPLoadToken(pConnection);
+
+#ifdef MSC_DEBUG
+	DebugLogB("TPLoadToken returns %s\n", pcsc_stringify_error(rv));
+#endif
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
+		pConnection->hCard = 0;
+		return pcscToMSC(rv);
+	}
+
+	/*
+	 * Select the AID or initialization routine for the card 
+	 */
+	vInitFunction = pConnection->libPointers.pvfInitializePlugin;
+	vIdFunction = pConnection->libPointers.pvfIdentifyToken;
+
+	if (vInitFunction == 0)
+	{
+		DebugLogB("Error: Card service failure: %s\n",
+			"InitializePlugin function missing");
+		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
+		pConnection->hCard = 0;
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	if (vIdFunction == 0)
+	{
+		DebugLogB("Error: Card service failure: %s\n",
+			"IdentifyToken function missing");
+		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
+		pConnection->hCard = 0;
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	libPL_MSCInitializePlugin = (MSCLong32(*)(MSCLPTokenConnection))
+		vInitFunction;
+
+	libPL_MSCIdentifyToken = (MSCLong32(*)(MSCLPTokenConnection))
+		vIdFunction;
+
+	rv = (*libPL_MSCInitializePlugin) (pConnection);
+
+	if (rv != MSC_SUCCESS)
+	{
+	        SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
+	        if (pConnection->tokenLibHandle != 0)
+	        {
+		       TPUnloadToken(pConnection);
+		       pConnection->tokenLibHandle = 0;
+	        }
+	        pConnection->hCard = 0;
+	}
+
+	if (sharingMode != MSC_SHARE_DIRECT)
+	{
+
+	        if ((applicationName == 0) || (nameSize == 0))
+	        {
+		        /*
+		         * Use the default AID given by the Info.plist 
+		         */
+
+		         rv = (*libPL_MSCIdentifyToken) (pConnection);
+  	        } else
+	        {
+		        pConnection->tokenInfo.tokenAppLen = nameSize;
+		        memcpy(pConnection->tokenInfo.tokenApp, 
+			       applicationName, nameSize);
+		        rv = (*libPL_MSCIdentifyToken) (pConnection);
+	        }
+
+#ifdef MSC_DEBUG
+	DebugLogB("MSCIdentifyToken returns %s\n", msc_error(rv));
+#endif
+
+		if (rv != MSC_SUCCESS)
+		{
+			SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
+			if (pConnection->tokenLibHandle != 0)
+			{
+				TPUnloadToken(pConnection);
+				pConnection->tokenLibHandle = 0;
+			}
+			pConnection->hCard = 0;
+
+			if (rv == MSC_SHARING_VIOLATION)
+			{
+				return rv;
+			} else
+			{
+				return MSC_UNRECOGNIZED_TOKEN;
+			}
+		}
+	}
+
+	pConnection->shareMode = sharingMode;
+	return MSC_SUCCESS;
+}
+
+MSC_RV MSCReleaseConnection(MSCLPTokenConnection pConnection,
+			    MSCULong32 endAction)
+{
+
+	MSCLong32 rv = SCARD_S_SUCCESS;
+	MSCLong32(*libPL_MSCFinalizePlugin) (MSCLPTokenConnection);
+	MSCPVoid32 vFunction;
+
+	vFunction = 0;
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (pConnection->tokenLibHandle == 0 ||
+		pConnection->hContext == 0 || pConnection->hCard == 0)
+	{
+		return MSC_INVALID_HANDLE;
+	}
+
+	/*
+	 * Select finalization routine for the token plugin 
+	 */
+	vFunction = pConnection->libPointers.pvfFinalizePlugin;
+
+	if (vFunction == 0)
+	{
+		DebugLogB("Error: Card service failure: %s\n",
+			"FinalizePlugin function missing");
+		return MSC_INTERNAL_ERROR;
+	}
+
+	libPL_MSCFinalizePlugin = (MSCLong32(*)(MSCLPTokenConnection))
+		vFunction;
+
+	/*
+	 * Stop and clean up the plugin 
+	 */
+	rv = (*libPL_MSCFinalizePlugin) (pConnection);
+
+	/*
+	 * Disconnect from the token 
+	 */
+	if (pConnection->hCard != 0)
+	{
+		rv = SCardDisconnect(pConnection->hCard, endAction);
+		if (pcscToMSC(rv) != MSC_SUCCESS)
+		{
+			return pcscToMSC(rv);
+		}
+	}
+
+	/*
+	 * Unload the token driver 
+	 */
+	if (pConnection->tokenLibHandle != 0)
+	{
+		rv = TPUnloadToken(pConnection);
+		pConnection->tokenLibHandle = 0;
+	}
+
+	pConnection->tokenLibHandle = 0;
+	pConnection->hCard = 0;
+	pConnection->hContext = 0;
+	pConnection->shareMode = 0;
+
+	return MSC_SUCCESS;
+}
+
+MSC_RV MSCWaitForTokenEvent(MSCLPTokenInfo tokenArray,
+			    MSCULong32 arraySize, 
+			    MSCULong32 timeoutValue)
+{
+
+	MSCLong32 rv, rt;
+	LPSCARD_READERSTATE_A rgReaderStates;
+	MSCTokenInfo tokenInfo;
+	int i;
+
+	rgReaderStates = 0;
+
+	/*
+	 * Allocate array of SCARD_READERSTATE_A structures, set UNAWARE on
+	 * all of the structures to get the current status and then send them
+	 * to GetStatusChange for blocking event 
+	 */
+
+	if (arraySize == 0)
+	{
+		return MSC_SUCCESS;
+	} else if (arraySize > MSC_MAXSIZE_TOKENARRAY)
+	{
+		return MSC_INSUFFICIENT_BUFFER;
+	}
+
+	/*
+	 * Set up the initial connection to the resource manager 
+	 */
+
+	mscLockThread();
+	if (localHContext == 0)
+	{
+		rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0,
+			&localHContext);
+		if (pcscToMSC(rv) != MSC_SUCCESS)
+		{
+			localHContext = 0;
+			mscUnLockThread();
+			return pcscToMSC(rv);
+		}
+	}
+	mscUnLockThread();
+
+	rgReaderStates = (LPSCARD_READERSTATE_A)
+		malloc(sizeof(SCARD_READERSTATE_A) * arraySize);
+
+	if (rgReaderStates == 0)
+	{
+		return MSC_INTERNAL_ERROR;
+	}
+
+	for (i = 0; i < arraySize; i++)
+	{
+		/*
+		 * Make sure they don't pass an empty structure 
+		 */
+		if (strlen(tokenArray[i].slotName) == 0)
+		{
+			free(rgReaderStates);
+			return MSC_INVALID_PARAMETER;
+		}
+
+		rgReaderStates[i].szReader = tokenArray[i].slotName;
+		rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
+		rgReaderStates[i].dwEventState = 0;
+	}
+
+	rv = SCardGetStatusChange(localHContext, timeoutValue,
+		rgReaderStates, arraySize);
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		free(rgReaderStates);
+		return pcscToMSC(rv);
+	}
+
+	for (i = 0; i < arraySize; i++)
+	{
+		if (tokenArray[i].tokenState == 0)
+		{
+			rgReaderStates[i].dwCurrentState =
+				rgReaderStates[i].dwEventState;
+		} else if (tokenArray[i].tokenState == MSC_STATE_UNAWARE)
+		{
+			rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
+		} else
+		{
+			rgReaderStates[i].dwCurrentState = tokenArray[i].tokenState;
+		}
+		rgReaderStates[i].dwEventState = 0;
+	}
+
+	rv = SCardGetStatusChange(localHContext, timeoutValue,
+		rgReaderStates, arraySize);
+
+	for (i = 0; i < arraySize; i++)
+	{
+		tokenArray[i].tokenState = rgReaderStates[i].dwEventState;
+
+		if (tokenArray[i].tokenState & MSC_STATE_CHANGED)
+		{
+			/*
+			 * If it is removed, we need to update the names/etc 
+			 */
+			if (tokenArray[i].tokenState & MSC_STATE_EMPTY)
+			{
+				memset(tokenArray[i].tokenId, 0x00, MAX_ATR_SIZE);
+				tokenArray[i].tokenIdLength = 0;
+				tokenArray[i].tokenType = MSC_TOKEN_TYPE_REMOVED;
+				strncpy(tokenArray[i].tokenName, MSC_TOKEN_EMPTY_STR,
+					MSC_MAXSIZE_TOKENAME);
+			} else if (tokenArray[i].tokenState & MSC_STATE_PRESENT)
+			{
+				memcpy(tokenArray[i].tokenId, rgReaderStates[i].rgbAtr,
+					rgReaderStates[i].cbAtr);
+				tokenArray[i].tokenIdLength = rgReaderStates[i].cbAtr;
+
+				rt = TPSearchBundlesForAtr(rgReaderStates[i].rgbAtr,
+					rgReaderStates[i].cbAtr, &tokenInfo);
+				/*
+				 * Successfully found 
+				 */
+				if (rt == 0)
+				{
+					tokenArray[i].tokenType = MSC_TOKEN_TYPE_KNOWN;
+					strncpy(tokenArray[i].tokenName, tokenInfo.tokenName,
+						MSC_MAXSIZE_TOKENAME);
+				} else
+				{
+					tokenArray[i].tokenType = MSC_TOKEN_TYPE_UNKNOWN;
+					strncpy(tokenArray[i].tokenName, MSC_TOKEN_UNKNOWN_STR,
+						MSC_MAXSIZE_TOKENAME);
+				}
+			}
+		}
+	}
+
+	free(rgReaderStates);
+	return pcscToMSC(rv);
+}
+
+MSC_RV MSCCancelEventWait(void)
+{
+
+	MSCLong32 rv;
+
+	rv = SCardCancel(localHContext);
+
+	return pcscToMSC(rv);
+}
+
+/************************ Start of Callbacks ****************************/
+#ifdef USE_THREAD_SAFETY
+void *_MSCEventThread(void *arg)
+{
+
+	MSCLong32 rv;
+	MSCLPEventWaitInfo evlist;
+	MSCLong32 curToken;
+
+	if (arg == NULL)
+	{
+		SYS_ThreadExit(NULL);
+	}
+
+	evlist = (MSCLPEventWaitInfo) arg;
+	blockingContext = MSC_BLOCKSTATUS_BLOCKING;
+
+	while (1)
+	{
+		rv = MSCWaitForTokenEvent(evlist->tokenArray, 
+					  evlist->arraySize,
+					  MSC_NO_TIMEOUT);
+
+		if (rv == MSC_SUCCESS)
+		{
+		       (evlist->callBack) (evlist->tokenArray, 
+					   evlist->arraySize,
+					   evlist->appData);
+		} else {
+		       break;
+
+		}
+		
+		if (blockingContext == MSC_BLOCKSTATUS_CANCELLING)
+		{
+		        break;
+		}
+	}
+
+	for (curToken = 0; curToken < evlist->arraySize; curToken++)
+	{
+	        if (evlist->tokenArray[curToken].addParams)
+	        {
+		        free(evlist->tokenArray[curToken].addParams);
+	        }
+	}
+	
+
+	free(evlist);
+	blockingContext = MSC_BLOCKSTATUS_RESUME;
+	SYS_ThreadExit(&rv);
+
+	return NULL;
+}
+
+MSC_RV MSCCallbackForTokenEvent(MSCLPTokenInfo tokenArray,
+				MSCULong32 arraySize, 
+				MSCCallBack callBack, 
+				MSCPVoid32 appData)
+{
+	MSCLPEventWaitInfo evlist;
+	MSCULong32 curToken;
+
+	/*
+	 * Create the event wait list 
+	 */
+	evlist = (MSCLPEventWaitInfo) malloc(sizeof(MSCEventWaitInfo));
+
+	if (evlist == NULL)
+	{
+		return MSC_INTERNAL_ERROR;
+	}
+
+	evlist->arraySize = arraySize;
+	evlist->tokenArray = malloc(sizeof(MSCTokenInfo) * arraySize);
+	evlist->appData = appData;
+	evlist->callBack = callBack;
+
+	if (evlist->tokenArray == NULL)
+	{
+		free(evlist);
+		return MSC_INTERNAL_ERROR;
+	}
+
+	mscLockThread();
+	memcpy(evlist->tokenArray, tokenArray,
+		sizeof(MSCTokenInfo) * arraySize);
+
+	/*
+	 * Copy the "extra" data 
+	 */
+	for (curToken = 0; curToken < arraySize; curToken++)
+	{
+		if (tokenArray[curToken].addParams != NULL)
+		{
+			evlist->tokenArray[curToken].addParams =
+				malloc(evlist->tokenArray[curToken].addParamsSize);
+			memcpy((void *) (evlist->tokenArray[curToken].addParams),
+				&tokenArray[curToken],
+				evlist->tokenArray[curToken].addParamsSize);
+
+		}
+	}
+	mscUnLockThread();
+
+	if (SYS_ThreadCreate(&callbackThread, THREAD_ATTR_DEFAULT, _MSCEventThread, 
+			     (void *) evlist) == 0)
+	{
+		return MSC_INTERNAL_ERROR;
+	}
+
+	return MSC_SUCCESS;
+}
+
+MSC_RV MSCCallbackCancelEvent()
+{
+
+        LONG rv;
+
+        /* Release the thread and stop the GetStatusChange */
+        if (blockingContext == MSC_BLOCKSTATUS_BLOCKING)
+	{  
+                blockingContext = MSC_BLOCKSTATUS_CANCELLING;
+	        rv = MSCCancelEventWait();
+
+		SYS_ThreadJoin(&callbackThread, 0);
+
+	} 
+
+      return MSC_SUCCESS;
+}
+
+#endif
+/************************** End of Callbacks *****************************/
+
+MSC_RV MSCBeginTransaction(MSCLPTokenConnection pConnection)
+{
+
+	MSCLong32 rv;
+	MSCLong32 ret;
+
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	while (1)
+	{
+		rv = SCardBeginTransaction(pConnection->hCard);
+		ret = pcscToMSC(rv);
+
+		if (ret == MSC_SUCCESS)
+			break;
+		if (ret == MSC_TOKEN_RESET)
+		{
+		        pConnection->tokenInfo.tokenType |= 
+			  MSC_TOKEN_TYPE_RESET;
+			ret = MSCReEstablishConnection(pConnection);
+			if (ret != MSC_SUCCESS)
+				break;
+			continue;
+		} else if (ret == MSC_TOKEN_REMOVED)
+		{
+		        pConnection->tokenInfo.tokenType = 
+			  MSC_TOKEN_TYPE_REMOVED;
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+MSC_RV MSCEndTransaction(MSCLPTokenConnection pConnection,
+	MSCULong32 endAction)
+{
+
+	MSCLong32 rv;
+	MSCLong32 ret;
+
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	while (1)
+	{
+		rv = SCardEndTransaction(pConnection->hCard, endAction);
+		ret = pcscToMSC(rv);
+
+		if (ret == MSC_SUCCESS)
+			break;
+		if (ret == MSC_TOKEN_RESET)
+		{
+		        pConnection->tokenInfo.tokenType |= 
+			  MSC_TOKEN_TYPE_RESET;
+			ret = MSCReEstablishConnection(pConnection);
+			if (ret != MSC_SUCCESS)
+				break;
+			continue;
+		} else if (ret == MSC_TOKEN_REMOVED)
+		{
+		        pConnection->tokenInfo.tokenType = 
+			  MSC_TOKEN_TYPE_REMOVED;
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+MSC_RV MSCWriteFramework(MSCLPTokenConnection pConnection,
+	MSCLPInitTokenParams pInitParams)
+{
+
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCWriteFramework) (MSCLPTokenConnection,
+		MSCLPInitTokenParams);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfWriteFramework;
+
+	if (vFunction != 0)
+	{
+		libMSCWriteFramework = (MSCLong32(*)(MSCLPTokenConnection,
+				MSCLPInitTokenParams)) vFunction;
+		rv = (*libMSCWriteFramework) (pConnection, pInitParams);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+/*
+ * Real MSC functions 
+ */
+
+MSC_RV MSCGetStatus(MSCLPTokenConnection pConnection,
+	MSCLPStatusInfo pStatusInfo)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCGetStatus) (MSCLPTokenConnection, MSCLPStatusInfo);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfGetStatus;
+
+	if (vFunction != 0)
+	{
+		libMSCGetStatus = (MSCLong32(*)(MSCLPTokenConnection,
+				MSCLPStatusInfo)) vFunction;
+		rv = (*libMSCGetStatus) (pConnection, pStatusInfo);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCGetCapabilities(MSCLPTokenConnection pConnection, MSCULong32 Tag,
+	MSCPUChar8 Value, MSCPULong32 Length)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCGetCapabilities) (MSCLPTokenConnection, MSCULong32,
+		MSCPUChar8, MSCPULong32);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfGetCapabilities;
+
+	if (vFunction != 0)
+	{
+		libMSCGetCapabilities =
+			(MSCLong32(*)(MSCLPTokenConnection, MSCULong32, MSCPUChar8,
+				MSCPULong32)) vFunction;
+		rv = (*libMSCGetCapabilities) (pConnection, Tag, Value, Length);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCExtendedFeature(MSCLPTokenConnection pConnection,
+	MSCULong32 extFeature, MSCPUChar8 outData,
+	MSCULong32 outLength, MSCPUChar8 inData, MSCPULong32 inLength)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCExtendedFeature) (MSCLPTokenConnection, MSCULong32,
+		MSCPUChar8, MSCULong32, MSCPUChar8, MSCPULong32);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfExtendedFeature;
+
+	if (vFunction != 0)
+	{
+		libMSCExtendedFeature =
+			(MSCLong32(*)(MSCLPTokenConnection, MSCULong32, MSCPUChar8,
+				MSCULong32, MSCPUChar8, MSCPULong32)) vFunction;
+		rv = (*libMSCExtendedFeature) (pConnection, extFeature, outData,
+			outLength, inData, inLength);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCGenerateKeys(MSCLPTokenConnection pConnection,
+	MSCUChar8 prvKeyNum, MSCUChar8 pubKeyNum, MSCLPGenKeyParams pParams)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCGenerateKeys) (MSCLPTokenConnection, MSCUChar8,
+		MSCUChar8, MSCLPGenKeyParams);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfGenerateKeys;
+
+	if (vFunction != 0)
+	{
+		libMSCGenerateKeys = (MSCLong32(*)(MSCLPTokenConnection,
+						   MSCUChar8, MSCUChar8, 
+						   MSCLPGenKeyParams)) 
+		  vFunction;
+		rv = (*libMSCGenerateKeys) (pConnection, prvKeyNum, pubKeyNum,
+					    pParams);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCImportKey(MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+                    MSCLPKeyACL pKeyACL, MSCPUChar8 pKeyBlob,MSCULong32 keyBlobSize, 
+		    MSCLPKeyPolicy keyPolicy, MSCPVoid32 pAddParams, 
+		    MSCUChar8 addParamsSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCImportKey) (MSCLPTokenConnection, MSCUChar8, 
+                                     MSCLPKeyACL, MSCPUChar8, 
+				     MSCULong32, MSCLPKeyPolicy, MSCPVoid32,
+				     MSCUChar8);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfImportKey;
+
+	if (vFunction != 0)
+	{
+		libMSCImportKey = (MSCLong32(*)(MSCLPTokenConnection, 
+						MSCUChar8, 
+						MSCLPKeyACL, MSCPUChar8, 
+						MSCULong32, MSCLPKeyPolicy, 
+						MSCPVoid32, MSCUChar8)) 
+		  vFunction;
+
+		rv = (*libMSCImportKey) (pConnection, keyNum,  
+					 pKeyACL, pKeyBlob, keyBlobSize, 
+					 keyPolicy, pAddParams, addParamsSize);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCExportKey(MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
+		    MSCPUChar8 pKeyBlob, MSCPULong32 keyBlobSize,
+		    MSCPVoid32 pAddParams, MSCUChar8 addParamsSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCExportKey) (MSCLPTokenConnection, MSCUChar8,
+		MSCPUChar8, MSCPULong32, MSCPVoid32, MSCUChar8);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfExportKey;
+
+	if (vFunction != 0)
+	{
+		libMSCExportKey = (MSCLong32(*)(MSCLPTokenConnection, 
+						MSCUChar8, MSCPUChar8, 
+						MSCPULong32, MSCPVoid32, 
+						MSCUChar8)) vFunction;
+
+		rv = (*libMSCExportKey) (pConnection, keyNum, pKeyBlob,
+			keyBlobSize, pAddParams, addParamsSize);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCComputeCrypt(MSCLPTokenConnection pConnection,
+		       MSCLPCryptInit cryptInit, MSCPUChar8 pInputData,
+		       MSCULong32 inputDataSize, MSCPUChar8 pOutputData,
+		       MSCPULong32 outputDataSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCComputeCrypt) (MSCLPTokenConnection, MSCLPCryptInit,
+					MSCPUChar8, MSCULong32, MSCPUChar8, 
+					MSCPULong32);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfComputeCrypt;
+
+	if (vFunction != 0)
+	{
+		libMSCComputeCrypt =
+			(MSCLong32(*)(MSCLPTokenConnection, MSCLPCryptInit, 
+				      MSCPUChar8, MSCULong32, MSCPUChar8, 
+				      MSCPULong32)) vFunction;
+		rv = (*libMSCComputeCrypt) (pConnection, cryptInit, pInputData,
+					    inputDataSize, pOutputData, 
+					    outputDataSize);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCExtAuthenticate(MSCLPTokenConnection pConnection,
+			  MSCUChar8 keyNum, MSCUChar8 cipherMode, 
+			  MSCUChar8 cipherDirection,
+			  MSCPUChar8 pData, MSCULong32 dataSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCExtAuthenticate) (MSCLPTokenConnection, MSCUChar8,
+					   MSCUChar8, MSCUChar8, MSCPUChar8, 
+					   MSCULong32);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfExtAuthenticate;
+
+	if (vFunction != 0)
+	{
+		libMSCExtAuthenticate =
+			(MSCLong32(*)(MSCLPTokenConnection, MSCUChar8, 
+				      MSCUChar8, MSCUChar8, MSCPUChar8, 
+				      MSCULong32)) vFunction;
+		rv = (*libMSCExtAuthenticate) (pConnection, keyNum, cipherMode,
+			cipherDirection, pData, dataSize);
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCListKeys(MSCLPTokenConnection pConnection, MSCUChar8 seqOption,
+		   MSCLPKeyInfo pKeyInfo)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCListKeys) (MSCLPTokenConnection, MSCUChar8,
+		MSCLPKeyInfo);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfListKeys;
+
+	if (vFunction != 0)
+	{
+		libMSCListKeys = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
+					       MSCLPKeyInfo)) vFunction;
+		rv = (*libMSCListKeys) (pConnection, seqOption, pKeyInfo);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCCreatePIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+	MSCUChar8 pinAttempts, MSCPUChar8 pPinCode,
+	MSCULong32 pinCodeSize, MSCPUChar8 pUnblockCode,
+	MSCUChar8 unblockCodeSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCCreatePIN) (MSCLPTokenConnection, MSCUChar8,
+		MSCUChar8, MSCPUChar8, MSCULong32, MSCPUChar8, MSCUChar8);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfCreatePIN;
+
+	if (vFunction != 0)
+	{
+		libMSCCreatePIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
+				MSCUChar8, MSCPUChar8,
+				MSCULong32, MSCPUChar8, MSCUChar8)) vFunction;
+		rv = (*libMSCCreatePIN) (pConnection, pinNum, pinAttempts,
+			pPinCode, pinCodeSize, pUnblockCode, unblockCodeSize);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCVerifyPIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+	MSCPUChar8 pPinCode, MSCULong32 pinCodeSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCVerifyPIN) (MSCLPTokenConnection, MSCUChar8,
+		MSCPUChar8, MSCULong32);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfVerifyPIN;
+
+	if (vFunction != 0)
+	{
+		libMSCVerifyPIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
+				MSCPUChar8, MSCULong32)) vFunction;
+		rv = (*libMSCVerifyPIN) (pConnection, pinNum, pPinCode,
+			pinCodeSize);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCChangePIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+	MSCPUChar8 pOldPinCode, MSCUChar8 oldPinCodeSize,
+	MSCPUChar8 pNewPinCode, MSCUChar8 newPinCodeSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCChangePIN) (MSCLPTokenConnection, MSCUChar8,
+		MSCPUChar8, MSCUChar8, MSCPUChar8, MSCUChar8);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfChangePIN;
+
+	if (vFunction != 0)
+	{
+		libMSCChangePIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
+				MSCPUChar8, MSCUChar8, MSCPUChar8, MSCUChar8)) vFunction;
+		rv = (*libMSCChangePIN) (pConnection, pinNum, pOldPinCode,
+			oldPinCodeSize, pNewPinCode, newPinCodeSize);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCUnblockPIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
+	MSCPUChar8 pUnblockCode, MSCULong32 unblockCodeSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCUnblockPIN) (MSCLPTokenConnection, MSCUChar8,
+		MSCPUChar8, MSCULong32);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfUnblockPIN;
+
+	if (vFunction != 0)
+	{
+		libMSCUnblockPIN = (MSCLong32(*)(MSCLPTokenConnection,
+				MSCUChar8, MSCPUChar8, MSCULong32)) vFunction;
+		rv = (*libMSCUnblockPIN) (pConnection, pinNum, pUnblockCode,
+			unblockCodeSize);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCListPINs(MSCLPTokenConnection pConnection,
+	MSCPUShort16 pPinBitMask)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCListPINs) (MSCLPTokenConnection, MSCPUShort16);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfListPINs;
+
+	if (vFunction != 0)
+	{
+		libMSCListPINs = (MSCLong32(*)(MSCLPTokenConnection,
+				MSCPUShort16)) vFunction;
+		rv = (*libMSCListPINs) (pConnection, pPinBitMask);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCCreateObject(MSCLPTokenConnection pConnection,
+	MSCString objectID, MSCULong32 objectSize, MSCLPObjectACL pObjectACL)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCCreateObject) (MSCLPTokenConnection, MSCString,
+		MSCULong32, MSCLPObjectACL);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfCreateObject;
+
+	if (vFunction != 0)
+	{
+		libMSCCreateObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
+				MSCULong32, MSCLPObjectACL)) vFunction;
+		rv = (*libMSCCreateObject) (pConnection, objectID, objectSize,
+			pObjectACL);
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCDeleteObject(MSCLPTokenConnection pConnection,
+	MSCString objectID, MSCUChar8 zeroFlag)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCDeleteObject) (MSCLPTokenConnection, MSCString,
+		MSCUChar8);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfDeleteObject;
+
+	if (vFunction != 0)
+	{
+		libMSCDeleteObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
+				MSCUChar8)) vFunction;
+		rv = (*libMSCDeleteObject) (pConnection, objectID, zeroFlag);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCWriteObject(MSCLPTokenConnection pConnection,
+		      MSCString objectID, MSCULong32 offSet,
+		      MSCPUChar8 pInputData, MSCULong32 dataSize,
+		      LPRWEventCallback rwCallback, MSCPVoid32 addParams)
+{
+	MSC_RV rv = MSC_UNSPECIFIED_ERROR;
+	MSCULong32 objectSize;
+	int totalSteps, stepInterval;
+	MSC_RV(*callBackFunction) (void *, int);
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCWriteObject) (MSCLPTokenConnection, MSCString,
+		MSCULong32, MSCPUChar8, MSCUChar8);
+	int i;
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction        = pConnection->libPointers.pvfWriteObject;
+	callBackFunction = (MSC_RV(*)(void *, int)) rwCallback;
+	objectSize       = dataSize;
+
+	if (vFunction == 0)
+	{
+	        return MSC_UNSUPPORTED_FEATURE;
+        }
+
+	libMSCWriteObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
+					  MSCULong32, MSCPUChar8, MSCUChar8)) 
+	  vFunction;
+
+	/*
+	 * Figure out the number of steps total and present this in a percent
+	 * step basis 
+	 */
+
+	totalSteps = objectSize / MSC_SIZEOF_KEYPACKET + 1;
+	stepInterval = MSC_PERCENT_STEPSIZE / totalSteps;
+
+	for (i = 0; i < objectSize / MSC_SIZEOF_KEYPACKET; i++)
+	{
+	  rv = (*libMSCWriteObject) (pConnection, objectID, 
+				     i * MSC_SIZEOF_KEYPACKET + offSet,
+				     &pInputData[i * MSC_SIZEOF_KEYPACKET], 
+				     MSC_SIZEOF_KEYPACKET);				     
+		if (rv != MSC_SUCCESS)
+		{
+			return rv;
+		}
+
+		if (rwCallback)
+		{
+			if ((*callBackFunction) (addParams,
+			      stepInterval * i) == MSC_CANCELLED)
+			{
+				return MSC_CANCELLED;
+			}
+		}
+	}
+
+	if (objectSize % MSC_SIZEOF_KEYPACKET)
+	{
+
+	  rv = (*libMSCWriteObject) (pConnection, objectID, 
+				     i * MSC_SIZEOF_KEYPACKET + offSet,
+				     &pInputData[i * MSC_SIZEOF_KEYPACKET], 
+				     objectSize % MSC_SIZEOF_KEYPACKET);
+
+		if (rv != MSC_SUCCESS)
+		{
+			return rv;
+		}
+	}
+
+	if (rwCallback)
+	{
+		(*callBackFunction) (addParams, MSC_PERCENT_STEPSIZE);
+	}
+
+	return rv;
+}
+
+MSC_RV MSCReadObject(MSCLPTokenConnection pConnection,
+		     MSCString objectID, MSCULong32 offSet,
+		     MSCPUChar8 pOutputData, MSCULong32 dataSize,
+		     LPRWEventCallback rwCallback, 
+		     MSCPVoid32 addParams)
+{
+
+        MSC_RV rv = MSC_UNSPECIFIED_ERROR;
+	MSCULong32 objectSize;
+	int totalSteps, stepInterval;
+	MSC_RV(*callBackFunction) (void *, int);
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCReadObject) (MSCLPTokenConnection, MSCString,
+		MSCULong32, MSCPUChar8, MSCUChar8);
+	int i;
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction        = pConnection->libPointers.pvfReadObject;
+	callBackFunction = (MSC_RV(*)(void *, int)) rwCallback;
+	objectSize       = dataSize;
+
+	if (vFunction == 0)
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	libMSCReadObject = (MSCLong32(*)(MSCLPTokenConnection, 
+					 MSCString, MSCULong32, 
+					 MSCPUChar8, MSCUChar8)) 
+	  vFunction;
+
+	/*
+	 * Figure out the number of steps total and present this in a percent
+	 * step basis 
+	 */
+
+	totalSteps = objectSize / MSC_SIZEOF_KEYPACKET + 1;
+	stepInterval = MSC_PERCENT_STEPSIZE / totalSteps;
+
+	for (i = 0; i < objectSize / MSC_SIZEOF_KEYPACKET; i++)
+	{
+	        rv = (*libMSCReadObject) (pConnection, objectID, 
+				    i * MSC_SIZEOF_KEYPACKET + offSet,
+				    &pOutputData[i * MSC_SIZEOF_KEYPACKET], 
+				    MSC_SIZEOF_KEYPACKET);
+
+		if (rv != MSC_SUCCESS)
+		{
+			return rv;
+		}
+
+		if (rwCallback)
+		{
+			if ((*callBackFunction) (addParams,
+					stepInterval * i) == MSC_CANCELLED)
+			{
+				return MSC_CANCELLED;
+			}
+		}
+	}
+
+	if (objectSize % MSC_SIZEOF_KEYPACKET)
+	{
+	        rv = (*libMSCReadObject) (pConnection, objectID, 
+				    i * MSC_SIZEOF_KEYPACKET + offSet,
+				    &pOutputData[i * MSC_SIZEOF_KEYPACKET], 
+				    objectSize % MSC_SIZEOF_KEYPACKET);
+
+		if (rv != MSC_SUCCESS)
+		{
+			return rv;
+		}
+	}
+
+	if (rwCallback)
+	{
+		(*callBackFunction) (addParams, MSC_PERCENT_STEPSIZE);
+	}
+
+	return rv;
+}
+
+MSC_RV MSCListObjects(MSCLPTokenConnection pConnection,
+	MSCUChar8 seqOption, MSCLPObjectInfo pObjectInfo)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCListObjects) (MSCLPTokenConnection, MSCUChar8,
+		MSCLPObjectInfo);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfListObjects;
+
+	if (vFunction != 0)
+	{
+		libMSCListObjects = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
+				MSCLPObjectInfo)) vFunction;
+		rv = (*libMSCListObjects) (pConnection, seqOption, pObjectInfo);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCLogoutAll(MSCLPTokenConnection pConnection)
+{
+
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCLogoutAll) (MSCLPTokenConnection);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfLogoutAll;
+
+	if (vFunction != 0)
+	{
+		libMSCLogoutAll = (MSCLong32(*)(MSCLPTokenConnection)) vFunction;
+		rv = (*libMSCLogoutAll) (pConnection);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCGetChallenge(MSCLPTokenConnection pConnection, MSCPUChar8 pSeed,
+	MSCUShort16 seedSize, MSCPUChar8 pRandomData,
+	MSCUShort16 randomDataSize)
+{
+	MSCLong32 rv;
+	MSCPVoid32 vFunction;
+	MSCLong32(*libMSCGetChallenge) (MSCLPTokenConnection, MSCPUChar8,
+		MSCUShort16, MSCPUChar8, MSCUShort16);
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	vFunction = pConnection->libPointers.pvfGetChallenge;
+
+	if (vFunction != 0)
+	{
+		libMSCGetChallenge = (MSCLong32(*)(MSCLPTokenConnection,
+				MSCPUChar8, MSCUShort16,
+				MSCPUChar8, MSCUShort16)) vFunction;
+		rv = (*libMSCGetChallenge) (pConnection, pSeed, seedSize,
+			pRandomData, randomDataSize);
+
+	} else
+	{
+		return MSC_UNSUPPORTED_FEATURE;
+	}
+
+	return rv;
+}
+
+MSC_RV MSCGetKeyAttributes(MSCLPTokenConnection pConnection,
+			   MSCUChar8 keyNumber, MSCLPKeyInfo pKeyInfo)
+{
+
+	MSC_RV rv;
+	MSCKeyInfo keyInfo;
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	rv = MSCListKeys(pConnection, MSC_SEQUENCE_RESET, &keyInfo);
+
+	if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
+	{
+		return rv;
+	}
+
+	if (rv == MSC_SEQUENCE_END)
+	{
+		return MSC_INVALID_PARAMETER;
+	}
+
+	if (keyNumber == keyInfo.keyNum)
+	{
+		pKeyInfo->keyNum = keyInfo.keyNum;
+		pKeyInfo->keyType = keyInfo.keyType;
+		pKeyInfo->keySize = keyInfo.keySize;
+
+		pKeyInfo->keyPolicy.cipherMode = keyInfo.keyPolicy.cipherMode;
+		pKeyInfo->keyPolicy.cipherDirection =
+			keyInfo.keyPolicy.cipherDirection;
+
+		pKeyInfo->keyACL.readPermission = 
+		  keyInfo.keyACL.readPermission;
+		pKeyInfo->keyACL.writePermission = 
+		  keyInfo.keyACL.writePermission;
+		pKeyInfo->keyACL.usePermission = 
+		  keyInfo.keyACL.usePermission;
+
+		return MSC_SUCCESS;
+	}
+
+	do
+	{
+		rv = MSCListKeys(pConnection, MSC_SEQUENCE_NEXT, &keyInfo);
+		if (keyNumber == keyInfo.keyNum)
+			break;
+	}
+	while (rv == MSC_SUCCESS);
+
+	if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
+	{
+		return rv;
+	}
+
+	if (rv == MSC_SEQUENCE_END)
+	{
+		return MSC_INVALID_PARAMETER;
+	}
+
+	pKeyInfo->keyNum = keyInfo.keyNum;
+	pKeyInfo->keyType = keyInfo.keyType;
+	pKeyInfo->keySize = keyInfo.keySize;
+
+	pKeyInfo->keyPolicy.cipherMode = keyInfo.keyPolicy.cipherMode;
+	pKeyInfo->keyPolicy.cipherDirection =
+		keyInfo.keyPolicy.cipherDirection;
+
+	pKeyInfo->keyACL.readPermission = keyInfo.keyACL.readPermission;
+	pKeyInfo->keyACL.writePermission = keyInfo.keyACL.writePermission;
+	pKeyInfo->keyACL.usePermission = keyInfo.keyACL.usePermission;
+
+	return MSC_SUCCESS;
+}
+
+MSC_RV MSCGetObjectAttributes(MSCLPTokenConnection pConnection,
+	MSCString objectID, MSCLPObjectInfo pObjectInfo)
+{
+
+	MSC_RV rv;
+	MSCObjectInfo objInfo;
+
+	if (pConnection == NULL)
+		return MSC_INVALID_PARAMETER;
+	if (localHContext == 0)
+		return MSC_INTERNAL_ERROR;
+
+	rv = MSCListObjects(pConnection, MSC_SEQUENCE_RESET, &objInfo);
+
+	if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
+	{
+		return rv;
+	}
+
+	if (rv == MSC_SEQUENCE_END)
+	{
+		return MSC_OBJECT_NOT_FOUND;
+	}
+
+	if (strncmp(objectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0)
+	{
+		pObjectInfo->objectSize = objInfo.objectSize;
+		pObjectInfo->objectACL.readPermission =
+			objInfo.objectACL.readPermission;
+		pObjectInfo->objectACL.writePermission =
+			objInfo.objectACL.writePermission;
+		pObjectInfo->objectACL.deletePermission =
+			objInfo.objectACL.deletePermission;
+		strncpy(pObjectInfo->objectID, objectID, MSC_MAXSIZE_OBJID);
+		return MSC_SUCCESS;
+	}
+
+	do
+	{
+		rv = MSCListObjects(pConnection, MSC_SEQUENCE_NEXT, &objInfo);
+		if (strncmp(objectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0)
+			break;
+	}
+	while (rv == MSC_SUCCESS);
+
+	if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
+	{
+		return rv;
+	}
+
+	if (rv == MSC_SEQUENCE_END)
+	{
+		return MSC_OBJECT_NOT_FOUND;
+	}
+
+	pObjectInfo->objectSize = objInfo.objectSize;
+	pObjectInfo->objectACL.readPermission =
+		objInfo.objectACL.readPermission;
+	pObjectInfo->objectACL.writePermission =
+		objInfo.objectACL.writePermission;
+	pObjectInfo->objectACL.deletePermission =
+		objInfo.objectACL.deletePermission;
+	strncpy(pObjectInfo->objectID, objectID, MSC_MAXSIZE_OBJID);
+
+	return MSC_SUCCESS;
+}
+
+MSC_RV MSCReadAllocateObject(MSCLPTokenConnection pConnection,
+			     MSCString objectID, MSCPUChar8 * pOutputData,
+			     MSCPULong32 dataSize, 
+			     LPRWEventCallback rwCallback, 
+			     MSCPVoid32 addParams)
+{
+    MSC_RV rv;
+    MSCObjectInfo objInfo;
+    MSCULong32 objectSize;
+    MSCPUChar8  data = NULL;
+    
+    if (pConnection == NULL)
+        return MSC_INVALID_PARAMETER;
+     if (localHContext == 0)
+         return MSC_INTERNAL_ERROR;
+
+    if (pOutputData == 0)
+    {
+        return MSC_INVALID_PARAMETER;
+    }
+
+    *dataSize = 0;
+    *pOutputData = 0;
+
+    rv = MSCGetObjectAttributes(pConnection, objectID, &objInfo);
+    if (rv == MSC_SUCCESS) 
+    {
+        objectSize = objInfo.objectSize;
+        data = (MSCPUChar8) malloc(sizeof(MSCUChar8) * objectSize);
+        if(data)
+        {
+            rv =  MSCReadObject(pConnection, objectID, 0, data,
+                     objectSize, rwCallback, addParams);
+            
+            if (rv == MSC_SUCCESS)
+            {
+                *dataSize = objectSize;
+                *pOutputData = data;
+            }
+            else
+            {
+                rv = MSC_INTERNAL_ERROR;
+                free(data);
+            }
+        }
+    }
+
+    return rv;
+}
+
+
+MSC_RV pcscToMSC(MSCLong32 pcscCode)
+{
+
+	switch (pcscCode)
+	{
+	case SCARD_S_SUCCESS:
+		return MSC_SUCCESS;
+	case SCARD_E_INVALID_HANDLE:
+		return MSC_INVALID_HANDLE;
+	case SCARD_E_SHARING_VIOLATION:
+		return MSC_SHARING_VIOLATION;
+	case SCARD_W_REMOVED_CARD:
+		return MSC_TOKEN_REMOVED;
+	case SCARD_E_NO_SMARTCARD:
+		return MSC_TOKEN_REMOVED;
+	case SCARD_W_RESET_CARD:
+		return MSC_TOKEN_RESET;
+	case SCARD_W_INSERTED_CARD:
+		return MSC_TOKEN_INSERTED;
+	case SCARD_E_NO_SERVICE:
+		return MSC_SERVICE_UNRESPONSIVE;
+	case SCARD_E_UNKNOWN_CARD:
+	case SCARD_W_UNSUPPORTED_CARD:
+	case SCARD_E_CARD_UNSUPPORTED:
+		return MSC_UNRECOGNIZED_TOKEN;
+	case SCARD_E_INVALID_PARAMETER:
+	case SCARD_E_INVALID_VALUE:
+	case SCARD_E_UNKNOWN_READER:
+	case SCARD_E_PROTO_MISMATCH:
+	case SCARD_E_READER_UNAVAILABLE:
+		return MSC_INVALID_PARAMETER;
+	case SCARD_E_CANCELLED:
+		return MSC_CANCELLED;
+	case SCARD_E_TIMEOUT:
+		return MSC_TIMEOUT_OCCURRED;
+
+	default:
+		return MSC_INTERNAL_ERROR;
+	}
+}
+
+char *msc_error(unsigned long int errorCode)	//MSC_RV
+{
+
+	static char message[500];
+
+	switch (errorCode)
+	{
+	case MSC_SUCCESS:
+		strncpy(message, "Successful", sizeof(message));
+		break;
+	case MSC_NO_MEMORY_LEFT:
+		strncpy(message, "No more memory", sizeof(message));
+		break;
+	case MSC_AUTH_FAILED:
+		strncpy(message, "Authentication failed", sizeof(message));
+		break;
+	case MSC_OPERATION_NOT_ALLOWED:
+		strncpy(message, "Operation not allowed", sizeof(message));
+		break;
+	case MSC_INCONSISTENT_STATUS:
+		strncpy(message, "Inconsistent status", sizeof(message));
+		break;
+	case MSC_UNSUPPORTED_FEATURE:
+		strncpy(message, "Feature unsupported", sizeof(message));
+		break;
+	case MSC_UNAUTHORIZED:
+		strncpy(message, "Unauthorized usage", sizeof(message));
+		break;
+	case MSC_OBJECT_NOT_FOUND:
+		strncpy(message, "Object not found", sizeof(message));
+		break;
+	case MSC_OBJECT_EXISTS:
+		strncpy(message, "Object already exists", sizeof(message));
+		break;
+	case MSC_INCORRECT_ALG:
+		strncpy(message, "Incorrect algorithm", sizeof(message));
+		break;
+	case MSC_SIGNATURE_INVALID:
+		strncpy(message, "Invalid signature", sizeof(message));
+		break;
+	case MSC_IDENTITY_BLOCKED:
+		strncpy(message, "Identity is blocked", sizeof(message));
+		break;
+	case MSC_UNSPECIFIED_ERROR:
+		strncpy(message, "Unspecified error", sizeof(message));
+		break;
+	case MSC_TRANSPORT_ERROR:
+		strncpy(message, "Transport error", sizeof(message));
+		break;
+	case MSC_INVALID_PARAMETER:
+		strncpy(message, "Invalid parameter", sizeof(message));
+		break;
+	case MSC_SEQUENCE_END:
+		strncpy(message, "End of sequence", sizeof(message));
+		break;
+	case MSC_INTERNAL_ERROR:
+		strncpy(message, "Internal Error", sizeof(message));
+		break;
+	case MSC_CANCELLED:
+		strncpy(message, "Operation Cancelled", sizeof(message));
+		break;
+	case MSC_INSUFFICIENT_BUFFER:
+		strncpy(message, "Buffer is too small", sizeof(message));
+		break;
+	case MSC_UNRECOGNIZED_TOKEN:
+		strncpy(message, "Token is unsupported", sizeof(message));
+		break;
+	case MSC_SERVICE_UNRESPONSIVE:
+		strncpy(message, "Service is not running", sizeof(message));
+		break;
+	case MSC_TIMEOUT_OCCURRED:
+		strncpy(message, "Timeout has occurred", sizeof(message));
+		break;
+	case MSC_TOKEN_REMOVED:
+		strncpy(message, "Token was removed", sizeof(message));
+		break;
+	case MSC_TOKEN_RESET:
+		strncpy(message, "Token was reset", sizeof(message));
+		break;
+	case MSC_TOKEN_INSERTED:
+		strncpy(message, "Token was inserted", sizeof(message));
+		break;
+	case MSC_TOKEN_UNRESPONSIVE:
+		strncpy(message, "Token is unresponsive", sizeof(message));
+		break;
+	case MSC_INVALID_HANDLE:
+		strncpy(message, "Handle is invalid", sizeof(message));
+		break;
+	case MSC_SHARING_VIOLATION:
+		strncpy(message, "Sharing violation", sizeof(message));
+		break;
+
+	default:
+		sprintf(message, "Unknown SW: %04lu", errorCode);
+		break;
+	}
+
+	return message;
+}
+
+MSC_RV MSCReEstablishConnection(MSCLPTokenConnection pConnection)
+{
+
+	MSC_RV rv;
+	MSCPVoid32 vInitFunction, vFinFunction, vIdFunction;
+	MSCULong32 dwActiveProtocol;
+	MSCLong32(*libPL_MSCInitializePlugin) (MSCLPTokenConnection);
+	MSCLong32(*libPL_MSCFinalizePlugin) (MSCLPTokenConnection);
+        MSCLong32 (*libPL_MSCIdentifyToken)(MSCLPTokenConnection);
+
+	vInitFunction = 0;
+	vFinFunction  = 0;
+	vIdFunction   = 0;
+
+	/*
+	 * Select the AID or initialization routine for the card 
+	 */
+	vInitFunction = pConnection->libPointers.pvfInitializePlugin;
+	vFinFunction  = pConnection->libPointers.pvfFinalizePlugin;
+	vIdFunction   = pConnection->libPointers.pvfIdentifyToken;
+
+	if (vInitFunction == 0)
+	{
+		DebugLogB("Error: Card service failure: %s\n",
+			"InitializePlugin function missing");
+		return MSC_INTERNAL_ERROR;
+	}
+
+	if (vFinFunction == 0)
+	{
+		DebugLogB("Error: Card service failure: %s\n",
+			"FinalizePlugin function missing");
+		return MSC_INTERNAL_ERROR;
+	}
+
+	if ( vIdFunction == 0 ) 
+	{
+	        DebugLogB("Error: Card service failure: %s\n", 
+			  "IdentifyToken function missing");
+		return MSC_INTERNAL_ERROR;
+	}
+
+	libPL_MSCInitializePlugin = (MSCLong32(*)(MSCLPTokenConnection))
+		vInitFunction;
+
+	libPL_MSCFinalizePlugin = (MSCLong32(*)(MSCLPTokenConnection))
+		vFinFunction;
+
+	libPL_MSCIdentifyToken = (MSCLong32 (*)(MSCLPTokenConnection))
+	        vIdFunction;
+
+	rv = SCardReconnect(pConnection->hCard, pConnection->shareMode,
+		SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+		SCARD_LEAVE_CARD, &dwActiveProtocol);
+
+	if (rv != SCARD_S_SUCCESS)
+		return pcscToMSC(rv);
+
+	/*
+	 * Stop the plugin and start it up again 
+	 */
+	rv = (*libPL_MSCFinalizePlugin) (pConnection);
+
+	/*
+	 * Use the default AID given by the Info.plist 
+	 */
+	rv = (*libPL_MSCInitializePlugin) (pConnection);
+
+	/* 
+	 * Use the default AID given by the Info.plist 
+	 */
+	rv = (*libPL_MSCIdentifyToken)(pConnection);
+
+	if (rv != MSC_SUCCESS)
+		return rv;
+
+	return MSC_SUCCESS;
+}
+
+MSCUChar8 MSCIsTokenReset(MSCLPTokenConnection pConnection)
+{
+        MSCULong32 rv;
+	char slotName[MAX_READERNAME];
+	MSCULong32 slotNameSize, slotState, slotProtocol;
+	MSCUChar8 tokenId[MAX_ATR_SIZE];
+	MSCULong32 tokenIdLength;
+
+	rv = SCardStatus(pConnection->hCard, slotName,
+			 &slotNameSize, &slotState, &slotProtocol, 
+			 tokenId, &tokenIdLength);
+
+	if (rv == SCARD_W_RESET_CARD)
+	{
+	        return 1;
+	} 
+
+	if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_RESET)
+	{
+		return 1;
+	} else
+	{
+		return 0;
+	}
+}
+
+MSCUChar8 MSCClearReset(MSCLPTokenConnection pConnection)
+{
+	pConnection->tokenInfo.tokenType &= ~MSC_TOKEN_TYPE_RESET;
+	return 1;
+}
+
+MSCUChar8 MSCIsTokenMoved(MSCLPTokenConnection pConnection)
+{
+        MSCULong32 rv;
+	char slotName[MAX_READERNAME];
+	MSCULong32 slotNameSize, slotState, slotProtocol;
+	MSCUChar8 tokenId[MAX_ATR_SIZE];
+	MSCULong32 tokenIdLength;
+
+
+	rv = SCardStatus(pConnection->hCard, slotName,
+			 &slotNameSize, &slotState, &slotProtocol, 
+			 tokenId, &tokenIdLength);
+
+	if (rv == SCARD_W_REMOVED_CARD)
+	{
+	        return 1;
+	} else if (rv == SCARD_W_INSERTED_CARD)
+	{
+	        return 1;
+	} else if (slotState & SCARD_ABSENT)
+	{
+	        return 1;
+	}
+
+
+	if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_REMOVED)
+	{
+		return 1;
+	} else
+	{
+		return 0;
+	}
+}
+
+MSCUChar8 MSCIsTokenChanged(MSCLPTokenConnection pConnection)
+{
+	if (MSCIsTokenMoved(pConnection))
+	{
+		return 1;
+	} else if (MSCIsTokenReset(pConnection)) 
+	{
+		return 1;
+	} else {
+	        return 0;
+	}
+}
+
+MSCUChar8 MSCIsTokenKnown(MSCLPTokenConnection pConnection)
+{
+	if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_KNOWN)
+	{
+		return 1;
+	} else
+	{
+		return 0;
+	}
+}

Added: trunk/SmartCardServices/src/PCSC/musclecard.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/musclecard.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/musclecard.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : musclecard.h
+            Package: MuscleCard Framework
+            Author : David Corcoran
+            Date   : 11/28/01
+            License: Copyright (C) 2001 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This abstracts the MUSCLE Card Edge Inteface
+
+	    You may not remove this header from this file
+	    without prior permission from the author.
+ 
+********************************************************************/
+
+#ifndef __musclecard_h__
+#define __musclecard_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef WIN32
+#include "PCSC.h"
+#endif
+
+#ifndef __APPLE__
+#include <mscdefines.h>
+#else
+#include <PCSC/mscdefines.h>
+#endif
+
+	/****************
+     * Return codes *
+     ****************/
+
+	/** success */
+#define MSC_SUCCESS                        0x9000
+
+	/** There have been memory problems on the card */
+#define MSC_NO_MEMORY_LEFT                 0x9C01
+	/** Entered PIN is not correct */
+#define MSC_AUTH_FAILED                    0x9C02
+	/** Required operation is not allowed in actual circumstances */
+#define MSC_OPERATION_NOT_ALLOWED          0x9C03
+	/** Required operation is inconsistent with memory contents */
+#define MSC_INCONSISTENT_STATUS            0x9C04
+	/** Required feature is not (yet) supported */
+#define MSC_UNSUPPORTED_FEATURE            0x9C05
+	/** Required operation was not authorized because of a lack of privileges */
+#define MSC_UNAUTHORIZED                   0x9C06
+	/** Required object is missing */
+#define MSC_OBJECT_NOT_FOUND               0x9C07
+	/** New object ID already in use */
+#define MSC_OBJECT_EXISTS                  0x9C08
+	/** Algorithm specified is not correct */
+#define MSC_INCORRECT_ALG                  0x9C09
+
+	/** Verify operation detected an invalid signature */
+#define MSC_SIGNATURE_INVALID              0x9C0B
+	/** Operation has been blocked for security reason  */
+#define MSC_IDENTITY_BLOCKED               0x9C0C
+	/** Unspecified error */
+#define MSC_UNSPECIFIED_ERROR              0x9C0D
+	/** PCSC and driver transport errors */
+#define MSC_TRANSPORT_ERROR                0x9C0E
+	/** Invalid parameter given */
+#define MSC_INVALID_PARAMETER              0x9C0F
+	/** Incorrect P1 parameter */
+#define MSC_INCORRECT_P1                   0x9C10
+	/** Incorrect P2 parameter */
+#define MSC_INCORRECT_P2                   0x9C11
+	/** End of sequence */
+#define MSC_SEQUENCE_END                   0x9C12
+	/** For debugging purposes */
+#define MSC_INTERNAL_ERROR                 0x9CFF
+
+	/*******************************************************/
+	/*
+	 * These returns are beyond the protocol specification 
+	 */
+	/*
+	 * and only exist here to provide return codes for the 
+	 */
+	/*
+	 * additional functions provided by the MuscleCard API 
+	 */
+	/*
+	 * beyond the protocol specification.  
+	 */
+	/*******************************************************/
+
+	/** A blocking event has been cancelled */
+#define MSC_CANCELLED                      0x9C50
+	/*
+	 * The buffer provided is too short 
+	 */
+#define MSC_INSUFFICIENT_BUFFER            0x9C51
+	/*
+	 * The selected token is not recognized 
+	 */
+#define MSC_UNRECOGNIZED_TOKEN             0x9C52
+	/*
+	 * The PC/SC services is not available 
+	 */
+#define MSC_SERVICE_UNRESPONSIVE           0x9C53
+	/*
+	 * The action has timed out 
+	 */
+#define MSC_TIMEOUT_OCCURRED               0x9C54
+	/*
+	 * The token has been removed 
+	 */
+#define MSC_TOKEN_REMOVED                  0x9C55
+	/*
+	 * The token has been reset 
+	 */
+#define MSC_TOKEN_RESET                    0x9C56
+	/*
+	 * The token has been inserted 
+	 */
+#define MSC_TOKEN_INSERTED                 0x9C57
+	/*
+	 * The token is unresponsive 
+	 */
+#define MSC_TOKEN_UNRESPONSIVE             0x9C58
+	/*
+	 * The handle is invalid 
+	 */
+#define MSC_INVALID_HANDLE                 0x9C59
+	/*
+	 * Invalid sharing 
+	 */
+#define MSC_SHARING_VIOLATION              0x9C60
+
+
+#define MSC_BLOCKSTATUS_RESUME             0x0000
+#define MSC_BLOCKSTATUS_BLOCKING           0x0001
+#define MSC_BLOCKSTATUS_CANCELLING         0x0002
+
+	/*
+	 * Some boundary defines 
+	 */
+#define MSC_MAX_KEYS                       16
+#define MSC_MAX_PINS                        8
+#define MSC_SIZEOF_KEYPACKET              200
+#define MSC_MAXSIZEOF_APDU_DATALEN        255
+#define MSC_PERCENT_STEPSIZE             1000
+#define MSC_SINGLE_READ_PACKET            255
+#define MSC_MAXSIZE_TOKENARRAY            255
+
+	/*
+	 * KeyPair Generation algorithms 
+	 */
+#define MSC_GEN_ALG_RSA	        0x00
+#define MSC_GEN_ALG_RSA_CRT	0x01
+#define MSC_GEN_ALG_DSA	        0x02
+#define MSC_GEN_ALG_DES	        0x03
+#define MSC_GEN_ALG_3DES	0x04
+#define MSC_GEN_ALG_3DES3	0x05
+
+	/*
+	 * Blob encodings in KeyBlob structure 
+	 */
+#define MSC_BLOB_ENC_PLAIN	0x00
+#define MSC_BLOB_ENC_CRYPT	0x01
+
+	/*
+	 * Key Type in Key Blobs 
+	 */
+#define MSC_KEY_RSA_PUBLIC       0x01
+#define MSC_KEY_RSA_PRIVATE      0x02
+#define MSC_KEY_RSA_PRIVATE_CRT  0x03
+#define MSC_KEY_DSA_PUBLIC       0x04
+#define MSC_KEY_DSA_PRIVATE      0x05
+#define MSC_KEY_DES              0x06
+#define MSC_KEY_3DES             0x07
+#define MSC_KEY_3DES3            0x08
+
+	/*
+	 * Key generation options TODO: add other 
+	 */
+#define MSC_OPT_DEFAULT		 0x00
+#define MSC_OPT_RSA_PUB_EXP      0x01
+#define MSC_OPT_DSA_GPQ          0x02
+
+	/*
+	 * Cipher operations in ComputeCrypt() 
+	 */
+#define MSC_CIPHER_INIT	        0x01
+#define MSC_CIPHER_PROCESS	0x02
+#define MSC_CIPHER_FINAL	0x03
+
+	/*
+	 * Cipher modes in ComputeCrypt() 
+	 */
+#define MSC_MODE_RSA_NOPAD	0x00
+#define MSC_MODE_RSA_PAD_PKCS1	0x01
+#define MSC_MODE_DSA_SHA	0x10
+#define MSC_MODE_DES_CBC_NOPAD	0x20
+#define MSC_MODE_DES_ECB_NOPAD	0x21
+
+	/*
+	 * Cipher directions 
+	 */
+#define MSC_DIR_SIGN		0x01
+#define MSC_DIR_VERIFY		0x02
+#define MSC_DIR_ENCRYPT		0x03
+#define MSC_DIR_DECRYPT		0x04
+
+	/*
+	 * Sequence options in ListXXX() 
+	 */
+#define MSC_SEQUENCE_RESET	0x00
+#define MSC_SEQUENCE_NEXT	0x01
+
+	/*
+	 * Zero flag in DeleteObject() 
+	 */
+#define MSC_ZF_DEFAULT	0x00
+#define MSC_ZF_WRITE_ZERO	0x01
+
+	/*
+	 * Some defines for ID's Bitmask 
+	 */
+#define MSC_AUT_ALL       0x0000
+#define MSC_AUT_NONE      0xFFFF
+
+#define MSC_AUT_PIN_0     0x0001
+#define MSC_AUT_PIN_1     0x0002
+#define MSC_AUT_PIN_2     0x0004
+#define MSC_AUT_PIN_3     0x0008
+#define MSC_AUT_PIN_4     0x0010
+
+#define MSC_AUT_KEY_0     0x0100
+#define MSC_AUT_KEY_1     0x0200
+#define MSC_AUT_KEY_2     0x0400
+#define MSC_AUT_KEY_3     0x0800
+#define MSC_AUT_KEY_4     0x1000
+#define MSC_AUT_KEY_5     0x2000
+
+#define MSC_AUT_USR_0     0x4000
+#define MSC_AUT_USR_1     0x8000
+
+	/*
+	 * This structure allows you to customize your MuscleCard. It is used
+	 * in MSCWriteFramework to specify attributes you may want to set in
+	 * this 'personalization' routine and will be getting new values in
+	 * future revisions of the API 
+	 */
+
+#define MSC_INIT_DEFAULT_KEY     0x00	/* Use card's default transport
+										 * key */
+#define MSC_INIT_IGNORE_KEY      0x01	/* Don't verify any key at all */
+#define MSC_INIT_USE_KEY         0x02	/* Use the key in this struct */
+
+	typedef struct
+	{
+		MSCUChar8 transportKey[MAX_BUFFER_SIZE];
+		MSCULong32 transportKeyLen;
+		MSCUChar8  transportBehavior;
+		MSCULong32 objectMemory;
+
+		MSCUChar8  newTransportKey[MAX_BUFFER_SIZE];
+		MSCULong32 newTransportKeyLen;
+
+		MSCUChar8  defaultCHV[MAX_BUFFER_SIZE];
+		MSCULong32 defaultCHVLen;
+		MSCUChar8  defaultCHVTries;
+
+		MSCUChar8  defaultCHVUnblock[MAX_BUFFER_SIZE];
+		MSCULong32 defaultCHVUnblockSize;
+		MSCUChar8  defaultCHVUnblockTries;
+
+		MSCUShort16 createObjectACL;
+		MSCUShort16 createKeysACL;
+		MSCUShort16 createPINsACL;
+
+		MSCUChar8   maxNumberKeys;
+		MSCUChar8   maxNumberPINs;
+		MSCUShort16 maxNumberObjects;
+
+	}
+	MSCInitTokenParams, *MSCLPInitTokenParams;
+
+	/*
+	 * Direction policy bitmasks for MSCKeyPolicy 
+	 */
+#define MSC_KEYPOLICY_MODE_RSA_NOPAD      0x0001
+#define MSC_KEYPOLICY_MODE_RSA_PAD_PKCS1  0x0002
+#define MSC_KEYPOLICY_MODE_DSA_SHA        0x0004
+#define MSC_KEYPOLICY_MODE_DES_CBC_NOPAD  0x0008
+#define MSC_KEYPOLICY_MODE_DES_ECB_NOPAD  0x0010
+
+#define MSC_KEYPOLICY_DIR_SIGN            0x0100
+#define MSC_KEYPOLICY_DIR_VERIFY          0x0200
+#define MSC_KEYPOLICY_DIR_ENCRYPT         0x0400
+#define MSC_KEYPOLICY_DIR_DECRYPT         0x0800
+
+	typedef struct
+	{
+		MSCUShort16 cipherMode;
+		MSCUShort16 cipherDirection;
+	}
+	MSCKeyPolicy, *MSCLPKeyPolicy;
+
+	typedef struct
+	{
+		MSCUShort16 readPermission;
+		MSCUShort16 writePermission;
+		MSCUShort16 usePermission;
+	}
+	MSCKeyACL, *MSCLPKeyACL;
+
+	typedef struct
+	{
+		MSCUShort16 readPermission;
+		MSCUShort16 writePermission;
+		MSCUShort16 deletePermission;
+	}
+	MSCObjectACL, *MSCLPObjectACL, MSCCertACL, *MSCLPCertACL;
+
+	typedef struct
+	{
+		MSCUChar8 algoType;
+		MSCUShort16 keySize;
+		MSCKeyACL privateKeyACL;
+		MSCKeyACL publicKeyACL;
+		MSCKeyPolicy privateKeyPolicy;
+		MSCKeyPolicy publicKeyPolicy;
+		MSCUChar8 keyGenOptions;
+		MSCPUChar8 pOptParams;
+		MSCULong32 optParamsSize;
+	}
+	MSCGenKeyParams, *MSCLPGenKeyParams;
+
+	typedef MSCPUChar8 MSCLPKeyBlob;
+
+	typedef struct
+	{
+		MSCUChar8 keyNum;
+		MSCUChar8 keyType;
+		MSCUChar8 keyPartner;   /* Do not use (deprecated) */
+	        MSCUChar8 keyMapping;   /* Do not use (deprecated) */
+		MSCUShort16 keySize;
+		MSCKeyPolicy keyPolicy;
+		MSCKeyACL keyACL;
+	}
+	MSCKeyInfo, *MSCLPKeyInfo;
+
+	typedef struct
+	{
+		MSCUChar8 keyNum;
+		MSCUChar8 cipherMode;
+		MSCUChar8 cipherDirection;
+		MSCPUChar8 optParams;
+		MSCUShort16 optParamsSize;
+	}
+	MSCCryptInit, *MSCLPCryptInit;
+
+	/*
+	 * Scope definitions for MSCListTokens 
+	 */
+#define MSC_LIST_KNOWN     1	/* Lists known tokens only */
+#define MSC_LIST_SLOTS     2	/* Lists all slots, with or without tokens 
+								 */
+#define MSC_LIST_ALL       3	/* Lists all tokens, known or not */
+
+#define MSC_TOKEN_EMPTY_STR    "Token Removed"
+#define MSC_TOKEN_UNKNOWN_STR  "Token Unknown"
+
+#define MSC_TOKEN_TYPE_REMOVED   1	/* Token was removed at one point */
+#define MSC_TOKEN_TYPE_UNKNOWN   2	/* Token is unknown, state is fine */
+#define MSC_TOKEN_TYPE_KNOWN     4	/* Token is known, state is fine */
+#define MSC_TOKEN_TYPE_RESET     8	/* Token is known, was reset */
+
+	/*
+	 * endAction definitions for MSCReleaseConnection 
+	 */
+#define MSC_LEAVE_TOKEN    SCARD_LEAVE_CARD
+#define MSC_RESET_TOKEN    SCARD_RESET_CARD
+#define MSC_EJECT_TOKEN    SCARD_EJECT_CARD
+
+	/*
+	 * sharingMode for MSCEstablishConnection 
+	 */
+#define MSC_SHARE_SHARED     SCARD_SHARE_SHARED
+#define MSC_SHARE_EXCLUSIVE  SCARD_SHARE_EXCLUSIVE
+#define MSC_SHARE_DIRECT     SCARD_SHARE_DIRECT
+
+	/*
+	 * tokenState for MSCWaitForTokenEvent 
+	 */
+#define MSC_STATE_UNAWARE      0x4000
+#define MSC_STATE_CHANGED      SCARD_STATE_CHANGED
+#define MSC_STATE_UNKNOWN      SCARD_STATE_UNKNOWN
+#define MSC_STATE_UNAVAILABLE  SCARD_STATE_UNAVAILABLE
+#define MSC_STATE_EMPTY        SCARD_STATE_EMPTY
+#define MSC_STATE_PRESENT      SCARD_STATE_PRESENT
+#define MSC_STATE_EXCLUSIVE    SCARD_STATE_EXCLUSIVE
+#define MSC_STATE_INUSE        SCARD_STATE_INUSE
+#define MSC_STATE_MUTE         SCARD_STATE_MUTE
+
+#define MSC_NO_TIMEOUT         INFINITE
+
+/********************** TAGS for GetStatus ********************************/
+
+	/*
+	 * high level tags 
+	 */
+#define MSC_TAG_SUPPORT_FUNCTIONS     101	/* Supported functions */
+#define MSC_TAG_SUPPORT_CRYPTOALG     102	/* Supported crypto algorithms 
+											 */
+
+	/*
+	 * crypto related tags 
+	 */
+#define MSC_TAG_CAPABLE_RSA           103	/* RSA capabilities */
+#define MSC_TAG_CAPABLE_DSA           104	/* DSA capabilities */
+#define MSC_TAG_CAPABLE_ECURVE        105	/* Eliptic Curve capabilities */
+#define MSC_TAG_CAPABLE_ELGAMAL       106	/* El Gamal capabilities */
+
+#define MSC_TAG_CAPABLE_KEY_AUTH      180	/* Key import/gen AUT needed */
+
+#define MSC_TAG_CAPABLE_DES           201	/* DES capabilities */
+#define MSC_TAG_CAPABLE_3DES          202	/* Triple DES capabilities */
+#define MSC_TAG_CAPABLE_IDEA          203	/* IDEA capabilities */
+#define MSC_TAG_CAPABLE_AES           204	/* AES capabilities */
+#define MSC_TAG_CAPABLE_BLOWFISH      205	/* Blowfish capabilities */
+#define MSC_TAG_CAPABLE_TWOFISH       206	/* Twofish capabilities */
+
+#define MSC_TAG_CAPABLE_MD5           207	/* MD5 capabilities */
+#define MSC_TAG_CAPABLE_SHA1          208	/* SHA1 capabilities */
+
+	/*
+	 * object related tags 
+	 */
+#define MSC_TAG_CAPABLE_OBJ_ATTR      301	/* returns general attributes */
+#define MSC_TAG_CAPABLE_OBJ_IDSIZE    302	/* returns size of object id */
+#define MSC_TAG_CAPABLE_OBJ_AUTH      303	/* return AUT needed for
+											 * create */
+#define MSC_TAG_CAPABLE_OBJ_MAXNUM    304	/* maximum number of objects */
+
+	/*
+	 * pin related tags 
+	 */
+#define MSC_TAG_CAPABLE_PIN_ATTR      401	/* returns general attributes */
+#define MSC_TAG_CAPABLE_PIN_MAXNUM    402	/* returns max number of pins */
+#define MSC_TAG_CAPABLE_PIN_MINSIZE   403	/* returns minimum pin size */
+#define MSC_TAG_CAPABLE_PIN_MAXSIZE   404	/* returns maximum pin size */
+#define MSC_TAG_CAPABLE_PIN_CHARSET   405	/* char set supported
+											 * (bitmask) */
+#define MSC_TAG_CAPABLE_PIN_POLICY    406	/* returns pin policy
+											 * (bitmask) */
+#define MSC_TAG_CAPABLE_PIN_AUTH      407	/* return AUT needed for
+											 * create */
+
+#define MSC_TAG_CAPABLE_ID_STATE      501	/* returns state capability */
+
+#define MSC_TAG_CAPABLE_RANDOM        600	/* Random number capabilities */
+#define MSC_TAG_CAPABLE_RANDOM_MAX    601	/* Maximum random number */
+#define MSC_TAG_CAPABLE_RANDOM_MIN    602	/* Minimum random number */
+
+/********************************** END OF TAGS ***************************/
+
+	/*
+	 * Bitmask for TAG MSC_TAG_SUPPORT_FUNCTIONS 
+	 */
+#define MSC_SUPPORT_GENKEYS           0x00000001
+#define MSC_SUPPORT_IMPORTKEY         0x00000002
+#define MSC_SUPPORT_EXPORTKEY         0x00000004
+#define MSC_SUPPORT_COMPUTECRYPT      0x00000008
+#define MSC_SUPPORT_EXTAUTH           0x00000010
+#define MSC_SUPPORT_LISTKEYS          0x00000020
+#define MSC_SUPPORT_CREATEPIN         0x00000040
+#define MSC_SUPPORT_VERIFYPIN         0x00000080
+#define MSC_SUPPORT_CHANGEPIN         0x00000100
+#define MSC_SUPPORT_UNBLOCKPIN        0x00000200
+#define MSC_SUPPORT_LISTPINS          0x00000400
+#define MSC_SUPPORT_CREATEOBJECT      0x00000800
+#define MSC_SUPPORT_DELETEOBJECT      0x00001000
+#define MSC_SUPPORT_WRITEOBJECT       0x00002000
+#define MSC_SUPPORT_READOBJECT        0x00004000
+#define MSC_SUPPORT_LISTOBJECTS       0x00008000
+#define MSC_SUPPORT_LOGOUTALL         0x00010000
+#define MSC_SUPPORT_GETCHALLENGE      0x00020000
+
+	/*
+	 * Bitmask for MSC_TAG_SUPPORT_CRYPTOALG 
+	 */
+#define MSC_SUPPORT_RSA           0x00000001	/* Supports RSA */
+#define MSC_SUPPORT_DSA           0x00000002	/* Supports DSA */
+#define MSC_SUPPORT_ECURVE        0x00000004	/* Supports Eliptic Curve */
+#define MSC_SUPPORT_ELGAMAL       0x00000008	/* Supports El Gamal */
+
+#define MSC_SUPPORT_DES           0x00000010	/* Supports DES */
+#define MSC_SUPPORT_3DES          0x00000020	/* Supports Triple DES */
+#define MSC_SUPPORT_IDEA          0x00000040	/* Supports IDEA */
+#define MSC_SUPPORT_AES           0x00000080	/* Supports AES */
+#define MSC_SUPPORT_BLOWFISH      0x00000100	/* Supports Blowfish */
+#define MSC_SUPPORT_TWOFISH       0x00000200	/* Supports Twofish */
+#define MSC_SUPPORT_SHA1          0x00000400	/* Supports SHA1 */
+#define MSC_SUPPORT_MD5           0x00000800	/* Supports MD5 */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_RSA 
+	 */
+#define MSC_CAPABLE_RSA_512       0x00000001	/* Supports 512 bit RSA */
+#define MSC_CAPABLE_RSA_768       0x00000002	/* Supports 768 bit RSA */
+#define MSC_CAPABLE_RSA_1024      0x00000004	/* Supports 1024 bit RSA */
+#define MSC_CAPABLE_RSA_2048      0x00000008	/* Supports 2048 bit RSA */
+#define MSC_CAPABLE_RSA_4096      0x00000010	/* Supports 4096 bit RSA */
+
+#define MSC_CAPABLE_RSA_KEYGEN    0x00001000	/* Support RSA key-gen */
+#define MSC_CAPABLE_RSA_NOPAD     0x00002000	/* Supports RSA NO PAD */
+#define MSC_CAPABLE_RSA_PKCS1     0x00004000	/* Supports PKCS padding */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_DSA 
+	 */
+#define MSC_CAPABLE_DSA_512       0x00000001	/* Supports 512 bit DSA */
+#define MSC_CAPABLE_DSA_768       0x00000002	/* Supports 768 bit DSA */
+#define MSC_CAPABLE_DSA_1024      0x00000004	/* Supports 1024 bit DSA */
+#define MSC_CAPABLE_DSA_2048      0x00000008	/* Supports 2048 bit DSA */
+#define MSC_CAPABLE_DSA_4096      0x00000010	/* Supports 4096 bit DSA */
+#define MSC_CAPABLE_DSA_KEYGEN    0x00001000	/* Supports DSA key-gen */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_DES 
+	 */
+#define MSC_CAPABLE_DES_KEYGEN    0x00001000	/* Supports DES key-gen */
+#define MSC_CAPABLE_DES_CBC       0x00002000	/* Supports DES CBC mode */
+#define MSC_CAPABLE_DES_EBC       0x00004000	/* Supports DES EBC mode */
+#define MSC_CAPABLE_DES_ECB       0x00008000	/* Supports DES ECB mode */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_3DES 
+	 */
+#define MSC_CAPABLE_3DES_KEYGEN   0x00001000	/* Supports 3DES key-gen */
+#define MSC_CAPABLE_3DES_3KEY     0x00002000	/* Support 3 key 3DES */
+#define MSC_CAPABLE_3DES_CBC      0x00004000	/* Supports 3DES CBC mode */
+#define MSC_CAPABLE_3DES_EBC      0x00008000	/* Supports 3DES EBC mode */
+#define MSC_CAPABLE_3DES_ECB      0x00010000	/* Supports 3DES ECB mode */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_IDEA 
+	 */
+#define MSC_CAPABLE_IDEA_KEYGEN   0x00001000	/* Supports IDEA key-gen */
+#define MSC_CAPABLE_IDEA_CBC      0x00002000	/* Supports IDEA CBC mode */
+#define MSC_CAPABLE_IDEA_ECB      0x00008000	/* Supports IDEA ECB mode */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_AES 
+	 */
+#define MSC_CAPABLE_AES_KEYGEN    0x00001000	/* Supports AES key-gen */
+#define MSC_CAPABLE_AES_CBC       0x00002000	/* Supports AES CBC mode */
+#define MSC_CAPABLE_AES_ECB       0x00008000	/* Supports AES ECB mode */
+
+	/***********************************
+     Bitmasks for other crypto algorithms 
+     will come in future releases 
+    ************************************/
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_OBJ_ATTR 
+	 */
+#define MSC_CAPABLE_OBJ_ZERO      0x00010000	/* Supports zero on DEL */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_PIN_ATTR 
+	 */
+#define MSC_CAPABLE_PIN_RESET     0x00000100	/* Unblock reset's pin */
+#define MSC_CAPABLE_PIN_LEAVE     0x00000200	/* Unblock leaves pin */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_PIN_CHARSET 
+	 */
+#define MSC_CAPABLE_PIN_A_Z       0x00000001	/* Supports uppercase A-Z */
+#define MSC_CAPABLE_PIN_a_z       0x00000002	/* Supports lowercase a-z */
+#define MSC_CAPABLE_PIN_0_9       0x00000004	/* Supports numbers 0-9 */
+#define MSC_CAPABLE_PIN_SPACE     0x00000008	/* Supports spaces */
+#define MSC_CAPABLE_PIN_CALC      0x00000010	/* Supports + - / * % .= */
+#define MSC_CAPABLE_PIN_NONALPHA  0x00000020	/* Supports all other
+												 * chars */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_PIN_POLICY 
+	 */
+#define MSC_CAPABLE_PIN_A_Z       0x00000001	/* Requires uppercase A-Z */
+#define MSC_CAPABLE_PIN_a_z       0x00000002	/* Requires lowercase a-z */
+#define MSC_CAPABLE_PIN_0_9       0x00000004	/* Requires numbers 0-9 */
+#define MSC_CAPABLE_PIN_NONALPHA  0x00000020	/* Requires
+												 * non-alphanumeric */
+#define MSC_CAPABLE_PIN_HISTORY   0x00001000	/* Checks pin history */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_ID_STATE 
+	 */
+#define MSC_CAPABLE_ID_STATE      0x00000001	/* maintains logged id
+												 * state */
+
+	/*
+	 * Bitmask for TAG MSC_TAG_CAPABLE_RANDOM 
+	 */
+#define MSC_CAPABLE_RANDOM_SEED   0x00000001	/* Uses supplied seed */
+
+	/*
+	 * Structure used in MSCGetStatus to return status and capability
+	 * information about the inserted token 
+	 */
+
+	typedef struct
+	{
+		MSCUShort16 appVersion;	/* Applet version number */
+		MSCUShort16 swVersion;	/* Software version number */
+		MSCULong32 freeMemory;	/* Free memory for objects */
+		MSCULong32 totalMemory;	/* Total amount of memory */
+		MSCUChar8 usedPINs;		/* Number of pins used */
+		MSCUChar8 usedKeys;		/* Number of keys used */
+		MSCUShort16 loggedID;	/* Bitmask of ID's verified */
+	}
+	MSCStatusInfo, *MSCLPStatusInfo;
+
+	typedef struct
+	{
+		MSCChar8 objectID[MSC_MAXSIZE_OBJID];
+		MSCULong32 objectSize;
+		MSCObjectACL objectACL;
+	}
+	MSCObjectInfo, *MSCLPObjectInfo;
+
+	/*******************************************************************/
+	/*
+	 * Connection oriented functions 
+	 */
+	/*
+	 * These functions do not coorespond to internal library funcions 
+	 */
+	/*
+	 * but serve to connect to tokens.  You can still use the internal 
+	 */
+	/*
+	 * PC/SC calls to do this.  These provide an abstract means.  
+	 */
+	/*******************************************************************/
+
+	/*
+	 * Lists all known tokens on the system 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	 MSC_RV MSCListTokens(MSCULong32 listScope,	/* defines the scope to
+												 * return */
+		MSCLPTokenInfo tokenArray,	/* token struct array */
+		MSCPULong32 arrayLength	/* Length of array */
+		);
+
+	/*
+	 * Establishes a connection to the specified token 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCEstablishConnection(MSCLPTokenInfo tokenStruct,	/* The
+																 * struct
+																 * of
+																 * token */
+		MSCULong32 sharingMode,	/* Mode of sharing */
+		MSCPUChar8 applicationName,	/* The applet ID/Name */
+		MSCULong32 nameSize,	/* The ID/Name Size */
+		MSCLPTokenConnection pConnection	/* Returned connection */
+		);
+
+	/*
+	 * Releases a connection to the specified token 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCReleaseConnection(MSCLPTokenConnection pConnection,	/* Connection 
+																	 * handle 
+																	 */
+		MSCULong32 endAction	/* Action to perform */
+		);
+
+	/*
+	 * Blocks for an event to occur on a token 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCWaitForTokenEvent(MSCLPTokenInfo tokenArray,	/* Array of
+															 * token
+															 * structs */
+		MSCULong32 arraySize,	/* Size of the array */
+		MSCULong32 timeoutValue	/* Timeout */
+		);
+
+	/*
+	 * Cancels a pending MSCWaitForTokenEvent 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCCancelEventWait(void	/* No parameters */
+		);
+
+	/*
+	 * Registers a callback function for event change 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCCallbackForTokenEvent(MSCLPTokenInfo tokenArray,	/* Array
+																 * of
+																 * token
+																 * structs 
+																 */
+		MSCULong32 arraySize,	/* Size of the array */
+		MSCCallBack callBack,	/* Callback function */
+		MSCPVoid32 appData		/* Application data */
+		);
+
+	/*
+	 * Cancels all callback registrations 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCCallbackCancelEvent();
+
+	/*
+	 * Locks a transaction to the token 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCBeginTransaction(MSCLPTokenConnection pConnection	/* Connection 
+																 * handle */
+		);
+
+	/*
+	 * Releases a locked transaction to the token 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCEndTransaction(MSCLPTokenConnection pConnection,	/* Connection 
+																 * handle */
+		MSCULong32 endAction	/* Action to perform on token */
+		);
+
+	/*
+	 * Selects applet - Not to be used by applications 
+	 */
+	MSC_RV MSCSelectAID(MSCLPTokenConnection pConnection,
+		MSCPUChar8 aidValue, MSCULong32 aidSize);
+
+	/*
+	 * Pre-personalization function 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCWriteFramework(MSCLPTokenConnection pConnection,
+		MSCLPInitTokenParams pInitParams);
+
+	/*****************************************************************/
+	/*
+	 * Core Musclecard functions 
+	 */
+	/*
+	 * These functions coorespond directly to internal library 
+	 */
+	/*
+	 * functions.  
+	 */
+	/*****************************************************************/
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCGetStatus(MSCLPTokenConnection pConnection,
+		MSCLPStatusInfo pStatusInfo);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCGetCapabilities(MSCLPTokenConnection pConnection,
+		MSCULong32 Tag, MSCPUChar8 Value, MSCPULong32 Length);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCExtendedFeature(MSCLPTokenConnection pConnection,
+		MSCULong32 extFeature,
+		MSCPUChar8 outData,
+		MSCULong32 outLength, MSCPUChar8 inData, MSCPULong32 inLength);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCGenerateKeys(MSCLPTokenConnection pConnection,
+		MSCUChar8 prvKeyNum,
+		MSCUChar8 pubKeyNum, MSCLPGenKeyParams pParams);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCImportKey(MSCLPTokenConnection pConnection,
+		MSCUChar8 keyNum,
+		MSCLPKeyACL pKeyACL,
+		MSCPUChar8 pKeyBlob,
+		MSCULong32 keyBlobSize,
+		MSCLPKeyPolicy keyPolicy,
+		MSCPVoid32 pAddParams, MSCUChar8 addParamsSize);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCExportKey(MSCLPTokenConnection pConnection,
+		MSCUChar8 keyNum,
+		MSCPUChar8 pKeyBlob,
+		MSCPULong32 keyBlobSize,
+		MSCPVoid32 pAddParams, MSCUChar8 addParamsSize);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCComputeCrypt(MSCLPTokenConnection pConnection,
+		MSCLPCryptInit cryptInit,
+		MSCPUChar8 pInputData,
+		MSCULong32 inputDataSize,
+		MSCPUChar8 pOutputData, MSCPULong32 outputDataSize);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCExtAuthenticate(MSCLPTokenConnection pConnection,
+				  MSCUChar8 keyNum,
+				  MSCUChar8 cipherMode,
+				  MSCUChar8 cipherDirection, 
+				  MSCPUChar8 pData, 
+				  MSCULong32 dataSize);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCListKeys(MSCLPTokenConnection pConnection,
+			   MSCUChar8 seqOption, 
+			   MSCLPKeyInfo pKeyInfo);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCCreatePIN(MSCLPTokenConnection pConnection,
+			    MSCUChar8 pinNum,
+			    MSCUChar8 pinAttempts,
+			    MSCPUChar8 pPinCode,
+			    MSCULong32 pinCodeSize,
+			    MSCPUChar8 pUnblockCode, 
+			    MSCUChar8 unblockCodeSize);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCVerifyPIN(MSCLPTokenConnection pConnection,
+			    MSCUChar8 pinNum, 
+			    MSCPUChar8 pPinCode, 
+			    MSCULong32 pinCodeSize);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCChangePIN(MSCLPTokenConnection pConnection,
+		MSCUChar8 pinNum,
+		MSCPUChar8 pOldPinCode,
+		MSCUChar8 oldPinCodeSize,
+		MSCPUChar8 pNewPinCode, MSCUChar8 newPinCodeSize);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCUnblockPIN(MSCLPTokenConnection pConnection,
+		MSCUChar8 pinNum,
+		MSCPUChar8 pUnblockCode, MSCULong32 unblockCodeSize);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCListPINs(MSCLPTokenConnection pConnection,
+		MSCPUShort16 pPinBitMask);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCCreateObject(MSCLPTokenConnection pConnection,
+		MSCString objectID,
+		MSCULong32 objectSize, MSCLPObjectACL pObjectACL);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCDeleteObject(MSCLPTokenConnection pConnection,
+		MSCString objectID, MSCUChar8 zeroFlag);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCWriteObject(MSCLPTokenConnection pConnection,
+		MSCString objectID, MSCULong32 offset, 
+		MSCPUChar8 pInputData, MSCULong32 dataSize,
+		LPRWEventCallback rwCallback, MSCPVoid32 addParams);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCReadObject(MSCLPTokenConnection pConnection,
+		MSCString objectID, MSCULong32 offset, 
+                MSCPUChar8 pOutputData, MSCULong32 dataSize,
+		LPRWEventCallback rwCallback, MSCPVoid32 addParams);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCReadAllocateObject(MSCLPTokenConnection pConnection,
+		MSCString objectID, MSCPUChar8 *pOutputData, 
+                MSCPULong32 dataSize,
+                LPRWEventCallback rwCallback, MSCPVoid32 addParams);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCListObjects(MSCLPTokenConnection pConnection,
+		MSCUChar8 seqOption, MSCLPObjectInfo pObjectInfo);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCLogoutAll(MSCLPTokenConnection pConnection);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCGetChallenge(MSCLPTokenConnection pConnection,
+		MSCPUChar8 pSeed,
+		MSCUShort16 seedSize,
+		MSCPUChar8 pRandomData, MSCUShort16 randomDataSize);
+
+	/*****************************************************************/
+	/*
+	 * Extended Musclecard functions 
+	 */
+	/*
+	 * These functions do not coorespond to internal library funcions 
+	 */
+	/*
+	 * but rather use them to provide some extended functionality.  
+	 */
+	/*****************************************************************/
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCGetKeyAttributes(MSCLPTokenConnection pConnection,
+				   MSCUChar8 keyNumber, 
+				   MSCLPKeyInfo pKeyInfo);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSC_RV MSCGetObjectAttributes(MSCLPTokenConnection pConnection,
+				      MSCString objectID, 
+				      MSCLPObjectInfo pObjectInfo);
+
+#ifdef WIN32
+	PCSC_API
+#endif
+	char *msc_error(unsigned long int errorCode);
+
+	/*
+	 * Was the token reset ? 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSCUChar8 MSCIsTokenReset(MSCLPTokenConnection pConnection);
+
+	/*
+	 * Clear the Reset state 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSCUChar8 MSCClearReset(MSCLPTokenConnection pConnection);
+
+	/*
+	 * Was the token moved (removed, removed/inserted) ? 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSCUChar8 MSCIsTokenMoved(MSCLPTokenConnection pConnection);
+
+	/*
+	 * Did any state change with the token ? 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSCUChar8 MSCIsTokenChanged(MSCLPTokenConnection pConnection);
+
+	/*
+	 * Is the token recognized ? 
+	 */
+#ifdef WIN32
+	PCSC_API
+#endif
+	MSCUChar8 MSCIsTokenKnown(MSCLPTokenConnection pConnection);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __musclecard_h__ */

Added: trunk/SmartCardServices/src/PCSC/muscletest.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/muscletest.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/muscletest.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+        MUSCLE SmartCard Development ( http://www.linuxnet.com )
+            Title  : test.c
+            Package: card edge
+            Author : David Corcoran
+            Date   : 10/04/01
+            License: Copyright (C) 2001 David Corcoran
+                     <corcoran at linuxnet.com>
+            Purpose: This tests the virtual card edge
+ 
+ 
+********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <winscard.h>
+#include <mscdefines.h>
+#include <musclecard.h>
+
+#define MY_OBJECT_ID    "c1"
+#define MY_OBJECT_SIZE  50
+
+#ifdef MSC_ARCH_WIN32
+MSCString pcsc_stringify_error(MSCLong32 Error);
+#endif
+
+int main(int argc, char **argv)
+{
+
+	MSCLong32 rv;
+	MSCTokenConnection pConnection;
+	MSCStatusInfo statusInf;
+	MSCObjectACL objACL;
+	MSCObjectInfo objInfo;
+	MSCUChar8 pRandomData[20];
+	MSCUChar8 pSeed[8];
+	MSCUChar8 defaultPIN[16];
+	MSCUChar8 AID[6] = { 0xA0, 0x00, 0x00, 0x00, 0x01, 0x01 };
+	MSCUChar8 myData[] =
+		{ 'M', 'U', 'S', 'C', 'L', 'E', ' ', 'V', 'I', 'R',
+		'T', 'U', 'A', 'L', ' ', 'C', 'A', 'R', 'D', '.', 0
+	};
+	MSCUChar8 readData[50];
+	MSCLPTokenInfo tokenList;
+	MSCULong32 tokenSize;
+	int i, j;
+
+	printf("********************************************************\n");
+	printf("\n");
+
+	tokenList = 0;
+	tokenSize = 0;
+
+	rv = MSCListTokens(MSC_LIST_SLOTS, tokenList, &tokenSize);
+	if (rv != MSC_SUCCESS)
+	{
+		printf("MSCListTokens returns     : %s\n", msc_error(rv));
+		return -1;
+	}
+
+	tokenList = (MSCLPTokenInfo) malloc(sizeof(MSCTokenInfo) * tokenSize);
+
+	rv = MSCListTokens(MSC_LIST_SLOTS, tokenList, &tokenSize);
+	if (rv != MSC_SUCCESS)
+	{
+		printf("MSCListTokens returns     : %s\n", msc_error(rv));
+		return -1;
+	}
+
+	for (i = 0; i < tokenSize; i++)
+	{
+		printf("Token #%d\n", i);
+		printf("Token name     : %s\n", tokenList[i].tokenName);
+		printf("Slot name      : %s\n", tokenList[i].slotName);
+		printf("Token id       : ");
+		for (j = 0; j < tokenList[i].tokenIdLength; j++)
+		{
+			printf("%02X", tokenList[i].tokenId[j]);
+		}
+		printf("\n");
+		printf("Token state    : %ld\n", tokenList[i].tokenState);
+		printf("\n");
+
+		tokenList[i].tokenState = MSC_STATE_EMPTY;
+	}
+
+	printf("********************************************************\n");
+
+	rv = MSCWaitForTokenEvent(tokenList, tokenSize, MSC_NO_TIMEOUT);
+
+	for (i = 0; i < tokenSize; i++)
+	{
+		printf("Token #%d\n", i);
+		printf("Token name     : %s\n", tokenList[i].tokenName);
+		printf("Slot name      : %s\n", tokenList[i].slotName);
+		printf("Token id       : ");
+		for (j = 0; j < tokenList[i].tokenIdLength; j++)
+		{
+			printf("%02X", tokenList[i].tokenId[j]);
+		}
+		printf("\n");
+		printf("Token state    : %ld\n", tokenList[i].tokenState);
+		printf("\n");
+	}
+
+	rv = MSCEstablishConnection(&tokenList[0], MSC_SHARE_SHARED, AID,
+		6, &pConnection);
+	if (rv != MSC_SUCCESS)
+	{
+		printf("EstablishConn returns     : %s\n", msc_error(rv));
+		return -1;
+	}
+
+	rv = MSCBeginTransaction(&pConnection);
+	printf("BeginTransaction returns    : %s\n", msc_error(rv));
+
+	rv = MSCGetStatus(&pConnection, &statusInf);
+	printf("GetStatus returns           : %s\n", msc_error(rv));
+	printf("Protocol version            : %04x\n", statusInf.appVersion);
+	printf("Applet version              : %04x\n", statusInf.swVersion);
+	printf("Total object memory         : %08ld\n", statusInf.totalMemory);
+	printf("Free object memory          : %08ld\n", statusInf.freeMemory);
+	printf("Number of used PINs         : %02d\n", statusInf.usedPINs);
+	printf("Number of used Keys         : %02d\n", statusInf.usedKeys);
+	printf("Currently logged identities : %04x\n", statusInf.loggedID);
+
+        printf("Please enter the pin value\n");
+        fgets(defaultPIN, sizeof(defaultPIN), stdin);
+
+	rv = MSCVerifyPIN(&pConnection, 0, defaultPIN, strlen(defaultPIN) - 1);
+	printf("Verify default PIN          : %s\n", msc_error(rv));
+
+	rv = MSCGetStatus(&pConnection, &statusInf);
+	printf("Currently logged identities : %04x\n", statusInf.loggedID);
+
+	objACL.readPermission = MSC_AUT_ALL;
+	objACL.writePermission = MSC_AUT_ALL;
+	objACL.deletePermission = MSC_AUT_ALL;
+
+	rv = MSCCreateObject(&pConnection, MY_OBJECT_ID, MY_OBJECT_SIZE,
+		&objACL);
+	printf("CreateObject returns        : %s\n", msc_error(rv));
+
+	rv = MSCWriteObject(&pConnection, MY_OBJECT_ID, 0, myData,
+		            sizeof(myData), 0, 0);
+	printf("WriteObject returns         : %s\n", msc_error(rv));
+
+	rv = MSCReadObject(&pConnection, MY_OBJECT_ID, 0, readData, 25, 0, 0);
+	printf("ReadObject returns          : %s\n", msc_error(rv));
+
+	if (rv == MSC_SUCCESS)
+	{
+		printf("Object data                 : %s\n", readData);
+		if (strcmp(readData, myData) == 0)
+		{
+			printf("Data comparison             : Successful\n");
+		} else
+		{
+			printf("Data comparison             : Data mismatch\n");
+		}
+	}
+
+	rv = MSCListObjects(&pConnection, MSC_SEQUENCE_RESET, &objInfo);
+
+	printf("\n");
+	printf("Listing objects             : %s\n", msc_error(rv));
+	printf("------------------------------------------------------\n");
+	printf("%20s %12s %6s %6s  %6s\n", "Object ID", "Object Size",
+		"READ", "WRITE", "DELETE");
+	printf("   -----------------  -----------   ----  -----  ------\n");
+
+	if (rv == MSC_SUCCESS)
+	{
+		printf("%20s %12d   %04x   %04x    %04x\n", objInfo.objectID,
+			objInfo.objectSize,
+			objInfo.objectACL.readPermission,
+			objInfo.objectACL.writePermission,
+			objInfo.objectACL.deletePermission);
+	}
+
+	do
+	{
+		rv = MSCListObjects(&pConnection, MSC_SEQUENCE_NEXT, &objInfo);
+		if (rv == MSC_SUCCESS)
+		{
+			printf("%20s %12d   %04x   %04x    %04x\n", objInfo.objectID,
+				objInfo.objectSize,
+				objInfo.objectACL.readPermission,
+				objInfo.objectACL.writePermission,
+				objInfo.objectACL.deletePermission);
+		} else
+		{
+			break;
+		}
+
+	}
+	while (1);
+
+	printf("------------------------------------------------------\n");
+	printf("\n");
+
+	rv = MSCGetStatus(&pConnection, &statusInf);
+	printf("Free object memory          : %08ld\n", statusInf.freeMemory);
+
+	rv = MSCDeleteObject(&pConnection, MY_OBJECT_ID, MSC_ZF_DEFAULT);
+	printf("DeleteObject returns        : %s\n", msc_error(rv));
+
+	rv = MSCGetStatus(&pConnection, &statusInf);
+	printf("Free object memory          : %08ld\n", statusInf.freeMemory);
+
+	rv = MSCGetChallenge(&pConnection, pSeed, 0, pRandomData, 8);
+	printf("GetChallenge returns        : %s\n", msc_error(rv));
+	printf("Random data                 : ");
+
+	for (i = 0; i < 8; i++)
+	{
+		printf("%x ", pRandomData[i]);
+	}
+	printf("\n");
+
+	rv = MSCLogoutAll(&pConnection);
+	printf("Logout all identities       : %s\n", msc_error(rv));
+
+	rv = MSCGetStatus(&pConnection, &statusInf);
+	printf("Currently logged identities : %04x\n", statusInf.loggedID);
+
+	rv = MSCEndTransaction(&pConnection, SCARD_LEAVE_CARD);
+	printf("EndTransaction returns      : %s\n", msc_error(rv));
+
+	MSCReleaseConnection(&pConnection, SCARD_LEAVE_CARD);
+	printf("ReleaseConn returns         : %s\n", msc_error(rv));
+
+	return 0;
+}
+
+#ifdef MSC_ARCH_WIN32
+MSCString pcsc_stringify_error(MSCLong32 Error)
+{
+
+	static char strError[75];
+
+	switch (Error)
+	{
+	case SCARD_S_SUCCESS:
+		strcpy(strError, "Command successful.");
+		break;
+	case SCARD_E_CANCELLED:
+		strcpy(strError, "Command cancelled.");
+		break;
+	case SCARD_E_CANT_DISPOSE:
+		strcpy(strError, "Cannot dispose handle.");
+		break;
+	case SCARD_E_INSUFFICIENT_BUFFER:
+		strcpy(strError, "Insufficient buffer.");
+		break;
+	case SCARD_E_INVALID_ATR:
+		strcpy(strError, "Invalid ATR.");
+		break;
+	case SCARD_E_INVALID_HANDLE:
+		strcpy(strError, "Invalid handle.");
+		break;
+	case SCARD_E_INVALID_PARAMETER:
+		strcpy(strError, "Invalid parameter given.");
+		break;
+	case SCARD_E_INVALID_TARGET:
+		strcpy(strError, "Invalid target given.");
+		break;
+	case SCARD_E_INVALID_VALUE:
+		strcpy(strError, "Invalid value given.");
+		break;
+	case SCARD_E_NO_MEMORY:
+		strcpy(strError, "Not enough memory.");
+		break;
+	case SCARD_F_COMM_ERROR:
+		strcpy(strError, "RPC transport error.");
+		break;
+	case SCARD_F_INTERNAL_ERROR:
+		strcpy(strError, "Unknown internal error.");
+		break;
+	case SCARD_F_UNKNOWN_ERROR:
+		strcpy(strError, "Unknown internal error.");
+		break;
+	case SCARD_F_WAITED_TOO_MSCLong32:
+		strcpy(strError, "Waited too long.");
+		break;
+	case SCARD_E_UNKNOWN_READER:
+		strcpy(strError, "Unknown reader specified.");
+		break;
+	case SCARD_E_TIMEOUT:
+		strcpy(strError, "Command timeout.");
+		break;
+	case SCARD_E_SHARING_VIOLATION:
+		strcpy(strError, "Sharing violation.");
+		break;
+	case SCARD_E_NO_SMARTCARD:
+		strcpy(strError, "No smartcard inserted.");
+		break;
+	case SCARD_E_UNKNOWN_CARD:
+		strcpy(strError, "Unknown card.");
+		break;
+	case SCARD_E_PROTO_MISMATCH:
+		strcpy(strError, "Card protocol mismatch.");
+		break;
+	case SCARD_E_NOT_READY:
+		strcpy(strError, "Subsystem not ready.");
+		break;
+	case SCARD_E_SYSTEM_CANCELLED:
+		strcpy(strError, "System cancelled.");
+		break;
+	case SCARD_E_NOT_TRANSACTED:
+		strcpy(strError, "Transaction failed.");
+		break;
+	case SCARD_E_READER_UNAVAILABLE:
+		strcpy(strError, "Reader/s is unavailable.");
+		break;
+	case SCARD_W_UNSUPPORTED_CARD:
+		strcpy(strError, "Card is not supported.");
+		break;
+	case SCARD_W_UNRESPONSIVE_CARD:
+		strcpy(strError, "Card is unresponsive.");
+		break;
+	case SCARD_W_UNPOWERED_CARD:
+		strcpy(strError, "Card is unpowered.");
+		break;
+	case SCARD_W_RESET_CARD:
+		strcpy(strError, "Card was reset.");
+		break;
+	case SCARD_W_REMOVED_CARD:
+		strcpy(strError, "Card was removed.");
+		break;
+	case SCARD_E_PCI_TOO_SMALL:
+		strcpy(strError, "PCI struct too small.");
+		break;
+	case SCARD_E_READER_UNSUPPORTED:
+		strcpy(strError, "Reader is unsupported.");
+		break;
+	case SCARD_E_DUPLICATE_READER:
+		strcpy(strError, "Reader already exists.");
+		break;
+	case SCARD_E_CARD_UNSUPPORTED:
+		strcpy(strError, "Card is unsupported.");
+		break;
+	case SCARD_E_NO_SERVICE:
+		strcpy(strError, "Service not available.");
+		break;
+	case SCARD_E_SERVICE_STOPPED:
+		strcpy(strError, "Service was stopped.");
+		break;
+
+	};
+
+	return strError;
+}
+#endif

Added: trunk/SmartCardServices/src/PCSC/pcscdaemon.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/pcscdaemon.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/pcscdaemon.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,699 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  pcscdaemon.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2005
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: pcscdaemon.c 2377 2007-02-05 13:13:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This is the main pcscd daemon.
+ *
+ * The function \c main() starts up the communication environment.\n
+ * Then an endless loop is calld to look for Client connections. For each
+ * Client connection a call to \c CreateContextThread() is done.
+ */
+
+#include "config.h"
+#include <time.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "debuglog.h"
+#include "winscard_msg.h"
+#include "winscard_svc.h"
+#include "sys_generic.h"
+#include "thread_generic.h"
+#include "hotplug.h"
+#include "readerfactory.h"
+#include "configfile.h"
+#include "powermgt_generic.h"
+
+#include <security_utilities/debugging.h>
+
+char AraKiri = 0;
+static char Init = 1;
+int HPForceReaderPolling = 0;
+
+/*
+ * Some internal functions
+ */
+void SVCServiceRunLoop(void);
+void SVCClientCleanup(psharedSegmentMsg);
+void at_exit(void);
+void clean_temp_files(void);
+void signal_reload(int sig);
+void signal_trap(int);
+void print_version (void);
+void print_usage (char const * const);
+int ProcessHotplugRequest();
+
+PCSCLITE_MUTEX usbNotifierMutex;
+
+#ifdef USE_RUN_PID
+pid_t GetDaemonPid(void);
+pid_t GetDaemonPid(void)
+{
+	FILE *f;
+	pid_t pid;
+
+	/* pids are only 15 bits but 4294967296
+	 * (32 bits in case of a new system use it) is on 10 bytes
+	 */
+	if ((f = fopen(USE_RUN_PID, "rb")) != NULL)
+	{
+#define PID_ASCII_SIZE 11
+		char pid_ascii[PID_ASCII_SIZE];
+
+		fgets(pid_ascii, PID_ASCII_SIZE, f);
+		fclose(f);
+
+		pid = atoi(pid_ascii);
+	}
+	else
+	{
+		Log2(PCSC_LOG_CRITICAL, "Can't open " USE_RUN_PID ": %s",
+			strerror(errno));
+		return -1;
+	}
+
+	return pid;
+} /* GetDaemonPid */
+#endif
+
+int SendHotplugSignal(void)
+{
+#ifdef USE_RUN_PID
+	pid_t pid;
+
+	pid = GetDaemonPid();
+
+	if (pid != -1)
+	{
+		Log2(PCSC_LOG_INFO, "Send hotplug signal to pcscd (pid=%d)", pid);
+		if (kill(pid, SIGUSR1) < 0)
+		{
+			Log3(PCSC_LOG_CRITICAL, "Can't signal pcscd (pid=%d): %s",
+				pid, strerror(errno));
+			return EXIT_FAILURE ;
+		}
+	}
+#endif
+
+	return EXIT_SUCCESS;
+} /* SendHotplugSignal */
+
+int ProcessHotplugRequest()
+{
+#ifdef USE_RUN_PID
+
+	/* read the pid file to get the old pid and test if the old pcscd is
+	 * still running
+	 */
+	if (GetDaemonPid() != -1)
+		return SendHotplugSignal();
+
+	Log1(PCSC_LOG_CRITICAL, "file " USE_RUN_PID " does not exist");
+	Log1(PCSC_LOG_CRITICAL,	"Perhaps pcscd is not running?");
+#else
+	struct stat tmpStat;
+	if (SYS_Stat(PCSCLITE_CSOCK_NAME, &tmpStat) == 0)	// socket file exists, so maybe pcscd is running
+		return SendHotplugSignal();
+	Log1(PCSC_LOG_CRITICAL, "pcscd was not configured with --enable-runpid=FILE");
+#endif
+	Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
+	return EXIT_FAILURE;
+}
+
+/*
+ * Cleans up messages still on the queue when a client dies
+ */
+void SVCClientCleanup(psharedSegmentMsg msgStruct)
+{
+	/*
+	 * May be implemented in future releases
+	 */
+}
+
+/**
+ * @brief The Server's Message Queue Listener function.
+ *
+ * An endless loop calls the function \c SHMProcessEventsServer() to check for
+ * messages sent by clients.
+ * If the message is valid, \c CreateContextThread() is called to serve this
+ * request.
+ */
+void SVCServiceRunLoop(void)
+{
+	int rsp;
+	LONG rv;
+	DWORD dwClientID;	/* Connection ID used to reference the Client */
+
+	rsp = 0;
+	rv = 0;
+
+	/*
+	 * Initialize the comm structure
+	 */
+	rsp = SHMInitializeCommonSegment();
+
+	if (rsp == -1)
+	{
+		Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
+		exit(-1);
+	}
+
+	/*
+	 * Initialize the contexts structure
+	 */
+	rv = ContextsInitialize();
+
+	if (rv == -1)
+	{
+		Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
+		exit(-1);
+	}
+
+	/*
+	 * Solaris sends a SIGALRM and it is annoying
+	 */
+
+	signal(SIGALRM, SIG_IGN);
+	signal(SIGPIPE, SIG_IGN);
+	signal(SIGHUP, SIG_IGN);	/* needed for Solaris. The signal is sent
+				 * when the shell is existed */
+
+	/*
+	 * This function always returns zero
+	 */
+	rsp = SYS_MutexInit(&usbNotifierMutex);
+
+	/*
+	 * Set up the search for USB/PCMCIA devices
+	 */
+	HPSearchHotPluggables();
+	HPRegisterForHotplugEvents();
+
+	/*
+	 * Set up the power management callback routine
+	 */
+//	PMRegisterForPowerEvents();
+
+	while (1)
+	{
+		switch (rsp = SHMProcessEventsServer(&dwClientID, 0))
+		{
+
+		case 0:
+			Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
+			rv = CreateContextThread(&dwClientID);
+
+ 			if (rv != SCARD_S_SUCCESS)
+			{
+				Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
+				AraKiri = 1;
+			}
+
+			break;
+
+		case 2:
+			/*
+			 * timeout in SHMProcessEventsServer(): do nothing
+			 * this is used to catch the Ctrl-C signal at some time when
+			 * nothing else happens
+			 */
+			break;
+
+		case -1:
+			Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsServer");
+			break;
+
+		case -2:
+			/* Nothing to do in case of a syscall interrupted
+			 * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received
+			 * We just try again */
+			break;
+
+		default:
+			Log2(PCSC_LOG_ERROR, "SHMProcessEventsServer unknown retval: %d",
+				rsp);
+			break;
+		}
+
+		if (AraKiri)
+		{
+			/* stop the hotpug thread and waits its exit */
+//			HPStopHotPluggables();
+			SYS_Sleep(1);
+
+			/* now stop all the drivers */
+			RFCleanupReaders(1);
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int rv;
+	char setToForeground;
+	char HotPlug;
+	char *newReaderConfig;
+	struct stat fStatBuf;
+	int opt;
+#ifdef HAVE_GETOPT_LONG
+	int option_index = 0;
+	static struct option long_options[] = {
+		{"config", 1, 0, 'c'},
+		{"foreground", 0, 0, 'f'},
+		{"help", 0, 0, 'h'},
+		{"version", 0, 0, 'v'},
+		{"apdu", 0, 0, 'a'},
+		{"debug", 0, 0, 'd'},
+		{"info", 0, 0, 0},
+		{"error", 0, 0, 'e'},
+		{"critical", 0, 0, 'C'},
+		{"hotplug", 0, 0, 'H'},
+		{"force-reader-polling", optional_argument, 0, 0},
+		{0, 0, 0, 0}
+	};
+#endif
+#define OPT_STRING "c:fdhvaeCH"
+
+	rv = 0;
+	newReaderConfig = NULL;
+	setToForeground = 0;
+	HotPlug = 0;
+
+	/*
+	 * test the version
+	 */
+	if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
+	{
+		printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
+		printf("  in pcsclite.h (%s) does not match the release version number\n",
+			PCSCLITE_VERSION_NUMBER);
+		printf("  generated in config.h (%s) (see configure.in).\n", VERSION);
+
+		return EXIT_FAILURE;
+	}
+
+	/*
+	 * By default we create a daemon (not connected to any output)
+	 * The log will go to wherever securityd log output goes.
+	 */
+	DebugLogSetLogType(DEBUGLOG_NO_DEBUG);
+
+	/*
+	 * Handle any command line arguments
+	 */
+#ifdef  HAVE_GETOPT_LONG
+	while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
+#else
+	while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
+#endif
+		switch (opt) {
+#ifdef  HAVE_GETOPT_LONG
+			case 0:
+				if (strcmp(long_options[option_index].name,
+					"force-reader-polling") == 0)
+					HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
+				break;
+#endif
+			case 'c':
+				Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
+				newReaderConfig = optarg;
+				break;
+
+			case 'f':
+				setToForeground = 1;
+				/* debug to stderr instead of default syslog */
+				Log1(PCSC_LOG_INFO,
+					"pcscd set to foreground with debug send to stderr");
+				break;
+
+			case 'd':
+				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
+				DebugLogSetLevel(PCSC_LOG_DEBUG);
+				break;
+
+			case 'e':
+				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
+				DebugLogSetLevel(PCSC_LOG_ERROR);
+				break;
+
+			case 'C':
+				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
+				DebugLogSetLevel(PCSC_LOG_CRITICAL);
+				break;
+
+			case 'h':
+				print_usage (argv[0]);
+				return EXIT_SUCCESS;
+
+			case 'v':
+				print_version ();
+				return EXIT_SUCCESS;
+
+			case 'a':
+				DebugLogSetCategory(DEBUG_CATEGORY_APDU);
+				break;
+
+			case 'H':
+				/* debug to stderr instead of default syslog */
+				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
+				HotPlug = 1;
+				break;
+
+			default:
+				print_usage (argv[0]);
+				return EXIT_FAILURE;
+		}
+
+	}
+
+	if (argv[optind])
+	{
+		printf("Unknown option: %s\n\n", argv[optind]);
+		print_usage(argv[0]);
+		return EXIT_SUCCESS;
+	}
+
+	/*
+		If this run of pcscd has the hotplug option, just send a signal to the
+		running one and exit
+	*/
+	
+	if (HotPlug)
+		return ProcessHotplugRequest();
+
+	/*
+	 * test the presence of /var/run/pcsc.comm
+	 */
+
+	rv = SYS_Stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
+
+	if (rv == 0)
+	{
+#ifdef USE_RUN_PID
+		pid_t pid;
+
+		/* read the pid file to get the old pid and test if the old pcscd is
+		 * still running
+		 */
+		pid = GetDaemonPid();
+
+		if (pid != -1)
+		{
+			if (kill(pid, 0) == 0)
+			{
+				Log2(PCSC_LOG_CRITICAL,
+					"Another pcscd (pid: %d) seems to be running.", pid);
+				Log1(PCSC_LOG_CRITICAL,
+					"Remove " USE_RUN_PID " if pcscd is not running to clear this message.");
+				return EXIT_FAILURE;
+			}
+			else
+				/* the old pcscd is dead. Do some cleanup */
+				clean_temp_files();
+		}
+#else
+		{
+			Log1(PCSC_LOG_CRITICAL,
+				"file " PCSCLITE_CSOCK_NAME " already exists.");
+			Log1(PCSC_LOG_CRITICAL,
+				"Maybe another pcscd is running?");
+			Log1(PCSC_LOG_CRITICAL,
+				"Remove " PCSCLITE_CSOCK_NAME "if pcscd is not running to clear this message.");
+			return EXIT_FAILURE;
+		}
+#endif
+	}
+
+	/*
+	 * If this is set to one the user has asked it not to fork
+	 */
+	if (!setToForeground)
+	{
+		if (SYS_Daemon(0, 0))
+			Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s",
+				strerror(errno));
+	}
+
+	/*
+	 * cleanly remove /tmp/pcsc when exiting
+	 */
+	signal(SIGQUIT, signal_trap);
+	signal(SIGTERM, signal_trap);
+	signal(SIGINT, signal_trap);
+	signal(SIGHUP, signal_trap);
+
+#ifdef USE_RUN_PID
+	/*
+	 * Record our pid to make it easier
+	 * to kill the correct pcscd
+	 */
+	{
+		FILE *f;
+
+		if ((f = fopen(USE_RUN_PID, "wb")) != NULL)
+		{
+			fprintf(f, "%u\n", (unsigned) getpid());
+			fclose(f);
+		}
+	}
+#endif
+
+	/*
+	 * If PCSCLITE_IPC_DIR does not exist then create it
+	 */
+	rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf);
+	if (rv < 0)
+	{
+		rv = SYS_Mkdir(PCSCLITE_IPC_DIR, S_ISVTX | S_IRWXO | S_IRWXG | S_IRWXU);
+		if (rv != 0)
+		{
+			Log2(PCSC_LOG_CRITICAL,
+				"cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
+			return EXIT_FAILURE;
+		}
+	}
+
+	/* cleanly remove /var/run/pcsc.* files when exiting */
+	if (atexit(at_exit))
+		Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
+
+	/*
+	 * Allocate memory for reader structures
+	 */
+	RFAllocateReaderSpace();
+
+	/*
+	 * Grab the information from the reader.conf
+	 */
+	if (newReaderConfig)
+	{
+		rv = RFStartSerialReaders(newReaderConfig);
+		if (rv != 0)
+		{
+			Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
+				strerror(errno));
+			at_exit();
+		}
+	}
+	else
+	{
+		rv = RFStartSerialReaders(PCSCLITE_READER_CONFIG);
+
+#if 0
+		if (rv == 1)
+		{
+			Log1(PCSC_LOG_INFO,
+				"warning: no " PCSCLITE_READER_CONFIG " found");
+			/*
+			 * Token error in file
+			 */
+		}
+		else
+#endif
+			if (rv == -1)
+				at_exit();
+	}
+
+	/*
+	 * Set the default globals
+	 */
+	g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0;
+	g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1;
+	g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW;
+
+	Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
+
+	/*
+	 * post initialistion
+	 */
+	Init = 0;
+
+	/*
+	 * signal_trap() does just set a global variable used by the main loop
+	 */
+	signal(SIGQUIT, signal_trap);
+	signal(SIGTERM, signal_trap);
+	signal(SIGINT, signal_trap);
+	signal(SIGHUP, signal_trap);
+
+	signal(SIGUSR1, signal_reload);
+
+	SVCServiceRunLoop();
+
+	Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
+	return EXIT_FAILURE;
+}
+
+void at_exit(void)
+{
+	Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
+
+	clean_temp_files();
+
+	SYS_Exit(EXIT_SUCCESS);
+}
+
+void clean_temp_files(void)
+{
+	int rv;
+
+	rv = SYS_Unlink(PCSCLITE_CSOCK_NAME);
+	if (rv != 0)
+		Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_CSOCK_NAME ": %s",
+			strerror(errno));
+
+#ifdef USE_RUN_PID
+	rv = SYS_Unlink(USE_RUN_PID);
+	if (rv != 0)
+		Log2(PCSC_LOG_ERROR, "Cannot unlink " USE_RUN_PID ": %s",
+			strerror(errno));
+#endif
+}
+
+void signal_reload(int sig)
+{
+	static int rescan_ongoing = 0;
+
+	if (AraKiri)
+		return;
+
+	Log1(PCSC_LOG_INFO, "Reload serial configuration");
+	if (rescan_ongoing)
+	{
+		Log1(PCSC_LOG_INFO, "Rescan already ongoing");
+		return;
+	}
+
+	rescan_ongoing = 0;
+
+	HPReCheckSerialReaders();
+
+	rescan_ongoing = 0;
+	Log1(PCSC_LOG_INFO, "End reload serial configuration");
+} /* signal_reload */
+
+void signal_trap(int sig)
+{
+	/* the signal handler is called several times for the same Ctrl-C */
+	if (AraKiri == 0)
+	{
+		Log1(PCSC_LOG_INFO, "Preparing for suicide");
+		AraKiri = 1;
+
+		/* if still in the init/loading phase the AraKiri will not be
+		 * seen by the main event loop
+		 */
+		if (Init)
+		{
+			Log1(PCSC_LOG_INFO, "Suicide during init");
+			at_exit();
+		}
+	}
+}
+
+void print_version (void)
+{
+	printf("%s version %s.\n",  PACKAGE, VERSION);
+	printf("Copyright (C) 1999-2002 by David Corcoran <corcoran at linuxnet.com>.\n");
+	printf("Copyright (C) 2001-2005 by Ludovic Rousseau <ludovic.rousseau at free.fr>.\n");
+	printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron at labri.fr>.\n");
+	printf("Portions Copyright (C) 2000-2007 by Apple Inc.\n");
+	printf("Report bugs to <sclinux at linuxnet.com>.\n");
+}
+
+void print_usage (char const * const progname)
+{
+	printf("Usage: %s options\n", progname);
+	printf("Options:\n");
+#ifdef HAVE_GETOPT_LONG
+	printf("  -a, --apdu		log APDU commands and results\n");
+	printf("  -c, --config		path to reader.conf\n");
+	printf("  -f, --foreground	run in foreground (no daemon),\n");
+	printf("			send logs to stderr instead of syslog\n");
+	printf("  -h, --help		display usage information\n");
+	printf("  -H, --hotplug		ask the daemon to rescan the available readers\n");
+	printf("  -v, --version		display the program version number\n");
+	printf("  -d, --debug	 	display lower level debug messages\n");
+	printf("      --info	 	display info level debug messages (default level)\n");
+	printf("  -e  --error	 	display error level debug messages\n");
+	printf("  -C  --critical 	display critical only level debug messages\n");
+	printf("  --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
+#else
+	printf("  -a    log APDU commands and results\n");
+	printf("  -c 	path to reader.conf\n");
+	printf("  -f	run in foreground (no daemon), send logs to stderr instead of syslog\n");
+	printf("  -d 	display debug messages. Output may be:\n");
+	printf("  -h 	display usage information\n");
+	printf("  -H	ask the daemon to rescan the avaiable readers\n");
+	printf("  -v 	display the program version number\n");
+#endif
+}
+

Added: trunk/SmartCardServices/src/PCSC/pcscdmonitor.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/pcscdmonitor.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/pcscdmonitor.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1131 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+//
+// pcscmonitor - use PCSC to monitor smartcard reader/card state for securityd
+//
+// PCSCDMonitor is the "glue" between PCSC and the securityd objects representing
+// smartcard-related things. Its job is to manage the daemon and translate real-world
+// events (such as card and device insertions) into the securityd object web.
+//
+// PCSCDMonitor uses multiple inheritance to the hilt. It is (among others)
+//	(*) A notification listener, to listen to pcscd state notifications
+//  (*) A MachServer::Timer, to handle timed actions
+//  (*) A NotificationPort::Receiver, to get IOKit notifications of device insertions
+//
+
+#include "pcscdmonitor.h"
+#include <security_utilities/logging.h>
+#include <security_utilities/refcount.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOMessage.h>
+//#include <Kernel/IOKit/pccard/IOPCCardBridge.h>
+//#include <Kernel/IOKit/pccard/cs.h>
+
+#ifndef _IOKIT_IOPCCARDBRIDGE_H
+// Avoid kernel header include
+#define kIOPCCardVersionOneMatchKey			"VersionOneInfo"
+#define kIOPCCardFunctionNameMatchKey		"FunctionName"
+#define kIOPCCardFunctionIDMatchKey			"FunctionID"
+#define kIOPCCardVendorIDMatchKey			"VendorID"
+#define kIOPCCardDeviceIDMatchKey			"DeviceID"
+#define kIOPCCardFunctionExtensionMatchKey	"FunctionExtension"
+#define kIOPCCardMemoryDeviceNameMatchKey	"MemoryDeviceName"
+
+// this should be unique across the entire system
+#define sub_iokit_pccard        err_sub(21)
+#define kIOPCCardCSEventMessage iokit_family_msg(sub_iokit_pccard, 1)
+#endif /*  _IOKIT_IOPCCARDBRIDGE_H */
+
+// _LINUX_CS_H
+#define CS_EVENT_CARD_INSERTION		0x000004
+#define CS_EVENT_CARD_REMOVAL		0x000008
+#define CS_EVENT_EJECTION_REQUEST	0x010000
+
+// Locally defined string constants for IOKit values
+
+#define kzIOUSBSerialNumberKey				"Serial Number"
+#define kzIOUSBVendorNameKey				"USB Vendor Name"
+#define kzIOUSBProductNameKey				"USB Product Name"
+#define kzIOUSBLocationIDKey				"locationID"
+#define kzIOUSBbInterfaceClassKey			"bInterfaceClass"
+#define kzIOUSBbDeviceClassKey				"bDeviceClass"
+
+#define kzIOPCCardIONameKey					"IOName"
+#define kzIOPCCardIODeviceMemoryKey			"IODeviceMemory"
+#define kzIOPCCardParentKey					"parent"
+#define kzIOPCCardAddressKey				"address"
+
+#define kzIOPCCard16DeviceClassName			"IOPCCard16Device"
+
+//
+// Fixed configuration parameters
+//
+static const Time::Interval PCSCD_IDLE_SHUTDOWN(120);		// kill daemon if no devices present
+
+// Apple built-in iSight Device VendorID/ProductID: 0x05AC/0x8501
+
+static const uint32_t kVendorProductMask = 0x0000FFFF;
+static const uint32_t kVendorIDApple = 0x05AC;
+static const uint16_t kProductIDBuiltInISight = 0x8501;
+
+static void dumpdictentry(const void *key, const void *value, void *context);
+
+#pragma mark -------------------- Class Methods --------------------
+
+//
+// Construct a PCSCDMonitor.
+// We strongly assume there's only one of us around here.
+//
+// Note that this constructor may well run before the server loop has started.
+// Don't call anything here that requires an active server loop (like Server::active()).
+// In fact, you should push all the hard work into a timer, so as not to hold up the
+// general startup process.
+//
+
+PCSCDMonitor::PCSCDMonitor(PCSCD::Server &server, PCSCD::DriverBundles &drivers) :
+	MachPlusPlus::MachServer::Timer(true),			// "heavy" timer task
+	server(server),
+	drivers(drivers),
+	mAddDeviceCallback(NULL), mRemoveDeviceCallback(NULL),
+	mWillSleepCallback(NULL), mIsWakingCallback(NULL),
+	mTimerAction(&PCSCDMonitor::initialSetup),
+	mGoingToSleep(false),
+	mTerminationNoticeReceiver(*this),
+	mSleepWakePeriod(false),
+	mWakeConditionVariable(mWakeConditionLock)
+{
+	// do all the smartcard-related work once the event loop has started
+	secdebug("pcsc", "PCSCDMonitor server is %p", &server);
+	server.setTimer(this, Time::now());				// ASAP
+	// timer only used now to call initialSetup
+	mDevices.erase(mDevices.begin(),mDevices.end());
+}
+
+//
+// Power event notifications
+//
+void PCSCDMonitor::systemWillSleep()
+{
+	StLock<Mutex> _(mLock);
+	secdebug("pcsc", "setting sleep marker (%ld readers as of now)", mDevices.size());
+	mGoingToSleep = true;
+	server.clearTimer(this);
+	if (mWillSleepCallback)
+	{
+		uint32_t rx = (*mWillSleepCallback)();
+		secdebug("pcsc", "  WillSleepCallback returned %d", rx);
+	}
+	setSystemIsAwakeCondition(false);
+}
+
+void PCSCDMonitor::systemIsWaking()
+{
+	StLock<Mutex> _(mLock);
+	secdebug("pcsc", "------------------ Waking from sleep ... ------------------ ");
+	secdebug("pcsc", "clearing sleep marker (%ld readers as of now)", mDevices.size());
+	mGoingToSleep = false;
+	// rescan here
+	if (mIsWakingCallback)
+	{
+		uint32_t rx = (*mIsWakingCallback)();
+		secdebug("pcsc", "  IsWakingCallback returned %d", rx);
+	}
+	setSystemIsAwakeCondition(true);
+}
+
+void PCSCDMonitor::setSystemIsAwakeCondition(bool isAwake)
+{
+	secdebug("pcsc", "  setSystemIsAwakeCondition %d", isAwake);
+	if (isAwake)
+	{
+		sleepWakePeriod(false);
+		mWakeConditionVariable.broadcast();
+	}
+	else
+		sleepWakePeriod(true);
+}
+
+bool PCSCDMonitor::isSleepWakePeriod() const
+{
+	StLock<Mutex> _(mSleepWakePeriodLock);
+	return mSleepWakePeriod;
+}
+
+void PCSCDMonitor::sleepWakePeriod(bool isASleepWakePeriod)
+{
+	StLock<Mutex> _(mSleepWakePeriodLock);
+	mSleepWakePeriod = isASleepWakePeriod;
+}
+
+void PCSCDMonitor::systemAwakeAndReadyCheck()
+{
+//	const long sleepTimeMSec = 100;	// 0.1s
+ 
+	StLock<Mutex> _(mWakeConditionLock);
+	while (isSleepWakePeriod())
+    {
+		secdebug("pcsc", "...### thread paused before waking ###...");
+		mWakeConditionVariable.wait();
+		secdebug("pcsc", "...### thread resume after waking ###...");
+	}
+}
+
+void PCSCDMonitor::action()
+{
+	// Timer action
+	StLock<Mutex> _(mLock);
+	secdebug("pcsc", "Calling PCSCDMonitor::action()");
+	(this->*mTimerAction)();
+	mTimerAction = &PCSCDMonitor::noDeviceTimeout;
+}
+
+void PCSCDMonitor::scheduleTimer(bool enable)
+{
+	// Update the timeout timer as requested (and indicated by context)
+}
+
+//
+// Perform the initial PCSC subsystem initialization.
+// This runs (shortly) after securityd is fully functional and the
+// server loop has started.
+//
+void PCSCDMonitor::initialSetup()
+{
+	secdebug("pcsc", "Calling PCSCDMonitor::initialSetup()");
+	// receive Mach-based IOKit notifications through mIOKitNotifier
+	server.add(mIOKitNotifier);
+
+	// receive power event notifications (through our IOPowerWatcher personality)
+	server.add(this);
+
+	AddIOKitNotifications();
+	
+	PCSCDMonitor::postNotification(SecurityServer::kNotificationPCSCInitialized);
+}
+
+void PCSCDMonitor::AddIOKitNotifications()
+{
+	try
+	{
+		// ask for IOKit notifications for all new USB devices and process present ones
+		IOKit::DeviceMatch usbSelector(kIOUSBInterfaceClassName);
+		IOKit::DeviceMatch pcCardSelector(kzIOPCCard16DeviceClassName);
+		mIOKitNotifier.add(usbSelector, *this, kIOMatchedNotification);	// this will scan existing USB devices	
+	//	mIOKitNotifier.add(usbSelector, mTerminationNoticeReceiver, kIOTerminatedNotification);	// ditto for PC Card devices
+		mIOKitNotifier.add(pcCardSelector, *this, kIOMatchedNotification);	// ditto for PC Card devices
+		mIOKitNotifier.add(pcCardSelector, mTerminationNoticeReceiver, kIOTerminatedNotification);	// ditto for PC Card devices
+
+		// catch custom non-composite USB devices - they don't have IOServices attached
+		IOKit::DeviceMatch customUsbSelector(::IOServiceMatching(kIOUSBDeviceClassName));
+		mIOKitNotifier.add(customUsbSelector, *this, kIOMatchedNotification);	// ditto for custom USB devices
+	//	mIOKitNotifier.add(customUsbSelector, mTerminationNoticeReceiver, kIOTerminatedNotification);
+	}
+	catch (...)
+	{
+		secdebug("pcscd", "trouble adding IOKit notifications (ignored)");
+	}
+}
+	
+void PCSCDMonitor::RemoveIOKitNotifications()
+{
+}
+
+
+void PCSCDMonitor::rescanExistingDevices()
+{
+    kern_return_t kr;
+	mach_port_t masterPort = ((IOKit::NotificationPort)mIOKitNotifier).port();
+//	mach_port_t masterPort = port();
+	io_iterator_t iterator;
+	
+	// Process existing USB devices
+	IOKit::DeviceMatch usbSelector(kIOUSBInterfaceClassName);
+	kr = IOServiceGetMatchingServices(masterPort, usbSelector, &iterator);
+	IOKit::DeviceIterator usbdev(iterator);
+	ioChange(usbdev);
+
+	// Process existing PC Card devices
+	IOKit::DeviceMatch pcCardSelector(kzIOPCCard16DeviceClassName);
+	kr = IOServiceGetMatchingServices(masterPort, pcCardSelector, &iterator);
+	IOKit::DeviceIterator pcdev(iterator);
+	ioChange(pcdev);
+	
+	// catch custom non-composite USB devices - they don't have IOServices attached
+	IOKit::DeviceMatch customUsbSelector(::IOServiceMatching(kIOUSBDeviceClassName));
+	kr = IOServiceGetMatchingServices(masterPort, customUsbSelector, &iterator);
+	IOKit::DeviceIterator customusbdev(iterator);
+	ioChange(customusbdev);
+}
+
+void PCSCDMonitor::postNotification(const SecurityServer::NotificationEvent event)
+{
+	// send a change notification to securityd
+	// Either kNotificationPCSCStateChange or kNotificationPCSCInitialized
+	using namespace SecurityServer;
+	ClientSession session(Allocator::standard(), Allocator::standard());
+	try {
+		session.postNotification(kNotificationDomainPCSC, event, CssmData());
+		secdebug("pcscd", "notification sent");
+	} catch (const MachPlusPlus::Error &err) {
+		switch (err.error) {
+		case BOOTSTRAP_UNKNOWN_SERVICE: // securityd not yet available; this is not an error
+			secdebug("pcscd", "securityd not up; no notification sent");
+			break;
+#if !defined(NDEBUG)
+		// for debugging only, support a securityd restart. This is NOT thread-safe
+		case MACH_SEND_INVALID_DEST:
+			secdebug("pcscd", "resetting securityd connection for debugging");
+			session.reset();
+			try {
+				session.postNotification(kNotificationDomainPCSC,
+					kNotificationPCSCStateChange, CssmData());
+			} catch (...) {
+				secdebug("pcscd", "re-send attempt failed, punting");
+			}
+			break;
+#endif //NDEBUG
+		default:
+			secdebug("pcscd", "exception trying to send notification (ignored)");
+		}
+	} catch (...) {
+		secdebug("pcscd", "trouble sending security notification (ignored)");
+	}
+}
+
+//
+// This function is called (as a timer function) when there haven't been any (recognized)
+// smartcard devicees in the system for a while.
+//
+void PCSCDMonitor::noDeviceTimeout()
+{
+	secdebug("pcsc", "killing pcscd (no smartcard devices present for %g seconds)",
+		PCSCD_IDLE_SHUTDOWN.seconds());
+}
+
+void PCSCDMonitor::addInterestNotification()
+{
+	secdebug("pcsc", "Adding interest notification for service 0x%04X (this=%p)", mServiceOfInterest,this);
+	mIOKitNotifier.addInterestNotification(*this, mServiceOfInterest);
+}
+
+void PCSCDMonitor::scheduleAddInterestNotification(io_service_t serviceOfInterest)
+{
+	StLock<Mutex> _(mLock);
+	secdebug("pcsc", "Scheduling interest notification for service 0x%04X (this=%p)", serviceOfInterest, this);
+	mServiceOfInterest = serviceOfInterest;
+	mTimerAction = &PCSCDMonitor::addInterestNotification;
+	server.setTimer(this, Time::now());				// ASAP
+}
+
+//
+// IOKit device event notification.
+// Here we listen for newly inserted devices
+//
+void PCSCDMonitor::ioChange(IOKit::DeviceIterator &iterator)
+{
+	secdebug("pcsc", "Processing device event notification");
+	int def=0, pos=0, total=0;
+	// Always drain this iterator
+	while (IOKit::Device dev = iterator())
+	{
+		++total;
+		displayPropertiesOfDevice(dev);
+		switch (deviceSupport(dev))
+		{
+		case definite:
+			++def;
+			addDevice(dev);
+			break;
+		case possible:
+			++pos;
+			addDevice(dev);
+			break;
+		case impossible:
+			break;
+		}
+	}
+
+	dumpDevices();
+	secdebug("pcsc", "Relevant devices: %d definite, %d possible, %d total", def, pos, total);
+}
+
+// IOKit device event notification.
+// Here we listen for newly removed devices
+//
+void PCSCDMonitor::ioServiceChange(void *refCon, io_service_t service,
+	natural_t messageType, void *messageArgument)
+{
+	secdebug("pcsc", "Processing ioServiceChange notice: 0x%08X [refCon=0x%08X, service=0x%08X, arg=0x%08X]", 
+		messageType, (uint32_t)refCon, service, (uint32_t)messageArgument);
+
+	if (mGoingToSleep && isSleepWakePeriod())	// waking up but still drowsy
+	{
+		secdebug("pcsc", "  ignoring ioServiceChange notice during wake up phase");
+		return;
+	}
+
+	PCSCDMonitor::displayPropertiesOfDevice(service);
+	// This is called since we asked for kIOGeneralInterest notices
+	// Usually it is the "device removed" notification
+	switch (messageType)
+	{
+	case kIOMessageServiceIsTerminated:		// We get these when device is removed
+		{
+			uint32_t address;
+			if (deviceAddress(service, address))
+			{
+				secdebug("pcsc", "  device removed notice: 0x%04X address: 0x%08X", service, address);
+				this->removeDevice(service, address);
+			}
+			else
+				secdebug("pcsc", "  device removed notice, but failed to find address for service: 0x%04X", service);
+		}
+		break;
+	case kIOMessageServiceWasClosed:		// We get these when the system sleeps
+		{
+#ifndef NDEBUG
+			uint32_t address;
+			deviceAddress(service, address);
+			secdebug("pcsc", "  service was closed notice: 0x%04X address: 0x%08X", service, address);
+#endif
+		}
+		break;
+	case kIOPCCardCSEventMessage:	// 0xE0054001 - not handled by mach_error_string
+		secdebug("pcsc", "  pccard event message: service: 0x%04X, type: 0x%08X", 
+			service, (unsigned int)messageArgument);
+		// Card Services Events are defined in IOKit/pccard/cs.h
+		switch ((unsigned int)messageArgument)
+		{
+			case CS_EVENT_EJECTION_REQUEST:
+				secdebug("pcsc", "  pccard event message: ejection request"); 
+				break;
+                    
+			case CS_EVENT_CARD_REMOVAL:
+			{
+				uint32_t address;
+				if (deviceMemoryAddress(service, address))
+				{
+					secdebug("pcsc", "  device removed notice: 0x%04X address: 0x%08X", service, address);
+					this->removeDevice(service, address);
+				}
+				else
+					secdebug("pcsc", "  device removed notice, but failed to find address for service: 0x%04X", service);
+				break;
+			}
+		}
+		break;
+	default:
+		secdebug("pcsc", "  processing device general notice: 0x%08X", messageType);
+		break;
+	}
+}
+
+void PCSCDMonitor::addDevice(const IOKit::Device &dev)
+{
+	DeviceMap::iterator it;
+	if (!findDevice(dev,it))		// new device
+	{
+		io_service_t service = dev.ioObject();
+
+		RefPointer<PCSCD::Device> newDevice = new PCSCD::Device(service);
+		uint32_t address = 0;
+
+		if (deviceAddress(dev, address))
+		{
+			newDevice->setAddress(address);
+			secdebug("scsel", "  Device address:  0x%08X [service: 0x%04X]", address, service);
+			setDeviceProperties(dev, *newDevice);
+			if (drivers.find(*newDevice))
+			{
+				secdebug("driver", "  found matching driver for %s: %s", newDevice->name().c_str(), newDevice->path().c_str());
+				setDebugPropertiesForDevice(dev, newDevice);
+				insert(make_pair(address, newDevice));
+				if (mAddDeviceCallback)
+				{
+					// kPCSCLITE_HP_BASE_PORT
+					uint32_t rx = (*mAddDeviceCallback)(newDevice->name().c_str(), address, newDevice->path().c_str(), newDevice->name().c_str());
+					secdebug("pcsc", "  AddDeviceCallback returned %d", rx);
+					if (rx != SCARD_S_SUCCESS && rx != SCARD_E_DUPLICATE_READER)
+					{
+						DeviceMap::iterator it = mDevices.find(address);
+						if (it != mDevices.end())		// found it
+							remove(it);					// remove from reader map
+						return;
+					}
+				}
+				PCSCDMonitor::postNotification(SecurityServer::kNotificationPCSCStateChange);
+				secdebug("pcsc", "     added to device map, address:  0x%08X, service: 0x%04X, [class @:%p]", address, service, newDevice.get());
+			}
+			else
+				secdebug("driver", "  no matching driver found for %s: %s", newDevice->name().c_str(), newDevice->path().c_str());
+		}
+		else
+			secdebug("pcsc", "  device added notice, but failed to find address for service: 0x%04X", service);
+	}
+	else
+	{
+		PCSCD::Device *theDevice = static_cast<PCSCD::Device *>(it->second);
+		secdebug("scsel", "  Already in map: Device address:  0x%08X [service: 0x%04X]", 
+			theDevice->address(), dev.ioObject());
+		setDeviceProperties(dev, *theDevice);
+		setDebugPropertiesForDevice(dev, theDevice);
+	}
+
+	// We always try to add the interest notification. It may be that
+	// we added the device during a callback for a particular plane,
+	// but we didn't have the right information then to add the notification
+	io_service_t servicex = dev.ioObject();
+	mIOKitNotifier.addInterestNotification(*this, servicex);
+	dumpDevices();
+}
+
+bool PCSCDMonitor::findDevice(const IOKit::Device &dev, DeviceMap::iterator &it)
+{
+	uint32_t address = 0;
+	deviceAddress(dev, address);
+	it = mDevices.find(address);
+	return (it != mDevices.end());
+}
+
+bool PCSCDMonitor::findDeviceByName(const IOKit::Device &dev, DeviceMap::iterator &outit)
+{
+	CFRef<CFStringRef> ioName = dev.property<CFStringRef>(kzIOPCCardIONameKey);
+	if (!ioName)
+		return false;
+		
+	std::string devname = cfString(ioName);
+	for (DeviceMap::iterator it = mDevices.begin(); it != mDevices.end(); ++it)
+	{
+		PCSCD::Device *theDevice = static_cast<PCSCD::Device *>(it->second);
+		if (theDevice->name() == devname)
+		{
+			outit = it;
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+void PCSCDMonitor::updateDevice(const IOKit::Device &dev)
+{
+	DeviceMap::iterator it;
+	if (findDevice(dev,it))
+	{
+		PCSCD::Device *theDevice = static_cast<PCSCD::Device *>(it->second);
+		setDeviceProperties(dev, *theDevice);
+		if (drivers.find(*theDevice))
+			secdebug("driver", "  found matching driver for %s: %s", theDevice->name().c_str(), theDevice->path().c_str());
+		setDebugPropertiesForDevice(dev, theDevice);
+	}
+}
+
+bool PCSCDMonitor::hasLegacyDriver(const IOKit::Device &dev)
+{
+	PCSCD::Device tmpDevice(0);	//dev.ioObject() - fake it
+	uint32_t address = 0;
+	if (deviceAddress(dev, address))
+		tmpDevice.setAddress(address);
+	setDeviceProperties(dev, tmpDevice);
+	if (drivers.find(tmpDevice))
+	{
+		secdebug("driver", "  found matching driver for legacy device: %s", tmpDevice.path().c_str());
+		return true;
+	}
+
+	return false;
+}
+
+bool PCSCDMonitor::deviceIsPCCard(const IOKit::Device &dev)
+{
+	if (CFRef<CFStringRef> ioName = dev.property<CFStringRef>(kzIOPCCardIONameKey))
+		if (cfString(ioName).find("pccard", 0, 1) == 0)
+			return true;
+			
+	return false;
+}
+
+bool PCSCDMonitor::deviceIsPCCard(io_service_t service)
+{
+	if (CFRef<CFStringRef> ioName = static_cast<CFStringRef>(::IORegistryEntryCreateCFProperty(
+		service, CFSTR(kzIOPCCardIONameKey), kCFAllocatorDefault, 0)))
+		if (cfString(ioName).find("pccard", 0, 1) == 0)
+			return true;
+			
+	return false;
+}
+
+void PCSCDMonitor::getVendorAndProductID(const IOKit::Device &dev, uint32_t &vendorID, uint32_t &productID, bool &isPCCard)
+{
+	vendorID = productID = 0;
+	isPCCard = deviceIsPCCard(dev);
+	
+	if (!isPCCard)
+	{
+		if (CFRef<CFNumberRef> cfVendorID = dev.property<CFNumberRef>(kUSBVendorID))
+			vendorID = cfNumber(cfVendorID);
+
+		if (CFRef<CFNumberRef> cfProductID = dev.property<CFNumberRef>(kUSBProductID))
+			productID = cfNumber(cfProductID);
+	}	
+	else
+	{
+		if (CFRef<CFNumberRef> cfVendorID = dev.property<CFNumberRef>(kIOPCCardVendorIDMatchKey))
+			vendorID = cfNumber(cfVendorID);
+
+		if (CFRef<CFNumberRef> cfProductID = dev.property<CFNumberRef>(kIOPCCardDeviceIDMatchKey))
+			productID = cfNumber(cfProductID);
+
+		// One special case for legacy OmniKey CardMan 4040 support
+		CFRef<CFStringRef> ioName = dev.property<CFStringRef>(kzIOPCCardIONameKey);
+		if (ioName && CFEqual(ioName, CFSTR("pccard-no-cis")))
+		{
+			vendorID = 0x0223;
+			productID = 0x0200;
+		}
+	}
+}
+
+void PCSCDMonitor::setDeviceProperties(const IOKit::Device &dev, PCSCD::Device &device)
+{
+	uint32_t vendorID, productID;
+	bool isPCCard;
+	
+	getVendorAndProductID(dev, vendorID, productID, isPCCard);
+	
+	device.setIsPCCard(isPCCard);
+
+	if (CFRef<CFNumberRef> cfInterface = dev.property<CFNumberRef>(kzIOUSBbInterfaceClassKey))
+		device.setInterfaceClass(cfNumber(cfInterface));
+
+	if (CFRef<CFNumberRef> cfDevice = dev.property<CFNumberRef>(kzIOUSBbDeviceClassKey))
+		device.setDeviceClass(cfNumber(cfDevice));
+
+	device.setVendorid(vendorID);
+	device.setProductid(productID);
+	
+	if (CFRef<CFStringRef> ioName = dev.property<CFStringRef>(kzIOPCCardIONameKey))
+		device.setName(cfString(ioName));
+}
+
+bool PCSCDMonitor::isExcludedDevice(const IOKit::Device &dev)
+{
+	uint32_t vendorID, productID;
+	bool isPCCard;
+	
+	getVendorAndProductID(dev, vendorID, productID, isPCCard);
+	
+	return ((vendorID & kVendorProductMask) == kVendorIDApple && (productID & kVendorProductMask) == kProductIDBuiltInISight);
+}
+
+void PCSCDMonitor::setDebugPropertiesForDevice(const IOKit::Device &dev, PCSCD::Device * newDevice)
+{
+	/*
+		Many of these properties are only defined on the "IOUSBDevice" plane, so
+		will be non-empty on the third iteration.
+	*/
+	std::string vendorName, productName, serialNumber;
+
+	if (CFRef<CFStringRef> cfVendorString = dev.property<CFStringRef>(kzIOUSBVendorNameKey))
+		vendorName = cfString(cfVendorString);
+
+	if (CFRef<CFStringRef> cfProductString = dev.property<CFStringRef>(kzIOUSBProductNameKey))
+		productName = cfString(cfProductString);
+
+	if (CFRef<CFStringRef> cfSerialString = dev.property<CFStringRef>(kzIOUSBSerialNumberKey))
+		serialNumber = cfString(cfSerialString);
+
+	if (deviceIsPCCard(dev))
+	{
+		if (CFRef<CFArrayRef> cfVersionOne = dev.property<CFArrayRef>(kIOPCCardVersionOneMatchKey))
+		if (CFArrayGetCount(cfVersionOne) > 1)
+		{
+			CFStringRef cfVendorString = (CFStringRef)CFArrayGetValueAtIndex(cfVersionOne, 0);
+			if (cfVendorString)
+				vendorName = cfString(cfVendorString);
+
+			CFStringRef cfProductString = (CFStringRef)CFArrayGetValueAtIndex(cfVersionOne, 1);
+			if (cfProductString)
+				productName = cfString(cfProductString);
+		}
+	}
+	
+	newDevice->setDebugParams(vendorName, productName, serialNumber);
+		
+//	secdebug("scsel", "  deviceSupport: vendor/product: 0x%04X/0x%04X, vendor:  %s, product: %s, serial: %s", vendorid, productid,
+//		vendorName.c_str(), productName.c_str(), serialNumber.c_str());
+}
+
+void PCSCDMonitor::removeDevice(io_service_t service, uint32_t address)
+{
+	secdebug("pcsc", " Size of mDevices: %ld, service: 0x%04X", mDevices.size(), service);
+	if (!mDevices.empty())
+	{
+		secdebug("pcsc", "  device removed notice: 0x%04X address: 0x%08X", service, address);
+		DeviceMap::iterator it = mDevices.find(address);
+		if (it != mDevices.end())		// found it
+		{
+			if (mRemoveDeviceCallback)
+			{
+				uint32_t rx = (*mRemoveDeviceCallback)((it->second)->name().c_str(), address);
+				secdebug("pcsc", "  RemoveDeviceCallback returned %d", rx);
+			}
+			remove(it);					// remove from reader map
+		}
+		else
+			secdebug("pcsc", " service: 0x%04X at address 0x%04X not found ??", service, address);
+	}
+	dumpDevices();
+	::IOObjectRelease(service);		// we don't want notifications here until re-added
+}
+
+void PCSCDMonitor::removeDeviceByName(const IOKit::Device &dev)
+{
+	io_service_t service = dev.ioObject();
+	secdebug("pcsc", " Size of mDevices: %ld, service: 0x%04X", mDevices.size(), service);
+	if (!mDevices.empty())
+	{
+		uint32_t address = 0;
+		deviceAddress(dev, address);
+		DeviceMap::iterator it;
+		if (findDeviceByName(dev, it))		// found it
+		{
+			if (mRemoveDeviceCallback)
+			{
+				uint32_t rx = (*mRemoveDeviceCallback)((it->second)->name().c_str(), address);
+				secdebug("pcsc", "  RemoveDeviceCallback returned %d", rx);
+			}
+			remove(it);					// remove from reader map
+		}
+		else
+			secdebug("pcsc", " service: 0x%04X at address 0x%04X not found ??", service, address);
+	}
+	dumpDevices();
+	::IOObjectRelease(service);		// we don't want notifications here until re-added
+}
+
+void PCSCDMonitor::removeAllDevices()
+{
+	secdebug("pcsc", ">>>>>> removeAllDevices: Size of mDevices: %ld", mDevices.size());
+	for (DeviceMap::iterator it = mDevices.begin(); it != mDevices.end(); ++it)
+	{
+		PCSCD::Device *dev = static_cast<PCSCD::Device *>(it->second);
+		uint32_t address = 0;
+	//	PCSCDMonitor::deviceAddress(*dev, &address);
+	address = dev->address();
+		io_service_t service = dev->ioObject();
+		if (mRemoveDeviceCallback)
+		{
+			uint32_t rx = (*mRemoveDeviceCallback)(dev->name().c_str(), address);
+			secdebug("pcsc", "  RemoveDeviceCallback returned %d", rx);
+		}
+		::IOObjectRelease(service);		// we don't want notifications here until re-added
+		remove(it);						// remove from reader map
+	}
+	secdebug("pcsc", ">>>>>> removeAllDevices [end]: Size of mDevices: %ld", mDevices.size());
+}
+
+
+//
+// Check an IOKit device that's just come online to see if it's
+// a smartcard device of some sort.
+//
+PCSCDMonitor::DeviceSupport PCSCDMonitor::deviceSupport(const IOKit::Device &dev)
+{
+#ifndef NDEBUG
+	try
+	{
+		secdebug("scsel", "path: %s", dev.path().c_str());	// this can fail sometimes
+	}
+	catch (...)
+	{
+		secdebug("scsel", "  exception while displaying device path - ignoring error");
+	}
+#endif
+	
+	try
+	{
+		// composite USB device with interface class
+		if (CFRef<CFNumberRef> cfInterface = dev.property<CFNumberRef>(kzIOUSBbInterfaceClassKey))
+			switch (uint32_t clas = cfNumber(cfInterface))
+			{
+			case kUSBChipSmartCardInterfaceClass:		// CCID smartcard reader - go
+				secdebug("scsel", "  CCID smartcard reader recognized");
+				return definite;
+			case kUSBVendorSpecificInterfaceClass:
+				if (isExcludedDevice(dev))
+				{
+					secdebug("scsel", "  interface class %d is not a smartcard device (excluded)", clas);
+					return impossible;
+				}
+				secdebug("scsel", "  Vendor-specific interface - possible match");
+				return possible;
+			default:
+				if ((clas == 0) && hasLegacyDriver(dev))
+				{
+					secdebug("scsel", "  Vendor-specific legacy driver - possible match");
+					return possible;
+				}
+				secdebug("scsel", "  interface class %d is not a smartcard device", clas);
+				return impossible;
+			}
+
+		// noncomposite USB device
+		if (CFRef<CFNumberRef> cfDevice = dev.property<CFNumberRef>(kzIOUSBbDeviceClassKey))
+			if (cfNumber(cfDevice) == kUSBVendorSpecificClass)
+			{
+				if (isExcludedDevice(dev))
+				{
+					secdebug("scsel", "  device class %d is not a smartcard device (excluded)", cfNumber(cfDevice));
+					return impossible;
+				}
+				secdebug("scsel", "  Vendor-specific device - possible match");
+				return possible;
+			}
+
+		// PCCard (aka PCMCIA aka ...) interface (don't know how to recognize a reader here)
+		if (deviceIsPCCard(dev))
+		{
+			secdebug("scsel", "  PCCard - possible match");
+			return possible;
+		}
+		
+		return impossible;
+	}
+	catch (...)
+	{
+		secdebug("scsel", "  exception while examining device - ignoring it");
+		return impossible;
+	}
+}
+
+#pragma mark -------------------- Static Methods --------------------
+
+bool PCSCDMonitor::deviceAddress(io_service_t service, uint32_t &address)
+{	
+	if (CFRef<CFNumberRef> cfLocationID = static_cast<CFNumberRef>(::IORegistryEntryCreateCFProperty(
+		service, CFSTR(kzIOUSBLocationIDKey), kCFAllocatorDefault, 0)))
+	{
+		address = cfNumber(cfLocationID);
+		return true;
+	}
+	
+	// don't bother to test if it is a pc card, just try looking
+	return deviceMemoryAddress(service, address);
+}
+
+bool PCSCDMonitor::deviceAddress(const IOKit::Device &dev, uint32_t &address)
+{
+	if (CFRef<CFNumberRef> cfLocationID = dev.property<CFNumberRef>(kzIOUSBLocationIDKey))
+	{
+		address = cfNumber(cfLocationID);
+		return true;
+	}
+
+	// don't bother to test if it is a pc card, just try looking
+	return deviceMemoryAddress(dev, address);
+}
+
+bool PCSCDMonitor::deviceMemoryAddress(const IOKit::Device &dev, uint32_t &address)
+{
+//	CFRef<CFStringRef> ioName = dev.property<CFStringRef>(kzIOPCCardIONameKey);
+	CFRef<CFArrayRef> cfDeviceMemory = dev.property<CFArrayRef>(kzIOPCCardIODeviceMemoryKey);
+	return deviceMemoryAddressCore(cfDeviceMemory, dev.path(), address);
+}
+
+bool PCSCDMonitor::deviceMemoryAddress(io_service_t service, uint32_t &address)
+{
+//	CFRef<CFStringRef> ioName = static_cast<CFStringRef>(::IORegistryEntryCreateCFProperty(
+//		service, CFSTR(kzIOPCCardIONameKey), kCFAllocatorDefault, 0));
+	CFRef<CFArrayRef> cfDeviceMemory = static_cast<CFArrayRef>(::IORegistryEntryCreateCFProperty(
+			service, CFSTR(kzIOPCCardIODeviceMemoryKey), kCFAllocatorDefault, 0));
+	return deviceMemoryAddressCore(cfDeviceMemory, "", address);
+}
+
+bool PCSCDMonitor::deviceMemoryAddressCore(CFArrayRef cfDeviceMemory, std::string path, uint32_t &address)
+{
+	address = 0;
+	try
+	{
+		if (cfDeviceMemory)
+		{
+			if (CFRef<CFDictionaryRef> cfTempMem = (CFDictionaryRef)CFRetain(CFArrayGetValueAtIndex(cfDeviceMemory, 0)))
+			{
+			//	CFDictionaryApplyFunction(cfTempMem, dumpdictentry, NULL);
+				if (CFRef<CFArrayRef> cfParent = (CFArrayRef)CFRetain(CFDictionaryGetValue(cfTempMem, CFSTR(kzIOPCCardParentKey))))
+					if (CFRef<CFDictionaryRef> cfTempMem2 = (CFDictionaryRef)CFRetain(CFArrayGetValueAtIndex(cfParent, 0)))
+						if (CFRef<CFNumberRef> cfAddress = (CFNumberRef)CFRetain(CFDictionaryGetValue((CFDictionaryRef)cfTempMem2, CFSTR(kzIOPCCardAddressKey))))
+						{
+							address = cfNumber(cfAddress);
+							secdebug("scsel", "  address from device memory address property: 0x%08X", address);
+							return true;
+						}
+			}
+		}
+		else
+		if (!path.empty())
+		{
+		//	std::string name = cfString(ioName);
+		//	address = CFHash (ioName);
+		//	address = 0xF2000000;
+			addressFromPath(path, address);
+			secdebug("scsel", "  extracted address: 0x%08X for device [%s]", address, path.c_str());
+			return true;
+		}
+	}
+	catch (...)
+	{
+		secdebug("scsel", "  exception while examining deviceMemoryAddress property");
+	}
+	return false;
+}
+
+bool PCSCDMonitor::addressFromPath(std::string path, uint32_t &address)
+{
+	/*
+		Try to extract the address from the path if the other keys are not present.
+		An example path is:
+		
+			IOService:/MacRISC2PE/pci at f2000000/AppleMacRiscPCI/cardbus at 13/IOPCCardBridge/pccard2bd,1003 at 0,0
+			
+		where e.g. the address is f2000000, the vendor is 0x2bd, and the product id is 0x1003
+	*/
+	address = 0;
+	#define HEX_TO_INT(x) ((x) >= '0' &&(x) <= '9' ? (x) - '0' : (x) - ('a' - 10)) 
+	
+	try
+	{
+		secdebug("scsel", "path: %s", path.c_str());			// this can fail sometimes
+
+		std::string lhs("/pci@");
+		std::string rhs("/");
+
+		std::string::size_type start = path.find(lhs)+lhs.length();
+		std::string::size_type end = path.find(rhs, start);
+
+		std::string addressString(path, start, end-start);
+		
+		// now addressString should contain something like f2000000
+		uint32_t tmp = 0;
+		const char *px = addressString.c_str();
+		size_t len = strlen(px);
+		for (unsigned int ix=0;ix<len;ix++,px++)
+		{
+			tmp<<=4;
+			tmp += HEX_TO_INT(*px);
+		}
+
+		address = tmp;
+		
+		secdebug("scsel", "  address 0x%08X extracted from path", address);
+	}
+	catch (...)
+	{
+		secdebug("scsel", "  exception while displaying device path - ignoring error");
+		return false;
+	}
+	
+	return true;
+}
+
+#pragma mark -------------------- Termination Notice Receiver --------------------
+
+TerminationNoticeReceiver::~TerminationNoticeReceiver()
+{
+}
+
+void TerminationNoticeReceiver::ioChange(IOKit::DeviceIterator &iterator)
+{
+	secdebug("pcsc", "[TerminationNoticeReceiver] Processing ioChange notification");
+	// Always drain this iterator
+	while (IOKit::Device dev = iterator())
+	{
+		PCSCDMonitor::displayPropertiesOfDevice(dev);
+		parent().removeDeviceByName(dev);
+	}
+}
+
+void TerminationNoticeReceiver::ioServiceChange(void *refCon, io_service_t service,
+	natural_t messageType, void *messageArgument)
+{
+	secdebug("pcsc", "  [TerminationNoticeReceiver] processing ioServiceChange notice: 0x%08X [refCon=0x%08X, service=0x%08X, arg=0x%08X]", 
+		messageType, (uint32_t)refCon, service, (uint32_t)messageArgument);
+	parent().ioServiceChange(refCon, service, messageType, messageArgument);
+}
+
+#pragma mark -------------------- Debug Routines --------------------
+
+void PCSCDMonitor::displayPropertiesOfDevice(const IOKit::Device &dev)
+{
+	/*
+		Many of these properties are only defined on the "IOUSBDevice" plane, so
+		will be non-empty on the third iteration.
+	*/
+	try
+	{
+		std::string vendorName, productName, serialNumber, name;
+
+		uint32_t vendorID, productID;
+		bool isPCCard;
+		
+		CFRef<CFStringRef> ioName = dev.property<CFStringRef>(kzIOPCCardIONameKey);
+		if (ioName)
+			name = cfString(ioName);
+
+		getVendorAndProductID(dev, vendorID, productID, isPCCard);
+
+		if (CFRef<CFStringRef> cfSerialString = dev.property<CFStringRef>(kzIOUSBSerialNumberKey))
+			serialNumber = cfString(cfSerialString);
+
+		if (isPCCard)
+		{
+			if (CFRef<CFArrayRef> cfVersionOne = dev.property<CFArrayRef>(kIOPCCardVersionOneMatchKey))
+			if (CFArrayGetCount(cfVersionOne) > 1)
+			{
+				CFStringRef cfVendorString = (CFStringRef)CFArrayGetValueAtIndex(cfVersionOne, 0);
+				if (cfVendorString)
+					vendorName = cfString(cfVendorString);
+
+				CFStringRef cfProductString = (CFStringRef)CFArrayGetValueAtIndex(cfVersionOne, 1);
+				if (cfProductString)
+					productName = cfString(cfProductString);
+			}
+		
+			uint32_t address;
+			deviceMemoryAddress(dev, address);
+		}
+		else
+		{
+			if (CFRef<CFStringRef> cfVendorString = dev.property<CFStringRef>(kzIOUSBVendorNameKey))
+				vendorName = cfString(cfVendorString);
+
+			if (CFRef<CFStringRef> cfProductString = dev.property<CFStringRef>(kzIOUSBProductNameKey))
+				productName = cfString(cfProductString);
+		}
+
+		secdebug("scsel", "--- properties: service: 0x%04X, name: %s, vendor/product: 0x%04X/0x%04X, vendor: %s, product: %s, serial: %s", 
+			dev.ioObject(), name.c_str(), vendorID, productID,
+			vendorName.c_str(), productName.c_str(), serialNumber.c_str());
+	}
+	catch (...)
+	{
+		secdebug("scsel", "  exception in displayPropertiesOfDevice - ignoring error");
+	}
+}
+
+void PCSCDMonitor::displayPropertiesOfDevice(io_service_t service)
+{
+    kern_return_t	kr;
+    CFMutableDictionaryRef properties = NULL;
+
+	// get a copy of the in kernel registry object
+	kr = IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, 0);
+	if (kr != KERN_SUCCESS)
+	{
+	    printf("IORegistryEntryCreateCFProperties failed with %x\n", kr);
+	}
+	else
+	if (properties)
+	{
+//		CFShow(properties);
+		CFRelease(properties);
+	}
+
+	try
+	{
+		std::string vendorName, productName, serialNumber, name;
+
+		uint32_t vendorID, productID;
+		bool isPCCard;
+		
+		CFRef<CFStringRef> ioName = static_cast<CFStringRef>(::IORegistryEntryCreateCFProperty(
+			service, CFSTR(kzIOPCCardIONameKey), kCFAllocatorDefault, 0));
+		if (ioName)
+			name = cfString(ioName);
+
+//		getVendorAndProductID(dev, vendorID, productID, isPCCard);
+
+		CFRef<CFStringRef> cfSerialString = static_cast<CFStringRef>(::IORegistryEntryCreateCFProperty(
+			service, CFSTR(kzIOUSBSerialNumberKey), kCFAllocatorDefault, 0));
+		if (cfSerialString)
+			serialNumber = cfString(cfSerialString);
+
+		if (isPCCard)
+		{
+			CFRef<CFArrayRef> cfVersionOne = static_cast<CFArrayRef>(::IORegistryEntryCreateCFProperty(
+				service, CFSTR(kIOPCCardVersionOneMatchKey), kCFAllocatorDefault, 0));
+			if (cfVersionOne && (CFArrayGetCount(cfVersionOne) > 1))
+			{
+				CFStringRef cfVendorString = (CFStringRef)CFArrayGetValueAtIndex(cfVersionOne, 0);
+				if (cfVendorString)
+					vendorName = cfString(cfVendorString);
+
+				CFStringRef cfProductString = (CFStringRef)CFArrayGetValueAtIndex(cfVersionOne, 1);
+				if (cfProductString)
+					productName = cfString(cfProductString);
+			}
+		
+			uint32_t address;
+			deviceMemoryAddress(service, address);
+		}
+		else
+		{
+			CFRef<CFStringRef> cfVendorString = static_cast<CFStringRef>(::IORegistryEntryCreateCFProperty(
+				service, CFSTR(kzIOUSBVendorNameKey), kCFAllocatorDefault, 0));
+			if (cfVendorString)
+				vendorName = cfString(cfVendorString);
+
+			CFRef<CFStringRef> cfProductString = static_cast<CFStringRef>(::IORegistryEntryCreateCFProperty(
+				service, CFSTR(kzIOUSBProductNameKey), kCFAllocatorDefault, 0));
+			if (cfProductString)
+				productName = cfString(cfProductString);
+		}
+
+		secdebug("scsel", "--- properties: service: 0x%04X, name: %s, vendor/product: 0x%04X/0x%04X, vendor: %s, product: %s, serial: %s", 
+			service, name.c_str(), vendorID, productID,
+			vendorName.c_str(), productName.c_str(), serialNumber.c_str());
+	}
+	catch (...)
+	{
+		secdebug("scsel", "  exception in displayPropertiesOfDevice - ignoring error");
+	}
+}
+
+void PCSCDMonitor::dumpDevices()
+{
+	secdebug("pcsc", "------------------ Device Map ------------------");
+	for (DeviceMap::iterator it = mDevices.begin();it!=mDevices.end();++it)
+	{
+		PCSCD::Device *dev = static_cast<PCSCD::Device *>(it->second);
+		dev->dump();
+	}
+	secdebug("pcsc", "------------------------------------------------");
+}
+
+static void dumpdictentry(const void *key, const void *value, void *context)
+{
+	secdebug("dumpd", "  dictionary key: %s, val: %p, CFGetTypeID: %d", cfString((CFStringRef)key).c_str(), value, (int)CFGetTypeID(value));
+}
+

Added: trunk/SmartCardServices/src/PCSC/pcscdmonitor.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/pcscdmonitor.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/pcscdmonitor.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+//
+// pcscmonitor - use PCSC to monitor smartcard reader/card state for securityd
+//
+#ifndef _H_PCSCDMONITOR
+#define _H_PCSCDMONITOR
+
+#include <security_utilities/powerwatch.h>
+#include <security_utilities/pcsc++.h>
+#include <security_utilities/refcount.h>
+#include <security_utilities/iodevices.h>
+#include <security_utilities/threading.h>
+#include <securityd_client/ssclient.h>
+
+#include "pcscdserver.h"
+#include "PCSCDevice.h"
+#include "PCSCDriverBundles.h"
+
+typedef int32_t (*addDeviceCallback)(const char *name, uint32_t address, const char *pathLibrary, const char *pathDevice);
+typedef int32_t (*removeDeviceCallback)(const char *name, uint32_t address);
+typedef int32_t (*willSleepCallback)();
+typedef int32_t (*isWakingCallback)();
+
+#if defined(__cplusplus)
+
+class PCSCDMonitor;
+
+class TerminationNoticeReceiver : public IOKit::NotificationPort::Receiver
+{
+public:
+	TerminationNoticeReceiver(PCSCDMonitor &parent) : mParent(parent) {}
+	virtual ~TerminationNoticeReceiver();
+	
+	virtual void ioChange(IOKit::DeviceIterator &iterator);
+	virtual void ioServiceChange(void *refCon, io_service_t service,	//IOServiceInterestCallback
+		natural_t messageType, void *messageArgument);
+		
+	virtual PCSCDMonitor &parent() { return mParent; }
+
+private:
+	PCSCDMonitor &mParent;
+};
+
+//
+// A PCSCMonitor uses PCSC to monitor the state of smartcard readers and
+// tokens (cards) in the system, and dispatches messages and events to the
+// various related players in securityd. There should be at most one of these
+// objects active within securityd.
+//
+class PCSCDMonitor :
+	private MachPlusPlus::MachServer::Timer,
+	private IOKit::NotificationPort::Receiver,
+	private MachPlusPlus::PowerWatcher
+{
+public:
+
+	friend class TerminationNoticeReceiver;
+	
+	PCSCDMonitor(PCSCD::Server &server, PCSCD::DriverBundles &drivers);
+	void setCallbacks(addDeviceCallback theAddDeviceCallback, removeDeviceCallback theRemoveDeviceCallback,
+		willSleepCallback theWillSleepCallback, isWakingCallback theIsWakingCallback)
+		{ mAddDeviceCallback = theAddDeviceCallback; mRemoveDeviceCallback = theRemoveDeviceCallback;
+		  mWillSleepCallback = theWillSleepCallback; mIsWakingCallback = theIsWakingCallback; }
+		  
+	static void postNotification(const SecurityServer::NotificationEvent event);
+	
+	void systemAwakeAndReadyCheck();
+
+protected:
+	
+	PCSCD::Server &server;
+	PCSCD::DriverBundles &drivers;
+	addDeviceCallback mAddDeviceCallback;
+	removeDeviceCallback mRemoveDeviceCallback;
+	willSleepCallback mWillSleepCallback;
+	isWakingCallback mIsWakingCallback;
+
+protected:
+	// MachServer::Timer
+	void action();
+	
+	// NotificationPort::Receiver
+	void ioChange(IOKit::DeviceIterator &iterator);
+	void ioServiceChange(void *refCon, io_service_t service, natural_t messageType, void *messageArgument);
+
+	// PowerWatcher
+	void systemWillSleep();
+	void systemIsWaking();
+		
+protected:
+	void scheduleTimer(bool enable);
+	void initialSetup();
+	void noDeviceTimeout();
+
+	enum DeviceSupport
+	{
+		impossible,				// certain this is not a smartcard
+		definite,				// definitely a smartcard device
+		possible				// perhaps... we're not sure
+	};
+	DeviceSupport deviceSupport(const IOKit::Device &dev);
+	
+	void addDevice(const IOKit::Device &dev);
+	void removeDevice(io_service_t service, uint32_t address);
+	void removeDeviceByName(const IOKit::Device &dev);
+	bool hasLegacyDriver(const IOKit::Device &dev);
+	bool isExcludedDevice(const IOKit::Device &dev);
+	void scheduleAddInterestNotification(io_service_t serviceOfInterest);
+	void addInterestNotification();
+	void removeAllDevices();
+	void AddIOKitNotifications();
+	void RemoveIOKitNotifications();
+	void rescanExistingDevices();
+
+	typedef std::map<uint32_t, RefPointer<PCSCD::Device> > DeviceMap;
+	DeviceMap mDevices;
+
+	mutable Mutex mDeviceMapLock;
+
+	void insert(pair<uint32_t, RefPointer<PCSCD::Device> > devicepair) { StLock<Mutex> _(mDeviceMapLock); mDevices.insert(devicepair); }
+	void remove(DeviceMap::iterator it) { StLock<Mutex> _(mDeviceMapLock); mDevices.erase(it); }
+
+private:
+	void (PCSCDMonitor::*mTimerAction)();		// what to do when our timer fires	
+	bool mGoingToSleep;							// between sleep and wakeup; special timer handling
+
+	mutable Mutex mLock;
+
+	IOKit::MachPortNotificationPort mIOKitNotifier;	// IOKit connection
+	TerminationNoticeReceiver mTerminationNoticeReceiver;
+	
+	io_object_t mRemoveNotification;
+	io_service_t mServiceOfInterest;
+
+	bool mSleepWakePeriod;
+	mutable Mutex mSleepWakePeriodLock;
+	mutable Mutex mWakeConditionLock;
+	Condition mWakeConditionVariable;
+	bool isSleepWakePeriod() const;
+	void sleepWakePeriod(bool isASleepWakePeriod);
+	void setSystemIsAwakeCondition(bool isAwake);
+
+	bool findDevice(const IOKit::Device &dev, DeviceMap::iterator &it);
+	bool findDeviceByName(const IOKit::Device &dev, DeviceMap::iterator &outit);
+	void updateDevice(const IOKit::Device &dev);
+	void setDeviceProperties(const IOKit::Device &dev, PCSCD::Device &device);
+
+	static void getVendorAndProductID(const IOKit::Device &dev, uint32_t &vendorID, uint32_t &productID, bool &isPCCard);
+	static bool deviceIsPCCard(const IOKit::Device &dev);
+	static bool deviceIsPCCard(io_service_t service);
+	static bool deviceAddress(io_service_t service, uint32_t &address);
+	static bool deviceAddress(const IOKit::Device &dev, uint32_t &address);
+	static bool deviceMemoryAddress(const IOKit::Device &dev, uint32_t &address);
+	static bool deviceMemoryAddress(io_service_t service, uint32_t &address);
+	static bool deviceMemoryAddressCore(CFArrayRef cfDeviceMemory, std::string path, uint32_t &address);
+	static bool addressFromPath(std::string path, uint32_t &address);
+
+	// debug
+	void setDebugPropertiesForDevice(const IOKit::Device &dev, PCSCD::Device* newDevice);
+	static void displayPropertiesOfDevice(const IOKit::Device &dev);
+	static void displayPropertiesOfDevice(io_service_t service);
+	void dumpDevices();
+};
+
+#endif /* __cplusplus__ */
+
+#endif //_H_PCSCDMONITOR
+

Added: trunk/SmartCardServices/src/PCSC/pcscdserver.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/pcscdserver.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/pcscdserver.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// server - pcscd main server object
+//
+#include "pcscdserver.h"
+#include <mach/mach_error.h>
+
+using namespace Security;
+using namespace MachPlusPlus;
+
+namespace PCSCD {
+
+Server::Server(const char *bootstrapName) : MachServer(bootstrapName),
+    mBootstrapName(bootstrapName)
+{
+	// Construct the server object
+    // engage the subsidiary port handler for sleep notifications
+	add(sleepWatcher);
+}
+
+Server::~Server()
+{
+	// Clean up the server object
+}
+
+void Server::run()
+{
+	// Run the server. This will not return until the server is forced to exit.
+	MachServer::run(0x10000,
+        MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
+        MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT));
+}
+
+//
+// Handle thread overflow. MachServer will call this if it has hit its thread
+// limit and yet still needs another thread.
+//
+void Server::threadLimitReached(UInt32 limit)
+{
+//	Syslog::notice("pcscd has reached its thread limit (%ld) - service deadlock is possible",
+//		limit);
+}
+
+void Server::notifyDeadName(Port port)
+{
+	// Handling dead-port notifications.
+	// This receives DPNs for all kinds of ports we're interested in.
+	StLock<Mutex> _(mLock);
+	secdebug("SSports", "port %d is dead", port.port());
+
+	// well, what IS IT?!
+	secdebug("server", "spurious dead port notification for port %d", port.port());
+}
+
+//
+// Handling no-senders notifications.
+// This is currently only used for (subsidiary) service ports
+//
+void Server::notifyNoSenders(Port port, mach_port_mscount_t)
+{
+	secdebug("SSports", "port %d no senders", port.port());
+//	Session::destroy(port);
+}
+
+void Server::notifyIfDead(MachPlusPlus::Port port, bool doNotify) const
+{
+	secdebug("SSports", "port %d is dead", port.port());
+	MachServer::notifyIfDead(port, doNotify);
+}
+
+void Server::notifyIfUnused(MachPlusPlus::Port port, bool doNotify) const
+{
+	secdebug("SSports", "port %d is dead", port.port());
+	MachServer::notifyIfUnused(port, doNotify);
+}
+
+void Server::SleepWatcher::systemWillSleep()
+{
+	// Notifier for system sleep events
+    secdebug("SS", "sleep notification received");
+//    Session::processSystemSleep();
+	secdebug("server", "distributing sleep event to %ld clients", mPowerClients.size());
+	for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
+		(*it)->systemWillSleep();
+}
+
+void Server::SleepWatcher::systemIsWaking()
+{
+	secdebug("server", "distributing wakeup event to %ld clients", mPowerClients.size());
+	for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
+		(*it)->systemIsWaking();
+}
+
+void Server::SleepWatcher::add(PowerWatcher *client)
+{
+	assert(mPowerClients.find(client) == mPowerClients.end());
+	mPowerClients.insert(client);
+}
+
+void Server::SleepWatcher::remove(PowerWatcher *client)
+{
+	assert(mPowerClients.find(client) != mPowerClients.end());
+	mPowerClients.erase(client);
+}
+
+boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
+{
+	// The primary server run-loop function
+    secdebug("SSreq", "Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)");
+	return false;
+}
+
+
+} // end namespace PCSCD
+

Added: trunk/SmartCardServices/src/PCSC/pcscdserver.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/pcscdserver.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/pcscdserver.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// pcscdserver - stripped down securityd main server object
+//
+#ifndef _H_PCSCDSERVER
+#define _H_PCSCDSERVER
+
+#include <security_utilities/machserver.h>
+#include <security_utilities/powerwatch.h>
+#include <map>
+
+#if defined(__cplusplus)
+
+namespace PCSCD {
+//
+// The server object itself. This is the "go to" object for anyone who wants
+// to access the server's global state. It runs the show.
+// There is only one Server, and its name is Server::active().
+//
+
+class Server : public MachPlusPlus::MachServer
+{
+public:
+	Server(const char *bootstrapName);
+	~Server();
+		
+    // run the server until it shuts down
+	void run();
+	
+    //
+    // Retrieve pieces of the Server's object web.
+    // These are all static methods that use the active() Server of this thread.
+    //
+	static Server &active() { return safer_cast<Server &>(MachServer::active()); }
+	static const char *bootstrapName() { return active().mBootstrapName.c_str(); }
+
+protected:
+    // implementation methods of MachServer
+	boolean_t handle(mach_msg_header_t *in, mach_msg_header_t *out);
+	void notifyDeadName(MachPlusPlus::Port port);
+	void notifyNoSenders(MachPlusPlus::Port port, mach_port_mscount_t);
+	void threadLimitReached(UInt32 count);
+	// request port status notifications (override virtual methods below to receive)
+	virtual void notifyIfDead(MachPlusPlus::Port port, bool doNotify = true) const;
+	virtual void notifyIfUnused(MachPlusPlus::Port port, bool doNotify = true) const;
+
+private:
+	class SleepWatcher : public MachPlusPlus::PortPowerWatcher
+	{
+	public:
+		void systemWillSleep();
+		void systemIsWaking();
+		
+		void add(PowerWatcher *client);
+		void remove(PowerWatcher *client);
+
+	private:
+		set<PowerWatcher *> mPowerClients;
+	};
+
+	SleepWatcher sleepWatcher;
+	
+public:
+	using MachServer::add;
+	using MachServer::remove;
+	void add(MachPlusPlus::PowerWatcher *client)	{ StLock<Mutex> _(mLock); sleepWatcher.add(client); }
+	void remove(MachPlusPlus::PowerWatcher *client)	{ StLock<Mutex> _(mLock); sleepWatcher.remove(client); }
+    
+private:
+	// mach bootstrap registration name
+	std::string mBootstrapName;
+	mutable Mutex mLock;	
+};
+
+} // end namespace PCSCD
+
+#endif /* __cplusplus__ */
+
+#endif //_H_PCSCDSERVER

Added: trunk/SmartCardServices/src/PCSC/pcscexport.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/pcscexport.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/pcscexport.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,62 @@
+/*
+ * This handles GCC attributes
+ *
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2005
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: misc.h 2188 2006-10-19 11:29:29Z rousseau $
+ */
+
+#ifndef __misc_h__
+#define __misc_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ * Declare the function as internal to the library: the function name is
+ * not exported and can't be used by a program linked to the library
+ *
+ * see http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gcc/Function-Attributes.html#Function-Attributes
+ * see http://www.nedprod.com/programs/gccvisibility.html
+ */
+#if defined __GNUC__ && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
+#define INTERNAL __attribute__ ((visibility("hidden")))
+/*
+#define PCSC_API __attribute__ ((visibility("default")))
+We don't want to change how this was defined in previous versions*/
+#define PCSC_API
+#else
+#define INTERNAL
+#define PCSC_API
+#endif
+#define EXTERNAL PCSC_API
+
+#if defined __GNUC__
+
+/* GNU Compiler Collection (GCC) */
+#define CONSTRUCTOR __attribute__ ((constructor))
+#define DESTRUCTOR __attribute__ ((destructor))
+
+#else
+
+/* SUN C compiler does not use __attribute__ but #pragma init (function)
+ * We can't use a # inside a #define so it is not possible to use
+ * #define CONSTRUCTOR_DECLARATION(x) #pragma init (x)
+ * The #pragma is used directly where needed */
+
+/* any other */
+#define CONSTRUCTOR
+#define DESTRUCTOR
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __misc_h__ */

Added: trunk/SmartCardServices/src/PCSC/pcsclite.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/pcsclite.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/pcsclite.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: pcsclite.h.in 2124 2006-08-07 14:18:52Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This keeps a list of defines for pcsc-lite.
+ */
+
+#ifndef __pcsclite_h__
+#define __pcsclite_h__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef int32_t SCARDCONTEXT;
+typedef SCARDCONTEXT *PSCARDCONTEXT;
+typedef SCARDCONTEXT *LPSCARDCONTEXT;
+typedef int32_t SCARDHANDLE;
+typedef SCARDHANDLE *PSCARDHANDLE;
+typedef SCARDHANDLE *LPSCARDHANDLE;
+
+#define MAX_ATR_SIZE			33	/**< Maximum ATR size */
+
+/* Set structure elements aligment on bytes
+ * http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */
+#ifdef __APPLE__
+#pragma pack(1)
+#else
+#pragma pack(push, 1)
+#endif
+
+typedef struct
+{
+	const char *szReader;
+	void *pvUserData;
+	uint32_t dwCurrentState;
+	uint32_t dwEventState;
+	uint32_t cbAtr;
+	unsigned char rgbAtr[MAX_ATR_SIZE];
+}
+SCARD_READERSTATE_A;
+
+typedef SCARD_READERSTATE_A SCARD_READERSTATE, *PSCARD_READERSTATE_A,
+	*LPSCARD_READERSTATE_A;
+
+typedef struct _SCARD_IO_REQUEST
+{
+	uint32_t dwProtocol;	/* Protocol identifier */
+	uint32_t cbPciLength;	/* Protocol Control Inf Length */
+}
+SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST;
+
+typedef const SCARD_IO_REQUEST *LPCSCARD_IO_REQUEST;
+
+extern SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci,
+	g_rgSCardRawPci;
+
+/* restore default structure elements alignment */
+#ifdef __APPLE__
+#pragma pack()
+#else
+#pragma pack(pop)
+#endif
+
+#define SCARD_PCI_T0	(&g_rgSCardT0Pci)
+#define SCARD_PCI_T1	(&g_rgSCardT1Pci)
+#define SCARD_PCI_RAW	(&g_rgSCardRawPci)
+
+#define SCARD_S_SUCCESS			0x00000000
+#define SCARD_E_CANCELLED		0x80100002
+#define SCARD_E_CANT_DISPOSE		0x8010000E
+#define SCARD_E_INSUFFICIENT_BUFFER	0x80100008
+#define SCARD_E_INVALID_ATR		0x80100015
+#define SCARD_E_INVALID_HANDLE		0x80100003
+#define SCARD_E_INVALID_PARAMETER	0x80100004
+#define SCARD_E_INVALID_TARGET		0x80100005
+#define SCARD_E_INVALID_VALUE		0x80100011
+#define SCARD_E_NO_MEMORY		0x80100006
+#define SCARD_F_COMM_ERROR		0x80100013
+#define SCARD_F_INTERNAL_ERROR		0x80100001
+#define SCARD_F_UNKNOWN_ERROR		0x80100014
+#define SCARD_F_WAITED_TOO_LONG		0x80100007
+#define SCARD_E_UNKNOWN_READER		0x80100009
+#define SCARD_E_TIMEOUT			0x8010000A
+#define SCARD_E_SHARING_VIOLATION	0x8010000B
+#define SCARD_E_NO_SMARTCARD		0x8010000C
+#define SCARD_E_UNKNOWN_CARD		0x8010000D
+#define SCARD_E_PROTO_MISMATCH		0x8010000F
+#define SCARD_E_NOT_READY		0x80100010
+#define SCARD_E_SYSTEM_CANCELLED	0x80100012
+#define SCARD_E_NOT_TRANSACTED		0x80100016
+#define SCARD_E_READER_UNAVAILABLE	0x80100017
+
+#define SCARD_W_UNSUPPORTED_CARD	0x80100065
+#define SCARD_W_UNRESPONSIVE_CARD	0x80100066
+#define SCARD_W_UNPOWERED_CARD		0x80100067
+#define SCARD_W_RESET_CARD		0x80100068
+#define SCARD_W_REMOVED_CARD		0x80100069
+
+#define SCARD_E_PCI_TOO_SMALL		0x80100019
+#define SCARD_E_READER_UNSUPPORTED	0x8010001A
+#define SCARD_E_DUPLICATE_READER	0x8010001B
+#define SCARD_E_CARD_UNSUPPORTED	0x8010001C
+#define SCARD_E_NO_SERVICE		0x8010001D
+#define SCARD_E_SERVICE_STOPPED		0x8010001E
+
+#define SCARD_SCOPE_USER		0x0000	/**< Scope in user space */
+#define SCARD_SCOPE_TERMINAL		0x0001	/**< Scope in terminal */
+#define SCARD_SCOPE_SYSTEM		0x0002	/**< Scope in system */
+
+#define SCARD_PROTOCOL_UNSET		0x0000	/**< protocol not set */
+#define SCARD_PROTOCOL_T0		0x0001	/**< T=0 active protocol. */
+#define SCARD_PROTOCOL_T1		0x0002	/**< T=1 active protocol. */
+#define SCARD_PROTOCOL_RAW		0x0004	/**< Raw active protocol. */
+#define SCARD_PROTOCOL_T15		0x0008	/**< T=15 protocol. */
+
+#define SCARD_PROTOCOL_ANY		(SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1)	/**< IFD determines prot. */
+
+#define SCARD_SHARE_EXCLUSIVE		0x0001	/**< Exclusive mode only */
+#define SCARD_SHARE_SHARED		0x0002	/**< Shared mode only */
+#define SCARD_SHARE_DIRECT		0x0003	/**< Raw mode only */
+
+#define SCARD_LEAVE_CARD		0x0000	/**< Do nothing on close */
+#define SCARD_RESET_CARD		0x0001	/**< Reset on close */
+#define SCARD_UNPOWER_CARD		0x0002	/**< Power down on close */
+#define SCARD_EJECT_CARD		0x0003	/**< Eject on close */
+
+#define SCARD_UNKNOWN			0x0001	/**< Unknown state */
+#define SCARD_ABSENT			0x0002	/**< Card is absent */
+#define SCARD_PRESENT			0x0004	/**< Card is present */
+#define SCARD_SWALLOWED			0x0008	/**< Card not powered */
+#define SCARD_POWERED			0x0010	/**< Card is powered */
+#define SCARD_NEGOTIABLE		0x0020	/**< Ready for PTS */
+#define SCARD_SPECIFIC			0x0040	/**< PTS has been set */
+
+#define SCARD_STATE_UNAWARE		0x0000	/**< App wants status */
+#define SCARD_STATE_IGNORE		0x0001	/**< Ignore this reader */
+#define SCARD_STATE_CHANGED		0x0002	/**< State has changed */
+#define SCARD_STATE_UNKNOWN		0x0004	/**< Reader unknown */
+#define SCARD_STATE_UNAVAILABLE		0x0008	/**< Status unavailable */
+#define SCARD_STATE_EMPTY		0x0010	/**< Card removed */
+#define SCARD_STATE_PRESENT		0x0020	/**< Card inserted */
+#define SCARD_STATE_ATRMATCH		0x0040	/**< ATR matches card */
+#define SCARD_STATE_EXCLUSIVE		0x0080	/**< Exclusive Mode */
+#define SCARD_STATE_INUSE		0x0100	/**< Shared Mode */
+#define SCARD_STATE_MUTE		0x0200	/**< Unresponsive card */
+#define SCARD_STATE_UNPOWERED		0x0400	/**< Unpowered card */
+
+/** PC/SC Lite specific extensions */
+#define SCARD_W_INSERTED_CARD		0x8010006A
+#define SCARD_E_UNSUPPORTED_FEATURE	0x8010001F
+
+#define SCARD_SCOPE_GLOBAL		0x0003	/**< Scope is global */
+
+#define SCARD_RESET			0x0001	/**< Card was reset */
+#define SCARD_INSERTED			0x0002	/**< Card was inserted */
+#define SCARD_REMOVED			0x0004	/**< Card was removed */
+
+#define BLOCK_STATUS_RESUME		0x00FF	/**< Normal resume */
+#define BLOCK_STATUS_BLOCKING		0x00FA	/**< Function is blocking */
+
+#define PCSCLITE_CONFIG_DIR		"/etc"
+
+#ifndef USE_IPCDIR
+#define PCSCLITE_IPC_DIR		"/var/run"
+#else
+#define PCSCLITE_IPC_DIR		USE_IPCDIR
+#endif
+
+#define PCSCLITE_READER_CONFIG		PCSCLITE_CONFIG_DIR "/reader.conf"
+#define PCSCLITE_PUBSHM_FILE		PCSCLITE_IPC_DIR "/pcscd.pub"
+#define PCSCLITE_CSOCK_NAME		PCSCLITE_IPC_DIR "/pcscd.comm"
+
+#define PCSCLITE_SVC_IDENTITY		0x01030000	/**< Service ID */
+
+#ifndef INFINITE
+#define INFINITE			0xFFFFFFFF	/**< Infinite timeout */
+#endif
+#define PCSCLITE_INFINITE_TIMEOUT	4320000		/**< 50 day infinite t/o */
+
+#define PCSCLITE_VERSION_NUMBER		"1.4.0"	/**< Current version */
+#define PCSCLITE_CLIENT_ATTEMPTS	120		/**< Attempts to reach sv */
+#define PCSCLITE_MCLIENT_ATTEMPTS	20		/**< Attempts to reach sv */
+#define PCSCLITE_STATUS_POLL_RATE	400000		/**< Status polling rate */
+#define PCSCLITE_MSG_KEY_LEN		16		/**< App ID key length */
+#define PCSCLITE_RW_ATTEMPTS		100		/**< Attempts to rd/wrt */
+
+/** Maximum applications */
+#define PCSCLITE_MAX_APPLICATIONS			16
+/** Maximum contexts by application */
+#define PCSCLITE_MAX_APPLICATION_CONTEXTS		16
+/** Maximum of applications contexts that pcscd can accept */
+#define PCSCLITE_MAX_APPLICATIONS_CONTEXTS \
+	PCSCLITE_MAX_APPLICATIONS * PCSCLITE_MAX_APPLICATION_CONTEXTS
+/** Maximum channels on a reader context */
+#define PCSCLITE_MAX_READER_CONTEXT_CHANNELS		16
+/** Maximum channels on an application context */
+#define PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS	16
+/** Maximum readers context (a slot is count as a reader) */
+#define PCSCLITE_MAX_READERS_CONTEXTS			16
+
+/* PCSCLITE_MAX_READERS is deprecated
+ * use PCSCLITE_MAX_READERS_CONTEXTS instead */
+/* extern int PCSCLITE_MAX_READERS __attribute__ ((deprecated)); */
+
+#define PCSCLITE_MAX_THREADS		16	/**< Stat change threads */
+#define PCSCLITE_STATUS_WAIT		200000	/**< Status Change Sleep */
+#define PCSCLITE_TRANSACTION_TIMEOUT	40	/**< Transaction timeout */
+#define MAX_READERNAME			52
+#define MAX_LIBNAME			100
+#define MAX_DEVICENAME		255
+
+#ifndef SCARD_ATR_LENGTH
+#define SCARD_ATR_LENGTH		MAX_ATR_SIZE	/**< Maximum ATR size */
+#endif
+
+/* These are deprecated */
+#define PCSCLITE_MAX_CHANNELS           16	/* Maximum channels */
+#define PCSCLITE_MAX_CONTEXTS           16	/* Maximum readers */
+#define PCSCLITE_MAX_COMSIZE            64	/* Maximum arg size */
+
+/*
+ * Enhanced messaging has been added to accomodate newer devices which have
+ * more advanced capabilites, such as dedicated secure co-processors which
+ * can stream and encrypt data over USB.  In order to used enhanced messaging
+ * you must define PCSCLITE_ENHANCED_MESSAGING in the framework(library), 
+ * the daemon, and your application
+ */
+
+/*
+ * The message and buffer sizes must be multiples of 16.
+ * The max message size must be at least large enough
+ * to accomodate the transmit_struct
+ */
+
+#ifndef PCSCLITE_ENHANCED_MESSAGING
+#define PCSCLITE_MAX_MESSAGE_SIZE	2048	/**< Transport msg len */
+#define MAX_BUFFER_SIZE			264	/**< Maximum Tx/Rx Buffer for short APDU */
+#define PCSCLITE_SERVER_ATTEMPTS	5	/**< Attempts to reach cl */
+#else
+#define PCSCLITE_MAX_MESSAGE_SIZE       (1<<17)  /* enhanced (128K) msg len */
+#define MAX_BUFFER_SIZE                 (1<<15)  /* enhanced (32K) Tx/Rx Buffer */
+#define PCSCLITE_SERVER_ATTEMPTS         200     /* To allow larger data reads/writes */
+#endif
+
+#define MAX_BUFFER_SIZE_EXTENDED	(4 + 3 + (1<<16) + 3)	/**< enhanced (64K + APDU + Lc + Le) Tx/Rx Buffer */
+
+/*
+ * Gets a stringified error response 
+ */
+char *pcsc_stringify_error(int32_t err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

Added: trunk/SmartCardServices/src/PCSC/powermgt_generic.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/powermgt_generic.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/powermgt_generic.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	Title  : powermgt_generic.h
+	Package: pcsc lite
+	Author : David Corcoran
+	Date   : 04/22/02
+	License: Copyright (C) 2002 David Corcoran
+		<corcoran at linuxnet.com>
+	Purpose: This handles power management routines. 
+
+$Id: powermgt_generic.h,v 1.2 2003/02/13 20:06:28 ghoo Exp $
+
+********************************************************************/
+
+#ifndef __powermgt_generic_h__
+#define __powermgt_generic_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/* 
+ * Registers for Power Management callbacks 
+ */
+
+ULONG PMRegisterForPowerEvents();
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PCSC/powermgt_macosx.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/powermgt_macosx.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/powermgt_macosx.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+cc test2.c -o pm_callback -Wall -Wno-four-char-constants -framework IOKit -framework CoreFoundation
+*/
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <mach/mach_port.h>
+#include <mach/mach_interface.h>
+#include <mach/mach_init.h>
+
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <IOKit/IOMessage.h>
+
+#include "config.h"
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "debuglog.h"
+#include "readerfactory.h"
+#include "thread_generic.h"
+#include "hotplug.h"
+
+
+static io_connect_t		root_port;
+static IONotificationPortRef	notify;
+static io_object_t 		anIterator;
+
+PCSCLITE_THREAD_T       pmgmtThread;
+extern PCSCLITE_MUTEX   usbNotifierMutex;
+
+void PMPowerRegistrationThread();
+
+
+void PMPowerEventCallback(void * x,io_service_t y,natural_t messageType,void * messageArgument)
+{
+
+    switch ( messageType ) {
+    case kIOMessageCanSystemSleep:
+          IOAllowPowerChange(root_port,(long)messageArgument);
+          break;
+    case kIOMessageSystemWillSleep:
+          DebugLogA("PMPowerEventCallback: system will sleep");
+          SYS_MutexLock(&usbNotifierMutex);
+	// see WrapRFSuspendAllReaders
+    //      RFSuspendAllReaders();
+          IOAllowPowerChange(root_port,(long)messageArgument);
+          DebugLogA("PMPowerEventCallback: system allowed to sleep");
+          break;
+    case kIOMessageSystemHasPoweredOn: 
+        DebugLogA("PMPowerEventCallback: system has powered on");
+    // see WrapRFSuspendAllReaders
+	//    HPSearchHotPluggables();       
+     //   RFAwakeAllReaders();
+        SYS_MutexUnLock(&usbNotifierMutex);
+        break;
+	case kIOMessageSystemWillPowerOn:
+        DebugLogA("PMPowerEventCallback: system will power on");
+		break;
+	default:
+		DebugLogB("PMPowerEventCallback: unknown event: %d", messageType);
+		break;
+    }
+    
+}
+
+void PMPowerRegistrationThread() {
+
+    root_port = IORegisterForSystemPower (0,&notify,PMPowerEventCallback,&anIterator);
+  
+    if ( root_port == 0 ) {
+            printf("IORegisterForSystemPower failed\n");
+            return;
+    }
+    
+    CFRunLoopAddSource(CFRunLoopGetCurrent(),
+                        IONotificationPortGetRunLoopSource(notify),
+                        kCFRunLoopDefaultMode);
+                
+    CFRunLoopRun();
+}
+
+ULONG PMRegisterForPowerEvents()
+{
+	LONG rv;
+	DebugLogA("PMRegisterForPowerEvents");
+	rv = SYS_ThreadCreate(&pmgmtThread, THREAD_ATTR_DEFAULT, (LPVOID) PMPowerRegistrationThread, NULL);
+	return 0;
+}
+
+
+

Added: trunk/SmartCardServices/src/PCSC/prothandler.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/prothandler.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/prothandler.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,185 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  prothandler.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 2004
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: prothandler.c 2377 2007-02-05 13:13:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles protocol defaults, PTS, etc.
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "ifdhandler.h"
+#include "debuglog.h"
+#include "readerfactory.h"
+#include "prothandler.h"
+#include "atrhandler.h"
+#include "ifdwrapper.h"
+#include "eventhandler.h"
+
+/*
+ * Function: PHGetDefaultProtocol Purpose : To get the default protocol
+ * used immediately after reset. This protocol is returned from the
+ * function.
+ */
+
+UCHAR PHGetDefaultProtocol(const unsigned char *pucAtr, DWORD dwLength)
+{
+	SMARTCARD_EXTENSION sSmartCard;
+
+	/*
+	 * Zero out everything
+	 */
+	memset(&sSmartCard, 0x00, sizeof(SMARTCARD_EXTENSION));
+
+	if (ATRDecodeAtr(&sSmartCard, pucAtr, dwLength))
+		return sSmartCard.CardCapabilities.CurrentProtocol;
+	else
+		return 0x00;
+}
+
+/*
+ * Function: PHGetAvailableProtocols Purpose : To get the protocols
+ * supported by the card. These protocols are returned from the function
+ * as bit masks.
+ */
+
+UCHAR PHGetAvailableProtocols(const unsigned char *pucAtr, DWORD dwLength)
+{
+	SMARTCARD_EXTENSION sSmartCard;
+
+	/*
+	 * Zero out everything
+	 */
+	memset(&sSmartCard, 0x00, sizeof(SMARTCARD_EXTENSION));
+
+	if (ATRDecodeAtr(&sSmartCard, pucAtr, dwLength))
+		return sSmartCard.CardCapabilities.AvailableProtocols;
+	else
+		return 0x00;
+}
+
+/*
+ * Function: PHSetProtocol Purpose : To determine which protocol to use.
+ * SCardConnect has a DWORD dwPreferredProtocols that is a bitmask of what
+ * protocols to use.  Basically, if T=N where N is not zero will be used
+ * first if it is available in ucAvailable.  Otherwise it will always
+ * default to T=0.
+ *
+ * IFDSetPTS() is _always_ called so that the driver can initialise its data
+ */
+
+DWORD PHSetProtocol(struct ReaderContext * rContext,
+	DWORD dwPreferred, UCHAR ucAvailable, UCHAR ucDefault)
+{
+	DWORD protocol;
+	LONG rv;
+	UCHAR ucChosen;
+
+	/* App has specified no protocol */
+	if (dwPreferred == 0)
+		return SET_PROTOCOL_WRONG_ARGUMENT;
+
+	/* requested protocol is not available */
+	if (! (dwPreferred & ucAvailable))
+	{
+		/* Note:
+		 * dwPreferred must be either SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1
+		 * if dwPreferred == SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 the test
+		 * (SCARD_PROTOCOL_T0 == dwPreferred) will not work as expected
+		 * and the debug message will not be correct.
+		 *
+		 * This case may only occur if
+		 * dwPreferred == SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1
+		 * and ucAvailable == 0 since we have (dwPreferred & ucAvailable) == 0
+		 * and the case ucAvailable == 0 should never occur (the card is at
+		 * least T=0 or T=1)
+		 */
+		Log2(PCSC_LOG_ERROR, "Protocol T=%d requested but unsupported by the card",
+			(SCARD_PROTOCOL_T0 == dwPreferred) ? 0 : 1);
+		return SET_PROTOCOL_WRONG_ARGUMENT;
+	}
+
+	/* set default value */
+	protocol = ucDefault;
+
+	/* keep only the available protocols */
+	dwPreferred &= ucAvailable;
+
+	/* we try to use T=1 first */
+	if (dwPreferred & SCARD_PROTOCOL_T1)
+		ucChosen = SCARD_PROTOCOL_T1;
+	else
+		if (dwPreferred & SCARD_PROTOCOL_T0)
+			ucChosen = SCARD_PROTOCOL_T0;
+		else
+			/* App wants unsupported protocol */
+			return SET_PROTOCOL_WRONG_ARGUMENT;
+
+	Log2(PCSC_LOG_INFO, "Attempting PTS to T=%d",
+		(SCARD_PROTOCOL_T0 == ucChosen ? 0 : 1));
+	rv = IFDSetPTS(rContext, ucChosen, 0x00, 0x00, 0x00, 0x00);
+
+	if (IFD_SUCCESS == rv)
+		protocol = ucChosen;
+	else
+		if (IFD_NOT_SUPPORTED == rv)
+			Log2(PCSC_LOG_INFO, "PTS not supported by driver, using T=%d",
+				(SCARD_PROTOCOL_T0 == protocol) ? 0 : 1);
+		else
+			if (IFD_PROTOCOL_NOT_SUPPORTED == rv)
+				Log2(PCSC_LOG_INFO, "PTS protocol not supported, using T=%d",
+					(SCARD_PROTOCOL_T0 == protocol) ? 0 : 1);
+			else
+			{
+				Log3(PCSC_LOG_INFO, "PTS failed (%d), using T=%d", rv,
+					(SCARD_PROTOCOL_T0 == protocol) ? 0 : 1);
+
+				/* ISO 7816-3:1997 ch. 7.2 PPS protocol page 14
+				 * - If the PPS exchange is unsuccessful, then the interface device
+				 *   shall either reset or reject the card.
+				 */
+				return SET_PROTOCOL_PPS_FAILED;
+			}
+
+	return protocol;
+}
+

Added: trunk/SmartCardServices/src/PCSC/prothandler.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/prothandler.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/prothandler.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  prothandler.h
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 2004
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: prothandler.h 1421 2005-04-12 12:09:21Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles protocol defaults, PTS, etc.
+ */
+
+#ifndef __prothandler_h__
+#define __prothandler_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	UCHAR PHGetDefaultProtocol(const unsigned char *, DWORD);
+	UCHAR PHGetAvailableProtocols(const unsigned char *, DWORD);
+	DWORD PHSetProtocol(struct ReaderContext *, DWORD, UCHAR, UCHAR);
+
+#define SET_PROTOCOL_WRONG_ARGUMENT -1
+#define SET_PROTOCOL_PPS_FAILED -2
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __prothandler_h__ */

Added: trunk/SmartCardServices/src/PCSC/reader.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/reader.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/reader.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  reader.cpp
+ *  SmartCardServices
+*/
+
+#include "reader.h"
+#include "eventhandler.h"
+#include "pcsclite.h"
+#include <security_utilities/debugging.h>
+
+static PCSCD::Readers *mReaders;
+
+namespace PCSCD {
+
+
+Readers::Readers()
+{
+}
+
+Readers::~Readers()
+{
+}
+
+bool Readers::find(const char *name, XReaderContext &rc) const
+{
+	return false;
+}
+
+bool Readers::find(uint32_t port, const char *name, XReaderContext &rc) const
+{
+	return false;
+}
+
+bool Readers::find(uint32_t id, XReaderContext &rc) const
+{
+	return false;
+}
+
+
+} // end namespace PCSCD
+
+#pragma mark ---------- C Interface ----------
+
+LONG XRFAllocateReaderSpace(DWORD dwAllocNum)
+{
+	try
+	{
+		mReaders = new PCSCD::Readers();
+	}
+	catch (...)
+	{
+		secdebug("pcscd", "failed to allocate Readers");
+		return -1;
+	}
+	return EHInitializeEventStructures();
+}
+
+LONG XRFReaderInfo(LPSTR lpcReader, PREADER_CONTEXT *sReader)
+{
+	// Find a reader given a name
+	PCSCD::XReaderContext rc;	//>>>> use iterator instead
+	if (!sReader)
+		return SCARD_E_INVALID_PARAMETER;
+
+	if (!mReaders->find(lpcReader, rc))
+		return SCARD_E_UNKNOWN_READER;
+
+	*sReader = &rc;	//>>>> WRONG - temporary var
+	return SCARD_S_SUCCESS;
+}
+
+LONG XRFReaderInfoNamePort(DWORD dwPort, LPSTR lpcReader, PREADER_CONTEXT *sReader)
+{
+	// Find a reader given a name
+	PCSCD::XReaderContext rc;
+	if (!sReader)
+		return SCARD_E_INVALID_PARAMETER;
+
+	if (!mReaders->find(dwPort, lpcReader, rc))
+		return SCARD_E_UNKNOWN_READER;
+
+	*sReader = &rc;	//>>>> WRONG - temporary var
+	return SCARD_S_SUCCESS;
+}
+
+LONG XRFReaderInfoById(DWORD dwIdentity, PREADER_CONTEXT * sReader)
+{
+	// Find a reader given a handle
+	PCSCD::XReaderContext rc;
+	if (!sReader)
+		return SCARD_E_INVALID_PARAMETER;
+
+	if (!mReaders->find(dwIdentity, rc))
+		return SCARD_E_INVALID_VALUE;
+
+	*sReader = &rc;	//>>>> WRONG - temporary var
+	return SCARD_S_SUCCESS;
+}
+
+LONG XRFCheckSharing(DWORD hCard)
+{
+	PCSCD::XReaderContext rc;
+	if (!mReaders->find(hCard, rc))
+		return SCARD_E_INVALID_VALUE;
+
+	return (rc.dwLockId == 0 || rc.dwLockId == hCard)?SCARD_S_SUCCESS:SCARD_E_SHARING_VIOLATION;
+}
+
+LONG XRFLockSharing(DWORD hCard)
+{
+	PCSCD::XReaderContext rc;
+	if (!mReaders->find(hCard, rc))
+		return SCARD_E_INVALID_VALUE;
+
+	if (rc.dwLockId != 0 && rc.dwLockId != hCard)
+	{
+		secdebug("pcscd", "XRFLockSharing: Lock ID invalid: %d", rc.dwLockId);
+		return SCARD_E_SHARING_VIOLATION;
+	}
+	
+	EHSetSharingEvent(&rc, 1);
+	rc.dwLockId = hCard;
+	return SCARD_S_SUCCESS;
+}
+
+LONG XRFUnlockSharing(DWORD hCard)
+{
+	PCSCD::XReaderContext rc;
+	if (!mReaders->find(hCard, rc))
+		return SCARD_E_INVALID_VALUE;
+
+	if (rc.dwLockId != 0 && rc.dwLockId != hCard)
+	{
+		secdebug("pcscd", "XRFUnlockSharing: Lock ID invalid: %d", rc.dwLockId);
+		return SCARD_E_SHARING_VIOLATION;
+	}
+	
+	EHSetSharingEvent(&rc, 0);
+	rc.dwLockId = 0;
+	return SCARD_S_SUCCESS;
+}
+

Added: trunk/SmartCardServices/src/PCSC/reader.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/reader.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/reader.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  reader.h
+ *  SmartCardServices
+ */
+
+#ifndef _H_PCSCD_READER
+#define _H_PCSCD_READER
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "readerfactory.h"
+#include <security_utilities/refcount.h>
+#include <security_cdsa_utilities/handleobject.h>
+#include <map>
+
+#if 0
+	struct ReaderContext
+	{
+		char lpcReader[MAX_READERNAME];	/* Reader Name */
+		char lpcLibrary[MAX_LIBNAME];	/* Library Path */
+		PCSCLITE_THREAD_T pthThread;	/* Event polling thread */
+		PCSCLITE_MUTEX_T mMutex;	/* Mutex for this connection */
+		RDR_CAPABILITIES psCapabilites;	/* Structure of reader
+						   capabilities */
+		PROT_OPTIONS psProtOptions;	/* Structure of protocol options */
+		RDR_CLIHANDLES psHandles[PCSCLITE_MAX_CONTEXTS];	
+                                         /* Structure of connected handles */
+		FCT_MAP psFunctions;	/* Structure of function pointers */
+		UCHAR ucAtr[MAX_ATR_SIZE];	/* Atr for inserted card */
+		DWORD dwAtrLen;			/* Size of the ATR */
+		LPVOID vHandle;			/* Dlopen handle */
+		DWORD dwVersion;		/* IFD Handler version number */
+		DWORD dwPort;			/* Port ID */
+		DWORD dwProtocol;		/* Currently used protocol */
+		DWORD dwSlot;			/* Current Reader Slot */
+		DWORD dwBlockStatus;	/* Current blocking status */
+		DWORD dwStatus;			/* Current Status Mask */
+		DWORD dwLockId;			/* Lock Id */
+		DWORD dwIdentity;		/* Shared ID High Nibble */
+		DWORD dwContexts;		/* Number of open contexts */
+		DWORD dwPublicID;		/* Public id of public state struct */
+		PDWORD dwFeeds;			/* Number of shared client to lib */
+	};
+#endif
+
+#if defined(__cplusplus)
+
+namespace PCSCD {
+
+//
+// The server object itself. This is the "go to" object for anyone who wants
+// to access the server's global state. It runs the show.
+// There is only one Server, and its name is Server::active().
+//
+
+//
+// A PODWrapper for the PCSC READER_CONTEXT structure
+//
+class XReaderContext : public PodWrapper<XReaderContext, READER_CONTEXT>
+{
+public:
+	void set(const char *name, unsigned long known = SCARD_STATE_UNAWARE);
+	
+	const char *name() const	{ return lpcReader; }
+//	void name(const char *s)	{ szReader = s; }
+
+//	unsigned long lastKnown() const { return dwStatus; }
+	void lastKnown(unsigned long s);
+
+	unsigned long state() const { return 0; }	//fix
+	bool state(unsigned long it) const { return state() & it; }
+	bool changed() const		{ return state(SCARD_STATE_CHANGED); }
+	
+//	template <class T>
+//	T * &userData() { return reinterpret_cast<T * &>(pvUserData); }
+	
+	// DataOid access to the ATR data
+//	const void *data() const { return ucAtr; }
+//	size_t length() const { return dwAtrLen; }
+	void setATR(const void *atr, size_t size);
+	
+	IFDUMP(void dump());
+};
+
+
+class Reader : public HandleObject, public RefCount
+{
+public:
+	Reader(const char *bootstrapName);
+	~Reader();
+private:
+	// mach bootstrap registration name
+	std::string mBootstrapName;
+	mutable Mutex mLock;	
+};
+
+class Readers
+{
+public:
+	Readers();
+	~Readers();
+
+	typedef std::map<uint32_t, RefPointer<PCSCD::Reader> > ReaderMap;
+	ReaderMap mReaders;
+
+	bool find(uint32_t id, XReaderContext &rc) const;
+	bool find(const char *name, XReaderContext &rc) const;
+	bool find(uint32_t port, const char *name, XReaderContext &rc) const;
+	
+	mutable Mutex mReaderMapLock;
+
+	void insert(pair<uint32_t, RefPointer<PCSCD::Reader> > readerpair) { StLock<Mutex> _(mReaderMapLock); mReaders.insert(readerpair); }
+	void remove(ReaderMap::iterator it) { StLock<Mutex> _(mReaderMapLock); mReaders.erase(it); }
+
+private:
+	mutable Mutex mLock;	
+};
+
+} // end namespace PCSCD
+
+#endif /* __cplusplus__ */
+
+#endif //_H_PCSCD_READER
+

Added: trunk/SmartCardServices/src/PCSC/readerfactory.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/readerfactory.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/readerfactory.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1469 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  readerfactory.c
+ *  SmartCardServices
+ */
+
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	Title  : readerfactory.c
+	Package: pcsc lite
+	Author : David Corcoran
+	Date   : 7/27/99
+	License: Copyright (C) 1999 David Corcoran
+			<corcoran at linuxnet.com>
+	Purpose: This keeps track of a list of currently 
+	available reader structures.
+
+$Id: readerfactory.c,v 1.3 2004/10/14 20:33:35 mb Exp $
+
+********************************************************************/
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <fcntl.h>
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "ifdhandler.h"
+#include "debuglog.h"
+#include "thread_generic.h"
+#include "readerfactory.h"
+#include "dyn_generic.h"
+#include "sys_generic.h"
+#include "eventhandler.h"
+#include "ifdwrapper.h"
+#include "readerState.h"
+
+#include <security_utilities/debugging.h>
+
+#ifndef PCSCLITE_HP_BASE_PORT
+#define PCSCLITE_HP_BASE_PORT       0x200000
+#endif /* PCSCLITE_HP_BASE_PORT */
+
+static LONG RFLoadReader(PREADER_CONTEXT);
+static LONG RFUnBindFunctions(PREADER_CONTEXT);
+static LONG RFUnloadReader(PREADER_CONTEXT);
+
+static PREADER_CONTEXT sReadersContexts[PCSCLITE_MAX_READERS_CONTEXTS];
+static DWORD dwNumReadersContexts = 0;
+static DWORD lastLockID = 0;
+static PCSCLITE_MUTEX_T sReadersContextsLock = NULL;
+
+static int ReaderContextConstructor(PREADER_CONTEXT ctx, LPCSTR lpcReader, 
+	DWORD dwPort, LPCSTR lpcLibrary, LPCSTR lpcDevice);
+static void ReaderContextDestructor(PREADER_CONTEXT ctx);
+static void ReaderContextFree(PREADER_CONTEXT ctx);
+static void ReaderContextClear(PREADER_CONTEXT ctx);
+static int ReaderContextInsert(PREADER_CONTEXT ctx);
+static int ReaderContextRemove(PREADER_CONTEXT ctx);
+static int ReaderContextCheckDuplicateReader(LPCSTR lpcReader, DWORD dwPort);
+static int ReaderSlotCount(PREADER_CONTEXT ctx);
+static BOOL ReaderDriverIsThreadSafe(PREADER_CONTEXT ctx, BOOL testSlot);
+static BOOL ReaderNameMatchForIndex(DWORD dwPort, LPCSTR lpcReader, int index);
+static void ReaderContextDuplicateSlot(PREADER_CONTEXT ctxBase, PREADER_CONTEXT ctxSlot, int slotNumber, BOOL baseIsThreadSafe);
+static int ReaderCheckForClone(PREADER_CONTEXT ctx, LPCSTR lpcReader, 
+	DWORD dwPort, LPCSTR lpcLibrary);
+
+
+LONG RFAllocateReaderSpace()
+{
+	int i;
+
+	sReadersContextsLock = (PCSCLITE_MUTEX_T) malloc(sizeof(PCSCLITE_MUTEX));
+	SYS_MutexInit(sReadersContextsLock);
+
+	/*
+	 * Allocate each reader structure
+	 */
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+		sReadersContexts[i] = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
+
+	/*
+	 * Create public event structures
+	 */
+	return EHInitializeEventStructures();
+}
+
+LONG RFAddReader(LPSTR lpcReader, DWORD dwPort, LPSTR lpcLibrary, LPSTR lpcDevice)
+{
+	int slotCount;
+	LONG rv = SCARD_E_NO_MEMORY;
+	int slot;
+	PREADER_CONTEXT baseContext = NULL;
+
+	if ((lpcReader == NULL) || (lpcLibrary == NULL) || (lpcDevice == NULL))
+		return SCARD_E_INVALID_VALUE;
+
+	/* Reader name too long? */
+	if (strlen(lpcReader) >= MAX_READERNAME)
+	{
+		Log3(PCSC_LOG_ERROR, "Reader name too long: %d chars instead of max %d",
+			strlen(lpcReader), MAX_READERNAME);
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	/* Library name too long? */
+	if (strlen(lpcLibrary) >= MAX_LIBNAME)
+	{
+		Log3(PCSC_LOG_ERROR, "Library name too long: %d chars instead of max %d",
+			strlen(lpcLibrary), MAX_LIBNAME);
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	/* Device name too long? */
+	if (strlen(lpcDevice) >= MAX_DEVICENAME)
+	{
+		Log3(PCSC_LOG_ERROR, "Device name too long: %d chars instead of max %d",
+			strlen(lpcDevice), MAX_DEVICENAME);
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	rv = ReaderContextCheckDuplicateReader(lpcReader, dwPort);
+	if (rv)
+		return rv;
+
+	// Make sure we have an empty slot to put the reader structure
+	rv = ReaderContextInsert(NULL);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	// Allocate a temporary reader context struct
+	baseContext = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
+
+	rv = ReaderContextConstructor(baseContext, lpcReader, dwPort, lpcLibrary, lpcDevice);
+	if (rv != SCARD_S_SUCCESS)
+		goto xit;
+
+	rv = ReaderCheckForClone(baseContext, lpcReader, dwPort, lpcLibrary);
+	if (rv != SCARD_S_SUCCESS)
+		goto xit;
+
+	rv = RFInitializeReader(baseContext);
+	if (rv != SCARD_S_SUCCESS)
+		goto xit;
+
+	rv = ReaderContextInsert(baseContext);
+	if (rv != SCARD_S_SUCCESS)
+		goto xit;
+
+	rv = EHSpawnEventHandler(baseContext);
+	if (rv != SCARD_S_SUCCESS)
+		goto xit;
+
+	slotCount = ReaderSlotCount(baseContext);
+	if (slotCount <= 1)
+		return SCARD_S_SUCCESS;
+
+	/*
+	 * Check the number of slots and create a different
+	 * structure for each one accordingly
+	 */
+
+	BOOL baseIsThreadSafe = ReaderDriverIsThreadSafe(baseContext, 1);
+	
+	for (slot = 1; slot < slotCount; slot++)
+	{
+		// Make sure we have an empty slot to put the reader structure
+		// If not, we remove the whole reader
+		rv = ReaderContextInsert(NULL);
+		if (rv != SCARD_S_SUCCESS)
+		{
+			rv = RFRemoveReader(lpcReader, dwPort);
+			return rv;
+		}
+
+		// Allocate a temporary reader context struct
+		PREADER_CONTEXT ctxSlot = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
+
+		rv = ReaderContextConstructor(ctxSlot, lpcReader, dwPort, lpcLibrary, lpcDevice);
+		if (rv != SCARD_S_SUCCESS)
+		{
+			ReaderContextDestructor(ctxSlot);
+			free(ctxSlot);
+			return rv;
+		}
+
+		ReaderContextDuplicateSlot(baseContext, ctxSlot, slot, baseIsThreadSafe);
+
+		rv = RFInitializeReader(ctxSlot);
+		if (rv != SCARD_S_SUCCESS)
+		{
+			Log2(PCSC_LOG_ERROR, "%s init failed.", lpcReader);
+			ReaderContextDestructor(ctxSlot);
+			free(ctxSlot);
+			return rv;
+		}
+
+		rv = ReaderContextInsert(ctxSlot);
+		if (rv != SCARD_S_SUCCESS)
+			return rv;
+
+		rv = EHSpawnEventHandler(ctxSlot);
+		if (rv != SCARD_S_SUCCESS)
+			return rv;
+		EHSpawnEventHandler(ctxSlot);
+	}
+
+xit:
+	if (rv != SCARD_S_SUCCESS)
+	{
+		// Cannot connect to reader, so exit gracefully
+		Log3(PCSC_LOG_ERROR, "RFAddReader: %s init failed: %d", lpcReader, rv);
+		ReaderContextDestructor(baseContext);
+		free(baseContext);
+	}
+
+	return rv;
+}
+
+LONG RFRemoveReader(LPSTR lpcReader, DWORD dwPort)
+{
+	LONG rv;
+	PREADER_CONTEXT tmpContext = NULL;
+
+	if (lpcReader == 0)
+		return SCARD_E_INVALID_VALUE;
+
+	secdebug("pcscd", "RFRemoveReader: removing %s", lpcReader);
+	while ((rv = RFReaderInfoNamePort(dwPort, lpcReader, &tmpContext)) == SCARD_S_SUCCESS)
+	{
+		// Try to destroy the thread
+		rv = EHDestroyEventHandler(tmpContext);
+
+		rv = RFUnInitializeReader(tmpContext);
+		if (rv != SCARD_S_SUCCESS)
+			return rv;
+
+		ReaderContextRemove(tmpContext);
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFSetReaderName(PREADER_CONTEXT rContext, LPCSTR readerName,
+	LPCSTR libraryName, DWORD dwPort, DWORD dwSlot)
+{
+	LONG parent = -1;	/* reader number of the parent of the clone */
+	DWORD valueLength;
+	int currentDigit = -1;
+	int supportedChannels = 0;
+	int usedDigits[PCSCLITE_MAX_READERS_CONTEXTS] = {0,};
+	int i;
+
+	if ((0 == dwSlot) && (dwNumReadersContexts != 0))
+	{
+		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+		{
+			if (sReadersContexts[i] == NULL)
+				continue;
+			if ((sReadersContexts[i])->vHandle != 0)
+			{
+				if (strcmp((sReadersContexts[i])->lpcLibrary, libraryName) == 0)
+				{
+					UCHAR tagValue[1];
+					LONG ret;
+
+					/*
+					 * Ask the driver if it supports multiple channels
+					 */
+					valueLength = sizeof(tagValue);
+					ret = IFDGetCapabilities((sReadersContexts[i]),
+						TAG_IFD_SIMULTANEOUS_ACCESS,
+						&valueLength, tagValue);
+
+					if ((ret == IFD_SUCCESS) && (valueLength == 1) &&
+						(tagValue[0] > 1))
+					{
+						supportedChannels = tagValue[0];
+						Log2(PCSC_LOG_INFO,
+							"Support %d simultaneous readers", tagValue[0]);
+					}
+					else
+						supportedChannels = 1;
+
+					/*
+					 * Check to see if it is a hotplug reader and
+					 * different
+					 */
+					if (((((sReadersContexts[i])->dwPort & 0xFFFF0000) ==
+							PCSCLITE_HP_BASE_PORT)
+						&& ((sReadersContexts[i])->dwPort != dwPort))
+						|| (supportedChannels > 1))
+					{
+						char *lpcReader = sReadersContexts[i]->lpcReader;
+
+						/*
+						 * tells the caller who the parent of this
+						 * clone is so it can use it's shared
+						 * resources like mutex/etc.
+						 */
+						parent = i;
+
+						/*
+						 * If the same reader already exists and it is
+						 * hotplug then we must look for others and
+						 * enumerate the readername
+						 */
+						currentDigit = strtol(lpcReader + strlen(lpcReader) - 5, NULL, 16);
+
+						/*
+						 * This spot is taken
+						 */
+						usedDigits[currentDigit] = 1;
+					}
+				}
+			}
+		}
+
+	}
+
+	/* default value */
+	i = 0;
+
+	/* Other identical readers exist on the same bus */
+	if (currentDigit != -1)
+	{
+		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+		{
+			/* get the first free digit */
+			if (usedDigits[i] == 0)
+				break;
+		}
+
+		if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+		{
+			Log2(PCSC_LOG_ERROR, "Max number of readers reached: %d", PCSCLITE_MAX_READERS_CONTEXTS);
+			return -2;
+		}
+
+		if (i >= supportedChannels)
+		{
+			Log3(PCSC_LOG_ERROR, "Driver %s does not support more than "
+				"%d reader(s). Maybe the driver should support "
+				"TAG_IFD_SIMULTANEOUS_ACCESS", libraryName, supportedChannels);
+			return -2;
+		}
+	}
+
+	sprintf(rContext->lpcReader, "%s %02X %02X", readerName, i, dwSlot);
+
+	/*
+	 * Set the slot in 0xDDDDCCCC
+	 */
+	rContext->dwSlot = (i << 16) + dwSlot;
+
+	return parent;
+}
+
+LONG RFReaderInfo(LPSTR lpcReader, PREADER_CONTEXT * sReader)
+{
+	int i;
+	LONG rv = SCARD_E_UNKNOWN_READER;
+	
+	if (lpcReader == 0)
+		return SCARD_E_UNKNOWN_READER;
+
+	SYS_MutexLock(sReadersContextsLock);
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
+		{
+			if (strcmp(lpcReader, (sReadersContexts[i])->lpcReader) == 0)
+			{
+				*sReader = sReadersContexts[i];
+				rv = SCARD_S_SUCCESS;
+				break;
+			}
+		}
+	}
+	SYS_MutexUnLock(sReadersContextsLock);
+
+	return rv;
+}
+
+LONG RFReaderInfoNamePort(DWORD dwPort, LPSTR lpcReader,
+	PREADER_CONTEXT * sReader)
+{
+	int ix;
+	LONG rv = SCARD_E_INVALID_VALUE;
+
+	SYS_MutexLock(sReadersContextsLock);
+	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
+	{
+		if ((sReadersContexts[ix]!=NULL) && ((sReadersContexts[ix])->vHandle != 0) &&
+			ReaderNameMatchForIndex(dwPort, lpcReader, ix))
+			{
+				*sReader = sReadersContexts[ix];
+				rv = SCARD_S_SUCCESS;
+				break;
+			}
+	}
+	SYS_MutexUnLock(sReadersContextsLock);
+
+	return rv;
+}
+
+LONG RFReaderInfoById(DWORD dwIdentity, PREADER_CONTEXT * sReader)
+{
+	int i;
+	LONG rv = SCARD_E_INVALID_VALUE;
+
+	/*
+	 * Strip off the lower nibble and get the identity
+	 */
+	dwIdentity = dwIdentity >> (sizeof(DWORD) / 2) * 8;
+	dwIdentity = dwIdentity << (sizeof(DWORD) / 2) * 8;
+
+	SYS_MutexLock(sReadersContextsLock);
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		if ((sReadersContexts[i]!=NULL) && (dwIdentity == (sReadersContexts[i])->dwIdentity))
+		{
+			*sReader = sReadersContexts[i];
+			rv = SCARD_S_SUCCESS;
+			break;
+		}
+	}
+	SYS_MutexUnLock(sReadersContextsLock);
+
+	return rv;
+}
+
+static LONG RFLoadReader(PREADER_CONTEXT rContext)
+{
+	if (rContext->vHandle != 0)
+	{
+		Log1(PCSC_LOG_ERROR, "Warning library pointer not NULL");
+		/*
+		 * Another reader exists with this library loaded
+		 */
+		return SCARD_S_SUCCESS;
+	}
+
+	return DYN_LoadLibrary(&rContext->vHandle, rContext->lpcLibrary);
+}
+
+LONG RFBindFunctions(PREADER_CONTEXT rContext)
+{
+	int rv1, rv2, rv3;
+	void *f;
+
+	/*
+	 * Use this function as a dummy to determine the IFD Handler version
+	 * type  1.0/2.0/3.0.  Suppress error messaging since it can't be 1.0,
+	 * 2.0 and 3.0.
+	 */
+
+	Log1(PCSC_LOG_INFO, "Binding driver functions");
+
+//	DebugLogSuppress(DEBUGLOG_IGNORE_ENTRIES);
+
+	rv1 = DYN_GetAddress(rContext->vHandle, &f, "IO_Create_Channel");
+	rv2 = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannel");
+	rv3 = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannelByName");
+
+//	DebugLogSuppress(DEBUGLOG_LOG_ENTRIES);
+
+	if (rv1 != SCARD_S_SUCCESS && rv2 != SCARD_S_SUCCESS && rv3 != SCARD_S_SUCCESS)
+	{
+		/*
+		 * Neither version of the IFD Handler was found - exit
+		 */
+		Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing");
+
+		exit(1);
+	} else if (rv1 == SCARD_S_SUCCESS)
+	{
+		/*
+		 * Ifd Handler 1.0 found
+		 */
+		rContext->dwVersion = IFD_HVERSION_1_0;
+	} else if (rv3 == SCARD_S_SUCCESS)
+	{
+		/*
+		 * Ifd Handler 3.0 found
+		 */
+		rContext->dwVersion = IFD_HVERSION_3_0;
+	}
+	else
+	{
+		/*
+		 * Ifd Handler 2.0 found
+		 */
+		rContext->dwVersion = IFD_HVERSION_2_0;
+	}
+
+	/*
+	 * The following binds version 1.0 of the IFD Handler specs
+	 */
+
+	if (rContext->dwVersion == IFD_HVERSION_1_0)
+	{
+		Log1(PCSC_LOG_INFO, "Loading IFD Handler 1.0");
+
+#define GET_ADDRESS_OPTIONALv1(field, function, code) \
+{ \
+	void *f1 = NULL; \
+	if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFD_" #function)) \
+	{ \
+		code \
+	} \
+	rContext->psFunctions.psFunctions_v1.pvf ## field = f1; \
+}
+
+#define GET_ADDRESSv1(field, function) \
+	GET_ADDRESS_OPTIONALv1(field, function, \
+		Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #function ); \
+		exit(1); )
+
+		DYN_GetAddress(rContext->vHandle, &f, "IO_Create_Channel");
+		rContext->psFunctions.psFunctions_v1.pvfCreateChannel = f;
+
+		if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f,
+			"IO_Close_Channel"))
+		{
+			Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing");
+			exit(1);
+		}
+		rContext->psFunctions.psFunctions_v1.pvfCloseChannel = f;
+
+		GET_ADDRESSv1(GetCapabilities, Get_Capabilities)
+		GET_ADDRESSv1(SetCapabilities, Set_Capabilities)
+		GET_ADDRESSv1(PowerICC, Power_ICC)
+		GET_ADDRESSv1(TransmitToICC, Transmit_to_ICC)
+		GET_ADDRESSv1(ICCPresence, Is_ICC_Present)
+
+		GET_ADDRESS_OPTIONALv1(SetProtocolParameters, Set_Protocol_Parameters, )
+	}
+	else if (rContext->dwVersion == IFD_HVERSION_2_0)
+	{
+		/*
+		 * The following binds version 2.0 of the IFD Handler specs
+		 */
+
+#define GET_ADDRESS_OPTIONALv2(s, code) \
+{ \
+	void *f1 = NULL; \
+	if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s)) \
+	{ \
+		code \
+	} \
+	rContext->psFunctions.psFunctions_v2.pvf ## s = f1; \
+}
+
+#define GET_ADDRESSv2(s) \
+	GET_ADDRESS_OPTIONALv2(s, \
+		Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
+		exit(1); )
+
+		Log1(PCSC_LOG_INFO, "Loading IFD Handler 2.0");
+
+		GET_ADDRESSv2(CreateChannel)
+		GET_ADDRESSv2(CloseChannel)
+		GET_ADDRESSv2(GetCapabilities)
+		GET_ADDRESSv2(SetCapabilities)
+		GET_ADDRESSv2(PowerICC)
+		GET_ADDRESSv2(TransmitToICC)
+		GET_ADDRESSv2(ICCPresence)
+		GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
+
+		GET_ADDRESSv2(Control)
+	}
+	else if (rContext->dwVersion == IFD_HVERSION_3_0)
+	{
+		/*
+		 * The following binds version 3.0 of the IFD Handler specs
+		 */
+
+#define GET_ADDRESS_OPTIONALv3(s, code) \
+{ \
+	void *f1 = NULL; \
+	if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s)) \
+	{ \
+		code \
+	} \
+	rContext->psFunctions.psFunctions_v3.pvf ## s = f1; \
+}
+
+#define GET_ADDRESSv3(s) \
+	GET_ADDRESS_OPTIONALv3(s, \
+		Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
+		exit(1); )
+
+		Log1(PCSC_LOG_INFO, "Loading IFD Handler 3.0");
+
+		GET_ADDRESSv2(CreateChannel)
+		GET_ADDRESSv2(CloseChannel)
+		GET_ADDRESSv2(GetCapabilities)
+		GET_ADDRESSv2(SetCapabilities)
+		GET_ADDRESSv2(PowerICC)
+		GET_ADDRESSv2(TransmitToICC)
+		GET_ADDRESSv2(ICCPresence)
+		GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
+
+		GET_ADDRESSv3(CreateChannelByName)
+		GET_ADDRESSv3(Control)
+	}
+	else
+	{
+		/*
+		 * Who knows what could have happenned for it to get here.
+		 */
+		Log1(PCSC_LOG_CRITICAL, "IFD Handler not 1.0/2.0 or 3.0");
+		exit(1);
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+static LONG RFUnBindFunctions(PREADER_CONTEXT rContext)
+{
+	/*
+	 * Zero out everything
+	 */
+
+	Log1(PCSC_LOG_INFO, "Unbinding driver functions");
+	memset(&rContext->psFunctions, 0, sizeof(rContext->psFunctions));
+
+	return SCARD_S_SUCCESS;
+}
+
+static LONG RFUnloadReader(PREADER_CONTEXT rContext)
+{
+	/*
+	 * Make sure no one else is using this library
+	 */
+
+		Log1(PCSC_LOG_INFO, "Unloading reader driver.");
+	if (*rContext->pdwFeeds == 1)
+	{
+		Log1(PCSC_LOG_INFO, "--- closing dynamic library");
+		DYN_CloseLibrary(&rContext->vHandle);
+	}
+
+	rContext->vHandle = 0;
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFCheckSharing(DWORD hCard)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	if (rContext->dwLockId == 0 || rContext->dwLockId == hCard)
+		return SCARD_S_SUCCESS;
+	else
+	{
+		secdebug("pcscd", "RFCheckSharing: sharing violation, dwLockId: 0x%02X", rContext->dwLockId);
+		return SCARD_E_SHARING_VIOLATION;
+	}
+}
+
+LONG RFLockSharing(DWORD hCard)
+{
+	PREADER_CONTEXT rContext = NULL;
+
+	RFReaderInfoById(hCard, &rContext);
+
+	if (RFCheckSharing(hCard) == SCARD_S_SUCCESS)
+	{
+		EHSetSharingEvent(rContext, 1);
+		rContext->dwLockId = hCard;
+	}
+	else
+		return SCARD_E_SHARING_VIOLATION;
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFUnlockSharing(DWORD hCard)
+{
+	PREADER_CONTEXT rContext = NULL;
+	LONG rv;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFCheckSharing(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	EHSetSharingEvent(rContext, 0);
+	rContext->dwLockId = 0;
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFUnblockContext(SCARDCONTEXT hContext)
+{
+	int i;
+
+	SYS_MutexLock(sReadersContextsLock);
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+		if (sReadersContexts[i])
+			(sReadersContexts[i])->dwBlockStatus = hContext;
+	SYS_MutexUnLock(sReadersContextsLock);
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFUnblockReader(PREADER_CONTEXT rContext)
+{
+	rContext->dwBlockStatus = BLOCK_STATUS_RESUME;
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFInitializeReader(PREADER_CONTEXT rContext)
+{
+	LONG rv;
+
+	/*
+	 * Spawn the event handler thread
+	 */
+	Log3(PCSC_LOG_INFO, "Attempting startup of %s using %s",
+		rContext->lpcReader, rContext->lpcLibrary);
+
+  /******************************************/
+	/*
+	 * This section loads the library
+	 */
+  /******************************************/
+	rv = RFLoadReader(rContext);
+	if (rv != SCARD_S_SUCCESS)
+	{
+		Log2(PCSC_LOG_ERROR, "RFLoadReader failed: %X", rv);
+		return rv;
+	}
+
+  /*******************************************/
+	/*
+	 * This section binds the functions
+	 */
+  /*******************************************/
+	rv = RFBindFunctions(rContext);
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		Log2(PCSC_LOG_ERROR, "RFBindFunctions failed: %X", rv);
+		RFUnloadReader(rContext);
+		return rv;
+	}
+
+  /*******************************************/
+	/*
+	 * This section tries to open the port
+	 */
+  /*******************************************/
+
+	rv = IFDOpenIFD(rContext);
+
+	if (rv != IFD_SUCCESS)
+	{
+		Log3(PCSC_LOG_CRITICAL, "Open Port %X Failed (%s)",
+			rContext->dwPort, rContext->lpcDevice);
+		RFUnBindFunctions(rContext);
+		RFUnloadReader(rContext);
+		return SCARD_E_INVALID_TARGET;
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFUnInitializeReader(PREADER_CONTEXT rContext)
+{
+	Log2(PCSC_LOG_INFO, "Attempting shutdown of %s.",
+		rContext->lpcReader);
+
+	/*
+	 * Close the port, unbind the functions, and unload the library
+	 */
+
+	/*
+	 * If the reader is getting uninitialized then it is being unplugged
+	 * so I can't send a IFDPowerICC call to it
+	 *
+	 * IFDPowerICC( rContext, IFD_POWER_DOWN, Atr, &AtrLen );
+	 */
+	IFDCloseIFD(rContext);
+	RFUnBindFunctions(rContext);
+	RFUnloadReader(rContext);
+
+	return SCARD_S_SUCCESS;
+}
+
+SCARDHANDLE RFCreateReaderHandle(PREADER_CONTEXT rContext)
+{
+	USHORT randHandle;
+
+	/*
+	 * Create a random handle with 16 bits check to see if it already is
+	 * used.
+	 */
+	randHandle = SYS_Random(SYS_GetSeed(), 10, 65000);
+
+	while (1)
+	{
+		int i;
+
+		SYS_MutexLock(sReadersContextsLock);
+		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+		{
+			if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
+			{
+				int j;
+
+				for (j = 0; j < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; j++)
+				{
+					if ((rContext->dwIdentity + randHandle) ==
+						(sReadersContexts[i])->psHandles[j].hCard)
+					{
+						/*
+						 * Get a new handle and loop again
+						 */
+						randHandle = SYS_Random(randHandle, 10, 65000);
+						continue;
+					}
+				}
+			}
+		}
+		SYS_MutexUnLock(sReadersContextsLock);
+
+		/*
+		 * Once the for loop is completed w/o restart a good handle was
+		 * found and the loop can be exited.
+		 */
+
+		if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+			break;
+	}
+
+	return rContext->dwIdentity + randHandle;
+}
+
+LONG RFFindReaderHandle(SCARDHANDLE hCard)
+{
+	int i;
+	LONG rv = SCARD_E_INVALID_HANDLE;
+	
+	SYS_MutexLock(sReadersContextsLock);
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
+		{
+			int j;
+
+			for (j = 0; j < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; j++)
+			{
+				if (hCard == (sReadersContexts[i])->psHandles[j].hCard)
+				{
+					rv = SCARD_S_SUCCESS;
+					goto xit;
+				}
+			}
+		}
+	}
+xit:
+	SYS_MutexUnLock(sReadersContextsLock);
+
+	return rv;
+}
+
+LONG RFDestroyReaderHandle(SCARDHANDLE hCard)
+{
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFAddReaderHandle(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
+	{
+		if (rContext->psHandles[i].hCard == 0)
+		{
+			rContext->psHandles[i].hCard = hCard;
+			rContext->psHandles[i].dwEventStatus = 0;
+			break;
+		}
+	}
+
+	if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
+		/* List is full */
+		return SCARD_E_INSUFFICIENT_BUFFER;
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFRemoveReaderHandle(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
+	{
+		if (rContext->psHandles[i].hCard == hCard)
+		{
+			rContext->psHandles[i].hCard = 0;
+			rContext->psHandles[i].dwEventStatus = 0;
+			break;
+		}
+	}
+
+	if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
+		/* Not Found */
+		return SCARD_E_INVALID_HANDLE;
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFSetReaderEventState(PREADER_CONTEXT rContext, DWORD dwEvent)
+{
+	int i;
+
+	/*
+	 * Set all the handles for that reader to the event
+	 */
+	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
+	{
+		if (rContext->psHandles[i].hCard != 0)
+			rContext->psHandles[i].dwEventStatus = dwEvent;
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFCheckReaderEventState(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
+	{
+		if (rContext->psHandles[i].hCard == hCard)
+		{
+			if (rContext->psHandles[i].dwEventStatus == SCARD_REMOVED)
+				return SCARD_W_REMOVED_CARD;
+			else
+			{
+				if (rContext->psHandles[i].dwEventStatus == SCARD_RESET)
+					return SCARD_W_RESET_CARD;
+				else
+				{
+					if (rContext->psHandles[i].dwEventStatus == 0)
+						return SCARD_S_SUCCESS;
+					else
+						return SCARD_E_INVALID_VALUE;
+				}
+			}
+		}
+	}
+
+	return SCARD_E_INVALID_HANDLE;
+}
+
+LONG RFClearReaderEventState(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
+	{
+		if (rContext->psHandles[i].hCard == hCard)
+			rContext->psHandles[i].dwEventStatus = 0;
+	}
+
+	if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
+		/* Not Found */
+		return SCARD_E_INVALID_HANDLE;
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG RFCheckReaderStatus(PREADER_CONTEXT rContext)
+{
+	LONG rx = 0;
+	rx = ((rContext == NULL) || (rContext->readerState == NULL) || 
+		(SharedReaderState_State(rContext->readerState) & SCARD_UNKNOWN))?SCARD_E_READER_UNAVAILABLE:SCARD_S_SUCCESS;
+	return rx;
+}
+
+void RFCleanupReaders(int shouldExit)
+{
+	int i;
+
+	Log1(PCSC_LOG_INFO, "entering cleaning function");
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		if ((sReadersContexts[i]!=NULL) && (sReadersContexts[i]->vHandle != 0))
+		{
+			LONG rv;
+			char lpcStripReader[MAX_READERNAME];
+
+			Log2(PCSC_LOG_INFO, "Stopping reader: %s",
+				sReadersContexts[i]->lpcReader);
+
+			strncpy(lpcStripReader, (sReadersContexts[i])->lpcReader,
+				sizeof(lpcStripReader));
+			/*
+			 * strip the 6 last char ' 00 00'
+			 */
+			lpcStripReader[strlen(lpcStripReader) - 6] = '\0';
+
+			rv = RFRemoveReader(lpcStripReader, sReadersContexts[i]->dwPort);
+
+			if (rv != SCARD_S_SUCCESS)
+				Log2(PCSC_LOG_ERROR, "RFRemoveReader error: 0x%08X", rv);
+		}
+	}
+
+	secdebug("pcscd", "RFCleanupReaders: exiting cleaning function");
+	/*
+	 * exit() will call at_exit()
+	 */
+
+	if (shouldExit)
+		exit(0);
+}
+
+int RFStartSerialReaders(const char *readerconf)
+{
+	return DBUpdateReaders(readerconf);
+}
+
+void RFReCheckReaderConf(void)
+{
+}
+
+void RFSuspendAllReaders() 
+{
+	int ix;
+	secdebug("pcscd", "RFSuspendAllReaders");
+	Log1(PCSC_LOG_DEBUG, "zzzzz zzzzz zzzzz zzzzz RFSuspendAllReaders zzzzz zzzzz zzzzz zzzzz ");
+
+	// @@@ We still need code to mark state first as "trying to sleep", in case
+	// not all of it gets done before we sleep
+	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
+	{
+		if ((sReadersContexts[ix]!=NULL) && ((sReadersContexts[ix])->vHandle != 0))
+		{
+			EHDestroyEventHandler(sReadersContexts[ix]);
+			IFDCloseIFD(sReadersContexts[ix]);
+		}
+	}
+}
+
+void RFAwakeAllReaders(void)
+{
+	LONG rv = IFD_SUCCESS;
+	int i;
+
+	secdebug("pcscd", "RFAwakeAllReaders");
+	Log1(PCSC_LOG_DEBUG, "----- ----- ----- ----- RFAwakeAllReaders ----- ----- ----- -----  ");
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		if (sReadersContexts[i]==NULL)
+			continue;
+		/* If the library is loaded and the event handler is not running */
+		if ( ((sReadersContexts[i])->vHandle   != 0) &&
+		     ((sReadersContexts[i])->pthThread == 0) )
+		{
+			int jx;
+			int alreadyInitializedFlag = 0;
+
+			// If a clone of this already did the initialization, 
+			// set flag so we don't do again
+			for (jx=0; jx < i; jx++)
+			{
+				if (((sReadersContexts[jx])->vHandle == (sReadersContexts[i])->vHandle)&&
+					((sReadersContexts[jx])->dwPort  == (sReadersContexts[i])->dwPort))
+				{
+					alreadyInitializedFlag = 1;
+				}
+			}
+
+			if (!alreadyInitializedFlag)
+			{
+				SYS_USleep(100000L);	// 0.1s (in microseconds)
+				rv = IFDOpenIFD(sReadersContexts[i]);
+			}
+			
+			RFSetReaderEventState(sReadersContexts[i], SCARD_RESET);
+			if (rv != IFD_SUCCESS)
+			{
+				Log3(PCSC_LOG_ERROR, "Open Port %X Failed (%s)",
+					(sReadersContexts[i])->dwPort, (sReadersContexts[i])->lpcDevice);
+				Log2(PCSC_LOG_ERROR, "  with error 0x%08X", rv);
+				continue;
+			}
+
+			EHSpawnEventHandler(sReadersContexts[i]);
+		}
+	}
+}
+
+#pragma mark ---------- Context Share Lock Tracking ----------
+
+void ReaderContextLock(PREADER_CONTEXT rContext)
+{
+	if (rContext)
+	{
+		secdebug("pcscd", "===> ReaderContextLock [was: %02X]", rContext->dwLockId);
+		rContext->dwLockId = 0xFFFF;
+		lastLockID = -3;			// something different
+	}
+}
+
+void ReaderContextUnlock(PREADER_CONTEXT rContext)
+{
+	if (rContext)
+	{
+		secdebug("pcscd", "<=== ReaderContextUnlock [was: %02X]", rContext->dwLockId);
+		rContext->dwLockId = 0;
+		lastLockID = -2;			// something different
+	}
+}
+
+int ReaderContextIsLocked(PREADER_CONTEXT rContext)
+{
+	if (rContext)
+	{
+		if (rContext->dwLockId && (rContext->dwLockId != lastLockID))		// otherwise too many messages
+		{
+			lastLockID = rContext->dwLockId;
+			secdebug("pcscd", ".... ReaderContextLock state: %02X", rContext->dwLockId);
+		}
+		return (rContext->dwLockId == 0xFFFF)?1:0;
+	}
+	else
+		return 0;
+}
+
+#pragma mark ---------- Reader Context Management ----------
+
+static int ReaderContextConstructor(PREADER_CONTEXT ctx, LPCSTR lpcReader, 
+	DWORD dwPort, LPCSTR lpcLibrary, LPCSTR lpcDevice)
+{
+	// We assume the struct was created with a calloc, so we don't call ReaderContextClear
+	if (!ctx)
+		return SCARD_E_NO_MEMORY;
+	
+	strlcpy(ctx->lpcLibrary, lpcLibrary, sizeof(ctx->lpcLibrary));
+	strlcpy(ctx->lpcDevice,  lpcDevice,  sizeof(ctx->lpcDevice));
+	ctx->dwPort = dwPort;
+
+	/*	
+		Initialize pdwFeeds to 1, otherwise multiple cloned readers will cause 
+		pcscd to crash when RFUnloadReader unloads the driver library
+		and there are still devices attached using it
+	*/
+	ctx->pdwFeeds = malloc(sizeof(DWORD));
+	*ctx->pdwFeeds = 1;
+
+	ctx->mMutex = (PCSCLITE_MUTEX_T) malloc(sizeof(PCSCLITE_MUTEX));
+	SYS_MutexInit(ctx->mMutex);
+
+	ctx->pdwMutex = malloc(sizeof(DWORD));
+	*ctx->pdwMutex = 1;
+
+	return SCARD_S_SUCCESS;
+}
+
+static int ReaderCheckForClone(PREADER_CONTEXT ctx, LPCSTR lpcReader, 
+	DWORD dwPort, LPCSTR lpcLibrary)
+{
+	// Check and set the readername to see if it must be enumerated
+	// A parentNode of -2 or less indicates fatal error
+	
+	LONG parentNode = RFSetReaderName(ctx, lpcReader, lpcLibrary, dwPort, 0);
+	if (parentNode < -1)			
+		return SCARD_E_NO_MEMORY;
+
+	// If a clone to this reader exists take some values from that clone
+	if ((parentNode >= 0) && (parentNode < PCSCLITE_MAX_READERS_CONTEXTS)
+		&& sReadersContexts[parentNode])
+	{
+		SYS_MutexLock(sReadersContextsLock);
+		ctx->pdwFeeds = (sReadersContexts[parentNode])->pdwFeeds;
+		*ctx->pdwFeeds += 1;
+		ctx->vHandle = (sReadersContexts[parentNode])->vHandle;
+		ctx->mMutex = (sReadersContexts[parentNode])->mMutex;
+		ctx->pdwMutex = (sReadersContexts[parentNode])->pdwMutex;
+		SYS_MutexUnLock(sReadersContextsLock);
+
+		if (0 && ReaderDriverIsThreadSafe(sReadersContexts[parentNode], 0))
+		{
+			ctx->mMutex = 0;
+			ctx->pdwMutex = NULL;
+		}
+		else
+			*ctx->pdwMutex += 1;
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+static void ReaderContextDestructor(PREADER_CONTEXT ctx)
+{
+	ReaderContextFree(ctx);
+}
+
+static void ReaderContextFree(PREADER_CONTEXT ctx)
+{
+	if (!ctx)
+		return;
+
+	// Destroy and free the mutex
+	if (ctx->pdwMutex)
+	{
+		if (*ctx->pdwMutex == 1)
+		{
+			SYS_MutexDestroy(ctx->mMutex);
+			free(ctx->mMutex);
+		}
+		*ctx->pdwMutex -= 1;
+	}
+	
+	// Destroy and free the mutex counter
+	if (ctx->pdwMutex && (*ctx->pdwMutex == 0))
+	{
+		free(ctx->pdwMutex);
+		ctx->pdwMutex = NULL;
+	}
+
+	if (ctx->pdwFeeds)
+	{
+		*ctx->pdwFeeds -= 1;
+		if (*ctx->pdwFeeds == 0)
+		{
+			free(ctx->pdwFeeds);
+			ctx->pdwFeeds = NULL;
+		}
+	}
+	
+	// zero out everything else
+	ReaderContextClear(ctx);
+}
+
+static void ReaderContextClear(PREADER_CONTEXT ctx)
+{
+	// This assumes that ReaderContextFree has already been called if necessary
+	if (ctx)
+		memset(ctx, 0, sizeof(READER_CONTEXT));
+}
+
+static int ReaderContextInsert(PREADER_CONTEXT ctx)
+{
+	// Find an empty slot to put the reader structure, and copy it in
+	// If NULL is passed in, just return whether a spot is available or not
+
+	int ix, rv = SCARD_E_NO_MEMORY;
+	
+	SYS_MutexLock(sReadersContextsLock);
+	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
+	{
+		if ((sReadersContexts[ix] == NULL) || (sReadersContexts[ix])->vHandle == 0)
+		{
+			if (ctx)
+			{
+				if (sReadersContexts[ix])
+					free(sReadersContexts[ix]);
+				sReadersContexts[ix] = ctx;
+				(sReadersContexts[ix])->dwIdentity = (ix + 1) << (sizeof(DWORD) / 2) * 8;
+				dwNumReadersContexts += 1;
+			}
+			rv = SCARD_S_SUCCESS;
+			break;
+		}
+	}
+	SYS_MutexUnLock(sReadersContextsLock);
+	return rv;
+}
+
+static int ReaderContextRemove(PREADER_CONTEXT ctx)
+{
+	int ix, rv = SCARD_E_UNKNOWN_READER;
+	PREADER_CONTEXT ctxToRemove = NULL;
+	DWORD dwPort = ctx->dwPort;
+	LPSTR lpcReader = ctx->lpcReader;
+	SYS_MutexLock(sReadersContextsLock);
+	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
+	{
+		if (!ReaderNameMatchForIndex(dwPort, lpcReader, ix))
+			continue;
+
+		ctxToRemove = sReadersContexts[ix];
+		sReadersContexts[ix] = NULL;
+		dwNumReadersContexts -= 1;
+		rv = SCARD_S_SUCCESS;
+		break;
+	}
+	SYS_MutexUnLock(sReadersContextsLock);
+	// We can do this cleanup outside the lock
+	if (ctxToRemove)
+	{
+		ReaderContextDestructor(ctxToRemove);
+		free(ctxToRemove);
+	}
+	return rv;
+}
+
+static int ReaderContextCheckDuplicateReader(LPCSTR lpcReader, DWORD dwPort)
+{
+	// Readers with the same name and same port cannot be used
+
+	if (dwNumReadersContexts == 0)
+		return SCARD_S_SUCCESS;
+
+	int ix, rv = SCARD_S_SUCCESS;
+	SYS_MutexLock(sReadersContextsLock);
+	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
+	{
+		if ((sReadersContexts[ix]==NULL) || ((sReadersContexts[ix])->vHandle == 0))
+			continue;
+		
+		if (ReaderNameMatchForIndex(dwPort, lpcReader, ix))
+		{
+			Log1(PCSC_LOG_ERROR, "Duplicate reader found.");
+			rv = SCARD_E_DUPLICATE_READER;
+			break;
+		}
+	}
+	SYS_MutexUnLock(sReadersContextsLock);
+	return rv;
+}
+
+static int ReaderSlotCount(PREADER_CONTEXT ctx)
+{
+	// Call on the driver to see if there are multiple slots
+	// If we encounter errors, pretend it is just a single slot reader
+	
+	UCHAR ucGetData[1];
+	DWORD dwGetSize = sizeof(ucGetData);
+	int rv = IFDGetCapabilities(ctx, TAG_IFD_SLOTS_NUMBER, &dwGetSize, ucGetData);
+
+	//Reader does not have this defined, so assume a single slot
+	if (rv != IFD_SUCCESS || dwGetSize != 1 || ucGetData[0] == 0)
+		return 1;
+
+	// Reader has this defined and it only has one slot
+	if (rv == IFD_SUCCESS && dwGetSize == 1 && ucGetData[0] == 1)
+		return 1;
+
+	return (int)ucGetData[0];
+}
+
+static BOOL ReaderDriverIsThreadSafe(PREADER_CONTEXT ctx, BOOL testSlot)
+{
+	// Call on the driver to see if it is thread safe
+	UCHAR ucThread[1];
+	DWORD dwGetSize = sizeof(ucThread);
+	int rv = IFDGetCapabilities(ctx, testSlot?TAG_IFD_SLOT_THREAD_SAFE:TAG_IFD_THREAD_SAFE, 
+		&dwGetSize, ucThread);
+	if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1)
+	{
+		Log1(PCSC_LOG_INFO, "Driver is thread safe");
+		return 1;
+	}
+	else
+	{
+		Log1(PCSC_LOG_INFO, "Driver is not thread safe");
+		return 0;
+	}
+}
+
+static BOOL ReaderNameMatchForIndex(DWORD dwPort, LPCSTR lpcReader, int index)
+{
+	// "index" is index in sReadersContexts
+	char lpcStripReader[MAX_READERNAME];
+	int tmplen;
+
+	if (sReadersContexts[index]==NULL)
+		return 0;
+
+	strncpy(lpcStripReader, (sReadersContexts[index])->lpcReader, sizeof(lpcStripReader));
+	tmplen = strlen(lpcStripReader);
+	lpcStripReader[tmplen - 6] = 0;
+
+	return ((strcmp(lpcReader, lpcStripReader) == 0) && (dwPort == (sReadersContexts[index])->dwPort))?1:0;
+}
+
+static void ReaderContextDuplicateSlot(PREADER_CONTEXT ctxBase, PREADER_CONTEXT ctxSlot, int slotNumber, BOOL baseIsThreadSafe)
+{
+	// Copy the previous reader name and set the slot number
+	// The slot number for the base is 0
+
+	int ix;
+	char *tmpReader = ctxSlot->lpcReader;
+	strlcpy(tmpReader, ctxBase->lpcReader, sizeof(ctxSlot->lpcReader));
+	sprintf(tmpReader + strlen(tmpReader) - 2, "%02X", slotNumber);
+
+	strlcpy(ctxSlot->lpcLibrary, ctxBase->lpcLibrary, sizeof(ctxSlot->lpcLibrary));
+	strlcpy(ctxSlot->lpcDevice,  ctxBase->lpcDevice,  sizeof(ctxSlot->lpcDevice));
+
+	ctxSlot->dwVersion = ctxBase->dwVersion;
+	ctxSlot->dwPort = ctxBase->dwPort;
+	ctxSlot->vHandle = ctxBase->vHandle;
+	ctxSlot->mMutex = ctxBase->mMutex;
+	ctxSlot->pdwMutex = ctxBase->pdwMutex;
+	ctxSlot->dwSlot = ctxBase->dwSlot + slotNumber;
+
+	ctxSlot->pdwFeeds = ctxBase->pdwFeeds;
+
+	*ctxSlot->pdwFeeds += 1;
+
+	ctxSlot->dwBlockStatus = 0;
+	ctxSlot->dwContexts = 0;
+	ctxSlot->dwLockId = 0;
+	ctxSlot->readerState = NULL;
+	ctxSlot->dwIdentity = (slotNumber + 1) << (sizeof(DWORD) / 2) * 8;
+
+	for (ix = 0; ix < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; ix++)
+		ctxSlot->psHandles[ix].hCard = 0;
+
+	if (!ctxSlot->pdwMutex)
+		ctxSlot->pdwMutex = malloc(sizeof(DWORD));
+	if (baseIsThreadSafe)
+	{
+		ctxSlot->mMutex = malloc(sizeof(PCSCLITE_MUTEX));
+		SYS_MutexInit(ctxSlot->mMutex);
+		*ctxSlot->pdwMutex = 1;
+	}
+	else
+		*ctxSlot->pdwMutex += 1;
+}
+

Added: trunk/SmartCardServices/src/PCSC/readerfactory.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/readerfactory.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/readerfactory.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,256 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  readerfactory.h
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999
+ *  David Corcoran <corcoran at linuxnet.com>
+ * Copyright (C) 2004
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: readerfactory.h 2330 2007-01-11 16:54:16Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This keeps track of a list of currently available reader structures.
+ */
+
+#ifndef __readerfactory_h__
+#define __readerfactory_h__
+
+#include <inttypes.h>
+
+#include "thread_generic.h"
+#include "ifdhandler.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	typedef struct
+	{
+		char *pcFriendlyname;
+		char *pcDevicename;
+		char *pcLibpath;
+		int dwChannelId;
+	} SerialReader;
+
+	struct FctMap_V1
+	{
+		RESPONSECODE (*pvfCreateChannel)(DWORD);
+		RESPONSECODE (*pvfCloseChannel)(void);
+		RESPONSECODE (*pvfGetCapabilities)(DWORD, PUCHAR);
+		RESPONSECODE (*pvfSetCapabilities)(DWORD, PUCHAR);
+		RESPONSECODE (*pvfSetProtocolParameters)(DWORD, UCHAR, UCHAR, UCHAR,
+			UCHAR);
+		RESPONSECODE (*pvfPowerICC)(DWORD);
+		RESPONSECODE (*pvfTransmitToICC)(SCARD_IO_HEADER, PUCHAR, DWORD,
+			PUCHAR, PDWORD, PSCARD_IO_HEADER);
+		RESPONSECODE (*pvfICCPresence)(void);
+	};
+
+	typedef struct FctMap_V1 FCT_MAP_V1, *PFCT_MAP_V1;
+
+	struct FctMap_V2
+	{
+		/* shared with API 3.0 */
+		RESPONSECODE (*pvfCreateChannel)(DWORD, DWORD);
+		RESPONSECODE (*pvfCloseChannel)(DWORD);
+		RESPONSECODE (*pvfGetCapabilities)(DWORD, DWORD, PDWORD, PUCHAR);
+		RESPONSECODE (*pvfSetCapabilities)(DWORD, DWORD, DWORD, PUCHAR);
+		RESPONSECODE (*pvfSetProtocolParameters)(DWORD, DWORD, UCHAR, UCHAR,
+			UCHAR, UCHAR);
+		RESPONSECODE (*pvfPowerICC)(DWORD, DWORD, PUCHAR, PDWORD);
+		RESPONSECODE (*pvfTransmitToICC)(DWORD, SCARD_IO_HEADER, PUCHAR,
+			DWORD, PUCHAR, PDWORD, PSCARD_IO_HEADER);
+		RESPONSECODE (*pvfICCPresence)(DWORD);
+
+		/* API v2.0 only */
+		RESPONSECODE (*pvfControl)(DWORD, PUCHAR, DWORD, PUCHAR, PDWORD);
+	};
+
+	typedef struct FctMap_V2 FCT_MAP_V2, *PFCT_MAP_V2;
+
+	struct FctMap_V3
+	{
+		/* the common fields SHALL be in the same order as in FctMap_V2 */
+		RESPONSECODE (*pvfCreateChannel)(DWORD, DWORD);
+		RESPONSECODE (*pvfCloseChannel)(DWORD);
+		RESPONSECODE (*pvfGetCapabilities)(DWORD, DWORD, PDWORD, PUCHAR);
+		RESPONSECODE (*pvfSetCapabilities)(DWORD, DWORD, DWORD, PUCHAR);
+		RESPONSECODE (*pvfSetProtocolParameters)(DWORD, DWORD, UCHAR, UCHAR,
+				UCHAR, UCHAR);
+		RESPONSECODE (*pvfPowerICC)(DWORD, DWORD, PUCHAR, PDWORD);
+		RESPONSECODE (*pvfTransmitToICC)(DWORD, SCARD_IO_HEADER, PUCHAR,
+			DWORD, PUCHAR, PDWORD, PSCARD_IO_HEADER);
+		RESPONSECODE (*pvfICCPresence)(DWORD);
+
+		/* API V3.0 only */
+		RESPONSECODE (*pvfControl)(DWORD, DWORD, LPCVOID, DWORD, LPVOID,
+			DWORD, LPDWORD);
+		RESPONSECODE (*pvfCreateChannelByName)(DWORD, LPSTR);
+	};
+
+	typedef struct FctMap_V3 FCT_MAP_V3, *PFCT_MAP_V3;
+
+	/*
+	 * The following is not currently used but in place if needed
+	 */
+
+	struct RdrCapabilities
+	{
+		DWORD dwAsynch_Supported;	/* Asynchronous Support */
+		DWORD dwDefault_Clock;	/* Default Clock Rate */
+		DWORD dwMax_Clock;		/* Max Clock Rate */
+		DWORD dwDefault_Data_Rate;	/* Default Data Rate */
+		DWORD dwMax_Data_Rate;	/* Max Data Rate */
+		DWORD dwMax_IFSD;		/* Maximum IFSD Size */
+		DWORD dwSynch_Supported;	/* Synchronous Support */
+		DWORD dwPower_Mgmt;		/* Power Mgmt Features */
+		DWORD dwCard_Auth_Devices;	/* Card Auth Devices */
+		DWORD dwUser_Auth_Device;	/* User Auth Devices */
+		DWORD dwMechanics_Supported;	/* Machanics Supported */
+		DWORD dwVendor_Features;	/* User Defined.  */
+	};
+
+	typedef struct RdrCapabilities RDR_CAPABILITIES, *PRDR_CAPABILITIES;
+
+	struct ProtOptions
+	{
+		DWORD dwProtocol_Type;	/* Protocol Type */
+		DWORD dwCurrent_Clock;	/* Current Clock */
+		DWORD dwCurrent_F;		/* Current F */
+		DWORD dwCurrent_D;		/* Current D */
+		DWORD dwCurrent_N;		/* Current N */
+		DWORD dwCurrent_W;		/* Current W */
+		DWORD dwCurrent_IFSC;	/* Current IFSC */
+		DWORD dwCurrent_IFSD;	/* Current IFSD */
+		DWORD dwCurrent_BWT;	/* Current BWT */
+		DWORD dwCurrent_CWT;	/* Current CWT */
+		DWORD dwCurrent_EBC;	/* Current EBC */
+	};
+
+	typedef struct ProtOptions PROT_OPTIONS, *PPROT_OPTIONS;
+
+	struct RdrCliHandles
+	{
+		SCARDHANDLE hCard;		/* hCard for this connection */
+		DWORD dwEventStatus;	/* Recent event that must be sent */
+	};
+
+	typedef struct RdrCliHandles RDR_CLIHANDLES, *PRDR_CLIHANDLES;
+
+	struct ReaderContext
+	{
+		char lpcReader[MAX_READERNAME];	/* Reader Name */
+		char lpcLibrary[MAX_LIBNAME];	/* Library Path */
+		char lpcDevice[MAX_DEVICENAME];	/* Device Name */
+		PCSCLITE_THREAD_T pthThread;	/* Event polling thread */
+		PCSCLITE_MUTEX_T mMutex;	/* Mutex for this connection */
+		RDR_CLIHANDLES psHandles[PCSCLITE_MAX_READER_CONTEXT_CHANNELS];
+                                         /* Structure of connected handles */
+		union
+		{
+			FCT_MAP_V1 psFunctions_v1;	/* API V1.0 */
+			FCT_MAP_V2 psFunctions_v2;	/* API V2.0 */
+			FCT_MAP_V3 psFunctions_v3;	/* API V3.0 */
+		} psFunctions;
+
+		LPVOID vHandle;			/* Dlopen handle */
+		DWORD dwVersion;		/* IFD Handler version number */
+		DWORD dwPort;			/* Port ID */
+		DWORD dwSlot;			/* Current Reader Slot */
+		DWORD dwBlockStatus;	/* Current blocking status */
+		DWORD dwLockId;			/* Lock Id */
+		DWORD dwIdentity;		/* Shared ID High Nibble */
+		int32_t dwContexts;		/* Number of open contexts */
+		PDWORD pdwFeeds;		/* Number of shared client to lib */
+		PDWORD pdwMutex;		/* Number of client to mutex */
+
+		struct pubReaderStatesList *readerState; /* link to the reader state */
+		/* we can't use PREADER_STATE here since eventhandler.h can't be
+		 * included because of circular dependencies */
+
+		/* these structures are unused */
+#if 0
+		RDR_CAPABILITIES psCapabilites;	/* Structure of reader
+						   capabilities */
+		PROT_OPTIONS psProtOptions;	/* Structure of protocol options */
+#endif
+	};
+
+	typedef struct ReaderContext READER_CONTEXT, *PREADER_CONTEXT;
+
+	LONG RFAllocateReaderSpace(void);
+	LONG RFAddReader(LPSTR, DWORD, LPSTR, LPSTR);
+	LONG RFRemoveReader(LPSTR, DWORD);
+	LONG RFSetReaderName(PREADER_CONTEXT, LPCSTR, LPCSTR, DWORD, DWORD);
+	LONG RFListReaders(LPSTR, LPDWORD);
+	LONG RFReaderInfo(LPSTR, struct ReaderContext **);
+	LONG RFReaderInfoNamePort(DWORD, LPSTR, struct ReaderContext **);
+	LONG RFReaderInfoById(DWORD, struct ReaderContext **);
+	LONG RFCheckSharing(DWORD);
+	LONG RFLockSharing(DWORD);
+	LONG RFUnlockSharing(DWORD);
+	LONG RFUnblockReader(PREADER_CONTEXT);
+	LONG RFUnblockContext(SCARDCONTEXT);
+#if 0
+	LONG RFLoadReader(PREADER_CONTEXT);
+	LONG RFBindFunctions(PREADER_CONTEXT);
+	LONG RFUnBindFunctions(PREADER_CONTEXT);
+	LONG RFUnloadReader(PREADER_CONTEXT);
+#endif	
+	LONG RFInitializeReader(PREADER_CONTEXT);
+	LONG RFUnInitializeReader(PREADER_CONTEXT);
+	SCARDHANDLE RFCreateReaderHandle(PREADER_CONTEXT);
+	LONG RFDestroyReaderHandle(SCARDHANDLE hCard);
+	LONG RFAddReaderHandle(PREADER_CONTEXT, SCARDHANDLE);
+	LONG RFFindReaderHandle(SCARDHANDLE);
+	LONG RFRemoveReaderHandle(PREADER_CONTEXT, SCARDHANDLE);
+	LONG RFSetReaderEventState(PREADER_CONTEXT, DWORD);
+	LONG RFCheckReaderEventState(PREADER_CONTEXT, SCARDHANDLE);
+	LONG RFClearReaderEventState(PREADER_CONTEXT, SCARDHANDLE);
+	LONG RFCheckReaderStatus(PREADER_CONTEXT);
+	void RFCleanupReaders(int);
+	int RFStartSerialReaders(const char *readerconf);
+	void RFReCheckReaderConf(void);
+	void RFSuspendAllReaders(void);
+	void RFAwakeAllReaders(void);
+
+	void ReaderContextLock(PREADER_CONTEXT rContext);
+	void ReaderContextUnlock(PREADER_CONTEXT rContext);
+	int ReaderContextIsLocked(PREADER_CONTEXT rContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PCSC/readerstate.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/readerstate.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/readerstate.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2007 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  readerstate.cpp
+ *  SmartCardServices
+*/
+
+#include "readerstate.h"
+#include "pcsclite.h"
+#include "eventhandler.h"
+#include <security_utilities/debugging.h>
+
+DWORD SharedReaderState_State(READER_STATE *rs)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	return srs->xreaderState();
+}
+
+DWORD SharedReaderState_Protocol(READER_STATE *rs)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	return srs->xcardProtocol();
+}
+
+DWORD SharedReaderState_Sharing(READER_STATE *rs)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	return srs->sharing();
+}
+
+size_t SharedReaderState_CardAtrLength(READER_STATE *rs)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	return srs->xcardAtrLength();
+}
+
+LONG SharedReaderState_ReaderID(READER_STATE *rs)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	return srs->xreaderID();
+}
+
+const unsigned char *SharedReaderState_CardAtr(READER_STATE *rs)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	return srs->xcardAtr();
+}
+
+const char *SharedReaderState_ReaderName(READER_STATE *rs)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	return srs->xreaderName();
+}
+
+int SharedReaderState_ReaderNameIsEqual(READER_STATE *rs, const char *otherName)
+{
+	if (otherName)
+	{
+		PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+		return (strcmp(otherName, srs->xreaderName()) == 0);
+	}
+	else
+		return 0;
+}
+
+void SharedReaderState_SetState(READER_STATE *rs, DWORD state)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	srs->xreaderState(state);
+}
+
+void SharedReaderState_SetProtocol(READER_STATE *rs, DWORD newprotocol)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	srs->xcardProtocol(newprotocol);
+}
+
+void SharedReaderState_SetCardAtrLength(READER_STATE *rs, size_t len)
+{
+	PCSCD::SharedReaderState *srs = PCSCD::SharedReaderState::overlay(rs);
+	srs->xcardAtrLength(len);
+}
+
+
+#pragma mark ---------- C Interface ----------
+
+

Added: trunk/SmartCardServices/src/PCSC/readerstate.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/readerstate.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/readerstate.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2007 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  readerstate.h
+ *  SmartCardServices
+ */
+
+#ifndef _H_PCSCD_READER_STATE
+#define _H_PCSCD_READER_STATE
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "readerfactory.h"
+#include "eventhandler.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+DWORD SharedReaderState_State(READER_STATE *rs);
+DWORD SharedReaderState_Protocol(READER_STATE *rs);
+DWORD SharedReaderState_Sharing(READER_STATE *rs);
+size_t SharedReaderState_CardAtrLength(READER_STATE *rs);
+LONG SharedReaderState_ReaderID(READER_STATE *rs);
+const unsigned char *SharedReaderState_CardAtr(READER_STATE *rs);
+const char *SharedReaderState_ReaderName(READER_STATE *rs);
+int SharedReaderState_ReaderNameIsEqual(READER_STATE *rs, const char *otherName);
+void SharedReaderState_SetState(READER_STATE *rs, DWORD state);
+void SharedReaderState_SetProtocol(READER_STATE *rs, DWORD newprotocol);
+void SharedReaderState_SetCardAtrLength(READER_STATE *rs, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#if defined(__cplusplus)
+
+#include <security_utilities/threading.h>
+
+namespace PCSCD {
+
+//
+// NB: We are using the fact that on our systems, mutexes provide read/write
+// memory barrier as a side effect to avoid having to flush the shared memory
+// region to disk
+//
+
+
+//
+// A PODWrapper for the PCSC ReaderState structure
+//
+class SharedReaderState : public PodWrapper<SharedReaderState, READER_STATE>
+{
+public:
+
+	LONG xreaderID() const {  Atomic<int>::barrier(); return ntohl(readerID); }
+	void xreaderID(LONG rid) { Atomic<int>::barrier(); readerID = htonl(rid); }
+	
+	DWORD xreaderState() const { Atomic<int>::barrier(); return ntohl(readerState); }
+	void xreaderState(DWORD state) { Atomic<int>::barrier(); readerState = htonl(state); }
+
+	DWORD sharing() const { Atomic<int>::barrier(); return ntohl(readerSharing); }
+	void sharing(DWORD sharing) { Atomic<int>::barrier(); readerSharing = htonl(sharing); }
+
+	DWORD xlockState() const { Atomic<int>::barrier(); return ntohl(lockState); }
+	void xlockState(DWORD state) { Atomic<int>::barrier(); lockState = htonl(state); }
+
+	DWORD xcardProtocol() const { Atomic<int>::barrier(); return ntohl(cardProtocol); }
+	void xcardProtocol(DWORD prot) { Atomic<int>::barrier(); cardProtocol = htonl(prot); }
+
+	// strings
+	const char *xreaderName() const	{ Atomic<int>::barrier(); return readerName; }
+	void xreaderName(const char *rname, size_t len = MAX_READERNAME)	{ Atomic<int>::barrier(); strlcpy(readerName, rname, len); }
+	size_t readerNameLength() const { return strlen(readerName); }
+	void xreaderNameClear()	{ Atomic<int>::barrier(); memset(readerName, 0, sizeof(readerName));  }
+
+	const unsigned char *xcardAtr() const	{ Atomic<int>::barrier(); return cardAtr; }
+	unsigned char *xcardAtr() 	{ Atomic<int>::barrier(); return cardAtr; }
+	void xcardAtr(const unsigned char *atr, size_t len)	{ Atomic<int>::barrier(); 
+		memcpy((char *)&cardAtr[0], (const char *)atr, len); cardAtrLength = htonl(len); }
+	size_t xcardAtrLength() const { Atomic<int>::barrier(); return ntohl(cardAtrLength); }
+	void xcardAtrLength(DWORD len)  { Atomic<int>::barrier(); cardAtrLength = htonl(len); }
+	void xcardAtrClear()	{ Atomic<int>::barrier(); memset(cardAtr, 0, sizeof(cardAtr));  }
+};
+
+
+
+} // end namespace PCSCD
+
+#endif /* __cplusplus__ */
+
+#endif //_H_PCSCD_READER_STATE
+

Added: trunk/SmartCardServices/src/PCSC/sys_generic.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/sys_generic.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/sys_generic.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  sys_generic.h
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999
+ *  David Corcoran <corcoran at linuxnet.com>
+ *
+ * $Id: sys_generic.h 2264 2006-12-03 13:15:03Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles abstract system level calls.
+ */
+
+#ifndef __sys_generic_h__
+#define __sys_generic_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <sys/stat.h>
+
+	int SYS_Initialize(void);
+
+	int SYS_Mkdir(const char *, int);
+
+	int SYS_GetPID(void);
+
+	int SYS_Sleep(int);
+
+	int SYS_USleep(int);
+
+	int SYS_OpenFile(const char *, int, int);
+
+	int SYS_CloseFile(int);
+
+	int SYS_RemoveFile(const char *);
+
+	int SYS_Chmod(const char *, int);
+
+	int SYS_Chdir(const char *);
+
+	int SYS_GetUID(void);
+
+	int SYS_GetGID(void);
+
+	int SYS_ChangePermissions(const char *, int);
+
+	int SYS_SeekFile(int, int);
+
+	int SYS_ReadFile(int, char *, int);
+
+	int SYS_WriteFile(int, const char *, int);
+
+	int SYS_GetPageSize(void);
+
+	void *SYS_MemoryMap(int, int, int);
+
+	void *SYS_PublicMemoryMap(int, int, int);
+
+	void SYS_PublicMemoryUnmap(void *, int);
+
+	int SYS_MMapSynchronize(void *, int);
+
+	int SYS_Fork(void);
+
+	int SYS_Daemon(int, int);
+
+	int SYS_Stat(const char *pcFile, struct stat *psStatus);
+
+	int SYS_Fstat(int);
+
+	int SYS_Random(int, float, float);
+
+	int SYS_GetSeed();
+
+	void SYS_Exit(int);
+
+	int SYS_Unlink(const char *pcFile);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __sys_generic_h__ */

Added: trunk/SmartCardServices/src/PCSC/sys_macosx.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/sys_macosx.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/sys_macosx.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	Title  : sys_unix.c
+	Package: pcsc lite
+	Author : David Corcoran
+	Date   : 11/8/99
+	License: Copyright (C) 1999 David Corcoran
+			<corcoran at linuxnet.com>
+	Purpose: This handles abstract system level calls. 
+
+$Id: sys_macosx.cpp,v 1.5.40.1 2005/06/17 22:40:12 mb Exp $
+
+********************************************************************/
+
+#include <sys_generic.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include "pcscexport.h"
+#include "debug.h"
+
+#include "pcscdmonitor.h"
+#include <securityd_client/ssclient.h>
+//#include <security_utilities/debugging.h>
+
+#include "config.h"
+
+
+extern "C" {
+
+int SYS_Initialize()
+{
+	/*
+	 * Nothing special for OS X and Linux 
+	 */
+	return 0;
+}
+
+/**
+ * @brief Attempts to create a directory with some permissions.
+ *
+ * @param[in] path Path of the directory to be created.
+ * @param[in] perms Permissions to the new directory.
+ *
+ * @return Eror code.
+ * @retval 0 Success.
+ * @retval -1 An error occurred.
+ */
+INTERNAL int SYS_Mkdir(const char *path, int perms)
+{
+	return mkdir(path, perms);
+}
+
+/**
+ * @brief Gets the running process's ID.
+ *
+ * @return PID.
+ */
+INTERNAL int SYS_GetPID(void)
+{
+	return getpid();
+}
+
+/**
+ * @brief Makes the current process sleep for some seconds.
+ *
+ * @param[in] iTimeVal Number of seconds to sleep.
+ */
+INTERNAL int SYS_Sleep(int iTimeVal)
+{
+#ifdef HAVE_NANOSLEEP
+	struct timespec mrqtp;
+	mrqtp.tv_sec = iTimeVal;
+	mrqtp.tv_nsec = 0;
+
+	return nanosleep(&mrqtp, NULL);
+#else
+	return sleep(iTimeVal);
+#endif
+}
+
+/**
+ * @brief Makes the current process sleep for some microseconds.
+ *
+ * @param[in] iTimeVal Number of microseconds to sleep.
+ */
+INTERNAL int SYS_USleep(int iTimeVal)
+{
+#ifdef HAVE_NANOSLEEP
+	struct timespec mrqtp;
+	mrqtp.tv_sec = iTimeVal/1000000;
+	mrqtp.tv_nsec = (iTimeVal - (mrqtp.tv_sec * 1000000)) * 1000;
+
+	return nanosleep(&mrqtp, NULL);
+#else
+	usleep(iTimeVal);
+	return iTimeVal;
+#endif
+}
+
+/**
+ * @brief Opens/creates a file.
+ *
+ * @param[in] pcFile path to the file.
+ * @param[in] flags Open and read/write choices.
+ * @param[in] mode Permissions to the file.
+ *
+ * @return File descriptor.
+ * @retval >0 The file descriptor.
+ * @retval -1 An error ocurred.
+ */
+INTERNAL int SYS_OpenFile(const char *pcFile, int flags, int mode)
+{
+	return open(pcFile, flags, mode);
+}
+
+/**
+ * @brief Opens/creates a file.
+ *
+ * @param[in] iHandle File descriptor.
+ *
+ * @return Error code.
+ * @retval 0 Success.
+ * @retval -1 An error ocurred.
+ */
+INTERNAL int SYS_CloseFile(int iHandle)
+{
+	return close(iHandle);
+}
+
+/**
+ * @brief Removes a file.
+ *
+ * @param[in] pcFile path to the file.
+ *
+ * @return Error code.
+ * @retval 0 Success.
+ * @retval -1 An error ocurred.
+ */
+INTERNAL int SYS_RemoveFile(const char *pcFile)
+{
+	return remove(pcFile);
+}
+
+INTERNAL int SYS_Chmod(const char *path, int mode)
+{
+	return chmod(path, mode);
+}
+
+INTERNAL int SYS_Chdir(const char *path)
+{
+	return chdir(path);
+}
+
+int SYS_Mkfifo(const char *path, int mode)
+{
+	return mkfifo(path, mode);
+}
+
+int SYS_Mknod(const char *path, int mode, int dev)
+{
+	return mknod(path, mode, dev);
+}
+
+int SYS_GetUID()
+{
+	return getuid();
+}
+
+INTERNAL int SYS_GetGID(void)
+{
+	return getgid();
+}
+
+INTERNAL int SYS_SeekFile(int iHandle, int iSeekLength)
+{
+	int iOffset;
+	iOffset = lseek(iHandle, iSeekLength, SEEK_SET);
+	return iOffset;
+}
+
+INTERNAL int SYS_ReadFile(int iHandle, char *pcBuffer, int iLength)
+{
+	return read(iHandle, pcBuffer, iLength);
+}
+
+INTERNAL int SYS_WriteFile(int iHandle, const char *pcBuffer, int iLength)
+{
+	return write(iHandle, pcBuffer, iLength);
+}
+
+/**
+ * @brief Gets the memory page size.
+ *
+ * The page size is used when calling the \c SYS_MemoryMap() and
+ * \c SYS_PublicMemoryMap() functions.
+ *
+ * @return Number of bytes per page.
+ */
+INTERNAL int SYS_GetPageSize(void)
+{
+	return getpagesize();
+}
+
+/**
+ * @brief Map the file \p iFid in memory for reading and writing.
+ *
+ * @param[in] iSize Size of the memmory mapped.
+ * @param[in] iFid File which will be mapped in memory.
+ * @param[in] iOffset Start point of the file to be mapped in memory.
+ *
+ * @return Address of the memory map.
+ * @retval MAP_FAILED in case of error
+ */
+INTERNAL void *SYS_MemoryMap(int iSize, int iFid, int iOffset)
+{
+
+	void *vAddress;
+
+	vAddress = 0;
+	vAddress = mmap(0, iSize, PROT_READ | PROT_WRITE,
+		MAP_SHARED, iFid, iOffset);
+
+	/*
+	 * Here are some common error types: switch( errno ) { case EINVAL:
+	 * printf("EINVAL"); case EBADF: printf("EBADF"); break; case EACCES:
+	 * printf("EACCES"); break; case EAGAIN: printf("EAGAIN"); break; case
+	 * ENOMEM: printf("ENOMEM"); break; }
+	 */
+
+	return vAddress;
+}
+
+/**
+ * @brief Map the file \p iFid in memory only for reading.
+ *
+ * @param[in] iSize Size of the memmory mapped.
+ * @param[in] iFid File which will be mapped in memory.
+ * @param[in] iOffset Start point of the file to be mapped in memory.
+ *
+ * @return Address of the memory map.
+ */
+INTERNAL void *SYS_PublicMemoryMap(int iSize, int iFid, int iOffset)
+{
+
+	void *vAddress;
+
+	vAddress = 0;
+	vAddress = mmap(0, iSize, PROT_READ, MAP_SHARED, iFid, iOffset);
+	if (vAddress == (void*)-1) /* mmap returns -1 on error */
+	{
+		Log2(PCSC_LOG_CRITICAL, "SYS_PublicMemoryMap() failed: %s",
+			strerror(errno));
+		vAddress = NULL;
+	}
+
+	return vAddress;
+}
+
+int SYS_MMapSynchronize(void *begin, int length)
+{
+	int rc = msync(begin, length, MS_SYNC | MS_INVALIDATE);
+	
+	PCSCDMonitor::postNotification(SecurityServer::kNotificationPCSCStateChange);
+
+	return rc;
+}
+
+int SYS_MUnmap(void *begin, int length)
+{
+	return munmap(begin, length);
+}
+
+INTERNAL int SYS_Fork(void)
+{
+	return fork();
+}
+
+#ifdef HAVE_DAEMON
+int SYS_Daemon(int nochdir, int noclose)
+{
+	return daemon(nochdir, noclose);
+}
+#endif
+
+int SYS_Wait(int iPid, int iWait)
+{
+	return waitpid(-1, 0, WNOHANG);
+}
+
+INTERNAL int SYS_Stat(const char *pcFile, struct stat *psStatus)
+{
+	return stat(pcFile, psStatus);
+}
+
+int SYS_Fstat(int iFd)
+{
+	struct stat sStatus;
+	return fstat(iFd, &sStatus);
+}
+
+int SYS_Random(int iSeed, float fStart, float fEnd)
+{
+
+	int iRandNum = 0;
+
+	if (iSeed != 0)
+	{
+		srand(iSeed);
+	}
+
+	iRandNum = 1 + (int) (fEnd * rand() / (RAND_MAX + fStart));
+	srand(iRandNum);
+
+	return iRandNum;
+}
+
+INTERNAL int SYS_GetSeed(void)
+{
+	struct timeval tv;
+	struct timezone tz;
+	long myseed = 0;
+
+	tz.tz_minuteswest = 0;
+	tz.tz_dsttime = 0;
+	if (gettimeofday(&tv, &tz) == 0)
+	{
+		myseed = tv.tv_usec;
+	} else
+	{
+		myseed = (long) time(NULL);
+	}
+	return myseed;
+}
+
+INTERNAL void SYS_Exit(int iRetVal)
+{
+	_exit(iRetVal);
+}
+
+INTERNAL int SYS_Unlink(const char *pcFile)
+{
+	return unlink(pcFile);
+}
+
+}   // extern "C"

Added: trunk/SmartCardServices/src/PCSC/sys_unix.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/sys_unix.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/sys_unix.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,404 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  sys_unix.c
+ *  SmartCardServices
+ */
+
+/*
+ * This handles abstract system level calls.
+ *
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999
+ *  David Corcoran <corcoran at linuxnet.com>
+ *
+ * $Id: sys_unix.c 2353 2007-01-23 10:31:50Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles abstract system level calls.
+ */
+
+#include <sys_generic.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <string.h>
+#include "debug.h"
+
+#include "config.h"
+#include "pcscexport.h"
+
+#include <security_utilities/debugging.h>
+
+/**
+ * @brief Make system wide initialization.
+ *
+ * @return Eror code.
+ * @retval 0 Success.
+ */
+INTERNAL int SYS_Initialize(void)
+{
+	/*
+	 * Nothing special for OS X and Linux 
+	 */
+	return 0;
+}
+
+/**
+ * @brief Attempts to create a directory with some permissions.
+ *
+ * @param[in] path Path of the directory to be created.
+ * @param[in] perms Permissions to the new directory.
+ *
+ * @return Eror code.
+ * @retval 0 Success.
+ * @retval -1 An error occurred.
+ */
+INTERNAL int SYS_Mkdir(const char *path, int perms)
+{
+	return mkdir(path, perms);
+}
+
+/**
+ * @brief Gets the running process's ID.
+ *
+ * @return PID.
+ */
+INTERNAL int SYS_GetPID(void)
+{
+	return getpid();
+}
+
+/**
+ * @brief Makes the current process sleep for some seconds.
+ *
+ * @param[in] iTimeVal Number of seconds to sleep.
+ */
+INTERNAL int SYS_Sleep(int iTimeVal)
+{
+#ifdef HAVE_NANOSLEEP
+	struct timespec mrqtp;
+	mrqtp.tv_sec = iTimeVal;
+	mrqtp.tv_nsec = 0;
+
+	return nanosleep(&mrqtp, NULL);
+#else
+	return sleep(iTimeVal);
+#endif
+}
+
+/**
+ * @brief Makes the current process sleep for some microseconds.
+ *
+ * @param[in] iTimeVal Number of microseconds to sleep.
+ */
+INTERNAL int SYS_USleep(int iTimeVal)
+{
+#ifdef HAVE_NANOSLEEP
+	struct timespec mrqtp;
+	mrqtp.tv_sec = iTimeVal/1000000;
+	mrqtp.tv_nsec = (iTimeVal - (mrqtp.tv_sec * 1000000)) * 1000;
+
+	return nanosleep(&mrqtp, NULL);
+#else
+	usleep(iTimeVal);
+	return iTimeVal;
+#endif
+}
+
+/**
+ * @brief Opens/creates a file.
+ *
+ * @param[in] pcFile path to the file.
+ * @param[in] flags Open and read/write choices.
+ * @param[in] mode Permissions to the file.
+ *
+ * @return File descriptor.
+ * @retval >0 The file descriptor.
+ * @retval -1 An error ocurred.
+ */
+INTERNAL int SYS_OpenFile(const char *pcFile, int flags, int mode)
+{
+	return open(pcFile, flags, mode);
+}
+
+/**
+ * @brief Opens/creates a file.
+ *
+ * @param[in] iHandle File descriptor.
+ *
+ * @return Error code.
+ * @retval 0 Success.
+ * @retval -1 An error ocurred.
+ */
+INTERNAL int SYS_CloseFile(int iHandle)
+{
+	return close(iHandle);
+}
+
+/**
+ * @brief Removes a file.
+ *
+ * @param[in] pcFile path to the file.
+ *
+ * @return Error code.
+ * @retval 0 Success.
+ * @retval -1 An error ocurred.
+ */
+INTERNAL int SYS_RemoveFile(const char *pcFile)
+{
+	return remove(pcFile);
+}
+
+INTERNAL int SYS_Chmod(const char *path, int mode)
+{
+	return chmod(path, mode);
+}
+
+INTERNAL int SYS_Chdir(const char *path)
+{
+	return chdir(path);
+}
+
+INTERNAL int SYS_GetUID(void)
+{
+	return getuid();
+}
+
+INTERNAL int SYS_GetGID(void)
+{
+	return getgid();
+}
+
+INTERNAL int SYS_SeekFile(int iHandle, int iSeekLength)
+{
+	int iOffset;
+	iOffset = lseek(iHandle, iSeekLength, SEEK_SET);
+	return iOffset;
+}
+
+INTERNAL int SYS_ReadFile(int iHandle, char *pcBuffer, int iLength)
+{
+	return read(iHandle, pcBuffer, iLength);
+}
+
+INTERNAL int SYS_WriteFile(int iHandle, const char *pcBuffer, int iLength)
+{
+	return write(iHandle, pcBuffer, iLength);
+}
+
+/**
+ * @brief Gets the memory page size.
+ *
+ * The page size is used when calling the \c SYS_MemoryMap() and
+ * \c SYS_PublicMemoryMap() functions.
+ *
+ * @return Number of bytes per page.
+ */
+INTERNAL int SYS_GetPageSize(void)
+{
+	return getpagesize();
+}
+
+/**
+ * @brief Map the file \p iFid in memory for reading and writing.
+ *
+ * @param[in] iSize Size of the memmory mapped.
+ * @param[in] iFid File which will be mapped in memory.
+ * @param[in] iOffset Start point of the file to be mapped in memory.
+ *
+ * @return Address of the memory map.
+ * @retval MAP_FAILED in case of error
+ */
+INTERNAL void *SYS_MemoryMap(int iSize, int iFid, int iOffset)
+{
+
+	void *vAddress;
+
+	vAddress = 0;
+	vAddress = mmap(0, iSize, PROT_READ | PROT_WRITE,
+		MAP_SHARED, iFid, iOffset);
+
+	/*
+	 * Here are some common error types: switch( errno ) { case EINVAL:
+	 * printf("EINVAL"); case EBADF: printf("EBADF"); break; case EACCES:
+	 * printf("EACCES"); break; case EAGAIN: printf("EAGAIN"); break; case
+	 * ENOMEM: printf("ENOMEM"); break; }
+	 */
+
+	return vAddress;
+}
+
+/**
+ * @brief Map the file \p iFid in memory only for reading.
+ *
+ * @param[in] iSize Size of the memmory mapped.
+ * @param[in] iFid File which will be mapped in memory.
+ * @param[in] iOffset Start point of the file to be mapped in memory.
+ *
+ * @return Address of the memory map.
+ */
+INTERNAL void *SYS_PublicMemoryMap(int iSize, int iFid, int iOffset)
+{
+
+	void *vAddress;
+
+	vAddress = 0;
+	vAddress = mmap(0, iSize, PROT_READ, MAP_SHARED, iFid, iOffset);
+	if (vAddress == (void*)-1) /* mmap returns -1 on error */
+	{
+		Log2(PCSC_LOG_CRITICAL, "SYS_PublicMemoryMap() failed: %s",
+			strerror(errno));
+		vAddress = NULL;
+	}
+
+	return vAddress;
+}
+
+/**
+ * @brief Unmap a memory segment
+ *
+ * @param ptr pointer returned by SYS_PublicMemoryMap()
+ * @param iSize size of the memory segment
+ */
+INTERNAL void SYS_PublicMemoryUnmap(void * ptr, int iSize)
+{
+	munmap(ptr, iSize);
+}
+
+/**
+ * @brief Writes the changes made in a memory map to the disk mapped file.
+ *
+ * @param[in] begin Start of the block to be written
+ * @param[in] length Lenght of the block to be written
+ *
+ * @return Error code.
+ * @retval 0 Success.
+ * @retval -1 An error ocurred.
+ */
+INTERNAL int SYS_MMapSynchronize(void *begin, int length)
+{
+	int flags = 0;
+
+#ifdef MS_INVALIDATE
+	flags |= MS_INVALIDATE;
+#endif
+	return msync(begin, length, MS_SYNC | flags);
+}
+
+INTERNAL int SYS_Fork(void)
+{
+	return fork();
+}
+
+/**
+ * @brief put the process to run in the background.
+ *
+ * @param[in] nochdir if zero, change the current directory to "/".
+ * @param[in] noclose if zero, redirect standard imput/output/error to /dev/nulll.
+ *
+ * @return error code.
+ * @retval 0 success.
+ * @retval -1 an error ocurred.
+ */
+INTERNAL int SYS_Daemon(int nochdir, int noclose)
+{
+#ifdef HAVE_DAEMON
+	return daemon(nochdir, noclose);
+}
+#endif
+
+int SYS_Wait(int iPid, int iWait)
+{
+	return waitpid(-1, 0, WNOHANG);
+}
+
+INTERNAL int SYS_Stat(const char *pcFile, struct stat *psStatus)
+{
+	return stat(pcFile, psStatus);
+}
+
+int SYS_Fstat(int iFd)
+{
+	struct stat sStatus;
+	return fstat(iFd, &sStatus);
+}
+
+int SYS_Random(int iSeed, float fStart, float fEnd)
+{
+
+	int iRandNum = 0;
+
+	if (iSeed != 0)
+	{
+		srand(iSeed);
+	}
+
+	iRandNum = 1 + (int) (fEnd * rand() / (RAND_MAX + fStart));
+	srand(iRandNum);
+
+	return iRandNum;
+}
+
+INTERNAL int SYS_GetSeed(void)
+{
+	struct timeval tv;
+	struct timezone tz;
+	long myseed = 0;
+
+	tz.tz_minuteswest = 0;
+	tz.tz_dsttime = 0;
+	if (gettimeofday(&tv, &tz) == 0)
+	{
+		myseed = tv.tv_usec;
+	} else
+	{
+		myseed = (long) time(NULL);
+	}
+	return myseed;
+}
+
+INTERNAL void SYS_Exit(int iRetVal)
+{
+	_exit(iRetVal);
+}
+
+INTERNAL int SYS_Unlink(const char *pcFile)
+{
+	return unlink(pcFile);
+}
+

Added: trunk/SmartCardServices/src/PCSC/testpcsc.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/testpcsc.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/testpcsc.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : test.c
+	    Package: pcsc lite
+            Author : David Corcoran
+            Date   : 7/27/99
+	    License: Copyright (C) 1999 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This is a test program for pcsc-lite.
+	            
+********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "pcsclite.h"
+#include "winscard.h"
+
+/*
+ * #define REPEAT_TEST 1 
+ */
+
+int main(int argc, char **argv)
+{
+	SCARDHANDLE hCard;
+	SCARDCONTEXT hContext;
+	SCARD_READERSTATE_A rgReaderStates[1];
+	uint32_t dwReaderLen, dwState, dwProt, dwAtrLen;
+	// unsigned long dwSendLength, dwRecvLength;
+	uint32_t dwPref, dwReaders;
+	char *pcReaders, *mszReaders;
+	unsigned char pbAtr[MAX_ATR_SIZE];
+	const char *mszGroups;
+	long rv;
+	int i, p, iReader;
+	int iList[16];
+
+	int t = 0;
+
+	printf("\nMUSCLE PC/SC Lite Test Program\n\n");
+
+doInit:
+	printf("Testing SCardEstablishContext    : ");
+	rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+
+	printf("%s\n", pcsc_stringify_error(rv));
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		return -1;
+	}
+
+	printf("Testing SCardGetStatusChange \n");
+	printf("Please insert a working reader   : ");
+	rv = SCardGetStatusChange(hContext, INFINITE, 0, 0);
+
+	printf("%s\n", pcsc_stringify_error(rv));
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		SCardReleaseContext(hContext);
+		return -1;
+	}
+
+	printf("Testing SCardListReaders         : ");
+
+	mszGroups = 0;
+	rv = SCardListReaders(hContext, mszGroups, 0, &dwReaders);
+
+	printf("%s\n", pcsc_stringify_error(rv));
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		SCardReleaseContext(hContext);
+		return -1;
+	}
+
+	mszReaders = (char *) malloc(sizeof(char) * dwReaders);
+	rv = SCardListReaders(hContext, mszGroups, mszReaders, &dwReaders);
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		SCardReleaseContext(hContext);
+		return -1;
+	}
+
+	/*
+	 * Have to understand the multi-string here 
+	 */
+	p = 0;
+	for (i = 0; i < dwReaders - 1; i++)
+	{
+		++p;
+		printf("Reader %02d: %s\n", p, &mszReaders[i]);
+		iList[p] = i;
+		while (mszReaders[++i] != 0) ;
+	}
+
+#ifdef REPEAT_TEST
+	if (t == 0)
+	{
+#endif
+
+		do
+		{
+			/* scanf doesn't provide a friendly way to 'throw away' the garbage input
+			 * so we grab a line and then try to parse it */
+			size_t iScanLength;
+			char *sLine;
+			printf("Enter the reader number          : ");
+			sLine = fgetln(stdin, &iScanLength);
+			if(sLine == NULL) /* EOF */
+				return 0;
+			/* Null terminate by replacing \n w/ \0*/
+			sLine[iScanLength - 1] = '\0';
+			iReader = atoi(sLine);
+			/* Since 0 is invalid input, no need to test errno */
+			if(iReader > p || iReader <= 0) {
+				printf("Invalid Value - try again\n");
+			}
+		}
+		while (iReader > p || iReader <= 0);
+
+#ifdef REPEAT_TEST
+		t = 1;
+	}
+#endif
+
+	rgReaderStates[0].szReader = &mszReaders[iList[iReader]];
+	rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;
+
+	printf("Waiting for card insertion         \n");
+	rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
+
+	printf("                                 : %s\n",
+		pcsc_stringify_error(rv));
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		SCardReleaseContext(hContext);
+		return -1;
+	}
+
+//	printf("   context handle: %d [0x%08X]\n", hContext, hContext);
+	printf("Testing SCardConnect             : ");
+	rv = SCardConnect(hContext, &mszReaders[iList[iReader]],
+		SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+		&hCard, &dwPref);
+
+	printf("%s\n", pcsc_stringify_error(rv));
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		SCardReleaseContext(hContext);
+		return -1;
+	}
+
+	printf("Testing SCardStatus              : ");
+
+	dwReaderLen = MAX_READERNAME;
+	pcReaders = (char *) malloc(sizeof(char) * MAX_READERNAME);
+	dwAtrLen = MAX_ATR_SIZE;
+	
+	rv = SCardStatus(hCard, pcReaders, &dwReaderLen, &dwState, &dwProt,
+		pbAtr, &dwAtrLen);
+
+	printf("%s\n", pcsc_stringify_error(rv));
+
+	printf("Current Reader Name              : %s\n", pcReaders);
+	printf("Current Reader State             : 0x%X\n", dwState);
+	printf("Current Reader Protocol          : 0x%X\n", dwProt - 1);
+	printf("Current Reader ATR Size          : %d (0x%x)\n", dwAtrLen, dwAtrLen);
+	printf("Current Reader ATR Value         : ");
+
+	for (i = 0; i < dwAtrLen; i++)
+	{
+		printf("%02X ", pbAtr[i]);
+	}
+	printf("\n");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		SCardDisconnect(hCard, SCARD_RESET_CARD);
+		SCardReleaseContext(hContext);
+	}
+
+	printf("Testing SCardDisconnect          : ");
+	rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
+
+	printf("%s\n", pcsc_stringify_error(rv));
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		SCardReleaseContext(hContext);
+		return -1;
+	}
+
+	printf("Testing SCardReleaseContext      : ");
+	rv = SCardReleaseContext(hContext);
+
+	printf("%s\n", pcsc_stringify_error(rv));
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		return -1;
+	}
+	if(t == 0) {
+		t = 1;
+		goto doInit;
+	}
+
+	printf("\n");
+	printf("PC/SC Test Completed Successfully !\n");
+
+	return 0;
+}

Added: trunk/SmartCardServices/src/PCSC/thread_generic.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/thread_generic.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/thread_generic.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : thread_generic.h
+	    Package: pcsc lite
+            Author : David Corcoran
+            Date   : 3/24/00
+	    License: Copyright (C) 2000 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This provides system specific thread calls. 
+	            
+********************************************************************/
+
+#ifndef __thread_generic_h__
+#define __thread_generic_h__
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef WIN32
+#define PCSCLITE_THREAD_T                HANDLE
+#define PCSCLITE_MUTEX                   CRITICAL_SECTION
+#define PCSCLITE_MUTEX_T                 CRITICAL_SECTION*
+#define PCSCLITE_THREAD_FUNCTION(f)      void *(*f)(void *)
+#else
+#define PCSCLITE_THREAD_T                pthread_t
+#define PCSCLITE_MUTEX                   pthread_mutex_t
+#define PCSCLITE_MUTEX_T                 pthread_mutex_t*
+#define PCSCLITE_THREAD_FUNCTION(f)      void *(*f)(void *)
+#endif
+
+/* thread attributes */
+#define THREAD_ATTR_DEFAULT			0
+#define THREAD_ATTR_DETACHED		1
+
+	int SYS_MutexInit(PCSCLITE_MUTEX_T);
+	int SYS_MutexDestroy(PCSCLITE_MUTEX_T);
+	int SYS_MutexLock(PCSCLITE_MUTEX_T);
+	int SYS_MutexUnLock(PCSCLITE_MUTEX_T);
+	int SYS_ThreadCreate(PCSCLITE_THREAD_T *, int, PCSCLITE_THREAD_FUNCTION( ), LPVOID);
+	int SYS_ThreadCancel(PCSCLITE_THREAD_T *);
+	int SYS_ThreadDetach(PCSCLITE_THREAD_T);
+	int SYS_ThreadJoin(PCSCLITE_THREAD_T *, LPVOID*);
+	int SYS_ThreadExit(LPVOID);
+	PCSCLITE_THREAD_T SYS_ThreadSelf(void);
+	int SYS_ThreadEqual(PCSCLITE_THREAD_T *, PCSCLITE_THREAD_T *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __thread_generic_h__ */

Added: trunk/SmartCardServices/src/PCSC/thread_macosx.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/thread_macosx.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/thread_macosx.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : thread_macosx.c
+	    Package: pcsc lite
+            Author : David Corcoran
+            Date   : 7/6/00
+	    License: Copyright (C) 2000 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This handles thread function abstraction.
+	            
+********************************************************************/
+
+#include "config.h"
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "thread_generic.h"
+
+#define PCSC_MUTEX_LOCKED    1
+#define PCSC_MUTEX_UNLOCKED  0
+
+int SYS_MutexInit(PCSCLITE_MUTEX_T mMutex)
+{
+	int retval;
+	retval = pthread_mutex_init(mMutex, NULL);
+	return retval;
+}
+
+int SYS_MutexDestroy(PCSCLITE_MUTEX_T mMutex)
+{
+	int retval;
+	retval = pthread_mutex_destroy(mMutex);
+	return retval;
+}
+
+int SYS_MutexLock(PCSCLITE_MUTEX_T mMutex)
+{
+	int retval;
+	retval = pthread_mutex_lock(mMutex);
+	return retval;
+}
+
+int SYS_MutexUnLock(PCSCLITE_MUTEX_T mMutex)
+{
+	int retval;
+	retval = pthread_mutex_unlock(mMutex);
+	return retval;
+}
+
+int SYS_ThreadCreate(PCSCLITE_THREAD_T * pthThread, int attributes,
+	PCSCLITE_THREAD_FUNCTION(pvFunction), LPVOID pvArg)
+{
+	pthread_attr_t attr;
+
+	if (0 != pthread_attr_init(&attr))
+		return 0;
+
+	if (0 != pthread_attr_setdetachstate(&attr,
+		attributes & THREAD_ATTR_DETACHED ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE))
+		return 0;
+
+	if (0 == pthread_create(pthThread, &attr, pvFunction, pvArg))
+		return 1;
+	else
+		return 0;
+}
+
+int SYS_ThreadCancel(PCSCLITE_THREAD_T * pthThread)
+{
+
+	int retval;
+	retval = pthread_cancel(*pthThread);
+
+	if (retval == 0)
+	{
+		return 1;
+	} else
+	{
+		return 0;
+	}
+}
+
+int SYS_ThreadDetach(PCSCLITE_THREAD_T pthThread)
+{
+	// Returns 1 (true) if thread detached OK, 0 (false) otherwise
+	if (pthThread)
+		return (pthread_detach(pthThread) == 0);	// 0 result is success
+
+	return 0;
+}
+
+int SYS_ThreadJoin(PCSCLITE_THREAD_T *pthThread, LPVOID* pvRetVal)
+{
+
+	int retval;
+	retval = pthread_join(*pthThread, pvRetVal);
+
+	if (retval == 0)
+	{
+		return 1;
+	} else
+	{
+		return 0;
+	}
+}
+
+int SYS_ThreadExit(LPVOID pvRetVal)
+{
+
+	pthread_exit(pvRetVal);
+	return 1;
+}

Added: trunk/SmartCardServices/src/PCSC/tokenfactory.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/tokenfactory.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/tokenfactory.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,787 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+		Title  : tokenfactory.c
+		Package: pcsc lite
+		Author : David Corcoran
+		Date   : 01/01/00
+		Purpose: This handles card abstraction attachment. 
+
+ $Id: tokenfactory.c,v 1.3 2004/09/21 02:43:57 mb Exp $
+
+*******************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#ifndef WIN32
+#include <dirent.h>
+#include "config.h"
+#else
+#include "../win32/win32_config.h"
+#endif
+
+#include "debuglog.h"
+#include "dyn_generic.h"
+#include "tokenfactory.h"
+
+#define MSC_MANUMSC_KEY_NAME                "spVendorName"
+#define MSC_PRODMSC_KEY_NAME                "spProductName"
+#define MSC_ATRMSC_KEY_NAME                 "spAtrValue"
+#define MSC_LIBRMSC_KEY_NAME                "CFBundleExecutable"
+#define MSC_DEFAULTAPP_NAME                 "spDefaultApplication"
+
+extern int LTPBundleFindValueWithKey(char *, char *, char *, int);
+
+int atrToString(MSCPUChar8 Atr, MSCULong32 Length, char *outAtr)
+{
+
+	int i;
+	int j;
+
+	j = 0;
+
+	for (i = 0; i < Length; i++)
+	{
+		if ((Atr[i] / 16) > 9)
+		{
+			outAtr[j] = ((Atr[i] / 16) - 10) + 'A';
+		} else
+		{
+			outAtr[j] = (Atr[i] / 16) + '0';
+		}
+
+		j += 1;
+
+		if ((Atr[i] % 16) > 9)
+		{
+			outAtr[j] = ((Atr[i] % 16) - 10) + 'A';
+		} else
+		{
+			outAtr[j] = (Atr[i] % 16) + '0';
+		}
+
+		j += 1;
+
+	}
+
+	outAtr[j] = 0;	/* Add the NULL */
+
+	return 0;
+}
+
+int stringToBytes(char *inStr, MSCPUChar8 Buffer, MSCPULong32 Length)
+{
+
+	int i;
+	int j;
+	int inLen;
+
+	j = 0;
+	inLen = 0;
+
+	inLen = strlen(inStr);
+
+	if (inLen > MSC_MAXSIZE_AID)
+	{
+		return -1;
+	}
+
+	for (i = 0; i < inLen; i += 2)
+	{
+		if (inStr[i] <= '9' && inStr[i] >= '0')
+		{
+			Buffer[j] = (inStr[i] - '0') * 16;
+		} else if (inStr[i] <= 'F' && inStr[i] >= 'A')
+		{
+			Buffer[j] = (inStr[i] - 'A' + 10) * 16;
+		}
+
+		if (inStr[i + 1] <= '9' && inStr[i + 1] >= '0')
+		{
+			Buffer[j] += inStr[i + 1] - '0';
+		} else if (inStr[i + 1] <= 'F' && inStr[i + 1] >= 'A')
+		{
+			Buffer[j] += inStr[i + 1] - 'A' + 10;
+		}
+
+		j += 1;
+	}
+
+	*Length = j;
+
+	return 0;
+}
+
+MSCLong32 TPSearchBundlesForAtr(MSCPUChar8 Atr, MSCULong32 Length,
+	MSCLPTokenInfo tokenInfo)
+{
+
+	MSCLong32 rv;
+
+#ifndef WIN32
+	DIR *hpDir = 0;
+	struct dirent *currFP = 0;
+#else
+	HANDLE hFind;
+	WIN32_FIND_DATA findData;
+	char findPath[200];
+#endif
+
+	char atrString[100];
+	char fullPath[200];
+	char fullLibPath[250];
+	char keyValue[200];
+	int atrIndex;
+
+	rv = 0;
+	atrIndex = 0;
+
+	atrToString(Atr, Length, atrString);
+
+#ifndef WIN32
+	
+	hpDir = opendir(MSC_SVC_DROPDIR);
+
+	if (hpDir == 0)
+#else
+	sprintf(findPath, "%s\\*.bundle", MSC_SVC_DROPDIR);
+	hFind = FindFirstFile(findPath, &findData);
+
+	if (hFind == INVALID_HANDLE_VALUE)
+#endif
+	{
+		DebugLogA("Cannot open PC/SC token drivers directory.\n");
+
+		return -1;
+	}
+
+#ifndef WIN32
+	while ((currFP = readdir(hpDir)) != 0)
+	{
+		if (strstr(currFP->d_name, ".bundle") != 0)
+#else
+	do
+	{
+		if (strstr(findData.cFileName, ".bundle") != 0)
+#endif
+		{
+
+			/*
+			 * The bundle exists - let's form a full path name and get the
+			 * vendor and product ID's for this particular bundle 
+			 */
+#ifndef WIN32
+			sprintf(fullPath, "%s%s%s", MSC_SVC_DROPDIR, currFP->d_name,
+				"/Contents/Info.plist");
+#else
+			sprintf(fullPath, "%s%s%s", MSC_SVC_DROPDIR, findData.cFileName,
+				"\\Contents\\Info.plist");
+#endif
+
+			atrIndex = 0;
+
+#ifdef MSC_DEBUG
+			DebugLogB("ATR comparison: FILE: %s\n", fullPath);
+			DebugLogB("ATR comparison: Target Match: %s\n", atrString);
+#endif
+
+			while (1)
+			{
+				rv = LTPBundleFindValueWithKey(fullPath,
+					MSC_ATRMSC_KEY_NAME, keyValue, atrIndex);
+				if (rv != 0)
+				{
+					break;	/* No aliases found, break out of search
+							 * aliases loop */
+				}
+#ifdef MSC_DEBUG
+				DebugLogB("ATR comparison: Source: %s\n", keyValue);
+#endif
+
+				if (strcmp(keyValue, atrString) != 0)
+				{
+					/*
+					 * Go back and see if there are any aliases 
+					 */
+					atrIndex += 1;
+					continue;
+				}
+#ifdef MSC_DEBUG
+				DebugLogB("Match found at ATR alias %d\n", atrIndex);
+#endif
+
+				/*
+				 * See if this bundle has a special name for this ATR 
+				 */
+				rv = LTPBundleFindValueWithKey(fullPath,
+					MSC_PRODMSC_KEY_NAME, keyValue, atrIndex);
+				if (rv != 0)
+				{
+					rv = LTPBundleFindValueWithKey(fullPath,
+						MSC_PRODMSC_KEY_NAME, keyValue, 0);
+					if (rv != 0)
+					{
+						DebugLogA
+							("Match found, failed due to no product name.\n");
+#ifndef WIN32
+						closedir(hpDir);
+#endif
+						return -1;
+					}
+				}
+#ifdef MSC_DEBUG
+				DebugLogB("Product name: %s\n", keyValue);
+#endif
+				strcpy(tokenInfo->tokenName, keyValue);
+
+				/*
+				 * See if this bundle has a special driver for this card 
+				 */
+				rv = LTPBundleFindValueWithKey(fullPath,
+					MSC_LIBRMSC_KEY_NAME, keyValue, atrIndex);
+				if (rv != 0)
+				{
+					rv = LTPBundleFindValueWithKey(fullPath,
+						MSC_LIBRMSC_KEY_NAME, keyValue, 0);
+					if (rv != 0)
+					{
+						DebugLogA
+							("Match found, failed due to no library path.\n");
+#ifndef WIN32
+						closedir(hpDir);
+#endif
+						return -1;
+					}
+				}
+#ifdef WIN32
+				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
+					findData.cFileName, "\\Contents\\Win32\\", keyValue);
+#else
+#ifdef MSC_TARGET_LINUX
+				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
+					currFP->d_name, "/Contents/Linux/", keyValue);
+#else
+#ifdef MSC_TARGET_OSX
+				sprintf(fullLibPath, "%s%s", MSC_SVC_DROPDIR,
+					currFP->d_name);
+
+#else
+#ifdef MSC_TARGET_BSD
+				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
+					currFP->d_name, "/Contents/BSD/", keyValue);
+
+#else
+#ifdef MSC_TARGET_SOLARIS
+				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
+					currFP->d_name, "/Contents/Solaris/", keyValue);
+
+#else
+#ifdef MSC_TARGET_HPUX
+				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
+					currFP->d_name, "/Contents/HPUX/", keyValue);
+
+#else
+#ifdef MSC_TARGET_TRU64
+				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
+					currFP->d_name, "/Contents/Tru64/", keyValue);
+
+#else
+#ifdef MSC_TARGET_CYGWIN
+				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
+					currFP->d_name, "/Contents/CygWin/", keyValue);
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+
+				if (fullLibPath == NULL)
+				{
+					DebugLogA("No path to bundle library found !\n");
+					return -1;
+				}
+
+				/*
+				 * Copy the library path and return successfully 
+				 */
+				strcpy(tokenInfo->svProvider, fullLibPath);
+
+				/*
+				 * See if this bundle has a default AID 
+				 */
+				rv = LTPBundleFindValueWithKey(fullPath,
+					MSC_DEFAULTAPP_NAME, keyValue, atrIndex);
+				if (rv != 0)
+				{
+					rv = LTPBundleFindValueWithKey(fullPath,
+						MSC_DEFAULTAPP_NAME, keyValue, 0);
+				}
+
+				if (rv == 0)
+				{
+#ifdef MSC_DEBUG
+					DebugLogB("Default AID name: %s\n", keyValue);
+#endif
+					rv = stringToBytes(keyValue, tokenInfo->tokenApp,
+						&tokenInfo->tokenAppLen);
+					if (rv != 0)
+					{
+						DebugLogA
+							("Match found, failed due to malformed aid string.\n");
+#ifndef WIN32
+						closedir(hpDir);
+#endif
+						return -1;
+					}
+
+				} else
+				{
+					DebugLogA("No AID specified in bundle\n");
+					tokenInfo->tokenAppLen = 0;
+				}
+
+#ifndef WIN32
+				closedir(hpDir);
+#endif
+				return 0;
+
+			}	/* do ... while */
+		}	/* if .bundle */
+	}	/* while readdir */
+#ifdef WIN32
+	// This is part of a Do..While loop (see above)
+	while (FindNextFile(hFind, &findData) != 0);
+#endif
+
+#ifndef WIN32
+	closedir(hpDir);
+#endif
+	return -1;
+}
+
+const char *TPSvcDropdir(void)
+{
+	const char *dropDir = getenv(MSC_SVC_DROPDIR_ENV);
+	if (dropDir)
+		return dropDir;
+
+	return MSC_SVC_DROPDIR_DEFAULT;
+}
+
+MSCLong32 TPLoadToken(MSCLPTokenConnection pConnection)
+{
+
+	MSCLong32 rv;
+
+	pConnection->libPointers.pvfWriteFramework = 0;
+	pConnection->libPointers.pvfInitializePlugin = 0;
+	pConnection->libPointers.pvfFinalizePlugin = 0;
+	pConnection->libPointers.pvfGetStatus = 0;
+	pConnection->libPointers.pvfGetCapabilities = 0;
+	pConnection->libPointers.pvfExtendedFeature = 0;
+	pConnection->libPointers.pvfGenerateKeys = 0;
+	pConnection->libPointers.pvfImportKey = 0;
+	pConnection->libPointers.pvfExportKey = 0;
+	pConnection->libPointers.pvfComputeCrypt = 0;
+	pConnection->libPointers.pvfExtAuthenticate = 0;
+	pConnection->libPointers.pvfListKeys = 0;
+	pConnection->libPointers.pvfCreatePIN = 0;
+	pConnection->libPointers.pvfVerifyPIN = 0;
+	pConnection->libPointers.pvfChangePIN = 0;
+	pConnection->libPointers.pvfUnblockPIN = 0;
+	pConnection->libPointers.pvfListPINs = 0;
+	pConnection->libPointers.pvfCreateObject = 0;
+	pConnection->libPointers.pvfDeleteObject = 0;
+	pConnection->libPointers.pvfWriteObject = 0;
+	pConnection->libPointers.pvfReadObject = 0;
+	pConnection->libPointers.pvfListObjects = 0;
+	pConnection->libPointers.pvfLogoutAll = 0;
+	pConnection->libPointers.pvfGetChallenge = 0;
+
+	/*
+	 * Find the Card's Library 
+	 */
+
+	rv = TPSearchBundlesForAtr(pConnection->tokenInfo.tokenId,
+		pConnection->tokenInfo.tokenIdLength, &pConnection->tokenInfo);
+
+	if (rv != 0)
+	{
+		DebugLogA("Error: Matching Token ATR Not Found.\n");
+		log_xxd(PCSC_LOG_INFO, "ATR  : ", pConnection->tokenInfo.tokenId,
+			pConnection->tokenInfo.tokenIdLength);
+
+		return SCARD_E_CARD_UNSUPPORTED;
+	}
+
+	/*
+	 * Load that library and store the handle in the SCARDCHANNEL
+	 * structure 
+	 */
+
+	rv = DYN_LoadLibrary(&pConnection->tokenLibHandle,
+		pConnection->tokenInfo.svProvider);
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		DebugLogA("Error: Could not load service library\n");
+		DebugLogB("->> %s\n", pConnection->tokenInfo.svProvider);
+		return SCARD_E_INVALID_TARGET;
+	} else
+	{
+		DebugLogB("Loading service library %s\n",
+			pConnection->tokenInfo.svProvider);
+	}
+
+	rv = TPBindFunctions(pConnection);
+
+	return rv;
+}
+
+MSCLong32 TPUnloadToken(MSCLPTokenConnection pConnection)
+{
+
+	MSCLong32 rv;
+
+	if (pConnection->tokenLibHandle == 0)
+	{
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	rv = DYN_CloseLibrary(&pConnection->tokenLibHandle);
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		return rv;
+	}
+
+	pConnection->tokenLibHandle = 0;
+	return TPUnbindFunctions(pConnection);
+}
+
+MSCLong32 TPBindFunctions(MSCLPTokenConnection pConnection)
+{
+
+	MSCLong32 rv;
+
+	if (pConnection->tokenLibHandle == 0)
+	{
+		return SCARD_E_INVALID_TARGET;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfWriteFramework,
+		"PL_MSCWriteFramework");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfWriteFramework = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		/*
+		 * No big deal - this feature is just not supported 
+		 */
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfIdentifyToken, "PL_MSCIdentifyToken");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfIdentifyToken = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfInitializePlugin,
+		"PL_MSCInitializePlugin");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfInitializePlugin = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfFinalizePlugin,
+		"PL_MSCFinalizePlugin");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfFinalizePlugin = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfGetStatus, "PL_MSCGetStatus");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfGetStatus = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfGetCapabilities,
+		"PL_MSCGetCapabilities");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfGetCapabilities = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfExtendedFeature,
+		"PL_MSCExtendedFeature");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfExtendedFeature = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		/*
+		 * No big deal - there are no extended features 
+		 */
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfGenerateKeys, "PL_MSCGenerateKeys");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfGenerateKeys = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfImportKey, "PL_MSCImportKey");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfImportKey = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfExportKey, "PL_MSCExportKey");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfExportKey = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfComputeCrypt, "PL_MSCComputeCrypt");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfComputeCrypt = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfExtAuthenticate,
+		"PL_MSCExtAuthenticate");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfExtAuthenticate = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfListKeys, "PL_MSCListKeys");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfListKeys = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfCreatePIN, "PL_MSCCreatePIN");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfCreatePIN = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfVerifyPIN, "PL_MSCVerifyPIN");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfVerifyPIN = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfChangePIN, "PL_MSCChangePIN");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfChangePIN = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfUnblockPIN, "PL_MSCUnblockPIN");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfUnblockPIN = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfListPINs, "PL_MSCListPINs");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfListPINs = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfCreateObject, "PL_MSCCreateObject");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfCreateObject = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfDeleteObject, "PL_MSCDeleteObject");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfDeleteObject = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfWriteObject, "PL_MSCWriteObject");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfWriteObject = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfReadObject, "PL_MSCReadObject");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfReadObject = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfListObjects, "PL_MSCListObjects");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfListObjects = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfLogoutAll, "PL_MSCLogoutAll");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfLogoutAll = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	rv = DYN_GetAddress(pConnection->tokenLibHandle,
+		&pConnection->libPointers.pvfGetChallenge, "PL_MSCGetChallenge");
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		pConnection->libPointers.pvfGetChallenge = 0;
+		DebugLogA("TPBindFunctions: Missing functions");
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+MSCLong32 TPUnbindFunctions(MSCLPTokenConnection pConnection)
+{
+
+	pConnection->libPointers.pvfWriteFramework = 0;
+	pConnection->libPointers.pvfInitializePlugin = 0;
+	pConnection->libPointers.pvfFinalizePlugin = 0;
+	pConnection->libPointers.pvfGetStatus = 0;
+	pConnection->libPointers.pvfGetCapabilities = 0;
+	pConnection->libPointers.pvfExtendedFeature = 0;
+	pConnection->libPointers.pvfGenerateKeys = 0;
+	pConnection->libPointers.pvfImportKey = 0;
+	pConnection->libPointers.pvfExportKey = 0;
+	pConnection->libPointers.pvfComputeCrypt = 0;
+	pConnection->libPointers.pvfExtAuthenticate = 0;
+	pConnection->libPointers.pvfListKeys = 0;
+	pConnection->libPointers.pvfCreatePIN = 0;
+	pConnection->libPointers.pvfVerifyPIN = 0;
+	pConnection->libPointers.pvfChangePIN = 0;
+	pConnection->libPointers.pvfUnblockPIN = 0;
+	pConnection->libPointers.pvfListPINs = 0;
+	pConnection->libPointers.pvfCreateObject = 0;
+	pConnection->libPointers.pvfDeleteObject = 0;
+	pConnection->libPointers.pvfWriteObject = 0;
+	pConnection->libPointers.pvfReadObject = 0;
+	pConnection->libPointers.pvfListObjects = 0;
+	pConnection->libPointers.pvfLogoutAll = 0;
+	pConnection->libPointers.pvfGetChallenge = 0;
+
+	return SCARD_S_SUCCESS;
+}

Added: trunk/SmartCardServices/src/PCSC/tokenfactory.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/tokenfactory.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/tokenfactory.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : tokenfactory.h
+	    Package: pcsc-lite
+            Author : David Corcoran
+            Date   : 01/01/00
+            Purpose: This handles card abstraction attachment. 
+	            
+********************************************************************/
+
+#ifndef __cardfactory_h__
+#define __cardfactory_h__
+
+#include "mscdefines.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef WIN32
+#ifndef MSC_SVC_DROPDIR
+#define MSC_SVC_DROPDIR                     TPSvcDropdir()
+#define MSC_SVC_DROPDIR_DEFAULT             "/usr/libexec/SmartCardServices/services/"
+#define MSC_SVC_DROPDIR_ENV                 "MSC_SVC_DROPDIR"
+#endif
+#else
+#define MSC_SVC_DROPDIR                     "C:\\Program Files\\Muscle\\Services\\"
+#endif
+
+	const char *TPSvcDropdir(void);
+	MSCLong32 TPLoadToken(MSCLPTokenConnection);
+	MSCLong32 TPUnloadToken(MSCLPTokenConnection);
+	MSCLong32 TPBindFunctions(MSCLPTokenConnection);
+	MSCLong32 TPUnbindFunctions(MSCLPTokenConnection);
+	MSCLong32 TPSearchBundlesForAtr(MSCPUChar8 Atr, MSCULong32 Length,
+		MSCLPTokenInfo tokenInfo);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __cardfactory_h__ */

Added: trunk/SmartCardServices/src/PCSC/tokenparser.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/tokenparser.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/tokenparser.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1775 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+#ifdef WIN32
+#include <malloc.h>
+#include <stdlib.h>
+#endif
+
+#define yy_create_buffer tp_create_buffer
+#define yy_delete_buffer tp_delete_buffer
+#define yy_scan_buffer tp_scan_buffer
+#define yy_scan_string tp_scan_string
+#define yy_scan_bytes tp_scan_bytes
+#define yy_flex_debug tp_flex_debug
+#define yy_init_buffer tp_init_buffer
+#define yy_flush_buffer tp_flush_buffer
+#define yy_load_buffer_state tp_load_buffer_state
+#define yy_switch_to_buffer tp_switch_to_buffer
+#define yyin tpin
+#define yyleng tpleng
+#define yylex tplex
+#define yyout tpout
+#define yyrestart tprestart
+#define yytext tptext
+#define yywrap tpwrap
+
+/*
+ * A lexical scanner generated by flex 
+ */
+
+/*
+ * Scanner skeleton version: $Header:
+ * /home/cvsroot/muscle/PCSC/src/tokenparser.c,v 1.2 2002/03/30 20:59:07
+ * corcoran Exp $ 
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+/*
+ * cfront 1.2 defines "c_plusplus" instead of "__cplusplus" 
+ */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * Use prototypes in function declarations. 
+ */
+#define YY_USE_PROTOS
+
+/*
+ * The "const" storage-class-modifier is valid. 
+ */
+#define YY_USE_CONST
+
+#else							/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif							/* __STDC__ */
+#endif							/* ! __cplusplus */
+
+#ifdef __TURBOC__
+#pragma warn -rch
+#pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/*
+ * Returned upon end-of-file. 
+ */
+#define YY_NULL 0
+
+/*
+ * Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative, we
+ * want to instead treat it as an 8-bit unsigned char, hence the double
+ * cast. 
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/*
+ * Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN. 
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/*
+ * Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility. 
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/*
+ * Action number for EOF rule of a given start state. 
+ */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/*
+ * Special action meaning "start processing a new file". 
+ */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/*
+ * Size of default input buffer. 
+ */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/*
+ * The funky do-while in the following #define is used to turn the
+ * definition int a single C statement (which needs a semi-colon
+ * terminator).  This avoids problems with code like: if (
+ * condition_holds ) yyless( 5 ); else do_something_else(); Prior to
+ * using the do-while the compiler would get upset at the "else" because
+ * it interpreted the "if" statement as being all done when it reached the 
+ * ';' after the yyless() call. 
+ */
+
+/*
+ * Return all but the first 'n' matched characters back to the input
+ * stream. 
+ */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/*
+ * The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own). 
+ */
+typedef unsigned int yy_size_t;
+
+struct yy_buffer_state
+{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;			/* input buffer */
+	char *yy_buf_pos;			/* current position in input buffer */
+
+	/*
+	 * Size of input buffer in bytes, not including room for EOB
+	 * characters. 
+	 */
+	yy_size_t yy_buf_size;
+
+	/*
+	 * Number of characters read into yy_ch_buf, not including EOB
+	 * characters. 
+	 */
+	int yy_n_chars;
+
+	/*
+	 * Whether we "own" the buffer - i.e., we know we created it, and can
+	 * realloc() it to grow it, and should free() it to delete it. 
+	 */
+	int yy_is_our_buffer;
+
+	/*
+	 * Whether this is an "interactive" input source; if so, and if we're
+	 * using stdio for input, then we want to use getc() instead of
+	 * fread(), to make sure we stop fetching input after each newline. 
+	 */
+	int yy_is_interactive;
+
+	/*
+	 * Whether we're considered to be at the beginning of a line. If so,
+	 * '^' rules will be active on the next match, otherwise not. 
+	 */
+	int yy_at_bol;
+
+	/*
+	 * Whether to try to fill the input buffer when we reach the end of
+	 * it. 
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/*
+	 * When an EOF's been seen but there's still some text to process then 
+	 * we mark the buffer as YY_EOF_PENDING, to indicate that we shouldn't 
+	 * try reading from the input source any more.  We might still have a
+	 * bunch of tokens to match, though, because of possible backing-up.
+	 * When we actually see the EOF, we change the status to "new" (via
+	 * yyrestart()), so that the user can continue scanning by just
+	 * pointing yyin at a new input file. 
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/*
+ * We provide macros for accessing buffer states in case in the future we
+ * want to put the buffer states in a more general "scanner state". 
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+/*
+ * yy_hold_char holds the character lost when yytext is formed. 
+ */
+static char yy_hold_char;
+
+static int yy_n_chars;			/* number of characters read into
+								 * yy_ch_buf */
+
+int yyleng;
+
+/*
+ * Points to current character in buffer. 
+ */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;			/* whether we need to initialize */
+static int yy_start = 0;		/* start state number */
+
+/*
+ * Flag which is used to allow yywrap()'s to do buffer switches instead of 
+ * setting up a fresh yyin.  A bit of a hack ... 
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO((FILE * input_file));
+
+void yy_switch_to_buffer YY_PROTO((YY_BUFFER_STATE new_buffer));
+void yy_load_buffer_state YY_PROTO((void));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO((FILE * file, int size));
+void yy_delete_buffer YY_PROTO((YY_BUFFER_STATE b));
+void yy_init_buffer YY_PROTO((YY_BUFFER_STATE b, FILE * file));
+void yy_flush_buffer YY_PROTO((YY_BUFFER_STATE b));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO((char *base, yy_size_t size));
+YY_BUFFER_STATE yy_scan_string YY_PROTO((yyconst char *yy_str));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO((yyconst char *bytes, int len));
+
+static void *yy_flex_alloc YY_PROTO((yy_size_t));
+static void *yy_flex_realloc YY_PROTO((void *, yy_size_t));
+static void yy_flex_free YY_PROTO((void *));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO((void));
+static yy_state_type yy_try_NUL_trans YY_PROTO((yy_state_type
+		current_state));
+static int yy_get_next_buffer YY_PROTO((void));
+static void yy_fatal_error YY_PROTO((yyconst char msg[]));
+
+/*
+ * Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext. 
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 7
+#define YY_END_OF_BUFFER 8
+static yyconst short int yy_accept[39] = { 0,
+	0, 0, 8, 6, 4, 2, 1, 6, 1, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+	0, 0, 0, 0, 0, 0, 5, 0
+};
+
+static yyconst int yy_ec[256] = { 0,
+	1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 2, 4, 4, 5, 4, 4, 4, 4, 4,
+	4, 4, 4, 4, 4, 4, 6, 7, 7, 7,
+	7, 7, 7, 7, 7, 7, 7, 4, 1, 8,
+	4, 9, 4, 4, 10, 10, 10, 10, 10, 10,
+	10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	1, 1, 1, 4, 4, 1, 11, 11, 11, 11,
+
+	12, 11, 13, 11, 14, 11, 15, 11, 11, 16,
+	11, 11, 11, 17, 18, 19, 11, 11, 11, 11,
+	20, 11, 1, 1, 1, 4, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1
+};
+
+static yyconst int yy_meta[21] = { 0,
+	1, 2, 3, 4, 4, 4, 2, 1, 1, 2,
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+static yyconst short int yy_base[43] = { 0,
+	0, 7, 49, 50, 50, 50, 0, 1, 0, 36,
+	28, 26, 28, 35, 29, 0, 26, 33, 27, 33,
+	29, 22, 0, 24, 27, 14, 27, 23, 13, 50,
+	10, 9, 4, 1, 0, 2, 50, 50, 19, 23,
+	2, 26
+};
+
+static yyconst short int yy_def[43] = { 0,
+	39, 39, 38, 38, 38, 38, 40, 38, 40, 38,
+	38, 38, 38, 38, 38, 41, 38, 41, 38, 38,
+	38, 38, 42, 38, 42, 38, 38, 38, 38, 38,
+	38, 38, 38, 38, 38, 38, 38, 0, 38, 38,
+	38, 38
+};
+
+static yyconst short int yy_nxt[71] = { 0,
+	38, 5, 6, 18, 7, 38, 38, 8, 5, 6,
+	37, 7, 36, 38, 8, 10, 35, 34, 11, 4,
+	4, 4, 4, 9, 9, 33, 9, 25, 32, 25,
+	31, 30, 29, 28, 27, 26, 24, 23, 22, 21,
+	20, 19, 17, 16, 15, 14, 13, 12, 38, 3,
+	38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+	38, 38, 38, 38, 38, 38, 38, 38, 38, 38
+};
+
+static yyconst short int yy_chk[71] = { 0,
+	0, 1, 1, 41, 1, 0, 0, 1, 2, 2,
+	36, 2, 35, 0, 2, 8, 34, 33, 8, 39,
+	39, 39, 39, 40, 40, 32, 40, 42, 31, 42,
+	29, 28, 27, 26, 25, 24, 22, 21, 20, 19,
+	18, 17, 15, 14, 13, 12, 11, 10, 3, 38,
+	38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+	38, 38, 38, 38, 38, 38, 38, 38, 38, 38
+};
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/*
+ * The intent behind this definition is that it'll catch any uses of
+ * REJECT which flex missed. 
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "tokenparser.l"
+#define INITIAL 0
+/*****************************************************************
+
+  File   :   configfile.ll
+  Author :   David Corcoran
+  Date   :   February 12, 1999 modified 7/28/99
+  Purpose:   Reads lexical config files and updates database.
+             See http://www.linuxnet.com for more information.
+  License:   Copyright (C) 1999 David Corcoran
+             <corcoran at linuxnet.com>
+
+******************************************************************/
+#line 14 "tokenparser.l"
+
+void tpevalToken(char *pcToken, int tokType);
+
+static char *pcDesiredKey = 0;
+static char pcKey[200];
+static char pcValue[200];
+static char pcFinValue[200];
+static int valueIndex = 0;
+static int desiredIndex = 0;
+
+void tperrorCheck(char *pcToken_error);
+
+#line 429 "lex.tp.c"
+
+/*
+ * Macros after this point can all be overridden by user definitions in
+ * section 1. 
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO((void));
+#else
+extern int yywrap YY_PROTO((void));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO((int c, char *buf_ptr));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO((char *, yyconst char *, int));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO((yyconst char *));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO((void));
+#else
+static int input YY_PROTO((void));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO((int new_state));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO((void));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO((void));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/*
+ * Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int). 
+ */
+#endif
+#endif
+
+/*
+ * Amount of stuff to slurp up with each read. 
+ */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/*
+ * Copy whatever the last rule matched to the standard output. 
+ */
+
+#ifndef ECHO
+/*
+ * This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite(). 
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/*
+ * Gets input and stuffs it into "buf".  number of characters read, or
+ * YY_NULL, is returned in "result". 
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/*
+ * No semi-colon after return; correct usage is to write "yyterminate();"
+ * - we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements. 
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/*
+ * Number of entries by which start-condition stack grows. 
+ */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/*
+ * Report a fatal error. 
+ */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/*
+ * Default declaration of generated scanner - a define so the user can
+ * easily add parameters. 
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/*
+ * Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up. 
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/*
+ * Code executed at the end of each rule. 
+ */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 28 "tokenparser.l"
+
+#line 583 "lex.tp.c"
+
+	if (yy_init)
+	{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if (!yy_start)
+			yy_start = 1;	/* first start state */
+
+		if (!yyin)
+			yyin = stdin;
+
+		if (!yyout)
+			yyout = stdout;
+
+		if (!yy_current_buffer)
+			yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
+
+		yy_load_buffer_state();
+	}
+
+	while (1)	/* loops until end-of-file is reached */
+	{
+		yy_cp = yy_c_buf_p;
+
+		/*
+		 * Support of yytext. 
+		 */
+		*yy_cp = yy_hold_char;
+
+		/*
+		 * yy_bp points to the position in yy_ch_buf of the start of the
+		 * current run. 
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+	  yy_match:
+		do
+		{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if (yy_accept[yy_current_state])
+			{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+			}
+			while (yy_chk[yy_base[yy_current_state] + yy_c] !=
+				yy_current_state)
+			{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if (yy_current_state >= 39)
+					yy_c = yy_meta[(unsigned int) yy_c];
+			}
+			yy_current_state =
+				yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+		}
+		while (yy_base[yy_current_state] != 50);
+
+	  yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if (yy_act == 0)
+		{	/* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+		}
+
+		YY_DO_BEFORE_ACTION;
+
+	  do_action:	/* This label is used only to access EOF actions. */
+
+		switch (yy_act)
+		{	/* beginning of action switch */
+		case 0:	/* must back up */
+			/*
+			 * undo the effects of YY_DO_BEFORE_ACTION 
+			 */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+		case 1:
+			YY_RULE_SETUP
+#line 30 "tokenparser.l"
+			{
+			}
+		YY_BREAK case 2:
+			YY_RULE_SETUP
+#line 31 "tokenparser.l"
+			{
+			}
+		YY_BREAK case 3:
+			YY_RULE_SETUP
+#line 32 "tokenparser.l"
+			{
+				valueIndex = 0;
+				tpevalToken(yytext, 1);
+			}
+		YY_BREAK case 4:
+			YY_RULE_SETUP
+#line 33 "tokenparser.l"
+			{
+			}
+		YY_BREAK case 5:
+			YY_RULE_SETUP
+#line 34 "tokenparser.l"
+			{
+				tpevalToken(yytext, 2);
+				valueIndex += 1;
+			}
+		YY_BREAK case 6:
+			YY_RULE_SETUP
+#line 35 "tokenparser.l"
+			{
+				tperrorCheck(yytext);
+			}
+		YY_BREAK case 7:
+			YY_RULE_SETUP
+#line 36 "tokenparser.l"
+				ECHO;
+			YY_BREAK
+#line 701 "lex.tp.c"
+		case YY_STATE_EOF(INITIAL):
+			yyterminate();
+
+		case YY_END_OF_BUFFER:
+			{
+				/*
+				 * Amount of text matched not including the EOB char. 
+				 */
+				int yy_amount_of_matched_text =
+					(int) (yy_cp - yytext_ptr) - 1;
+
+				/*
+				 * Undo the effects of YY_DO_BEFORE_ACTION. 
+				 */
+				*yy_cp = yy_hold_char;
+				YY_RESTORE_YY_MORE_OFFSET
+					if (yy_current_buffer->yy_buffer_status ==
+					YY_BUFFER_NEW)
+				{
+					/*
+					 * We're scanning a new file or input source.  It's
+					 * possible that this happened because the user just
+					 * pointed yyin at a new source and called yylex().
+					 * If so, then we have to assure consistency between
+					 * yy_current_buffer and our globals.  Here is the
+					 * right place to do so, because this is the first
+					 * action (other than possibly a back-up) that will
+					 * match for the new input source. 
+					 */
+					yy_n_chars = yy_current_buffer->yy_n_chars;
+					yy_current_buffer->yy_input_file = yyin;
+					yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+				}
+
+				/*
+				 * Note that here we test for yy_c_buf_p "<=" to the
+				 * position of the first EOB in the buffer, since
+				 * yy_c_buf_p will already have been incremented past the
+				 * NUL character (since all states make transitions on EOB 
+				 * to the end-of-buffer state).  Contrast this with the
+				 * test in input(). 
+				 */
+				if (yy_c_buf_p <=
+					&yy_current_buffer->yy_ch_buf[yy_n_chars])
+				{	/* This was really a NUL. */
+					yy_state_type yy_next_state;
+
+					yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+					yy_current_state = yy_get_previous_state();
+
+					/*
+					 * Okay, we're now positioned to make the NUL
+					 * transition.  We couldn't have
+					 * yy_get_previous_state() go ahead and do it for us
+					 * because it doesn't know how to deal with the
+					 * possibility of jamming (and we don't want to build
+					 * jamming into it because then it will run more
+					 * slowly). 
+					 */
+
+					yy_next_state = yy_try_NUL_trans(yy_current_state);
+
+					yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+					if (yy_next_state)
+					{
+						/*
+						 * Consume the NUL. 
+						 */
+						yy_cp = ++yy_c_buf_p;
+						yy_current_state = yy_next_state;
+						goto yy_match;
+					}
+
+					else
+					{
+						yy_cp = yy_c_buf_p;
+						goto yy_find_action;
+					}
+				}
+
+				else
+					switch (yy_get_next_buffer())
+					{
+					case EOB_ACT_END_OF_FILE:
+						{
+							yy_did_buffer_switch_on_eof = 0;
+
+							if (yywrap())
+							{
+								/*
+								 * Note: because we've taken care in
+								 * yy_get_next_buffer() to have set up
+								 * yytext, we can now set up yy_c_buf_p so 
+								 * that if some total hoser (like flex
+								 * itself) wants to call the scanner after 
+								 * we return the YY_NULL, it'll still work 
+								 * - another YY_NULL will get returned. 
+								 */
+								yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+								yy_act = YY_STATE_EOF(YY_START);
+								goto do_action;
+							}
+
+							else
+							{
+								if (!yy_did_buffer_switch_on_eof)
+									YY_NEW_FILE;
+							}
+							break;
+						}
+
+					case EOB_ACT_CONTINUE_SCAN:
+						yy_c_buf_p =
+							yytext_ptr + yy_amount_of_matched_text;
+
+						yy_current_state = yy_get_previous_state();
+
+						yy_cp = yy_c_buf_p;
+						yy_bp = yytext_ptr + YY_MORE_ADJ;
+						goto yy_match;
+
+					case EOB_ACT_LAST_MATCH:
+						yy_c_buf_p =
+							&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+						yy_current_state = yy_get_previous_state();
+
+						yy_cp = yy_c_buf_p;
+						yy_bp = yytext_ptr + YY_MORE_ADJ;
+						goto yy_find_action;
+					}
+				break;
+			}
+
+		default:
+			YY_FATAL_ERROR
+				("fatal flex scanner internal error--no action found");
+		}	/* end of action switch */
+	}	/* end of scanning one token */
+}	/* end of yylex */
+
+/*
+ * yy_get_next_buffer - try to read in a new buffer Returns a code
+ * representing an action: EOB_ACT_LAST_MATCH - EOB_ACT_CONTINUE_SCAN -
+ * continue scanning from current position EOB_ACT_END_OF_FILE - end of
+ * file 
+ */
+
+static int yy_get_next_buffer()
+{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
+		YY_FATAL_ERROR
+			("fatal flex scanner internal error--end of buffer missed");
+
+	if (yy_current_buffer->yy_fill_buffer == 0)
+	{	/* Don't try to fill the buffer, so this is an EOF. */
+		if (yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1)
+		{
+			/*
+			 * We matched a single character, the EOB, so treat this as a
+			 * final EOF. 
+			 */
+			return EOB_ACT_END_OF_FILE;
+		}
+
+		else
+		{
+			/*
+			 * We matched some text prior to the EOB, first process it. 
+			 */
+			return EOB_ACT_LAST_MATCH;
+		}
+	}
+
+	/*
+	 * Try to read more data. 
+	 */
+
+	/*
+	 * First move last chars to start of buffer. 
+	 */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for (i = 0; i < number_to_move; ++i)
+		*(dest++) = *(source++);
+
+	if (yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING)
+		/*
+		 * don't do the read, it's not guaranteed to return an EOF, just
+		 * force an EOF 
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+	{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while (num_to_read <= 0)
+		{	/* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR
+				("input buffer overflow, can't enlarge buffer because scanner uses REJECT");
+#else
+
+			/*
+			 * just a shorter name for the current buffer 
+			 */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset = (int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if (b->yy_is_our_buffer)
+			{
+				int new_size = b->yy_buf_size * 2;
+
+				if (new_size <= 0)
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/*
+					 * Include room in for 2 EOB chars. 
+					 */
+					yy_flex_realloc((void *) b->yy_ch_buf,
+					b->yy_buf_size + 2);
+			} else
+				/*
+				 * Can't grow it, we don't own it. 
+				 */
+				b->yy_ch_buf = 0;
+
+			if (!b->yy_ch_buf)
+				YY_FATAL_ERROR
+					("fatal error - scanner input buffer overflow");
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+				number_to_move - 1;
+#endif
+		}
+
+		if (num_to_read > YY_READ_BUF_SIZE)
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/*
+		 * Read in more data. 
+		 */
+		YY_INPUT((&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read);
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+	}
+
+	if (yy_n_chars == 0)
+	{
+		if (number_to_move == YY_MORE_ADJ)
+		{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart(yyin);
+		}
+
+		else
+		{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_EOF_PENDING;
+		}
+	}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/*
+ * yy_get_previous_state - get the state just before the EOB char was
+ * reached 
+ */
+
+static yy_state_type yy_get_previous_state()
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp)
+	{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if (yy_accept[yy_current_state])
+		{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+		}
+		while (yy_chk[yy_base[yy_current_state] + yy_c] !=
+			yy_current_state)
+		{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if (yy_current_state >= 39)
+				yy_c = yy_meta[(unsigned int) yy_c];
+		}
+		yy_current_state =
+			yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	}
+
+	return yy_current_state;
+}
+
+/*
+ * yy_try_NUL_trans - try to make a transition on the NUL character
+ * synopsis next_state = yy_try_NUL_trans( current_state ); 
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state)
+#else
+static yy_state_type yy_try_NUL_trans(yy_current_state)
+	yy_state_type yy_current_state;
+#endif
+{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if (yy_accept[yy_current_state])
+	{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+	}
+	while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state)
+	{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if (yy_current_state >= 39)
+			yy_c = yy_meta[(unsigned int) yy_c];
+	}
+	yy_current_state =
+		yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 38);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput(int c, register char *yy_bp)
+#else
+static void yyunput(c, yy_bp)
+	int c;
+	register char *yy_bp;
+#endif
+{
+	register char *yy_cp = yy_c_buf_p;
+
+	/*
+	 * undo effects of setting up yytext 
+	 */
+	*yy_cp = yy_hold_char;
+
+	if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
+	{	/* need to shift things up to make room */
+		/*
+		 * +2 for EOB chars. 
+		 */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest =
+			&yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size +
+			2];
+		register char *source =
+			&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while (source > yy_current_buffer->yy_ch_buf)
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
+			YY_FATAL_ERROR("flex scanner push-back overflow");
+	}
+
+	*--yy_cp = (char) c;
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+}
+#endif							/* ifndef YY_NO_UNPUT */
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if (*yy_c_buf_p == YY_END_OF_BUFFER_CHAR)
+	{
+		/*
+		 * yy_c_buf_p now points to the character we want to return. If
+		 * this occurs *before* the EOB characters, then it's a valid NUL; 
+		 * if not, then we've hit the end of the buffer. 
+		 */
+		if (yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars])
+			/*
+			 * This was really a NUL. 
+			 */
+			*yy_c_buf_p = '\0';
+
+		else
+		{	/* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch (yy_get_next_buffer())
+			{
+			case EOB_ACT_LAST_MATCH:
+				/*
+				 * This happens because yy_g_n_b() sees that we've
+				 * accumulated a token and flags that we need to try
+				 * matching the token before proceeding.  But for input(),
+				 * there's no matching to consider. So convert the
+				 * EOB_ACT_LAST_MATCH to EOB_ACT_END_OF_FILE. 
+				 */
+
+				/*
+				 * Reset buffer status. 
+				 */
+				yyrestart(yyin);
+
+				/*
+				 * fall through 
+				 */
+
+			case EOB_ACT_END_OF_FILE:
+				{
+					if (yywrap())
+						return EOF;
+
+					if (!yy_did_buffer_switch_on_eof)
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p = yytext_ptr + offset;
+				break;
+			}
+		}
+	}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+	return c;
+}
+
+#ifdef YY_USE_PROTOS
+void yyrestart(FILE * input_file)
+#else
+void yyrestart(input_file)
+	FILE *input_file;
+#endif
+{
+	if (!yy_current_buffer)
+		yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
+
+	yy_init_buffer(yy_current_buffer, input_file);
+	yy_load_buffer_state();
+}
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer)
+#else
+void yy_switch_to_buffer(new_buffer)
+	YY_BUFFER_STATE new_buffer;
+#endif
+{
+	if (yy_current_buffer == new_buffer)
+		return;
+
+	if (yy_current_buffer)
+	{
+		/*
+		 * Flush out information for old buffer. 
+		 */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+	}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/*
+	 * We don't actually know whether we did this switch during EOF
+	 * (yywrap()) processing, but the only time this flag is looked at is
+	 * after yywrap() is called, so it's safe to go ahead and always set
+	 * it. 
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+}
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state(void)
+#else
+void yy_load_buffer_state()
+#endif
+{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+}
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer(FILE * file, int size)
+#else
+YY_BUFFER_STATE yy_create_buffer(file, size)
+	FILE *file;
+	int size;
+#endif
+{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc(sizeof(struct yy_buffer_state));
+	if (!b)
+		YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
+
+	b->yy_buf_size = size;
+
+	/*
+	 * yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters. 
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc(b->yy_buf_size + 2);
+	if (!b->yy_ch_buf)
+		YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer(b, file);
+
+	return b;
+}
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer(YY_BUFFER_STATE b)
+#else
+void yy_delete_buffer(b)
+	YY_BUFFER_STATE b;
+#endif
+{
+	if (!b)
+		return;
+
+	if (b == yy_current_buffer)
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if (b->yy_is_our_buffer)
+		yy_flex_free((void *) b->yy_ch_buf);
+
+	yy_flex_free((void *) b);
+}
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO((int));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer(YY_BUFFER_STATE b, FILE * file)
+#else
+void yy_init_buffer(b, file)
+	YY_BUFFER_STATE b;
+	FILE *file;
+#endif
+
+{
+	yy_flush_buffer(b);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty(fileno(file)) > 0) : 0;
+#endif
+#endif
+}
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer(YY_BUFFER_STATE b)
+#else
+void yy_flush_buffer(b)
+	YY_BUFFER_STATE b;
+#endif
+
+{
+	if (!b)
+		return;
+
+	b->yy_n_chars = 0;
+
+	/*
+	 * We always need two end-of-buffer characters.  The first causes a
+	 * transition to the end-of-buffer state.  The second causes a jam in
+	 * that state. 
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if (b == yy_current_buffer)
+		yy_load_buffer_state();
+}
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size)
+#else
+YY_BUFFER_STATE yy_scan_buffer(base, size)
+	char *base;
+	yy_size_t size;
+#endif
+{
+	YY_BUFFER_STATE b;
+
+	if (size < 2 ||
+		base[size - 2] != YY_END_OF_BUFFER_CHAR ||
+		base[size - 1] != YY_END_OF_BUFFER_CHAR)
+		/*
+		 * They forgot to leave room for the EOB's. 
+		 */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc(sizeof(struct yy_buffer_state));
+	if (!b)
+		YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()");
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer(b);
+
+	return b;
+}
+#endif
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string(yyconst char *yy_str)
+#else
+YY_BUFFER_STATE yy_scan_string(yy_str)
+	yyconst char *yy_str;
+#endif
+{
+	int len;
+	for (len = 0; yy_str[len]; ++len)
+		;
+
+	return yy_scan_bytes(yy_str, len);
+}
+#endif
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes(yyconst char *bytes, int len)
+#else
+YY_BUFFER_STATE yy_scan_bytes(bytes, len)
+	yyconst char *bytes;
+	int len;
+#endif
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/*
+	 * Get memory for full buffer, including space for trailing EOB's. 
+	 */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc(n);
+	if (!buf)
+		YY_FATAL_ERROR("out of dynamic memory in yy_scan_bytes()");
+
+	for (i = 0; i < len; ++i)
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len + 1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer(buf, n);
+	if (!b)
+		YY_FATAL_ERROR("bad buffer in yy_scan_bytes()");
+
+	/*
+	 * It's okay to grow etc. this buffer, and we should throw it away
+	 * when we're done. 
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+#endif
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state(int new_state)
+#else
+static void yy_push_state(new_state)
+	int new_state;
+#endif
+{
+	if (yy_start_stack_ptr >= yy_start_stack_depth)
+	{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof(int);
+
+		if (!yy_start_stack)
+			yy_start_stack = (int *) yy_flex_alloc(new_size);
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+				(void *) yy_start_stack, new_size);
+
+		if (!yy_start_stack)
+			YY_FATAL_ERROR
+				("out of memory expanding start-condition stack");
+	}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+}
+#endif
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+{
+	if (--yy_start_stack_ptr < 0)
+		YY_FATAL_ERROR("start-condition stack underflow");
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+}
+#endif
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error(yyconst char msg[])
+#else
+static void yy_fatal_error(msg)
+	char msg[];
+#endif
+{
+	(void) fprintf(stderr, "%s\n", msg);
+	exit(YY_EXIT_FAILURE);
+}
+
+/*
+ * Redefine yyless() so it works in section 3 code. 
+ */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+/*
+ * Internal utility routines. 
+ */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy(char *s1, yyconst char *s2, int n)
+#else
+static void yy_flex_strncpy(s1, s2, n)
+	char *s1;
+	yyconst char *s2;
+	int n;
+#endif
+{
+	register int i;
+	for (i = 0; i < n; ++i)
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen(yyconst char *s)
+#else
+static int yy_flex_strlen(s)
+	yyconst char *s;
+#endif
+{
+	register int n;
+	for (n = 0; s[n]; ++n)
+		;
+
+	return n;
+}
+#endif
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc(yy_size_t size)
+#else
+static void *yy_flex_alloc(size)
+	yy_size_t size;
+#endif
+{
+	return (void *) malloc(size);
+}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc(void *ptr, yy_size_t size)
+#else
+static void *yy_flex_realloc(ptr, size)
+	void *ptr;
+	yy_size_t size;
+#endif
+{
+	/*
+	 * The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those that use 
+	 * void* generic pointers.  It works with the latter because both ANSI 
+	 * C and C++ allow castless assignment from any pointer type to void*, 
+	 * and deal with argument conversions as though doing an assignment. 
+	 */
+	return (void *) realloc((char *) ptr, size);
+}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free(void *ptr)
+#else
+static void yy_flex_free(ptr)
+	void *ptr;
+#endif
+{
+	free(ptr);
+}
+
+#if YY_MAIN
+int main()
+{
+	yylex();
+	return 0;
+}
+#endif
+#line 36 "tokenparser.l"
+
+#include <stdio.h>
+#include <string.h>
+#include "debuglog.h"
+
+#ifndef WIN32
+#include "config.h"
+#else
+#include "../win32/win32_config.h"
+#endif
+
+int yywrap()
+{
+	return 1;
+}
+
+void tpevalToken(char *pcToken, int tokType)
+{
+
+	int len;
+	len = 0;
+
+	if (tokType == 1)
+	{
+		for (len = 5; pcToken[len] != '<'; len++) ;
+		strncpy(pcKey, &pcToken[5], len - 5);
+		pcKey[len - 5] = 0;
+	}
+
+	if (tokType == 2)
+	{
+		for (len = 8; pcToken[len] != '<'; len++) ;
+		strncpy(pcValue, &pcToken[8], len - 8);
+		pcValue[len - 8] = 0;
+		if (strcmp(pcKey, pcDesiredKey) == 0)
+		{
+			if (desiredIndex == valueIndex)
+			{
+				strcpy(pcFinValue, pcValue);
+			}
+		}
+	}
+
+}
+
+void tperrorCheck(char *token_error)
+{
+}
+
+int LTPBundleFindValueWithKey(char *fileName, char *tokenKey,
+	char *tokenValue, int tokenIndice)
+{
+
+	FILE *file;
+	file = 0;
+
+	desiredIndex = tokenIndice;
+	pcDesiredKey = tokenKey;
+	pcFinValue[0] = 0;
+
+	file = fopen(fileName, "r");
+
+	if (!file)
+	{
+		DebugLogB("Could not open bundle file : %s\n", fileName);
+		return 1;
+	}
+
+	yyin = file;
+
+	do
+	{
+		yylex();
+	}
+	while (!feof(file));
+
+	if (pcFinValue[0] == 0)
+	{
+		if (tokenIndice == 0)
+		{
+			/*
+			 * Not defined at all 
+			 */
+			DebugLogB("Value/Key not defined for: %s\n", tokenKey);
+		}
+		fclose(file);
+		return -1;
+	} else
+	{
+		strcpy(tokenValue, pcFinValue);
+		fclose(file);
+		return 0;
+	}
+
+	fclose(file);
+	return 0;
+}

Added: trunk/SmartCardServices/src/PCSC/tokenparser.l
===================================================================
--- trunk/SmartCardServices/src/PCSC/tokenparser.l	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/tokenparser.l	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,114 @@
+/*****************************************************************
+
+  File   :   configfile.ll
+  Author :   David Corcoran
+  Date   :   February 12, 1999 modified 7/28/99
+  Purpose:   Reads lexical config files and updates database.
+             See http://www.linuxnet.com for more information.
+  License:   Copyright (C) 1999 David Corcoran
+             <corcoran at linuxnet.com>
+
+******************************************************************/
+
+%{
+
+void tpevalToken( char *pcToken, int tokType );
+
+static char *pcDesiredKey   = 0;
+static char pcKey[200];
+static char pcValue[200];
+static char pcFinValue[200];
+static int valueIndex = 0;
+static int desiredIndex = 0;
+
+void tperrorCheck ( char *pcToken_error );
+
+%}
+
+%%
+
+#.*                                             {}
+"\n"                                            {}
+\<key\>([A-Z]|[a-z]|[0-9]|[ \t])+\<\/key\>      { valueIndex = 0; tpevalToken(yytext, 1); } 
+[ \t]                     		        {}
+\<string\>([A-Z]|[a-z]|[0-9]|[ \t]|[!@#$%^&*()\-+/_\:?.,=~'"])+\<\/string\> {tpevalToken(yytext, 2); valueIndex += 1;} 
+.                                               { tperrorCheck( yytext ); }
+%%
+
+#include <stdio.h>
+#include <string.h>
+#include "debuglog.h"
+#include "config.h"
+
+int yywrap() {
+  return 1;
+}
+
+
+void tpevalToken( char *pcToken, int tokType ) {
+
+  int len;
+  len = 0;
+
+  if ( tokType == 1 ) {
+   for (len=5; pcToken[len] != '<'; len++);
+   strncpy(pcKey, &pcToken[5], len - 5);
+   pcKey[len-5] = 0;
+  }
+
+  if ( tokType == 2 ) {
+   for (len=8; pcToken[len] != '<'; len++);
+   strncpy(pcValue, &pcToken[8], len - 8);
+   pcValue[len-8] = 0;
+    if ( strcmp(pcKey, pcDesiredKey) == 0 ) {
+     if ( desiredIndex == valueIndex ) {
+        strcpy(pcFinValue, pcValue);
+      }
+    }
+  }
+
+
+}
+
+void tperrorCheck ( char *token_error ) { }
+
+int LTPBundleFindValueWithKey(char *fileName, char *tokenKey, 
+                              char *tokenValue, int tokenIndice) {
+
+  FILE *file;
+  file = 0;
+ 
+  desiredIndex  = tokenIndice;
+  pcDesiredKey  = tokenKey;
+  pcFinValue[0] = 0;
+
+  file = fopen(fileName, "r");
+ 
+  if (!file) {
+    DebugLogC( "Could not open bundle file : %s\n", fileName );
+    return 1;
+  }
+ 
+  yyin = file;
+ 
+  do {
+    yylex();
+   } while (!feof(file));
+
+  if ( pcFinValue[0] == 0 ) {
+    if ( tokenIndice == 0 ) {
+      /* Not defined at all */
+      DebugLogC( "Value/Key not defined for: %s\n", tokenKey );
+    }
+    fclose(file);
+    return -1;
+  } else {
+    strcpy(tokenValue, pcFinValue);
+    fclose(file);
+    return 0;
+  }
+ 
+  fclose(file);  
+  return 0;    
+}
+

Added: trunk/SmartCardServices/src/PCSC/utils/bundleTool.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/utils/bundleTool.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/utils/bundleTool.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ 
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	Title  : bundleTool.c
+	Package: MuscleCard Framework
+	Author : David Corcoran
+	Date   : 03/11/01
+	License: Copyright (C) 2002 David Corcoran
+			<corcoran at linuxnet.com>
+	Purpose: This automatically updates the Info.plist
+
+	You may not remove this header from this file
+	without prior permission from the author.
+
+$Id: bundleTool.c,v 1.2 2003/02/13 20:06:36 ghoo Exp $
+ 
+********************************************************************/
+
+#include "wintypes.h"
+#include "winscard.h"
+#include "tokenfactory.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+/*
+ * End of personalization 
+ */
+
+#define CHECK_ERR(cond, msg) { if (cond) { \
+  printf("Error: %s\n", msg); return -1; } }
+
+int main(int argc, char **argv)
+{
+
+	LONG rv;
+	SCARDCONTEXT hContext;
+	SCARD_READERSTATE_A rgReaderStates;
+	DWORD readerListSize;
+	struct stat statBuffer;
+	char spAtrValue[100];
+	char chosenInfoPlist[1024];
+	char *readerList;
+	char *restFile;
+	char atrInsertion[256];
+	FILE *fp;
+	DIR *bundleDir;
+	struct dirent *currBundle;
+	int i, p;
+	int userChoice;
+	int totalBundles;
+	int filePosition;
+	int restFileSize;
+	int restOffset;
+	int getsSize;
+
+	if (argc > 1)
+	{
+		printf("Invalid arguments\n");
+		printf("./bundleTool\n");
+		return -1;
+	}
+
+	currBundle = 0;
+
+	bundleDir = opendir(MSC_SVC_DROPDIR);
+	CHECK_ERR(bundleDir == 0, "Could not open services directory.");
+        
+	printf("Select the approprate token driver:\n");
+	printf("-----------------------------------\n");
+
+	i = 1;
+	totalBundles = 0;
+
+	while ((currBundle = readdir(bundleDir)) != 0)
+	{
+		if (strstr(currBundle->d_name, ".bundle") != 0)
+		{
+			printf("  %d.     %s\n", i++, currBundle->d_name);
+			totalBundles += 1;
+		}
+	}
+	printf("-----------------------------------\n");
+
+	if (totalBundles == 0)
+	{
+		printf("No services are present - exiting.\n");
+		return 1;
+	}
+
+	do
+	{
+		printf("Enter the number: ");
+		scanf("%d", &userChoice);
+	}
+	while (userChoice < 1 && userChoice > totalBundles);
+
+	closedir(bundleDir);
+
+	bundleDir = opendir(MSC_SVC_DROPDIR);
+	CHECK_ERR(bundleDir == 0, "Could not open services directory.");
+	CHECK_ERR(bundleDir == 0, MSC_SVC_DROPDIR);
+
+	do
+	{
+		if ((currBundle = readdir(bundleDir)) != 0)
+		{
+			if (strstr(currBundle->d_name, ".bundle") != 0)
+			{
+				userChoice -= 1;
+			}
+		}
+	}
+	while (userChoice != 0);
+
+	snprintf(chosenInfoPlist, sizeof(chosenInfoPlist),
+		"%s%s/Contents/Info.plist", MSC_SVC_DROPDIR, currBundle->d_name);
+	closedir(bundleDir);
+	printf("\n");
+
+	rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0, &hContext);
+	CHECK_ERR(rv != SCARD_S_SUCCESS, "PC/SC SCardEstablishContext Failed");
+
+	readerListSize = 0;
+	rv = SCardListReaders(hContext, 0, 0, &readerListSize);
+	CHECK_ERR(rv != SCARD_S_SUCCESS, "PC/SC SCardListReaders Failed");
+
+	readerList = (char *) malloc(sizeof(char) * readerListSize);
+	CHECK_ERR(readerList == 0, "Malloc Failed");
+
+	rv = SCardListReaders(hContext, 0, readerList, &readerListSize);
+	CHECK_ERR(rv != SCARD_S_SUCCESS, "PC/SC SCardListReaders Alloc Failed");
+
+	printf("Insert your token in: %s\n", readerList);
+
+	rgReaderStates.szReader = readerList;
+	rgReaderStates.dwCurrentState = SCARD_STATE_EMPTY;
+
+	rv = SCardGetStatusChange(hContext, INFINITE, &rgReaderStates, 1);
+	CHECK_ERR(rv != SCARD_S_SUCCESS, "PC/SC SCardGetStatusChange Failed");
+
+	p = 0;
+	for (i = 0; i < rgReaderStates.cbAtr; i++)
+	{
+		sprintf(&spAtrValue[p], "%02X", rgReaderStates.rgbAtr[i]);
+		p += 2;
+	}
+	printf("\n");
+
+	snprintf(atrInsertion, sizeof(atrInsertion),
+		"        <string>%s</string>\n", spAtrValue);
+
+	fp = fopen(chosenInfoPlist, "r+");
+	if (fp == 0)
+	{
+		printf("Could not open %s\n", chosenInfoPlist);
+	}
+	CHECK_ERR(fp == 0, "Opening of Info.plist failed.");
+
+	rv = stat(chosenInfoPlist, &statBuffer);
+	CHECK_ERR(rv != 0, "File Stat failed\n");
+
+	restFileSize = statBuffer.st_size + strlen(atrInsertion);
+	restFile = (char *) malloc(sizeof(char) * restFileSize);
+	CHECK_ERR(restFile == 0, "Malloc failed");
+
+	filePosition = 0;
+	restOffset = 0;
+	getsSize = 0;
+
+	do
+	{
+		if (fgets(&restFile[restOffset], restFileSize, fp) == 0)
+		{
+			break;
+		}
+
+		if (strstr(&restFile[restOffset], "<key>spAtrValue</key>"))
+		{
+			filePosition = ftell(fp);
+		}
+
+		getsSize = strlen(&restFile[restOffset]);
+		restOffset += getsSize;
+	}
+	while (1);
+
+	rewind(fp);
+	fwrite(restFile, 1, filePosition, fp);
+	fwrite(atrInsertion, 1, strlen(atrInsertion), fp);
+	fwrite(&restFile[filePosition], 1,
+		statBuffer.st_size - filePosition, fp);
+
+	fclose(fp);
+
+	printf("Token support updated successfully !\n");
+
+	return 0;
+}
+

Added: trunk/SmartCardServices/src/PCSC/winscard.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1497 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  winscard.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: winscard.c 2385 2007-02-05 13:55:01Z rousseau $
+ */
+
+/**
+ * @mainpage MUSCLE PC/SC-Lite API Documentation
+ *
+ * @section Introduction
+ *
+ * This document contains the reference API calls for communicating to the
+ * MUSCLE PC/SC Smart Card Resource Manager. PC/SC is a standard proposed by
+ * the PC/SC workgroup http://www.pcscworkgroup.com/ which is a conglomerate of
+ * representative from major smart card manufacturers and other companies. This
+ * specification tries to abstract the smart card layer into a high level API
+ * so that smart cards and their readers can be accessed in a homogeneous
+ * fashion.
+ *
+ * This toolkit was written in ANSI C that can be used with most compilers and
+ * does NOT use complex and large data structures such as vectors, etc. The C
+ * API emulates the winscard API that is used on the Windows platform. It is
+ * contained in the library <tt>libpcsclite.so</tt> that is linked to your
+ * application.
+ *
+ * I would really like to hear from you. If you have any feedback either on
+ * this documentation or on the MUSCLE project please feel free to email me at:
+ * corcoran at musclecard.com.
+ *
+ *
+ * @section API Routines
+ *
+ * These routines specified here are winscard routines like those in the
+ * winscard API provided under Windows(R). These are compatible with the
+ * Microsoft(R) API calls. This list of calls is mainly an abstraction of
+ * readers. It gives a common API for communication to most readers in a
+ * homogeneous fashion.
+ *
+ * Since all functions can produce a wide array of errors, please refer to 
+ * Error codes for a list of error returns.
+ *
+ * For a human readable representation of an error the function
+ * pcsc_stringify_error() is declared in pcsclite.h. This function is not
+ * available on Microsoft(R) winscard API and is pcsc-lite specific.
+ *
+ * @section Internals
+ *
+ * PC/SC Lite is formed by a server deamon (<tt>pcscd</tt>) and a client
+ * library (<tt>libpcsclite.so</tt>) that communicate via IPC.
+ *
+ * The file \em winscard_clnt.c in the client-side exposes the API for
+ * applications.\n The file \em winscard.c has the server-side counterpart
+ * functions present in \em winscard_clnt.c.\n The file \em winscard_msg.c is
+ * the communication interface between \em winscard_clnt.c and \em
+ * winscard.c.\n The file pcscdaemon.c has the main server-side function,
+ * including a loop for accepting client requests.\n The file \em
+ * winscard_svc.c has the functions called by \em pcscdaemon.c to serve clients
+ * requests.
+ *
+ * When a function from \em winscard_clnt.c is called by a client application,
+ * it calls a function in \em winscard_msg.c to send the message to \em
+ * pcscdaemon.c.  When \em pcscdaemon.c a client detects a request arrived, it
+ * calls \em winscard_svc.c which identifies what command the message contains
+ * and requests \em winscard.c to execute the command.\n Meanwhile
+ * winscard_clnt.c waits for the response until a timeout occurs.
+ */
+
+/**
+ * @file
+ * @brief This handles smartcard reader communications.
+ * This is the heart of the MS smartcard API.
+ *
+ * Here are the main server-side functions which execute the requests from the
+ * clients.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "winscard.h"
+#include "ifdhandler.h"
+#include "debuglog.h"
+#include "readerfactory.h"
+#include "prothandler.h"
+#include "ifdwrapper.h"
+#include "atrhandler.h"
+#include "configfile.h"
+#include "sys_generic.h"
+#include "eventhandler.h"
+#include "readerstate.h"
+
+#include <security_utilities/debugging.h>
+
+/** used for backward compatibility */
+#define SCARD_PROTOCOL_ANY_OLD	 0x1000
+
+/** Some defines for context stack. */
+#define SCARD_LAST_CONTEXT       1
+/** Some defines for context stack. */
+#define SCARD_NO_CONTEXT         0
+/** Some defines for context stack. */
+#define SCARD_EXCLUSIVE_CONTEXT -1
+/** Some defines for context stack. */
+#define SCARD_NO_LOCK            0
+
+SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 };
+SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 };
+SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 };
+
+#define PCSCLITE_LOCK_POLL_RATE		100000		/**< Lock polling rate */
+
+static LONG NotifyOfCardReset(DWORD state, PREADER_CONTEXT rContext, SCARDHANDLE hCard);
+static LONG EjectCard(PREADER_CONTEXT rContext);
+
+
+/**
+ * @brief Creates an Application Context for a client.
+ *
+ * This must be the first function called in a PC/SC application.
+ *
+ * @param[in] dwScope Scope of the establishment.
+ * This can either be a local or remote connection.
+ * <ul>
+ *   <li>SCARD_SCOPE_USER - Not used.
+ *   <li>SCARD_SCOPE_TERMINAL - Not used.
+ *   <li>SCARD_SCOPE_GLOBAL - Not used.
+ *   <li>SCARD_SCOPE_SYSTEM - Services on the local machine.
+ * </ul>
+ * @param[in] pvReserved1 Reserved for future use. Can be used for remote connection.
+ * @param[in] pvReserved2 Reserved for future use.
+ * @param[out] phContext Returned Application Context.
+ *
+ * @return Connection status.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_VALUE Invalid scope type passed (\ref SCARD_E_INVALID_VALUE)
+ * @retval SCARD_E_INVALID_PARAMETER phContext is null (\ref SCARD_E_INVALID_PARAMETER)
+ */
+LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
+	LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
+{
+	/*
+	 * Check for NULL pointer
+	 */
+	if (phContext == 0)
+		return SCARD_E_INVALID_PARAMETER;
+
+	if (dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL &&
+		dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL)
+	{
+
+		*phContext = 0;
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	/*
+	 * Unique identifier for this server so that it can uniquely be
+	 * identified by clients and distinguished from others
+	 */
+
+	*phContext = (PCSCLITE_SVC_IDENTITY + SYS_Random(SYS_GetSeed(),
+			1.0, 65535.0));
+
+	Log3(PCSC_LOG_DEBUG, "Establishing Context: %d [0x%08X]", *phContext, *phContext);
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG SCardReleaseContext(SCARDCONTEXT hContext)
+{
+	/*
+	 * Nothing to do here RPC layer will handle this
+	 */
+
+	Log2(PCSC_LOG_DEBUG, "Releasing Context: %d", hContext);
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG SCardSetTimeout(SCARDCONTEXT hContext, DWORD dwTimeout)
+{
+	/*
+	 * This is only used at the client side of an RPC call but just in
+	 * case someone calls it here
+	 */
+
+	return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
+	DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
+	LPDWORD pdwActiveProtocol)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+	DWORD dwStatus;
+
+	/*
+	 * Check for NULL parameters
+	 */
+	if (szReader == NULL || phCard == NULL || pdwActiveProtocol == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+	else
+		*phCard = 0;
+
+	if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
+			!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
+			!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
+			!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
+		return SCARD_E_PROTO_MISMATCH;
+
+	if (dwShareMode != SCARD_SHARE_EXCLUSIVE &&
+			dwShareMode != SCARD_SHARE_SHARED &&
+			dwShareMode != SCARD_SHARE_DIRECT)
+		return SCARD_E_INVALID_VALUE;
+
+	Log3(PCSC_LOG_DEBUG, "Attempting Connect to %s using protocol: %d",
+		szReader, dwPreferredProtocols);
+
+	rv = RFReaderInfo((LPSTR) szReader, &rContext);
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		Log2(PCSC_LOG_ERROR, "Reader %s Not Found", szReader);
+		return rv;
+	}
+
+	/*
+	 * Make sure the reader is working properly
+	 */
+	rv = RFCheckReaderStatus(rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+	
+	/*******************************************
+	 *
+	 * This section checks for simple errors
+	 *
+	 *******************************************/
+
+	/*
+	 * Connect if not exclusive mode
+	 */
+	if (rContext->dwContexts == SCARD_EXCLUSIVE_CONTEXT)
+	{
+		Log1(PCSC_LOG_ERROR, "Error Reader Exclusive");
+		return SCARD_E_SHARING_VIOLATION;
+	}
+
+	/*
+	 * wait until a possible transaction is finished
+	 */
+	if (rContext->dwLockId != 0)
+	{
+		Log1(PCSC_LOG_INFO, "Waiting for release of lock");
+		while (rContext->dwLockId != 0)
+			SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
+		Log1(PCSC_LOG_INFO, "Lock released");
+
+		/* Allow the status thread to convey information */
+		SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
+	}
+
+	/*******************************************
+	 *
+	 * This section tries to determine the
+	 * presence of a card or not
+	 *
+	 *******************************************/
+	dwStatus = SharedReaderState_State(rContext->readerState);
+
+	if (dwShareMode != SCARD_SHARE_DIRECT)
+	{
+		if (!(dwStatus & SCARD_PRESENT))
+		{
+			Log1(PCSC_LOG_ERROR, "Card Not Inserted");
+			return SCARD_E_NO_SMARTCARD;
+		}
+
+		if (dwStatus & SCARD_SWALLOWED)
+		{
+			Log1(PCSC_LOG_ERROR, "Card Not Powered");
+			return SCARD_W_UNPOWERED_CARD;
+		}
+	}
+
+
+	/*******************************************
+	 *
+	 * This section tries to decode the ATR
+	 * and set up which protocol to use
+	 *
+	 *******************************************/
+	if (dwPreferredProtocols & SCARD_PROTOCOL_RAW)
+		SharedReaderState_SetProtocol(rContext->readerState, SCARD_PROTOCOL_RAW);
+	else
+	{
+		if (dwShareMode != SCARD_SHARE_DIRECT)
+		{
+			/* the protocol is not yet set (no PPS yet) */
+			if (SCARD_PROTOCOL_UNSET == SharedReaderState_Protocol(rContext->readerState))
+			{
+				UCHAR ucAvailable, ucDefault;
+				int ret;
+
+				ucDefault = PHGetDefaultProtocol(SharedReaderState_CardAtr(rContext->readerState), 
+					SharedReaderState_CardAtrLength(rContext->readerState));
+				ucAvailable =
+					PHGetAvailableProtocols(SharedReaderState_CardAtr(rContext->readerState), 
+					SharedReaderState_CardAtrLength(rContext->readerState));
+
+				/*
+				 * If it is set to ANY let it do any of the protocols
+				 */
+				if (dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD)
+					dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
+
+				ret = PHSetProtocol(rContext, dwPreferredProtocols,
+					ucAvailable, ucDefault);
+
+				/* keep cardProtocol = SCARD_PROTOCOL_UNSET in case of error  */
+				if (SET_PROTOCOL_PPS_FAILED == ret)
+					return SCARD_W_UNRESPONSIVE_CARD;
+
+				if (SET_PROTOCOL_WRONG_ARGUMENT == ret)
+					return SCARD_E_PROTO_MISMATCH;
+
+				/* use negociated protocol */
+				SharedReaderState_SetProtocol(rContext->readerState, ret);
+			}
+			else
+			{
+				if (! (dwPreferredProtocols & SharedReaderState_Protocol(rContext->readerState)))
+					return SCARD_E_PROTO_MISMATCH;
+			}
+		}
+	}
+
+	*pdwActiveProtocol = SharedReaderState_Protocol(rContext->readerState);
+
+	if (dwShareMode != SCARD_SHARE_DIRECT)
+	{
+		if ((*pdwActiveProtocol != SCARD_PROTOCOL_T0)
+			&& (*pdwActiveProtocol != SCARD_PROTOCOL_T1))
+			Log2(PCSC_LOG_ERROR, "Active Protocol: unknown %d",
+				*pdwActiveProtocol);
+		else
+			Log2(PCSC_LOG_DEBUG, "Active Protocol: T=%d",
+				(*pdwActiveProtocol == SCARD_PROTOCOL_T0) ? 0 : 1);
+	}
+	else
+		Log1(PCSC_LOG_DEBUG, "Direct access: no protocol selected");
+
+	/*
+	 * Prepare the SCARDHANDLE identity
+	 */
+	*phCard = RFCreateReaderHandle(rContext);
+
+	Log2(PCSC_LOG_DEBUG, "hCard Identity: %x", *phCard);
+
+	/*******************************************
+	 *
+	 * This section tries to set up the
+	 * exclusivity modes. -1 is exclusive
+	 *
+	 *******************************************/
+
+	if (dwShareMode == SCARD_SHARE_EXCLUSIVE)
+	{
+		if (rContext->dwContexts == SCARD_NO_CONTEXT)
+		{
+			rContext->dwContexts = SCARD_EXCLUSIVE_CONTEXT;
+			RFLockSharing(*phCard);
+		}
+		else
+		{
+			RFDestroyReaderHandle(*phCard);
+			*phCard = 0;
+			Log1(PCSC_LOG_ERROR, "SCardConnect: share mode is exclusive, but already in use");
+			return SCARD_E_SHARING_VIOLATION;
+		}
+	}
+	else
+	{
+		/*
+		 * Add a connection to the context stack
+		 */
+		rContext->dwContexts += 1;
+	}
+
+	/*
+	 * Add this handle to the handle list
+	 */
+	rv = RFAddReaderHandle(rContext, *phCard);
+
+	if (rv != SCARD_S_SUCCESS)
+	{
+		/*
+		 * Clean up - there is no more room
+		 */
+		RFDestroyReaderHandle(*phCard);
+		if (rContext->dwContexts == SCARD_EXCLUSIVE_CONTEXT)
+			rContext->dwContexts = SCARD_NO_CONTEXT;
+		else
+			if (rContext->dwContexts > SCARD_NO_CONTEXT)
+				rContext->dwContexts -= 1;
+
+		*phCard = 0;
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	/*
+	 * Allow the status thread to convey information
+	 */
+	SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
+	DWORD dwPreferredProtocols, DWORD dwInitialization,
+	LPDWORD pdwActiveProtocol)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+	int do_sleep = 1;
+
+	Log1(PCSC_LOG_DEBUG, "Attempting reconnect to token.");
+
+	if (hCard == 0)
+		return SCARD_E_INVALID_HANDLE;
+
+	/*
+	 * Handle the dwInitialization
+	 */
+	if (dwInitialization != SCARD_LEAVE_CARD &&
+			dwInitialization != SCARD_RESET_CARD &&
+			dwInitialization != SCARD_UNPOWER_CARD)
+		return SCARD_E_INVALID_VALUE;
+
+	if (dwShareMode != SCARD_SHARE_SHARED &&
+			dwShareMode != SCARD_SHARE_EXCLUSIVE &&
+			dwShareMode != SCARD_SHARE_DIRECT)
+		return SCARD_E_INVALID_VALUE;
+
+	if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
+			!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
+			!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
+			!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
+		return SCARD_E_PROTO_MISMATCH;
+
+	if (pdwActiveProtocol == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure the reader is working properly
+	 */
+	rv = RFCheckReaderStatus(rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure no one has a lock on this reader
+	 */
+	rv = RFCheckSharing(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * RFUnblockReader( rContext ); FIX - this doesn't work
+	 */
+
+	if (dwInitialization == SCARD_RESET_CARD ||
+		dwInitialization == SCARD_UNPOWER_CARD)
+	{
+		LONG ret = NotifyOfCardReset(dwInitialization, rContext, hCard);
+		if (ret != SCARD_S_SUCCESS)
+			return ret;
+
+		do_sleep = 1;
+	}
+	else if (dwInitialization == SCARD_LEAVE_CARD)
+		{
+			/*
+			 * Do nothing
+			 */
+			do_sleep = 0;
+		}
+
+	/*******************************************
+	 *
+	 * This section tries to decode the ATR
+	 * and set up which protocol to use
+	 *
+	 *******************************************/
+
+
+	if (dwPreferredProtocols & SCARD_PROTOCOL_RAW)
+		SharedReaderState_SetProtocol(rContext->readerState, SCARD_PROTOCOL_RAW);
+	else
+	{
+		if (dwShareMode != SCARD_SHARE_DIRECT)
+		{
+			/* the protocol is not yet set (no PPS yet) */
+			if (SCARD_PROTOCOL_UNSET == SharedReaderState_Protocol(rContext->readerState))
+			{
+				UCHAR ucAvailable, ucDefault;
+				int ret;
+
+				ucDefault = PHGetDefaultProtocol(SharedReaderState_CardAtr(rContext->readerState), 
+					SharedReaderState_CardAtrLength(rContext->readerState));
+				ucAvailable =
+					PHGetAvailableProtocols(SharedReaderState_CardAtr(rContext->readerState), 
+					SharedReaderState_CardAtrLength(rContext->readerState));
+
+				/* If it is set to ANY let it do any of the protocols */
+				if (dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD)
+					dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
+
+				ret = PHSetProtocol(rContext, dwPreferredProtocols,
+					ucAvailable, ucDefault);
+
+				/* keep cardProtocol = SCARD_PROTOCOL_UNSET in case of error  */
+				if (SET_PROTOCOL_PPS_FAILED == ret)
+					return SCARD_W_UNRESPONSIVE_CARD;
+
+				if (SET_PROTOCOL_WRONG_ARGUMENT == ret)
+					return SCARD_E_PROTO_MISMATCH;
+
+				/* use negociated protocol */
+				SharedReaderState_SetProtocol(rContext->readerState, ret);
+			}
+			else
+			{
+				if (! (dwPreferredProtocols & SharedReaderState_Protocol(rContext->readerState)))
+					return SCARD_E_PROTO_MISMATCH;
+			}
+		}
+	}
+
+	*pdwActiveProtocol = SharedReaderState_Protocol(rContext->readerState);
+
+	if (dwShareMode == SCARD_SHARE_EXCLUSIVE)
+	{
+		if (rContext->dwContexts == SCARD_EXCLUSIVE_CONTEXT)
+		{
+			/*
+			 * Do nothing - we are already exclusive
+			 */
+		} else
+		{
+			if (rContext->dwContexts == SCARD_LAST_CONTEXT)
+			{
+				rContext->dwContexts = SCARD_EXCLUSIVE_CONTEXT;
+				RFLockSharing(hCard);
+			} else
+			{
+				Log1(PCSC_LOG_ERROR, "SCardReConnect: share mode is exclusive, but already in use");
+				return SCARD_E_SHARING_VIOLATION;
+			}
+		}
+	} else if (dwShareMode == SCARD_SHARE_SHARED)
+	{
+		if (rContext->dwContexts != SCARD_EXCLUSIVE_CONTEXT)
+		{
+			/*
+			 * Do nothing - in sharing mode already
+			 */
+		} else
+		{
+			/*
+			 * We are in exclusive mode but want to share now
+			 */
+			RFUnlockSharing(hCard);
+			rContext->dwContexts = SCARD_LAST_CONTEXT;
+		}
+	} else if (dwShareMode == SCARD_SHARE_DIRECT)
+	{
+		if (rContext->dwContexts != SCARD_EXCLUSIVE_CONTEXT)
+		{
+			/*
+			 * Do nothing - in sharing mode already
+			 */
+		} else
+		{
+			/*
+			 * We are in exclusive mode but want to share now
+			 */
+			RFUnlockSharing(hCard);
+			rContext->dwContexts = SCARD_LAST_CONTEXT;
+		}
+	} else
+		return SCARD_E_INVALID_VALUE;
+
+	/*
+	 * Clear a previous event to the application
+	 */
+	RFClearReaderEventState(rContext, hCard);
+
+	/*
+	 * Allow the status thread to convey information
+	 */
+	if (do_sleep)
+		SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+
+	if (hCard == 0)
+		return SCARD_E_INVALID_HANDLE;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	if ((dwDisposition != SCARD_LEAVE_CARD)
+		&& (dwDisposition != SCARD_UNPOWER_CARD)
+		&& (dwDisposition != SCARD_RESET_CARD)
+		&& (dwDisposition != SCARD_EJECT_CARD))
+		return SCARD_E_INVALID_VALUE;
+
+	/*
+	 * wait until a possible transaction is finished
+	 */
+	if ((rContext->dwLockId != 0) && (rContext->dwLockId != (uint32_t)hCard))
+	{
+		Log1(PCSC_LOG_INFO, "Waiting for release of lock");
+		while (rContext->dwLockId != 0)
+			SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
+		Log1(PCSC_LOG_INFO, "Lock released");
+	}
+
+	/*
+	 * Unlock any blocks on this context
+	 */
+	rv = RFUnlockSharing(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	Log2(PCSC_LOG_DEBUG, "Active Contexts: %d", rContext->dwContexts);
+
+	if (dwDisposition == SCARD_RESET_CARD ||
+		dwDisposition == SCARD_UNPOWER_CARD)
+	{
+		/* LONG ret = */ NotifyOfCardReset(dwDisposition, rContext, hCard);
+		/* we ignore the return values in this case */
+		
+		/*
+		 * Allow the status thread to convey information
+		 */
+		SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
+
+	}
+	else
+	if (dwDisposition == SCARD_EJECT_CARD)
+		EjectCard(rContext);
+	else if (dwDisposition == SCARD_LEAVE_CARD)
+	{
+		/*
+		 * Do nothing
+		 */
+	}
+
+	/*
+	 * Remove and destroy this handle
+	 */
+	RFRemoveReaderHandle(rContext, hCard);
+	RFDestroyReaderHandle(hCard);
+
+	/*
+	 * For exclusive connection reset it to no connections
+	 */
+	if (rContext->dwContexts == SCARD_EXCLUSIVE_CONTEXT)
+	{
+		rContext->dwContexts = SCARD_NO_CONTEXT;
+		return SCARD_S_SUCCESS;
+	}
+
+	/*
+	 * Remove a connection from the context stack
+	 */
+	rContext->dwContexts -= 1;
+
+	if (rContext->dwContexts < 0)
+		rContext->dwContexts = 0;
+
+	return SCARD_S_SUCCESS;
+}
+
+LONG SCardBeginTransaction(SCARDHANDLE hCard)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext;
+
+	if (hCard == 0)
+		return SCARD_E_INVALID_HANDLE;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+
+	/*
+	 * Cannot find the hCard in this context
+	 */
+	if (rv != SCARD_S_SUCCESS)
+	{
+		Log3(PCSC_LOG_DEBUG, "SCardBeginTransaction: cannot find hCard: 0x%08X [0x%08X]", hCard, rv);
+		return rv;
+	}
+	
+	/*
+	 * Make sure the reader is working properly
+	 */
+	rv = RFCheckReaderStatus(rContext);
+	if (rv != SCARD_S_SUCCESS)
+	{
+		Log3(PCSC_LOG_DEBUG, "SCardBeginTransaction: reader status fail: 0x%08X [0x%08X]", hCard, rv);
+		return rv;
+	}
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+	{
+		Log3(PCSC_LOG_DEBUG, "SCardBeginTransaction: reader handle fail: 0x%08X [0x%08X]", hCard, rv);
+		return rv;
+	}
+
+	/*
+	 * Make sure some event has not occurred
+	 */
+	if ((rv = RFCheckReaderEventState(rContext, hCard)) != SCARD_S_SUCCESS)
+	{
+		Log3(PCSC_LOG_DEBUG, "SCardBeginTransaction: reader event fail: 0x%08X [0x%08X]", hCard, rv);
+		return rv;
+	}
+
+	rv = RFLockSharing(hCard);
+
+	/* if the transaction is not yet ready we sleep a bit so the client
+	 * do not retry immediately */
+	if (SCARD_E_SHARING_VIOLATION == (uint32_t)rv)
+		SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
+
+	Log2(PCSC_LOG_DEBUG, "SCardBeginTransaction ending status: 0x%08X", rv);
+
+	return rv;
+}
+
+LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+
+	/*
+	 * Ignoring dwDisposition for now
+	 */
+	if (hCard == 0)
+		return SCARD_E_INVALID_HANDLE;
+
+	if ((dwDisposition != SCARD_LEAVE_CARD)
+		&& (dwDisposition != SCARD_UNPOWER_CARD)
+		&& (dwDisposition != SCARD_RESET_CARD)
+		&& (dwDisposition != SCARD_EJECT_CARD))
+	return SCARD_E_INVALID_VALUE;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+
+	/*
+	 * Cannot find the hCard in this context
+	 */
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure some event has not occurred
+	 */
+	if ((rv = RFCheckReaderEventState(rContext, hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	if (dwDisposition == SCARD_RESET_CARD ||
+		dwDisposition == SCARD_UNPOWER_CARD)
+	{
+		/* LONG ret = */ NotifyOfCardReset(dwDisposition, rContext, hCard);
+	}
+	else if (dwDisposition == SCARD_EJECT_CARD)
+		EjectCard(rContext);
+	else if (dwDisposition == SCARD_LEAVE_CARD)
+	{
+		/*
+		 * Do nothing
+		 */
+	}
+
+	/*
+	 * Unlock any blocks on this context
+	 */
+	RFUnlockSharing(hCard);
+
+	Log2(PCSC_LOG_DEBUG, "Status: 0x%08X", rv);
+
+	return rv;
+}
+
+LONG SCardCancelTransaction(SCARDHANDLE hCard)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+
+	/*
+	 * Ignoring dwDisposition for now
+	 */
+	if (hCard == 0)
+		return SCARD_E_INVALID_HANDLE;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+
+	/*
+	 * Cannot find the hCard in this context
+	 */
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure some event has not occurred
+	 */
+	if ((rv = RFCheckReaderEventState(rContext, hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFUnlockSharing(hCard);
+
+	Log2(PCSC_LOG_DEBUG, "Status: 0x%08X", rv);
+
+	return rv;
+}
+
+LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderNames,
+	LPDWORD pcchReaderLen, LPDWORD pdwState,
+	LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+
+	/*
+	 * Cannot find the hCard in this context
+	 */
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	if (strlen(rContext->lpcReader) > MAX_BUFFER_SIZE
+			|| SharedReaderState_CardAtrLength(rContext->readerState) > MAX_ATR_SIZE)
+		return SCARD_F_INTERNAL_ERROR;
+
+	/*
+	 * This is a client side function however the server maintains the
+	 * list of events between applications so it must be passed through to
+	 * obtain this event if it has occurred
+	 */
+
+	/*
+	 * Make sure some event has not occurred
+	 */
+	if ((rv = RFCheckReaderEventState(rContext, hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure the reader is working properly
+	 */
+	rv = RFCheckReaderStatus(rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	if (mszReaderNames)			/* want reader name */
+	{
+		int cchReaderLen;
+		if (!pcchReaderLen)		/* present buf & no buflen */
+			return SCARD_E_INVALID_PARAMETER;
+
+		cchReaderLen = strlen(rContext->lpcReader);
+		if(*pcchReaderLen < cchReaderLen)
+			rv = SCARD_E_INSUFFICIENT_BUFFER;
+		else   /* There's enough room in the buffer */
+			strncpy(mszReaderNames, rContext->lpcReader, cchReaderLen);
+		*pcchReaderLen = cchReaderLen;
+	}
+	else if (pcchReaderLen) /* want the reader length but not the name */
+		*pcchReaderLen = strlen(rContext->lpcReader);
+
+	if (pdwState)
+		*pdwState = SharedReaderState_State(rContext->readerState);
+
+	if (pdwProtocol)
+		*pdwProtocol = SharedReaderState_Protocol(rContext->readerState);
+
+	if (pbAtr)     /* want ATR */
+	{
+		int cbAtrLen;
+		if (!pcbAtrLen)
+			return SCARD_E_INVALID_PARAMETER;
+		cbAtrLen = SharedReaderState_CardAtrLength(rContext->readerState);
+
+		if(cbAtrLen >= *pcbAtrLen)
+			rv = SCARD_E_INSUFFICIENT_BUFFER;
+		else
+		{
+			*pcbAtrLen = cbAtrLen;
+			memcpy(pbAtr, SharedReaderState_CardAtr(rContext->readerState), cbAtrLen);
+		}
+	}
+	else if (pcbAtrLen)
+		*pcbAtrLen = SharedReaderState_CardAtrLength(rContext->readerState);
+
+	return rv;
+}
+
+LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
+	LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders)
+{
+	/*
+	 * Client side function
+	 */
+	return SCARD_S_SUCCESS;
+}
+
+#undef SCardControl
+
+LONG SCardControl(SCARDHANDLE hCard, const void *pbSendBuffer,
+	DWORD cbSendLength, void *pbRecvBuffer, LPDWORD pcbRecvLength)
+{
+	// Pre pcsclite 1.3.2 version
+	
+	uint32_t dwControlCode = 0;
+	
+	uint32_t cbRecvLength = *pcbRecvLength;
+	uint32_t bytesReturned = 0;
+	int32_t rv = SCardControl132(hCard, dwControlCode, pbSendBuffer, cbSendLength,
+		pbRecvBuffer, cbRecvLength, &bytesReturned);
+	*pcbRecvLength = bytesReturned;
+	return rv;
+}
+
+int32_t SCardControl132(SCARDHANDLE hCard, uint32_t dwControlCode,
+		const void *pbSendBuffer, uint32_t cbSendLength,
+		void *pbRecvBuffer, uint32_t cbRecvLength, uint32_t *lpBytesReturned)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+
+	/* 0 bytes returned by default */
+	*lpBytesReturned = 0;
+
+	if (0 == hCard)
+		return SCARD_E_INVALID_HANDLE;
+
+	/*
+	 * Make sure no one has a lock on this reader
+	 */
+	if ((rv = RFCheckSharing(hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	if (IFD_HVERSION_2_0 == rContext->dwVersion)
+		if (NULL == pbSendBuffer || 0 == cbSendLength)
+			return SCARD_E_INVALID_PARAMETER;
+
+	/*
+	 * Make sure the reader is working properly
+	 */
+	rv = RFCheckReaderStatus(rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure some event has not occurred
+	 */
+	if ((rv = RFCheckReaderEventState(rContext, hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	if (IFD_HVERSION_2_0 == rContext->dwVersion)
+	{
+		/* we must wrap a API 3.0 client in an API 2.0 driver */
+		*lpBytesReturned = cbRecvLength;
+		return IFDControl_v2(rContext, (PUCHAR)pbSendBuffer,
+			cbSendLength, (uint8_t *)pbRecvBuffer, lpBytesReturned);
+	}
+	else
+		if (IFD_HVERSION_3_0 == rContext->dwVersion)
+			return IFDControl(rContext, dwControlCode, pbSendBuffer,
+				cbSendLength, pbRecvBuffer, cbRecvLength, lpBytesReturned);
+		else
+			return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId,
+	LPBYTE pbAttr, LPDWORD pcbAttrLen)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+
+	if (0 == hCard)
+		return SCARD_E_INVALID_HANDLE;
+
+	/*
+	 * Make sure no one has a lock on this reader
+	 */
+	if ((rv = RFCheckSharing(hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure the reader is working properly
+	 */
+	rv = RFCheckReaderStatus(rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure some event has not occurred
+	 */
+	if ((rv = RFCheckReaderEventState(rContext, hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = IFDGetCapabilities(rContext, dwAttrId, pcbAttrLen, pbAttr);
+	if (rv == IFD_SUCCESS)
+		return SCARD_S_SUCCESS;
+	else
+		if (rv == IFD_ERROR_TAG)
+			return SCARD_E_UNSUPPORTED_FEATURE;
+		else
+			return SCARD_E_NOT_TRANSACTED;
+}
+
+LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId,
+	LPCBYTE pbAttr, DWORD cbAttrLen)
+{
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+
+	if (0 == hCard)
+		return SCARD_E_INVALID_HANDLE;
+
+	/*
+	 * Make sure no one has a lock on this reader
+	 */
+	if ((rv = RFCheckSharing(hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure the reader is working properly
+	 */
+	rv = RFCheckReaderStatus(rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure some event has not occurred
+	 */
+	if ((rv = RFCheckReaderEventState(rContext, hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = IFDSetCapabilities(rContext, dwAttrId, cbAttrLen, (PUCHAR)pbAttr);
+	if (rv == IFD_SUCCESS)
+		return SCARD_S_SUCCESS;
+	else
+		if (rv == IFD_ERROR_TAG)
+			return SCARD_E_UNSUPPORTED_FEATURE;
+		else
+			return SCARD_E_NOT_TRANSACTED;
+}
+
+#define kSCARD_LE_IN_SW2	0x6C
+#define kReadBinaryAPDU		0xB0
+#define kReadBinaryLe		4
+
+LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
+	LPCBYTE pbSendBuffer, DWORD cbSendLength,
+	LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer,
+	LPDWORD pcbRecvLength)
+{
+	/*
+		See for example:
+		NIST IR 6887	"Government Smart Card Interoperability Specification (GSC-IS), v2.1",
+		July 2003
+		http://csrc.nist.gov/publications/nistir/nistir-6887.pdf
+		for info on error conditions. One define is SCARD_LE_IN_SW2
+	*/
+	LONG rv;
+	PREADER_CONTEXT rContext = NULL;
+	SCARD_IO_HEADER sSendPci, sRecvPci;
+	DWORD dwRxLength, tempRxLength;
+
+	if (pcbRecvLength == 0)
+		return SCARD_E_INVALID_PARAMETER;
+
+	dwRxLength = *pcbRecvLength;
+	*pcbRecvLength = 0;
+
+	if (hCard == 0)
+		return SCARD_E_INVALID_HANDLE;
+
+	if (pbSendBuffer == NULL || pbRecvBuffer == NULL || pioSendPci == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+
+	/*
+	 * Must at least send a 4 bytes APDU
+	 */
+	if (cbSendLength < 4)
+		return SCARD_E_INVALID_PARAMETER;
+
+	/*
+	 * Must at least have 2 status words even for SCardControl
+	 */
+	if (dwRxLength < 2)
+		return SCARD_E_INSUFFICIENT_BUFFER;
+
+	/*
+	 * Make sure no one has a lock on this reader
+	 */
+	if ((rv = RFCheckSharing(hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFReaderInfoById(hCard, &rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure the reader is working properly
+	 */
+	rv = RFCheckReaderStatus(rContext);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	rv = RFFindReaderHandle(hCard);
+	if (rv != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Make sure some event has not occurred
+	 */
+	if ((rv = RFCheckReaderEventState(rContext, hCard)) != SCARD_S_SUCCESS)
+		return rv;
+
+	/*
+	 * Check for some common errors
+	 */
+	if (pioSendPci->dwProtocol != SCARD_PROTOCOL_RAW)
+	{
+		if (SharedReaderState_State(rContext->readerState) & SCARD_ABSENT)
+		{
+			return SCARD_E_NO_SMARTCARD;
+		}
+	}
+
+	if (pioSendPci->dwProtocol != SCARD_PROTOCOL_RAW)
+	{
+		if (pioSendPci->dwProtocol != SCARD_PROTOCOL_ANY_OLD)
+		{
+			if (pioSendPci->dwProtocol != SharedReaderState_Protocol(rContext->readerState))
+			{
+				return SCARD_E_PROTO_MISMATCH;
+			}
+		}
+	}
+
+	/*
+	 * Quick fix: PC/SC starts at 1 for bit masking but the IFD_Handler
+	 * just wants 0 or 1
+	 */
+
+	sSendPci.Protocol = 0; /* protocol T=0 by default */
+
+	if (pioSendPci->dwProtocol == SCARD_PROTOCOL_T1)
+	{
+		sSendPci.Protocol = 1;
+	} else if (pioSendPci->dwProtocol == SCARD_PROTOCOL_RAW)
+	{
+		/*
+		 * This is temporary ......
+		 */
+		sSendPci.Protocol = SCARD_PROTOCOL_RAW;
+	} else if (pioSendPci->dwProtocol == SCARD_PROTOCOL_ANY_OLD)
+	{
+	  /* Fix by Amira (Athena) */
+		unsigned long i;
+		unsigned long prot = SharedReaderState_Protocol(rContext->readerState);
+
+		for (i = 0 ; prot != 1 ; i++)
+			prot >>= 1;
+
+		sSendPci.Protocol = i;
+	}
+
+	sSendPci.Length = pioSendPci->cbPciLength;
+
+	/* the protocol number is decoded a few lines above */
+	Log2(PCSC_LOG_DEBUG, "Send Protocol: T=%d", sSendPci.Protocol);
+
+	tempRxLength = dwRxLength;
+
+	if (pioSendPci->dwProtocol == SCARD_PROTOCOL_RAW)
+	{
+		rv = IFDControl_v2(rContext, (PUCHAR)pbSendBuffer , cbSendLength,
+			pbRecvBuffer, &dwRxLength);
+	} else
+	{
+		rv = IFDTransmit(rContext, sSendPci, (PUCHAR)pbSendBuffer,
+			cbSendLength, pbRecvBuffer, &dwRxLength, &sRecvPci);
+	}
+
+	if (pioRecvPci)
+	{
+		pioRecvPci->dwProtocol = sRecvPci.Protocol;
+		pioRecvPci->cbPciLength = sRecvPci.Length;
+	}
+	
+	Log3(PCSC_LOG_DEBUG, "IFDControl_v2/IFDTransmit result: 0x%08X, received: %d", rv, dwRxLength);
+	Log3(PCSC_LOG_DEBUG, " pbRecvBuffer: [0]: 0x%02X, [1]: 0x%02X", pbRecvBuffer[0], pbRecvBuffer[1]);
+
+	/*
+	 * Check for any errors that might have occurred
+	 */
+	
+	if (rv != SCARD_S_SUCCESS)
+	{
+		*pcbRecvLength = 0;
+		Log2(PCSC_LOG_ERROR, "Card not transacted: 0x%08lX", rv);
+		return SCARD_E_NOT_TRANSACTED;
+	}
+
+	/*
+	 * Available is less than received
+	 */
+	if (tempRxLength < dwRxLength)
+	{
+		Log3(PCSC_LOG_DEBUG, "Available is less than received: avail: %d, received: %d", tempRxLength, dwRxLength);
+		*pcbRecvLength = 0;
+		return SCARD_E_INSUFFICIENT_BUFFER;
+	}
+
+	/*
+	 * Successful return
+	 */
+	*pcbRecvLength = dwRxLength;
+	return SCARD_S_SUCCESS;
+}
+
+LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups,
+	LPSTR mszReaders, LPDWORD pcchReaders)
+{
+	/*
+	 * Client side function
+	 */
+	return SCARD_S_SUCCESS;
+}
+
+LONG SCardCancel(SCARDCONTEXT hContext)
+{
+	/*
+	 * Client side function
+	 */
+	return SCARD_S_SUCCESS;
+}
+
+static LONG NotifyOfCardReset(DWORD state, PREADER_CONTEXT rContext, SCARDHANDLE hCard)
+{
+	/*
+	 * Currently pcsc-lite keeps the card powered constantly
+	 * Note that although EndTransaction initially sets dwAction in one
+	 * case to IFD_POWER_DOWN, it then sets it to IFD_RESET
+	 */
+
+	LONG rv = SCARD_S_SUCCESS, ret = SCARD_S_SUCCESS;
+
+	DWORD tmpCardAtrLength = SharedReaderState_CardAtrLength(rContext->readerState);
+	if (SCARD_RESET_CARD == state)
+		rv = IFDPowerICC(rContext, IFD_RESET, SharedReaderState_CardAtr(rContext->readerState), &tmpCardAtrLength);
+	else
+	{
+		rv = IFDPowerICC(rContext, IFD_POWER_DOWN, SharedReaderState_CardAtr(rContext->readerState), &tmpCardAtrLength);
+		rv = IFDPowerICC(rContext, IFD_POWER_UP,   SharedReaderState_CardAtr(rContext->readerState), &tmpCardAtrLength);
+	}
+	SharedReaderState_SetCardAtrLength(rContext->readerState, tmpCardAtrLength);
+
+	/* the protocol is unset after a power on */
+	SharedReaderState_SetProtocol(rContext->readerState, SCARD_PROTOCOL_UNSET);
+
+	/*
+	 * Notify the card has been reset
+	 * Not doing this could result in deadlock
+	 */
+	ret = RFCheckReaderEventState(rContext, hCard);
+	
+	/*
+		Note: there is disagreement on which value of rv to use for the switch below:
+		
+		SCardReconnect:			result of RFCheckReaderEventState
+		SCardDisconnect:		result of IFDPowerICC
+		SCardEndTransaction: 	result of IFDPowerICC
+		
+		We use the result of IFDPowerICC here; this seems more sensible
+	*/
+	switch (rv)
+	{
+	/* avoid deadlock */
+	case SCARD_W_RESET_CARD:
+		break;
+
+	case SCARD_W_REMOVED_CARD:
+		Log1(PCSC_LOG_ERROR, "card removed");
+		return SCARD_W_REMOVED_CARD;
+
+	/* invalid EventStatus */
+	case SCARD_E_INVALID_VALUE:
+		Log1(PCSC_LOG_ERROR, "invalid EventStatus");
+		return SCARD_F_INTERNAL_ERROR;
+
+	/* invalid hCard, but hCard was widely used some lines above :( */
+	case SCARD_E_INVALID_HANDLE:
+		Log1(PCSC_LOG_ERROR, "invalid handle");
+		return SCARD_F_INTERNAL_ERROR;
+
+	case SCARD_S_SUCCESS:
+		/*
+		 * Notify the card has been reset
+		 */
+		RFSetReaderEventState(rContext, SCARD_RESET);
+
+		/*
+		 * Set up the status bit masks on dwStatus
+		 */
+		DWORD readerStateTmp = SharedReaderState_State(rContext->readerState);
+		if (rv == SCARD_S_SUCCESS)
+		{
+			readerStateTmp |= SCARD_PRESENT;
+			readerStateTmp &= ~SCARD_ABSENT;
+			readerStateTmp |= SCARD_POWERED;
+			readerStateTmp |= SCARD_NEGOTIABLE;
+			readerStateTmp &= ~SCARD_SPECIFIC;
+			readerStateTmp &= ~SCARD_SWALLOWED;
+			readerStateTmp &= ~SCARD_UNKNOWN;
+		}
+		else
+		{
+			readerStateTmp |= SCARD_PRESENT;
+			readerStateTmp &= ~SCARD_ABSENT;
+			readerStateTmp |= SCARD_SWALLOWED;
+			readerStateTmp &= ~SCARD_POWERED;
+			readerStateTmp &= ~SCARD_NEGOTIABLE;
+			readerStateTmp &= ~SCARD_SPECIFIC;
+			readerStateTmp &= ~SCARD_UNKNOWN;
+			SharedReaderState_SetCardAtrLength(rContext->readerState, 0);
+		}
+		SharedReaderState_SetState(rContext->readerState, readerStateTmp);
+
+		if (SharedReaderState_CardAtrLength(rContext->readerState) > 0)
+		{
+			Log1(PCSC_LOG_ERROR, "Reset complete.");
+			LogXxd(PCSC_LOG_DEBUG, "Card ATR: ", SharedReaderState_CardAtr(rContext->readerState), 
+				SharedReaderState_CardAtrLength(rContext->readerState));
+		}
+		else
+		{
+			DWORD dwStatus, dwAtrLen;
+			UCHAR ucAtr[MAX_ATR_SIZE];
+
+			Log1(PCSC_LOG_ERROR, "Error resetting card.");
+			IFDStatusICC(rContext, &dwStatus, ucAtr, &dwAtrLen);
+			if (dwStatus & SCARD_PRESENT)
+				return SCARD_W_UNRESPONSIVE_CARD;
+			else
+				return SCARD_E_NO_SMARTCARD;
+		}
+		break;
+	default:
+		Log2(PCSC_LOG_ERROR, "invalid retcode from RFCheckReaderEventState (%X)", rv);
+		return SCARD_F_INTERNAL_ERROR;
+	}
+	return SCARD_S_SUCCESS;
+}
+
+static LONG EjectCard(PREADER_CONTEXT rContext)
+{
+	LONG rv = SCARD_S_SUCCESS;
+
+	UCHAR controlBuffer[5];
+	UCHAR receiveBuffer[MAX_BUFFER_SIZE];
+	DWORD receiveLength;
+
+	/*
+	 * Set up the CTBCS command for Eject ICC
+	 */
+	controlBuffer[0] = 0x20;
+	controlBuffer[1] = 0x15;
+	controlBuffer[2] = (rContext->dwSlot & 0x0000FFFF) + 1;
+	controlBuffer[3] = 0x00;
+	controlBuffer[4] = 0x00;
+	receiveLength = 2;
+	rv = IFDControl_v2(rContext, controlBuffer, 5, receiveBuffer, &receiveLength);
+
+	if (rv == SCARD_S_SUCCESS)
+	{
+		if (receiveLength == 2 && receiveBuffer[0] == 0x90)	// Successful
+			Log1(PCSC_LOG_ERROR, "Card ejected successfully.");
+		else
+		{
+			Log3(PCSC_LOG_ERROR, "Error ejecting card: %02X%02X", receiveBuffer[0], receiveBuffer[1]);
+			rv = SCARD_F_UNKNOWN_ERROR;
+		}
+	}
+	else
+		Log1(PCSC_LOG_ERROR, "Error ejecting card.");
+		
+	return rv;
+}
+
+

Added: trunk/SmartCardServices/src/PCSC/winscard.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2003
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: winscard.h 2072 2006-06-06 09:31:07Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles smartcard reader communications.
+ */
+
+#ifndef __winscard_h__
+#define __winscard_h__
+
+#include <PCSC/pcsclite.h>
+#include <stdint.h>
+//#include "pcscexport.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef PCSC_API
+#define PCSC_API
+#endif
+
+	PCSC_API int32_t SCardEstablishContext(uint32_t dwScope,
+		const void *pvReserved1, const void *pvReserved2, LPSCARDCONTEXT phContext);
+
+	PCSC_API int32_t SCardReleaseContext(SCARDCONTEXT hContext);
+
+	PCSC_API int32_t SCardSetTimeout(SCARDCONTEXT hContext, uint32_t dwTimeout);
+
+	PCSC_API int32_t SCardConnect(SCARDCONTEXT hContext,
+		const char *szReader,
+		uint32_t dwShareMode,
+		uint32_t dwPreferredProtocols,
+		LPSCARDHANDLE phCard, uint32_t *pdwActiveProtocol);
+
+	PCSC_API int32_t SCardReconnect(SCARDHANDLE hCard,
+		uint32_t dwShareMode,
+		uint32_t dwPreferredProtocols,
+		uint32_t dwInitialization, uint32_t *pdwActiveProtocol);
+
+	PCSC_API int32_t SCardDisconnect(SCARDHANDLE hCard, uint32_t dwDisposition);
+
+	PCSC_API int32_t SCardBeginTransaction(SCARDHANDLE hCard);
+
+	PCSC_API int32_t SCardEndTransaction(SCARDHANDLE hCard, uint32_t dwDisposition);
+
+	PCSC_API int32_t SCardCancelTransaction(SCARDHANDLE hCard);
+
+	PCSC_API int32_t SCardStatus(SCARDHANDLE hCard,
+		char *mszReaderNames, uint32_t *pcchReaderLen,
+		uint32_t *pdwState,
+		uint32_t *pdwProtocol,
+		unsigned char *pbAtr, uint32_t *pcbAtrLen);
+
+	PCSC_API int32_t SCardGetStatusChange(SCARDCONTEXT hContext,
+		uint32_t dwTimeout,
+		LPSCARD_READERSTATE_A rgReaderStates, uint32_t cReaders);
+
+	PCSC_API int32_t SCardControl(SCARDHANDLE hCard,
+		const void *pbSendBuffer, uint32_t cbSendLength,
+		void *pbRecvBuffer, uint32_t *pcbRecvLength);
+
+	PCSC_API int32_t SCardControl132(SCARDHANDLE hCard, uint32_t dwControlCode,
+		const void *pbSendBuffer, uint32_t cbSendLength,
+		void *pbRecvBuffer, uint32_t cbRecvLength, uint32_t *lpBytesReturned);
+
+	PCSC_API int32_t SCardTransmit(SCARDHANDLE hCard,
+		LPCSCARD_IO_REQUEST pioSendPci,
+		const unsigned char *pbSendBuffer, uint32_t cbSendLength,
+		LPSCARD_IO_REQUEST pioRecvPci,
+		unsigned char *pbRecvBuffer, uint32_t *pcbRecvLength);
+
+	PCSC_API int32_t SCardListReaderGroups(SCARDCONTEXT hContext,
+		char *mszGroups, uint32_t *pcchGroups);
+
+	PCSC_API int32_t SCardListReaders(SCARDCONTEXT hContext,
+		const char *mszGroups,
+		char *mszReaders, uint32_t *pcchReaders);
+
+	PCSC_API int32_t SCardCancel(SCARDCONTEXT hContext);
+
+	PCSC_API int32_t SCardGetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId,
+		uint8_t *pbAttr, uint32_t *pcbAttrLen);
+
+	PCSC_API int32_t SCardSetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId,
+		const uint8_t *pbAttr, uint32_t cbAttrLen);
+
+	void SCardUnload(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+	To support the newer version of SCardControl, we define it
+	as follows. The old version number was 1.1.2, the new call
+	appears in 1.3.2 of pcsc-lite (or perhaps earlier).
+*/
+
+#if !defined(USE_SCARD_CONTROL_112)
+#define SCardControl SCardControl132
+#endif /* USE_SCARD_CONTROL_112 */
+
+#endif
+

Added: trunk/SmartCardServices/src/PCSC/winscard_clnt.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard_clnt.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard_clnt.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,3385 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  winscard_clnt.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Damien Sauveron <damien.sauveron at labri.fr>
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: winscard_clnt.c 2377 2007-02-05 13:13:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This handles smartcard reader communications and
+ * forwarding requests over message queues.
+ *
+ * Here is exposed the API for client applications.
+ */
+
+#include <assert.h>
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/_endian.h>
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "pcscexport.h"
+#include "winscard.h"
+#include "debug.h"
+#include "thread_generic.h"
+
+#include "readerfactory.h"
+#include "eventhandler.h"
+#include "sys_generic.h"
+#include "winscard_msg.h"
+#include "readerstate.h"
+
+#include <security_utilities/debugging.h>
+
+/** used for backward compatibility */
+#define SCARD_PROTOCOL_ANY_OLD	0x1000
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define PROFILE_START
+#define PROFILE_END
+
+/**
+ * Represents an Application Context Channel.
+ * A channel belongs to an Application Context (\c _psContextMap).
+ */
+struct _psChannelMap
+{
+	SCARDHANDLE hCard;
+	LPSTR readerName;
+};
+
+typedef struct _psChannelMap CHANNEL_MAP, *PCHANNEL_MAP;
+
+/**
+ * @brief Represents the an Application Context on the Client side.
+ *
+ * An Application Context contains Channels (\c _psChannelMap).
+ */
+static struct _psContextMap
+{
+	DWORD dwClientID;				/** Client Connection ID */
+	SCARDCONTEXT hContext;			/** Application Context ID */
+	DWORD contextBlockStatus;
+	PCSCLITE_MUTEX_T mMutex;		/** Mutex for this context */
+	CHANNEL_MAP psChannelMap[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS];
+} psContextMap[PCSCLITE_MAX_APPLICATION_CONTEXTS];
+
+/**
+ * Make sure the initialization code is executed only once.
+ */
+static short isExecuted = 0;
+
+/**
+ * Memory mapped address used to read status information about the readers.
+ * Each element in the vector \ref readerStates makes references to a part of
+ * the memory mapped.
+ */
+static int mapAddr = 0;
+
+/**
+ * Ensure that some functions be accessed in thread-safe mode.
+ * These function's names finishes with "TH".
+ */
+static PCSCLITE_MUTEX clientMutex = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Pointers to a memory mapped area used to read status information about the
+ * readers.
+ * Each element in the vector \ref readerStates makes references to a part of
+ * the memory mapped \ref mapAddr.
+ */
+static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
+
+PCSC_API SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 };
+PCSC_API SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 };
+PCSC_API SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 };
+
+
+static LONG SCardAddContext(SCARDCONTEXT, DWORD);
+static LONG SCardGetContextIndice(SCARDCONTEXT);
+static LONG SCardGetContextIndiceTH(SCARDCONTEXT);
+static LONG SCardRemoveContext(SCARDCONTEXT);
+
+static LONG SCardAddHandle(SCARDHANDLE, DWORD, LPSTR);
+static LONG SCardGetIndicesFromHandle(SCARDHANDLE, PDWORD, PDWORD);
+static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE, PDWORD, PDWORD);
+static LONG SCardRemoveHandle(SCARDHANDLE);
+
+static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
+	LPBYTE pbAttr, LPDWORD pcbAttrLen);
+
+static LONG SCardCheckDaemonAvailability(void);
+static int SCardInitializeOnce();
+
+/*
+ * Thread safety functions
+ */
+inline static LONG SCardLockThread(void);
+inline static LONG SCardUnlockThread(void);
+
+static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT);
+
+/**
+ * @brief Creates an Application Context to the PC/SC Resource Manager.
+
+ * This must be the first function called in a PC/SC application.
+ * This is a thread-safe wrapper to the function SCardEstablishContextTH().
+ *
+ * @param[in] dwScope Scope of the establishment.
+ * This can either be a local or remote connection.
+ * <ul>
+ *   <li>\ref SCARD_SCOPE_USER - Not used.
+ *   <li>\ref SCARD_SCOPE_TERMINAL - Not used.
+ *   <li>\ref SCARD_SCOPE_GLOBAL - Not used.
+ *   <li>\ref SCARD_SCOPE_SYSTEM - Services on the local machine.
+ * </ul>
+ * @param[in] pvReserved1 Reserved for future use. Can be used for remote connection.
+ * @param[in] pvReserved2 Reserved for future use.
+ * @param[out] phContext Returned Application Context.
+ *
+ * @return Connection status.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_NO_SERVICE The server is not runing (\ref SCARD_E_NO_SERVICE)
+ * @retval SCARD_E_INVALID_VALUE Invalid scope type passed (\ref SCARD_E_INVALID_VALUE )
+ * @retval SCARD_E_INVALID_PARAMETER phContext is null (\ref SCARD_E_INVALID_PARAMETER)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * @endcode
+ */
+LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
+	LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
+{
+	LONG rv;
+
+	PROFILE_START
+
+	SCardLockThread();
+	rv = SCardEstablishContextTH(dwScope, pvReserved1,
+		pvReserved2, phContext);
+	SCardUnlockThread();
+
+	PROFILE_END
+
+	return rv;
+}
+
+/**
+ * @brief Creates a communication context to the PC/SC Resource
+ * Manager.
+ *
+ * This function shuld not be called directly. Instead, the thread-safe
+ * function SCardEstablishContext() should be called.
+ *
+ * @param[in] dwScope Scope of the establishment.
+ * This can either be a local or remote connection.
+ * <ul>
+ *   <li>\ref SCARD_SCOPE_USER - Not used.
+ *   <li>\ref SCARD_SCOPE_TERMINAL - Not used.
+ *   <li>\ref SCARD_SCOPE_GLOBAL - Not used.
+ *   <li>\ref SCARD_SCOPE_SYSTEM - Services on the local machine.
+ * </ul>
+ * @param[in] pvReserved1 Reserved for future use. Can be used for remote connection.
+ * @param[in] pvReserved2 Reserved for future use.
+ * @param[out] phContext Returned reference to this connection.
+ *
+ * @return Connection status.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_NO_SERVICE The server is not runing (\ref SCARD_E_NO_SERVICE)
+ * @retval SCARD_E_INVALID_PARAMETER phContext is null. (\ref SCARD_E_INVALID_PARAMETER)
+ * @retval SCARD_E_INVALID_VALUE Invalid scope type passed (\ref SCARD_E_INVALID_VALUE)
+ */
+static LONG SCardEstablishContextTH(DWORD dwScope, LPCVOID pvReserved1,
+	LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
+{
+	LONG rv;
+	establish_struct scEstablishStruct;
+	sharedSegmentMsg msgStruct;
+	DWORD dwClientID = 0;
+
+	if (phContext == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+	else
+		*phContext = 0;
+
+	/* Check if the server is running */
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Do this only once:
+	 * - Initialize debug of need.
+	 * - Set up the memory mapped structures for reader states.
+	 * - Allocate each reader structure.
+	 * - Initialize context struct.
+	 */
+	if (isExecuted == 0)
+	{
+		SCardInitializeOnce();
+		isExecuted = 1;
+	}
+
+	/* Establishes a connection to the server */
+	if (SHMClientSetupSession(&dwClientID) != 0)
+	{
+		SYS_CloseFile(mapAddr);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	{	/* exchange client/server protocol versions */
+		sharedSegmentMsg msgStruct;
+		version_struct *veStr = (version_struct *)&msgStruct.data;
+		veStr->major = PROTOCOL_VERSION_MAJOR;
+		veStr->minor = PROTOCOL_VERSION_MINOR;
+		htonlVersionStruct(veStr);
+
+		if (-1 == WrapSHMWrite(CMD_VERSION, dwClientID, sizeof(version_struct), PCSCLITE_CLIENT_ATTEMPTS, veStr))
+			return SCARD_E_NO_SERVICE;
+
+		/*
+		 * Read a message from the server
+		 */
+		if (-1 == SHMClientReadMessage(&msgStruct, dwClientID, sizeof(version_struct), PCSCLITE_CLIENT_ATTEMPTS))
+		{
+			Log1(PCSC_LOG_ERROR, "Your pcscd is too old and does not support CMD_VERSION");
+			return SCARD_F_COMM_ERROR;
+		}
+
+		ntohlVersionStruct(veStr);
+		Log3(PCSC_LOG_ERROR, "Server is protocol version %d:%d",
+			veStr->major, veStr->minor);
+
+		if (veStr->rv != SCARD_S_SUCCESS)
+			return veStr->rv;
+	}
+
+	if (dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL &&
+		dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL)
+	{
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	/*
+	 * Try to establish an Application Context with the server
+	 */
+	scEstablishStruct.dwScope = dwScope;
+	scEstablishStruct.phContext = 0;
+	scEstablishStruct.rv = 0;
+
+	htonlEstablishStruct(&scEstablishStruct);
+	rv = WrapSHMWrite(SCARD_ESTABLISH_CONTEXT, dwClientID,
+		sizeof(scEstablishStruct), PCSCLITE_MCLIENT_ATTEMPTS,
+		(void *) &scEstablishStruct);
+
+	if (rv == -1)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Read the response from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, dwClientID, sizeof(establish_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+	if (rv == -1)
+		return SCARD_F_COMM_ERROR;
+
+	memcpy(&scEstablishStruct, &msgStruct.data, sizeof(scEstablishStruct));
+	ntohlEstablishStruct(&scEstablishStruct);
+	
+	if (scEstablishStruct.rv != SCARD_S_SUCCESS)
+		return scEstablishStruct.rv;
+
+	*phContext = scEstablishStruct.phContext;
+
+	/*
+	 * Allocate the new hContext - if allocator full return an error
+	 */
+	rv = SCardAddContext(*phContext, dwClientID);
+
+	return rv;
+}
+
+/**
+ * @brief This function destroys a communication context to the PC/SC Resource
+ * Manager. This must be the last function called in a PC/SC application.
+ *
+ * @param[in] hContext Connection context to be closed.
+ *
+ * @return Connection status.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardReleaseContext(hContext);
+ * @endcode
+ */
+LONG SCardReleaseContext(SCARDCONTEXT hContext)
+{
+	LONG rv;
+	release_struct scReleaseStruct;
+	sharedSegmentMsg msgStruct;
+	LONG dwContextIndex;
+
+	PROFILE_START
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this context has been opened
+	 */
+	dwContextIndex = SCardGetContextIndice(hContext);
+	if (dwContextIndex == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	scReleaseStruct.hContext = hContext;
+	scReleaseStruct.rv = 0;
+	htonlReleaseStruct(&scReleaseStruct);
+	
+	rv = WrapSHMWrite(SCARD_RELEASE_CONTEXT, psContextMap[dwContextIndex].dwClientID,
+			  sizeof(scReleaseStruct),
+			  PCSCLITE_MCLIENT_ATTEMPTS, (void *) &scReleaseStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	/*
+	 * Read a message from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(release_struct), PCSCLITE_CLIENT_ATTEMPTS);
+	memcpy(&scReleaseStruct, &msgStruct.data, sizeof(scReleaseStruct));
+	ntohlReleaseStruct(&scReleaseStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_F_COMM_ERROR;
+	}
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	/*
+	 * Remove the local context from the stack
+	 */
+	SCardLockThread();
+	SCardRemoveContext(hContext);
+	SCardUnlockThread();
+
+	PROFILE_END
+
+	return scReleaseStruct.rv;
+}
+
+/**
+ * @deprecated
+ * This function is not in Microsoft(R) WinSCard API and is deprecated
+ * in pcsc-lite API.
+ * The function does not do anything except returning \ref SCARD_S_SUCCESS.
+ *
+ * @param[in] hContext Connection context to the PC/SC Resource Manager.
+ * @param[in] dwTimeout New timeout value.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ */
+LONG SCardSetTimeout(SCARDCONTEXT hContext, DWORD dwTimeout)
+{
+	/*
+	 * Deprecated
+	 */
+
+	return SCARD_S_SUCCESS;
+}
+
+/**
+ * This function establishes a connection to the friendly name of the reader
+ * specified in szReader. The first connection will power up and perform a
+ * reset on the card.
+ *
+ * @param[in] hContext Connection context to the PC/SC Resource Manager.
+ * @param[in] szReader Reader name to connect to.
+ * @param[in] dwShareMode Mode of connection type: exclusive or shared.
+ * <ul>
+ *   <li>\ref SCARD_SHARE_SHARED - This application will allow others to share
+ *   the reader.
+ *   <li>\ref SCARD_SHARE_EXCLUSIVE - This application will NOT allow others to
+ *   share the reader.
+ *   <li>\ref SCARD_SHARE_DIRECT - Direct control of the reader, even without a
+ *   card.  \ref SCARD_SHARE_DIRECT can be used before using SCardControl() to
+ *   send control commands to the reader even if a card is not present in the
+ *   reader.
+ * </ul>
+ * @param[in] dwPreferredProtocols Desired protocol use.
+ * <ul>
+ *   <li>\ref SCARD_PROTOCOL_T0 - Use the T=0 protocol.
+ *   <li>\ref SCARD_PROTOCOL_T1 - Use the T=1 protocol.
+ *   <li>\ref SCARD_PROTOCOL_RAW - Use with memory type cards.
+ * </ul>
+ * dwPreferredProtocols is a bit mask of acceptable protocols for the
+ * connection. You can use (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) if you
+ * do not have a preferred protocol.
+ * @param[out] phCard Handle to this connection.
+ * @param[out] pdwActiveProtocol Established protocol to this connection.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid hContext handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_INVALID_VALUE Invalid sharing mode, requested protocol, or reader name (\ref SCARD_E_INVALID_VALUE)
+ * @retval SCARD_E_NOT_READY Could not allocate the desired port (\ref SCARD_E_NOT_READY)
+ * @retval SCARD_E_READER_UNAVAILABLE Could not power up the reader or card (\ref SCARD_E_READER_UNAVAILABLE)
+ * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION)
+ * @retval SCARD_E_UNSUPPORTED_FEATURE Protocol not supported (\ref SCARD_E_UNSUPPORTED_FEATURE)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
+ * @endcode
+ */
+LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
+	DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
+	LPDWORD pdwActiveProtocol)
+{
+	LONG rv;
+	connect_struct scConnectStruct = {0,};
+	sharedSegmentMsg msgStruct = {0,};
+	LONG dwContextIndex;
+
+	PROFILE_START
+
+	/*
+	 * Check for NULL parameters
+	 */
+	if (phCard == NULL || pdwActiveProtocol == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+	else
+		*phCard = 0;
+
+	if (szReader == NULL)
+		return SCARD_E_UNKNOWN_READER;
+
+	/*
+	 * Check for uninitialized strings
+	 */
+	if (strlen(szReader) > MAX_READERNAME)
+		return SCARD_E_INVALID_VALUE;
+
+	if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
+		!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
+		!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
+		!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
+	{
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this context has been opened
+	 */
+	dwContextIndex = SCardGetContextIndice(hContext);
+	if (dwContextIndex == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME);
+
+	scConnectStruct.hContext = hContext;
+	scConnectStruct.dwShareMode = dwShareMode;
+	scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
+	scConnectStruct.phCard = *phCard;
+	scConnectStruct.pdwActiveProtocol = *pdwActiveProtocol;
+	htonlConnectStruct(&scConnectStruct);
+	
+	rv = WrapSHMWrite(SCARD_CONNECT, psContextMap[dwContextIndex].dwClientID,
+		sizeof(scConnectStruct),
+		PCSCLITE_CLIENT_ATTEMPTS, (void *) &scConnectStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	/*
+	 * Read a message from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(connect_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+	memcpy(&scConnectStruct, &msgStruct.data, sizeof(scConnectStruct));
+	ntohlConnectStruct(&scConnectStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_F_COMM_ERROR;
+	}
+
+	*phCard = scConnectStruct.phCard;
+	*pdwActiveProtocol = scConnectStruct.pdwActiveProtocol;
+
+	if (scConnectStruct.rv == SCARD_S_SUCCESS)
+	{
+		/*
+		 * Keep track of the handle locally
+		 */
+		rv = SCardAddHandle(*phCard, dwContextIndex, (LPSTR) szReader);
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+		PROFILE_END
+
+		return rv;
+	}
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return scConnectStruct.rv;
+}
+
+/**
+ * @brief This function reestablishes a connection to a reader that was previously
+ * connected to using SCardConnect().
+ *
+ * In a multi application environment it is possible for an application to reset
+ * the card in shared mode. When this occurs any other application trying to
+ * access certain commands will be returned the value SCARD_W_RESET_CARD. When
+ * this occurs SCardReconnect() must be called in order to acknowledge that
+ * the card was reset and allow it to change it's state accordingly.
+ *
+ * @param[in] hCard Handle to a previous call to connect.
+ * @param[in] dwShareMode Mode of connection type: exclusive/shared.
+ * <ul>
+ *   <li>\ref SCARD_SHARE_SHARED - This application will allow others to share
+ *   the reader.
+ *   <li>\ref SCARD_SHARE_EXCLUSIVE - This application will NOT allow others to
+ *   share the reader.
+ * </ul>
+ * @param[in] dwPreferredProtocols Desired protocol use.
+ * <ul>
+ *   <li>\ref SCARD_PROTOCOL_T0 - Use the T=0 protocol.
+ *   <li>\ref SCARD_PROTOCOL_T1 - Use the T=1 protocol.
+ *   <li>\ref SCARD_PROTOCOL_RAW - Use with memory type cards.
+ * </ul>
+ * \p dwPreferredProtocols is a bit mask of acceptable protocols for
+ * the connection. You can use (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)
+ * if you do not have a preferred protocol.
+ * @param[in] dwInitialization Desired action taken on the card/reader.
+ * <ul>
+ *   <li>\ref SCARD_LEAVE_CARD - Do nothing.
+ *   <li>\ref SCARD_RESET_CARD - Reset the card (warm reset).
+ *   <li>\ref SCARD_UNPOWER_CARD - Unpower the card (cold reset).
+ *   <li>\ref SCARD_EJECT_CARD - Eject the card.
+ * </ul>
+ * @param[out] pdwActiveProtocol Established protocol to this connection.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_NOT_READY Could not allocate the desired port (\ref SCARD_E_NOT_READY)
+ * @retval SCARD_E_INVALID_VALUE Invalid sharing mode, requested protocol, or reader name (\ref SCARD_E_INVALID_VALUE)
+ * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
+ * @retval SCARD_E_UNSUPPORTED_FEATURE Protocol not supported (\ref SCARD_E_UNSUPPORTED_FEATURE)
+ * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol, dwSendLength, dwRecvLength;
+ * LONG rv;
+ * BYTE pbRecvBuffer[10];
+ * BYTE pbSendBuffer[] = {0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00};
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
+ * ...
+ * dwSendLength = sizeof(pbSendBuffer);
+ * dwRecvLength = sizeof(pbRecvBuffer);
+ * rv = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, dwSendLength, &pioRecvPci, pbRecvBuffer, &dwRecvLength);
+ * / * Card has been reset by another application * /
+ * if (rv == SCARD_W_RESET_CARD)
+ * {
+ *   rv = SCardReconnect(hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &dwActiveProtocol);
+ * }
+ * @endcode
+ */
+LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
+	DWORD dwPreferredProtocols, DWORD dwInitialization,
+	LPDWORD pdwActiveProtocol)
+{
+	LONG rv;
+	reconnect_struct scReconnectStruct;
+	sharedSegmentMsg msgStruct;
+	int i;
+	DWORD dwContextIndex, dwChannelIndex;
+
+	PROFILE_START
+
+	if (dwInitialization != SCARD_LEAVE_CARD &&
+		dwInitialization != SCARD_RESET_CARD &&
+		dwInitialization != SCARD_UNPOWER_CARD &&
+		dwInitialization != SCARD_EJECT_CARD)
+	{
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
+		!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
+		!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
+		!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
+	{
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	if (pdwActiveProtocol == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
+		/* by default r == NULL */
+		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_READER_UNAVAILABLE;
+	}
+
+	scReconnectStruct.hCard = hCard;
+	scReconnectStruct.dwShareMode = dwShareMode;
+	scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
+	scReconnectStruct.dwInitialization = dwInitialization;
+	scReconnectStruct.pdwActiveProtocol = *pdwActiveProtocol;
+	htonlReconnectStruct(&scReconnectStruct);
+
+	rv = WrapSHMWrite(SCARD_RECONNECT, psContextMap[dwContextIndex].dwClientID,
+		sizeof(scReconnectStruct),
+		PCSCLITE_CLIENT_ATTEMPTS, (void *) &scReconnectStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	/*
+	 * Read a message from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(reconnect_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+	memcpy(&scReconnectStruct, &msgStruct.data, sizeof(scReconnectStruct));
+	ntohlReconnectStruct(&scReconnectStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_F_COMM_ERROR;
+	}
+
+	*pdwActiveProtocol = scReconnectStruct.pdwActiveProtocol;
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return scReconnectStruct.rv;
+}
+
+/**
+ * This function terminates a connection to the connection made through
+ * SCardConnect(). dwDisposition can have the following values:
+ *
+ * @param[in] hCard Connection made from SCardConnect.
+ * @param[in] dwDisposition Reader function to execute.
+ * <ul>
+ *   <li>\ref SCARD_LEAVE_CARD - Do nothing.
+ *   <li>\ref SCARD_RESET_CARD - Reset the card (warm reset).
+ *   <li>\ref SCARD_UNPOWER_CARD - Unpower the card (cold reset).
+ *   <li>\ref SCARD_EJECT_CARD - Eject the card.
+ * </ul>
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful(\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_INVALID_VALUE - Invalid \p dwDisposition (\ref SCARD_E_INVALID_VALUE)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
+ * rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
+ * @endcode
+ */
+LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+	LONG rv;
+	disconnect_struct scDisconnectStruct;
+	sharedSegmentMsg msgStruct;
+	DWORD dwContextIndex, dwChannelIndex;
+
+	PROFILE_START
+
+	if (dwDisposition != SCARD_LEAVE_CARD &&
+		dwDisposition != SCARD_RESET_CARD &&
+		dwDisposition != SCARD_UNPOWER_CARD &&
+		dwDisposition != SCARD_EJECT_CARD)
+	{
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	scDisconnectStruct.hCard = hCard;
+	scDisconnectStruct.dwDisposition = dwDisposition;
+	htonlDisconnectStruct(&scDisconnectStruct);
+	
+	rv = WrapSHMWrite(SCARD_DISCONNECT, psContextMap[dwContextIndex].dwClientID,
+		sizeof(scDisconnectStruct),
+		PCSCLITE_CLIENT_ATTEMPTS, (void *) &scDisconnectStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	/*
+	 * Read a message from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(disconnect_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+	memcpy(&scDisconnectStruct, &msgStruct.data, sizeof(scDisconnectStruct));
+	ntohlDisconnectStruct(&scDisconnectStruct);
+	
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_F_COMM_ERROR;
+	}
+
+	SCardRemoveHandle(hCard);
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return scDisconnectStruct.rv;
+}
+
+/**
+ * @brief This function establishes a temporary exclusive access mode for
+ * doing a series of commands or transaction.
+ *
+ * You might want to use this when you are selecting a few files and then
+ * writing a large file so you can make sure that another application will
+ * not change the current file. If another application has a lock on this
+ * reader or this application is in \ref SCARD_SHARE_EXCLUSIVE there will be no
+ * action taken.
+ *
+ * @param[in] hCard Connection made from SCardConnect.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION)
+ * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
+ * rv = SCardBeginTransaction(hCard);
+ * ...
+ * / * Do some transmit commands * /
+ * @endcode
+ */
+LONG SCardBeginTransaction(SCARDHANDLE hCard)
+{
+
+	LONG rv;
+	begin_struct txBeginStruct = {0,}, rxBeginStruct = {0,};
+	int i;
+	sharedSegmentMsg msgStruct = {0,};
+	DWORD dwContextIndex, dwChannelIndex;
+
+	PROFILE_START
+
+	secdebug("pcscd", "SCardBeginTransaction: initial request: hCard: 0x%08X", hCard);
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
+
+		/* by default r == NULL */
+		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_READER_UNAVAILABLE;
+	}
+
+	txBeginStruct.hCard = hCard;
+	htonlBeginStruct(&txBeginStruct);
+
+	/*
+	 * Query the server every so often until the sharing violation ends
+	 * and then hold the lock for yourself.
+	 */
+
+	do
+	{
+		rv = WrapSHMWrite(SCARD_BEGIN_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
+			sizeof(txBeginStruct),
+			PCSCLITE_CLIENT_ATTEMPTS, (void *) &txBeginStruct);
+
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_E_NO_SERVICE;
+		}
+
+		/*
+		 * Read a message from the server
+		 */
+		rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(begin_struct), PCSCLITE_CLIENT_ATTEMPTS);
+		memcpy(&rxBeginStruct, &msgStruct.data, sizeof(rxBeginStruct));
+		ntohlBeginStruct(&rxBeginStruct);
+
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_F_COMM_ERROR;
+		}
+
+	}
+	while (rxBeginStruct.rv == SCARD_E_SHARING_VIOLATION);
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+	secdebug("pcscd", "SCardBeginTransaction: hCard: 0x%08X, returning: 0x%08X", rxBeginStruct.hCard, rxBeginStruct.rv);
+
+	return rxBeginStruct.rv;
+}
+
+/**
+ * @brief This function ends a previously begun transaction.
+ *
+ * The calling application must be the owner of the previously begun
+ * transaction or an error will occur.
+ *
+ * @param[in] hCard Connection made from SCardConnect.
+ * @param[in] dwDisposition Action to be taken on the reader.
+ * The disposition action is not currently used in this release.
+ * <ul>
+ *   <li>\ref SCARD_LEAVE_CARD - Do nothing.
+ *   <li>\ref SCARD_RESET_CARD - Reset the card.
+ *   <li>\ref SCARD_UNPOWER_CARD - Unpower the card.
+ *   <li>\ref SCARD_EJECT_CARD - Eject the card.
+ * </ul>
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION)
+ * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
+ * rv = SCardBeginTransaction(hCard);
+ * ...
+ * / * Do some transmit commands * /
+ * ...
+ * rv = SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
+ * @endcode
+ */
+LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+	LONG rv;
+	end_struct scEndStruct;
+	sharedSegmentMsg msgStruct;
+	int randnum, i;
+	DWORD dwContextIndex, dwChannelIndex;
+
+	PROFILE_START
+
+	secdebug("pcscd", "SCardEndTransaction: initial request: hCard: 0x%08X, dwDisposition: 0x%04X", 
+			hCard, dwDisposition);
+	/*
+	 * Zero out everything
+	 */
+	randnum = 0;
+
+	if (dwDisposition != SCARD_LEAVE_CARD &&
+		dwDisposition != SCARD_RESET_CARD &&
+		dwDisposition != SCARD_UNPOWER_CARD &&
+		dwDisposition != SCARD_EJECT_CARD)
+	{
+		return SCARD_E_INVALID_VALUE;
+	}
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
+
+		/* by default r == NULL */
+		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_READER_UNAVAILABLE;
+	}
+
+	scEndStruct.hCard = hCard;
+	scEndStruct.dwDisposition = dwDisposition;
+	htonlEndStruct(&scEndStruct);
+	
+	rv = WrapSHMWrite(SCARD_END_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
+		sizeof(scEndStruct),
+		PCSCLITE_CLIENT_ATTEMPTS, (void *) &scEndStruct);
+	secdebug("pcscd", "SCardEndTransaction: WrapSHMWrite result: 0x%08X", rv);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	/*
+	 * Read a message from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(end_struct), PCSCLITE_CLIENT_ATTEMPTS);
+	secdebug("pcscd", "SCardEndTransaction: SHMClientRead result: 0x%08X", rv);
+
+	memcpy(&scEndStruct, &msgStruct.data, sizeof(scEndStruct));
+	ntohlEndStruct(&scEndStruct);
+	
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_F_COMM_ERROR;
+	}
+
+	/*
+	 * This helps prevent starvation
+	 */
+	randnum = SYS_Random(randnum, 1000.0, 10000.0);
+	SYS_USleep(randnum);
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	secdebug("pcscd", "SCardEndTransaction: returning: 0x%08X", scEndStruct.rv);
+	return scEndStruct.rv;
+}
+
+/**
+ * @deprecated
+ * This function is not in Microsoft(R) WinSCard API and is deprecated
+ * in pcsc-lite API.
+ */
+LONG SCardCancelTransaction(SCARDHANDLE hCard)
+{
+	LONG rv;
+	cancel_struct scCancelStruct;
+	sharedSegmentMsg msgStruct;
+	int i;
+	DWORD dwContextIndex, dwChannelIndex;
+
+	PROFILE_START
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
+
+		/* by default r == NULL */
+		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_READER_UNAVAILABLE;
+	}
+
+	scCancelStruct.hCard = hCard;
+	htonlCancelStruct(&scCancelStruct);
+	
+	rv = WrapSHMWrite(SCARD_CANCEL_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
+		sizeof(scCancelStruct),
+		PCSCLITE_CLIENT_ATTEMPTS, (void *) &scCancelStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	/*
+	 * Read a message from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(cancel_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+	memcpy(&scCancelStruct, &msgStruct.data, sizeof(scCancelStruct));
+	ntohlCancelStruct(&scCancelStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_F_COMM_ERROR;
+	}
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return scCancelStruct.rv;
+}
+
+/**
+ * @brief This function returns the current status of the reader connected to by hCard.
+ *
+ * It's friendly name will be stored in szReaderName. pcchReaderLen will be
+ * the size of the allocated buffer for szReaderName, while pcbAtrLen will
+ * be the size of the allocated buffer for pbAtr. If either of these is too
+ * small, the function will return with \ref SCARD_E_INSUFFICIENT_BUFFER and the
+ * necessary size in pcchReaderLen and pcbAtrLen. The current state, and
+ * protocol will be stored in pdwState and pdwProtocol respectively.
+ *
+ * @param[in] hCard Connection made from SCardConnect.
+ * @param mszReaderNames [inout] Friendly name of this reader.
+ * @param pcchReaderLen [inout] Size of the szReaderName multistring.
+ * @param[out] pdwState Current state of this reader. pdwState
+ * is a DWORD possibly OR'd with the following values:
+ * <ul>
+ *   <li>\ref SCARD_ABSENT - There is no card in the reader.
+ *   <li>\ref SCARD_PRESENT - There is a card in the reader, but it has not
+ *       been moved into position for use.
+ *   <li>\ref SCARD_SWALLOWED - There is a card in the reader in position for
+ *       use.  The card is not powered.
+ *   <li>\ref SCARD_POWERED - Power is being provided to the card, but the
+ *       reader driver is unaware of the mode of the card.
+ *   <li>\ref SCARD_NEGOTIABLE - The card has been reset and is awaiting PTS
+ *       negotiation.
+ *   <li>\ref SCARD_SPECIFIC - The card has been reset and specific
+ *       communication protocols have been established.
+ * </ul>
+ * @param[out] pdwProtocol Current protocol of this reader.
+ * <ul>
+ *   <li>\ref SCARD_PROTOCOL_T0 	Use the T=0 protocol.
+ *   <li>\ref SCARD_PROTOCOL_T1 	Use the T=1 protocol.
+ * </ul>
+ * @param[out] pbAtr Current ATR of a card in this reader.
+ * @param[out] pcbAtrLen Length of ATR.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_INSUFFICIENT_BUFFER Not enough allocated memory for szReaderName or for pbAtr (\ref SCARD_E_INSUFFICIENT_BUFFER)
+ * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol;
+ * DWORD dwState, dwProtocol, dwAtrLen, dwReaderLen;
+ * BYTE pbAtr[MAX_ATR_SIZE];
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
+ * ...
+ * dwAtrLen = sizeof(pbAtr);
+ * rv=SCardStatus(hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen);
+ * @endcode
+ */
+LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderNames,
+	LPDWORD pcchReaderLen, LPDWORD pdwState,
+	LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+	DWORD dwReaderLen, atrOutputBufferSize;
+	LONG rv;
+	int i;
+	status_struct scStatusStruct;
+	sharedSegmentMsg msgStruct;
+	DWORD dwContextIndex, dwChannelIndex;
+	char *r;
+
+	PROFILE_START
+
+	/*
+	 * Check for NULL parameters
+	 */
+
+	if (pcchReaderLen == NULL || pcbAtrLen == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+
+	/* length passed from caller */
+	dwReaderLen = *pcchReaderLen;
+	atrOutputBufferSize = *pcbAtrLen;
+
+	/* default output values */
+	if (pdwState)
+		*pdwState = 0;
+
+	if (pdwProtocol)
+		*pdwProtocol = 0;
+
+	*pcchReaderLen = 0;
+	*pcbAtrLen = 0;
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		/* by default r == NULL */
+		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_READER_UNAVAILABLE;
+	}
+
+	/* initialise the structure */
+	memset(&scStatusStruct, 0, sizeof(scStatusStruct));
+	scStatusStruct.hCard = hCard;
+
+	/* those sizes need to be initialised */
+	scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames);
+	scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr);
+	htonlStatusStruct(&scStatusStruct);
+	
+	rv = WrapSHMWrite(SCARD_STATUS, psContextMap[dwContextIndex].dwClientID,
+		sizeof(scStatusStruct),
+		PCSCLITE_CLIENT_ATTEMPTS, (void *) &scStatusStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	/*
+	 * Read a message from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(status_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+	memcpy(&scStatusStruct, &msgStruct.data, sizeof(scStatusStruct));
+	ntohlStatusStruct(&scStatusStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_F_COMM_ERROR;
+	}
+
+	rv = scStatusStruct.rv;
+	if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
+	{
+		/*
+		 * An event must have occurred
+		 */
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return rv;
+	}
+
+	/*
+	 * Now continue with the client side SCardStatus
+	 */
+
+	*pcchReaderLen = strlen(psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName) + 1;
+	*pcbAtrLen = SharedReaderState_CardAtrLength(readerStates[i]);
+
+	if (pdwState)
+		*pdwState = SharedReaderState_State(readerStates[i]);
+
+	if (pdwProtocol)
+		*pdwProtocol = SharedReaderState_Protocol(readerStates[i]);
+
+	/* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
+	if (mszReaderNames)
+	{
+		if (*pcchReaderLen > dwReaderLen)
+			rv = SCARD_E_INSUFFICIENT_BUFFER;
+
+		strncpy(mszReaderNames,
+			psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName,
+			dwReaderLen);
+	}
+
+	if (pbAtr)
+	{
+		if (*pcbAtrLen > atrOutputBufferSize)
+			rv = SCARD_E_INSUFFICIENT_BUFFER;
+
+		memcpy(pbAtr, SharedReaderState_CardAtr(readerStates[i]),
+			min(*pcbAtrLen, atrOutputBufferSize));
+	}
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return rv;
+}
+
+/**
+ * @brief This function receives a structure or list of structures containing
+ * reader names. It then blocks for a change in state to occur on any of the
+ * OR'd values contained in dwCurrentState for a maximum blocking time of
+ * dwTimeout or forever if INFINITE is used.
+ *
+ * The new event state will be contained in dwEventState. A status change might
+ * be a card insertion or removal event, a change in ATR, etc.
+ *
+ * This function will block for reader availability if cReaders is equal to
+ * zero and rgReaderStates is NULL.
+ *
+ * @code
+ * typedef struct {
+ *   LPCSTR szReader;          // Reader name
+ *   LPVOID pvUserData;         // User defined data
+ *   DWORD dwCurrentState;      // Current state of reader
+ *   DWORD dwEventState;        // Reader state after a state change
+ *   DWORD cbAtr;               // ATR Length, usually MAX_ATR_SIZE
+ *   BYTE rgbAtr[MAX_ATR_SIZE]; // ATR Value
+ * } SCARD_READERSTATE;
+ * ...
+ * typedef SCARD_READERSTATE *PSCARD_READERSTATE, **LPSCARD_READERSTATE;
+ * ...
+ * @endcode
+ *
+ * Value of dwCurrentState and dwEventState:
+ * <ul>
+ *   <li>\ref SCARD_STATE_UNAWARE The application is unaware of the current
+ *       state, and would like to know. The use of this value results in an
+ *       immediate return from state transition monitoring services. This is
+ *       represented by all bits set to zero.
+ *   <li>\ref SCARD_STATE_IGNORE This reader should be ignored
+ *   <li>\ref SCARD_STATE_CHANGED There is a difference between the state believed
+ *       by the application, and the state known by the resource manager.
+ *       When this bit is set, the application may assume a significant state
+ *       change has occurred on this reader.
+ *   <li>\ref SCARD_STATE_UNKNOWN The given reader name is not recognized by the
+ *       resource manager. If this bit is set, then \ref SCARD_STATE_CHANGED and
+ *       \ref SCARD_STATE_IGNORE will also be set
+ *   <li>\ref SCARD_STATE_UNAVAILABLE The actual state of this reader is not
+ *       available. If this bit is set, then all the following bits are clear.
+ *   <li>\ref SCARD_STATE_EMPTY There is no card in the reader. If this bit is set,
+ *       all the following bits will be clear
+ *   <li>\ref SCARD_STATE_PRESENT There is a card in the reader
+ *   <li>\ref SCARD_STATE_ATRMATCH There is a card in the reader with an ATR
+ *       matching one of the target cards. If this bit is set,
+ *       \ref SCARD_STATE_PRESENT will also be set. This bit is only returned on
+ *       the SCardLocateCards() function.
+ *   <li>\ref SCARD_STATE_EXCLUSIVE The card in the reader is allocated for
+ *       exclusive use by another application. If this bit is set,
+ *       \ref SCARD_STATE_PRESENT will also be set.
+ *   <li>\ref SCARD_STATE_INUSE The card in the reader is in use by one or more
+ *       other applications, but may be connected to in shared mode. If this
+ *       bit is set, \ref SCARD_STATE_PRESENT will also be set.
+ *   <li>\ref SCARD_STATE_MUTE There is an unresponsive card in the reader.
+ * </ul>
+ *
+ * @param[in] hContext Connection context to the PC/SC Resource Manager.
+ * @param[in] dwTimeout Maximum waiting time (in miliseconds) for status
+ *            change, zero (or INFINITE) for infinite.
+ * @param rgReaderStates [inout] Structures of readers with current states.
+ * @param[in] cReaders Number of structures.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_VALUE Invalid States, reader name, etc (\ref SCARD_E_INVALID_VALUE)
+ * @retval SCARD_E_INVALID_HANDLE Invalid hContext handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_READER_UNAVAILABLE The reader is unavailable (\ref SCARD_E_READER_UNAVAILABLE)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * SCARD_READERSTATE_A rgReaderStates[1];
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * ...
+ * rgReaderStates[0].szReader = "Reader X";
+ * rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
+ * ...
+ * rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
+ * printf("reader state: 0x%04X\n", rgReaderStates[0].dwEventState);
+ * @endcode
+ */
+LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
+	LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders)
+{
+	PSCARD_READERSTATE_A currReader;
+	PREADER_STATE rContext;
+	DWORD dwTime = 0;
+	DWORD dwState;
+	DWORD dwBreakFlag = 0;
+	int j;
+	LONG dwContextIndex;
+	int currentReaderCount = 0;
+
+	PROFILE_START
+
+	if (rgReaderStates == NULL && cReaders > 0)
+		return SCARD_E_INVALID_PARAMETER;
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this context has been opened
+	 */
+
+	dwContextIndex = SCardGetContextIndice(hContext);
+	if (dwContextIndex == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	/*
+	 * Application is waiting for a reader - return the first available
+	 * reader
+	 */
+
+	if (cReaders == 0)
+	{
+		while (1)
+		{
+			int i;
+
+			if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+			{
+				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+				return SCARD_E_NO_SERVICE;
+			}
+
+			for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+			{
+				if (SharedReaderState_ReaderID(readerStates[i]) != 0)
+				{
+					/*
+					 * Reader was found
+					 */
+					SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+					PROFILE_END
+
+					return SCARD_S_SUCCESS;
+				}
+			}
+
+			if (dwTimeout == 0)
+			{
+				/*
+				 * return immediately - no reader available
+				 */
+				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+				return SCARD_E_READER_UNAVAILABLE;
+			}
+
+			SYS_USleep(PCSCLITE_STATUS_WAIT);
+
+			if (dwTimeout != INFINITE)
+			{
+				dwTime += PCSCLITE_STATUS_WAIT;
+
+				if (dwTime >= (dwTimeout * 1000))
+				{
+					SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+					PROFILE_END
+
+					return SCARD_E_TIMEOUT;
+				}
+			}
+		}
+	}
+	else
+		if (cReaders >= PCSCLITE_MAX_READERS_CONTEXTS)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_E_INVALID_VALUE;
+		}
+
+	/*
+	 * Check the integrity of the reader states structures
+	 */
+
+	for (j = 0; j < cReaders; j++)
+	{
+		currReader = &rgReaderStates[j];
+
+		if (currReader->szReader == NULL)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_E_INVALID_VALUE;
+		}
+	}
+
+	/*
+	 * End of search for readers
+	 */
+
+	/*
+	 * Clear the event state for all readers
+	 */
+	for (j = 0; j < cReaders; j++)
+	{
+		currReader = &rgReaderStates[j];
+		currReader->dwEventState = 0;
+	}
+
+	/*
+	 * Now is where we start our event checking loop
+	 */
+
+	Log1(PCSC_LOG_DEBUG, "Event Loop Start");
+
+	psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_BLOCKING;
+
+	/* Get the initial reader count on the system */
+	for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
+		if (SharedReaderState_ReaderID(readerStates[j]) != 0)
+			currentReaderCount++;
+
+	j = 0;
+
+	do
+	{
+		int newReaderCount = 0;
+		char ReaderCountChanged = 0;
+
+		if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+			PROFILE_END
+
+			return SCARD_E_NO_SERVICE;
+		}
+
+		if (j == 0)
+		{
+			int i;
+
+			for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+				if (SharedReaderState_ReaderID(readerStates[i]) != 0)
+					newReaderCount++;
+
+			if (newReaderCount != currentReaderCount)
+			{
+				Log1(PCSC_LOG_INFO, "Reader list changed");
+				ReaderCountChanged = 1;
+				currentReaderCount = newReaderCount;
+			}
+		}
+		currReader = &rgReaderStates[j];
+
+	/************ Look for IGNORED readers ****************************/
+
+		if (currReader->dwCurrentState & SCARD_STATE_IGNORE)
+			currReader->dwEventState = SCARD_STATE_IGNORE;
+		else
+		{
+			LPSTR lpcReaderName;
+			int i;
+
+	  /************ Looks for correct readernames *********************/
+
+			lpcReaderName = (char *) currReader->szReader;
+
+			for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+			{
+				if (SharedReaderState_ReaderNameIsEqual(readerStates[i], lpcReaderName))
+					break;
+			}
+
+			/*
+			 * The requested reader name is not recognized
+			 */
+			if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+			{
+				if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
+					currReader->dwEventState = SCARD_STATE_UNKNOWN;
+				else
+				{
+					currReader->dwEventState =
+						SCARD_STATE_UNKNOWN | SCARD_STATE_CHANGED;
+					/*
+					 * Spec says use SCARD_STATE_IGNORE but a removed USB
+					 * reader with eventState fed into currentState will
+					 * be ignored forever
+					 */
+					dwBreakFlag = 1;
+				}
+			}
+			else
+			{
+
+				/*
+				 * The reader has come back after being away
+				 */
+				if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
+				{
+					currReader->dwEventState |= SCARD_STATE_CHANGED;
+					currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
+					dwBreakFlag = 1;
+				}
+
+	/*****************************************************************/
+
+				/*
+				 * Set the reader status structure
+				 */
+				rContext = readerStates[i];
+
+				/*
+				 * Now we check all the Reader States
+				 */
+				dwState = SharedReaderState_State(rContext);
+
+	/*********** Check if the reader is in the correct state ********/
+				if (dwState & SCARD_UNKNOWN)
+				{
+					/*
+					 * App thinks reader is in bad state and it is
+					 */
+					if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
+						currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
+					else
+					{
+						/*
+						 * App thinks reader is in good state and it is
+						 * not
+						 */
+						currReader->dwEventState = SCARD_STATE_CHANGED |
+							SCARD_STATE_UNAVAILABLE;
+						dwBreakFlag = 1;
+					}
+				}
+				else
+				{
+					/*
+					 * App thinks reader in bad state but it is not
+					 */
+					if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
+					{
+						currReader->dwEventState &=
+							~SCARD_STATE_UNAVAILABLE;
+						currReader->dwEventState |= SCARD_STATE_CHANGED;
+						dwBreakFlag = 1;
+					}
+				}
+
+	/********** Check for card presence in the reader **************/
+
+				if (dwState & SCARD_PRESENT)
+				{
+					/* card present but not yet powered up */
+					if (0 == SharedReaderState_CardAtrLength(rContext))
+						/* Allow the status thread to convey information */
+						SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
+
+					currReader->cbAtr = SharedReaderState_CardAtrLength(rContext);
+					memcpy(currReader->rgbAtr, SharedReaderState_CardAtr(rContext),
+						currReader->cbAtr);
+				}
+				else
+					currReader->cbAtr = 0;
+
+				/*
+				 * Card is now absent
+				 */
+				if (dwState & SCARD_ABSENT)
+				{
+					currReader->dwEventState |= SCARD_STATE_EMPTY;
+					currReader->dwEventState &= ~SCARD_STATE_PRESENT;
+					currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
+					currReader->dwEventState &= ~SCARD_STATE_IGNORE;
+					currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
+					currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
+					currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
+					currReader->dwEventState &= ~SCARD_STATE_MUTE;
+					currReader->dwEventState &= ~SCARD_STATE_INUSE;
+
+					/*
+					 * After present the rest are assumed
+					 */
+					if (currReader->dwCurrentState & SCARD_STATE_PRESENT
+						|| currReader->dwCurrentState & SCARD_STATE_ATRMATCH
+						|| currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE
+						|| currReader->dwCurrentState & SCARD_STATE_INUSE)
+					{
+						currReader->dwEventState |= SCARD_STATE_CHANGED;
+						dwBreakFlag = 1;
+					}
+
+					/*
+					 * Card is now present
+					 */
+				} else if (dwState & SCARD_PRESENT)
+				{
+					currReader->dwEventState |= SCARD_STATE_PRESENT;
+					currReader->dwEventState &= ~SCARD_STATE_EMPTY;
+					currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
+					currReader->dwEventState &= ~SCARD_STATE_IGNORE;
+					currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
+					currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
+					currReader->dwEventState &= ~SCARD_STATE_MUTE;
+
+					if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
+					{
+						currReader->dwEventState |= SCARD_STATE_CHANGED;
+						dwBreakFlag = 1;
+					}
+
+					if (dwState & SCARD_SWALLOWED)
+					{
+						if (currReader->dwCurrentState & SCARD_STATE_MUTE)
+							currReader->dwEventState |= SCARD_STATE_MUTE;
+						else
+						{
+							currReader->dwEventState |= SCARD_STATE_MUTE;
+							if (currReader->dwCurrentState
+								!= SCARD_STATE_UNAWARE)
+								currReader->dwEventState |= SCARD_STATE_CHANGED;
+							dwBreakFlag = 1;
+						}
+					}
+					else
+					{
+						/*
+						 * App thinks card is mute but it is not
+						 */
+						if (currReader->dwCurrentState & SCARD_STATE_MUTE)
+						{
+							currReader->dwEventState |=
+								SCARD_STATE_CHANGED;
+							dwBreakFlag = 1;
+						}
+					}
+				}
+
+				/*
+				 * Now figure out sharing modes
+				 */
+				DWORD sharing = SharedReaderState_Sharing(rContext);
+				if (sharing == -1)
+				{
+					currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
+					currReader->dwEventState &= ~SCARD_STATE_INUSE;
+					if (currReader->dwCurrentState & SCARD_STATE_INUSE)
+					{
+						currReader->dwEventState |= SCARD_STATE_CHANGED;
+						dwBreakFlag = 1;
+					}
+				}
+				else if (sharing >= 1)
+				{
+					/*
+					 * A card must be inserted for it to be INUSE
+					 */
+					if (dwState & SCARD_PRESENT)
+					{
+						currReader->dwEventState |= SCARD_STATE_INUSE;
+						currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
+						if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
+						{
+							currReader->dwEventState |= SCARD_STATE_CHANGED;
+							dwBreakFlag = 1;
+						}
+					}
+				}
+				else if (sharing == 0)
+				{
+					currReader->dwEventState &= ~SCARD_STATE_INUSE;
+					currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
+
+					if (currReader->dwCurrentState & SCARD_STATE_INUSE)
+					{
+						currReader->dwEventState |= SCARD_STATE_CHANGED;
+						dwBreakFlag = 1;
+					}
+					else if (currReader-> dwCurrentState
+						& SCARD_STATE_EXCLUSIVE)
+					{
+						currReader->dwEventState |= SCARD_STATE_CHANGED;
+						dwBreakFlag = 1;
+					}
+				}
+
+				if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
+				{
+					/*
+					 * Break out of the while .. loop and return status
+					 * once all the status's for all readers is met
+					 */
+					currReader->dwEventState |= SCARD_STATE_CHANGED;
+					dwBreakFlag = 1;
+				}
+
+			}	/* End of SCARD_STATE_UNKNOWN */
+
+		}	/* End of SCARD_STATE_IGNORE */
+
+		/*
+		 * Counter and resetter
+		 */
+		j = j + 1;
+		if (j == cReaders)
+		{
+			if (!dwBreakFlag)
+			{
+				/* break if the reader count changed,
+				 * so that the calling application can update
+				 * the reader list
+				 */
+				if (ReaderCountChanged)
+					break;
+			}
+			j = 0;
+		}
+
+		/*
+		 * Declare all the break conditions
+		 */
+
+		if (psContextMap[dwContextIndex].contextBlockStatus
+				== BLOCK_STATUS_RESUME)
+			break;
+
+		/*
+		 * Break if UNAWARE is set and all readers have been checked
+		 */
+		if ((dwBreakFlag == 1) && (j == 0))
+			break;
+
+		/*
+		 * Timeout has occurred and all readers checked
+		 */
+		if ((dwTimeout == 0) && (j == 0))
+			break;
+
+		if (dwTimeout != INFINITE && dwTimeout != 0)
+		{
+			/*
+			 * If time is greater than timeout and all readers have been
+			 * checked
+			 */
+			if ((dwTime >= (dwTimeout * 1000)) && (j == 0))
+			{
+				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+				return SCARD_E_TIMEOUT;
+			}
+		}
+
+		/*
+		 * Only sleep once for each cycle of reader checks.
+		 */
+		if (j == 0)
+		{
+			SYS_USleep(PCSCLITE_STATUS_WAIT);
+			dwTime += PCSCLITE_STATUS_WAIT;
+		}
+	}
+	while (1);
+
+	Log1(PCSC_LOG_DEBUG, "Event Loop End");
+
+	if (psContextMap[dwContextIndex].contextBlockStatus ==
+			BLOCK_STATUS_RESUME)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_CANCELLED;
+	}
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return SCARD_S_SUCCESS;
+}
+
+#undef SCardControl
+
+LONG SCardControl(SCARDHANDLE hCard, const void *pbSendBuffer,
+	DWORD cbSendLength, void *pbRecvBuffer, LPDWORD pcbRecvLength)
+{
+
+	SCARD_IO_REQUEST pioSendPci, pioRecvPci;
+
+	pioSendPci.dwProtocol = SCARD_PROTOCOL_RAW;
+	pioRecvPci.dwProtocol = SCARD_PROTOCOL_RAW;
+
+	return SCardTransmit(hCard, &pioSendPci, pbSendBuffer, cbSendLength,
+		&pioRecvPci, pbRecvBuffer, pcbRecvLength);
+}
+
+/**
+ * @brief This function sends a command directly to the IFD Handler to be
+ * processed by the reader.
+ *
+ * This is useful for creating client side reader drivers for functions like
+ * PIN pads, biometrics, or other extensions to the normal smart card reader
+ * that are not normally handled by PC/SC.
+ *
+ * @note the API of this function changed. In pcsc-lite 1.2.0 and before the
+ * API was not Windows(R) PC/SC compatible. This has been corrected.
+ *
+ * @param[in] hCard Connection made from SCardConnect.
+ * @param[in] dwControlCode Control code for the operation.\n
+ * <a href="http://pcsclite.alioth.debian.org/pcsc-lite/node26.html#Some_SCardControl_commands">
+ * Click here</a> for a list of supported commands by some drivers.
+ * @param[in] pbSendBuffer Command to send to the reader.
+ * @param[in] cbSendLength Length of the command.
+ * @param[out] pbRecvBuffer Response from the reader.
+ * @param[in] cbRecvLength Length of the response buffer.
+ * @param[out] lpBytesReturned Length of the response.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED)
+ * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_INVALID_VALUE Invalid value was presented (\ref SCARD_E_INVALID_VALUE)
+ * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed(\ref SCARD_E_READER_UNAVAILABLE)
+ * @retval SCARD_W_RESET_CARD The card has been reset by another application (\ref SCARD_W_RESET_CARD)
+ * @retval SCARD_W_REMOVED_CARD The card has been removed from the reader(\ref SCARD_W_REMOVED_CARD)
+ *
+ * @test
+ * @code
+ * LONG rv;
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol, dwSendLength, dwRecvLength;
+ * BYTE pbRecvBuffer[10];
+ * BYTE pbSendBuffer[] = { 0x06, 0x00, 0x0A, 0x01, 0x01, 0x10 0x00 };
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol);
+ * dwSendLength = sizeof(pbSendBuffer);
+ * dwRecvLength = sizeof(pbRecvBuffer);
+ * rv = SCardControl(hCard, 0x42000001, pbSendBuffer, dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer), &dwRecvLength);
+ * @endcode
+ */
+int32_t SCardControl132(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
+	DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
+	LPDWORD lpBytesReturned)
+{
+	// Real implementation to be provided as part of:
+	//	<rdar://problem/4711576> Support the new SCardControl function
+	//
+
+	LONG rv;
+	control_struct scControlStruct;
+	sharedSegmentMsg msgStruct;
+	int i;
+	DWORD dwContextIndex, dwChannelIndex;
+
+	PROFILE_START
+
+	/* 0 bytes received by default */
+	if (NULL != lpBytesReturned)
+		*lpBytesReturned = 0;
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
+
+		/* by default r == NULL */
+		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_READER_UNAVAILABLE;
+	}
+
+	if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
+		|| (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_INSUFFICIENT_BUFFER;
+	}
+
+	if ((cbSendLength > MAX_BUFFER_SIZE) || (cbRecvLength > MAX_BUFFER_SIZE))
+	{
+		/* extended control */
+		unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED];
+		control_struct_extended *scControlStructExtended = (control_struct_extended *)buffer;
+		sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer;
+
+		scControlStructExtended->hCard = hCard;
+		scControlStructExtended->dwControlCode = dwControlCode;
+		scControlStructExtended->cbSendLength = cbSendLength;
+		scControlStructExtended->cbRecvLength = cbRecvLength;
+		scControlStructExtended->size = sizeof(*scControlStructExtended) + cbSendLength;
+		memcpy(scControlStructExtended->data, pbSendBuffer, cbSendLength);
+
+		size_t csesize = scControlStructExtended->size;		// remember it from before byte swap
+		htonlControlStructExtended(scControlStructExtended);
+		rv = WrapSHMWrite(SCARD_CONTROL_EXTENDED,
+			psContextMap[dwContextIndex].dwClientID,
+			csesize,
+			PCSCLITE_CLIENT_ATTEMPTS, buffer);
+
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_E_NO_SERVICE;
+		}
+
+		/*
+		 * Read a message from the server
+		 */
+		/* read the first block */
+		rv = SHMClientReadMessage(pmsgStruct, psContextMap[dwContextIndex].dwClientID, 0, PCSCLITE_CLIENT_ATTEMPTS);
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_F_COMM_ERROR;
+		}
+
+		/* we receive a sharedSegmentMsg and not a control_struct_extended */
+		scControlStructExtended = (control_struct_extended *)&(pmsgStruct -> data);
+		ntohlControlStructExtended(scControlStructExtended);
+		
+		/* a second block is present */
+		if (scControlStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE)
+		{
+			rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg),
+				scControlStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE,
+				psContextMap[dwContextIndex].dwClientID,
+				PCSCLITE_CLIENT_ATTEMPTS);
+			if (rv == -1)
+			{
+				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+				return SCARD_F_COMM_ERROR;
+			}
+		}
+
+		if (scControlStructExtended -> rv == SCARD_S_SUCCESS)
+		{
+			/*
+			 * Copy and zero it so any secret information is not leaked
+			 */
+			memcpy(pbRecvBuffer, scControlStructExtended -> data,
+				scControlStructExtended -> pdwBytesReturned);
+			memset(scControlStructExtended -> data, 0x00,
+				scControlStructExtended -> pdwBytesReturned);
+		}
+
+		if (NULL != lpBytesReturned)
+			*lpBytesReturned = scControlStructExtended -> pdwBytesReturned;
+
+		rv = scControlStructExtended -> rv;
+	}
+	else
+	{
+		scControlStruct.hCard = hCard;
+		scControlStruct.dwControlCode = dwControlCode;
+		scControlStruct.cbSendLength = cbSendLength;
+		scControlStruct.cbRecvLength = cbRecvLength;
+		memcpy(scControlStruct.pbSendBuffer, pbSendBuffer, cbSendLength);
+		htonlControlStruct(&scControlStruct);
+		
+		rv = WrapSHMWrite(SCARD_CONTROL, psContextMap[dwContextIndex].dwClientID,
+			sizeof(scControlStruct), PCSCLITE_CLIENT_ATTEMPTS, &scControlStruct);
+
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_E_NO_SERVICE;
+		}
+
+		/*
+		 * Read a message from the server
+		 */
+		rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(control_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_F_COMM_ERROR;
+		}
+
+		memcpy(&scControlStruct, &msgStruct.data, sizeof(scControlStruct));
+		ntohlControlStruct(&scControlStruct);
+	
+		if (NULL != lpBytesReturned)
+			*lpBytesReturned = scControlStruct.dwBytesReturned;
+
+		if (scControlStruct.rv == SCARD_S_SUCCESS)
+		{
+			/*
+			 * Copy and zero it so any secret information is not leaked
+			 */
+			memcpy(pbRecvBuffer, scControlStruct.pbRecvBuffer,
+				scControlStruct.cbRecvLength);
+			memset(scControlStruct.pbRecvBuffer, 0x00,
+				sizeof(scControlStruct.pbRecvBuffer));
+		}
+
+		rv = scControlStruct.rv;
+	}
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return rv;
+}
+
+/**
+ * This function get an attribute from the IFD Handler. The list of possible
+ * attributes is available in the file \c pcsclite.h.
+ *
+ * @param[in] hCard Connection made from SCardConnect().
+ * @param[in] dwAttrId Identifier for the attribute to get.
+ * <ul>
+ *   <li>\ref SCARD_ATTR_ASYNC_PROTOCOL_TYPES
+ *   <li>\ref SCARD_ATTR_ATR_STRING
+ *   <li>\ref SCARD_ATTR_CHANNEL_ID
+ *   <li>\ref SCARD_ATTR_CHARACTERISTICS
+ *   <li>\ref SCARD_ATTR_CURRENT_BWT
+ *   <li>\ref SCARD_ATTR_CURRENT_CLK
+ *   <li>\ref SCARD_ATTR_CURRENT_CWT
+ *   <li>\ref SCARD_ATTR_CURRENT_D
+ *   <li>\ref SCARD_ATTR_CURRENT_EBC_ENCODING
+ *   <li>\ref SCARD_ATTR_CURRENT_F
+ *   <li>\ref SCARD_ATTR_CURRENT_IFSC
+ *   <li>\ref SCARD_ATTR_CURRENT_IFSD
+ *   <li>\ref SCARD_ATTR_CURRENT_IO_STATE
+ *   <li>\ref SCARD_ATTR_CURRENT_N
+ *   <li>\ref SCARD_ATTR_CURRENT_PROTOCOL_TYPE
+ *   <li>\ref SCARD_ATTR_CURRENT_W
+ *   <li>\ref SCARD_ATTR_DEFAULT_CLK
+ *   <li>\ref SCARD_ATTR_DEFAULT_DATA_RATE
+ *   <li>\ref SCARD_ATTR_DEVICE_FRIENDLY_NAME_A
+ *   <li>\ref SCARD_ATTR_DEVICE_FRIENDLY_NAME_W
+ *   <li>\ref SCARD_ATTR_DEVICE_IN_USE
+ *   <li>\ref SCARD_ATTR_DEVICE_SYSTEM_NAME_A
+ *   <li>\ref SCARD_ATTR_DEVICE_SYSTEM_NAME_W
+ *   <li>\ref SCARD_ATTR_DEVICE_UNIT
+ *   <li>\ref SCARD_ATTR_ESC_AUTHREQUEST
+ *   <li>\ref SCARD_ATTR_ESC_CANCEL
+ *   <li>\ref SCARD_ATTR_ESC_RESET
+ *   <li>\ref SCARD_ATTR_EXTENDED_BWT
+ *   <li>\ref SCARD_ATTR_ICC_INTERFACE_STATUS
+ *   <li>\ref SCARD_ATTR_ICC_PRESENCE
+ *   <li>\ref SCARD_ATTR_ICC_TYPE_PER_ATR
+ *   <li>\ref SCARD_ATTR_MAX_CLK
+ *   <li>\ref SCARD_ATTR_MAX_DATA_RATE
+ *   <li>\ref SCARD_ATTR_MAX_IFSD
+ *   <li>\ref SCARD_ATTR_MAXINPUT
+ *   <li>\ref SCARD_ATTR_POWER_MGMT_SUPPORT
+ *   <li>\ref SCARD_ATTR_SUPRESS_T1_IFS_REQUEST
+ *   <li>\ref SCARD_ATTR_SYNC_PROTOCOL_TYPES
+ *   <li>\ref SCARD_ATTR_USER_AUTH_INPUT_DEVICE
+ *   <li>\ref SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE
+ *   <li>\ref SCARD_ATTR_VENDOR_IFD_SERIAL_NO
+ *   <li>\ref SCARD_ATTR_VENDOR_IFD_TYPE
+ *   <li>\ref SCARD_ATTR_VENDOR_IFD_VERSION
+ *   <li>\ref SCARD_ATTR_VENDOR_NAME
+ * </ul>
+ *
+ * Not all the dwAttrId values listed above may be implemented in the IFD
+ * Handler you are using. And some dwAttrId values not listed here may be
+ * implemented.
+ *
+ * @param[out] pbAttr Pointer to a buffer that receives the attribute.
+ * @param pcbAttrLen [inout] Length of the \p pbAttr buffer in bytes.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED)
+ * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER)
+ *
+ * @test
+ * @code
+ * LONG rv;
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol;
+ * unsigned char pbAtr[MAX_ATR_SIZE];
+ * DWORD dwAtrLen;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED,
+ *                           SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol);
+ * rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, pbAtr, &dwAtrLen);
+ * @endcode
+ */
+
+int32_t SCardGetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId, uint8_t * pbAttr,
+	uint32_t * pcbAttrLen)
+{
+	PROFILE_START
+
+	if (NULL == pcbAttrLen)
+		return SCARD_E_INVALID_PARAMETER;
+
+	/* if only get the length */
+	if (NULL == pbAttr)
+		/* this variable may not be set by the caller. use a reasonable size */
+		*pcbAttrLen = MAX_BUFFER_SIZE;
+
+	PROFILE_END
+
+	return SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, pbAttr,
+		pcbAttrLen);
+}
+
+/**
+ * @brief This function set an attribute of the IFD Handler.
+ *
+ * The list of attributes you can set is dependent on the IFD Handler you are
+ * using.
+ *
+ * @param[in] hCard Connection made from SCardConnect().
+ * @param[in] dwAttrId Identifier for the attribute to set.
+ * @param[in] pbAttr Pointer to a buffer that receives the attribute.
+ * @param[in] cbAttrLen Length of the \p pbAttr buffer in bytes.
+ *
+ * @return Error code
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED)
+ *
+ * @test
+ * @code
+ * LONG rv;
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol;
+ * unsigned char pbAtr[MAX_ATR_SIZE];
+ * DWORD dwAtrLen;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED,
+ *                   SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol);
+ * rv = SCardSetAttrib(hCard, 0x42000001, "\x12\x34\x56", 3);
+ * @endcode
+ */
+
+int32_t SCardSetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId, const uint8_t *pbAttr,
+	uint32_t cbAttrLen)
+{
+	PROFILE_START
+
+	if (NULL == pbAttr || 0 == cbAttrLen)
+		return SCARD_E_INVALID_PARAMETER;
+
+	PROFILE_END
+
+	return SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
+		&cbAttrLen);
+}
+
+static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
+	LPBYTE pbAttr, LPDWORD pcbAttrLen)
+{
+	PROFILE_START
+
+	LONG rv;
+	getset_struct scGetSetStruct;
+	sharedSegmentMsg msgStruct;
+	int i;
+	DWORD dwContextIndex, dwChannelIndex;
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
+
+		/* by default r == NULL */
+		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_READER_UNAVAILABLE;
+	}
+
+	if (*pcbAttrLen > MAX_BUFFER_SIZE)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_INSUFFICIENT_BUFFER;
+	}
+
+	scGetSetStruct.hCard = hCard;
+	scGetSetStruct.dwAttrId = dwAttrId;
+	scGetSetStruct.cbAttrLen = *pcbAttrLen;
+	scGetSetStruct.rv = SCARD_E_NO_SERVICE;
+	if (SCARD_SET_ATTRIB == command)
+		memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
+
+	ntohlGetSetStruct(&scGetSetStruct);
+	rv = WrapSHMWrite(command,
+		psContextMap[dwContextIndex].dwClientID, sizeof(scGetSetStruct),
+		PCSCLITE_CLIENT_ATTEMPTS, &scGetSetStruct);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	/*
+	 * Read a message from the server
+	 */
+	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(getset_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+	if (rv == -1)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_F_COMM_ERROR;
+	}
+
+	memcpy(&scGetSetStruct, &msgStruct.data, sizeof(scGetSetStruct));
+	ntohlGetSetStruct(&scGetSetStruct);
+	
+	if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
+	{
+		/*
+		 * Copy and zero it so any secret information is not leaked
+		 */
+		if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
+		{
+			scGetSetStruct.cbAttrLen = *pcbAttrLen;
+			scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
+		}
+		else
+			*pcbAttrLen = scGetSetStruct.cbAttrLen;
+
+		if (pbAttr)
+			memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
+
+		memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
+	}
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return scGetSetStruct.rv;
+}
+
+/**
+ * @brief This function sends an APDU to the smart card contained in the reader
+ * connected to by SCardConnect().
+ *
+ * The card responds from the APDU and stores this response in pbRecvBuffer
+ * and it's length in SpcbRecvLength.
+ * SSendPci and SRecvPci are structures containing the following:
+ * @code
+ * typedef struct {
+ *    DWORD dwProtocol;    // SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1
+ *    DWORD cbPciLength;   // Length of this structure - not used
+ * } SCARD_IO_REQUEST;
+ * @endcode
+ *
+ * @param[in] hCard Connection made from SCardConnect().
+ * @param pioSendPci [inout] Structure of protocol information.
+ * <ul>
+ *   <li>\ref SCARD_PCI_T0 - Pre-defined T=0 PCI structure.
+ *   <li>\ref SCARD_PCI_T1 - Pre-defined T=1 PCI structure.
+ * </ul>
+ * @param[in] pbSendBuffer APDU to send to the card.
+ * @param[in] cbSendLength Length of the APDU.
+ * @param pioRecvPci [inout] Structure of protocol information.
+ * @param[out] pbRecvBuffer Response from the card.
+ * @param pcbRecvLength [inout] Length of the response.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_NOT_TRANSACTED APDU exchange not successful (\ref SCARD_E_NOT_TRANSACTED)
+ * @retval SCARD_E_PROTO_MISMATCH Connect protocol is different than desired (\ref SCARD_E_PROTO_MISMATCH)
+ * @retval SCARD_E_INVALID_VALUE Invalid Protocol, reader name, etc (\ref SCARD_E_INVALID_VALUE)
+ * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
+ * @retval SCARD_W_RESET_CARD The card has been reset by another application (\ref SCARD_W_RESET_CARD)
+ * @retval SCARD_W_REMOVED_CARD The card has been removed from the reader (\ref SCARD_W_REMOVED_CARD)
+ *
+ * @test
+ * @code
+ * LONG rv;
+ * SCARDCONTEXT hContext;
+ * SCARDHANDLE hCard;
+ * DWORD dwActiveProtocol, dwSendLength, dwRecvLength;
+ * SCARD_IO_REQUEST pioRecvPci;
+ * BYTE pbRecvBuffer[10];
+ * BYTE pbSendBuffer[] = { 0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 };
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
+ * dwSendLength = sizeof(pbSendBuffer);
+ * dwRecvLength = sizeof(pbRecvBuffer);
+ * rv = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, dwSendLength, &pioRecvPci, pbRecvBuffer, &dwRecvLength);
+ * @endcode
+ */
+#include <syslog.h>
+LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
+	LPCBYTE pbSendBuffer, DWORD cbSendLength,
+	LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer,
+	LPDWORD pcbRecvLength)
+{
+	LONG rv;
+	int i;
+	DWORD dwContextIndex, dwChannelIndex;
+
+	PROFILE_START
+
+	if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
+			pcbRecvLength == NULL || pioSendPci == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this handle has been opened
+	 */
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
+
+	if (rv == -1)
+	{
+		*pcbRecvLength = 0;
+		return SCARD_E_INVALID_HANDLE;
+	}
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
+
+		/* by default r == NULL */
+		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_READER_UNAVAILABLE;
+	}
+
+	if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
+		|| (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
+	{
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_INSUFFICIENT_BUFFER;
+	}
+
+	if ((cbSendLength > MAX_BUFFER_SIZE) || (*pcbRecvLength > MAX_BUFFER_SIZE))
+	{
+		/* extended APDU */
+		unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED];
+		const sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer;
+		transmit_struct_extended *scTransmitStructExtended = (transmit_struct_extended *)buffer;
+
+		scTransmitStructExtended->hCard = hCard;
+		scTransmitStructExtended->cbSendLength = cbSendLength;
+		scTransmitStructExtended->pcbRecvLength = *pcbRecvLength;
+		scTransmitStructExtended->size = sizeof(*scTransmitStructExtended) + cbSendLength;
+		memcpy(&scTransmitStructExtended->pioSendPci, pioSendPci,
+			sizeof(SCARD_IO_REQUEST));
+		memcpy(scTransmitStructExtended->data, pbSendBuffer, cbSendLength);
+		secdebug("pcscd", "Extended APDU: initial request: hCard: 0x%08X, cbSendLength: %d", 
+			hCard, cbSendLength);
+		secdebug("pcscd", "               pcbRecvLength: %d", *pcbRecvLength);
+
+		if (pioRecvPci)
+		{
+			memcpy(&scTransmitStructExtended->pioRecvPci, pioRecvPci,
+				sizeof(SCARD_IO_REQUEST));
+		}
+		else
+			scTransmitStructExtended->pioRecvPci.dwProtocol = SCARD_PROTOCOL_ANY;
+
+		size_t tsesize = scTransmitStructExtended->size;		// remember it before we byte swap
+		LogXxd(PCSC_LOG_INFO, "Extended APDU: sending: ", pbSendBuffer, cbSendLength);
+		htonlTransmitStructExtended(scTransmitStructExtended);
+		rv = WrapSHMWrite(SCARD_TRANSMIT_EXTENDED,
+			psContextMap[dwContextIndex].dwClientID,
+			tsesize,
+			PCSCLITE_CLIENT_ATTEMPTS, buffer);
+		secdebug("pcscd", "Extended APDU: WrapSHMWrite result: %d [0x%08X]", rv, rv);
+
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_E_NO_SERVICE;
+		}
+
+		/*
+		 * Read a message from the server
+		 */
+		rv = SHMClientReadMessage((psharedSegmentMsg)buffer, psContextMap[dwContextIndex].dwClientID, 0, PCSCLITE_CLIENT_ATTEMPTS);
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_F_COMM_ERROR;
+		}
+		
+		/* we receive a sharedSegmentMsg and not a transmit_struct_extended */
+		scTransmitStructExtended = (transmit_struct_extended *)pmsgStruct->data;
+		ntohlTransmitStructExtended(scTransmitStructExtended);
+		secdebug("pcscd", "Extended APDU: reply received: hCard: 0x%08X, cbSendLength: %d", 
+			hCard, cbSendLength);
+		secdebug("pcscd", "               reply received: pcbRecvLength: %d, size: %d", 
+			scTransmitStructExtended->pcbRecvLength, scTransmitStructExtended->size);
+		secdebug("pcscd", "               reply received: rv %d [0x%08X]", 
+			scTransmitStructExtended -> rv, scTransmitStructExtended -> rv);
+		LogXxd(PCSC_LOG_INFO, "Extended APDU: received: ", scTransmitStructExtended->data, scTransmitStructExtended->pcbRecvLength);
+
+		/* a second block is present */
+		if (scTransmitStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE)
+		{
+			rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg),
+				scTransmitStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE,
+				psContextMap[dwContextIndex].dwClientID,
+				PCSCLITE_CLIENT_ATTEMPTS);
+			if (rv == -1)
+			{
+				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+				return SCARD_F_COMM_ERROR;
+			}
+			// we don't fix up byte order here since this is in the data portion
+		}
+
+		if (scTransmitStructExtended -> rv == SCARD_S_SUCCESS)
+		{
+			/*
+			 * Copy and zero it so any secret information is not leaked
+			 */
+			memcpy(pbRecvBuffer, scTransmitStructExtended -> data,
+				scTransmitStructExtended -> pcbRecvLength);
+			memset(scTransmitStructExtended -> data, 0x00,
+				scTransmitStructExtended -> pcbRecvLength);
+
+			if (pioRecvPci)
+				memcpy(pioRecvPci, &scTransmitStructExtended -> pioRecvPci,
+					sizeof(SCARD_IO_REQUEST));
+		}
+
+		*pcbRecvLength = scTransmitStructExtended -> pcbRecvLength;
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+		rv = scTransmitStructExtended -> rv;
+	}
+	else
+	{
+		/* short APDU */
+		transmit_struct scTransmitStruct;
+		sharedSegmentMsg msgStruct;
+
+		scTransmitStruct.hCard = hCard;
+		scTransmitStruct.cbSendLength = cbSendLength;
+		scTransmitStruct.pcbRecvLength = *pcbRecvLength;
+		memcpy(&scTransmitStruct.pioSendPci, pioSendPci,
+			sizeof(SCARD_IO_REQUEST));
+		memcpy(scTransmitStruct.pbSendBuffer, pbSendBuffer, cbSendLength);
+
+		if (pioRecvPci)
+		{
+			memcpy(&scTransmitStruct.pioRecvPci, pioRecvPci,
+				sizeof(SCARD_IO_REQUEST));
+		}
+		else
+			scTransmitStruct.pioRecvPci.dwProtocol = SCARD_PROTOCOL_ANY;
+
+		htonlTransmitStruct(&scTransmitStruct);
+		rv = WrapSHMWrite(SCARD_TRANSMIT,
+			psContextMap[dwContextIndex].dwClientID, sizeof(scTransmitStruct),
+			PCSCLITE_CLIENT_ATTEMPTS, (void *) &scTransmitStruct);
+
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_E_NO_SERVICE;
+		}
+
+		/*
+		 * Read a message from the server
+		 */
+		rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(transmit_struct), PCSCLITE_CLIENT_ATTEMPTS);
+
+		memcpy(&scTransmitStruct, &msgStruct.data, sizeof(scTransmitStruct));
+		ntohlTransmitStruct(&scTransmitStruct);
+		
+		if (rv == -1)
+		{
+			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+			return SCARD_F_COMM_ERROR;
+		}
+
+		/*
+		 * Zero it and free it so any secret information cannot be leaked
+		 */
+		memset(scTransmitStruct.pbSendBuffer, 0x00, cbSendLength);
+
+		if (scTransmitStruct.rv == SCARD_S_SUCCESS)
+		{
+			/*
+			 * Copy and zero it so any secret information is not leaked
+			 */
+			memcpy(pbRecvBuffer, scTransmitStruct.pbRecvBuffer,
+				scTransmitStruct.pcbRecvLength);
+			memset(scTransmitStruct.pbRecvBuffer, 0x00,
+				scTransmitStruct.pcbRecvLength);
+
+			if (pioRecvPci)
+				memcpy(pioRecvPci, &scTransmitStruct.pioRecvPci,
+					sizeof(SCARD_IO_REQUEST));
+		}
+
+		*pcbRecvLength = scTransmitStruct.pcbRecvLength;
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+		rv = scTransmitStruct.rv;
+	}
+
+	PROFILE_END
+
+	return rv;
+}
+
+/**
+ * This function returns a list of currently available readers on the system.
+ * \p mszReaders is a pointer to a character string that is allocated by the application.
+ * If the application sends mszGroups and mszReaders as NULL then this function will
+ * return the size of the buffer needed to allocate in pcchReaders.
+ *
+ * @param[in] hContext Connection context to the PC/SC Resource Manager.
+ * @param[in] mszGroups List of groups to list readers (not used).
+ * @param[out] mszReaders Multi-string with list of readers.
+ * @param pcchReaders [inout] Size of multi-string buffer including NULL's.
+ *
+ * @return Connection status.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid Scope Handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * LPSTR mszReaders;
+ * DWORD dwReaders;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
+ * mszReaders = malloc(sizeof(char)*dwReaders);
+ * rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
+ * @endcode
+ */
+LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups,
+	LPSTR mszReaders, LPDWORD pcchReaders)
+{
+	DWORD dwReadersLen;
+	int i, lastChrPtr;
+	LONG dwContextIndex;
+
+	PROFILE_START
+
+	/*
+	 * Check for NULL parameters
+	 */
+	if (pcchReaders == NULL)
+		return SCARD_E_INVALID_PARAMETER;
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this context has been opened
+	 */
+	dwContextIndex = SCardGetContextIndice(hContext);
+	if (dwContextIndex == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	dwReadersLen = 0;
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+		if (SharedReaderState_ReaderID(readerStates[i]) != 0)
+			dwReadersLen += strlen(SharedReaderState_ReaderName(readerStates[i])) + 1;
+
+	/* for the last NULL byte */
+	dwReadersLen += 1;
+
+	if ((mszReaders == NULL)	/* text array not allocated */
+		|| (*pcchReaders == 0))	/* size == 0 */
+	{
+		*pcchReaders = dwReadersLen;
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_S_SUCCESS;
+	}
+
+	if (*pcchReaders < dwReadersLen)
+	{
+		*pcchReaders = dwReadersLen;
+		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+		return SCARD_E_INSUFFICIENT_BUFFER;
+	}
+
+	lastChrPtr = 0;
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		if (SharedReaderState_ReaderID(readerStates[i]) != 0)
+		{
+			/*
+			 * Build the multi-string
+			 */
+			strcpy(&mszReaders[lastChrPtr], SharedReaderState_ReaderName(readerStates[i]));
+			lastChrPtr += strlen(SharedReaderState_ReaderName(readerStates[i]))+1;
+		}
+	}
+	mszReaders[lastChrPtr] = '\0';	/* Add the last null */
+
+	*pcchReaders = dwReadersLen;
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return SCARD_S_SUCCESS;
+}
+
+/**
+ * @brief This function returns a list of currently available reader groups on the system.
+ * \p mszGroups is a pointer to a character string that is allocated by the
+ * application.  If the application sends mszGroups as NULL then this function
+ * will return the size of the buffer needed to allocate in pcchGroups.
+ *
+ * The group names is a multi-string and separated by a nul character ('\\0') and ended by
+ * a double nul character. "SCard$DefaultReaders\\0Group 2\\0\\0".
+ *
+ * @param[in] hContext Connection context to the PC/SC Resource Manager.
+ * @param[out] mszGroups List of groups to list readers.
+ * @param pcchGroups [inout] Size of multi-string buffer including NULL's.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid Scope Handle (\ref SCARD_E_INVALID_HANDLE)
+ * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * LPSTR mszGroups;
+ * DWORD dwGroups;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardListReaderGroups(hContext, NULL, &dwGroups);
+ * mszGroups = malloc(sizeof(char)*dwGroups);
+ * rv = SCardListReaderGroups(hContext, mszGroups, &dwGroups);
+ * @endcode
+ */
+LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
+	LPDWORD pcchGroups)
+{
+	LONG rv = SCARD_S_SUCCESS;
+	LONG dwContextIndex;
+
+	PROFILE_START
+
+	const char ReaderGroup[] = "SCard$DefaultReaders";
+	const int dwGroups = strlen(ReaderGroup) + 2;
+
+	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
+		return SCARD_E_NO_SERVICE;
+
+	/*
+	 * Make sure this context has been opened
+	 */
+	dwContextIndex = SCardGetContextIndice(hContext);
+	if (dwContextIndex == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
+
+	if (mszGroups)
+	{
+
+		if (*pcchGroups < dwGroups)
+			rv = SCARD_E_INSUFFICIENT_BUFFER;
+		else
+		{
+			memset(mszGroups, 0, dwGroups);
+			memcpy(mszGroups, ReaderGroup, strlen(ReaderGroup));
+		}
+	}
+
+	*pcchGroups = dwGroups;
+
+	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
+
+	PROFILE_END
+
+	return rv;
+}
+
+/**
+ * This function cancels all pending blocking requests on the
+ * SCardGetStatusChange() function.
+ *
+ * @param[in] hContext Connection context to the PC/SC Resource Manager.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid \p hContext handle (\ref SCARD_E_INVALID_HANDLE)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * DWORD cReaders;
+ * SCARD_READERSTATE rgReaderStates;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rgReaderStates.szReader = strdup("Reader X");
+ * rgReaderStates.dwCurrentState = SCARD_STATE_EMPTY;
+ * ...
+ * / * Spawn off thread for following function * /
+ * ...
+ * rv = SCardGetStatusChange(hContext, 0, rgReaderStates, cReaders);
+ * rv = SCardCancel(hContext);
+ * @endcode
+ */
+LONG SCardCancel(SCARDCONTEXT hContext)
+{
+	LONG dwContextIndex;
+
+	PROFILE_START
+
+	dwContextIndex = SCardGetContextIndice(hContext);
+
+	if (dwContextIndex == -1)
+		return SCARD_E_INVALID_HANDLE;
+
+	/*
+	 * Set the block status for this Context so blocking calls will
+	 * complete
+	 */
+	psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_RESUME;
+
+	PROFILE_END
+
+	return SCARD_S_SUCCESS;
+}
+
+/**
+ * @brief check if a \ref SCARDCONTEXT is valid.
+ *
+ * Call this function to determine whether a smart card context handle is still
+ * valid. After a smart card context handle has been set by \ref
+ * SCardEstablishContext, it may become not valid if the resource manager
+ * service has been shut down.
+ *
+ * @param[in] hContext Connection context to the PC/SC Resource Manager.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE Invalid Handle (\ref SCARD_E_INVALID_HANDLE)
+ *
+ * @test
+ * @code
+ * SCARDCONTEXT hContext;
+ * LONG rv;
+ * ...
+ * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+ * rv = SCardIsValidContext(hContext);
+ * @endcode
+ */
+LONG SCardIsValidContext(SCARDCONTEXT hContext)
+{
+	LONG rv;
+	LONG dwContextIndex;
+
+	PROFILE_START
+
+	rv = SCARD_S_SUCCESS;
+
+	/*
+	 * Make sure this context has been opened
+	 */
+	dwContextIndex = SCardGetContextIndice(hContext);
+	if (dwContextIndex == -1)
+		rv = SCARD_E_INVALID_HANDLE;
+
+	PROFILE_END
+
+	return rv;
+}
+
+/**
+ * Functions for managing instances of SCardEstablishContext These functions
+ * keep track of Context handles and associate the blocking
+ * variable contextBlockStatus to an hContext
+ */
+
+/**
+ * @brief Adds an Application Context to the vector \c psContextMap.
+ *
+ * @param[in] hContext Application Context ID.
+ * @param[in] dwClientID Client connection ID.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Success (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_NO_MEMORY There is no free slot to store \p hContext (\ref SCARD_E_NO_MEMORY)
+ */
+static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
+	{
+		if (psContextMap[i].hContext == 0)
+		{
+			psContextMap[i].hContext = hContext;
+			psContextMap[i].dwClientID = dwClientID;
+			psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME;
+			psContextMap[i].mMutex = malloc(sizeof(PCSCLITE_MUTEX));
+			SYS_MutexInit(psContextMap[i].mMutex);
+			return SCARD_S_SUCCESS;
+		}
+	}
+
+	return SCARD_E_NO_MEMORY;
+}
+
+/**
+ * @brief Get the index from the Application Context vector \c psContextMap
+ * for the passed context.
+ *
+ * This function is a thread-safe wrapper to the function
+ * SCardGetContextIndiceTH().
+ *
+ * @param[in] hContext Application Context whose index will be find.
+ *
+ * @return Index corresponding to the Application Context or -1 if it is
+ * not found.
+ */
+static LONG SCardGetContextIndice(SCARDCONTEXT hContext)
+{
+	LONG rv;
+
+	SCardLockThread();
+	rv = SCardGetContextIndiceTH(hContext);
+	SCardUnlockThread();
+
+	return rv;
+}
+
+/**
+ * @brief Get the index from the Application Context vector \c psContextMap
+ * for the passed context.
+ *
+ * This functions is not thread-safe and should not be called. Instead, call
+ * the function SCardGetContextIndice().
+ *
+ * @param[in] hContext Application Context whose index will be find.
+ *
+ * @return Index corresponding to the Application Context or -1 if it is
+ * not found.
+ */
+static LONG SCardGetContextIndiceTH(SCARDCONTEXT hContext)
+{
+	int i;
+
+	if (hContext == 0)
+		return -1;
+		
+	/*
+	 * Find this context and return its spot in the array
+	 */
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
+		if (hContext == psContextMap[i].hContext)
+			return i;
+
+	return -1;
+}
+
+/**
+ * @brief Removes an Application Context from a control vector.
+ *
+ * @param[in] hContext Application Context to be removed.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Success (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_INVALID_HANDLE The context \p hContext was not found (\ref SCARD_E_INVALID_HANDLE)
+ */
+static LONG SCardRemoveContext(SCARDCONTEXT hContext)
+{
+	LONG  retIndice;
+
+	retIndice = SCardGetContextIndiceTH(hContext);
+
+	if (retIndice == -1)
+		return SCARD_E_INVALID_HANDLE;
+	else
+	{
+		int i;
+
+		psContextMap[retIndice].hContext = 0;
+		SHMClientCloseSession(psContextMap[retIndice].dwClientID);
+		psContextMap[retIndice].dwClientID = 0;
+		free(psContextMap[retIndice].mMutex);
+		psContextMap[retIndice].mMutex = NULL;
+		psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_RESUME;
+
+		for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
+		{
+			/*
+			 * Reset the \c hCard structs to zero
+			 */
+			psContextMap[retIndice].psChannelMap[i].hCard = 0;
+			free(psContextMap[retIndice].psChannelMap[i].readerName);
+			psContextMap[retIndice].psChannelMap[i].readerName = NULL;
+		}
+
+		return SCARD_S_SUCCESS;
+	}
+}
+
+/*
+ * Functions for managing hCard values returned from SCardConnect.
+ */
+
+static LONG SCardAddHandle(SCARDHANDLE hCard, DWORD dwContextIndex,
+	LPSTR readerName)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
+	{
+		if (psContextMap[dwContextIndex].psChannelMap[i].hCard == 0)
+		{
+			psContextMap[dwContextIndex].psChannelMap[i].hCard = hCard;
+			psContextMap[dwContextIndex].psChannelMap[i].readerName = strdup(readerName);
+			return SCARD_S_SUCCESS;
+		}
+	}
+
+	return SCARD_E_NO_MEMORY;
+}
+
+static LONG SCardRemoveHandle(SCARDHANDLE hCard)
+{
+	DWORD dwContextIndice, dwChannelIndice;
+	LONG rv;
+
+	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndice, &dwChannelIndice);
+
+	if (rv == -1)
+		return SCARD_E_INVALID_HANDLE;
+	else
+	{
+		psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].hCard = 0;
+		free(psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].readerName);
+		psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].readerName = NULL;
+		return SCARD_S_SUCCESS;
+	}
+}
+
+static LONG SCardGetIndicesFromHandle(SCARDHANDLE hCard, PDWORD pdwContextIndice, PDWORD pdwChannelIndice)
+{
+	LONG rv;
+
+	if (0 == hCard)
+		return -1;
+
+	SCardLockThread();
+	rv = SCardGetIndicesFromHandleTH(hCard, pdwContextIndice, pdwChannelIndice);
+	SCardUnlockThread();
+
+	return rv;
+}
+
+static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE hCard, PDWORD pdwContextIndice, PDWORD pdwChannelIndice)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
+	{
+		if (psContextMap[i].hContext != 0)
+		{
+			int j;
+
+			for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++)
+			{
+				if (psContextMap[i].psChannelMap[j].hCard == hCard)
+				{
+					*pdwContextIndice = i;
+					*pdwChannelIndice = j;
+					return SCARD_S_SUCCESS;
+				}
+			}
+
+		}
+	}
+
+	return -1;
+}
+
+/**
+ * @brief This function locks a mutex so another thread must wait to use this
+ * function.
+ *
+ * Wrapper to the function SYS_MutexLock().
+ */
+inline static LONG SCardLockThread(void)
+{
+	return SYS_MutexLock(&clientMutex);
+}
+
+/**
+ * @brief This function unlocks a mutex so another thread may use the client.
+ *
+ * Wrapper to the function SYS_MutexUnLock().
+ */
+inline static LONG SCardUnlockThread(void)
+{
+	return SYS_MutexUnLock(&clientMutex);
+}
+
+/**
+ * @brief Checks if the Server is running.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Server is running (\ref SCARD_S_SUCCESS)
+ * @retval SCARD_E_NO_SERVICE Server is not running (\ref SCARD_E_NO_SERVICE)
+ */
+static LONG SCardCheckDaemonAvailability(void)
+{
+	LONG rv;
+	struct stat statBuffer;
+
+	rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &statBuffer);
+
+	if (rv != 0)
+	{
+		Log1(PCSC_LOG_ERROR, "PCSC Not Running");
+		return SCARD_E_NO_SERVICE;
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+/**
+ * free resources allocated by the library
+ * You _shall_ call this function if you use dlopen/dlclose to load/unload the
+ * library. Otherwise you will exhaust the ressources available.
+ */
+#ifdef __SUNPRO_C
+#pragma fini (SCardUnload)
+#endif
+
+void DESTRUCTOR SCardUnload(void)
+{
+	int i;
+
+	if (!isExecuted)
+		return;
+
+	/* unmap public shared file from memory */
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
+	{
+		if (readerStates[i] != NULL)
+		{
+			SYS_PublicMemoryUnmap(readerStates[i], sizeof(READER_STATE));
+			readerStates[i] = NULL;
+		}
+	}
+
+	SYS_CloseFile(mapAddr);
+	isExecuted = 0;
+}
+
+static int SCardInitializeOnce()
+{
+	int pageSize;
+	int i;
+
+	/*
+	 * Do any system initilization here
+	 */
+	SYS_Initialize();
+
+	/*
+	 * Set up the memory mapped reader stats structures
+	 */
+	mapAddr = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDONLY, 0);
+	if (mapAddr < 0)
+	{
+		Log2(PCSC_LOG_ERROR, "Cannot open public shared file: %s",
+			PCSCLITE_PUBSHM_FILE);
+		return SCARD_E_NO_SERVICE;
+	}
+
+	pageSize = SYS_GetPageSize();
+
+	/*
+	 * Allocate each reader structure in the memory map
+	 */
+	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		readerStates[i] =
+			(PREADER_STATE)SYS_PublicMemoryMap(sizeof(READER_STATE),
+			mapAddr, (i * pageSize));
+		if (readerStates[i] == NULL)
+		{
+			Log1(PCSC_LOG_ERROR, "Cannot public memory map");
+			SYS_CloseFile(mapAddr);	/* Close the memory map file */
+			return SCARD_F_INTERNAL_ERROR;
+		}
+	}
+
+	/*
+	 * Initializes the application contexts and all channels for each one
+	 */
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
+	{
+		int j;
+
+		/*
+		 * Initially set the context struct to zero
+		 */
+		psContextMap[i].dwClientID = 0;
+		psContextMap[i].hContext = 0;
+		psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME;
+		psContextMap[i].mMutex = NULL;
+
+		for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++)
+		{
+			/*
+			 * Initially set the hcard structs to zero
+			 */
+			psContextMap[i].psChannelMap[j].hCard = 0;
+			psContextMap[i].psChannelMap[j].readerName = NULL;
+		}
+	}
+
+	/*
+	 * Is there a free slot for this connection ?
+	 */
+
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
+	{
+		if (psContextMap[i].dwClientID == 0)
+			break;
+	}
+
+	if (i == PCSCLITE_MAX_APPLICATION_CONTEXTS)
+	{
+		return SCARD_E_NO_MEMORY;
+	}
+
+	return SCARD_S_SUCCESS;
+}

Added: trunk/SmartCardServices/src/PCSC/winscard_msg.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard_msg.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard_msg.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	Title  : winscard_msg.c
+	Package: PC/SC Lite
+	Author : David Corcoran
+	Date   : 04/19/01
+	License: Copyright (C) 2001 David Corcoran
+			<corcoran at linuxnet.com>
+	Purpose: This is responsible for client/server transport.
+
+$Id: winscard_msg.c,v 1.4 2004/10/21 01:17:53 mb Exp $
+
+********************************************************************/
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+#ifdef PCSC_TARGET_SOLARIS
+#include <sys/filio.h>
+#endif
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "winscard.h"
+#include "winscard_msg.h"
+#include "sys_generic.h"
+#include "debuglog.h"
+
+int MSGSendData(int filedes, int blockAmount, const void *data,
+	unsigned int dataSize)
+{
+	/*
+	 * default is success 
+	 */
+	int retval = 0;
+	/*
+	 * record the time when we started 
+	 */
+	time_t start = time(0);
+	/*
+	 * data to be written 
+	 */
+	unsigned char *buffer = (unsigned char *) data;
+	/*
+	 * how many bytes remains to be written 
+	 */
+	size_t remaining = dataSize;
+
+	/*
+	 * repeat until all data is written 
+	 */
+	while (remaining > 0)
+	{
+		fd_set write_fd;
+		struct timeval timeout;
+		int selret;
+
+		FD_ZERO(&write_fd);
+		FD_SET(filedes, &write_fd);
+
+		timeout.tv_usec = 0;
+		if ((timeout.tv_sec = start + blockAmount - time(0)) < 0)
+		{
+			/*
+			 * we already timed out 
+			 */
+			retval = -1;
+			break;
+		}
+
+		selret = select(filedes + 1, NULL, &write_fd, NULL, &timeout);
+
+		/*
+		 * try to write only when the file descriptor is writable 
+		 */
+		if (selret > 0)
+		{
+			int written;
+
+			if (!FD_ISSET(filedes, &write_fd))
+			{
+				/*
+				 * very strange situation. it should be an assert really 
+				 */
+				retval = -1;
+				break;
+			}
+			written = write(filedes, buffer, remaining);
+
+			if (written > 0)
+			{
+				/*
+				 * we wrote something 
+				 */
+				buffer += written;
+				remaining -= written;
+			} else if (written == 0)
+			{
+				/*
+				 * peer closed the socket 
+				 */
+				retval = -1;
+				break;
+			} else
+			{
+				/*
+				 * we ignore the signals and socket full situations, all
+				 * other errors are fatal 
+				 */
+				if (errno != EINTR && errno != EAGAIN)
+				{
+					retval = -1;
+					break;
+				}
+			}
+		} else if (selret == 0)
+		{
+			/*
+			 * timeout 
+			 */
+			retval = -1;
+			break;
+		} else
+		{
+			/*
+			 * ignore signals 
+			 */
+			if (errno != EINTR)
+			{
+				DebugLogB
+					("MSGServerProcessEvents: Select returns with failure: %s",
+					strerror(errno));
+				retval = -1;
+				break;
+			}
+		}
+	}
+
+	return retval;
+}
+
+int MSGRecieveData(int filedes, int blockAmount, void *data,
+	unsigned int dataSize)
+{
+	/*
+	 * default is success 
+	 */
+	int retval = 0;
+	/*
+	 * record the time when we started 
+	 */
+	time_t start = time(0);
+	/*
+	 * buffer where we place the readed bytes 
+	 */
+	unsigned char *buffer = (unsigned char *) data;
+	/*
+	 * how many bytes we must read 
+	 */
+	size_t remaining = dataSize;
+
+	/*
+	 * repeat until we get the whole message 
+	 */
+	while (remaining > 0)
+	{
+		fd_set read_fd;
+		struct timeval timeout;
+		int selret;
+
+		FD_ZERO(&read_fd);
+		FD_SET(filedes, &read_fd);
+
+		timeout.tv_usec = 0;
+		if ((timeout.tv_sec = start + blockAmount - time(0)) < 0)
+		{
+			/*
+			 * we already timed out 
+			 */
+			retval = -1;
+			break;
+		}
+
+		selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
+
+		/*
+		 * try to read only when socket is readable 
+		 */
+		if (selret > 0)
+		{
+			int readed;
+
+			if (!FD_ISSET(filedes, &read_fd))
+			{
+				/*
+				 * very strange situation. it should be an assert really 
+				 */
+				retval = -1;
+				break;
+			}
+			readed = read(filedes, buffer, remaining);
+
+			if (readed > 0)
+			{
+				/*
+				 * we got something 
+				 */
+				buffer += readed;
+				remaining -= readed;
+			} else if (readed == 0)
+			{
+				/*
+				 * peer closed the socket 
+				 */
+				retval = -1;
+				break;
+			} else
+			{
+				/*
+				 * we ignore the signals and empty socket situations, all
+				 * other errors are fatal 
+				 */
+				if (errno != EINTR && errno != EAGAIN)
+				{
+					retval = -1;
+					break;
+				}
+			}
+		} else if (selret == 0)
+		{
+			/*
+			 * timeout 
+			 */
+			retval = -1;
+			break;
+		} else
+		{
+			/*
+			 * we ignore signals, all other errors are fatal 
+			 */
+			if (errno != EINTR)
+			{
+				DebugLogB
+					("MSGServerProcessEvents: Select returns with failure: %s",
+					strerror(errno));
+				retval = -1;
+				break;
+			}
+		}
+	}
+
+	return retval;
+}

Added: trunk/SmartCardServices/src/PCSC/winscard_msg.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard_msg.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard_msg.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1002 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  winscard_msg.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2001-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Damien Sauveron <damien.sauveron at labri.fr>
+ *  Ludoic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: winscard_msg.c 2377 2007-02-05 13:13:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This is responsible for client/server communication.
+ *
+ * A file based socket (\c commonSocket) is used to send/receive only messages
+ * among clients and server.\n
+ * The messages' data are passed throw a memory mapped file: \c sharedSegmentMsg.
+ */
+
+#include "config.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "pcscexport.h"
+#include "winscard.h"
+#include "debug.h"
+#include "winscard_msg.h"
+#include "sys_generic.h"
+
+#include <security_utilities/debugging.h>
+
+/**
+ * @brief Wrapper for the SHMMessageReceive() function.
+ *
+ * Called by clients to read the server responses.
+ *
+ * @param[out] msgStruct Message read.
+ * @param[in] dwClientID Client socket handle.
+ * @param[in] blockamount Timeout in milliseconds.
+ *
+ * @return Same error codes as SHMMessageReceive().
+ */
+INTERNAL int SHMClientRead(psharedSegmentMsg msgStruct, DWORD dwClientID, int blockamount)
+{
+	int rv = SHMMessageReceive(msgStruct, sizeof(*msgStruct), dwClientID, blockamount);
+	SHSharedSegmentMsgToHostOrder(msgStruct);
+	return rv;
+}
+
+/**
+ * @brief Wrapper for the SHMMessageReceive() function.
+ *
+ * Called by clients to read the server responses. This reads the exact number of bytes expected for the struct
+ *
+ * @param[out] msgStruct Message read.
+ * @param[in] dwClientID Client socket handle.
+ * @param[in] dataSize Size of the data at msgStruct->data
+ * @param[in] blockamount Timeout in milliseconds.
+ *
+ * @return Same error codes as SHMMessageReceive().
+ */
+INTERNAL int SHMClientReadMessage(psharedSegmentMsg msgStruct, DWORD dwClientID, size_t dataSize, int blockamount)
+{
+	// Read the basic header first so we know the size of the rest
+	// The special case of "dataSize == 0" means that we should deduce the size of the
+	// data from the header
+	size_t headerSize = sizeof(sharedSegmentMsg) - sizeof(msgStruct->data);
+	Log2(PCSC_LOG_DEBUG, "SHMClientReadMessage: Issuing read for %d bytes (header)", headerSize);
+	secdebug("pcscd", "SHMClientReadMessage: Issuing read for %ld bytes (header)", headerSize);
+	int rv = SHMMessageReceive(msgStruct, headerSize, dwClientID, blockamount);
+	Log3(rv?PCSC_LOG_CRITICAL:PCSC_LOG_DEBUG, "SHMClientReadMessage: read message header error: 0x%08X [0x%08X]", rv, rv);
+	secdebug("pcscd", "SHMClientReadMessage: read message header error: 0x%08X [0x%08X]", rv, rv);
+	if (rv)
+		return rv;
+	SHSharedSegmentMsgToHostOrder(msgStruct);
+	// Integrity check
+	if (msgStruct->headerTag != WINSCARD_MSG_HEADER_TAG)
+	{
+		Log3(PCSC_LOG_CRITICAL, "Error: read message header tag of: 0x%08X for possible command 0x%08X", 
+			msgStruct->headerTag, msgStruct->command);
+		secdebug("pcscd", "Error: read message header tag of: 0x%08X for possible command 0x%08X", 
+			msgStruct->headerTag, msgStruct->command);
+		return SCARD_F_INTERNAL_ERROR;
+	}
+	if (dataSize == 0)
+		dataSize = msgStruct->msgSize - headerSize;		// message size includes header
+	else
+	if (msgStruct->msgSize != (headerSize + dataSize))
+	{
+		Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s", strerror(errno));
+		secdebug("pcscd", "Error: create on client socket: %s", strerror(errno));
+		return SCARD_F_INTERNAL_ERROR;
+	}
+	Log2(PCSC_LOG_DEBUG, "SHMClientReadMessage: Issuing read for %d bytes", dataSize);
+	secdebug("pcscd", "SHMClientReadMessage: Issuing read for %ld bytes", dataSize);
+	if (blockamount == 0)
+		blockamount = PCSCLITE_SERVER_ATTEMPTS;
+	rv = SHMMessageReceive(msgStruct->data, dataSize, dwClientID, blockamount);
+	Log3(rv?PCSC_LOG_CRITICAL:PCSC_LOG_DEBUG, "SHMClientReadMessage: read message body error: 0x%08X [0x%08X]", rv, rv);
+	secdebug("pcscd", "SHMClientReadMessage: read message body error: 0x%08X [0x%08X]", rv, rv);
+	return rv;
+}
+
+/**
+ * @brief Prepares a communication channel for the client to talk to the server.
+ *
+ * This is called by the application to create a socket for local IPC with the
+ * server. The socket is associated to the file \c PCSCLITE_CSOCK_NAME.
+ *
+ * @param[out] pdwClientID Client Connection ID.
+ *
+ * @retval 0 Success.
+ * @retval -1 Can not create the socket.
+ * @retval -1 The socket can not open a connection.
+ * @retval -1 Can not set the socket to non-blocking.
+ */
+INTERNAL int SHMClientSetupSession(PDWORD pdwClientID)
+{
+	struct sockaddr_un svc_addr;
+	int one;
+	int ret;
+
+	ret = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (ret < 0)
+	{
+		Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
+			strerror(errno));
+		return -1;
+	}
+	*pdwClientID = ret;
+
+	svc_addr.sun_family = AF_UNIX;
+	strncpy(svc_addr.sun_path, PCSCLITE_CSOCK_NAME,
+		sizeof(svc_addr.sun_path));
+
+	if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
+			sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
+	{
+		Log2(PCSC_LOG_CRITICAL, "Error: connect to client socket: %s",
+			strerror(errno));
+		SYS_CloseFile(*pdwClientID);
+		return -1;
+	}
+
+	one = 1;
+	if (ioctl(*pdwClientID, FIONBIO, &one) < 0)
+	{
+		Log2(PCSC_LOG_CRITICAL, "Error: cannot set socket nonblocking: %s",
+			strerror(errno));
+		SYS_CloseFile(*pdwClientID);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * @brief Closes the socket used by the client to communicate with the server.
+ *
+ * @param[in] dwClientID Client socket handle to be closed.
+ *
+ * @retval 0 Success.
+ */
+INTERNAL int SHMClientCloseSession(DWORD dwClientID)
+{
+	SYS_CloseFile(dwClientID);
+	return 0;
+}
+
+/**
+ * @brief CalculateMessageSize
+ *
+ * @param[in] dataSize Size of the additional data to send in the message.
+ *
+ * @retval total message size.
+ */
+INTERNAL size_t SHMCalculateMessageSize(size_t dataSize)
+{
+	// PCSCLITE_MAX_MESSAGE_SIZE == sizeof(sharedSegmentMsg.data)
+	return sizeof(sharedSegmentMsg) - PCSCLITE_MAX_MESSAGE_SIZE + dataSize;;
+}
+
+
+/**
+ * @brief Sends a menssage from client to server or vice-versa.
+ *
+ * Writes the message in the shared file \c filedes.
+ *
+ * @param[in] buffer_void Message to be sent.
+ * @param[in] buffer_size Size of the message to send
+ * @param[in] filedes Socket handle.
+ * @param[in] blockAmount Timeout in milliseconds.
+ *
+ * @retval 0 Success
+ * @retval -1 Timeout.
+ * @retval -1 Socket is closed.
+ * @retval -1 A signal was received.
+ */
+INTERNAL int SHMMessageSend(void *buffer_void, size_t buffer_size,
+	int filedes, int blockAmount)
+{
+	char *buffer = (char *)buffer_void;
+
+	/*
+	 * default is success
+	 */
+	int retval = 0;
+	/*
+	 * record the time when we started
+	 */
+	time_t start = time(0);
+	/*
+	 * how many bytes remains to be written
+	 */
+	size_t remaining = buffer_size;
+
+	LogXxd(PCSC_LOG_DEBUG, "==> SHMMessageSend:\n", (const unsigned char *)buffer, buffer_size);
+
+	/*
+	 * repeat until all data is written
+	 */
+	while (remaining > 0)
+	{
+		fd_set write_fd;
+		struct timeval timeout;
+		int selret;
+
+		FD_ZERO(&write_fd);
+		FD_SET(filedes, &write_fd);
+
+		timeout.tv_usec = 0;
+		if ((timeout.tv_sec = start + blockAmount - time(0)) < 0)
+		{
+			/*
+			 * we already timed out
+			 */
+			Log1(PCSC_LOG_ERROR, "SHMMessageReceive: we already timed out");
+			retval = -1;
+			break;
+		}
+
+		selret = select(filedes + 1, NULL, &write_fd, NULL, &timeout);
+
+		/*
+		 * try to write only when the file descriptor is writable
+		 */
+		if (selret > 0)
+		{
+			int written;
+
+			if (!FD_ISSET(filedes, &write_fd))
+			{
+				/*
+				 * very strange situation. it should be an assert really
+				 */
+				Log1(PCSC_LOG_ERROR, "SHMMessageReceive: very strange situation: !FD_ISSET");
+				retval = -1;
+				break;
+			}
+			written = write(filedes, buffer, remaining);
+
+			if (written > 0)
+			{
+				/*
+				 * we wrote something
+				 */
+				buffer += written;
+				remaining -= written;
+			} else if (written == 0)
+			{
+				/*
+				 * peer closed the socket
+				 */
+				Log1(PCSC_LOG_ERROR, "SHMMessageReceive: peer closed the socket");
+				retval = -1;
+				break;
+			} else
+			{
+				/*
+				 * we ignore the signals and socket full situations, all
+				 * other errors are fatal
+				 */
+				if (errno != EINTR && errno != EAGAIN)
+				{
+					retval = -1;
+					break;
+				}
+			}
+		} else if (selret == 0)
+		{
+			/*
+			 * timeout
+			 */
+			Log1(PCSC_LOG_ERROR, "SHMMessageReceive: selret == 0 [timeout]");
+			retval = -1;
+			break;
+		} else
+		{
+			/*
+			 * ignore signals
+			 */
+			if (errno != EINTR)
+			{
+				Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
+					strerror(errno));
+				retval = -1;
+				break;
+			}
+		}
+	}
+
+	if (remaining > 0)
+		Log3(PCSC_LOG_ERROR, "failure to write all bytes, remaining: %d, err: ", remaining, strerror(errno));
+		
+	return retval;
+}
+
+/**
+ * @brief Called by the Client to get the reponse from the server or vice-versa.
+ *
+ * Reads the message from the file \c filedes.
+ *
+ * @param[out] buffer_void Message read.
+ * @param[in] buffer_size Size to read
+ * @param[in] filedes Socket handle.
+ * @param[in] blockAmount Timeout in milliseconds.
+ *
+ * @retval 0 Success.
+ * @retval -1 Timeout.
+ * @retval -1 Socket is closed.
+ * @retval -1 A signal was received.
+ */
+INTERNAL int SHMMessageReceive(void *buffer_void, size_t buffer_size,
+	int filedes, int blockAmount)
+{
+	char *buffer = (char *)buffer_void;
+
+	/*
+	 * default is success
+	 */
+	int retval = 0;
+	/*
+	 * record the time when we started
+	 */
+	time_t start = time(0);
+	/*
+	 * how many bytes we must read
+	 */
+	size_t remaining = buffer_size;
+
+	/*
+	 * repeat until we get the whole message
+	 */
+	while (remaining > 0)
+	{
+		fd_set read_fd;
+		struct timeval timeout;
+		int selret;
+
+		FD_ZERO(&read_fd);
+		FD_SET(filedes, &read_fd);
+
+		timeout.tv_usec = 0;
+		if ((timeout.tv_sec = start + blockAmount - time(0)) < 0)
+		{
+			/*
+			 * we already timed out
+			 */
+			Log1(PCSC_LOG_ERROR, "SHMMessageReceive: we already timed out");
+			retval = -1;
+			break;
+		}
+
+		selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
+
+		/*
+		 * try to read only when socket is readable
+		 */
+		if (selret > 0)
+		{
+			int readed;
+
+			if (!FD_ISSET(filedes, &read_fd))
+			{
+				/*
+				 * very strange situation. it should be an assert really
+				 */
+				Log1(PCSC_LOG_ERROR, "SHMMessageReceive: very strange situation: !FD_ISSET");
+				retval = -1;
+				break;
+			}
+			readed = read(filedes, buffer, remaining);
+
+			if (readed > 0)
+			{
+				/*
+				 * we got something
+				 */
+				buffer += readed;
+				remaining -= readed;
+			} else if (readed == 0)
+			{
+				/*
+				 * peer closed the socket
+				 */
+				Log1(PCSC_LOG_ERROR, "SHMMessageReceive: peer closed the socket");
+				retval = -1;
+				break;
+			} else
+			{
+				/*
+				 * we ignore the signals and empty socket situations, all
+				 * other errors are fatal
+				 */
+				if (errno != EINTR && errno != EAGAIN)
+				{
+					retval = -1;
+					break;
+				}
+			}
+		} else if (selret == 0)
+		{
+			/*
+			 * timeout
+			 */
+			Log1(PCSC_LOG_ERROR, "SHMMessageReceive: selret == 0 [timeout]");
+			retval = -1;
+			break;
+		} else
+		{
+			/*
+			 * we ignore signals, all other errors are fatal
+			 */
+			if (errno != EINTR)
+			{
+				Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
+					strerror(errno));
+				retval = -1;
+				break;
+			}
+		}
+	}
+
+	size_t bytesRead = (buffer_size - remaining);
+	Log3(PCSC_LOG_DEBUG, "SHMMessageReceive errno: 0x%08X: %s", errno, errno?strerror(errno):"no error");
+	Log3(retval?PCSC_LOG_ERROR:PCSC_LOG_DEBUG, "SHMMessageReceive retval: 0x%08X, bytes read: %d", retval, bytesRead);
+	LogXxd(PCSC_LOG_DEBUG, "<== SHMMessageReceive:\n", (const unsigned char *)buffer_void, bytesRead);
+	return retval;
+}
+
+/**
+ * @brief Wrapper for the SHMMessageSend() function.
+ *
+ * Called by clients to send messages to the server.
+ * The parameters \p command and \p data are set in the \c sharedSegmentMsg
+ * struct in order to be sent.
+ *
+ * @param[in] command Command to be sent.
+ * @param[in] dwClientID Client socket handle.
+ * @param[in] size Size of the message (\p data).
+ * @param[in] blockAmount Timeout to the operation in ms.
+ * @param[in] data_void Data to be sent.
+ *
+ * @return Same error codes as SHMMessageSend().
+ */
+INTERNAL int WrapSHMWrite(unsigned int command, DWORD dwClientID,
+	unsigned int dataSize, unsigned int blockAmount, void *data_void)
+{
+	char *data = (char *)data_void;
+
+	sharedSegmentMsg msgStruct;
+	int ret;
+
+	/*
+	 * Set the appropriate packet parameters
+	 */
+
+	memset(&msgStruct, 0, sizeof(msgStruct));
+	msgStruct.headerTag = WINSCARD_MSG_HEADER_TAG;
+	msgStruct.msgSize = sizeof(sharedSegmentMsg) - sizeof(msgStruct.data) + dataSize;
+	msgStruct.mtype = (command == CMD_VERSION)?CMD_VERSION:CMD_FUNCTION;
+	msgStruct.user_id = SYS_GetUID();
+	msgStruct.group_id = SYS_GetGID();
+	msgStruct.command = command;
+	msgStruct.date = time(NULL);
+
+	if ((SCARD_TRANSMIT_EXTENDED == command)
+		|| (SCARD_CONTROL_EXTENDED == command))
+	{
+		/* first block */
+		size_t sizeToSend = (msgStruct.msgSize <= PCSCLITE_MAX_MESSAGE_SIZE)?msgStruct.msgSize:PCSCLITE_MAX_MESSAGE_SIZE;
+		size_t sizeRemaining = (msgStruct.msgSize <= PCSCLITE_MAX_MESSAGE_SIZE)?0:
+			(msgStruct.msgSize - PCSCLITE_MAX_MESSAGE_SIZE);
+		memcpy(msgStruct.data, data, sizeToSend);
+		SHSharedSegmentMsgToNetworkOrder(&msgStruct);
+		ret = SHMMessageSend(&msgStruct, sizeToSend, dwClientID,
+			blockAmount);
+		if (ret)
+			return ret;
+
+		// Warning: this code only works for sizes of 2 blocks or less
+		if (sizeRemaining > PCSCLITE_MAX_MESSAGE_SIZE)
+		{
+			Log2(PCSC_LOG_ERROR, "WrapSHMWrite: cannot send message of size %d", msgStruct.msgSize);
+			return -1;
+		}
+		
+		/* do not send an empty second block */
+		if (sizeRemaining > 0)
+		{
+			/* second block */
+			ret = SHMMessageSend(data+PCSCLITE_MAX_MESSAGE_SIZE,
+				sizeRemaining, dwClientID, blockAmount);
+			if (ret)
+				return ret;
+		}
+	}
+	else
+	if (msgStruct.msgSize > PCSCLITE_MAX_MESSAGE_SIZE)
+	{
+		Log3(PCSC_LOG_ERROR, "WrapSHMWrite: cannot send message of size %d with this command: %d", msgStruct.msgSize, command);
+		return -1;
+	}
+	else
+	{
+		size_t savedSize = msgStruct.msgSize;
+		
+		memcpy(msgStruct.data, data, dataSize);
+		SHSharedSegmentMsgToNetworkOrder(&msgStruct);
+		ret = SHMMessageSend(&msgStruct, savedSize, dwClientID, blockAmount);
+	}
+	return ret;
+}
+
+/**
+ * @brief Closes the communications channel used by the server to talk to the
+ * clients.
+ *
+ * The socket used is closed and the file it is bound to is removed.
+ *
+ * @param[in] sockValue Socket to be closed.
+ * @param[in] pcFilePath File used by the socket.
+ */
+INTERNAL void SHMCleanupSharedSegment(int sockValue, const char *pcFilePath)
+{
+	SYS_CloseFile(sockValue);
+	SYS_Unlink((char *)pcFilePath);
+}
+
+#pragma mark -------------------- Byte ordering functions --------------------
+
+/**
+ * @brief Convert fields in the psharedSegmentMsg struct to network byte order for sending
+ *
+ * Call this before each call to SHMMessageSend. Note: the data fields are not processed
+ * and need to be done individually. Also have to look for WrapSHMWrite.
+ *
+ * @param[in/out] msgStruct Message read.
+ *
+ */
+INTERNAL void SHSharedSegmentMsgToNetworkOrder(psharedSegmentMsg msg)
+{
+	if (msg)
+	{
+		msg->headerTag = htonl(msg->headerTag);
+		msg->msgSize = htonl(msg->msgSize);
+		msg->mtype = htonl(msg->mtype);
+		msg->user_id = htonl(msg->user_id);
+		msg->group_id = htonl(msg->group_id);
+		msg->command = htonl(msg->command);
+		msg->dummy = htonl(msg->dummy);
+		msg->date = htonl(msg->date);
+	}
+}
+
+/**
+ * @brief Convert fields in the psharedSegmentMsg struct to host byte order on receive
+ *
+ * Call this after each call to SHMMessageReceive. Note: the data fields are not processed
+ * and need to be done individually, e.g. in MSGFunctionDemarshall
+ *
+ * @param[in/out] msgStruct Message read.
+ *
+ */
+INTERNAL void SHSharedSegmentMsgToHostOrder(psharedSegmentMsg msg)
+{
+	if (msg)
+	{
+		msg->headerTag = ntohl(msg->headerTag);
+		msg->msgSize = ntohl(msg->msgSize);
+		msg->mtype = ntohl(msg->mtype);
+		msg->user_id = ntohl(msg->user_id);
+		msg->group_id = ntohl(msg->group_id);
+		msg->command = ntohl(msg->command);
+		msg->dummy = ntohl(msg->dummy);
+		msg->date = ntohl(msg->date);
+	}
+}
+
+INTERNAL void htonlControlStructExtended(control_struct_extended *cs)
+{
+	if (cs)
+	{
+		cs->hCard = htonl(cs->hCard);
+		cs->dwControlCode = htonl(cs->dwControlCode);
+		cs->cbSendLength = htonl(cs->cbSendLength);
+		cs->cbRecvLength = htonl(cs->cbRecvLength);
+		cs->size = htonl(cs->size);
+		cs->rv = htonl(cs->rv);			// so we don't forget about it
+	}
+}
+
+INTERNAL void ntohlControlStructExtended(control_struct_extended *cs)
+{
+	if (cs)
+	{
+		cs->hCard = ntohl(cs->hCard);
+		cs->dwControlCode = ntohl(cs->dwControlCode);
+		cs->cbSendLength = ntohl(cs->cbSendLength);
+		cs->cbRecvLength = ntohl(cs->cbRecvLength);
+		cs->size = ntohl(cs->size);
+		cs->rv = ntohl(cs->rv);
+	}
+}
+
+INTERNAL void htonlTransmitStruct(transmit_struct *ts)
+{
+	if (ts)
+	{
+		ts->hCard = htonl(ts->hCard);
+		htonlSCARD_IO_REQUEST(&ts->pioSendPci);
+		ts->cbSendLength = htonl(ts->cbSendLength);
+		htonlSCARD_IO_REQUEST(&ts->pioRecvPci);
+		ts->pcbRecvLength = htonl(ts->pcbRecvLength);
+		ts->rv = htonl(ts->rv);			// so we don't forget about it
+	}
+}
+
+INTERNAL void ntohlTransmitStruct(transmit_struct *ts)
+{
+	if (ts)
+	{
+		ts->hCard = ntohl(ts->hCard);
+		ntohlSCARD_IO_REQUEST(&ts->pioSendPci);
+		ts->cbSendLength = ntohl(ts->cbSendLength);
+		ntohlSCARD_IO_REQUEST(&ts->pioRecvPci);
+		ts->pcbRecvLength = ntohl(ts->pcbRecvLength);
+		ts->rv = ntohl(ts->rv);
+	}
+}
+
+INTERNAL void htonlTransmitStructExtended(transmit_struct_extended *ts)
+{
+	if (ts)
+	{
+		ts->hCard = htonl(ts->hCard);
+		htonlSCARD_IO_REQUEST(&ts->pioSendPci);
+		ts->cbSendLength = htonl(ts->cbSendLength);
+		htonlSCARD_IO_REQUEST(&ts->pioRecvPci);
+		ts->pcbRecvLength = htonl(ts->pcbRecvLength);
+		ts->size = htonl(ts->size);
+		ts->rv = htonl(ts->rv);			// so we don't forget about it
+	}
+}
+
+INTERNAL void ntohlTransmitStructExtended(transmit_struct_extended *ts)
+{
+	if (ts)
+	{
+		ts->hCard = ntohl(ts->hCard);
+		ntohlSCARD_IO_REQUEST(&ts->pioSendPci);
+		ts->cbSendLength = ntohl(ts->cbSendLength);
+		ntohlSCARD_IO_REQUEST(&ts->pioRecvPci);
+		ts->pcbRecvLength = ntohl(ts->pcbRecvLength);
+		ts->size = ntohl(ts->size);
+		ts->rv = ntohl(ts->rv);
+	}
+}
+
+INTERNAL void htonlSCARD_IO_REQUEST(SCARD_IO_REQUEST *req)
+{
+	if (req)
+	{
+		req->dwProtocol = htonl(req->dwProtocol);
+		req->cbPciLength = htonl(req->cbPciLength);
+	}
+}
+
+INTERNAL void ntohlSCARD_IO_REQUEST(SCARD_IO_REQUEST *req)
+{
+	if (req)
+	{
+		req->dwProtocol = ntohl(req->dwProtocol);
+		req->cbPciLength = ntohl(req->cbPciLength);
+	}
+}
+
+INTERNAL void htonlEstablishStruct(establish_struct *es)
+{
+	if (es)
+	{
+		es->dwScope = htonl(es->dwScope);
+		es->phContext = htonl(es->phContext);
+		es->rv = htonl(es->rv);
+	}
+}
+
+INTERNAL void ntohlEstablishStruct(establish_struct *es)
+{
+	if (es)
+	{
+		es->dwScope = ntohl(es->dwScope);
+		es->phContext = ntohl(es->phContext);
+		es->rv = ntohl(es->rv);
+	}
+}
+
+INTERNAL void htonlReleaseStruct(release_struct *rs)
+{
+	if (rs)
+	{
+		rs->hContext = htonl(rs->hContext);
+		rs->rv = htonl(rs->rv);
+	}
+}
+
+INTERNAL void ntohlReleaseStruct(release_struct *rs)
+{
+	if (rs)
+	{
+		rs->hContext = ntohl(rs->hContext);
+		rs->rv = ntohl(rs->rv);
+	}
+}
+
+INTERNAL void htonlConnectStruct(connect_struct *cs)
+{
+	if (cs)
+	{
+		cs->hContext = htonl(cs->hContext);
+		cs->dwShareMode = htonl(cs->dwShareMode);
+		cs->dwPreferredProtocols = htonl(cs->dwPreferredProtocols);
+		cs->phCard = htonl(cs->phCard);
+		cs->pdwActiveProtocol = htonl(cs->pdwActiveProtocol);
+		cs->rv = htonl(cs->rv);
+	}
+}
+
+INTERNAL void ntohlConnectStruct(connect_struct *cs)
+{
+	if (cs)
+	{
+		cs->hContext = ntohl(cs->hContext);
+		cs->dwShareMode = ntohl(cs->dwShareMode);
+		cs->dwPreferredProtocols = ntohl(cs->dwPreferredProtocols);
+		cs->phCard = ntohl(cs->phCard);
+		cs->pdwActiveProtocol = ntohl(cs->pdwActiveProtocol);
+		cs->rv = ntohl(cs->rv);
+	}
+}
+
+INTERNAL void htonlReconnectStruct(reconnect_struct *rc)
+{
+	if (rc)
+	{
+		rc->hCard = htonl(rc->hCard);
+		rc->dwShareMode = htonl(rc->dwShareMode);
+		rc->dwPreferredProtocols = htonl(rc->dwPreferredProtocols);
+		rc->dwInitialization = htonl(rc->dwInitialization);
+		rc->pdwActiveProtocol = htonl(rc->pdwActiveProtocol);
+		rc->rv = htonl(rc->rv);
+	}
+}
+
+INTERNAL void ntohlReconnectStruct(reconnect_struct *rc)
+{
+	if (rc)
+	{
+		rc->hCard = ntohl(rc->hCard);
+		rc->dwShareMode = ntohl(rc->dwShareMode);
+		rc->dwPreferredProtocols = ntohl(rc->dwPreferredProtocols);
+		rc->dwInitialization = ntohl(rc->dwInitialization);
+		rc->pdwActiveProtocol = ntohl(rc->pdwActiveProtocol);
+		rc->rv = ntohl(rc->rv);
+	}
+}
+
+INTERNAL void htonlDisconnectStruct(disconnect_struct *dc)
+{
+	if (dc)
+	{
+		dc->hCard = htonl(dc->hCard);
+		dc->dwDisposition = htonl(dc->dwDisposition);
+		dc->rv = htonl(dc->rv);
+	}
+}
+
+INTERNAL void ntohlDisconnectStruct(disconnect_struct *dc)
+{
+	if (dc)
+	{
+		dc->hCard = ntohl(dc->hCard);
+		dc->dwDisposition = ntohl(dc->dwDisposition);
+		dc->rv = ntohl(dc->rv);
+	}
+}
+
+INTERNAL void htonlBeginStruct(begin_struct *bs)
+{
+	if (bs)
+	{
+		bs->hCard = htonl(bs->hCard);
+		bs->rv = htonl(bs->rv);
+	}
+}
+
+INTERNAL void ntohlBeginStruct(begin_struct *bs)
+{
+	if (bs)
+	{
+		bs->hCard = ntohl(bs->hCard);
+		bs->rv = ntohl(bs->rv);
+	}
+}
+
+INTERNAL void htonlCancelStruct(cancel_struct *cs)
+{
+	if (cs)
+	{
+		cs->hCard = htonl(cs->hCard);
+		cs->rv = htonl(cs->rv);
+	}
+}
+
+INTERNAL void ntohlCancelStruct(cancel_struct *cs)
+{
+	if (cs)
+	{
+		cs->hCard = ntohl(cs->hCard);
+		cs->rv = ntohl(cs->rv);
+	}
+}
+
+INTERNAL void htonlEndStruct(end_struct *es)
+{
+	if (es)
+	{
+		es->hCard = htonl(es->hCard);
+		es->dwDisposition = htonl(es->dwDisposition);
+		es->rv = htonl(es->rv);
+	}
+}
+
+INTERNAL void ntohlEndStruct(end_struct *es)
+{
+	if (es)
+	{
+		es->hCard = ntohl(es->hCard);
+		es->dwDisposition = ntohl(es->dwDisposition);
+		es->rv = ntohl(es->rv);
+	}
+}
+
+INTERNAL void htonlStatusStruct(status_struct *ss)
+{
+	if (ss)
+	{
+		ss->hCard = htonl(ss->hCard);
+		ss->pcchReaderLen = htonl(ss->pcchReaderLen);
+		ss->pdwState = htonl(ss->pdwState);
+		ss->pdwProtocol = htonl(ss->pdwProtocol);
+		ss->pcbAtrLen = htonl(ss->pcbAtrLen);
+		ss->rv = htonl(ss->rv);
+	}
+}
+
+INTERNAL void ntohlStatusStruct(status_struct *ss)
+{
+	if (ss)
+	{
+		ss->hCard = ntohl(ss->hCard);
+		ss->pcchReaderLen = ntohl(ss->pcchReaderLen);
+		ss->pdwState = ntohl(ss->pdwState);
+		ss->pdwProtocol = ntohl(ss->pdwProtocol);
+		ss->pcbAtrLen = ntohl(ss->pcbAtrLen);
+		ss->rv = ntohl(ss->rv);
+	}
+}
+
+INTERNAL void htonlControlStruct(control_struct *cs)
+{
+	if (cs)
+	{
+		cs->hCard = htonl(cs->hCard);
+		cs->dwControlCode = htonl(cs->dwControlCode);
+		cs->cbSendLength = htonl(cs->cbSendLength);
+		cs->cbRecvLength = htonl(cs->cbRecvLength);
+		cs->dwBytesReturned = htonl(cs->dwBytesReturned);
+		cs->rv = htonl(cs->rv);
+	}
+}
+
+INTERNAL void ntohlControlStruct(control_struct *cs)
+{
+	if (cs)
+	{
+		cs->hCard = ntohl(cs->hCard);
+		cs->dwControlCode = ntohl(cs->dwControlCode);
+		cs->cbSendLength = ntohl(cs->cbSendLength);
+		cs->cbRecvLength = ntohl(cs->cbRecvLength);
+		cs->dwBytesReturned = ntohl(cs->dwBytesReturned);
+		cs->rv = ntohl(cs->rv);
+	}
+}
+
+INTERNAL void htonlGetSetStruct(getset_struct *gs)
+{
+	if (gs)
+	{
+		gs->hCard = htonl(gs->hCard);
+		gs->dwAttrId = htonl(gs->dwAttrId);
+		gs->cbAttrLen = htonl(gs->cbAttrLen);
+		gs->rv = htonl(gs->rv);
+	}
+}
+
+INTERNAL void ntohlGetSetStruct(getset_struct *gs)
+{
+	if (gs)
+	{
+		gs->hCard = ntohl(gs->hCard);
+		gs->dwAttrId = ntohl(gs->dwAttrId);
+		gs->cbAttrLen = ntohl(gs->cbAttrLen);
+		gs->rv = ntohl(gs->rv);
+	}
+}
+
+INTERNAL void htonlVersionStruct(version_struct *vs)
+{
+	if (vs)
+	{
+		vs->major = htonl(vs->major);
+		vs->minor = htonl(vs->minor);
+		vs->rv = htonl(vs->rv);
+	}
+}
+
+INTERNAL void ntohlVersionStruct(version_struct *vs)
+{
+	if (vs)
+	{
+		vs->major = ntohl(vs->major);
+		vs->minor = ntohl(vs->minor);
+		vs->rv = ntohl(vs->rv);
+	}
+}
+

Added: trunk/SmartCardServices/src/PCSC/winscard_msg.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard_msg.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard_msg.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,421 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  winscard_msg.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2001-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Damien Sauveron <damien.sauveron at labri.fr>
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: winscard_msg.h 2308 2007-01-06 20:26:57Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This defines some structures and \#defines to be used over
+ * the transport layer.
+ */
+
+#ifndef __winscard_msg_h__
+#define __winscard_msg_h__
+
+#include "pcscexport.h"
+
+/** Major version of the current message protocol */
+#define PROTOCOL_VERSION_MAJOR 2
+/** Minor version of the current message protocol */
+#define PROTOCOL_VERSION_MINOR 2
+
+#define WINSCARD_MSG_HEADER_TAG	0x12345678
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	/**
+	 * @brief General structure for client/serve message data exchange.
+	 *
+	 * It is used in the calls of \c SHMMessageSend and \c SHMMessageReceive.
+	 * The field \c data is interpreted according to the values of the fields
+	 * \c mtype and \c command. The possible structs the \c data field can
+	 * represent are: \c version_struct \c client_struct \c establish_struct
+	 * \c release_struct \c connect_struct \c reconnect_struct
+	 * \c disconnect_struct \c begin_struct \c end_struct \c cancel_struct
+	 * \c status_struct \c transmit_struct \c control_struct \c getset_struct
+	 */
+	typedef struct rxSharedSegment
+	{
+		uint32_t headerTag;		/** Always WINSCARD_MSG_HEADER_TAG */
+		uint32_t msgSize;		/** size of the whole message being sent/received */
+		uint32_t mtype;			/** one of the \c pcsc_adm_commands */
+		uint32_t user_id;
+		uint32_t group_id;
+		uint32_t command;		/** one of the \c pcsc_msg_commands */
+		uint32_t dummy;			/* was request_id in pcsc-lite <= 1.2.0 */
+		time_t date;
+		unsigned char key[PCSCLITE_MSG_KEY_LEN];
+		unsigned char data[PCSCLITE_MAX_MESSAGE_SIZE];
+	}
+	sharedSegmentMsg, *psharedSegmentMsg;
+
+	/**
+	 * Command types available to use in the field \c sharedSegmentMsg.mtype.
+	 */
+	enum pcsc_adm_commands
+	{
+		CMD_FUNCTION = 0xF1,
+		CMD_FAILED = 0xF2,
+		CMD_SERVER_DIED = 0xF3,
+		CMD_CLIENT_DIED = 0xF4,
+		CMD_READER_EVENT = 0xF5,
+		CMD_SYN = 0xF6,
+		CMD_ACK = 0xF7,
+		CMD_VERSION = 0xF8
+	};
+
+	/**
+	 * @brief Commands available to use in the field \c sharedSegmentMsg.command.
+	 */
+	enum pcsc_msg_commands
+	{
+		SCARD_ESTABLISH_CONTEXT = 0x01,
+		SCARD_RELEASE_CONTEXT = 0x02,
+		SCARD_LIST_READERS = 0x03,
+		SCARD_CONNECT = 0x04,
+		SCARD_RECONNECT = 0x05,
+		SCARD_DISCONNECT = 0x06,
+		SCARD_BEGIN_TRANSACTION = 0x07,
+		SCARD_END_TRANSACTION = 0x08,
+		SCARD_TRANSMIT = 0x09,
+		SCARD_CONTROL = 0x0A,
+		SCARD_STATUS = 0x0B,
+		SCARD_GET_STATUS_CHANGE = 0x0C,
+		SCARD_CANCEL = 0x0D,
+		SCARD_CANCEL_TRANSACTION = 0x0E,
+		SCARD_GET_ATTRIB = 0x0F,
+		SCARD_SET_ATTRIB = 0x10,
+		SCARD_TRANSMIT_EXTENDED = 0x11,
+		SCARD_CONTROL_EXTENDED = 0x12
+	};
+
+	/**
+	 * @brief Information transmitted in \c CMD_VERSION Messages.
+	 */
+	struct version_struct
+	{
+		int major;
+		int minor;
+		LONG rv;
+	};
+	typedef struct version_struct version_struct;
+
+	struct client_struct
+	{
+		SCARDCONTEXT hContext;
+	};
+	typedef struct client_struct client_struct;
+
+	/**
+	 * @brief Information contained in \c SCARD_ESTABLISH_CONTEXT Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct establish_struct
+	{
+		DWORD dwScope;
+		SCARDCONTEXT phContext;
+		LONG rv;
+	};
+	typedef struct establish_struct establish_struct;
+
+	/**
+	 * @brief Information contained in \c SCARD_RELEASE_CONTEXT Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct release_struct
+	{
+		SCARDCONTEXT hContext;
+		LONG rv;
+	};
+	typedef struct release_struct release_struct;
+
+	/**
+	 * @brief contained in \c SCARD_CONNECT Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct connect_struct
+	{
+		SCARDCONTEXT hContext;
+		char szReader[MAX_READERNAME];
+		DWORD dwShareMode;
+		DWORD dwPreferredProtocols;
+		SCARDHANDLE phCard;
+		DWORD pdwActiveProtocol;
+		LONG rv;
+	};
+	typedef struct connect_struct connect_struct;
+
+	/**
+	 * @brief contained in \c SCARD_RECONNECT Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct reconnect_struct
+	{
+		SCARDHANDLE hCard;
+		DWORD dwShareMode;
+		DWORD dwPreferredProtocols;
+		DWORD dwInitialization;
+		DWORD pdwActiveProtocol;
+		LONG rv;
+	};
+	typedef struct reconnect_struct reconnect_struct;
+
+	/**
+	 * @brief contained in \c SCARD_DISCONNECT Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct disconnect_struct
+	{
+		SCARDHANDLE hCard;
+		DWORD dwDisposition;
+		LONG rv;
+	};
+	typedef struct disconnect_struct disconnect_struct;
+
+	/**
+	 * @brief contained in \c SCARD_BEGIN_TRANSACTION Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct begin_struct
+	{
+		SCARDHANDLE hCard;
+		LONG rv;
+	};
+	typedef struct begin_struct begin_struct;
+
+	/**
+	 * @brief contained in \c SCARD_END_TRANSACTION Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct end_struct
+	{
+		SCARDHANDLE hCard;
+		DWORD dwDisposition;
+		LONG rv;
+	};
+	typedef struct end_struct end_struct;
+
+	/**
+	 * @brief contained in \c SCARD_CANCEL Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct cancel_struct
+	{
+		SCARDHANDLE hCard;
+		LONG rv;
+	};
+	typedef struct cancel_struct cancel_struct;
+
+	/**
+	 * @brief contained in \c SCARD_STATUS Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct status_struct
+	{
+		SCARDHANDLE hCard;
+		char mszReaderNames[MAX_READERNAME];
+		DWORD pcchReaderLen;
+		DWORD pdwState;
+		DWORD pdwProtocol;
+		UCHAR pbAtr[MAX_ATR_SIZE];
+		DWORD pcbAtrLen;
+		LONG rv;
+	};
+	typedef struct status_struct status_struct;
+
+	/**
+	 * @brief contained in \c SCARD_TRANSMIT Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct transmit_struct
+	{
+		SCARDHANDLE hCard;
+		SCARD_IO_REQUEST pioSendPci;
+		UCHAR pbSendBuffer[MAX_BUFFER_SIZE];
+		DWORD cbSendLength;
+		SCARD_IO_REQUEST pioRecvPci;
+		BYTE pbRecvBuffer[MAX_BUFFER_SIZE];
+		DWORD pcbRecvLength;
+		LONG rv;
+	};
+	typedef struct transmit_struct transmit_struct;
+
+	/**
+	 * @brief contained in \c SCARD_TRANSMIT_EXTENDED Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct transmit_struct_extended
+	{
+		SCARDHANDLE hCard;
+		SCARD_IO_REQUEST pioSendPci;
+		DWORD cbSendLength;
+		SCARD_IO_REQUEST pioRecvPci;
+		DWORD pcbRecvLength;
+		LONG rv;
+		size_t size;
+		BYTE data[1];
+	};
+	typedef struct transmit_struct_extended transmit_struct_extended;
+
+	/**
+	 * @brief contained in \c SCARD_CONTROL Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct control_struct
+	{
+		SCARDHANDLE hCard;
+		DWORD dwControlCode;
+		UCHAR pbSendBuffer[MAX_BUFFER_SIZE];
+		DWORD cbSendLength;
+		UCHAR pbRecvBuffer[MAX_BUFFER_SIZE];
+		DWORD cbRecvLength;
+		DWORD dwBytesReturned;
+		LONG rv;
+	};
+	typedef struct control_struct control_struct;
+
+	/**
+	 * @brief contained in \c SCARD_CONTROL_EXTENDED Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct control_struct_extended
+	{
+		SCARDHANDLE hCard;
+		DWORD dwControlCode;
+		DWORD cbSendLength;
+		DWORD cbRecvLength;
+		DWORD pdwBytesReturned;
+		LONG rv;
+		size_t size;
+		BYTE data[1];
+	};
+	typedef struct control_struct_extended control_struct_extended;
+
+	/**
+	 * @brief contained in \c SCARD_GET_ATTRIB and \c  Messages.
+	 *
+	 * These data are passed throw the field \c sharedSegmentMsg.data.
+	 */
+	struct getset_struct
+	{
+		SCARDHANDLE hCard;
+		DWORD dwAttrId;
+		UCHAR pbAttr[MAX_BUFFER_SIZE];
+		DWORD cbAttrLen;
+		LONG rv;
+	};
+	typedef struct getset_struct getset_struct;
+
+	/*
+	 * Now some function definitions
+	 */
+
+	int SHMClientReadMessage(psharedSegmentMsg msgStruct, DWORD dwClientID, size_t dataSize, int blockamount);
+	int SHMClientRead(psharedSegmentMsg, DWORD, int);
+	int SHMClientSetupSession(PDWORD);
+	int SHMClientCloseSession(DWORD);
+	int SHMInitializeCommonSegment(void);
+	int SHMProcessEventsContext(PDWORD, psharedSegmentMsg, int);
+	int SHMProcessEventsServer(PDWORD, int);
+	int SHMMessageSend(void *buffer, size_t buffer_size, int filedes,
+		int blockAmount);
+	int SHMMessageReceive(void *buffer, size_t buffer_size,
+		int filedes, int blockAmount);
+	int WrapSHMWrite(unsigned int command, DWORD dwClientID, unsigned int dataSize,
+		unsigned int blockAmount, void *data);
+	void SHMCleanupSharedSegment(int, const char *);
+
+	void SHSharedSegmentMsgToNetworkOrder(psharedSegmentMsg msg);
+	void SHSharedSegmentMsgToHostOrder(psharedSegmentMsg msg);
+	size_t SHMCalculateMessageSize(size_t dataSize);
+	int SHMCommunicationTimeout();
+
+	// Fix up byte ordering
+	INTERNAL void htonlControlStructExtended(control_struct_extended *cs);
+	INTERNAL void ntohlControlStructExtended(control_struct_extended *cs);
+	INTERNAL void htonlTransmitStructExtended(transmit_struct_extended *ts);
+	INTERNAL void ntohlTransmitStructExtended(transmit_struct_extended *ts);
+	INTERNAL void htonlSCARD_IO_REQUEST(SCARD_IO_REQUEST *req);
+	INTERNAL void ntohlSCARD_IO_REQUEST(SCARD_IO_REQUEST *req);
+	INTERNAL void htonlEstablishStruct(establish_struct *es);
+	INTERNAL void ntohlEstablishStruct(establish_struct *es);
+	INTERNAL void htonlTransmitStruct(transmit_struct *ts);
+	INTERNAL void ntohlTransmitStruct(transmit_struct *ts);
+	INTERNAL void htonlReleaseStruct(release_struct *rs);
+	INTERNAL void ntohlReleaseStruct(release_struct *rs);
+	INTERNAL void htonlConnectStruct(connect_struct *Cs);
+	INTERNAL void ntohlConnectStruct(connect_struct *cs);
+	INTERNAL void htonlReconnectStruct(reconnect_struct *rc);
+	INTERNAL void ntohlReconnectStruct(reconnect_struct *rc);
+	INTERNAL void htonlDisconnectStruct(disconnect_struct *dc);
+	INTERNAL void ntohlDisconnectStruct(disconnect_struct *dc);
+	INTERNAL void htonlBeginStruct(begin_struct *bs);
+	INTERNAL void ntohlBeginStruct(begin_struct *bs);
+	INTERNAL void htonlCancelStruct(cancel_struct *cs);
+	INTERNAL void ntohlCancelStruct(cancel_struct *cs);
+	INTERNAL void htonlEndStruct(end_struct *es);
+	INTERNAL void ntohlEndStruct(end_struct *es);
+	INTERNAL void htonlStatusStruct(status_struct *ss);
+	INTERNAL void ntohlStatusStruct(status_struct *ss);
+	INTERNAL void htonlControlStruct(control_struct *cs);
+	INTERNAL void ntohlControlStruct(control_struct *cs);
+	INTERNAL void htonlGetSetStruct(getset_struct *gs);
+	INTERNAL void ntohlGetSetStruct(getset_struct *gs);
+	INTERNAL void htonlVersionStruct(version_struct *vs);
+	INTERNAL void ntohlVersionStruct(version_struct *vs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PCSC/winscard_msg_srv.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard_msg_srv.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard_msg_srv.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,305 @@
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2001-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Damien Sauveron <damien.sauveron at labri.fr>
+ *  Ludoic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: winscard_msg_srv.c 2377 2007-02-05 13:13:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief client/server communication (on the server side only)
+ *
+ * A file based socket (\c commonSocket) is used to send/receive only messages
+ * among clients and server.\n
+ * The messages' data are passed throw a memory mapped file: \c sharedSegmentMsg.
+ */
+
+#include "config.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#include "wintypes.h"
+#include "pcscexport.h"
+#include "winscard.h"
+#include "debuglog.h"
+#include "winscard_msg.h"
+#include "sys_generic.h"
+
+/**
+ * Socket to a file, used for clients-server comminication.
+ */
+static int commonSocket = 0;
+extern char AraKiri;
+extern char ReCheckSerialReaders;
+
+/**
+ * @brief Accepts a Client connection.
+ *
+ * Called by \c SHMProcessEventsServer().
+ *
+ * @param[out] pdwClientID Connection ID used to reference the Client.
+ *
+ * @return Error code.
+ * @retval 0 Success.
+ * @retval -1 Can not establish the connection.
+ * @retval -1 Can not set the connection to non-blocking mode.
+ */
+static int SHMProcessCommonChannelRequest(PDWORD pdwClientID)
+{
+	socklen_t clnt_len;
+	int new_sock;
+	struct sockaddr_un clnt_addr;
+	int one;
+
+	clnt_len = sizeof(clnt_addr);
+
+	if ((new_sock = accept(commonSocket, (struct sockaddr *) &clnt_addr,
+				&clnt_len)) < 0)
+	{
+		Log2(PCSC_LOG_CRITICAL, "Accept on common socket: %s",
+			strerror(errno));
+		return -1;
+	}
+
+	*pdwClientID = new_sock;
+
+	one = 1;
+	if (ioctl(*pdwClientID, FIONBIO, &one) < 0)
+	{
+		Log2(PCSC_LOG_CRITICAL, "Error: cannot set socket nonblocking: %s",
+			strerror(errno));
+		SYS_CloseFile(*pdwClientID);
+		*pdwClientID = -1;
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * @brief Prepares the communication channel used by the server to talk to the
+ * clients.
+ *
+ * This is called by the server to create a socket for local IPC with the
+ * clients. The socket is associated to the file \c PCSCLITE_CSOCK_NAME.
+ * Each client will open a connection to this socket.
+ *
+ * @return Error code.
+ * @retval 0 Success
+ * @retval -1 Can not create the socket.
+ * @retval -1 Can not bind the socket to the file \c PCSCLITE_CSOCK_NAME.
+ * @retval -1 Can not put the socket in listen mode.
+ */
+INTERNAL int SHMInitializeCommonSegment(void)
+{
+	static struct sockaddr_un serv_adr;
+
+	/*
+	 * Create the common shared connection socket
+	 */
+	if ((commonSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+	{
+		Log2(PCSC_LOG_CRITICAL, "Unable to create common socket: %s",
+			strerror(errno));
+		return -1;
+	}
+
+	serv_adr.sun_family = AF_UNIX;
+	strncpy(serv_adr.sun_path, PCSCLITE_CSOCK_NAME,
+		sizeof(serv_adr.sun_path));
+	SYS_Unlink(PCSCLITE_CSOCK_NAME);
+
+	if (bind(commonSocket, (struct sockaddr *) &serv_adr,
+			sizeof(serv_adr.sun_family) + strlen(serv_adr.sun_path) + 1) < 0)
+	{
+		Log2(PCSC_LOG_CRITICAL, "Unable to bind common socket: %s",
+			strerror(errno));
+		SHMCleanupSharedSegment(commonSocket, PCSCLITE_CSOCK_NAME);
+		return -1;
+	}
+
+	if (listen(commonSocket, 1) < 0)
+	{
+		Log2(PCSC_LOG_CRITICAL, "Unable to listen common socket: %s",
+			strerror(errno));
+		SHMCleanupSharedSegment(commonSocket, PCSCLITE_CSOCK_NAME);
+		return -1;
+	}
+
+	/*
+	 * Chmod the public entry channel
+	 */
+	SYS_Chmod(PCSCLITE_CSOCK_NAME, S_IRWXO | S_IRWXG | S_IRWXU);
+
+	return 0;
+}
+
+/**
+ * @brief Looks for messages sent by clients.
+ *
+ * This is called by the Server's function \c SVCServiceRunLoop().
+ *
+ * @param[out] pdwClientID Connection ID used to reference the Client.
+ * @param[in] blocktime Timeout (not used).
+ *
+ * @return Error code.
+ * @retval 0 Success.
+ * @retval -1 Error accessing the communication channel.
+ * @retval -1 Can not set the connection to non-blocking mode.
+ * @retval 2 Timeout.
+ */
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#define DO_TIMEOUT
+#endif
+INTERNAL int SHMProcessEventsServer(PDWORD pdwClientID, int blocktime)
+{
+	fd_set read_fd;
+	int selret;
+#ifdef DO_TIMEOUT
+	struct timeval tv;
+	 	
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+#endif
+
+	FD_ZERO(&read_fd);
+
+	/*
+	 * Set up the bit masks for select
+	 */
+	FD_SET(commonSocket, &read_fd);
+
+	selret = select(commonSocket + 1, &read_fd, (fd_set *) NULL,
+		(fd_set *) NULL,
+#ifdef DO_TIMEOUT
+		&tv
+#else
+		NULL
+#endif
+		);
+
+	if (selret < 0)
+	{
+		if (EINTR == errno)
+			return -2;
+
+		Log2(PCSC_LOG_CRITICAL, "Select returns with failure: %s",
+			strerror(errno));
+		return -1;
+	}
+
+	if (selret == 0)
+		/* timeout. On *BSD only */
+		return 2;
+
+	/*
+	 * A common pipe packet has arrived - it could be a new application
+	 */
+	if (FD_ISSET(commonSocket, &read_fd))
+	{
+		Log1(PCSC_LOG_DEBUG, "Common channel packet arrival");
+		if (SHMProcessCommonChannelRequest(pdwClientID) == -1)
+		{
+			Log2(PCSC_LOG_ERROR,
+				"error in SHMProcessCommonChannelRequest: %d", *pdwClientID);
+			return -1;
+		} else
+		{
+			Log2(PCSC_LOG_DEBUG,
+				"SHMProcessCommonChannelRequest detects: %d", *pdwClientID);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+/**
+ * @brief
+ *
+ * Called by \c ContextThread().
+ */
+INTERNAL int SHMProcessEventsContext(PDWORD pdwClientID, psharedSegmentMsg msgStruct, int blocktime)
+{
+	fd_set read_fd;
+	int selret, rv;
+	struct timeval tv;
+
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+
+	FD_ZERO(&read_fd);
+	FD_SET(*pdwClientID, &read_fd);
+
+	selret = select(*pdwClientID + 1, &read_fd, (fd_set *) NULL,
+		(fd_set *) NULL, &tv);
+
+	if (selret < 0)
+	{
+		Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
+			strerror(errno));
+		return -1;
+	}
+
+	if (selret == 0)
+	{
+//		Log3(PCSC_LOG_ERROR, "SHMProcessEventsContext: select timed out, errno: %d, %s", errno,
+//			strerror(errno));
+		/* timeout */
+		return 2;
+	}
+	
+	if (FD_ISSET(*pdwClientID, &read_fd))
+	{
+		/*
+		 * Return the current handle
+		 */
+		rv = SHMClientReadMessage(msgStruct, *pdwClientID, 0, SHMCommunicationTimeout());
+		if (rv == -1)
+		{	/* The client has died */
+			Log2(PCSC_LOG_DEBUG, "Client has disappeared: %d",
+				*pdwClientID);
+			msgStruct->mtype = CMD_CLIENT_DIED;
+			msgStruct->command = 0;
+			SYS_CloseFile(*pdwClientID);
+
+			return 0;
+		}
+
+		/*
+		 * Set the identifier handle
+		 */
+		Log2(PCSC_LOG_DEBUG, "correctly processed client: %d",
+			*pdwClientID);
+		return 1;
+	}
+
+	return -1;
+}
+
+INTERNAL int SHMCommunicationTimeout()
+{
+	int timeOut = PCSCLITE_SERVER_ATTEMPTS;
+#if !defined(NDEBUG)
+//	timeOut = 120 * 1000L;		// 120000 mS == 2 minutes
+//	timeOut = 5 * 1000L;		// 120000 mS == 2 minutes
+#endif
+	return timeOut;
+}

Added: trunk/SmartCardServices/src/PCSC/winscard_svc.c
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard_svc.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard_svc.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,867 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  winscard_svc.c
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2001-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Damien Sauveron <damien.sauveron at labri.fr>
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id: winscard_svc.c 2377 2007-02-05 13:13:56Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This demarshalls functions over the message queue and keeps
+ * track of clients and their handles.
+ *
+ * Each Client message is deald by creating a thread (\c CreateContextThread).
+ * The thread establishes reands and demarshalls the message and calls the
+ * appropriate function to threat it.
+ */
+
+#include "config.h"
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "wintypes.h"
+#include "pcsclite.h"
+#include "winscard.h"
+#include "debuglog.h"
+#include "winscard_msg.h"
+#include "winscard_svc.h"
+#include "sys_generic.h"
+#include "thread_generic.h"
+#include "readerfactory.h"
+#include "hotplug.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+/**
+ * @brief Represents the an Application Context on the Server side.
+ *
+ * An Application Context contains Channels (\c hCard).
+ */
+static struct _psContext
+{
+	SCARDCONTEXT hContext;
+	SCARDHANDLE hCard[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS];
+	DWORD dwClientID;			/* Connection ID used to reference the Client. */
+	PCSCLITE_THREAD_T pthThread;		/* Event polling thread's ID */
+	sharedSegmentMsg msgStruct;		/* Msg sent by the Client */
+	int protocol_major, protocol_minor;	/* Protocol number agreed between client and server*/
+} psContext[PCSCLITE_MAX_APPLICATIONS_CONTEXTS];
+
+LONG MSGCheckHandleAssociation(SCARDHANDLE, DWORD);
+LONG MSGFunctionDemarshall(psharedSegmentMsg, DWORD, uint32_t *replySize);
+LONG MSGAddContext(SCARDCONTEXT, DWORD);
+LONG MSGRemoveContext(SCARDCONTEXT, DWORD);
+LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, DWORD);
+LONG MSGRemoveHandle(SCARDHANDLE, DWORD);
+LONG MSGCleanupClient(DWORD);
+
+static void ContextThread(LPVOID pdwIndex);
+
+LONG ContextsInitialize(void)
+{
+	memset(psContext, 0, sizeof(struct _psContext)*PCSCLITE_MAX_APPLICATIONS_CONTEXTS);
+	return 1;
+}
+
+/**
+ * @brief Creates threads to handle messages received from Clients.
+ *
+ * @param[in] pdwClientID Connection ID used to reference the Client.
+ *
+ * @return Error code.
+ * @retval SCARD_S_SUCCESS Success.
+ * @retval SCARD_F_INTERNAL_ERROR Exceded the maximum number of simultaneous Application Contexts.
+ * @retval SCARD_E_NO_MEMORY Error creating the Context Thread.
+ */
+LONG CreateContextThread(PDWORD pdwClientID)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_APPLICATIONS_CONTEXTS; i++)
+	{
+		if (psContext[i].dwClientID == 0)
+		{
+			psContext[i].dwClientID = *pdwClientID;
+			*pdwClientID = 0;
+			break;
+		}
+	}
+
+	if (i == PCSCLITE_MAX_APPLICATIONS_CONTEXTS)
+	{
+		SYS_CloseFile(psContext[i].dwClientID);
+		psContext[i].dwClientID = 0;
+		Log2(PCSC_LOG_CRITICAL, "No more context available (max: %d)",
+			PCSCLITE_MAX_APPLICATIONS_CONTEXTS);
+		return SCARD_F_INTERNAL_ERROR;
+	}
+
+	if (SYS_ThreadCreate(&psContext[i].pthThread, THREAD_ATTR_DETACHED,
+		(PCSCLITE_THREAD_FUNCTION( )) ContextThread,
+		(LPVOID) i) != 1)
+	{
+		SYS_CloseFile(psContext[i].dwClientID);
+		psContext[i].dwClientID = 0;
+		Log1(PCSC_LOG_CRITICAL, "SYS_ThreadCreate failed");
+		return SCARD_E_NO_MEMORY;
+	}
+
+	return SCARD_S_SUCCESS;
+}
+
+/*
+ * A list of local functions used to keep track of clients and their
+ * connections
+ */
+
+/**
+ * @brief Handles messages received from Clients.
+ *
+ * For each Client message a new instance of this thread is created.
+ *
+ * @param[in] dwIndex Index of an avaiable Application Context slot in
+ * \c psContext.
+ */
+ 
+/*
+	To handle the possible case where the client is one architecture and the server is another
+	(e.g. a PPC app running through Rosetta on OS X talking to a native i386 pcscd), we convert
+	everything going OUT over the pipe to network byte order. Conversely, everything coming IN
+	over the pipe is converted to host byte order.
+*/
+
+static void ContextThread(LPVOID dwIndex)
+{
+	LONG rv;
+	DWORD dwContextIndex = (DWORD)dwIndex;
+
+	Log2(PCSC_LOG_DEBUG, "Thread is started: %d",
+		psContext[dwContextIndex].dwClientID);
+
+	while (1)
+	{
+		sharedSegmentMsg msgStruct = {0,};
+		
+		systemAwakeAndReadyCheck();
+
+		/*
+			Note: SHSharedSegmentMsgToHostOrder(&msgStruct) was called in SHMProcessEventsContext
+			This means that msgStruct contains host-order fields
+		*/
+		switch (rv = SHMProcessEventsContext(&psContext[dwContextIndex].dwClientID, &msgStruct, 0))
+		{
+		case 0:
+			if (msgStruct.mtype == CMD_CLIENT_DIED)
+			{
+				/*
+				 * Clean up the dead client
+				 */
+				Log2(PCSC_LOG_DEBUG, "Client die: %d",
+					psContext[dwContextIndex].dwClientID);
+				MSGCleanupClient(dwContextIndex);
+				SYS_ThreadExit((LPVOID) NULL);
+			}
+			break;
+
+		case 1:
+			if (msgStruct.mtype == CMD_FUNCTION)
+			{
+				/*
+				 * Command must be found
+				 */
+				uint32_t replySize = 0;
+				MSGFunctionDemarshall(&msgStruct, dwContextIndex, &replySize);
+
+				/* the SCARD_TRANSMIT_EXTENDED anwser is already sent by
+				 * MSGFunctionDemarshall */
+				if ((msgStruct.command != SCARD_TRANSMIT_EXTENDED)
+					&& (msgStruct.command != SCARD_CONTROL_EXTENDED))
+				{
+					sharedSegmentMsg tmpMsgStruct;
+					replySize += (sizeof(sharedSegmentMsg) - sizeof(msgStruct.data));
+					memcpy(&tmpMsgStruct, &msgStruct, replySize);
+					SHSharedSegmentMsgToNetworkOrder(&tmpMsgStruct);
+					rv = SHMMessageSend(&tmpMsgStruct, replySize,
+						psContext[dwContextIndex].dwClientID,
+						SHMCommunicationTimeout());
+				}
+			}
+			else
+				/* pcsc-lite client/server protocol version */
+				if (msgStruct.mtype == CMD_VERSION)
+				{
+					version_struct *veStr;
+					veStr = (version_struct *) msgStruct.data;
+					ntohlVersionStruct(veStr);
+					
+					/* get the client protocol version */
+					psContext[dwContextIndex].protocol_major = veStr->major;
+					psContext[dwContextIndex].protocol_minor = veStr->minor;
+
+					Log3(PCSC_LOG_DEBUG,
+						"Client is protocol version %d:%d",
+						veStr->major, veStr->minor);
+
+					veStr->rv = SCARD_S_SUCCESS;
+
+					/* client is newer than server */
+					if ((veStr->major > PROTOCOL_VERSION_MAJOR)
+						|| (veStr->major == PROTOCOL_VERSION_MAJOR
+							&& veStr->minor > PROTOCOL_VERSION_MINOR))
+					{
+						Log3(PCSC_LOG_CRITICAL,
+							"Client protocol is too new %d:%d",
+							veStr->major, veStr->minor);
+						Log3(PCSC_LOG_CRITICAL,
+							"Server protocol is %d:%d",
+							PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR);
+						veStr->rv = SCARD_E_NO_SERVICE;
+					}
+
+					/* set the server protocol version */
+					veStr->major = PROTOCOL_VERSION_MAJOR;
+					veStr->minor = PROTOCOL_VERSION_MINOR;
+					htonlVersionStruct(veStr);
+					
+					/* send back the response */
+					sharedSegmentMsg tmpMsgStruct = msgStruct;
+					SHSharedSegmentMsgToNetworkOrder(&tmpMsgStruct);
+					rv = SHMMessageSend(&tmpMsgStruct, SHMCalculateMessageSize(sizeof(version_struct)),
+						psContext[dwContextIndex].dwClientID,
+					    SHMCommunicationTimeout());
+				}
+				else
+					continue;
+
+			break;
+
+		case 2:
+			/*
+			 * timeout in SHMProcessEventsContext(): do nothing
+			 * this is used to catch the Ctrl-C signal at some time when
+			 * nothing else happens
+			 */
+			break;
+
+		case -1:
+			Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsContext");
+			break;
+
+		default:
+			Log2(PCSC_LOG_ERROR,
+				"SHMProcessEventsContext unknown retval: %d", rv);
+			break;
+		}
+	}
+}
+
+/**
+ * @brief Find out which message was sent by the Client and execute the right task.
+ *
+ * According to the command type sent by the client (\c pcsc_msg_commands),
+ * cast the message data to the correct struct so that is can be demarshalled.
+ * Then call the appropriate function to handle the request.
+ *
+ * Possible structs are: \c establish_struct \c release_struct
+ * \c connect_struct \c reconnect_struct \c disconnect_struct \c begin_struct
+ * \c cancel_struct \c end_struct \c status_struct \c transmit_struct
+ * \c control_struct \c getset_struct.
+ *
+ * @param[in] msgStruct Message to be demarshalled and executed.
+ * @param[in] dwContextIndex
+ */
+LONG MSGFunctionDemarshall(psharedSegmentMsg msgStruct, DWORD dwContextIndex, uint32_t *replySize)
+{
+	LONG rv;
+	establish_struct *esStr;
+	release_struct *reStr;
+	connect_struct *coStr;
+	reconnect_struct *rcStr;
+	disconnect_struct *diStr;
+	begin_struct *beStr;
+	cancel_struct *caStr;
+	end_struct *enStr;
+	status_struct *stStr;
+	transmit_struct *trStr;
+	control_struct *ctStr;
+	getset_struct *gsStr;
+
+	/*
+	 * Zero out everything
+	 */
+	rv = 0;
+	*replySize = 0;
+
+	/*
+		Note that we need to convert structs back out to network byte order
+		after the various calls are made, as this is how results are passed back
+		to the client
+	*/
+	switch (msgStruct->command)
+	{
+
+	case SCARD_ESTABLISH_CONTEXT:
+		esStr = ((establish_struct *) msgStruct->data);
+		ntohlEstablishStruct(esStr);
+		esStr->rv = SCardEstablishContext(esStr->dwScope, 0, 0,
+			&esStr->phContext);
+
+		if (esStr->rv == SCARD_S_SUCCESS)
+			esStr->rv =
+				MSGAddContext(esStr->phContext, dwContextIndex);
+		htonlEstablishStruct(esStr);
+		*replySize = sizeof(establish_struct);
+		break;
+
+	case SCARD_RELEASE_CONTEXT:
+		reStr = ((release_struct *) msgStruct->data);
+		ntohlReleaseStruct(reStr);
+
+		reStr->rv = SCardReleaseContext(reStr->hContext);
+
+		if (reStr->rv == SCARD_S_SUCCESS)
+			reStr->rv =
+				MSGRemoveContext(reStr->hContext, dwContextIndex);
+
+		htonlReleaseStruct(reStr);
+		*replySize = sizeof(release_struct);
+		break;
+
+	case SCARD_CONNECT:
+		coStr = ((connect_struct *) msgStruct->data);
+		ntohlConnectStruct(coStr);
+		Log3(PCSC_LOG_DEBUG, "SCardConnect hContext: 0x%08X, phCard: 0x%08X", coStr->hContext, coStr->phCard);
+		coStr->rv = SCardConnect(coStr->hContext, coStr->szReader,
+			coStr->dwShareMode, coStr->dwPreferredProtocols,
+			&coStr->phCard, &coStr->pdwActiveProtocol);
+		Log3(PCSC_LOG_DEBUG, "SCardConnect result: %d [0x%08X]", coStr->rv, coStr->rv);
+
+		if (coStr->rv == SCARD_S_SUCCESS)
+		{
+			coStr->rv =
+				MSGAddHandle(coStr->hContext, coStr->phCard, dwContextIndex);
+			Log3(PCSC_LOG_DEBUG, "MSGAddHandle result: %d [0x%08X]", coStr->rv, coStr->rv);
+		}
+		htonlConnectStruct(coStr);
+		*replySize = sizeof(connect_struct);
+		break;
+
+	case SCARD_RECONNECT:
+		rcStr = ((reconnect_struct *) msgStruct->data);
+		ntohlReconnectStruct(rcStr);
+		rv = MSGCheckHandleAssociation(rcStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+
+		rcStr->rv = SCardReconnect(rcStr->hCard, rcStr->dwShareMode,
+			rcStr->dwPreferredProtocols,
+			rcStr->dwInitialization, &rcStr->pdwActiveProtocol);
+		htonlReconnectStruct(rcStr);
+		*replySize = sizeof(reconnect_struct);
+		break;
+
+	case SCARD_DISCONNECT:
+		diStr = ((disconnect_struct *) msgStruct->data);
+		ntohlDisconnectStruct(diStr);
+		rv = MSGCheckHandleAssociation(diStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		diStr->rv = SCardDisconnect(diStr->hCard, diStr->dwDisposition);
+
+		if (diStr->rv == SCARD_S_SUCCESS)
+			diStr->rv =
+				MSGRemoveHandle(diStr->hCard, dwContextIndex);
+		htonlDisconnectStruct(diStr);
+		*replySize = sizeof(disconnect_struct);
+		break;
+
+	case SCARD_BEGIN_TRANSACTION:
+		{
+		beStr = ((begin_struct *) msgStruct->data);
+		int ix;
+		unsigned char *px = &msgStruct->data[sizeof(begin_struct)];
+		for (ix = 0; ix < 32; ++ix)
+			*px++ = 0xEE;
+		beStr->rv = -99;	// test
+		ntohlBeginStruct(beStr);
+		rv = MSGCheckHandleAssociation(beStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		beStr->rv = SCardBeginTransaction(beStr->hCard);
+		htonlBeginStruct(beStr);
+		}
+		*replySize = sizeof(begin_struct);
+		break;
+
+	case SCARD_END_TRANSACTION:
+		enStr = ((end_struct *) msgStruct->data);
+		ntohlEndStruct(enStr);
+		rv = MSGCheckHandleAssociation(enStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		enStr->rv =
+			SCardEndTransaction(enStr->hCard, enStr->dwDisposition);
+		htonlEndStruct(enStr);
+		*replySize = sizeof(end_struct);
+		break;
+
+	case SCARD_CANCEL_TRANSACTION:
+		caStr = ((cancel_struct *) msgStruct->data);
+		ntohlCancelStruct(caStr);
+		rv = MSGCheckHandleAssociation(caStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		caStr->rv = SCardCancelTransaction(caStr->hCard);
+		htonlCancelStruct(caStr);
+		*replySize = sizeof(cancel_struct);
+		break;
+
+	case SCARD_STATUS:
+		stStr = ((status_struct *) msgStruct->data);
+		ntohlStatusStruct(stStr);
+		rv = MSGCheckHandleAssociation(stStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		stStr->rv = SCardStatus(stStr->hCard, stStr->mszReaderNames,
+			&stStr->pcchReaderLen, &stStr->pdwState,
+			&stStr->pdwProtocol, stStr->pbAtr, &stStr->pcbAtrLen);
+		htonlStatusStruct(stStr);
+		*replySize = sizeof(status_struct);
+		break;
+
+	case SCARD_TRANSMIT:
+		trStr = ((transmit_struct *) msgStruct->data);
+		ntohlTransmitStruct(trStr);
+		Log2(PCSC_LOG_DEBUG, "SCardTransmit cbSendLength: %d", trStr->cbSendLength);
+		rv = MSGCheckHandleAssociation(trStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		trStr->rv = SCardTransmit(trStr->hCard, &trStr->pioSendPci,
+			trStr->pbSendBuffer, trStr->cbSendLength,
+			&trStr->pioRecvPci, trStr->pbRecvBuffer,
+			&trStr->pcbRecvLength);
+		Log2(PCSC_LOG_DEBUG, "SCardTransmit pcbRecvLength: %d", trStr->pcbRecvLength);
+		htonlTransmitStruct(trStr);
+		*replySize = sizeof(transmit_struct);
+		break;
+
+	case SCARD_CONTROL:
+		ctStr = ((control_struct *) msgStruct->data);
+		ntohlControlStruct(ctStr);
+		rv = MSGCheckHandleAssociation(ctStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		ctStr->rv = SCardControl(ctStr->hCard, ctStr->dwControlCode,
+			ctStr->pbSendBuffer, ctStr->cbSendLength,
+			ctStr->pbRecvBuffer, ctStr->cbRecvLength,
+			&ctStr->dwBytesReturned);
+		htonlControlStruct(ctStr);
+		*replySize = sizeof(control_struct);
+		break;
+
+	case SCARD_GET_ATTRIB:
+		gsStr = ((getset_struct *) msgStruct->data);
+		ntohlGetSetStruct(gsStr);
+		rv = MSGCheckHandleAssociation(gsStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		gsStr->rv = SCardGetAttrib(gsStr->hCard, gsStr->dwAttrId,
+			gsStr->pbAttr, &gsStr->cbAttrLen);
+		htonlGetSetStruct(gsStr);
+		*replySize = sizeof(getset_struct);
+		break;
+
+	case SCARD_SET_ATTRIB:
+		gsStr = ((getset_struct *) msgStruct->data);
+		ntohlGetSetStruct(gsStr);
+		rv = MSGCheckHandleAssociation(gsStr->hCard, dwContextIndex);
+		if (rv != 0) return rv;
+		gsStr->rv = SCardSetAttrib(gsStr->hCard, gsStr->dwAttrId,
+			gsStr->pbAttr, gsStr->cbAttrLen);
+		htonlGetSetStruct(gsStr);
+		*replySize = sizeof(getset_struct);
+		break;
+
+	case SCARD_TRANSMIT_EXTENDED:
+		{
+			transmit_struct_extended *treStr;
+			unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
+			unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
+
+			treStr = ((transmit_struct_extended *) msgStruct->data);
+			ntohlTransmitStructExtended(treStr);
+			Log2(PCSC_LOG_DEBUG, "SCardTransmitExt cbSendLength: %d", treStr->cbSendLength);
+			rv = MSGCheckHandleAssociation(treStr->hCard, dwContextIndex);
+			if (rv != 0) return rv;
+
+			/* one more block to read? */
+			if (treStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
+			{
+				/* copy the first APDU part */
+				memcpy(pbSendBuffer, treStr->data,
+					PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*treStr));
+
+				/* receive the second block */
+				rv = SHMMessageReceive(
+					pbSendBuffer+PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*treStr),
+					treStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
+					psContext[dwContextIndex].dwClientID,
+					SHMCommunicationTimeout());
+				if (rv)
+					Log1(PCSC_LOG_CRITICAL, "reception failed");
+			}
+			else
+				memcpy(pbSendBuffer, treStr->data, treStr->cbSendLength);
+
+			treStr->rv = SCardTransmit(treStr->hCard, &treStr->pioSendPci,
+				pbSendBuffer, treStr->cbSendLength,
+				&treStr->pioRecvPci, pbRecvBuffer,
+				&treStr->pcbRecvLength);
+
+			treStr->size = sizeof(*treStr) + treStr->pcbRecvLength;
+			Log3(PCSC_LOG_DEBUG, "SCardTransmitExt pcbRecvLength: %d, size: %d", 
+				treStr->pcbRecvLength, treStr->size);
+			Log3(PCSC_LOG_DEBUG, "SCardTransmitExt SCardTransmit result: %d [0x%08X]", 
+				treStr->rv, treStr->rv);
+			if (treStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
+			{
+				/* two blocks */
+				memcpy(treStr->data, pbRecvBuffer, PCSCLITE_MAX_MESSAGE_SIZE
+					- sizeof(*treStr));
+
+			//	sharedSegmentMsg tmpMsgStruct = *msgStruct;
+			//  we don't copy because of the size, and because it is not used after here
+			//	SHSharedSegmentMsgToNetworkOrder(&tmpMsgStruct);
+				SHSharedSegmentMsgToNetworkOrder(msgStruct);
+				htonlTransmitStructExtended(treStr);
+				rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
+					psContext[dwContextIndex].dwClientID,
+					SHMCommunicationTimeout());
+				if (rv)
+					Log1(PCSC_LOG_CRITICAL, "transmission failed");
+
+				rv = SHMMessageSend(pbRecvBuffer + PCSCLITE_MAX_MESSAGE_SIZE
+					- sizeof(*treStr),
+					treStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
+					psContext[dwContextIndex].dwClientID,
+					SHMCommunicationTimeout());
+				if (rv)
+					Log1(PCSC_LOG_CRITICAL, "transmission failed");
+			}
+			else
+			{
+				/* one block only */
+				size_t dataSize = treStr->pcbRecvLength;
+				memcpy(treStr->data, pbRecvBuffer, dataSize);
+				
+				// the 4 is to drop the "BYTE data[1]", which rounds to 4 bytes
+				size_t replySize = dataSize + sizeof(transmit_struct_extended) - 4;	
+				Log3(PCSC_LOG_DEBUG, "SCardTransmitExt/SHMMessageSend one block: data: %d, total: %d", 
+					dataSize, replySize);
+				htonlTransmitStructExtended(treStr);
+				rv = WrapSHMWrite(SCARD_TRANSMIT_EXTENDED, psContext[dwContextIndex].dwClientID,
+					replySize, SHMCommunicationTimeout(), treStr);
+	
+#if 0
+				// the 4 is to drop the "BYTE data[1]", which rounds to 4 bytes
+				size_t replySize = sizeof(sharedSegmentMsg) - sizeof(msgStruct->data) +	// header portion of msgStruct
+					dataSize + sizeof(transmit_struct_extended) - 4;	
+
+				Log3(PCSC_LOG_DEBUG, "SCardTransmitExt/SHMMessageSend one block: data: %d, total: %d", 
+					dataSize, replySize);
+				//  we don't copy because of the potential size
+				SHSharedSegmentMsgToNetworkOrder(msgStruct);
+				htonlTransmitStructExtended(treStr);
+				rv = SHMMessageSend(msgStruct, replySize,
+					psContext[dwContextIndex].dwClientID,
+					SHMCommunicationTimeout());
+#endif
+				if (rv)
+					Log1(PCSC_LOG_CRITICAL, "transmission failed");
+				// We flip back the header, since the SHMProcessEventsContext loop 
+				// tests msgStruct.command after MSGFunctionDemarshall is called
+#if 0
+				SHSharedSegmentMsgToHostOrder(msgStruct);
+#endif
+			}
+		}
+		break;
+
+	case SCARD_CONTROL_EXTENDED:
+		{
+			control_struct_extended *cteStr;
+			unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
+			unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
+
+			cteStr = ((control_struct_extended *) msgStruct->data);
+			ntohlControlStructExtended(cteStr);
+			Log2(PCSC_LOG_DEBUG, "SCardControlExt cbSendLength: %d", cteStr->cbSendLength);
+			rv = MSGCheckHandleAssociation(cteStr->hCard, dwContextIndex);
+			if (rv != 0) return rv;
+
+			/* one more block to read? */
+			if (cteStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
+			{
+				/* copy the first data part */
+				memcpy(pbSendBuffer, cteStr->data,
+					PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*cteStr));
+
+				/* receive the second block */
+				rv = SHMMessageReceive(
+					pbSendBuffer+PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*cteStr),
+					cteStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
+					psContext[dwContextIndex].dwClientID,
+					SHMCommunicationTimeout());
+				if (rv)
+					Log1(PCSC_LOG_CRITICAL, "reception failed");
+			}
+			else
+				memcpy(pbSendBuffer, cteStr->data, cteStr->cbSendLength);
+
+			cteStr->rv = SCardControl(cteStr->hCard, cteStr->dwControlCode,
+				pbSendBuffer, cteStr->cbSendLength,
+				pbRecvBuffer, cteStr->cbRecvLength,
+				&cteStr->pdwBytesReturned);
+
+			cteStr->size = sizeof(*cteStr) + cteStr->pdwBytesReturned;
+			Log3(PCSC_LOG_DEBUG, "SCardControlExt pdwBytesReturned: %d, size: %d", 
+				cteStr->pdwBytesReturned, cteStr->size);
+			if (cteStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
+			{
+				/* two blocks */
+				memcpy(cteStr->data, pbRecvBuffer, PCSCLITE_MAX_MESSAGE_SIZE
+					- sizeof(*cteStr));
+
+				sharedSegmentMsg tmpMsgStruct = *msgStruct;
+				SHSharedSegmentMsgToNetworkOrder(&tmpMsgStruct);
+				htonlControlStructExtended(cteStr);
+				rv = SHMMessageSend(&tmpMsgStruct, sizeof(tmpMsgStruct),
+					psContext[dwContextIndex].dwClientID,
+					SHMCommunicationTimeout());
+				if (rv)
+					Log1(PCSC_LOG_CRITICAL, "transmission failed");
+
+				rv = SHMMessageSend(pbRecvBuffer + PCSCLITE_MAX_MESSAGE_SIZE
+					- sizeof(*cteStr),
+					cteStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
+					psContext[dwContextIndex].dwClientID,
+					SHMCommunicationTimeout());
+				if (rv)
+					Log1(PCSC_LOG_CRITICAL, "transmission failed");
+			}
+			else
+			{
+				/* one block only */
+				size_t dataSize = cteStr->pdwBytesReturned;
+				memcpy(cteStr->data, pbRecvBuffer, dataSize);
+				dataSize = dataSize + sizeof(*cteStr) - sizeof(cteStr->data);
+
+				sharedSegmentMsg tmpMsgStruct = *msgStruct;
+				dataSize = SHMCalculateMessageSize(dataSize);
+				tmpMsgStruct.msgSize = dataSize;
+				SHSharedSegmentMsgToNetworkOrder(&tmpMsgStruct);
+				cteStr = ((control_struct_extended *) tmpMsgStruct.data);
+				htonlControlStructExtended(cteStr);
+				rv = SHMMessageSend(&tmpMsgStruct, dataSize,
+					psContext[dwContextIndex].dwClientID,
+					SHMCommunicationTimeout());
+				if (rv)
+					Log1(PCSC_LOG_CRITICAL, "transmission failed");
+			}
+		}
+		break;
+
+	default:
+		Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", msgStruct->command);
+		return -1;
+	}
+
+	return 0;
+}
+
+LONG MSGAddContext(SCARDCONTEXT hContext, DWORD dwContextIndex)
+{
+	psContext[dwContextIndex].hContext = hContext;
+	return SCARD_S_SUCCESS;
+}
+
+LONG MSGRemoveContext(SCARDCONTEXT hContext, DWORD dwContextIndex)
+{
+	int i;
+	LONG rv;
+
+	if (psContext[dwContextIndex].hContext == hContext)
+	{
+		for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
+		{
+			/*
+			 * Disconnect each of these just in case
+			 */
+
+			if (psContext[dwContextIndex].hCard[i] != 0)
+			{
+				PREADER_CONTEXT rContext = NULL;
+				DWORD dwLockId;
+
+				/*
+				 * Unlock the sharing
+				 */
+				rv = RFReaderInfoById(psContext[dwContextIndex].hCard[i],
+					&rContext);
+				if (rv != SCARD_S_SUCCESS)
+					return rv;
+
+				dwLockId = rContext->dwLockId;
+				rContext->dwLockId = 0;
+
+				if (psContext[dwContextIndex].hCard[i] != dwLockId) 
+				{
+					/*
+					 * if the card is locked by someone else we do not reset it
+					 * and simulate a card removal
+					 */
+					rv = SCARD_W_REMOVED_CARD;
+				}
+				else
+				{
+					/*
+					 * We will use SCardStatus to see if the card has been
+					 * reset there is no need to reset each time
+					 * Disconnect is called
+					 */
+					rv = SCardStatus(psContext[dwContextIndex].hCard[i], NULL,
+						NULL, NULL, NULL, NULL, NULL);
+				}
+
+				if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
+					SCardDisconnect(psContext[dwContextIndex].hCard[i],
+						SCARD_LEAVE_CARD);
+				else
+					SCardDisconnect(psContext[dwContextIndex].hCard[i],
+						SCARD_RESET_CARD);
+
+				psContext[dwContextIndex].hCard[i] = 0;
+			}
+		}
+
+		psContext[dwContextIndex].hContext = 0;
+		return SCARD_S_SUCCESS;
+	}
+
+	return SCARD_E_INVALID_VALUE;
+}
+
+LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard, DWORD dwContextIndex)
+{
+	int i;
+
+	if (psContext[dwContextIndex].hContext == hContext)
+	{
+
+		/*
+		 * Find an empty spot to put the hCard value
+		 */
+		for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
+		{
+			if (psContext[dwContextIndex].hCard[i] == 0)
+			{
+				psContext[dwContextIndex].hCard[i] = hCard;
+				break;
+			}
+		}
+
+		if (i == PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS)
+		{
+			return SCARD_F_INTERNAL_ERROR;
+		} else
+		{
+			return SCARD_S_SUCCESS;
+		}
+
+	}
+
+	return SCARD_E_INVALID_VALUE;
+}
+
+LONG MSGRemoveHandle(SCARDHANDLE hCard, DWORD dwContextIndex)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
+	{
+		if (psContext[dwContextIndex].hCard[i] == hCard)
+		{
+			psContext[dwContextIndex].hCard[i] = 0;
+			return SCARD_S_SUCCESS;
+		}
+	}
+
+	return SCARD_E_INVALID_VALUE;
+}
+
+
+LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, DWORD dwContextIndex)
+{
+	int i;
+
+	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
+	{
+		if (psContext[dwContextIndex].hCard[i] == hCard)
+		{
+			return 0;
+		}
+	}
+
+	/* Must be a rogue client, debug log and sleep a couple of seconds */
+	Log2(PCSC_LOG_ERROR, "Client failed to authenticate (hCard: 0x%08X)", hCard);
+	SYS_Sleep(2);
+
+	return SCARD_E_INVALID_HANDLE;
+}
+
+LONG MSGCleanupClient(DWORD dwContextIndex)
+{
+	if (psContext[dwContextIndex].hContext != 0)
+	{
+		SCardReleaseContext(psContext[dwContextIndex].hContext);
+		MSGRemoveContext(psContext[dwContextIndex].hContext, dwContextIndex);
+	}
+
+	psContext[dwContextIndex].dwClientID = 0;
+	psContext[dwContextIndex].protocol_major = 0;
+	psContext[dwContextIndex].protocol_minor = 0;
+
+	return 0;
+}
+
+

Added: trunk/SmartCardServices/src/PCSC/winscard_svc.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/winscard_svc.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/winscard_svc.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
+ * 
+ *  @APPLE_LICENSE_HEADER_START@
+ *  
+ *  This file contains Original Code and/or Modifications of Original Code
+ *  as defined in and that are subject to the Apple Public Source License
+ *  Version 2.0 (the 'License'). You may not use this file except in
+ *  compliance with the License. Please obtain a copy of the License at
+ *  http://www.opensource.apple.com/apsl/ and read it before using this
+ *  file.
+ *  
+ *  The Original Code and all software distributed under the License are
+ *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ *  Please see the License for the specific language governing rights and
+ *  limitations under the License.
+ *  
+ *  @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ *  winscard_svc.h
+ *  SmartCardServices
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2001-2004
+ *  David Corcoran <corcoran at linuxnet.com>
+ *  Damien Sauveron <damien.sauveron at labri.fr>
+ *
+ * $Id: winscard_svc.h 1421 2005-04-12 12:09:21Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This demarshalls functions over the message queue and
+ * keeps track of clients and their handles.
+ */
+
+#ifndef __winscard_svc_h__
+#define __winscard_svc_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+	LONG ContextsInitialize(void);
+	LONG CreateContextThread(PDWORD);
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PCSC/wintypes.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/wintypes.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/wintypes.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 1999
+ *  David Corcoran <corcoran at linuxnet.com>
+ *
+ * $Id: wintypes.h 2071 2006-06-06 09:20:19Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This keeps a list of Windows(R) types.
+ */
+
+#ifndef __wintypes_h__
+#define __wintypes_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if !defined(WIN32)
+
+#include <stdint.h>
+
+#ifndef BYTE
+	typedef uint8_t BYTE;
+#endif
+	typedef uint8_t UCHAR;
+	typedef uint8_t *PUCHAR;
+	typedef uint16_t USHORT;
+
+#ifndef __COREFOUNDATION_CFPLUGINCOM__
+	typedef uint32_t ULONG;
+	typedef void *LPVOID;
+	typedef int16_t BOOL;
+#endif
+
+	typedef uint32_t *PULONG;
+	typedef const void *LPCVOID;
+	typedef uint32_t DWORD;
+	typedef uint32_t *PDWORD;
+	typedef uint16_t WORD;
+	typedef int32_t LONG;
+	typedef int32_t RESPONSECODE;
+	typedef const char *LPCSTR;
+	typedef const BYTE *LPCBYTE;
+	typedef BYTE *LPBYTE;
+	typedef DWORD *LPDWORD;
+	typedef char *LPSTR;
+
+	/* these types are deprecated but still used by old drivers and applications
+	 * You should use LPSTR instead */
+	typedef char *LPTSTR
+#ifdef __GNUC__
+		/* __attribute__ is a GCC only extension */
+		__attribute__ ((deprecated))
+#endif
+		;
+	typedef const char *LPCTSTR
+#ifdef __GNUC__
+		/* __attribute__ is a GCC only extension */
+		__attribute__ ((deprecated))
+#endif
+		;
+	typedef char *LPCWSTR
+#ifdef __GNUC__
+		/* __attribute__ is a GCC only extension */
+		__attribute__ ((deprecated))
+#endif
+		;
+
+#else
+#include <windows.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PCSC/xiodevices.cpp
===================================================================
--- trunk/SmartCardServices/src/PCSC/xiodevices.cpp	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/xiodevices.cpp	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// xiodevices - additional code for finding and tracking devices via IOKit
+// >>> move this iodevices.cpp when final
+//
+#include "xiodevices.h"
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/mach++.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/usb/IOUSBLib.h>
+
+using namespace MachPlusPlus;
+
+namespace Security {
+namespace IOKit {
+
+void XNotificationPort::add(DeviceMatch match, XReceiver &receiver, const char *type)
+{
+	// The kIOProviderClassKey key is required in a matching dictionary. We extract it
+	// here only for debugging purposes
+
+	CFTypeRef valueRef = NULL;
+	const char *pclass = "";
+	CFRef<CFMutableDictionaryRef> theDict = match.dict();
+	if (theDict && CFDictionaryGetValueIfPresent(theDict, CFSTR(kIOProviderClassKey), &valueRef) && 
+		CFGetTypeID(valueRef) == CFStringGetTypeID())
+		pclass = cfString(static_cast<CFStringRef>(valueRef)).c_str();
+		
+	// type is usually IOServiceMatched
+	mach_port_t pp = NotificationPort::port();
+	secdebug("iokit", "XNotificationPort::add - type: %s [port: %p (0x%08X), class: %s]",
+		type, mPortRef, pp, pclass);	
+		
+//	CFShow(match.dict());
+	// p (void)CFShow(match.dict())
+	io_iterator_t iterator;
+ 	Error::check(::IOServiceAddMatchingNotification(mPortRef, type,
+		match, ioNotify, &receiver, &iterator));
+	CFRetain(match);	// compensate for IOSAMN not retaining its argument
+
+	// run initial iterator to process existing devices
+	secdebug("iokit", "dispatching INITIAL device match iterator %p", reinterpret_cast<void *>(iterator));
+	DeviceIterator it(iterator);
+	receiver.ioChange(it);
+}
+
+void XNotificationPort::addInterestNotification(XReceiver &receiver, io_service_t service, 
+	const io_name_t interestType)
+{
+	io_iterator_t iterator;
+	mach_port_t pp = NotificationPort::port();
+//	MachPlusPlus::Port(pp).dump(0);
+	secdebug("iokit", "XNotificationPort::addInterest - type: %s [port: %p (0x%08X), service: 0x%08X]",
+		interestType, mPortRef, pp, service);	// IOServiceMatched
+#if 1
+	CFRunLoopSourceRef notificationRunLoopSource = IONotificationPortGetRunLoopSource(mPortRef);
+	CFRunLoopSourceRef classRunLoopSource = NotificationPort::source();
+//    IONotificationPortRef r_notify_port = IONotificationPortCreate(0);
+	kern_return_t kr = ::IOServiceAddInterestNotification(mPortRef,	//,r_notify_port
+		service, interestType, ioDeviceNotification, &receiver, &iterator);
+	const char *msgstr = mach_error_string(kr);
+	const char *msgtyp = mach_error_type(kr);
+	if (msgstr && msgtyp)
+		secdebug("iokit", " msg: %s, typ: %s", msgstr, msgtyp);
+//	Error::check(kr);
+//    if(r_notify_port) IOObjectRelease((io_object_t)r_notify_port);
+#else
+	Error::check(::IOServiceAddInterestNotification(mPortRef,
+		service, interestType, ioDeviceNotification, &receiver, &iterator));
+#endif
+}
+
+// callbacks
+
+void XNotificationPort::ioNotify(void *refCon, io_iterator_t iterator)
+{
+	secdebug("iokit", "dispatching NEW device match iterator %p", reinterpret_cast<void *>(iterator));
+	DeviceIterator it(iterator);
+	reinterpret_cast<XReceiver *>(refCon)->ioChange(it);
+}
+
+void XNotificationPort::ioDeviceNotification(void *refCon, io_service_t service,
+	natural_t messageType, void *messageArgument)
+{
+	secdebug("iokit", "dispatching NEW device notification iterator, service 0x%08X, msg: 0x%04X, arg: %p", 
+		service, messageType, messageArgument);
+
+	const char *msgstr = mach_error_string(messageType);
+	const char *msgtyp = mach_error_type(messageType);
+	if (msgstr && msgtyp)
+		secdebug("iokit", " msg: %s, typ: %s", msgstr, msgtyp);
+	
+#if 0
+	secdebug("iokit", "kIOMessageServiceIsTerminated: 0x%04X", kIOMessageServiceIsTerminated);
+	secdebug("iokit", "kIOMessageServiceIsSuspended: 0x%04X", kIOMessageServiceIsSuspended);
+	secdebug("iokit", "kIOMessageServiceIsResumed: 0x%04X", kIOMessageServiceIsResumed);
+	secdebug("iokit", "kIOMessageServiceIsRequestingClose: 0x%04X", kIOMessageServiceIsRequestingClose);
+	secdebug("iokit", "kIOMessageServiceIsAttemptingOpen: 0x%04X", kIOMessageServiceIsAttemptingOpen);
+	secdebug("iokit", "kIOMessageServiceWasClosed: 0x%04X", kIOMessageServiceWasClosed);
+	secdebug("iokit", "kIOMessageServiceBusyStateChange: 0x%04X", kIOMessageServiceBusyStateChange);
+	secdebug("iokit", "kIOMessageServicePropertyChange: 0x%04X", kIOMessageServicePropertyChange);
+	secdebug("iokit", "kIOMessageCanDevicePowerOff: 0x%04X", kIOMessageCanDevicePowerOff);
+	secdebug("iokit", "kIOMessageDeviceWillPowerOff: 0x%04X", kIOMessageDeviceWillPowerOff);
+	secdebug("iokit", "kIOMessageDeviceWillNotPowerOff: 0x%04X", kIOMessageDeviceWillNotPowerOff);
+	secdebug("iokit", "kIOMessageDeviceHasPoweredOn: 0x%04X", kIOMessageDeviceHasPoweredOn);
+	secdebug("iokit", "kIOMessageCanSystemPowerOff: 0x%04X", kIOMessageCanSystemPowerOff);
+	secdebug("iokit", "iokit_vendor_specific_msg(0x000A): 0x%04X", iokit_vendor_specific_msg(0x000A));
+#endif	
+
+//	assert(service!=io_service_t(-1));
+	if (service!=io_service_t(-1))
+		reinterpret_cast<XReceiver *>(refCon)->ioServiceChange(refCon, service, messageType, messageArgument);
+}
+
+
+} // end namespace IOKit
+} // end namespace Security
+
+

Added: trunk/SmartCardServices/src/PCSC/xiodevices.h
===================================================================
--- trunk/SmartCardServices/src/PCSC/xiodevices.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PCSC/xiodevices.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// xiodevices - code for finding and tracking devices via IOKit
+//
+#ifndef _H_XIODEVICES
+#define _H_XIODEVICES
+
+#include <security_utilities/iodevices.h>
+
+#if defined(__cplusplus)
+
+namespace Security {
+namespace IOKit {
+
+//
+// An IOKit notification port object
+//
+class XNotificationPort : public MachPortNotificationPort
+{
+public:
+	XNotificationPort() : MachPortNotificationPort() {}
+	~XNotificationPort() {}
+	
+	class XReceiver : public Receiver
+	{
+	public:
+		virtual void ioChange(DeviceIterator &iterator) = 0;
+		virtual void ioServiceChange(void *refCon, io_service_t service,	//IOServiceInterestCallback
+			natural_t messageType, void *messageArgument) = 0;
+	};
+	
+	void add(DeviceMatch match, XReceiver &receiver, const char *type = kIOFirstMatchNotification);
+	void addInterestNotification(XReceiver &receiver, io_service_t service,
+		const io_name_t interestType = kIOGeneralInterest);
+
+private:
+
+	static void ioDeviceNotification(void *refCon, io_service_t service,
+		natural_t messageType, void *messageArgument);
+	static void ioNotify(void *refCon, io_iterator_t iterator);
+};
+
+} // end namespace MachPlusPlus
+} // end namespace Security
+
+#endif /* __cplusplus__ */
+
+#endif //_H_XIODEVICES

Added: trunk/SmartCardServices/src/PKCS11/cryptoki.h
===================================================================
--- trunk/SmartCardServices/src/PKCS11/cryptoki.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/cryptoki.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,394 @@
+/******************************************************************************
+** 
+**  $Id: cryptoki.h,v 1.2 2003/02/13 20:06:37 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Main cryptoki header (include in all source files)
+** 
+******************************************************************************/
+
+#ifndef __CRYPTOKI_H__
+#define __CRYPTOKI_H__
+
+/******************************************************************************
+** Include all "standard" RSA PKCS #11 headers
+******************************************************************************/
+#ifndef WIN32
+#include "cryptoki_unix.h"
+#else
+#include "cryptoki_win32.h"
+#endif
+
+
+/******************************************************************************
+** Regular headers
+******************************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <pthread.h>
+
+#ifndef __APPLE__
+#include <musclecard.h>
+#else
+#include <PCSC/wintypes.h>
+#include <PCSC/musclecard.h>
+#endif
+
+#include <sys/types.h>
+
+
+/******************************************************************************
+** Logging (OSX needs -no-cpp-precomp for VA_ARGS to work)
+******************************************************************************/
+#ifndef NO_LOG
+#define P11_LOG_START(x)        log_Start(x)
+#define P11_LOG_END(x)          log_End(x,rv)
+#define P11_ERR(x)              log_Err(x,__FILE__,__LINE__)
+/* #define P11_LOG(x,...)          log_Log(x,##__VA_ARGS__) */
+#else
+#define P11_LOG_START(x)
+#define P11_LOG_END(x)
+#define P11_ERR(x)
+/* #define P11_LOG(x,...) */
+#endif
+
+#define LOG_LOW     0
+#define LOG_MED     5
+#define LOG_HIGH    9
+
+
+/******************************************************************************
+** Error checking macros
+******************************************************************************/
+#define PCSC_ERROR_NOLOG(x)    ((x) != SCARD_S_SUCCESS)
+#define CKR_ERROR_NOLOG(x)     ((x) != CKR_OK)
+#define MSC_ERROR_NOLOG(x)     ((x) != MSC_SUCCESS)
+
+#ifndef NO_LOG
+#define PCSC_ERROR(x)       ((error_LogCmd((x),SCARD_S_SUCCESS,(CK_CHAR*)__FILE__,__LINE__,pcsc_stringify_error)) != SCARD_S_SUCCESS)
+#define CKR_ERROR(x)        ((error_LogCmd((x),CKR_OK,(CK_CHAR*)__FILE__,__LINE__,error_Stringify)) != CKR_OK)
+#define MSC_ERROR(x)        ((error_LogCmd((x),MSC_SUCCESS,(CK_CHAR*)__FILE__,__LINE__,msc_error)) != MSC_SUCCESS)
+#else
+#define PCSC_ERROR(x)       PCSC_ERROR_NOLOG(x)
+#define CKR_ERROR(x)        CKR_ERROR_NOLOG(x)
+#define MSC_ERROR(x)        MSC_ERROR_NOLOG(x)
+#endif
+
+#define INVALID_SLOT        ((!st.slots) || (!slotID) || (slotID > st.slot_count))
+#define INVALID_SESSION     (!(hSession && (((P11_Session *)hSession)->check == (P11_Session *)hSession)))
+#define INVALID_OBJECT      (!(hObject && (((P11_Object *)hObject)->check == (P11_Object *)hObject)))
+#define READ_ONLY_SESSION   0 /* Fixme: implement this */
+#define USER_MODE           (hSession && ((((P11_Session *)hSession)->session.state == CKS_RO_USER_FUNCTIONS) || (((P11_Session *)hSession)->session.state == CKS_RW_USER_FUNCTIONS)))
+
+
+/******************************************************************************
+** Utility macros
+******************************************************************************/
+#ifndef max
+#define max(a,b)            (((a)>(b))?(a):(b))
+#endif
+#ifndef min
+#define min(a,b)            (((a)<(b))?(a):(b))
+#endif
+
+#ifdef SUPERDEBUG
+#define malloc(a)           debug_Malloc((a), __LINE__, __FILE__)
+#define calloc(a,b)         debug_Calloc((a)*(b), __LINE__, __FILE__)
+#define free(a)             debug_Free((a), __LINE__, __FILE__)
+#endif
+
+#define P11_MAX_ULONG ((CK_ULONG)(~0))
+
+/* Preference settings */
+#define P11_SLOT_WATCH_THREAD_FULL          0
+#define P11_SLOT_WATCH_THREAD_PARTIAL       1
+#define P11_OBJ_SORT_NEWEST_FIRST           0
+#define P11_OBJ_SORT_NEWEST_LAST            1
+#define P11_DEFAULT_ATTRIB_OBJ_SIZE       512
+#define P11_DEFAULT_PRK_ATTRIB_OBJ_SIZE   912
+#define P11_DEFAULT_CERT_ATTRIB_OBJ_SIZE  712
+#define P11_DEFAULT_LOG_FILENAME          "PKCS11.log"
+
+
+/******************************************************************************
+** Library information
+******************************************************************************/
+#define PKCS11_MAJOR            0x02
+#define PKCS11_MINOR            0x0b
+#define PKCS11_LIB_MAJOR        0x01
+#define PKCS11_LIB_MINOR        0x00
+#define PKCS11_MFR_ID           "SCHLUMBERGER"
+#define PKCS11_DESC             "SLB PKCS #11 module"
+#define PKCS11_MAX_PIN_TRIES    8
+#define PKCS11_SO_USER_PIN      0
+#define PKCS11_USER_PIN         1
+
+
+/******************************************************************************
+** P11 typedefs
+******************************************************************************/
+
+typedef void* P11_Mutex;
+
+/* PKCS #11 mechanism info list */
+typedef struct _P11_MechInfo
+{
+    CK_MECHANISM_TYPE type;         /* Mechanism type   */
+    CK_MECHANISM_INFO info;         /* Mechanism info   */
+
+    struct _P11_MechInfo *prev;
+    struct _P11_MechInfo *next;
+} P11_MechInfo;
+
+/* PKCS #11 object attribute */
+typedef struct _P11_Attrib
+{
+    CK_ATTRIBUTE attrib;            /* Object attribute data        */
+    CK_BBOOL token;                 /* Store attribute on token?    */
+
+    struct _P11_Attrib *prev;
+    struct _P11_Attrib *next;
+} P11_Attrib;
+
+/* A PKCS #11 object (session or on-card) */
+typedef struct _P11_Object
+{
+    CK_SESSION_HANDLE session;      /* Session that owns this object. Not used with token objects   */
+    P11_Attrib *attrib;             /* List of attributes                                           */
+    MSCObjectInfo *msc_obj;         /* On-token object info.  Not used with session objects         */
+    MSCKeyInfo *msc_key;            /* On-token key info.  Not used with session objects            */
+    CK_ULONG sensitive;             /* True/false if this object is PIN protected                   */
+
+    struct _P11_Object *prev;
+    struct _P11_Object *next;
+    struct _P11_Object *check;      /* Should contain the memory address of this structure  */
+} P11_Object;
+
+/* Cached PIN */
+typedef struct _P11_Pin
+{
+    CK_BYTE pin[256];               /* Fixme: don't hardcode, use MAX_Musclecard_PIN)   */
+    CK_ULONG pin_size;
+} P11_Pin;
+
+/* A card reader.  */
+typedef struct
+{
+    CK_ULONG pin_state;             /* NONE (0), USER (1), SO (2)        */
+    CK_SLOT_INFO slot_info;         /* CK slot structure                 */
+    CK_TOKEN_INFO token_info;       /* CK token structure                */
+    P11_Object *objects;            /* List of objects                   */
+    P11_MechInfo *mechanisms;       /* List of mechanisms                */
+    P11_Pin pins[2];                /* Array of cached PIN's             */
+    MSCStatusInfo status_info;      /* Status of token                   */
+    MSCTokenConnection conn;        /* Connection to token               */
+} P11_Slot;
+
+/* A session with one slot.  */
+typedef struct _P11_Session
+{
+    CK_SESSION_INFO session;        /* CK session info                   */
+    CK_VOID_PTR application;        /* Passed to notify callback         */
+    CK_NOTIFY notify;               /* Notify callback                   */
+
+    P11_Object *search_object;      /* Current object (used with C_FindObjects) */
+    CK_ATTRIBUTE *search_attrib;    /* Current search attributes                */
+    CK_ULONG search_attrib_count;   /* Current search attribute count           */
+
+    CK_MECHANISM sign_mech;         /* Active signing mechanism */
+    CK_OBJECT_HANDLE sign_key;      /* Active signing key       */
+
+    struct _P11_Session *prev;
+    struct _P11_Session *next;
+    struct _P11_Session *check;     /* Should contain the memory address of this structure  */
+} P11_Session;
+
+/* Preferences. */
+typedef struct _P11_Preferences
+{
+    CK_ULONG multi_app;
+    CK_ULONG threaded;
+    CK_ULONG log_level;
+    CK_ULONG obj_sort_order;
+    CK_ULONG slot_watch_scheme;
+    CK_ULONG cache_pin;
+    CK_ULONG version_major;
+    CK_ULONG version_minor;
+    CK_ULONG max_pin_tries;
+    CK_ULONG so_user_pin_num;
+    CK_ULONG user_pin_num;
+    CK_ULONG cert_attrib_size;
+    CK_ULONG pubkey_attrib_size;
+    CK_ULONG prvkey_attrib_size;
+    CK_ULONG data_attrib_size;
+    CK_ULONG disable_security;
+    CK_CHAR log_filename[256];
+} P11_Preferences;
+
+/* Master PKCS #11 module state information */
+typedef struct
+{
+    CK_ULONG initialized;           /* Has Cryptoki been intialized                              */
+    P11_Preferences prefs;          /* Preferences                                               */
+    P11_Slot *slots;                /* Array of all slots                                        */
+    CK_ULONG slot_count;            /* Number of slots in array                                  */
+    P11_Session *sessions;          /* List of all sessions with all slots                       */
+    char *slot_status;              /* Says if the token state changed for a slot                */
+    P11_Mutex log_lock;             /* Log mutex                                                 */
+    P11_Mutex async_lock;           /* Asychronous mutex                                         */
+    CK_ULONG native_locks;
+    CK_ULONG create_threads;
+} P11_State;
+
+/* Global state variable : see p11x_state.c */
+extern P11_State st;
+
+/******************************************************************************
+** Prototypes (extensions in addition to the standard PKCS #11 functions)
+******************************************************************************/
+
+/* p11x_async.c */
+CK_RV async_StartSlotWatcher();
+CK_RV async_StopSlotWatcher();
+ void *async_WatchSlots(void *parent_pid);
+ void async_SignalHandler(int sig);
+MSCULong32 async_TokenEventCallback(MSCTokenInfo *tokenInfo, MSCULong32 len, void *data);
+
+/* p11x_debug.c */
+void debug_Init();
+void debug_CheckCorrupt(size_t i);
+void debug_Check();
+void *debug_Malloc(size_t size, int line, char *file);
+void debug_Free(void *ptr, int line, char *file);
+void *debug_Calloc(size_t size, int line, char *file);
+
+/* p11x_error.c */
+CK_RV error_LogCmd(CK_RV err, CK_RV cond, CK_CHAR *file, CK_LONG line, char *(*stringifyFn)(CK_RV));
+ char *error_Stringify(CK_RV rv);
+
+/* p11x_log.c */
+void log_Start(char *func);
+void log_End(char *func, CK_RV rv);
+void log_Err(char *msg, char *file, CK_LONG line);
+void log_Log(CK_ULONG level, char *format, ...);
+
+/* p11x_object.c */
+ void object_FreeAllObjects(CK_SLOT_ID slotID, P11_Object *list);
+ void object_FreeObject(CK_SLOT_ID slotID, P11_Object *object);
+ void object_FreeAllAttributes(P11_Attrib *list);
+CK_RV object_AddObject(CK_SLOT_ID slotID, CK_OBJECT_HANDLE *phObject);
+CK_RV object_UpdateKeyInfo(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *hObject, MSCKeyInfo *pKeyInfo);
+CK_RV object_UpdateObjectInfo(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *hObject, MSCObjectInfo *pObjectInfo);
+CK_RV object_FreeTokenObjects();
+CK_RV object_AddAttribute(P11_Object *object, CK_ATTRIBUTE_TYPE type, CK_BBOOL token, CK_BYTE *value, CK_ULONG value_len, P11_Attrib **attrib);
+CK_RV object_MatchAttrib(CK_ATTRIBUTE *attrib, P11_Object *object);
+CK_RV object_TemplateGetAttrib(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attrib, CK_ULONG attrib_count, CK_ATTRIBUTE **attrib_out);
+CK_RV object_RSAGenKeyPair(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE *pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE *pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE *phPublicKey, CK_OBJECT_HANDLE *phPrivateKey);
+CK_RV object_GetAttrib(CK_ATTRIBUTE_TYPE type, P11_Object *object, P11_Attrib **attrib);
+CK_RV object_SetAttrib(P11_Object *object, CK_ATTRIBUTE *attrib);
+void object_LogObjects(CK_SLOT_ID slotID);
+void object_LogObject(P11_Object *object);
+void object_LogAttribute(CK_ATTRIBUTE *attrib);
+CK_RV object_AddBoolAttribute(CK_ATTRIBUTE_TYPE type, CK_BBOOL value, P11_Object *object);
+ void object_BinToHex(CK_BYTE *data, CK_ULONG data_len, CK_BYTE *out);
+CK_RV object_AddAttributes(P11_Object *object, CK_BYTE *data, CK_ULONG len);
+CK_RV object_ReadAttributes(CK_SESSION_HANDLE hSession, CK_BYTE *obj_id, P11_Object *object);
+CK_RV object_InferAttributes(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_RV object_InferKeyAttributes(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_RV object_InferObjAttributes(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_RV object_WriteAttributes(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_RV object_InferClassAttributes(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_RV object_GetCertIssuer(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len);
+CK_RV object_GetCertSubject(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len);
+CK_RV object_GetCertSerial(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len);
+CK_RV object_GetCertModulus(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len);
+CK_RV object_GetCertPubExponent(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len);
+CK_RV object_CreateCertificate(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_RV object_CreatePublicKey(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_RV object_CreatePrivateKey(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_RV object_CreateObject(CK_SESSION_HANDLE hSession, P11_Object *object);
+CK_ULONG object_MapPIN(CK_ULONG pinNum);
+CK_ULONG object_UserMode(CK_SESSION_HANDLE hSession);
+
+/* p11x_prefs.c */
+void util_ParsePreference(char *buf, CK_ULONG buf_size);
+CK_RV util_ReadPreferences();
+
+/* p11x_state.c */
+CK_RV state_Init();
+CK_RV state_Free();
+
+/* p11x_slot.c */
+   CK_RV slot_BeginTransaction(CK_ULONG slotID);
+   CK_RV slot_EndTransaction(CK_ULONG slotID, CK_ULONG action);
+CK_BBOOL slot_CheckRWSOsession(CK_ULONG slotID);
+   CK_RV slot_EstablishConnection(CK_ULONG slotID);
+   CK_RV slot_ReleaseConnection(CK_ULONG slotID);
+   CK_RV slot_UpdateSlot(CK_ULONG slotID);
+   CK_RV slot_VerifyPIN(CK_SLOT_ID slotID, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen);
+CK_ULONG slot_MinRSAKeySize(MSCULong32 cap);
+CK_ULONG slot_MaxRSAKeySize(MSCULong32 cap);
+   CK_RV slot_UpdateMechanisms(CK_ULONG slotID);
+CK_ULONG slot_MechanismCount(P11_MechInfo *mech);
+    void slot_FreeAllMechanisms(P11_MechInfo *list);
+   CK_RV slot_AddMechanism(P11_Slot *slot, CK_MECHANISM_TYPE type, P11_MechInfo **mech_info);
+   CK_RV slot_UpdateToken(CK_ULONG slotID);
+   CK_RV slot_UpdateSlotList();
+   CK_RV slot_FreeAllSlots();
+   CK_RV slot_DisconnectSlot(CK_ULONG slotID, CK_ULONG action);
+   CK_RV slot_PublicMode(CK_ULONG slotID);
+   CK_RV slot_UserMode(CK_ULONG slotID);
+   CK_RV slot_TokenPresent(CK_ULONG slotID);
+   CK_RV slot_TokenChanged();
+   CK_RV slot_AsyncUpdateSlot();
+    void slot_BlankTokenInfo(CK_TOKEN_INFO *token_info);
+   CK_RV slot_ReverifyPins();
+
+/* p11x_session.c */
+CK_RV session_AddSession(CK_SESSION_HANDLE *phSession);
+CK_RV session_FreeSession(CK_SESSION_HANDLE hSession);
+
+/* p11x_thread_xxx.c */
+CK_RV thread_Initialize();
+CK_RV thread_InitFunctions(CK_CREATEMUTEX fn_init,
+                           CK_DESTROYMUTEX fn_destroy,
+                           CK_LOCKMUTEX fn_lock,
+                           CK_UNLOCKMUTEX fn_unlock);
+CK_RV thread_Finalize();
+CK_RV thread_MutexInit(P11_Mutex *mutex);
+CK_RV thread_MutexDestroy(P11_Mutex mutex);
+CK_RV thread_MutexLock(P11_Mutex mutex);
+CK_RV thread_MutexUnlock(P11_Mutex mutex);
+
+/* p11x_util.c */
+    void util_byterev(CK_BYTE *data, CK_ULONG len);
+CK_ULONG util_strpadlen(CK_CHAR *string, CK_ULONG max_len);
+   CK_RV util_PadStrSet(CK_CHAR *string, CK_CHAR *value, CK_ULONG size);
+   CK_RV util_StripPKCS1(CK_BYTE *data, CK_ULONG len, CK_BYTE *output, CK_ULONG *out_len);
+#ifndef __USE_GNU
+#ifndef WIN32
+   size_t strnlen(__const char *__string, size_t __maxlen);
+#else
+   size_t strnlen(const char *__string, size_t __maxlen);
+#endif
+#endif /* __USE_GNU */
+CK_BBOOL util_IsLittleEndian();
+
+/* p11x_msc.c */
+#include "p11x_msc.h"
+
+
+/******************************************************************************
+** dmalloc debugging
+******************************************************************************/
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+
+#endif /* __CRYPTOKI_H__ */

Added: trunk/SmartCardServices/src/PKCS11/cryptoki_unix.h
===================================================================
--- trunk/SmartCardServices/src/PKCS11/cryptoki_unix.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/cryptoki_unix.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,38 @@
+/******************************************************************************
+** 
+**  $Id: cryptoki_unix.h,v 1.2 2003/02/13 20:06:37 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: UNIX specific cryptoki definitions
+** 
+******************************************************************************/
+
+#ifndef __CRYPTOKI_UNIX_H__
+#define __CRYPTOKI_UNIX_H__
+#ifndef WIN32
+
+#define CK_PTR *
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+  returnType name
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+  returnType name
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+  returnType (* name)
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+  returnType (* name)
+
+#ifndef NULL_PTR
+#define NULL_PTR 0
+#endif
+
+#include "pkcs11.h"
+
+#endif /* ifndef WIN32 */
+#endif /* __CRYPTOKI_UNIX_H__ */

Added: trunk/SmartCardServices/src/PKCS11/cryptoki_win32.h
===================================================================
--- trunk/SmartCardServices/src/PKCS11/cryptoki_win32.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/cryptoki_win32.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,58 @@
+/******************************************************************************
+** 
+**  $Id: cryptoki_win32.h,v 1.2 2003/02/13 20:06:37 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: WIN32 specific cryptoki definitions
+** 
+******************************************************************************/
+
+#ifndef __CRYPTOKI_WIN32_H__
+#define __CRYPTOKI_WIN32_H__
+#ifdef WIN32
+
+#pragma pack(push, cryptoki, 1)
+
+/* Specifies that the function is a DLL entry point. */
+#define CK_IMPORT_SPEC __declspec(dllimport)
+
+/* Define CRYPTOKI_EXPORTS during the build of cryptoki libraries. Do
+ * not define it in applications.
+ */
+#ifdef CRYPTOKI_EXPORTS
+/* Specified that the function is an exported DLL entry point. */
+#define CK_EXPORT_SPEC __declspec(dllexport) 
+#else
+#define CK_EXPORT_SPEC CK_IMPORT_SPEC 
+#endif
+
+/* Ensures the calling convention for Win32 builds */
+#define CK_CALL_SPEC __cdecl
+
+#define CK_PTR *
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+  returnType CK_EXPORT_SPEC CK_CALL_SPEC name
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+  returnType CK_EXPORT_SPEC CK_CALL_SPEC name
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+  returnType CK_IMPORT_SPEC (CK_CALL_SPEC CK_PTR name)
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+  returnType (CK_CALL_SPEC CK_PTR name)
+
+#ifndef NULL_PTR
+#define NULL_PTR 0
+#endif
+
+#include "pkcs11.h"
+
+#pragma pack(pop, cryptoki)
+
+#endif /* WIN32 */
+#endif /* __CRYPTOKI_WIN32_H__ */

Added: trunk/SmartCardServices/src/PKCS11/p11_crypt.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_crypt.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_crypt.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,442 @@
+/******************************************************************************
+** 
+**  $Id: p11_crypt.c,v 1.3 2004/10/14 20:33:36 mb Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Encryption and decryption
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+#include <openssl/rsa.h>
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_EncryptInit)
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the encryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of encryption key */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+
+    P11_LOG_START("C_EncryptInit");
+
+    thread_MutexLock(st.async_lock);
+
+    log_Log(LOG_LOW, "Encrypt mech: %X", *pMechanism);
+    log_Log(LOG_LOW, "Encrypt key: %lX", hKey);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pMechanism || !hKey)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!USER_MODE)
+        rv = CKR_USER_NOT_LOGGED_IN;
+    else if (pMechanism->mechanism != CKM_RSA_PKCS)
+        rv = CKR_MECHANISM_INVALID;
+    else
+    {
+        /* Fixme: need to verify that the card supports the mechanism and its parameters */
+        /* Fixme: should probably add session.encrypt_mech and session.encrypt_key */
+        session->sign_mech = *pMechanism;
+        session->sign_key = hKey;
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_EncryptInit");
+
+    return rv;
+}
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_DEFINE_FUNCTION(CK_RV, C_Encrypt)
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pData,               /* the plaintext data */
+  CK_ULONG          ulDataLen,           /* bytes of plaintext */
+  CK_BYTE_PTR       pEncryptedData,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedDataLen  /* gets c-text size */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Object *key = (P11_Object *)session->sign_key;
+    MSCCryptInit cryptInit;
+    CK_BYTE *t_data1 = 0;
+    CK_ULONG t_data1_len;
+
+    P11_LOG_START("C_Encrypt");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pEncryptedData || !pData)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!key)
+        rv = CKR_OPERATION_NOT_INITIALIZED;
+    else if (!USER_MODE)
+        rv = CKR_USER_NOT_LOGGED_IN;
+    else if ((CK_ULONG)(key->msc_key->keySize / 8) > ulDataLen)
+        rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
+    else if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+        /* Intentionally blank */;
+    else if (session->sign_mech.mechanism == CKM_RSA_PKCS)
+    {
+        /* Fixme: this is not fully implemented since it doesn't look at the mechanism parameter */
+
+        cryptInit.keyNum = key->msc_key->keyNum;
+        cryptInit.cipherMode = MSC_MODE_RSA_NOPAD;
+        cryptInit.cipherDirection = MSC_DIR_SIGN;
+        cryptInit.optParams = 0;
+        cryptInit.optParamsSize = 0;
+
+        log_Log(LOG_LOW, "Using key number: %d", cryptInit.keyNum);
+
+        t_data1_len = key->msc_key->keySize / 8;
+        t_data1 = (CK_BYTE *)malloc(t_data1_len);
+
+        if (!t_data1)
+            rv = CKR_HOST_MEMORY;
+        else if (t_data1_len > *pulEncryptedDataLen)
+            rv = CKR_BUFFER_TOO_SMALL;
+        else if (!RSA_padding_add_PKCS1_type_1(t_data1, t_data1_len, pData, ulDataLen))
+            rv = CKR_FUNCTION_FAILED;
+        else if (MSC_ERROR(msc_ComputeCrypt(&st.slots[session->session.slotID - 1].conn,
+                                            &cryptInit,
+                                            t_data1,
+                                            t_data1_len,
+                                            pEncryptedData,
+                                            (MSCPULong32)pulEncryptedDataLen)))
+        {
+            P11_ERR("MSCComputeCrypt failed");
+            rv = CKR_FUNCTION_FAILED;
+        }
+
+        if (t_data1)
+            free(t_data1);
+
+        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+    }
+    else
+    {
+        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+        rv = CKR_MECHANISM_INVALID;
+    }
+
+    session->sign_key = 0;
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_Encrypt");
+
+    return rv;
+}
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_EncryptUpdate)
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pPart,              /* the plaintext data */
+  CK_ULONG          ulPartLen,          /* plaintext data len */
+  CK_BYTE_PTR       pEncryptedPart,     /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen /* gets c-text size */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_EncryptUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_EncryptUpdate");
+
+    return rv;
+}
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_EncryptFinal)
+(
+  CK_SESSION_HANDLE hSession,                /* session handle */
+  CK_BYTE_PTR       pLastEncryptedPart,      /* last c-text */
+  CK_ULONG_PTR      pulLastEncryptedPartLen  /* gets last size */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_EncryptFinal");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_EncryptFinal");
+
+    return rv;
+}
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the decryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of decryption key */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+
+    P11_LOG_START("C_DecryptInit");
+
+    thread_MutexLock(st.async_lock);
+
+    log_Log(LOG_LOW, "Decrypt mech: %X", *pMechanism);
+    log_Log(LOG_LOW, "Decrypt key: %lX", hKey);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pMechanism || !hKey)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!USER_MODE)
+        rv = CKR_USER_NOT_LOGGED_IN;
+    else if (pMechanism->mechanism != CKM_RSA_PKCS)
+        rv = CKR_MECHANISM_INVALID;
+    else
+    {
+        /* Fixme: need to verify that the card supports the mechanism and its parameters */
+        /* Fixme: should probably add session.decrypt_mech and session.decrypt_key */
+        session->sign_mech = *pMechanism;
+        session->sign_key = hKey;
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DecryptInit");
+
+    return rv;
+}
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_DEFINE_FUNCTION(CK_RV, C_Decrypt)
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pEncryptedData,     /* ciphertext */
+  CK_ULONG          ulEncryptedDataLen, /* ciphertext length */
+  CK_BYTE_PTR       pData,              /* gets plaintext */
+  CK_ULONG_PTR      pulDataLen          /* gets p-text size */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Object *key = (P11_Object *)session->sign_key;
+    MSCCryptInit cryptInit;
+    CK_BYTE *t_data1 = 0, *t_data2 = 0;
+    CK_ULONG t_data1_len, t_data2_len;
+
+    P11_LOG_START("C_Decrypt");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pEncryptedData || !pData)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!key)
+        rv = CKR_OPERATION_NOT_INITIALIZED;
+    else if (!USER_MODE)
+        rv = CKR_USER_NOT_LOGGED_IN;
+    else if ((CK_ULONG)(key->msc_key->keySize / 8) > ulEncryptedDataLen)
+        rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
+    else if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+        /* Intentionally blank */;
+    else if (session->sign_mech.mechanism == CKM_RSA_PKCS)
+    {
+        MSCULong32  ulValue, lenValue;
+        /* Fixme: this is not fully implemented since it doesn't look at the mechanism parameter */
+        if (MSC_ERROR(msc_GetCapabilities(&st.slots[session->session.slotID - 1].conn,
+                        MSC_TAG_CAPABLE_RSA,
+                        (CK_BYTE_PTR) &ulValue,
+                        &lenValue)))
+                 rv = CKR_FUNCTION_FAILED;
+        else if (ulValue & MSC_CAPABLE_RSA_NOPAD)
+        {
+            log_Log(LOG_LOW, "Decrypt: RSA NOPAD; key %i; keysize %i",
+                    key->msc_key->keyNum, key->msc_key->keySize);
+
+        cryptInit.keyNum = key->msc_key->keyNum;
+        cryptInit.cipherMode = MSC_MODE_RSA_NOPAD;
+            cryptInit.cipherDirection = MSC_DIR_DECRYPT;
+        cryptInit.optParams = 0;
+        cryptInit.optParamsSize = 0;
+
+        t_data1 = (CK_BYTE *)malloc(key->msc_key->keySize / 8);
+        t_data2 = (CK_BYTE *)malloc(key->msc_key->keySize / 8);
+        t_data2_len = key->msc_key->keySize / 8;   /* FIX - bugzilla 1701 */
+
+        if (!t_data1 || !t_data2)
+            rv = CKR_HOST_MEMORY;
+            else if (MSC_ERROR(msc_ComputeCrypt(
+                            &st.slots[session->session.slotID - 1].conn,
+                                       &cryptInit,
+                                       pEncryptedData,
+                                       ulEncryptedDataLen,
+                                       t_data1,
+                                       (MSCPULong32)&t_data1_len)))
+        {
+            P11_ERR("MSCComputeCrypt failed");
+            rv = CKR_FUNCTION_FAILED;
+        }
+            else if (CKR_ERROR(rv = util_StripPKCS1(t_data1, t_data1_len, 
+                            t_data2, &t_data2_len)))
+            /* Intentionally blank */;
+        else if (t_data2_len > *pulDataLen)
+            rv = CKR_BUFFER_TOO_SMALL;
+        else
+        {
+            memcpy(pData, t_data2, t_data2_len);
+            *pulDataLen = t_data2_len;
+        }
+        }
+        else if (ulValue & MSC_CAPABLE_RSA_PKCS1)
+        {
+            log_Log(LOG_LOW, "Decrypt: RSA PKCS1; key %i; keysize %i",
+                    key->msc_key->keyNum, key->msc_key->keySize);
+            
+            cryptInit.keyNum = key->msc_key->keyNum;
+            cryptInit.cipherDirection = MSC_DIR_DECRYPT;
+            cryptInit.cipherMode = MSC_MODE_RSA_PAD_PKCS1;
+            cryptInit.optParams = 0;
+            cryptInit.optParamsSize = 0;
+
+            t_data1 = (CK_BYTE *)malloc(key->msc_key->keySize / 8);
+
+            if (!t_data1)
+                rv = CKR_HOST_MEMORY;
+            else if (MSC_ERROR(msc_ComputeCrypt(
+                            &st.slots[session->session.slotID - 1].conn,
+                            &cryptInit,
+                            pEncryptedData,
+                            ulEncryptedDataLen,
+                            t_data1,
+                            (MSCPULong32)&t_data1_len)))
+            {
+                P11_ERR("MSCComputeCrypt failed");
+                rv = CKR_FUNCTION_FAILED;
+            }
+            if (t_data1_len > *pulDataLen)
+                rv = CKR_BUFFER_TOO_SMALL;
+            else
+            {
+                memcpy(pData, t_data1, t_data1_len);
+                *pulDataLen = t_data1_len;
+            }
+        }
+        else
+            rv = CKR_MECHANISM_PARAM_INVALID;
+
+        if (t_data1)
+            free(t_data1);
+
+        if (t_data2)
+            free(t_data2);
+
+        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+    }
+    else
+    {
+        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+        rv = CKR_MECHANISM_INVALID;
+    }
+
+    session->sign_key = 0;
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_Decrypt");
+
+    return rv;
+}
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DecryptUpdate)
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* encrypted data */
+  CK_ULONG          ulEncryptedPartLen,  /* input length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* p-text size */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DecryptUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DecryptUpdate");
+
+    return rv;
+}
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DecryptFinal)
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pLastPart,      /* gets plaintext */
+  CK_ULONG_PTR      pulLastPartLen  /* p-text size */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DecryptFinal");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DecryptFinal");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_digest.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_digest.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_digest.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,142 @@
+/******************************************************************************
+** 
+**  $Id: p11_digest.c,v 1.2 2003/02/13 20:06:37 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Message digesting
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DigestInit)
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism  /* the digesting mechanism */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DigestInit");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DigestInit");
+
+    return rv;
+}
+
+
+/* C_Digest digests data in a single part. */
+CK_DEFINE_FUNCTION(CK_RV, C_Digest)
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pData,        /* data to be digested */
+  CK_ULONG          ulDataLen,    /* bytes of data to digest */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets digest length */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_Digest");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_Digest");
+
+    return rv;
+}
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DigestUpdate)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* data to be digested */
+  CK_ULONG          ulPartLen  /* bytes of data to be digested */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DigestUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DigestUpdate");
+
+    return rv;
+}
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_DEFINE_FUNCTION(CK_RV, C_DigestKey)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hKey       /* secret key to digest */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DigestKey");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DigestKey");
+
+    return rv;
+}
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DigestFinal)
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets byte count of digest */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DigestFinal");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DigestFinal");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_dual.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_dual.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_dual.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,125 @@
+/******************************************************************************
+** 
+**  $Id: p11_dual.c,v 1.2 2003/02/13 20:06:38 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Dual-function cryptographic operation
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DigestEncryptUpdate)
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DigestEncryptUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DigestEncryptUpdate");
+
+    return rv;
+}
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DecryptDigestUpdate)
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets plaintext len */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DecryptDigestUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DecryptDigestUpdate");
+
+    return rv;
+}
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_SignEncryptUpdate)
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_SignEncryptUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SignEncryptUpdate");
+
+    return rv;
+}
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_DEFINE_FUNCTION(CK_RV, C_DecryptVerifyUpdate)
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets p-text length */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DecryptVerifyUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DecryptVerifyUpdate");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_ext.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_ext.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_ext.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,38 @@
+/******************************************************************************
+** 
+**  $Id: p11_ext.c,v 1.2 2003/02/13 20:06:38 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Functions added in for Cryptoki Version 2.01 or later
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_DEFINE_FUNCTION(CK_RV, C_WaitForSlotEvent)
+(
+  CK_FLAGS flags,        /* blocking/nonblocking flag */
+  CK_SLOT_ID_PTR pSlot,  /* location that receives the slot ID */
+  CK_VOID_PTR pRserved   /* reserved.  Should be NULL_PTR */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_WaitForSlotEvent");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_WaitForSlotEvent");
+
+    return rv;
+}

Added: trunk/SmartCardServices/src/PKCS11/p11_general.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_general.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_general.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,242 @@
+/******************************************************************************
+** 
+**  $Id: p11_general.c,v 1.2 2003/02/13 20:06:38 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: General-purpose
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* Win32 defines CreateMutex as a macro (CreateMutexA) */
+/* We need the preprocessor to not process the variable name in pInitArgs */
+#ifdef WIN32
+#undef CreateMutex
+#endif
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_DEFINE_FUNCTION(CK_RV, C_Initialize)
+(
+    CK_VOID_PTR pInitArgs  /* if this is not NULL_PTR, it gets * cast to CK_C_INITIALIZE_ARGS_PTR * and dereferenced */
+)
+{
+    CK_RV rv = CKR_OK;
+    CK_C_INITIALIZE_ARGS blank_init_args;
+    CK_C_INITIALIZE_ARGS *init_args;
+
+    memset(&blank_init_args, 0x00, sizeof(blank_init_args));
+
+    /* Must initialize the state and preferences before any logging starts */
+    rv = state_Init(); 
+
+    P11_LOG_START("C_Initialize");
+
+    if (CKR_ERROR(rv))
+        /* Do nothing */;
+    else if (st.initialized)
+        rv = CKR_CRYPTOKI_ALREADY_INITIALIZED;
+    else
+    {
+        if (!pInitArgs)
+            init_args = &blank_init_args;
+        else 
+        {
+            init_args = (CK_C_INITIALIZE_ARGS *)pInitArgs;
+            log_Log(LOG_LOW, "Init flags: 0x%X", init_args->flags);
+        }
+
+        /* If preferences request non-threaded mode then force this flag */
+        if (!st.prefs.threaded)
+            init_args->flags |= CKF_LIBRARY_CANT_CREATE_OS_THREADS;
+
+        if ((CKF_OS_LOCKING_OK & init_args->flags))
+        {
+            log_Log(LOG_LOW, "Native thread locks are fine");
+            st.native_locks = 1;
+        }
+        else
+        {
+            log_Log(LOG_LOW, "Using non-native (application supplied) thread locks");
+            st.native_locks = 0;
+        }
+
+        if ((CKF_LIBRARY_CANT_CREATE_OS_THREADS & init_args->flags))
+        {
+            log_Log(LOG_LOW, "Application does not allow thread creation; disabling threaded slot watcher");
+            st.create_threads = 0;
+        }
+        else
+        {
+            log_Log(LOG_LOW, "Creating threads is fine; using threaded slot watcher");
+            st.create_threads = 1;
+        }
+
+        if (init_args->pReserved)
+            rv = CKR_ARGUMENTS_BAD;
+        else if ((init_args->CreateMutex || init_args->DestroyMutex || init_args->LockMutex || init_args->UnlockMutex) &&
+                 (!init_args->CreateMutex || !init_args->DestroyMutex || !init_args->LockMutex || !init_args->UnlockMutex))
+        {
+            rv = CKR_ARGUMENTS_BAD;
+        }
+        else 
+        {
+            if (!st.prefs.threaded)
+                log_Log(LOG_LOW, "All threading disabled");
+            else
+            {
+                if (st.native_locks)
+                    rv = thread_Initialize();
+                else
+                    rv = thread_InitFunctions(init_args->CreateMutex,
+                                              init_args->DestroyMutex,
+                                              init_args->LockMutex,
+                                              init_args->UnlockMutex);
+
+                if (CKR_ERROR(rv))
+                    log_Log(LOG_MED, "Could not initialize thread subsystem");
+                else
+                {
+                    thread_MutexInit(&st.log_lock);
+                    thread_MutexInit(&st.async_lock);
+                }
+            }
+
+            if (!CKR_ERROR_NOLOG(rv))
+            {
+                if (CKR_ERROR(rv = slot_UpdateSlotList()))
+                    rv = CKR_DEVICE_REMOVED;
+                else if (!CKR_ERROR(rv = async_StartSlotWatcher()))
+                {
+                    st.initialized = TRUE;
+                    (void)CKR_ERROR(slot_TokenChanged());
+                }
+            }
+        }
+    }
+
+    P11_LOG_END("C_Initialize");
+    return rv;
+}
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library. */
+CK_DEFINE_FUNCTION(CK_RV, C_Finalize)
+(
+  CK_VOID_PTR   pReserved  /* reserved.  Should be NULL_PTR */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_Finalize");
+
+    /* Pause in case there are pending active operations */
+    thread_MutexLock(st.async_lock);
+    thread_MutexUnlock(st.async_lock);
+
+    if (!st.initialized)
+        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+    else if (pReserved)
+        rv = CKR_ARGUMENTS_BAD;
+    else
+    {
+        (void)CKR_ERROR(async_StopSlotWatcher());
+
+        if (st.log_lock)
+        {
+            thread_MutexDestroy(st.log_lock);
+            st.log_lock = 0;
+        }
+
+        if (st.async_lock)
+        {
+            thread_MutexDestroy(st.async_lock);
+            st.async_lock = 0;
+        }
+
+        if (st.prefs.threaded)
+            thread_Finalize();
+
+        (void)CKR_ERROR(state_Free());
+    }
+
+    P11_LOG_END("C_Finalize");
+
+    return rv;
+}
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)
+(
+  CK_INFO_PTR   pInfo  /* location that receives information */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_GetInfo");
+
+    thread_MutexLock(st.async_lock);
+
+    if (!st.initialized)
+        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+    else if(!pInfo)
+        rv = CKR_ARGUMENTS_BAD;
+    else
+    {
+        log_Log(LOG_LOW, "PKCS #11 version: %d.%d", st.prefs.version_major, st.prefs.version_minor);
+        pInfo->cryptokiVersion.major = (CK_BYTE)st.prefs.version_major;
+        pInfo->cryptokiVersion.minor = (CK_BYTE)st.prefs.version_minor;
+        util_PadStrSet(pInfo->manufacturerID, (CK_CHAR *)PKCS11_MFR_ID, sizeof(pInfo->manufacturerID));
+        pInfo->flags = 0;
+        util_PadStrSet(pInfo->libraryDescription, (CK_CHAR *)PKCS11_DESC, sizeof(pInfo->libraryDescription));
+        pInfo->libraryVersion.major = PKCS11_LIB_MAJOR;
+        pInfo->libraryVersion.minor = PKCS11_LIB_MINOR;
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetInfo");
+    return rv;
+}
+
+
+/* C_GetFunctionList returns the function list. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionList)
+(
+  CK_FUNCTION_LIST_PTR_PTR ppFunctionList  /* receives pointer to
+                                            * function list */
+)
+{
+    CK_RV rv = CKR_OK;
+    static CK_FUNCTION_LIST fnList;
+
+    /* Must initialize the state and preferences before any logging starts */
+    rv = state_Init();
+
+    P11_LOG_START("C_GetFunctionList");
+
+    if (CKR_ERROR(rv))
+        /* Do nothing */;
+    else if (!ppFunctionList)
+        rv = CKR_ARGUMENTS_BAD;
+    else
+    {
+        fnList.version.major = (CK_BYTE)st.prefs.version_major;
+        fnList.version.minor = (CK_BYTE)st.prefs.version_minor;
+
+#define CK_PKCS11_FUNCTION_INFO(name) fnList.name = name;
+#include "pkcs11f.h"
+#undef CK_PKCS11_FUNCTION_INFO
+
+        *ppFunctionList = &fnList;
+    }
+
+    P11_LOG_END("C_GetFunctionList");
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_key.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_key.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_key.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,350 @@
+/******************************************************************************
+** 
+**  $Id: p11_key.c,v 1.2 2003/02/13 20:06:38 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Key management
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_DEFINE_FUNCTION(CK_RV, C_GenerateKey)
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_MECHANISM_PTR     pMechanism,  /* key generation mech. */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new key */
+  CK_ULONG             ulCount,     /* # of attrs in template */
+  CK_OBJECT_HANDLE_PTR phKey        /* gets handle of new key */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_GenerateKey");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GenerateKey");
+
+    return rv;
+}
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair, 
+ * creating new key objects. */
+CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)
+(
+  CK_SESSION_HANDLE    hSession,                    /* session
+                                                     * handle */
+  CK_MECHANISM_PTR     pMechanism,                  /* key-gen
+                                                     * mech. */
+  CK_ATTRIBUTE_PTR     pPublicKeyTemplate,          /* template
+                                                     * for pub.
+                                                     * key */
+  CK_ULONG             ulPublicKeyAttributeCount,   /* # pub.
+                                                     * attrs. */
+  CK_ATTRIBUTE_PTR     pPrivateKeyTemplate,         /* template
+                                                     * for priv.
+                                                     * key */
+  CK_ULONG             ulPrivateKeyAttributeCount,  /* # priv.
+                                                     * attrs. */
+  CK_OBJECT_HANDLE_PTR phPublicKey,                 /* gets pub.
+                                                     * key
+                                                     * handle */
+  CK_OBJECT_HANDLE_PTR phPrivateKey                 /* gets
+                                                     * priv. key
+                                                     * handle */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    CK_ULONG i;
+    CK_ATTRIBUTE *attrib;
+
+    P11_LOG_START("C_GenerateKeyPair");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pMechanism || !pPublicKeyTemplate ||
+             !pPrivateKeyTemplate || !phPublicKey || !phPrivateKey)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (READ_ONLY_SESSION)
+        rv = CKR_SESSION_READ_ONLY;
+    else if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+        /* Intentionally blank */;
+    else
+    {
+        log_Log(LOG_LOW, "Mech type: %lX", pMechanism->mechanism);
+        log_Log(LOG_LOW, "Param Len: %lu", pMechanism->ulParameterLen);
+        log_Log(LOG_LOW, "Pub attrib count: %lu", ulPublicKeyAttributeCount);
+        for (i = 0; i < ulPublicKeyAttributeCount; i++)
+            log_Log(LOG_LOW, "Attrib type: %lX", pPublicKeyTemplate[i].type);
+        log_Log(LOG_LOW, "Priv attrib count: %lu", ulPrivateKeyAttributeCount);
+        for (i = 0; i < ulPrivateKeyAttributeCount; i++)
+            log_Log(LOG_LOW, "Attrib type: %lX", pPrivateKeyTemplate[i].type);
+
+        /* Fixme: Only supports generating keys on card */
+        if (CKR_ERROR(object_TemplateGetAttrib(CKA_TOKEN, pPublicKeyTemplate, ulPublicKeyAttributeCount, &attrib)) ||
+            CKR_ERROR(object_TemplateGetAttrib(CKA_TOKEN, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, &attrib)))
+            rv = CKR_ATTRIBUTE_VALUE_INVALID;
+        else if (pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN)
+            (void)CKR_ERROR(rv = object_RSAGenKeyPair(hSession, pPublicKeyTemplate, 
+                                                ulPublicKeyAttributeCount, 
+                                                pPrivateKeyTemplate, 
+                                                ulPrivateKeyAttributeCount,
+                                                phPublicKey,
+                                                phPrivateKey));
+        else
+            rv = CKR_MECHANISM_INVALID;
+
+        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+    }
+
+    log_Log(LOG_LOW, "Returning handles for public key: %lX and private key: %lX", *phPublicKey, *phPrivateKey);
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GenerateKeyPair");
+
+    return rv;
+}
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_DEFINE_FUNCTION(CK_RV, C_WrapKey)
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,      /* the wrapping mechanism */
+  CK_OBJECT_HANDLE  hWrappingKey,    /* wrapping key */
+  CK_OBJECT_HANDLE  hKey,            /* key to be wrapped */
+  CK_BYTE_PTR       pWrappedKey,     /* gets wrapped key */
+  CK_ULONG_PTR      pulWrappedKeyLen /* gets wrapped key size */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_WrapKey");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_WrapKey");
+
+    return rv;
+}
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey)
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* unwrapping mech. */
+  CK_OBJECT_HANDLE     hUnwrappingKey,    /* unwrapping key */
+  CK_BYTE_PTR          pWrappedKey,       /* the wrapped key */
+  CK_ULONG             ulWrappedKeyLen,   /* wrapped key len */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Object *object;
+    P11_Attrib *attrib;
+    MSCCryptInit cryptInit;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Object *key = (P11_Object *)hUnwrappingKey;
+    CK_BYTE *output = 0, *final_output = 0;
+    MSCULong32 output_len;
+	CK_ULONG final_output_len;
+    CK_ULONG i;
+
+    P11_LOG_START("C_UnwrapKey");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pMechanism ||
+             !hUnwrappingKey || !pWrappedKey || !pTemplate)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (READ_ONLY_SESSION)
+        rv = CKR_SESSION_READ_ONLY;
+    else if (pMechanism->mechanism == CKM_RSA_PKCS)
+    {
+        log_Log(LOG_LOW, "UnwrapKey:  %X", hUnwrappingKey);
+        log_Log(LOG_LOW, "WrappedLen:  %lu", ulWrappedKeyLen);
+
+        if (CKR_ERROR(object_AddObject(session->session.slotID, (CK_OBJECT_HANDLE *)&object)))
+            rv = CKR_FUNCTION_FAILED;
+        else
+        {
+            for (i = 0; i < ulAttributeCount; i++)
+                if (CKR_ERROR(rv = object_AddAttribute(object, 
+                                                       pTemplate[i].type, 
+                                                       FALSE,
+                                                       (CK_BYTE *)pTemplate[i].pValue, 
+                                                       pTemplate[i].ulValueLen, 
+                                                       &attrib)))
+                    break;
+    
+            if (!CKR_ERROR(rv))
+            {
+                MSCULong32  ulValue, lenValue;
+                if (MSC_ERROR(msc_GetCapabilities(
+                                &st.slots[session->session.slotID - 1].conn,
+                                MSC_TAG_CAPABLE_RSA,
+                                (CK_BYTE_PTR) &ulValue,
+                                &lenValue)))
+                        rv = CKR_FUNCTION_FAILED;
+                else if (ulValue & MSC_CAPABLE_RSA_NOPAD)
+                {
+                log_Log(LOG_LOW, "UnwrapKey num: %lu", key->msc_key->keyNum);
+                cryptInit.keyNum = key->msc_key->keyNum;
+                cryptInit.cipherMode = MSC_MODE_RSA_NOPAD;
+                    cryptInit.cipherDirection = MSC_DIR_DECRYPT;
+                cryptInit.optParams = 0;
+                cryptInit.optParamsSize = 0;
+        
+                output_len = key->msc_key->keySize / 8;
+                output = (CK_BYTE *)malloc(output_len);
+                final_output_len = output_len;
+                final_output = (CK_BYTE *)malloc(final_output_len);
+        
+                if (!output || !final_output)
+                    rv = CKR_HOST_MEMORY;
+                else if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+                    /* Intentionally blank */;
+                    else if (MSC_ERROR(msc_ComputeCrypt(
+                                    &st.slots[session->session.slotID - 1].conn,
+                                                   &cryptInit,
+                                                   pWrappedKey,
+                                                   ulWrappedKeyLen,
+                                                   output,
+                                                   &output_len)))
+                {
+                    P11_ERR("MSCComputeCrypt failed");
+                    rv = CKR_FUNCTION_FAILED;
+                }
+                else
+                {
+                    (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+
+                        if (!CKR_ERROR(rv = util_StripPKCS1(output, output_len, 
+                                        final_output, &final_output_len)))
+                        {
+                            rv = object_AddAttribute(object, CKA_VALUE, FALSE, 
+                                    final_output, final_output_len, &attrib);
+                            *phKey = (CK_OBJECT_HANDLE)object;
+                        }
+                    }
+                }
+                else if (ulValue & MSC_CAPABLE_RSA_PKCS1)
+                {
+                    log_Log(LOG_LOW, "UnwrapKey num: %lu", key->msc_key->keyNum);
+                    cryptInit.keyNum = key->msc_key->keyNum;
+                    cryptInit.cipherDirection = MSC_DIR_DECRYPT;
+                    cryptInit.cipherMode = MSC_MODE_RSA_PAD_PKCS1;
+                    cryptInit.optParams = 0;
+                    cryptInit.optParamsSize = 0;
+                    
+                    output_len = key->msc_key->keySize / 8;
+                    output = (CK_BYTE *)malloc(output_len);
+        
+                    if (!output)
+                        rv = CKR_HOST_MEMORY;
+                    else if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+                        /* Intentionally blank */;
+                    else if (MSC_ERROR(msc_ComputeCrypt(
+                                    &st.slots[session->session.slotID - 1].conn,
+                                    &cryptInit,
+                                    pWrappedKey,
+                                    ulWrappedKeyLen,
+                                    output,
+                                    &output_len)))
+                    {
+                        P11_ERR("MSCComputeCrypt failed");
+                        rv = CKR_FUNCTION_FAILED;
+                    }
+                    else
+                    {
+                        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+
+                        rv = object_AddAttribute(object, CKA_VALUE, FALSE,
+                                output, output_len, &attrib);
+                        *phKey = (CK_OBJECT_HANDLE)object;
+                    }
+                }
+                else
+                    rv = CKR_MECHANISM_PARAM_INVALID;
+        
+                if (output)
+                    free(output);
+
+                if (final_output)
+                    free(final_output);
+            }
+        }
+    }
+    else
+    {
+        log_Log(LOG_LOW, "Invalid mechanism specified: 0x%lX", pMechanism->mechanism);
+        rv = CKR_MECHANISM_INVALID;
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_UnwrapKey");
+
+    return rv;
+}
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_DEFINE_FUNCTION(CK_RV, C_DeriveKey)
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* key deriv. mech. */
+  CK_OBJECT_HANDLE     hBaseKey,          /* base key */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_DeriveKey");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DeriveKey");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_object.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_object.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_object.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,628 @@
+/******************************************************************************
+** 
+**  $Id: p11_object.c,v 1.2 2003/02/13 20:06:38 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Object management
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_CreateObject creates a new object. */
+CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,   /* the object's template */
+  CK_ULONG          ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phObject  /* gets new object's handle. */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Object *object;
+    P11_Attrib *attrib;
+    CK_BBOOL is_token = 0, token_attrib;
+    CK_ULONG i;
+    CK_ULONG obj_class;
+    CK_ATTRIBUTE t_attrib;
+
+    P11_LOG_START("C_CreateObject");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pTemplate)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (READ_ONLY_SESSION)
+        rv = CKR_SESSION_READ_ONLY;
+    else if (!CKR_ERROR(object_TemplateGetAttrib(CKA_CLASS, pTemplate, ulCount, 0)))
+    {
+        if (!CKR_ERROR(rv = object_AddObject(session->session.slotID, (CK_OBJECT_HANDLE *)&object)))
+        {
+            for (i = 0; i < ulCount; i++)
+            {
+                if (pTemplate[i].type == CKA_TOKEN)
+                    is_token = ((CK_BYTE *)(pTemplate[i].pValue))[0];
+
+                if ((pTemplate[i].type == CKA_VALUE) ||
+                    (pTemplate[i].type == CKA_SUBJECT) ||
+                    (pTemplate[i].type == CKA_ISSUER) ||
+                    (pTemplate[i].type == CKA_SERIAL_NUMBER) ||
+                    (pTemplate[i].type == CKA_PUBLIC_EXPONENT) ||
+                    (pTemplate[i].type == CKA_PRIVATE_EXPONENT) ||
+                    (pTemplate[i].type == CKA_PRIME_1) ||
+                    (pTemplate[i].type == CKA_PRIME_2) ||
+                    (pTemplate[i].type == CKA_EXPONENT_1) ||
+                    (pTemplate[i].type == CKA_EXPONENT_2) ||
+                    (pTemplate[i].type == CKA_COEFFICIENT))
+                {
+                    token_attrib = FALSE;
+                }
+                else
+                    token_attrib = TRUE;
+
+                if (CKR_ERROR(rv = object_AddAttribute(object, 
+                                                       pTemplate[i].type, 
+                                                       token_attrib,
+                                                       (CK_BYTE *)pTemplate[i].pValue, 
+                                                       pTemplate[i].ulValueLen, 
+                                                       &attrib)))
+                    break;
+
+                object_LogAttribute(&pTemplate[i]);
+            }
+
+            if (is_token && !CKR_ERROR(rv))
+            {
+                t_attrib.type = CKA_CLASS;
+                t_attrib.pValue = &obj_class;
+                t_attrib.ulValueLen = sizeof(obj_class);
+
+                obj_class = CKO_CERTIFICATE;
+
+                if (object_MatchAttrib(&t_attrib, object))
+                {
+                    /* Pull the serial from the cert because Netscape/Mozilla sets it incorrectly */
+                    CK_BYTE buf[4096]; /* Fixme: don't hardcode this */
+                    P11_Attrib *obj_attrib;
+                    CK_ULONG len;
+
+                    if (!CKR_ERROR(object_GetAttrib(CKA_VALUE, object, &obj_attrib)) &&
+                        !CKR_ERROR(object_GetCertSerial((CK_BYTE *)obj_attrib->attrib.pValue,
+                                                        obj_attrib->attrib.ulValueLen,
+                                                        buf,
+                                                        &len)))
+                    {
+                        log_Log(LOG_LOW, "Overwriting certificate serial number with infered value");
+                        (void)CKR_ERROR(object_AddAttribute(object, CKA_SERIAL_NUMBER, FALSE, buf, len, 0));
+                    }
+
+                    /* Write the cert & attributes to the card */
+                    log_Log(LOG_LOW, "Creating certificate");
+                    rv = object_CreateCertificate(hSession, object);
+                }
+                else
+                {
+                    obj_class = CKO_PUBLIC_KEY;
+                    if (object_MatchAttrib(&t_attrib, object))
+                    {
+                        log_Log(LOG_LOW, "Creating public key");
+                        rv = object_CreatePublicKey(hSession, object);
+                    }
+                    else
+                    {
+                        obj_class = CKO_PRIVATE_KEY;
+                        if (object_MatchAttrib(&t_attrib, object))
+                        {
+                            log_Log(LOG_LOW, "Creating private key");
+                            rv = object_CreatePrivateKey(hSession, object);
+
+                            { P11_Object *object2;
+                            // Fixme: hack to make sure the public key is on the token since some
+                            // Fixme: cards require the public key.  Missing error checking.
+                            log_Log(LOG_LOW, "Creating public key (THIS MAY BE REMOVED IN THE FUTURE)");
+                            rv = object_AddObject(session->session.slotID, (CK_OBJECT_HANDLE *)&object2);
+                            (void)CKR_ERROR(rv);
+
+                            obj_class = CKO_PUBLIC_KEY;
+                            rv = object_AddAttribute(object2, 
+                                                     CKA_CLASS, 
+                                                     TRUE,
+                                                     (CK_BYTE *)&obj_class, 
+                                                     sizeof(obj_class), 0);
+
+                            rv = object_GetAttrib(CKA_ID, object, &attrib);
+                            (void)CKR_ERROR(rv);
+                            rv = object_AddAttribute(object2, 
+                                                     attrib->attrib.type, 
+                                                     TRUE,
+                                                     (CK_BYTE *)attrib->attrib.pValue, 
+                                                     attrib->attrib.ulValueLen, 0);
+                            (void)CKR_ERROR(rv);
+                            rv = object_GetAttrib(CKA_MODULUS, object, &attrib);
+                            (void)CKR_ERROR(rv);
+                            rv = object_AddAttribute(object2, 
+                                                     attrib->attrib.type, 
+                                                     TRUE,
+                                                     (CK_BYTE *)attrib->attrib.pValue, 
+                                                     attrib->attrib.ulValueLen, 0);
+                            (void)CKR_ERROR(rv);
+                            rv = object_GetAttrib(CKA_PUBLIC_EXPONENT, object, &attrib);
+                            (void)CKR_ERROR(rv);
+                            rv = object_AddAttribute(object2, 
+                                                     attrib->attrib.type, 
+                                                     TRUE,
+                                                     (CK_BYTE *)attrib->attrib.pValue, 
+                                                     attrib->attrib.ulValueLen, 0);
+                            (void)CKR_ERROR(rv);
+
+                            rv = object_CreatePublicKey(hSession, object2);
+                            (void)CKR_ERROR(rv); }
+                        }
+                        else
+                        {
+                            log_Log(LOG_LOW, "Creating object");
+                            rv = object_CreateObject(hSession, object);
+                        }
+                    }
+                }
+            }
+
+            *phObject = (CK_OBJECT_HANDLE)object;
+            log_Log(LOG_LOW, "New object handle: %lX", *phObject);
+        }
+    }
+    else
+        rv = CKR_TEMPLATE_INCOMPLETE;
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_CreateObject");
+    return rv;
+}
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_DEFINE_FUNCTION(CK_RV, C_CopyObject)
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_OBJECT_HANDLE     hObject,     /* the object's handle */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new object */
+  CK_ULONG             ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phNewObject  /* receives handle of copy */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_CopyObject");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_CopyObject");
+
+    return rv;
+}
+
+
+/* C_DestroyObject destroys an object. */
+CK_DEFINE_FUNCTION(CK_RV, C_DestroyObject)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject    /* the object's handle */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+
+    P11_LOG_START("C_DestroyObject");
+
+    thread_MutexLock(st.async_lock);
+
+    log_Log(LOG_LOW, "Object handle: %lX", hObject);
+    object_FreeObject(session->session.slotID, (P11_Object *)hObject);
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_DestroyObject");
+
+    return rv;
+}
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetObjectSize)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,   /* the object's handle */
+  CK_ULONG_PTR      pulSize    /* receives size of object */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_GetObjectSize");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetObjectSize");
+
+    return rv;
+}
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetAttributeValue)
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs; gets vals */
+  CK_ULONG          ulCount     /* attributes in template */
+)
+{
+    CK_RV rv = CKR_OK;
+    CK_RV perm_rv = CKR_OK;
+    P11_Object *object = (P11_Object *)hObject;
+    P11_Attrib *attrib;
+    CK_ULONG i;
+    CK_CHAR *obj_type;
+
+    P11_LOG_START("C_GetAttributeValue");
+
+    thread_MutexLock(st.async_lock);
+
+    log_Log(LOG_LOW, "Object handle: %lX", hObject);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pTemplate)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (INVALID_OBJECT)
+        rv = CKR_OBJECT_HANDLE_INVALID;
+    else
+    {
+        if (object->msc_key)
+            obj_type = (CK_CHAR *)"Key";
+        else if (object->msc_obj)
+            obj_type = (CK_CHAR *)"Object";
+        else
+            obj_type = (CK_CHAR *)"Non-token object";
+
+        log_Log(LOG_LOW, "Get attribute object handle: %X  type: %s", hObject, obj_type);
+        for (i = 0; i < ulCount; i++)
+        {
+            log_Log(LOG_LOW, "Trying to get attribute: 0x%X", pTemplate[i].type);
+
+            if (!CKR_ERROR(rv = object_GetAttrib(pTemplate[i].type, object, &attrib)))
+            {
+                if (pTemplate[i].pValue == 0)
+                {
+                    log_Log(LOG_LOW, "pValue is NULL returning length: %lu", attrib->attrib.ulValueLen);
+                    pTemplate[i].ulValueLen = attrib->attrib.ulValueLen;
+                }
+                else if (pTemplate[i].ulValueLen < attrib->attrib.ulValueLen)
+                {
+                    log_Log(LOG_LOW, "Output buffer too small: %lu < %lu", 
+                                        pTemplate[i].ulValueLen, attrib->attrib.ulValueLen);
+                    rv = CKR_BUFFER_TOO_SMALL;
+                    pTemplate[i].ulValueLen = (CK_ULONG)-1;
+                }
+                else
+                {
+                    log_Log(LOG_LOW, "Returning attribute");
+                    object_LogAttribute(&attrib->attrib);
+
+                    memcpy(pTemplate[i].pValue, attrib->attrib.pValue, attrib->attrib.ulValueLen);
+                    pTemplate[i].ulValueLen = attrib->attrib.ulValueLen;
+
+                    /* FIXME: hack for Mozilla 1.1b endian issue */
+                    if (pTemplate[i].type == CKA_CLASS)
+                    {
+                        if (util_IsLittleEndian())
+                        {
+                            if ((((CK_BYTE *)pTemplate[i].pValue)[0] == 0x00) || 
+                                (((CK_BYTE *)pTemplate[i].pValue)[0] == 0x80))
+                            {
+                                log_Log(LOG_LOW, "Reversing CKA_CLASS for little endian");
+                                util_byterev(pTemplate[i].pValue, pTemplate[i].ulValueLen);
+                            }
+                        }
+                        else
+                        {
+                            if ((((CK_BYTE *)pTemplate[i].pValue)[0] != 0x00) &&
+                                (((CK_BYTE *)pTemplate[i].pValue)[0] != 0x80))
+                            {
+                                log_Log(LOG_LOW, "Reversing CKA_CLASS for big endian");
+                                util_byterev(pTemplate[i].pValue, pTemplate[i].ulValueLen);
+                            }
+                        }
+                    }
+                }
+            }
+            else
+            {
+                pTemplate[i].ulValueLen = (CK_ULONG)-1;
+                perm_rv = rv;
+                rv = CKR_OK;
+            }
+        }
+
+        if ((rv == CKR_OK) && (perm_rv != CKR_OK))
+            rv = perm_rv;
+    }
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetAttributeValue");
+
+    return rv;
+}
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_DEFINE_FUNCTION(CK_RV, C_SetAttributeValue)
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs and values */
+  CK_ULONG          ulCount     /* attributes in template */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Object *object = (P11_Object *)hObject;
+    ULONG i;
+
+    P11_LOG_START("C_SetAttributeValue");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pTemplate)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (INVALID_OBJECT)
+        rv = CKR_OBJECT_HANDLE_INVALID;
+    else if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+        /* Intentionally blank */;
+    else
+    {
+        for (i = 0; i < ulCount; i++)
+        {
+            log_Log(LOG_LOW, "SetAttributeValue:");
+            object_LogAttribute(&pTemplate[i]);
+
+            if (CKR_ERROR(rv = object_AddAttribute(object,
+                                                   pTemplate[i].type,
+                                                   TRUE, /* Fixme: Always a token attribute? */
+                                                   (CK_BYTE *)pTemplate[i].pValue,
+                                                   pTemplate[i].ulValueLen, 0)))
+                break;
+        }
+    
+        (void)CKR_ERROR(rv = object_WriteAttributes(hSession, object));
+
+        (void)CKR_ERROR(rv = slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SetAttributeValue");
+
+    return rv;
+}
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* attribute values to match */
+  CK_ULONG          ulCount     /* attrs in search template */
+)
+{
+    CK_RV rv = CKR_OK;
+    CK_RV msc_rv;
+    P11_Slot *slot;
+    P11_Session *session = (P11_Session *)hSession;
+    MSCKeyInfo keyInfo;
+    MSCObjectInfo objectInfo;
+
+    P11_LOG_START("C_FindObjectsInit");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (ulCount && !pTemplate)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else
+    {
+        slot = &st.slots[session->session.slotID - 1];
+        session->search_attrib_count = 0;
+
+        if (ulCount)
+        {
+            /* Fixme: Big problem? May need to malloc the pValue for the local search attributes. */
+            /*        Otherwise it uses the memory pointer back into the calling application. */
+            session->search_attrib = (CK_ATTRIBUTE *)calloc(ulCount, sizeof(CK_ATTRIBUTE));
+            if (!session->search_attrib)
+                rv = CKR_HOST_MEMORY;
+            else
+            {
+                memcpy(session->search_attrib, pTemplate, ulCount * sizeof(CK_ATTRIBUTE));
+                session->search_attrib_count = ulCount;
+            }
+        }
+
+        if (st.prefs.multi_app || !slot->objects)
+        {
+            if (!CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+            {
+                msc_rv = msc_ListKeys(&slot->conn, MSC_SEQUENCE_RESET, &keyInfo);
+                while (!MSC_ERROR(msc_rv) && !CKR_ERROR(rv))
+                {
+                    rv = object_UpdateKeyInfo(hSession, 0, &keyInfo);
+                    msc_rv = msc_ListKeys(&slot->conn, MSC_SEQUENCE_NEXT, &keyInfo); 
+                }
+        
+                msc_rv = msc_ListObjects(&slot->conn, MSC_SEQUENCE_RESET, &objectInfo);
+                while (!MSC_ERROR(msc_rv) && !CKR_ERROR(rv))
+                {
+                    if (!islower(objectInfo.objectID[0]))
+                        rv = object_UpdateObjectInfo(hSession, 0, &objectInfo);
+        
+                    msc_rv = msc_ListObjects(&slot->conn, MSC_SEQUENCE_NEXT, &objectInfo); 
+                }
+    
+                /* Fixme: Need to delete objects that are no longer on the token */
+
+                if (!CKR_ERROR(rv))
+                    (void)CKR_ERROR(rv = slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+                else
+                    (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+            }
+        }
+
+        session->search_object = st.slots[session->session.slotID - 1].objects;
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_FindObjectsInit");
+    return rv;
+}
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_DEFINE_FUNCTION(CK_RV, C_FindObjects)
+(
+ CK_SESSION_HANDLE    hSession,          /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject,          /* gets obj. handles */
+ CK_ULONG             ulMaxObjectCount,  /* max handles to get */
+ CK_ULONG_PTR         pulObjectCount     /* actual # returned */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    CK_ULONG j, objnum;
+    CK_BYTE match;
+
+    P11_LOG_START("C_FindObjects");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!phObject || !ulMaxObjectCount || !pulObjectCount)
+        rv= CKR_ARGUMENTS_BAD;
+    else
+    {
+        objnum = 0;
+
+        log_Log(LOG_LOW, "Find max object count: %lu", ulMaxObjectCount);
+        while ((objnum < ulMaxObjectCount) && session->search_object)
+        {
+            if (!session->search_object->sensitive || (slot->pin_state > 0))
+            {
+                match = 1;
+    
+                for (j = 0; j < session->search_attrib_count; j++)
+                {
+                    if (!object_MatchAttrib(&session->search_attrib[j], session->search_object))
+                    {
+                        match = 0;
+                        break;
+                    }
+                }
+    
+                if (match)
+                {
+                    log_Log(LOG_LOW, "Object matched: %lX", session->search_object);
+                    phObject[objnum] = (CK_OBJECT_HANDLE)session->search_object;
+                    objnum++;
+                }
+            }
+
+            session->search_object = session->search_object->next;
+        }
+
+        log_Log(LOG_LOW, "Matched %lu objects", objnum);
+        *pulObjectCount = objnum;
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_FindObjects");
+
+    return rv;
+}
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsFinal)
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+
+    P11_LOG_START("C_FindObjectsFinal");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else
+    {
+        session->search_object = 0x00;
+
+        if (session->search_attrib)
+        {
+            free(session->search_attrib);
+            session->search_attrib = 0x00;
+        }
+
+        session->search_attrib_count = 0x00;
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_FindObjectsFinal");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_parallel.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_parallel.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_parallel.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,66 @@
+/******************************************************************************
+** 
+**  $Id: p11_parallel.c,v 1.2 2003/02/13 20:06:39 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Parallel function management (deprecated)
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionStatus)
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_GetFunctionStatus");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_PARALLEL;
+    log_Log(LOG_MED, "Legacy function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetFunctionStatus");
+
+    return rv;
+}
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_DEFINE_FUNCTION(CK_RV, C_CancelFunction)
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_CancelFunction");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_PARALLEL;
+    log_Log(LOG_MED, "Legacy function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_CancelFunction");
+
+    return rv;
+}
+
+
+

Added: trunk/SmartCardServices/src/PKCS11/p11_random.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_random.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_random.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,64 @@
+/******************************************************************************
+** 
+**  $Id: p11_random.c,v 1.2 2003/02/13 20:06:39 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Random number generation
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_DEFINE_FUNCTION(CK_RV, C_SeedRandom)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pSeed,     /* the seed material */
+  CK_ULONG          ulSeedLen  /* length of seed material */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_SeedRandom");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SeedRandom");
+
+    return rv;
+}
+
+
+/* C_GenerateRandom generates random data. */
+CK_DEFINE_FUNCTION(CK_RV, C_GenerateRandom)
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_BYTE_PTR       RandomData,  /* receives the random data */
+  CK_ULONG          ulRandomLen  /* # of bytes to generate */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_GenerateRandom");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GenerateRandom");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_session.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_session.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_session.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,325 @@
+/******************************************************************************
+** 
+**  $Id: p11_session.c,v 1.2 2003/02/13 20:06:39 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Session management
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)
+(
+  CK_SLOT_ID            slotID,        /* the slot's ID */
+  CK_FLAGS              flags,         /* from CK_SESSION_INFO */
+  CK_VOID_PTR           pApplication,  /* passed to callback */
+  CK_NOTIFY             Notify,        /* callback function */
+  CK_SESSION_HANDLE_PTR phSession      /* gets session handle */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session;
+    CK_ULONG pin_state;
+
+    P11_LOG_START("C_OpenSession");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else if (!phSession)
+        rv = CKR_ARGUMENTS_BAD;
+    else
+    {
+        if (!(flags & CKF_RW_SESSION) && slot_CheckRWSOsession(slotID))
+            rv = CKR_SESSION_READ_WRITE_SO_EXISTS;
+        else if (CKR_ERROR(rv = slot_EstablishConnection(slotID)))
+            /* Return error */;
+        else if (CKR_ERROR(rv = session_AddSession(phSession)))
+            /* Return error */;
+        else
+        {
+            log_Log(LOG_LOW, "New session handle: %X", *phSession);
+            session = (P11_Session *)*phSession;
+            session->session.slotID = slotID;
+
+            pin_state = st.slots[slotID - 1].pin_state;
+
+            if (flags & CKF_RW_SESSION)
+            {
+                if (pin_state == 1)
+                    session->session.state = CKS_RW_USER_FUNCTIONS;
+                else if (pin_state == 2)
+                    session->session.state = CKS_RW_SO_FUNCTIONS;
+                else
+                    session->session.state = CKS_RW_PUBLIC_SESSION;
+            }
+            else
+            {
+                if (pin_state == 1)
+                    session->session.state = CKS_RO_USER_FUNCTIONS;
+                else if (pin_state == 2)
+                    session->session.state = CKS_RO_USER_FUNCTIONS;
+                else
+                    session->session.state = CKS_RO_PUBLIC_SESSION;
+            }
+
+            session->session.flags = flags;
+            session->session.ulDeviceError = 0x1F; /* Fixme: what is this used for? */
+            session->application = pApplication;
+            session->notify = Notify;
+        }
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_OpenSession");
+
+    return rv;
+}
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_DEFINE_FUNCTION(CK_RV, C_CloseSession)
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    CK_SLOT_ID slotID = session->session.slotID;
+
+    P11_LOG_START("C_CloseSession");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!CKR_ERROR(rv = session_FreeSession(hSession)))
+        rv = slot_ReleaseConnection(slotID);
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_CloseSession");
+
+    return rv;
+}
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_DEFINE_FUNCTION(CK_RV, C_CloseAllSessions)
+(
+  CK_SLOT_ID     slotID  /* the token's slot */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session_l;
+    P11_Session *session_l_temp;
+
+    P11_LOG_START("C_CloseAllSessions");
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else
+    {
+        session_l = st.sessions;
+
+        while (session_l)
+        {
+            session_l_temp = session_l->next;
+
+            if (session_l->session.slotID == slotID)
+                C_CloseSession((CK_SESSION_HANDLE)session_l); /* Fixme: ignore errors? */
+
+            session_l = session_l_temp;
+        }
+    }
+
+    P11_LOG_END("C_CloseAllSessions");
+
+    return rv;
+}
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetSessionInfo)
+(
+  CK_SESSION_HANDLE   hSession,  /* the session's handle */
+  CK_SESSION_INFO_PTR pInfo      /* receives session info */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+
+    P11_LOG_START("C_GetSessionInfo");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (!pInfo)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else
+    {
+        log_Log(LOG_LOW, "Session state: %lu", session->session.state);
+        memcpy(pInfo, &session->session, sizeof(CK_SESSION_INFO));
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetSessionInfo");
+
+    return rv;
+}
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetOperationState)
+(
+  CK_SESSION_HANDLE hSession,             /* session's handle */
+  CK_BYTE_PTR       pOperationState,      /* gets state */
+  CK_ULONG_PTR      pulOperationStateLen  /* gets state length */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_GetOperationState");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetOperationState");
+
+    return rv;
+}
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_DEFINE_FUNCTION(CK_RV, C_SetOperationState)
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR      pOperationState,      /* holds state */
+  CK_ULONG         ulOperationStateLen,  /* holds state length */
+  CK_OBJECT_HANDLE hEncryptionKey,       /* en/decryption key */
+  CK_OBJECT_HANDLE hAuthenticationKey    /* sign/verify key */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_SetOperationState");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SetOperationState");
+
+    return rv;
+}
+
+
+/* C_Login logs a user into a token. */
+CK_DEFINE_FUNCTION(CK_RV, C_Login)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_USER_TYPE      userType,  /* the user type */
+  CK_UTF8CHAR_PTR   pPin,      /* the user's PIN */
+  CK_ULONG          ulPinLen   /* the length of the PIN */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+
+    P11_LOG_START("C_Login");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (!pPin || !ulPinLen)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+    {
+        if (userType == CKU_SO)
+            log_Log(LOG_LOW, "Verifying SO PIN");
+        else if (userType == CKU_USER)
+            log_Log(LOG_LOW, "Verifying USER PIN");
+        else
+            log_Log(LOG_LOW, "Verifying Unknown user PIN: %lu", userType);
+
+        rv = slot_VerifyPIN(session->session.slotID, userType, pPin, ulPinLen);
+        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+
+        if (rv == CKR_OK)
+            slot_UserMode(session->session.slotID);
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_Login");
+
+    return rv;
+}
+
+
+/* C_Logout logs a user out from a token. */
+CK_DEFINE_FUNCTION(CK_RV, C_Logout)
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+
+    P11_LOG_START("C_Logout");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+    {
+        if (rv == CKR_OK)
+            slot_PublicMode(session->session.slotID);
+
+        memset(st.slots[session->session.slotID - 1].pins, 0x00, sizeof(st.slots[session->session.slotID - 1].pins));
+
+        if (MSC_ERROR(msc_LogoutAll(&st.slots[session->session.slotID - 1].conn)))
+            (void)CKR_ERROR(rv = slot_EndTransaction(session->session.slotID, MSC_RESET_TOKEN));
+        else
+            (void)CKR_ERROR(rv = slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_Logout");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_sign.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_sign.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_sign.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,296 @@
+/******************************************************************************
+** 
+**  $Id: p11_sign.c,v 1.2 2003/02/13 20:06:39 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Signing and MACing
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+#include <openssl/rsa.h>
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_SignInit)
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of signature key */
+)
+{
+    CK_RV rv = CKR_OK;
+    CK_OBJECT_HANDLE hObject = hKey; /* Needed for INVALID_OBJECT check */
+    P11_Session *session = (P11_Session *)hSession;
+
+    P11_LOG_START("C_SignInit");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pMechanism)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (INVALID_OBJECT)
+        rv = CKR_OBJECT_HANDLE_INVALID;
+    else if (!USER_MODE)
+        rv = CKR_USER_NOT_LOGGED_IN;
+    else
+    {
+        session->sign_mech = *pMechanism;
+        session->sign_key = hObject;
+
+        log_Log(LOG_LOW, "Sign object handle: 0x%lX", hObject);
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SignInit");
+
+    return rv;
+}
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_Sign)
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+)
+{
+    CK_RV rv = CKR_OK;
+    MSCCryptInit cryptInit;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Object *key = (P11_Object *)session->sign_key;
+    CK_BYTE *to = 0;
+    CK_ULONG tlen;
+
+    P11_LOG_START("C_Sign");
+
+    thread_MutexLock(st.async_lock);
+
+    log_Log(LOG_LOW, "Output buffer len: %lu", *pulSignatureLen);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!pData || !pSignature)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (!key)
+        rv = CKR_OPERATION_NOT_INITIALIZED;
+    else if (!USER_MODE)
+        rv = CKR_USER_NOT_LOGGED_IN;
+    else if ((CK_ULONG)(key->msc_key->keySize / 8) > *pulSignatureLen)
+    {
+        *pulSignatureLen = key->msc_key->keySize / 8;
+        rv = CKR_BUFFER_TOO_SMALL;
+    }
+    else if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+        /* Intentionally blank */;
+    else if (session->sign_mech.mechanism == CKM_RSA_PKCS)
+    {
+        MSCULong32  ulValue, lenValue;
+
+        if (MSC_ERROR(msc_GetCapabilities(&st.slots[session->session.slotID - 1].conn,
+                        MSC_TAG_CAPABLE_RSA,
+                        (CK_BYTE_PTR) &ulValue,
+                        &lenValue)))
+            rv = CKR_FUNCTION_FAILED;
+        else if (ulValue & MSC_CAPABLE_RSA_NOPAD)
+        {
+        cryptInit.keyNum = key->msc_key->keyNum;
+        cryptInit.cipherMode = MSC_MODE_RSA_NOPAD;
+        cryptInit.cipherDirection = MSC_DIR_SIGN;
+        cryptInit.optParams = 0;
+        cryptInit.optParamsSize = 0;
+
+        tlen = key->msc_key->keySize / 8;
+        to = (CK_BYTE *)malloc(tlen);
+
+            log_Log(LOG_LOW, "Pad and Sign object keyNum: %lu tlen: %lu", 
+                    key->msc_key->keyNum, tlen);
+
+        if (!to)
+            rv = CKR_HOST_MEMORY;
+        else if (!RSA_padding_add_PKCS1_type_1(to, tlen, pData, ulDataLen))
+            rv = CKR_FUNCTION_FAILED;
+
+            else
+			{
+				MSCULong32 outputDataSize = *pulSignatureLen;
+				if (MSC_ERROR(msc_ComputeCrypt(
+                            &st.slots[session->session.slotID - 1].conn,
+                                           &cryptInit,
+                                           to,
+                                           tlen,
+                                           pSignature,
+                                           &outputDataSize)))
+					rv = CKR_FUNCTION_FAILED;
+				*pulSignatureLen = outputDataSize;
+			}
+        }
+        else if (ulValue & MSC_CAPABLE_RSA_PKCS1)
+        {
+            cryptInit.keyNum = key->msc_key->keyNum;
+            cryptInit.cipherMode = MSC_MODE_RSA_PAD_PKCS1;
+            cryptInit.cipherDirection = MSC_DIR_SIGN;
+            cryptInit.optParams = 0;
+            cryptInit.optParamsSize = 0;
+
+            log_Log(LOG_LOW, "Sign object keyNum: %lu DataLen: %lu", 
+                    key->msc_key->keyNum, ulDataLen);
+
+			MSCULong32 outputDataSize = *pulSignatureLen;
+			if (MSC_ERROR(msc_ComputeCrypt(
+                            &st.slots[session->session.slotID - 1].conn,
+                            &cryptInit,
+                            pData,
+                            ulDataLen,
+                            pSignature,
+                            &outputDataSize)))
+                rv = CKR_FUNCTION_FAILED;
+			*pulSignatureLen = outputDataSize;
+        }
+        else
+            rv = CKR_MECHANISM_PARAM_INVALID;
+
+        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+    }
+    else
+    {
+        (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+        rv = CKR_MECHANISM_INVALID;
+    }
+
+    session->sign_key = 0;
+
+    if (to)
+        free(to);
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_Sign");
+
+    return rv;
+}
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_SignUpdate)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* the data to sign */
+  CK_ULONG          ulPartLen  /* count of bytes to sign */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_SignUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SignUpdate");
+
+    return rv;
+}
+
+
+/* C_SignFinal finishes a multiple-part signature operation, 
+ * returning the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_SignFinal)
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_SignFinal");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SignFinal");
+
+    return rv;
+}
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_SignRecoverInit)
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism, /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey        /* handle of the signature key */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_SignRecoverInit");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SignRecoverInit");
+
+    return rv;
+}
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_SignRecover)
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_SignRecover");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SignRecover");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_token.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_token.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_token.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,385 @@
+/******************************************************************************
+** 
+**  $Id: p11_token.c,v 1.2 2003/02/13 20:06:39 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Slot and token management
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)
+(
+  CK_BBOOL       tokenPresent,  /* only slots with tokens? */
+  CK_SLOT_ID_PTR pSlotList,     /* receives array of slot IDs */
+  CK_ULONG_PTR   pulCount       /* receives number of slots */
+)
+{
+    CK_RV rv = CKR_OK;
+    CK_RV token_rv;
+    CK_ULONG i, count = 0;
+
+    P11_LOG_START("C_GetSlotList");
+
+    thread_MutexLock(st.async_lock);
+
+    (void)CKR_ERROR(slot_TokenChanged());
+
+    if (!pulCount)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (!st.slots)
+    {
+        *pulCount = 0;
+        log_Log(LOG_LOW, "No active slots");
+    }
+    else if (!pSlotList && !tokenPresent)
+    {
+        *pulCount = st.slot_count;
+        log_Log(LOG_LOW, "Returning slot count: %ld", *pulCount);
+    }
+    else if ((*pulCount < st.slot_count) && !tokenPresent)
+        rv = CKR_BUFFER_TOO_SMALL;
+    else if (!tokenPresent)
+    {
+        *pulCount = st.slot_count;
+
+        for (i = 0; i < *pulCount; i++)
+        {
+             pSlotList[i] = i + 1;
+             log_Log(LOG_MED, "Found reader at slot: %ld", pSlotList[i]);
+        }
+    } 
+    else /* Look for readers with tokens present */
+    {
+        for (i = 1, count = 0; i <= st.slot_count; i++)
+        {
+            token_rv = slot_TokenPresent(i);
+            if ((token_rv == CKR_OK) || (token_rv == CKR_TOKEN_NOT_RECOGNIZED))
+            {
+                if (pSlotList)
+                    pSlotList[count] = i;
+
+                log_Log(LOG_MED, "Found reader with token at slot: %ld", i);
+                count++;
+            }
+        }
+
+        *pulCount = count;
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetSlotList");
+    return rv;
+}
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetSlotInfo)
+(
+  CK_SLOT_ID       slotID,  /* the ID of the slot */
+  CK_SLOT_INFO_PTR pInfo    /* receives the slot information */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_GetSlotInfo");
+
+    thread_MutexLock(st.async_lock);
+    log_Log(LOG_LOW, "Checking slot: %ld", slotID);
+
+    (void)CKR_ERROR(slot_TokenChanged());
+
+    if (!pInfo)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else
+    {
+        memcpy(pInfo, &st.slots[slotID - 1].slot_info, sizeof(CK_SLOT_INFO));
+        log_Log(LOG_LOW, "SlotInfo.flags: %lX", pInfo->flags);
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetSlotInfo");
+
+    return rv;
+}
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)
+(
+  CK_SLOT_ID        slotID,  /* ID of the token's slot */
+  CK_TOKEN_INFO_PTR pInfo    /* receives the token information */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_GetTokenInfo");
+
+    thread_MutexLock(st.async_lock);
+    log_Log(LOG_LOW, "Checking slot: %ld", slotID);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (!pInfo)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else
+        memcpy(pInfo, &st.slots[slotID - 1].token_info, sizeof(CK_TOKEN_INFO));
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetTokenInfo");
+
+    return rv;
+}
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismList)
+(
+  CK_SLOT_ID            slotID,          /* ID of token's slot */
+  CK_MECHANISM_TYPE_PTR pMechanismList,  /* gets mech. array */
+  CK_ULONG_PTR          pulCount         /* gets # of mechs. */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Slot *slot = &st.slots[slotID - 1];
+    P11_MechInfo *mech;
+    CK_ULONG i;
+
+    P11_LOG_START("C_GetMechanismList");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else if (!pMechanismList)
+    {
+        log_Log(LOG_LOW, "Returning count only");
+        *pulCount = slot_MechanismCount(slot->mechanisms);
+    }
+    else if (*pulCount < slot_MechanismCount(slot->mechanisms))
+        rv = CKR_BUFFER_TOO_SMALL;
+    else
+    {
+        mech = slot->mechanisms;
+
+        for (i = 0; mech; i++)
+        {
+            pMechanismList[i] = mech->type;
+            mech = mech->next;
+        }
+
+        *pulCount = i;
+    }
+    
+    log_Log(LOG_LOW, "Returning %lu mechanisms", *pulCount);
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetMechanismList");
+
+    return rv;
+}
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismInfo)
+(
+  CK_SLOT_ID            slotID,  /* ID of the token's slot */
+  CK_MECHANISM_TYPE     type,    /* type of mechanism */
+  CK_MECHANISM_INFO_PTR pInfo    /* receives mechanism info */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_MechInfo *mech;
+
+    P11_LOG_START("C_GetMechanismInfo");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else if (!pInfo)
+        rv = CKR_ARGUMENTS_BAD;
+    else
+    {
+        mech = st.slots[slotID - 1].mechanisms;
+
+        rv = CKR_MECHANISM_INVALID;
+
+        while (mech)
+        {
+            if (mech->type == type)
+            {
+                memcpy(pInfo, &mech->info, sizeof(CK_MECHANISM_INFO));
+                rv = CKR_OK;
+                break;
+            }
+
+            mech = mech->next;
+        }
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_GetMechanismInfo");
+
+    return rv;
+}
+
+
+/* C_InitToken initializes a token. */
+CK_DEFINE_FUNCTION(CK_RV, C_InitToken)
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+  CK_SLOT_ID      slotID,    /* ID of the token's slot */
+  CK_UTF8CHAR_PTR pPin,      /* the SO's initial PIN */
+  CK_ULONG        ulPinLen,  /* length in bytes of the PIN */
+  CK_UTF8CHAR_PTR pLabel     /* 32-byte token label (blank padded) */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_InitToken");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+    /* msc_WriteFramework() */
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_InitToken");
+
+    return rv;
+}
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_DEFINE_FUNCTION(CK_RV, C_InitPIN)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pPin,      /* the normal user's PIN */
+  CK_ULONG          ulPinLen   /* length in bytes of the PIN */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Slot *slot;
+    P11_Session *session;
+
+    P11_LOG_START("C_InitPIN");
+
+    thread_MutexLock(st.async_lock);
+
+//    if (CKR_ERROR(rv = slot_TokenChanged()))
+//        rv = CKR_DEVICE_REMOVED;
+//    else 
+    if (!pPin)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (READ_ONLY_SESSION)
+        rv = CKR_SESSION_READ_ONLY;
+    else
+    {
+        session = (P11_Session *)hSession;
+        slot = &st.slots[session->session.slotID - 1];
+
+        if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+            /* Return error */;
+        else if (MSC_ERROR(msc_CreatePIN(&slot->conn, 
+                                        (MSCUChar8)st.prefs.user_pin_num, 
+                                        (MSCUChar8)st.prefs.max_pin_tries, 
+                                        pPin, 
+                                        ulPinLen, 
+                                        (MSCUChar8 *)"PIN_UNBK", 8)))
+        {
+            (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+            rv = CKR_FUNCTION_FAILED;
+        }
+        else
+            rv = slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN);
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_InitPIN");
+
+    return rv;
+}
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pOldPin,   /* the old PIN */
+  CK_ULONG          ulOldLen,  /* length of the old PIN */
+  CK_UTF8CHAR_PTR   pNewPin,   /* the new PIN */
+  CK_ULONG          ulNewLen   /* length of the new PIN */
+)
+{
+    CK_RV rv = CKR_OK;
+    P11_Slot *slot;
+    P11_Session *session;
+
+    P11_LOG_START("C_SetPIN");
+
+    thread_MutexLock(st.async_lock);
+
+    if (CKR_ERROR(rv = slot_TokenChanged()))
+        rv = CKR_DEVICE_REMOVED;
+    else if (!pOldPin || !pNewPin)
+        rv = CKR_ARGUMENTS_BAD;
+    else if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else if (READ_ONLY_SESSION)
+        rv = CKR_SESSION_READ_ONLY;
+    else
+    {
+        session = (P11_Session *)hSession;
+        slot = &st.slots[session->session.slotID - 1];
+
+        if (CKR_ERROR(rv = slot_BeginTransaction(session->session.slotID)))
+            rv = rv;
+        else if (MSC_ERROR(msc_ChangePIN(&slot->conn,
+										 (MSCUChar8)st.prefs.user_pin_num,
+										 pOldPin,
+										 (CK_BYTE)ulOldLen,
+										 pNewPin,
+										 (CK_BYTE)ulNewLen)))
+        {
+            (void)CKR_ERROR(slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN));
+            rv = CKR_FUNCTION_FAILED;
+        }
+        else
+            rv = slot_EndTransaction(session->session.slotID, MSC_LEAVE_TOKEN);
+    }
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_SetPIN");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11_verify.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11_verify.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11_verify.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,176 @@
+/******************************************************************************
+** 
+**  $Id: p11_verify.c,v 1.2 2003/02/13 20:06:39 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Verifying signatures and MACs
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ *  cannot be recovered from the signature (e.g. DSA). */
+CK_DEFINE_FUNCTION(CK_RV, C_VerifyInit)
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */ 
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_VerifyInit");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_VerifyInit");
+
+    return rv;
+}
+
+
+/* C_Verify verifies a signature in a single-part operation, 
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_Verify)
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pData,          /* signed data */
+  CK_ULONG          ulDataLen,      /* length of signed data */
+  CK_BYTE_PTR       pSignature,     /* signature */
+  CK_ULONG          ulSignatureLen  /* signature length*/
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_Verify");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_Verify");
+
+    return rv;
+}
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_VerifyUpdate)
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* signed data */
+  CK_ULONG          ulPartLen  /* length of signed data */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_VerifyUpdate");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_VerifyUpdate");
+
+    return rv;
+}
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_VerifyFinal)
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pSignature,     /* signature to verify */
+  CK_ULONG          ulSignatureLen  /* signature length */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_VerifyFinal");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_VerifyFinal");
+
+    return rv;
+}
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecoverInit)
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_VerifyRecoverInit");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_VerifyRecoverInit");
+
+    return rv;
+}
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecover)
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* signature to verify */
+  CK_ULONG          ulSignatureLen,  /* signature length */
+  CK_BYTE_PTR       pData,           /* gets signed data */
+  CK_ULONG_PTR      pulDataLen       /* gets signed data len */
+)
+{
+    CK_RV rv = CKR_OK;
+
+    P11_LOG_START("C_VerifyRecover");
+
+    thread_MutexLock(st.async_lock);
+
+    rv = CKR_FUNCTION_NOT_SUPPORTED;
+    log_Log(LOG_MED, "Function not supported");
+
+    thread_MutexUnlock(st.async_lock);
+
+    P11_LOG_END("C_VerifyRecover");
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_async.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_async.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_async.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,143 @@
+/******************************************************************************
+** 
+**  $Id: p11x_async.c,v 1.2 2003/02/13 20:06:40 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Asynchronous functions (UNIX version)
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+#include <time.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
+/******************************************************************************
+** Function: async_StartSlotWatcher
+**
+** Starts a thread that watches all the slots in the system.
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_HOST_MEMORY on memory alloc error
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV async_StartSlotWatcher()
+{
+    CK_RV rv = CKR_OK;
+    CK_ULONG i;
+    MSCTokenInfo *tokenArray;
+
+    tokenArray = (MSCTokenInfo *)malloc(st.slot_count * sizeof(MSCTokenInfo));
+
+    if (!tokenArray)
+        return CKR_HOST_MEMORY;
+
+    for (i = 0; i < st.slot_count; i++)
+    {
+        memcpy(&tokenArray[i], &st.slots[i].conn.tokenInfo, sizeof(MSCTokenInfo));
+        tokenArray[i].tokenState = 0;
+    }
+
+    st.slot_status = (char *)malloc(st.slot_count);
+
+    if (!st.slot_status)
+        rv = CKR_HOST_MEMORY;
+    else
+    {
+        memset(st.slot_status, 0x01, st.slot_count);
+
+        if (st.prefs.threaded && st.create_threads)
+        {
+            if (MSC_ERROR(msc_CallbackForTokenEvent(tokenArray, 
+                                                   st.slot_count, 
+                                                   async_TokenEventCallback, 
+                                                   0)))
+            {
+                free(st.slot_status);
+                st.slot_status = 0;
+                rv = CKR_FUNCTION_FAILED;
+            }
+        }
+    }
+
+    if (tokenArray)
+        free(tokenArray);
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: async_StopSlotWatcher
+**
+** Stops the slot watching thread.
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV async_StopSlotWatcher()
+{
+    CK_RV rv = CKR_OK;
+
+    if (st.prefs.threaded && st.create_threads)
+        msc_CallbackCancelEvent();
+
+    if (st.slot_status)
+    {
+        free(st.slot_status);
+        st.slot_status = 0;    
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: async_TokenEventCallback
+**
+** Called for asynchronous token events.  Depending on the thread mode this
+** will either set a flag that will be picked up later by any call into the
+** P11 module, or if in fully threaded mode this will update all information
+** about the token in the callback thread.
+**
+** Parameters:
+**  tokenArray - Token status information
+**  arrayLen   - Number of items in tokenArray
+**  data       - Pointer to "data" that was set with MSCCallbackForTokenEvent
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+MSCULong32 async_TokenEventCallback(MSCTokenInfo *tokenArray, MSCULong32 arrayLen, void *data)
+{
+    CK_ULONG i;
+
+    for (i = 0; i < arrayLen; i++)
+    {
+        if (tokenArray[i].tokenState & MSC_STATE_CHANGED)
+        {
+            log_Log(LOG_LOW, "Async event on slot %ld: 0x%lX", i + 1, tokenArray[i].tokenState);
+            st.slot_status[i] = 0x01;
+        }
+    }
+
+    if (st.prefs.slot_watch_scheme == P11_SLOT_WATCH_THREAD_FULL)
+    {
+        thread_MutexLock(st.async_lock);
+        slot_TokenChanged();
+        thread_MutexUnlock(st.async_lock);
+    }
+
+    return MSC_SUCCESS;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_bio.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_bio.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_bio.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,11 @@
+/******************************************************************************
+** 
+**  $Id: p11x_bio.c,v 1.2 2003/02/13 20:06:40 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Chris Osgood
+**  Purpose: Biometric support functions to be used instead of a normal PIN.
+** 
+******************************************************************************/
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_error.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_error.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_error.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,403 @@
+/******************************************************************************
+** 
+**  $Id: p11x_error.c,v 1.2 2003/02/13 20:06:40 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Error handling
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/******************************************************************************
+** Function: error_LogCmd
+**
+** If there is an error then this logs it to the logfile as a stringified 
+** text message.
+**
+** Parameters:
+**  err         - CKR Error code
+**  cond        - Test condition that says whether or not this is an error
+**  file        - Filename where the error occured (__FILE__)
+**  line        - Line number of the error (__LINE__)
+**  stringifyFn - Function used to stringify the error code (err)
+**
+** Returns:
+**  The error code that was passed in
+*******************************************************************************/
+CK_RV error_LogCmd(CK_RV err, CK_RV cond, CK_CHAR *file, CK_LONG line, char *(*stringifyFn)(CK_RV))
+{
+    if (err != cond)
+        log_Log(LOG_MED, "(%s %ld): error: 0x%lX \"%s\"", file, line, err, stringifyFn(err));
+
+    return err;
+}
+
+/******************************************************************************
+** Function: error_Stringify
+**
+** Convert a CKR_XXX error code to text.
+**
+** Parameters:
+**  rv - Error code to convert
+**
+** Returns:
+**  A static string error message (make this const?)
+*******************************************************************************/
+char *error_Stringify(CK_RV rv)
+{
+    char *error;
+
+    switch(rv)
+    {
+    case CKR_OK:
+        error = "CKR_OK";
+        break;
+
+    case CKR_CANCEL:
+        error = "CKR_CANCEL";
+        break;
+
+    case CKR_HOST_MEMORY:
+        error = "CKR_HOST_MEMORY";
+        break;
+
+    case CKR_SLOT_ID_INVALID:
+        error = "CKR_SLOT_ID_INVALID";
+        break;
+
+    case CKR_GENERAL_ERROR:
+        error = "CKR_GENERAL_ERROR";
+        break;
+
+    case CKR_FUNCTION_FAILED:
+        error = "CKR_FUNCTION_FAILED";
+        break;
+
+    case CKR_ARGUMENTS_BAD:
+        error = "CKR_ARGUMENTS_BAD";
+        break;
+
+    case CKR_NO_EVENT:
+        error = "CKR_NO_EVENT";
+        break;
+
+    case CKR_NEED_TO_CREATE_THREADS:
+        error = "CKR_NEED_TO_CREATE_THREADS";
+        break;
+
+    case CKR_CANT_LOCK:
+        error = "CKR_CANT_LOCK";
+        break;
+
+    case CKR_ATTRIBUTE_READ_ONLY:
+        error = "CKR_ATTRIBUTE_READ_ONLY";
+        break;
+
+    case CKR_ATTRIBUTE_SENSITIVE:
+        error = "CKR_ATTRIBUTE_SENSITIVE";
+        break;
+
+    case CKR_ATTRIBUTE_TYPE_INVALID:
+        error = "CKR_ATTRIBUTE_TYPE_INVALID";
+        break;
+
+    case CKR_ATTRIBUTE_VALUE_INVALID:
+        error = "CKR_ATTRIBUTE_VALUE_INVALID";
+        break;
+
+    case CKR_DATA_INVALID:
+        error = "CKR_DATA_INVALID";
+        break;
+
+    case CKR_DATA_LEN_RANGE:
+        error = "CKR_DATA_LEN_RANGE";
+        break;
+
+    case CKR_DEVICE_ERROR:
+        error = "CKR_DEVICE_ERROR";
+        break;
+
+    case CKR_DEVICE_MEMORY:
+        error = "CKR_DEVICE_MEMORY";
+        break;
+
+    case CKR_DEVICE_REMOVED:
+        error = "CKR_DEVICE_REMOVED";
+        break;
+
+    case CKR_ENCRYPTED_DATA_INVALID:
+        error = "CKR_ENCRYPTED_DATA_INVALID";
+        break;
+
+    case CKR_ENCRYPTED_DATA_LEN_RANGE:
+        error = "CKR_ENCRYPTED_DATA_LEN_RANGE";
+        break;
+
+    case CKR_FUNCTION_CANCELED:
+        error = "CKR_FUNCTION_CANCELED";
+        break;
+
+    case CKR_FUNCTION_NOT_PARALLEL:
+        error = "CKR_FUNCTION_NOT_PARALLEL";
+        break;
+
+    case CKR_FUNCTION_NOT_SUPPORTED:
+        error = "CKR_FUNCTION_NOT_SUPPORTED";
+        break;
+
+    case CKR_KEY_HANDLE_INVALID:
+        error = "CKR_KEY_HANDLE_INVALID";
+        break;
+
+    case CKR_KEY_SIZE_RANGE:
+        error = "CKR_KEY_SIZE_RANGE";
+        break;
+
+    case CKR_KEY_TYPE_INCONSISTENT:
+        error = "CKR_KEY_TYPE_INCONSISTENT";
+        break;
+
+    case CKR_KEY_NOT_NEEDED:
+        error = "CKR_KEY_NOT_NEEDED";
+        break;
+
+    case CKR_KEY_CHANGED:
+        error = "CKR_KEY_CHANGED";
+        break;
+
+    case CKR_KEY_NEEDED:
+        error = "CKR_KEY_NEEDED";
+        break;
+
+    case CKR_KEY_INDIGESTIBLE:
+        error = "CKR_KEY_INDIGESTIBLE";
+        break;
+
+    case CKR_KEY_FUNCTION_NOT_PERMITTED:
+        error = "CKR_KEY_FUNCTION_NOT_PERMITTED";
+        break;
+
+    case CKR_KEY_NOT_WRAPPABLE:
+        error = "CKR_KEY_NOT_WRAPPABLE";
+        break;
+
+    case CKR_KEY_UNEXTRACTABLE:
+        error = "CKR_KEY_UNEXTRACTABLE";
+        break;
+
+    case CKR_MECHANISM_INVALID:
+        error = "CKR_MECHANISM_INVALID";
+        break;
+
+    case CKR_MECHANISM_PARAM_INVALID:
+        error = "CKR_MECHANISM_PARAM_INVALID";
+        break;
+
+    case CKR_OBJECT_HANDLE_INVALID:
+        error = "CKR_OBJECT_HANDLE_INVALID";
+        break;
+
+    case CKR_OPERATION_ACTIVE:
+        error = "CKR_OPERATION_ACTIVE";
+        break;
+
+    case CKR_OPERATION_NOT_INITIALIZED:
+        error = "CKR_OPERATION_NOT_INITIALIZED";
+        break;
+
+    case CKR_PIN_INCORRECT:
+        error = "CKR_PIN_INCORRECT";
+        break;
+
+    case CKR_PIN_INVALID:
+        error = "CKR_PIN_INVALID";
+        break;
+
+    case CKR_PIN_LEN_RANGE:
+        error = "CKR_PIN_LEN_RANGE";
+        break;
+
+    case CKR_PIN_EXPIRED:
+        error = "CKR_PIN_EXPIRED";
+        break;
+
+    case CKR_PIN_LOCKED:
+        error = "CKR_PIN_LOCKED";
+        break;
+
+    case CKR_SESSION_CLOSED:
+        error = "CKR_SESSION_CLOSED";
+        break;
+
+    case CKR_SESSION_COUNT:
+        error = "CKR_SESSION_COUNT";
+        break;
+
+    case CKR_SESSION_HANDLE_INVALID:
+        error = "CKR_SESSION_HANDLE_INVALID";
+        break;
+
+    case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
+        error = "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
+        break;
+
+    case CKR_SESSION_READ_ONLY:
+        error = "CKR_SESSION_READ_ONLY";
+        break;
+
+    case CKR_SESSION_EXISTS:
+        error = "CKR_SESSION_EXISTS";
+        break;
+
+    case CKR_SESSION_READ_ONLY_EXISTS:
+        error = "CKR_SESSION_READ_ONLY_EXISTS";
+        break;
+
+    case CKR_SESSION_READ_WRITE_SO_EXISTS:
+        error = "CKR_SESSION_READ_WRITE_SO_EXISTS";
+        break;
+
+    case CKR_SIGNATURE_INVALID:
+        error = "CKR_SIGNATURE_INVALID";
+        break;
+
+    case CKR_SIGNATURE_LEN_RANGE:
+        error = "CKR_SIGNATURE_LEN_RANGE";
+        break;
+
+    case CKR_TEMPLATE_INCOMPLETE:
+        error = "CKR_TEMPLATE_INCOMPLETE";
+        break;
+
+    case CKR_TEMPLATE_INCONSISTENT:
+        error = "CKR_TEMPLATE_INCONSISTENT";
+        break;
+
+    case CKR_TOKEN_NOT_PRESENT:
+        error = "CKR_TOKEN_NOT_PRESENT";
+        break;
+
+    case CKR_TOKEN_NOT_RECOGNIZED:
+        error = "CKR_TOKEN_NOT_RECOGNIZED";
+        break;
+
+    case CKR_TOKEN_WRITE_PROTECTED:
+        error = "CKR_TOKEN_WRITE_PROTECTED";
+        break;
+
+    case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
+        error = "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
+        break;
+
+    case CKR_UNWRAPPING_KEY_SIZE_RANGE:
+        error = "CKR_UNWRAPPING_KEY_SIZE_RANGE";
+        break;
+
+    case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
+        error = "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
+        break;
+
+    case CKR_USER_ALREADY_LOGGED_IN:
+        error = "CKR_USER_ALREADY_LOGGED_IN";
+        break;
+
+    case CKR_USER_NOT_LOGGED_IN:
+        error = "CKR_USER_NOT_LOGGED_IN";
+        break;
+
+    case CKR_USER_PIN_NOT_INITIALIZED:
+        error = "CKR_USER_PIN_NOT_INITIALIZED";
+        break;
+
+    case CKR_USER_TYPE_INVALID:
+        error = "CKR_USER_TYPE_INVALID";
+        break;
+
+    case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
+        error = "CKR_USER_ANOTHER_ALREADY_LOGGED_IN";
+        break;
+
+    case CKR_USER_TOO_MANY_TYPES:
+        error = "CKR_USER_TOO_MANY_TYPES";
+        break;
+
+    case CKR_WRAPPED_KEY_INVALID:
+        error = "CKR_WRAPPED_KEY_INVALID";
+        break;
+
+    case CKR_WRAPPED_KEY_LEN_RANGE:
+        error = "CKR_WRAPPED_KEY_LEN_RANGE";
+        break;
+
+    case CKR_WRAPPING_KEY_HANDLE_INVALID:
+        error = "CKR_WRAPPING_KEY_HANDLE_INVALID";
+        break;
+
+    case CKR_WRAPPING_KEY_SIZE_RANGE:
+        error = "CKR_WRAPPING_KEY_SIZE_RANGE";
+        break;
+
+    case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
+        error = "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
+        break;
+
+    case CKR_RANDOM_SEED_NOT_SUPPORTED:
+        error = "CKR_RANDOM_SEED_NOT_SUPPORTED";
+        break;
+
+    case CKR_RANDOM_NO_RNG:
+        error = "CKR_RANDOM_NO_RNG";
+        break;
+
+    case CKR_DOMAIN_PARAMS_INVALID:
+        error = "CKR_DOMAIN_PARAMS_INVALID";
+        break;
+
+    case CKR_BUFFER_TOO_SMALL:
+        error = "CKR_BUFFER_TOO_SMALL";
+        break;
+
+    case CKR_SAVED_STATE_INVALID:
+        error = "CKR_SAVED_STATE_INVALID";
+        break;
+
+    case CKR_INFORMATION_SENSITIVE:
+        error = "CKR_INFORMATION_SENSITIVE";
+        break;
+
+    case CKR_STATE_UNSAVEABLE:
+        error = "CKR_STATE_UNSAVEABLE";
+        break;
+
+    case CKR_CRYPTOKI_NOT_INITIALIZED:
+        error = "CKR_CRYPTOKI_NOT_INITIALIZED";
+        break;
+
+    case CKR_CRYPTOKI_ALREADY_INITIALIZED:
+        error = "CKR_CRYPTOKI_ALREADY_INITIALIZED";
+        break;
+
+    case CKR_MUTEX_BAD:
+        error = "CKR_MUTEX_BAD";
+        break;
+
+    case CKR_MUTEX_NOT_LOCKED:
+        error = "CKR_MUTEX_NOT_LOCKED";
+        break;
+
+    case CKR_VENDOR_DEFINED:
+        error = "CKR_VENDOR_DEFINED";
+        break;
+
+    default:
+        error = "Unknown CKR error";
+        break;
+    }
+
+    return error;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_log.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_log.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_log.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,144 @@
+/******************************************************************************
+** 
+**  $Id: p11x_log.c,v 1.2 2003/02/13 20:06:40 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Logging functions
+** 
+******************************************************************************/
+
+#include <stdio.h>
+#include <assert.h>
+#include <time.h>
+#include <stdarg.h>
+#include "cryptoki.h"
+
+#ifdef SYS_LOG
+#include <syslog.h>
+#endif
+
+/******************************************************************************
+** Function: log_Start
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+void log_Start(char *func)
+{
+    log_Log(LOG_LOW, "+%s : start", func);
+}
+
+/******************************************************************************
+** Function: log_End
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+void log_End(char *func, CK_RV rv)
+{
+    if (CKR_ERROR(rv));
+    log_Log(LOG_LOW, " -%s : end RV(0x%lX)", func, rv);
+}
+
+/******************************************************************************
+** Function: log_Err
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+void log_Err(char *msg, char *file, CK_LONG line)
+{
+    log_Log(LOG_MED, "Error (%s %ld): %s", file, line, msg);
+}
+
+/******************************************************************************
+** Function: log_Log
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+void log_Log(CK_ULONG level, char *msg, ...)
+{
+    va_list args;
+
+#ifdef SYS_LOG
+    thread_MutexLock(st.log_lock);
+
+    if (st.prefs.log_level > level)
+        return;
+
+    va_start(args, msg);
+    vsyslog(0, msg, args);
+    va_end(args);
+#else // SYS_LOG
+    FILE *fp;
+    time_t t;
+    struct tm *time_s;
+    char format[256];
+
+    if (st.prefs.log_level > level)
+        return;
+
+    thread_MutexLock(st.log_lock);
+
+    fp = fopen((char *)st.prefs.log_filename, "ab");
+
+    if (!fp)    
+    {
+        fp = stderr;
+        fprintf(fp, "Error, could not open: %s\n", st.prefs.log_filename);
+    }
+
+    time(&t);
+    time_s = localtime(&t);
+
+    sprintf(format, "%.2d/%.2d %.2d:%.2d:%.2d %s", 
+                    time_s->tm_mday, 
+                    time_s->tm_mon+1, 
+                    time_s->tm_hour, 
+                    time_s->tm_min, 
+                    time_s->tm_sec, 
+                    msg);
+
+    va_start(args, msg);
+    vfprintf(fp, format, args);
+    va_end(args);
+    
+#ifdef WIN32
+    fputs("\r\n", fp);
+#else
+    fputs("\n", fp);
+#endif // WIN32
+
+    fflush(fp); /* Fixme: more accurate, but slows logging */
+
+    if (fp != stderr)
+      fclose(fp);
+
+#endif // SYS_LOG
+
+    thread_MutexUnlock(st.log_lock);
+}

Added: trunk/SmartCardServices/src/PKCS11/p11x_msc.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_msc.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_msc.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,715 @@
+/******************************************************************************
+** 
+**  $Id: p11x_msc.c,v 1.2 2003/02/13 20:06:40 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: MSC wrappers.  This whole module does practically nothing other
+**           than proxy calls to the MSC libraries.  This is mostly just to
+**           provide a layer of protection in case the MSC API changes.
+**           msc_ComputeCrypt does handle some cached PIN stuff.
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+MSC_RV msc_ListTokens(
+  MSCULong32            listScope,        /* defines the scope to return */
+  MSCLPTokenInfo        tokenArray,       /* token struct array          */
+  MSCPULong32           arrayLength       /* Length of array             */
+)
+{
+    MSC_RV rv;
+
+    rv = MSCListTokens(
+      listScope,
+      tokenArray,
+      arrayLength
+    );
+
+    return rv;
+}
+
+    /* Establishes a connection to the specified token */
+MSC_RV msc_EstablishConnection( 
+  MSCLPTokenInfo        tokenStruct,       /* The struct of token   */
+  MSCULong32            sharingMode,       /* Mode of sharing       */
+  MSCPUChar8            applicationName,   /* The applet ID/Name    */
+  MSCULong32            nameSize,          /* The ID/Name Size      */
+  MSCLPTokenConnection  pConnection        /* Returned connection   */
+)
+{
+    MSC_RV rv;
+
+    rv = MSCEstablishConnection( 
+      tokenStruct,
+      sharingMode,
+      applicationName,
+      nameSize,
+      pConnection
+    );
+
+    return rv;
+}
+
+    /* Releases a connection to the specified token */
+MSC_RV msc_ReleaseConnection( 
+  MSCLPTokenConnection  pConnection,       /* Connection handle     */
+  MSCULong32            endAction          /* Action to perform     */
+)
+{
+    MSC_RV rv;
+
+    rv = MSCReleaseConnection( 
+      pConnection,
+      endAction
+    );
+
+    return rv;
+}
+
+    /* Blocks for an event to occur on a token */
+MSC_RV msc_WaitForTokenEvent( 
+  MSCLPTokenInfo        tokenArray,        /* Array of token structs */
+  MSCULong32            arraySize,	   /* Size of the array      */
+  MSCULong32            timeoutValue       /* Timeout                */
+)
+{
+    MSC_RV rv;
+
+    rv = MSCWaitForTokenEvent( 
+      tokenArray,
+      arraySize,
+      timeoutValue
+    );
+
+    return rv;
+}
+
+    /* Cancels a pending MSCWaitForTokenEvent */
+MSC_RV msc_CancelEventWait( 
+  void                                     /* No parameters          */
+)
+{
+    MSC_RV rv;
+
+    rv = MSCCancelEventWait();
+
+    return rv;
+}
+
+    /* Registers a callback function for event change */
+MSC_RV msc_CallbackForTokenEvent(
+  MSCLPTokenInfo        tokenArray,        /* Array of token structs */
+  MSCULong32            arraySize,         /* Size of the array      */
+  MSCCallBack           callBack,          /* Callback function      */
+  MSCPVoid32            appData            /* Application data       */
+)
+{
+    MSC_RV rv = SCARD_E_UNSUPPORTED_FEATURE;
+#if 0
+    rv = MSCCallbackForTokenEvent(
+      tokenArray,
+      arraySize,
+      callBack,
+      appData
+    );
+#endif
+    return rv;
+}
+
+    /* Cancels all callback registrations */
+MSC_RV msc_CallbackCancelEvent()
+{
+    MSC_RV rv = SCARD_E_UNSUPPORTED_FEATURE;
+#if 0
+    rv = MSCCallbackCancelEvent();
+#endif
+    return rv;
+}
+
+    /* Locks a transaction to the token */
+MSC_RV msc_BeginTransaction(
+  MSCLPTokenConnection  pConnection       /* Connection handle          */
+)
+{
+    MSC_RV rv;
+
+    rv = MSCBeginTransaction(
+      pConnection
+    );			       
+
+    return rv;
+}
+
+    /* Releases a locked transaction to the token */
+MSC_RV msc_EndTransaction(
+  MSCLPTokenConnection  pConnection,      /* Connection handle          */
+  MSCULong32            endAction         /* Action to perform on token */
+)
+{
+    MSC_RV rv;
+
+    rv = MSCEndTransaction(
+      pConnection,
+      endAction
+    );
+
+    return rv;
+}
+
+    /* Pre-personalization function */
+MSC_RV msc_WriteFramework( 
+  MSCLPTokenConnection  pConnection, 
+  MSCLPInitTokenParams  pInitParams 
+)
+{
+    MSC_RV rv;
+
+    rv = MSCWriteFramework( 
+      pConnection, 
+      pInitParams 
+    );
+
+    return rv;
+}
+
+MSC_RV msc_GetStatus(
+  MSCLPTokenConnection  pConnection, 
+  MSCLPStatusInfo       pStatusInfo
+)
+{
+    MSC_RV rv;
+
+    rv = MSCGetStatus(
+      pConnection, 
+      pStatusInfo
+    );
+
+    return rv;
+}
+
+MSC_RV msc_GetCapabilities(
+  MSCLPTokenConnection  pConnection,
+  MSCULong32            Tag,
+  MSCPUChar8            Value,
+  MSCPULong32           Length
+)
+{
+    MSC_RV rv;
+
+    rv = MSCGetCapabilities(
+      pConnection,
+      Tag,
+      Value,
+      Length
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ExtendedFeature( 
+  MSCLPTokenConnection  pConnection, 
+  MSCULong32            extFeature,
+  MSCPUChar8            outData, 
+  MSCULong32            outLength, 
+  MSCPUChar8            inData,
+  MSCPULong32           inLength 
+)
+{
+    MSC_RV rv;
+
+    rv = MSCExtendedFeature( 
+      pConnection, 
+      extFeature,
+      outData, 
+      outLength, 
+      inData,
+      inLength 
+    );
+
+    return rv;
+}
+
+MSC_RV msc_GenerateKeys(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		prvKeyNum,
+  MSCUChar8		pubKeyNum,
+  MSCLPGenKeyParams	pParams
+)
+{
+    MSC_RV rv;
+
+    rv = MSCGenerateKeys(
+      pConnection,
+      prvKeyNum,
+      pubKeyNum,
+      pParams
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ImportKey(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		keyNum,
+  MSCLPKeyACL		pKeyACL,
+  MSCPUChar8	        pKeyBlob,
+  MSCULong32            keyBlobSize,
+  MSCLPKeyPolicy        keyPolicy,
+  MSCPVoid32		pAddParams,
+  MSCUChar8		addParamsSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCImportKey(
+      pConnection,
+      keyNum,
+      pKeyACL,
+      pKeyBlob,
+      keyBlobSize,
+      keyPolicy,
+      pAddParams,
+      addParamsSize
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ExportKey(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		keyNum,
+  MSCPUChar8	        pKeyBlob,
+  MSCPULong32           keyBlobSize,
+  MSCPVoid32		pAddParams,
+  MSCUChar8		addParamsSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCExportKey(
+      pConnection,
+      keyNum,
+      pKeyBlob,
+      keyBlobSize,
+      pAddParams,
+      addParamsSize
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ComputeCrypt( 
+  MSCLPTokenConnection  pConnection,
+  MSCLPCryptInit        cryptInit, 
+  MSCPUChar8            pInputData,
+  MSCULong32            inputDataSize, 
+  MSCPUChar8            pOutputData,
+  MSCPULong32           outputDataSize
+)
+{
+    MSC_RV rv = MSC_SUCCESS;
+    CK_ULONG i;
+
+    /* Handles cached PIN's */
+    for (i = 0; i < 2; i++)
+    {
+        rv = MSCComputeCrypt( 
+          pConnection,
+          cryptInit, 
+          pInputData,
+          inputDataSize, 
+          pOutputData,
+          outputDataSize
+        );
+    
+        if (rv != MSC_SUCCESS)
+        {
+            if (CKR_ERROR(slot_ReverifyPins()))
+                break;
+        }
+        else
+            break;
+    }
+
+    return rv;
+}
+
+MSC_RV msc_ExtAuthenticate(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8	        keyNum,
+  MSCUChar8             cipherMode, 
+  MSCUChar8             cipherDirection,
+  MSCPUChar8	        pData,
+  MSCULong32	        dataSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCExtAuthenticate(
+      pConnection,
+      keyNum,
+      cipherMode, 
+      cipherDirection,
+      pData,
+      dataSize
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ListKeys(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		seqOption,
+  MSCLPKeyInfo		pKeyInfo
+)
+{
+    MSC_RV rv;
+
+    rv = MSCListKeys(
+      pConnection,
+      seqOption,
+      pKeyInfo
+    );
+
+    return rv;
+}
+
+MSC_RV msc_CreatePIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCUChar8		pinAttempts,
+  MSCPUChar8	        pPinCode,
+  MSCULong32		pinCodeSize,
+  MSCPUChar8	        pUnblockCode,
+  MSCUChar8		unblockCodeSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCCreatePIN(
+      pConnection,
+      pinNum,
+      pinAttempts,
+      pPinCode,
+      pinCodeSize,
+      pUnblockCode,
+      unblockCodeSize
+    );
+
+    return rv;
+}
+
+MSC_RV msc_VerifyPIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pPinCode,
+  MSCULong32		pinCodeSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCVerifyPIN(
+      pConnection,
+      pinNum,
+      pPinCode,
+      pinCodeSize
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ChangePIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pOldPinCode,
+  MSCUChar8		oldPinCodeSize,
+  MSCPUChar8	        pNewPinCode,
+  MSCUChar8		newPinCodeSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCChangePIN(
+      pConnection,
+      pinNum,
+      pOldPinCode,
+      oldPinCodeSize,
+      pNewPinCode,
+      newPinCodeSize
+    );
+
+    return rv;
+}
+
+MSC_RV msc_UnblockPIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pUnblockCode,
+  MSCULong32		unblockCodeSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCUnblockPIN(
+      pConnection,
+      pinNum,
+      pUnblockCode,
+      unblockCodeSize
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ListPINs(
+  MSCLPTokenConnection	pConnection,
+  MSCPUShort16	        pPinBitMask
+)
+{
+    MSC_RV rv;
+
+    rv = MSCListPINs(
+      pConnection,
+      pPinBitMask
+    );
+
+    return rv;
+}
+
+MSC_RV msc_CreateObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 	        objectID,
+  MSCULong32		objectSize,
+  MSCLPObjectACL	pObjectACL
+)
+{
+    MSC_RV rv;
+
+    rv = MSCCreateObject(
+      pConnection,
+      objectID,
+      objectSize,
+      pObjectACL
+    );
+
+    return rv;
+}
+
+MSC_RV msc_DeleteObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString  		objectID,
+  MSCUChar8		zeroFlag
+)
+{
+    MSC_RV rv;
+
+    rv = MSCDeleteObject(
+      pConnection,
+      objectID,
+      zeroFlag
+    );
+
+    return rv;
+}
+
+MSC_RV msc_WriteObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 		objectID,
+  MSCULong32		offset,
+  MSCPUChar8        pInputData,
+  MSCULong32		dataSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCWriteObject(
+      pConnection,
+      objectID,
+      offset,
+      pInputData,
+      dataSize,
+      0, /* Fixme: rwCallback */
+      0 /* Fixme: addParams */
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ReadObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 		objectID,
+  MSCULong32		offset,
+  MSCPUChar8	        pOutputData,
+  MSCULong32		dataSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCReadObject(
+      pConnection,
+      objectID,
+      offset,
+      pOutputData,
+      dataSize,
+      0, /* Fixme: rwCallback */
+      0 /* Fixme: addParams */
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ListObjects(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		seqOption,
+  MSCLPObjectInfo	pObjectInfo
+)
+{
+    MSC_RV rv;
+
+    rv = MSCListObjects(
+      pConnection,
+      seqOption,
+      pObjectInfo
+    );
+
+    return rv;
+}
+
+MSC_RV msc_LogoutAll(
+  MSCLPTokenConnection	pConnection
+)
+{
+    MSC_RV rv;
+
+    rv = MSCLogoutAll(
+      pConnection
+    );
+
+    return rv;
+}
+
+MSC_RV msc_GetChallenge(
+  MSCLPTokenConnection	pConnection,
+  MSCPUChar8	        pSeed,
+  MSCUShort16	        seedSize,
+  MSCPUChar8	        pRandomData,
+  MSCUShort16	        randomDataSize
+)
+{
+    MSC_RV rv;
+
+    rv = MSCGetChallenge(
+      pConnection,
+      pSeed,
+      seedSize,
+      pRandomData,
+      randomDataSize
+    );
+
+    return rv;
+}
+
+MSC_RV msc_GetKeyAttributes( 
+  MSCLPTokenConnection  pConnection, 
+  MSCUChar8             keyNumber,
+  MSCLPKeyInfo          pKeyInfo 
+)
+{
+    MSC_RV rv;
+
+    rv = MSCGetKeyAttributes( 
+      pConnection, 
+      keyNumber,
+      pKeyInfo 
+    );
+
+    return rv;
+}
+
+MSC_RV msc_GetObjectAttributes( 
+  MSCLPTokenConnection  pConnection, 
+  MSCString             objectID,
+  MSCLPObjectInfo       pObjectInfo 
+)
+{
+    MSC_RV rv;
+
+    rv = MSCGetObjectAttributes( 
+      pConnection, 
+      objectID,
+      pObjectInfo 
+    );
+
+    return rv;
+}
+
+MSC_RV msc_ReadAllocateObject( 
+  MSCLPTokenConnection  pConnection, 
+  MSCString             objectID,
+  MSCPUChar8*           pOutputData, 
+  MSCPULong32           dataSize 
+)
+{
+    MSC_RV rv;
+
+    rv = MSCReadAllocateObject( 
+      pConnection, 
+      objectID,
+      pOutputData, 
+      dataSize,
+      0, /* Fixme: rwCallback */
+      0 /* Fixme: addParams */
+    );
+
+    return rv;
+}
+
+
+MSCUChar8 msc_IsTokenReset(MSCLPTokenConnection pConnection)
+{
+    MSCUChar8 rv;
+
+    rv = MSCIsTokenReset(pConnection);
+
+    return rv;
+}
+
+MSCUChar8 msc_ClearReset(MSCLPTokenConnection pConnection)
+{
+    MSCUChar8 rv;
+
+    rv = MSCClearReset(pConnection);
+
+    return rv;
+}
+
+MSCUChar8 msc_IsTokenMoved(MSCLPTokenConnection pConnection)
+{
+    MSCUChar8 rv;
+
+    rv = MSCIsTokenMoved(pConnection);
+
+    return rv;
+}
+
+MSCUChar8 msc_IsTokenChanged(MSCLPTokenConnection pConnection)
+{
+    MSCUChar8 rv;
+
+    rv = MSCIsTokenChanged(pConnection);
+
+    return rv;
+}
+
+MSCUChar8 msc_IsTokenKnown(MSCLPTokenConnection pConnection)
+{
+    MSCUChar8 rv;
+
+    rv = MSCIsTokenKnown(pConnection);
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_msc.h
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_msc.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_msc.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,262 @@
+/******************************************************************************
+** 
+**  $Id: p11x_msc.h,v 1.2 2003/02/13 20:06:41 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: MSC wrappers
+** 
+******************************************************************************/
+
+
+MSC_RV msc_ListTokens(
+  MSCULong32            listScope,        /* defines the scope to return */
+  MSCLPTokenInfo        tokenArray,       /* token struct array          */
+  MSCPULong32           arrayLength       /* Length of array             */
+);
+
+MSC_RV msc_EstablishConnection( 
+  MSCLPTokenInfo        tokenStruct,       /* The struct of token   */
+  MSCULong32            sharingMode,       /* Mode of sharing       */
+  MSCPUChar8            applicationName,   /* The applet ID/Name    */
+  MSCULong32            nameSize,          /* The ID/Name Size      */
+  MSCLPTokenConnection  pConnection        /* Returned connection   */
+);
+
+MSC_RV msc_ReleaseConnection( 
+  MSCLPTokenConnection  pConnection,       /* Connection handle     */
+  MSCULong32            endAction          /* Action to perform     */
+);
+
+MSC_RV msc_WaitForTokenEvent( 
+  MSCLPTokenInfo        tokenArray,        /* Array of token structs */
+  MSCULong32            arraySize,	   /* Size of the array      */
+  MSCULong32            timeoutValue       /* Timeout                */
+);
+
+MSC_RV msc_CancelEventWait( 
+  void                                     /* No parameters          */
+);
+
+MSC_RV msc_CallbackForTokenEvent(
+  MSCLPTokenInfo        tokenArray,        /* Array of token structs */
+  MSCULong32            arraySize,         /* Size of the array      */
+  MSCCallBack           callBack,          /* Callback function      */
+  MSCPVoid32            appData            /* Application data       */
+);
+
+MSC_RV msc_CallbackCancelEvent();
+
+MSC_RV msc_BeginTransaction(
+  MSCLPTokenConnection  pConnection       /* Connection handle          */
+);
+
+MSC_RV msc_EndTransaction(
+  MSCLPTokenConnection  pConnection,      /* Connection handle          */
+  MSCULong32            endAction         /* Action to perform on token */
+);
+
+MSC_RV msc_WriteFramework( 
+  MSCLPTokenConnection  pConnection, 
+  MSCLPInitTokenParams  pInitParams 
+);
+
+MSC_RV msc_GetStatus(
+  MSCLPTokenConnection  pConnection, 
+  MSCLPStatusInfo       pStatusInfo
+);
+
+MSC_RV msc_GetCapabilities(
+  MSCLPTokenConnection  pConnection,
+  MSCULong32            Tag,
+  MSCPUChar8            Value,
+  MSCPULong32           Length
+);
+
+MSC_RV msc_ExtendedFeature( 
+  MSCLPTokenConnection  pConnection, 
+  MSCULong32            extFeature,
+  MSCPUChar8            outData, 
+  MSCULong32            outLength, 
+  MSCPUChar8            inData,
+  MSCPULong32           inLength 
+);
+
+MSC_RV msc_GenerateKeys(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		prvKeyNum,
+  MSCUChar8		pubKeyNum,
+  MSCLPGenKeyParams	pParams
+);
+
+MSC_RV msc_ImportKey(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		keyNum,
+  MSCLPKeyACL		pKeyACL,
+  MSCPUChar8	        pKeyBlob,
+  MSCULong32            keyBlobSize,
+  MSCLPKeyPolicy        keyPolicy,
+  MSCPVoid32		pAddParams,
+  MSCUChar8		addParamsSize
+);
+
+MSC_RV msc_ExportKey(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		keyNum,
+  MSCPUChar8	        pKeyBlob,
+  MSCPULong32           keyBlobSize,
+  MSCPVoid32		pAddParams,
+  MSCUChar8		addParamsSize
+);
+
+MSC_RV msc_ComputeCrypt( 
+  MSCLPTokenConnection  pConnection,
+  MSCLPCryptInit        cryptInit, 
+  MSCPUChar8            pInputData,
+  MSCULong32            inputDataSize, 
+  MSCPUChar8            pOutputData,
+  MSCPULong32           outputDataSize
+);
+
+
+MSC_RV msc_ExtAuthenticate(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8	        keyNum,
+  MSCUChar8             cipherMode, 
+  MSCUChar8             cipherDirection,
+  MSCPUChar8	        pData,
+  MSCULong32	        dataSize
+);
+
+
+MSC_RV msc_ListKeys(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		seqOption,
+  MSCLPKeyInfo		pKeyInfo
+);
+
+MSC_RV msc_CreatePIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCUChar8		pinAttempts,
+  MSCPUChar8	        pPinCode,
+  MSCULong32		pinCodeSize,
+  MSCPUChar8	        pUnblockCode,
+  MSCUChar8		unblockCodeSize
+);
+
+
+MSC_RV msc_VerifyPIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pPinCode,
+  MSCULong32		pinCodeSize
+);
+
+
+MSC_RV msc_ChangePIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pOldPinCode,
+  MSCUChar8		oldPinCodeSize,
+  MSCPUChar8	        pNewPinCode,
+  MSCUChar8		newPinCodeSize
+);
+
+
+MSC_RV msc_UnblockPIN(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		pinNum,
+  MSCPUChar8	        pUnblockCode,
+  MSCULong32		unblockCodeSize
+);
+
+
+MSC_RV msc_ListPINs(
+  MSCLPTokenConnection	pConnection,
+  MSCPUShort16	        pPinBitMask
+);
+
+
+MSC_RV msc_CreateObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 	        objectID,
+  MSCULong32		objectSize,
+  MSCLPObjectACL	pObjectACL
+);
+
+
+MSC_RV msc_DeleteObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString  		objectID,
+  MSCUChar8		zeroFlag
+);
+
+
+MSC_RV msc_WriteObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 		objectID,
+  MSCULong32		offset,
+  MSCPUChar8	        pInputData,
+  MSCULong32		dataSize
+);
+
+
+MSC_RV msc_ReadObject(
+  MSCLPTokenConnection	pConnection,
+  MSCString 		objectID,
+  MSCULong32		offset,
+  MSCPUChar8	        pOutputData,
+  MSCULong32		dataSize
+);
+
+
+MSC_RV msc_ListObjects(
+  MSCLPTokenConnection	pConnection,
+  MSCUChar8		seqOption,
+  MSCLPObjectInfo	pObjectInfo
+);
+
+
+MSC_RV msc_LogoutAll(
+  MSCLPTokenConnection	pConnection
+);
+
+
+MSC_RV msc_GetChallenge(
+  MSCLPTokenConnection	pConnection,
+  MSCPUChar8	        pSeed,
+  MSCUShort16	        seedSize,
+  MSCPUChar8	        pRandomData,
+  MSCUShort16	        randomDataSize
+);
+
+
+MSC_RV msc_GetKeyAttributes( 
+  MSCLPTokenConnection  pConnection, 
+  MSCUChar8             keyNumber,
+  MSCLPKeyInfo          pKeyInfo 
+);
+
+
+MSC_RV msc_GetObjectAttributes( 
+  MSCLPTokenConnection  pConnection, 
+  MSCString             objectID,
+  MSCLPObjectInfo       pObjectInfo 
+);
+
+
+MSC_RV msc_ReadAllocateObject( 
+  MSCLPTokenConnection  pConnection, 
+  MSCString             objectID,
+  MSCPUChar8*           pOutputData, 
+  MSCPULong32           dataSize 
+);
+
+MSCUChar8 msc_IsTokenReset(MSCLPTokenConnection pConnection);
+MSCUChar8 msc_ClearReset(MSCLPTokenConnection pConnection);
+MSCUChar8 msc_IsTokenMoved(MSCLPTokenConnection pConnection);
+MSCUChar8 msc_IsTokenChanged(MSCLPTokenConnection pConnection);
+MSCUChar8 msc_IsTokenKnown(MSCLPTokenConnection pConnection);

Added: trunk/SmartCardServices/src/PKCS11/p11x_object.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_object.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_object.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,2336 @@
+/******************************************************************************
+** 
+**  $Id: p11x_object.c,v 1.3 2004/10/14 20:33:36 mb Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Session & object management functions
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+#include <openssl/x509.h>
+
+/******************************************************************************
+** Function: object_FreeAllObjects
+**
+** Recursively releases all objects from the given slot.
+**
+** Parameters:
+**  slotID - Slot number to release
+**  list   - Object to free (used for recursion)
+**
+** Returns:
+**  none
+*******************************************************************************/
+void object_FreeAllObjects(CK_SLOT_ID slotID, P11_Object *list)
+{
+    if (list)
+    {
+        if (list->next) 
+            object_FreeAllObjects(slotID, list->next);
+        
+        object_FreeObject(slotID, list);
+    }
+}
+
+/******************************************************************************
+** Function: object_FreeObject
+**
+** Deletes/frees a specific object from a specific slot.  The slot ID is needed
+** because it contains the list of all objects.
+**
+** Parameters:
+**  slotID - Slot number that object relates to
+**  object - Pointer to object to free
+**
+** Returns:
+**  none
+*******************************************************************************/
+void object_FreeObject(CK_SLOT_ID slotID, P11_Object *object)
+{
+    slotID--;
+
+    if (object)
+    {
+        log_Log(LOG_LOW, "Removing object: %lX", object);
+
+        if (object->prev)
+        {
+            object->prev->next = object->next;
+
+            if (st.slots[slotID].objects == object)
+                st.slots[slotID].objects = object->prev;
+        }
+
+        if (object->next)
+        {
+            object->next->prev = object->prev;
+
+            if (st.slots[slotID].objects == object)
+                st.slots[slotID].objects = object->next;
+        }
+
+        if (!object->prev && !object->next)
+            st.slots[slotID].objects = 0x00;
+
+        if (object->msc_obj)
+            free(object->msc_obj);
+
+        if (object->msc_key)
+            free(object->msc_key);
+
+        object_FreeAllAttributes(object->attrib);
+
+        memset(object, 0x00, sizeof(P11_Object));
+
+        free(object);
+    }
+}
+
+/******************************************************************************
+** Function: object_FreeAllAttributes
+**
+** Deletes/frees all attributes relating to a specific object
+**
+** Parameters:
+**  list - attribute to free (used for recursion)
+**
+** Returns:
+**  none
+*******************************************************************************/
+void object_FreeAllAttributes(P11_Attrib *list)
+{
+    if (list)
+    {
+        log_Log(LOG_LOW, "Removing attribute: %lX", list);
+
+        if (list->next) 
+            object_FreeAllAttributes(list->next);
+
+        if (list->attrib.pValue)
+            free(list->attrib.pValue);
+
+        memset(list, 0x00, sizeof(P11_Attrib));
+
+        free(list);
+    }
+}
+
+/******************************************************************************
+** Function: object_AddObject
+**
+** Adds an object to specified slot
+**
+** Parameters:
+**  slotID   - Slot number to add object to
+**  phObject - Return handle new object
+**
+** Returns:
+**  CKR_HOST_MEMORY on memory alloc error
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_AddObject(CK_SLOT_ID slotID, CK_OBJECT_HANDLE *phObject)
+{
+    CK_RV rv = CKR_OK;
+
+    *phObject = 0;
+    slotID--;
+
+    if (st.slots[slotID].objects)
+    {
+        if (st.prefs.obj_sort_order == P11_OBJ_SORT_NEWEST_LAST)
+        {
+            P11_Object *object_l;
+
+            object_l = st.slots[slotID].objects;
+            while(object_l->next)
+                object_l = object_l->next;
+    
+            object_l->next = (P11_Object *)calloc(1, sizeof(P11_Object));
+    
+            if (!object_l->next)
+                rv = CKR_HOST_MEMORY;
+            else
+            {
+                object_l->next->prev = object_l;
+                object_l->next->check = object_l->next;
+                *phObject = (CK_OBJECT_HANDLE)object_l->next;
+            }
+        }
+        else
+        {
+            st.slots[slotID].objects->prev = (P11_Object *)calloc(1, sizeof(P11_Object));
+            if (!st.slots[slotID].objects->prev)
+                rv = CKR_HOST_MEMORY;
+            else
+            {
+                st.slots[slotID].objects->prev->next = st.slots[slotID].objects;
+                st.slots[slotID].objects = st.slots[slotID].objects->prev;
+                st.slots[slotID].objects->check = st.slots[slotID].objects;
+                *phObject = (CK_OBJECT_HANDLE)st.slots[slotID].objects;
+            }
+        }
+    }
+    else
+    {
+        st.slots[slotID].objects = (P11_Object *)calloc(1, sizeof(P11_Object));
+        if (!st.slots[slotID].objects)
+            rv = CKR_HOST_MEMORY;
+        else
+        {
+            st.slots[slotID].objects->check = st.slots[slotID].objects;
+            *phObject = (CK_OBJECT_HANDLE)st.slots[slotID].objects;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_UpdateKeyInfo
+**
+** Add a new token keyinfo to this session's object list.  Creates a new
+** object if neccessary, otherwise updates the existing object.
+**
+** Parameters:
+**  hSession - Session handle
+**  hObject  - Returns new or existing object handle
+**  pKeyInfo - Sets the object's msc_key property to this
+**
+** Returns:
+**  CKR_HOST_MEMORY on memory alloc error
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_UpdateKeyInfo(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *hObject, MSCKeyInfo *pKeyInfo)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Object *object_l, *new_obj;
+
+    if (!pKeyInfo)
+    {
+        new_obj = (P11_Object *)*hObject;
+        pKeyInfo = new_obj->msc_key;
+    }
+    else
+    {
+        object_l = st.slots[session->session.slotID - 1].objects;
+        while (object_l)
+        {
+            if (object_l->msc_key && (object_l->msc_key->keyNum == pKeyInfo->keyNum))
+            {
+                log_Log(LOG_LOW, "Found existing key num: %lu", pKeyInfo->keyNum);
+                memcpy(object_l->msc_key, pKeyInfo, sizeof(MSCKeyInfo));
+                if (hObject) *hObject = (CK_OBJECT_HANDLE)object_l;
+                return rv;
+            }
+    
+            object_l = object_l->next;
+        }
+        
+        if (!CKR_ERROR(rv = object_AddObject(session->session.slotID, (CK_OBJECT_HANDLE *)&new_obj)))
+        {
+            log_Log(LOG_LOW, "New key handle: %X", new_obj);
+            new_obj->msc_key = (MSCKeyInfo *)calloc(1, sizeof(MSCKeyInfo));
+            if (!new_obj->msc_key)
+                rv = CKR_HOST_MEMORY;
+            else
+            {
+                memcpy(new_obj->msc_key, pKeyInfo, sizeof(MSCKeyInfo));
+                if (hObject) *hObject = (CK_OBJECT_HANDLE)new_obj;
+            }
+        }
+    }
+
+    if (!CKR_ERROR(rv))
+    {
+        CK_BYTE key_obj_id[3] = "k ";
+
+        key_obj_id[1] = pKeyInfo->keyNum > 9 ? 65 + pKeyInfo->keyNum : 48 + pKeyInfo->keyNum;  /* Vinnie 1749 A-F (55-65) */
+
+        object_FreeAllAttributes(new_obj->attrib);
+        new_obj->attrib = 0;
+
+        (void)CKR_ERROR(rv = object_ReadAttributes(hSession, key_obj_id, new_obj));
+    }
+
+    P11_ERR("Done UpdateKeyInfo");
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_UpdateObjectInfo
+**
+** Add a new token objectinfo to this session's object list.  Creates a new
+** object if neccessary, otherwise updates the existing object.
+**
+** If the object is a certificate then this function does some extra work
+** to make sure the public/private match up and have all the attributes they
+** need.
+**
+** Parameters:
+**  hSession    - Session handle
+**  pObjectInfo - Returns new or existing object handle
+**
+** Returns:
+**  CKR_HOST_MEMORY on memory alloc error
+**  CKR_FUNCTION_FAILED on general error (could be failed MSC call)
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_UpdateObjectInfo(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *hObject, MSCObjectInfo *pObjectInfo)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    P11_Object *object_l, *new_obj;
+    P11_Attrib *attrib, *modulus, *cka_id, *pub_exp;
+    CK_ATTRIBUTE ck_attrib;
+    CK_OBJECT_CLASS obj_class;
+    CK_BYTE t_obj_id[MSC_MAXSIZE_OBJID];
+    CK_BYTE *data;
+
+    if (!pObjectInfo)
+    {
+        new_obj = (P11_Object *)*hObject;
+        pObjectInfo = new_obj->msc_obj;
+    }
+    else
+    {
+        object_l = slot->objects;
+        while (object_l)
+        {
+            /* Fixme: object ID's are always strings?! */
+            if (object_l->msc_obj && (!strncmp(object_l->msc_obj->objectID, pObjectInfo->objectID, MSC_MAXSIZE_OBJID)))
+            {
+                log_Log(LOG_LOW, "Found existing object ID: %.*s", MSC_MAXSIZE_OBJID, pObjectInfo->objectID);
+                memcpy(object_l->msc_obj, pObjectInfo, sizeof(MSCObjectInfo));
+                if (hObject) *hObject = (CK_OBJECT_HANDLE)object_l;
+                return rv;
+            }
+    
+            object_l = object_l->next;
+        }
+        
+        if (!CKR_ERROR(rv = object_AddObject(session->session.slotID, (CK_OBJECT_HANDLE *)&new_obj)))
+        {
+            log_Log(LOG_LOW, "New object handle: %X", new_obj);
+            new_obj->msc_obj = (MSCObjectInfo *)calloc(1, sizeof(MSCObjectInfo));
+            if (!new_obj->msc_obj)
+                rv = CKR_HOST_MEMORY;
+            else
+            {
+                memcpy(new_obj->msc_obj, pObjectInfo, sizeof(MSCObjectInfo));
+                if (hObject) *hObject = (CK_OBJECT_HANDLE)new_obj;
+            }
+        }
+    }
+
+    if (!CKR_ERROR(rv))
+    {
+        object_FreeAllAttributes(new_obj->attrib);
+        new_obj->attrib = 0;
+
+        data = (CK_BYTE *)malloc(pObjectInfo->objectSize);
+
+        if (!data)
+            rv = CKR_HOST_MEMORY;
+        else if (MSC_ERROR(msc_ReadObject(&slot->conn, 
+                                     pObjectInfo->objectID,
+                                     0, 
+                                     data, 
+                                     pObjectInfo->objectSize)))
+            rv = CKR_FUNCTION_FAILED;
+        else
+            (void)CKR_ERROR(rv = object_AddAttribute(new_obj, CKA_VALUE, FALSE, data, pObjectInfo->objectSize, &attrib));
+
+        if (data)
+            free(data);
+
+        strncpy((char *)t_obj_id, pObjectInfo->objectID, sizeof(t_obj_id));
+        t_obj_id[0] = tolower(t_obj_id[0]);
+
+        if (!CKR_ERROR(rv = object_ReadAttributes(hSession, t_obj_id, new_obj)))
+        {
+            rv = object_InferClassAttributes(hSession, new_obj);
+        }
+
+        obj_class = CKO_CERTIFICATE;
+        ck_attrib.type = CKA_CLASS;
+        ck_attrib.pValue = &obj_class;
+        ck_attrib.ulValueLen = 4;
+
+        if (object_MatchAttrib(&ck_attrib, new_obj))
+        {
+            if (!CKR_ERROR_NOLOG(object_GetAttrib(CKA_MODULUS, new_obj, &modulus)) &&
+                !CKR_ERROR_NOLOG(object_GetAttrib(CKA_PUBLIC_EXPONENT, new_obj, &pub_exp)) &&
+                !CKR_ERROR_NOLOG(object_GetAttrib(CKA_ID, new_obj, &cka_id)))
+            {
+                obj_class = CKO_PUBLIC_KEY;
+    
+                object_l = slot->objects;
+                while (object_l)
+                {
+                    if (object_MatchAttrib(&cka_id->attrib, object_l) &&
+                        object_MatchAttrib(&ck_attrib, object_l))
+                    {
+                        log_Log(LOG_LOW, "Found existing public key key match.");
+                        break;
+                    }
+    
+                    object_l = object_l->next;
+                }
+
+                /* object_l will be null if we didn't find an existing public key */
+                if (!object_l &&
+                    !CKR_ERROR(rv = object_AddObject(session->session.slotID, (CK_OBJECT_HANDLE *)&object_l)))
+                {
+                    log_Log(LOG_LOW, "Added non-token public key object");
+
+                    obj_class = CKO_PUBLIC_KEY;
+                    (void)CKR_ERROR(object_AddAttribute(object_l,
+                                           CKA_CLASS,
+                                           FALSE,
+                                           (CK_BYTE *)ck_attrib.pValue,
+                                           ck_attrib.ulValueLen, 0));
+
+                    (void)CKR_ERROR(object_AddAttribute(object_l,
+                                           CKA_MODULUS,
+                                           FALSE,
+                                           (CK_BYTE *)modulus->attrib.pValue,
+                                           modulus->attrib.ulValueLen, 0));
+        
+                    (void)CKR_ERROR(object_AddAttribute(object_l,
+                                           CKA_PUBLIC_EXPONENT,
+                                           FALSE,
+                                           (CK_BYTE *)pub_exp->attrib.pValue,
+                                           pub_exp->attrib.ulValueLen, 0));
+
+                    (void)CKR_ERROR(object_AddAttribute(object_l,
+                                           CKA_ID,
+                                           FALSE,
+                                           (CK_BYTE *)cka_id->attrib.pValue,
+                                           cka_id->attrib.ulValueLen, 0));
+                }
+            }
+        }
+
+        /* Fixme: move this up into the previous if's code block? */
+        obj_class = CKO_CERTIFICATE;
+        ck_attrib.type = CKA_CLASS;
+        ck_attrib.pValue = &obj_class;
+        ck_attrib.ulValueLen = 4;
+
+        if (object_MatchAttrib(&ck_attrib, new_obj))
+        {
+            if (!CKR_ERROR_NOLOG(object_GetAttrib(CKA_MODULUS, new_obj, &modulus)))
+            {
+                if (!CKR_ERROR_NOLOG(object_GetAttrib(CKA_ID, new_obj, &cka_id)))
+                {
+                    obj_class = CKO_PRIVATE_KEY;
+
+                    object_l = slot->objects;
+                    while (object_l)
+                    {
+                        if (object_MatchAttrib(&cka_id->attrib, object_l) &&
+                            object_MatchAttrib(&ck_attrib, object_l))
+                        {
+                            log_Log(LOG_LOW, "Found private key match.  Added modulus to key.");
+                            (void)CKR_ERROR(object_AddAttribute(object_l,
+                                                                CKA_MODULUS, 
+                                                                FALSE, 
+                                                                (CK_BYTE *)modulus->attrib.pValue,
+                                                                modulus->attrib.ulValueLen, 0));
+                            break;
+                        }
+
+                        object_l = object_l->next;
+                    }
+                }
+            }
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_FreeTokenObjects
+**
+** This only deletes/frees objects that are token objects (objects stored on
+** the token).
+**
+** Fixme: This function is not used?
+**
+** Parameters:
+**  slotID - Slot number to free objects on
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_FreeTokenObjects(CK_SLOT_ID slotID)
+{
+    CK_RV rv = CKR_OK;
+    P11_Object *object_l;
+
+    object_l = st.slots[slotID - 1].objects;
+
+    while (object_l)
+    {
+        if (object_l->msc_obj || object_l->msc_key)
+            object_FreeObject(slotID, object_l);
+
+        object_l = st.slots[slotID - 1].objects;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_GetAttrib
+**
+** Gets an attribute from an object
+**
+** Parameters:
+**  type   - Attribute type to get (like CKA_ID)
+**  object - Object to search for attribute
+**  attrib - Returns the found attribute 
+**
+** Returns:
+**  CKR_ATTRIBUTE_TYPE_INVALID if attribute was not found
+**  CKR_OK if attribute was found
+*******************************************************************************/
+CK_RV object_GetAttrib(CK_ATTRIBUTE_TYPE type, P11_Object *object, P11_Attrib **attrib)
+{
+    CK_RV rv = CKR_ATTRIBUTE_TYPE_INVALID;
+    P11_Attrib *attrib_l;
+
+    attrib_l = object->attrib;
+    while (attrib_l)
+    {
+        if (type == attrib_l->attrib.type)
+        {
+            rv = CKR_OK;
+            if (attrib)
+                *attrib = attrib_l;
+            break;
+        }
+
+        attrib_l = attrib_l->next;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_SetAttrib
+**
+** Set an attribute on an object (or adds a new one if it doesn't exist).
+** This function is the same as object_AddAttribute.
+**
+** Fixme: this function is not used?
+**
+** Parameters:
+**  object - Object to add attribute to
+**  attrib - Attribute to add
+**
+** Returns:
+**  Error from object_AddAttribute
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_SetAttrib(P11_Object *object, CK_ATTRIBUTE *attrib)
+{
+    CK_RV rv = CKR_OK;
+    P11_Attrib *attrib_new;
+
+    (void)CKR_ERROR(rv = object_AddAttribute(object, 
+                                             attrib->type, 
+                                             TRUE,
+                                             (CK_BYTE *)attrib->pValue, 
+                                             attrib->ulValueLen, 
+                                             &attrib_new));
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_AddAttribute
+**
+** Adds a new attribute to an object or replaces an existing attribute if it
+** already exists.
+**
+** Parameters:
+**  object    - Object to add attribute to
+**  type      - Attribute type (CKA_ID, etc.)
+**  token     - TRUE/FALSE stating whether this attribute will be stored on the
+**              token
+**  value     - Value of attribute (pValue)
+**  value_len - Length of value (ulValueLen)
+**  attrib    - Pointer to new attribute object
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV object_AddAttribute(P11_Object *object, CK_ATTRIBUTE_TYPE type, CK_BBOOL token, CK_BYTE *value, CK_ULONG value_len, P11_Attrib **attrib)
+{
+    CK_RV rv = CKR_OK;
+    P11_Attrib *t_attrib = 0;
+
+    if (object->attrib)
+    {
+        if (object_GetAttrib(type, object, &t_attrib) != CKR_OK)
+        {
+            t_attrib = (P11_Attrib *)calloc(1, sizeof(P11_Attrib));
+
+            if (!t_attrib)
+                rv = CKR_HOST_MEMORY;
+            else
+            {
+                object->attrib->prev = t_attrib;
+                t_attrib->next = object->attrib;
+                object->attrib = t_attrib;
+            }
+        }
+    }
+    else
+    {
+        t_attrib = (P11_Attrib *)calloc(1, sizeof(P11_Attrib));
+
+        if (!t_attrib)
+            rv = CKR_HOST_MEMORY;
+        else
+            object->attrib = t_attrib;
+    }
+
+    if (t_attrib)
+    {
+        if (t_attrib->attrib.pValue)
+            free(t_attrib->attrib.pValue);
+
+        t_attrib->token = token;
+        t_attrib->attrib.type = type;
+        t_attrib->attrib.ulValueLen = value_len;
+
+        if (value_len)
+            t_attrib->attrib.pValue = calloc(1, value_len);
+        else
+            t_attrib->attrib.pValue = 0;
+
+        if (value_len && !t_attrib->attrib.pValue)
+            rv = CKR_HOST_MEMORY; // Fixme: returns error, but has already added the attribute
+        else if (value)
+            memcpy(t_attrib->attrib.pValue, value, value_len);
+    }
+
+    if (attrib)
+        *attrib = t_attrib;
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_AddBoolAttribute
+**
+** Shortcut to add a simple true/false bool attribute to an object.
+**
+** Fixme: do the parameters need to be fixed? "object" should come first
+**
+** Parameters:
+**  type   - Attribute type (CKA_ID, etc.)
+**  value  - True or false
+**  object - Object to add attribute to
+**
+** Returns:
+**  Error from object_AddAttribute
+**  CKR_OK;
+*******************************************************************************/
+CK_RV object_AddBoolAttribute(CK_ATTRIBUTE_TYPE type, CK_BBOOL value, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    P11_Attrib *attrib;
+
+    /* Fixme: all bool attributes are stored on the token? */
+    (void)CKR_ERROR(rv = object_AddAttribute(object, type, TRUE, (CK_BYTE *)&value, sizeof(CK_BBOOL), &attrib));
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_MatchAttrib
+**
+** Finds an attribute (by value) of an object
+**
+** Parameters:
+**  attrib - Attrib to match
+**  object - Object to use
+**
+** Returns:
+**  CKR_HOST_MEMORY on memory alloc error
+**  True/False if attribute matched or not
+*******************************************************************************/
+CK_RV object_MatchAttrib(CK_ATTRIBUTE *attrib, P11_Object *object)
+{
+    CK_RV rv;
+    P11_Attrib *obj_attrib;
+    CK_BYTE *reverse, *forward, temp;
+    CK_ULONG i;
+
+    object_LogAttribute(attrib);
+
+    reverse = (CK_BYTE *)malloc(attrib->ulValueLen);
+
+    if (!reverse)
+        rv = CKR_HOST_MEMORY;
+    else
+    {
+        forward = (CK_BYTE *)attrib->pValue;
+
+        memcpy(reverse, forward, attrib->ulValueLen);
+
+        for (i = 0; i < (CK_ULONG)(attrib->ulValueLen / 2); i++)
+        {
+            temp = reverse[i];
+            reverse[i] = reverse[attrib->ulValueLen - i - 1];
+            reverse[attrib->ulValueLen - i - 1] = temp;
+        }
+
+        log_Log(LOG_LOW, "Match attribute type: 0x%lX", attrib->type);
+
+        if (!CKR_ERROR(rv = object_GetAttrib(attrib->type, object, &obj_attrib)) &&
+            (!memcmp(forward, obj_attrib->attrib.pValue, attrib->ulValueLen) ||
+             !memcmp(reverse, obj_attrib->attrib.pValue, attrib->ulValueLen)))
+        {
+            rv = 1;
+        }
+        else
+        {
+            { CK_BYTE buf[4096]; 
+              object_BinToHex((CK_BYTE *)forward, attrib->ulValueLen, buf); 
+              log_Log(LOG_LOW, "Orig:%s", buf);
+              object_BinToHex((CK_BYTE *)reverse, attrib->ulValueLen, buf); 
+              log_Log(LOG_LOW, " Rev:%s", buf);
+    
+              if (rv == CKR_OK)
+                { object_BinToHex((CK_BYTE *)obj_attrib->attrib.pValue, obj_attrib->attrib.ulValueLen, buf); 
+                  log_Log(LOG_LOW, " Obj:%s", buf); } }
+    
+            rv = 0;
+        }
+
+        free(reverse);
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_TemplateGetAttrib
+**
+** Finds an attribute inside a template attribute list.  This works with
+** CK_ATTRIBUTE instead of a P11_Attrib and does not match by value, only
+** attribute type.
+**
+** Parameters:
+**  type         - Attribute type (CKA_ID, etc.)
+**  attrib       - Attribute list
+**  attrib_count - Number of elements in attribute list
+**  attrib_out   - Returns matched attribute
+**
+** Returns:
+**  CKR_ATTRIBUTE_TYPE_INVALID if attribute was not found
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_TemplateGetAttrib(CK_ATTRIBUTE_TYPE type, 
+                               CK_ATTRIBUTE *attrib, 
+                               CK_ULONG attrib_count, 
+                               CK_ATTRIBUTE **attrib_out)
+{
+    CK_RV rv = CKR_ATTRIBUTE_TYPE_INVALID;
+    CK_ULONG i;
+
+    for (i = 0; i < attrib_count; i++)
+    {
+        if (attrib[i].type == type)
+        {
+            if (attrib_out)
+                *attrib_out = &attrib[i];
+
+            rv = CKR_OK;
+            break;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_RSAGenKeyPair
+**
+** Generates an RSA key pair on the token
+**
+** Parameters:
+**  hSession - Session handle
+**  pPublicKeyTemplate - Public key template
+**  ulPublicKeyAttributeCount - Public key template attribute count
+**  pPrivateKeyTemplate - Private key template
+**  ulPrivateKeyAttributeCount - Private key template attribute count
+**  phPublicKey - Pointer to new public key object
+**  phPrivateKey - Pointer to new private key object
+**
+** Returns:
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_RSAGenKeyPair(CK_SESSION_HANDLE hSession,
+                           CK_ATTRIBUTE *pPublicKeyTemplate,
+                           CK_ULONG ulPublicKeyAttributeCount,
+                           CK_ATTRIBUTE *pPrivateKeyTemplate,
+                           CK_ULONG ulPrivateKeyAttributeCount,
+                           CK_OBJECT_HANDLE *phPublicKey,
+                           CK_OBJECT_HANDLE *phPrivateKey)
+{
+    CK_RV rv = CKR_OK;
+    MSC_RV msc_rv;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    P11_Object *objectPub;
+    P11_Object *objectPrv;
+    CK_ATTRIBUTE *attrib;
+    P11_Attrib *p11_attrib;
+    MSCKeyInfo keyInfo;
+    MSCKeyInfo keyInfoPub;
+    MSCKeyInfo keyInfoPrv;
+    CK_BYTE keyNum = 0;
+    CK_ULONG keySize = 0;
+    MSCGenKeyParams params;
+
+    (void)CKR_ERROR(object_TemplateGetAttrib(CKA_MODULUS_BITS, 
+                                             pPublicKeyTemplate, 
+                                             ulPublicKeyAttributeCount, 
+                                             &attrib));
+    memcpy(&keySize, attrib->pValue, attrib->ulValueLen);
+
+    msc_rv = msc_ListKeys(&slot->conn, MSC_SEQUENCE_RESET, &keyInfo);
+    if (!MSC_ERROR(msc_rv))
+        keyNum = keyInfo.keyNum + 1;
+    while (!MSC_ERROR(msc_rv) && !CKR_ERROR(rv))
+    {
+        msc_rv = msc_ListKeys(&slot->conn, MSC_SEQUENCE_NEXT, &keyInfo);
+
+        if (!MSC_ERROR(msc_rv))
+            keyNum = keyInfo.keyNum + 1;
+    }
+
+    log_Log(LOG_LOW, "KeySize: %lu", keySize);
+    log_Log(LOG_LOW, "KeyNum: %lu", keyNum);
+
+    /* Fixme: check capabilities for CRT */
+
+    params.algoType = MSC_GEN_ALG_RSA_CRT;
+    params.keySize = (MSCUShort16)keySize;
+    params.privateKeyACL.readPermission = MSC_AUT_NONE;
+    params.privateKeyACL.writePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+    params.privateKeyACL.usePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+    params.publicKeyACL.readPermission = MSC_AUT_ALL;
+    params.publicKeyACL.writePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+    params.publicKeyACL.usePermission = MSC_AUT_ALL;
+    params.privateKeyPolicy.cipherDirection = MSC_KEYPOLICY_DIR_SIGN | MSC_KEYPOLICY_DIR_DECRYPT;
+    params.privateKeyPolicy.cipherMode = MSC_KEYPOLICY_MODE_RSA_NOPAD;
+    params.publicKeyPolicy.cipherDirection = MSC_KEYPOLICY_DIR_VERIFY | MSC_KEYPOLICY_DIR_ENCRYPT;
+    params.publicKeyPolicy.cipherMode = MSC_KEYPOLICY_MODE_RSA_NOPAD;
+    params.keyGenOptions = MSC_OPT_DEFAULT;
+    params.pOptParams = 0;
+    params.optParamsSize = 0;
+
+    if (MSC_ERROR(msc_GenerateKeys(&slot->conn, keyNum, (MSCUChar8)(keyNum + 1), &params)))
+        rv = CKR_FUNCTION_FAILED;
+    else
+    {
+
+        (void)MSC_ERROR(msc_GetKeyAttributes(&slot->conn, (MSCUChar8)(keyNum + 1), &keyInfoPub));
+        (void)MSC_ERROR(msc_GetKeyAttributes(&slot->conn, keyNum, &keyInfoPrv));
+
+        log_Log(LOG_LOW, "keyNums: %lu and %lu", keyNum, keyNum + 1);
+
+        (void)CKR_ERROR(object_UpdateKeyInfo(hSession, (CK_OBJECT_HANDLE *)&objectPub, &keyInfoPub));
+        (void)CKR_ERROR(object_UpdateKeyInfo(hSession, (CK_OBJECT_HANDLE *)&objectPrv, &keyInfoPrv));
+
+        *phPublicKey = (CK_OBJECT_HANDLE)objectPub;
+        *phPrivateKey = (CK_OBJECT_HANDLE)objectPrv;
+
+        (void)CKR_ERROR(object_GetAttrib(CKA_MODULUS, objectPub, &p11_attrib));
+        (void)CKR_ERROR(object_AddAttribute(objectPrv,
+                                            p11_attrib->attrib.type,
+                                            TRUE, /* Fixme: Always a token attribute? */
+                                            (CK_BYTE *)p11_attrib->attrib.pValue,
+                                            p11_attrib->attrib.ulValueLen, 0));
+
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_LogObjects
+**
+** Logs all objects and attributes for specified slot
+**
+** Parameters:
+**  slotID - Slot number
+**
+** Returns:
+**  none
+*******************************************************************************/
+void object_LogObjects(CK_SLOT_ID slotID)
+{
+    P11_Object *list;
+
+    list = st.slots[slotID - 1].objects;
+
+    while(list)
+    {
+
+        object_LogObject(list);
+
+        list = list->next;
+    }
+}
+
+/******************************************************************************
+** Function: object_LogObject
+**
+** Logs a single object and its attributes
+**
+** Parameters:
+**  object - Object to log
+**
+** Returns:
+**  none
+*******************************************************************************/
+void object_LogObject(P11_Object *object)
+{
+    P11_Attrib *attrib;
+
+    log_Log(LOG_LOW, "=== Object handle: %X", object);
+
+    if (object->msc_obj)
+        log_Log(LOG_LOW, "--- Object Object: %s  Size: %lu", 
+                        object->msc_obj->objectID, object->msc_obj->objectSize);
+    else if (object->msc_key)
+        log_Log(LOG_LOW, "--- Key Object: %lu  Size: %lu", 
+                        object->msc_key->keyNum, object->msc_key->keySize);
+
+    attrib = object->attrib;
+
+    while(attrib)
+    {
+        object_LogAttribute(&attrib->attrib);
+        attrib = attrib->next;
+    }
+}
+
+/******************************************************************************
+** Function: object_LogAttribute
+**
+** Write out a single attribute to the log file
+**
+** Parameters:
+**  attrib - Attribute to log
+**
+** Returns:
+**  none
+*******************************************************************************/
+void object_LogAttribute(CK_ATTRIBUTE *attrib)
+{
+    CK_ULONG ulValue = 0;
+    CK_BYTE bValue = 0;
+    CK_BYTE *buf;
+
+    buf = (CK_BYTE *)malloc((attrib->ulValueLen * 3) + 1);
+    if (!buf)
+    {
+        log_Log(LOG_HIGH, "Memory alloc failed");
+        return;
+    }
+
+    if (attrib->pValue)
+    {
+        memcpy(&ulValue, attrib->pValue, 4);
+        memcpy(&bValue, attrib->pValue, 1);
+        object_BinToHex((CK_BYTE *)attrib->pValue, attrib->ulValueLen, buf);
+
+        switch (attrib->type)
+        {
+        case CKA_ID:
+            log_Log(LOG_LOW, "CKA_ID:%s", buf);
+            break;
+        case CKA_SERIAL_NUMBER:
+            log_Log(LOG_LOW, "CKA_SERIAL_NUMBER:%s", buf);
+            break;
+        case CKA_SUBJECT:
+            log_Log(LOG_LOW, "CKA_SUBJECT:%s", buf);
+            break;
+        case CKA_ISSUER:
+            log_Log(LOG_LOW, "CKA_ISSUER:%s", buf);
+            break;
+        case CKA_MODULUS:
+            log_Log(LOG_LOW, "CKA_MODULUS:%s", buf);
+            break;
+        case CKA_CLASS:
+            log_Log(LOG_LOW, "CKA_CLASS: %lu 0x%X", ulValue, ulValue);
+            break;
+        case CKA_KEY_TYPE:
+            log_Log(LOG_LOW, "CKA_KEY_TYPE: %lu 0x%X", ulValue, ulValue);
+            break;
+        case CKA_TOKEN: 
+            log_Log(LOG_LOW, "CKA_TOKEN: %lu 0x%X", bValue, bValue);
+            break;
+        case CKA_LABEL:
+            log_Log(LOG_LOW, "CKA_LABEL:%s", buf);
+            log_Log(LOG_LOW, "CKA_LABEL (string): %.*s", attrib->ulValueLen, attrib->pValue);
+            break;
+        case CKA_VALUE:
+            log_Log(LOG_LOW, "CKA_VALUE:%s", buf);
+            break;
+        case CKA_PUBLIC_EXPONENT:
+            log_Log(LOG_LOW, "CKA_PUBLIC_EXPONENT:%s", buf);
+            break;
+        case CKA_CERTIFICATE_TYPE:
+            log_Log(LOG_LOW, "CKA_CERTIFICATE_TYPE:%s", buf);
+            break;
+        case CKA_EXTRACTABLE:
+            log_Log(LOG_LOW, "CKA_EXTRACTABLE:%s", buf);
+            break;
+        case CKA_SIGN_RECOVER:
+            log_Log(LOG_LOW, "CKA_SIGN_RECOVER:%s", buf);
+            break;
+        case CKA_DERIVE:
+            log_Log(LOG_LOW, "CKA_DERIVE:%s", buf);
+            break;
+        case CKA_MODIFIABLE:
+            log_Log(LOG_LOW, "CKA_MODIFIABLE:%s", buf);
+            break;
+        case CKA_UNWRAP:
+            log_Log(LOG_LOW, "CKA_UNWRAP:%s", buf);
+            break;
+        case CKA_DECRYPT:
+            log_Log(LOG_LOW, "CKA_DECRYPT:%s", buf);
+            break;
+        case CKA_PRIVATE:
+            log_Log(LOG_LOW, "CKA_PRIVATE:%s", buf);
+            break;
+        case CKA_SIGN:
+            log_Log(LOG_LOW, "CKA_SIGN:%s", buf);
+            break;
+        case CKA_NEVER_EXTRACTABLE:
+            log_Log(LOG_LOW, "CKA_NEVER_EXTRACTABLE:%s", buf);
+            break;
+        case CKA_ALWAYS_SENSITIVE:
+            log_Log(LOG_LOW, "CKA_CKA_ALWAYS_SENSITIVE:%s", buf);
+            break;
+        case CKA_SENSITIVE:
+            log_Log(LOG_LOW, "CKA_SENSITIVE:%s", buf);
+            break;
+        default:
+            log_Log(LOG_LOW, "CKA_UNKNOWN (0x%lX):%s", attrib->type, buf);
+            break;
+        }
+    }
+
+    free(buf);
+}
+
+/******************************************************************************
+** Function: object_BinToHex
+**
+** Converts a binary array to hex text
+**
+** Parameters:
+**  data     - Input data
+**  data_len - Input data len
+**  out      - Output text data
+**
+** Returns:
+**  none
+*******************************************************************************/
+void object_BinToHex(CK_BYTE *data, CK_ULONG data_len, CK_BYTE *out)
+{
+    CK_ULONG i;
+
+    for (i = 0; i < data_len; i++)
+        sprintf((char *)&out[i * 3], " %.2X", data[i]);
+
+    out[data_len * 3] = 0;
+}
+
+/******************************************************************************
+** Function: object_AddAttributes
+**
+** Used by object_ReadAttributes when reading an object's attribute file.
+** Handles endian conversion of types.
+**
+** Parameters:
+**  object - Object to add attributes to
+**  data   - Raw data to be processed
+**  len    - Length of raw data
+**
+** Returns:
+**  Result of object_AddAttribute
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_AddAttributes(P11_Object *object, CK_BYTE *data, CK_ULONG len)
+{
+    CK_RV rv = CKR_OK;
+    CK_ULONG i;
+    P11_Attrib *attrib;
+    CK_ATTRIBUTE_TYPE type;
+    CK_ULONG data_len;
+
+    for (i = 0; (i < len) && !CKR_ERROR(rv);)
+    {
+        type = (data[i] * 0x1000000) + 
+               (data[i+1] * 0x10000) + 
+               (data[i+2] * 0x100) + 
+               data[i+3];
+
+        data_len = (data[i+4] * 0x100) + data[i+5];
+
+        (void)CKR_ERROR(rv = object_AddAttribute(object, type, TRUE, &data[i + 6], data_len, &attrib));
+
+        log_Log(LOG_LOW, "object_AddAttributes:");
+        object_LogAttribute(&attrib->attrib);
+   
+        i += 6 + attrib->attrib.ulValueLen;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_ReadAttributes
+**
+** Reads the attributes (from attribute file) of an object
+**
+** Parameters:
+**  hSession - Session handle
+**  obj_id   - Object ID of attribute file (string)
+**  object   - Object to add attributes to
+**
+** Returns:
+**  CKR_HOST_MEMORY on memory alloc error
+**  Error from object_AddAttributes
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_ReadAttributes(CK_SESSION_HANDLE hSession, CK_BYTE *obj_id, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    CK_RV msc_rv;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    CK_ULONG data_len;
+    CK_BYTE *data;
+    CK_BYTE data_hdr[7];
+        
+    (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_TOKEN, 1, object));
+
+    msc_rv = msc_ReadObject(&slot->conn, (char *)obj_id, 0, data_hdr, sizeof(data_hdr));
+
+    if (MSC_ERROR(msc_rv) && (msc_rv != MSC_UNAUTHORIZED))
+    {
+InferAttributes:
+        if (CKR_ERROR(object_InferAttributes(hSession, object)))
+            rv = CKR_FUNCTION_FAILED;
+        else
+            (void)CKR_ERROR(object_WriteAttributes(hSession, object));
+    }
+    else if (msc_rv == MSC_UNAUTHORIZED)
+    {
+        object->sensitive = 1;
+    }
+    else
+    {
+        { CK_BYTE buf[(sizeof(data_hdr) * 3) + 1];
+          object_BinToHex(data_hdr, sizeof(data_hdr), buf);
+          log_Log(LOG_LOW, "Raw attribute header (file %s): %s", obj_id, buf); }
+
+        data_len = (data_hdr[5] * 0x100) + data_hdr[6];
+        data = (CK_BYTE *)malloc(data_len);
+
+        log_Log(LOG_LOW, "Going to read %lu (0x%lX) bytes of data at offset %lX", data_len, data_len, sizeof(data_hdr));
+
+        if (!data)
+            rv = CKR_HOST_MEMORY;
+        else if (MSC_ERROR(msc_ReadObject(&slot->conn,
+                                          (char *)obj_id, 
+                                          sizeof(data_hdr), 
+                                          data, 
+                                          data_len)))
+        {
+            P11_ERR("Reading of attribute object failed");
+            goto InferAttributes; /* Fixme: may want to remove the goto; this is fairly clean, if hard to follow */
+        }
+        else
+        {
+            { CK_BYTE *buf;
+              buf = (CK_BYTE *)malloc((data_len * 3) + 1);
+              object_BinToHex(data, data_len, buf);
+              log_Log(LOG_LOW, "Raw attribute file: %s", buf);
+              free(buf); }
+
+            (void)CKR_ERROR(rv = object_AddAttributes(object, data, data_len));
+         }
+
+        if (data)
+            free(data);
+    }
+
+    object_LogObject(object);
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_InferAttributes
+**
+** Depending on the type of object this adds some default values of attributes
+** or pulls out values that it can and adds them as attributes.
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to infer attributes on
+**
+** Returns:
+**  CKR_FUNCTION_FAILED if a non-token object is specified
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_InferAttributes(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+
+    if (object->msc_key)
+        object_InferKeyAttributes(hSession, object);
+    else if (object->msc_obj)
+        object_InferObjAttributes(hSession, object);
+    else
+    {
+        P11_ERR("Invalid non-token object");
+        rv = CKR_FUNCTION_FAILED;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_InferKeyAttributes
+**
+** Adds some default values of attributes or pulls out values that it can and
+** adds them as attributes for this key.
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to infer attributes on
+**
+** Returns:
+**  Error from object_AddAttribute
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_InferKeyAttributes(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    P11_Attrib *attrib, *modulus;
+    CK_OBJECT_CLASS obj_class;
+    CK_KEY_TYPE key_type;
+
+    switch (object->msc_key->keyType)
+    {
+    case MSC_KEY_RSA_PUBLIC:
+    case MSC_KEY_DSA_PUBLIC:
+        obj_class = CKO_PUBLIC_KEY;
+        break;
+    case MSC_KEY_RSA_PRIVATE:
+    case MSC_KEY_RSA_PRIVATE_CRT:
+    case MSC_KEY_DSA_PRIVATE:
+        obj_class = CKO_PRIVATE_KEY;
+        break;
+    case MSC_KEY_DES:
+    case MSC_KEY_3DES:
+    case MSC_KEY_3DES3:
+        obj_class = CKO_SECRET_KEY; /* Fixme: Secret key??? */
+        break;
+    default:
+        obj_class = CKO_DATA;
+        break;
+    }
+
+    switch (object->msc_key->keyType)
+    {
+    case MSC_KEY_DSA_PUBLIC:
+    case MSC_KEY_DSA_PRIVATE:
+        key_type = CKK_DSA;
+        break;
+    case MSC_KEY_RSA_PUBLIC:
+    case MSC_KEY_RSA_PRIVATE:
+    case MSC_KEY_RSA_PRIVATE_CRT:
+        key_type = CKK_RSA;
+        break;
+    case MSC_KEY_DES:
+        key_type = CKK_DES;
+        break;
+    case MSC_KEY_3DES:
+        key_type = CKK_DES2;
+        break;
+    case MSC_KEY_3DES3:
+        key_type = CKK_DES3;
+        break;
+    default:
+        key_type = CKK_VENDOR_DEFINED;
+        break;
+    }
+
+    /* Fixme: some of these are ULONG values?  Need to convert to big-endian? */
+    (void)CKR_ERROR(rv = object_AddAttribute(object, CKA_CLASS, TRUE, (CK_BYTE *)&obj_class, sizeof(CK_OBJECT_CLASS), &attrib));
+    (void)CKR_ERROR(rv = object_AddAttribute(object, CKA_KEY_TYPE, TRUE, (CK_BYTE *)&key_type, sizeof(CK_KEY_TYPE), &attrib));
+
+    if ((object->msc_key->keyType == MSC_KEY_RSA_PRIVATE) ||
+        (object->msc_key->keyType == MSC_KEY_RSA_PRIVATE_CRT) ||
+        (object->msc_key->keyType == MSC_KEY_DSA_PRIVATE))
+    {
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_SENSITIVE, 1, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_ALWAYS_SENSITIVE, 1, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_NEVER_EXTRACTABLE, 1, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_SIGN, 1, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_PRIVATE, 1, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_DECRYPT, 1, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_UNWRAP, 1, object));
+
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_MODIFIABLE, 0, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_DERIVE, 0, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_SIGN_RECOVER, 0, object));
+        (void)CKR_ERROR(rv = object_AddBoolAttribute(CKA_EXTRACTABLE, 0, object));
+    }
+
+    if ((object->msc_key->keyType == MSC_KEY_RSA_PUBLIC) ||
+        (object->msc_key->keyType == MSC_KEY_DSA_PUBLIC))
+    {
+        MSCUChar8 keyBlob[4096]; // Fixme: don't hardcode this
+        MSCULong32 keyBlobSize = sizeof(keyBlob);
+        CK_RV msc_rv;
+
+        if (!MSC_ERROR(msc_rv = msc_ExportKey(&slot->conn,
+                                              object->msc_key->keyNum,
+                                              keyBlob,
+                                              &keyBlobSize,
+                                              0, 0)))
+        {
+            (void)CKR_ERROR(rv = object_AddAttribute(object, 
+                                                     CKA_MODULUS, 
+                                                     TRUE, 
+                                                     &keyBlob[6], 
+                                                     (keyBlob[4] * 0x100) + keyBlob[5], &modulus));
+
+            (void)CKR_ERROR(rv = object_AddAttribute(object, 
+                                   CKA_PUBLIC_EXPONENT, 
+                                   TRUE,
+                                   &keyBlob[modulus->attrib.ulValueLen + 8], 
+                                   (keyBlob[modulus->attrib.ulValueLen + 6] * 255) + keyBlob[modulus->attrib.ulValueLen + 7], 
+                                   &attrib));
+        }
+    }
+
+    if (!CKR_ERROR(rv = object_AddAttribute(object, CKA_ID, TRUE, 0, 20, &attrib)))
+    {
+        char t_id[21];
+
+        sprintf(t_id, "KEY%.17u", object->msc_key->keyNum);
+        memcpy(attrib->attrib.pValue, t_id, 20);
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_InferObjAttributes
+**
+** Adds some default values of attributes or pulls out values that it can and
+** adds them as attributes for this object.
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to infer attributes on
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_InferObjAttributes(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_WriteAttributes
+**
+** Writes attributes of object out to attribute file.  This function is big
+** because it handles keys, certs, and other objects along with creating them
+** if necessary.  This could be split into smaller pieces.
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to get attributes from
+**
+** Returns:
+**  CKR_HOST_MEMORY on memory alloc erro
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_WriteAttributes(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    MSC_RV msc_rv;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    P11_Attrib *attrib;
+    char obj_id[MSC_MAXSIZE_OBJID];
+    MSCObjectACL objACL;
+    CK_ULONG obj_size;
+    CK_BYTE data_hdr[7];
+    CK_BYTE *data;
+    CK_ULONG data_pos;
+    CK_ATTRIBUTE ck_attrib;
+    CK_BBOOL priv;
+    CK_OBJECT_CLASS obj_class;
+
+    memset(obj_id, 0x00, sizeof(obj_id));
+    memset(data_hdr, 0x00, sizeof(data_hdr));
+
+    attrib = object->attrib;
+    obj_size = 0;
+
+    while (attrib)
+    {
+        if (attrib->token)
+            obj_size += attrib->attrib.ulValueLen + 6; // Fixme: what if the obj_id is more than 2 bytes??
+
+        log_Log(LOG_LOW, "%lX Objsize: %lu Len: %lu", attrib->attrib.type, obj_size, attrib->attrib.ulValueLen);
+
+        attrib = attrib->next;
+    }
+
+    if (object->msc_key)
+    {
+        obj_id[0] = 'k';
+        obj_id[1] = object->msc_key->keyNum + 1 > 9 ? 65 + object->msc_key->keyNum : 48 + object->msc_key->keyNum;
+
+        data_hdr[0] = 0; // Fixme: Key object type
+
+        priv = 0x01;
+        ck_attrib.type = CKA_PRIVATE;
+        ck_attrib.pValue = &priv;
+        ck_attrib.ulValueLen = sizeof(priv);
+
+/*
+        if (object_MatchAttrib(&ck_attrib, object))
+            objACL.readPermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+        else
+*/
+        objACL.readPermission = MSC_AUT_ALL;
+
+        objACL.writePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+        objACL.deletePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+
+        obj_class = CKO_PRIVATE_KEY;
+        ck_attrib.type = CKA_CLASS;
+        ck_attrib.pValue = &obj_class;
+        ck_attrib.ulValueLen = sizeof(obj_class);
+
+        if (object_MatchAttrib(&ck_attrib, object))
+            msc_rv = msc_CreateObject(&slot->conn, (char *)obj_id, st.prefs.prvkey_attrib_size, &objACL);
+        else
+            msc_rv = msc_CreateObject(&slot->conn, (char *)obj_id, st.prefs.pubkey_attrib_size, &objACL);
+
+        if (MSC_ERROR(msc_rv) && (msc_rv != MSC_OBJECT_EXISTS))
+            rv = CKR_FUNCTION_FAILED;
+    }
+    else if (object->msc_obj)
+    {
+        data_hdr[0] = 0; // Fixme: object type
+
+        strncpy((char *)obj_id, object->msc_obj->objectID, sizeof(obj_id));
+        objACL.readPermission = object->msc_obj->objectACL.readPermission;
+        objACL.writePermission = object->msc_obj->objectACL.writePermission;
+        objACL.deletePermission = object->msc_obj->objectACL.deletePermission;
+
+        log_Log(LOG_LOW, "Object ID is: %s", obj_id);
+
+        if (!isupper(obj_id[0]))
+        {
+            P11_ERR("Can't create object; first character in OID is not upper-case");
+            rv = CKR_FUNCTION_FAILED;
+        }
+        else if (CKR_ERROR(object_GetAttrib(CKA_VALUE, object, &attrib)))
+        {
+            P11_ERR("Can't create object; no CKA_VALUE attribute");
+            rv = CKR_FUNCTION_FAILED;
+        }
+        else
+        {
+            msc_rv = msc_CreateObject(&slot->conn, (char *)obj_id, attrib->attrib.ulValueLen, &objACL);
+
+            if (msc_rv == MSC_OBJECT_EXISTS)
+            {
+                if (MSC_ERROR(msc_DeleteObject(&slot->conn, obj_id, 0)))
+                    rv = CKR_FUNCTION_FAILED;
+                else if (MSC_ERROR(msc_CreateObject(&slot->conn, (char *)obj_id, attrib->attrib.ulValueLen, &objACL)))
+                    rv = CKR_FUNCTION_FAILED;
+                else if (MSC_ERROR(msc_WriteObject(&slot->conn, (char *)obj_id, 0, 
+                                                   (CK_BYTE *)attrib->attrib.pValue, attrib->attrib.ulValueLen)))
+                    rv = CKR_FUNCTION_FAILED;
+            }
+            else if (MSC_ERROR(msc_rv))
+                rv = CKR_FUNCTION_FAILED;
+            else if (MSC_ERROR(msc_WriteObject(&slot->conn, (char *)obj_id, 0, 
+                                               (CK_BYTE *)attrib->attrib.pValue, attrib->attrib.ulValueLen)))
+                rv = CKR_FUNCTION_FAILED;
+
+            obj_id[0] = tolower(obj_id[0]);
+
+            priv = 0x01;
+            ck_attrib.type = CKA_PRIVATE;
+            ck_attrib.pValue = &priv;
+            ck_attrib.ulValueLen = sizeof(priv);
+    
+            if (object_MatchAttrib(&ck_attrib, object))
+                objACL.readPermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+            else
+                objACL.readPermission = MSC_AUT_ALL;
+
+            objACL.writePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+            objACL.deletePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+    
+            obj_class = CKO_CERTIFICATE;
+            ck_attrib.type = CKA_CLASS;
+            ck_attrib.pValue = &obj_class;
+            ck_attrib.ulValueLen = sizeof(obj_class);
+    
+            if (object_MatchAttrib(&ck_attrib, object))
+                msc_rv = msc_CreateObject(&slot->conn, (char *)obj_id, st.prefs.cert_attrib_size, &objACL);
+            else
+                msc_rv = msc_CreateObject(&slot->conn, (char *)obj_id, st.prefs.data_attrib_size, &objACL);
+    
+            if (MSC_ERROR(msc_rv) && (msc_rv != MSC_OBJECT_EXISTS))
+                rv = CKR_FUNCTION_FAILED;
+        }
+    }
+    else
+    {
+        P11_ERR("Invalid non-token object");
+        rv = CKR_FUNCTION_FAILED;
+    }
+
+    if (!CKR_ERROR(rv))
+    {
+        data = (CK_BYTE *)malloc(obj_size + sizeof(data_hdr));
+
+        if (!data)
+            rv = CKR_HOST_MEMORY;
+        else
+        {
+            log_Log(LOG_LOW, "Obj size is: %lu (0x%lX)", obj_size, obj_size);
+
+            data_hdr[1] = obj_id[0];
+            data_hdr[2] = obj_id[1];
+            data_hdr[5] = (CK_BYTE)((obj_size & 0xFF00) >> 8);
+            data_hdr[6] = (CK_BYTE)(obj_size & 0xFF);
+            memcpy(data, data_hdr, sizeof(data_hdr));
+
+            attrib = object->attrib;
+            data_pos = sizeof(data_hdr);
+    
+            while (attrib)
+            {
+                if (!attrib->token)
+                {
+                    log_Log(LOG_LOW, "Skipping attribute:");
+                    object_LogAttribute(&attrib->attrib);
+                }
+                else
+                {
+                    log_Log(LOG_LOW, "Writing attribute:");
+                    object_LogAttribute(&attrib->attrib);
+
+                    data[data_pos] = (CK_BYTE)((attrib->attrib.type & 0xFF000000) >> 24);
+                    data[data_pos + 1] = (CK_BYTE)((attrib->attrib.type & 0xFF0000) >> 16);
+                    data[data_pos + 2] = (CK_BYTE)((attrib->attrib.type & 0xFF00) >> 8);
+                    data[data_pos + 3] = (CK_BYTE)(attrib->attrib.type & 0xFF);
+                    data[data_pos + 4] = (CK_BYTE)((attrib->attrib.ulValueLen & 0xFF00) >> 8);
+                    data[data_pos + 5] = (CK_BYTE)(attrib->attrib.ulValueLen & 0xFF);
+                    memcpy(&data[data_pos + 6], attrib->attrib.pValue, attrib->attrib.ulValueLen);
+
+                    data_pos += attrib->attrib.ulValueLen + 6; // Fixme: 2 byte obj_id??
+                }
+    
+                attrib = attrib->next;
+            }
+
+            log_Log(LOG_LOW, "ID: %s  SIZE: %lu", obj_id, obj_size);
+        
+            { CK_BYTE buf[4096]; 
+              object_BinToHex(data, obj_size + sizeof(data_hdr), buf); 
+              log_Log(LOG_LOW, "Data:%s", buf); }
+
+            if (MSC_ERROR(msc_WriteObject(&slot->conn, obj_id, 0, data, obj_size + sizeof(data_hdr))))
+                rv = CKR_FUNCTION_FAILED;
+        }
+
+        if (data)
+            free(data);
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_InferClassAttributes
+**
+** Infer attribute about a specific class of object (a certificate for example)
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to infer attributes
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV object_InferClassAttributes(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    CK_ATTRIBUTE attrib;
+    P11_Attrib *obj_attrib, *t_attrib;
+    CK_OBJECT_CLASS obj_class;
+    CK_BYTE buf[4096]; /* Fixme: don't hardcode this */
+    CK_ULONG len;
+
+    log_Log(LOG_LOW, "object_InferClassAttributes");
+
+    if (!CKR_ERROR(object_GetAttrib(CKA_VALUE, object, &obj_attrib)))
+    {
+        obj_class = CKO_CERTIFICATE;
+        attrib.type = CKA_CLASS;
+        attrib.pValue = &obj_class; // Fixme: endian issue
+        attrib.ulValueLen = 4;
+
+        log_Log(LOG_LOW, "object_InferClassAttributes: got CKA_VALUE");
+    
+        if (object_MatchAttrib(&attrib, object))
+        {
+            log_Log(LOG_LOW, "object_InferClassAttributes: got CKO_CERTIFICATE");
+    
+            if (CKR_ERROR_NOLOG(object_GetAttrib(CKA_MODULUS, object, &t_attrib)) &&
+                !CKR_ERROR(object_GetCertModulus((CK_BYTE *)obj_attrib->attrib.pValue,
+                                                 obj_attrib->attrib.ulValueLen,
+                                                 buf,
+                                                 &len)))
+            {
+                log_Log(LOG_LOW, "object_InferClassAttributes: got CKA_MODULUS");
+                (void)CKR_ERROR(object_AddAttribute(object, CKA_MODULUS, FALSE, buf, len, &t_attrib));
+            }
+
+            if (CKR_ERROR_NOLOG(object_GetAttrib(CKA_PUBLIC_EXPONENT, object, &t_attrib)) &&
+                !CKR_ERROR(object_GetCertPubExponent((CK_BYTE *)obj_attrib->attrib.pValue,
+                                                     obj_attrib->attrib.ulValueLen,
+                                                     buf,
+                                                     &len)))
+            {
+                log_Log(LOG_LOW, "object_InferClassAttributes: got CKA_PUBLIC_EXPONENT");
+                (void)CKR_ERROR(object_AddAttribute(object, CKA_PUBLIC_EXPONENT, FALSE, buf, len, &t_attrib));
+            }
+
+            if (CKR_ERROR_NOLOG(object_GetAttrib(CKA_SUBJECT, object, &t_attrib)) &&
+                !CKR_ERROR(object_GetCertSubject((CK_BYTE *)obj_attrib->attrib.pValue,
+                                                 obj_attrib->attrib.ulValueLen,
+                                                 buf,
+                                                 &len)))
+            {
+                log_Log(LOG_LOW, "object_InferClassAttributes: got CKA_SUBJECT");
+                (void)CKR_ERROR(object_AddAttribute(object, CKA_SUBJECT, FALSE, buf, len, &t_attrib));
+            }
+
+            if (CKR_ERROR_NOLOG(object_GetAttrib(CKA_ISSUER, object, &t_attrib)) &&
+                !CKR_ERROR(object_GetCertIssuer((CK_BYTE *)obj_attrib->attrib.pValue,
+                                                obj_attrib->attrib.ulValueLen,
+                                                buf,
+                                                &len)))
+            {
+                log_Log(LOG_LOW, "object_InferClassAttributes: got CKA_ISSUER");
+                (void)CKR_ERROR(object_AddAttribute(object, CKA_ISSUER, FALSE, buf, len, &t_attrib));
+            }
+
+            if (CKR_ERROR_NOLOG(object_GetAttrib(CKA_SERIAL_NUMBER, object, &t_attrib)) &&
+                !CKR_ERROR(object_GetCertSerial((CK_BYTE *)obj_attrib->attrib.pValue,
+                                                obj_attrib->attrib.ulValueLen,
+                                                buf,
+                                                &len)))
+            {
+                log_Log(LOG_LOW, "object_InferClassAttributes: got CKA_SERIAL_NUMBER");
+                (void)CKR_ERROR(object_AddAttribute(object, CKA_SERIAL_NUMBER, FALSE, buf, len, &t_attrib));
+            }
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_GetCertSerial
+**
+** Pulls the serial number from raw certificate data using OpenSSL.
+**
+** Fixme: add error checking for OpenSSL functions?
+**
+** Parameters:
+**  cert      - Input certificate
+**  cert_size - Size of input data
+**  out       - Output data (serial number)
+**  out_len   - Length of output data
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_GetCertSerial(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len)
+{
+    CK_RV rv = CKR_OK;
+    BIO *inObject=NULL;
+    X509 *certObject=NULL;
+    ASN1_INTEGER *serial;
+    BUF_MEM *bptr;
+
+    inObject   = BIO_new_mem_buf(cert, cert_size);
+    certObject = d2i_X509_bio(inObject, NULL);
+
+    serial = X509_get_serialNumber(certObject);
+
+    *out_len = serial->length;
+
+    if (out)
+        memcpy(out, serial->data, serial->length);
+
+    { CK_BYTE *buf;
+      buf = (CK_BYTE *)malloc(((*out_len) * 3) + 1);
+      object_BinToHex(out, *out_len, buf);
+      log_Log(LOG_LOW, "GetCertSerial:%s", buf);
+      free(buf); }
+
+    ASN1_INTEGER_free(serial);
+    //Fixme: X509_free(certObject);
+    BIO_get_mem_ptr(inObject, &bptr);
+    BIO_set_close(inObject, BIO_NOCLOSE);
+    BIO_free(inObject);
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_GetCertSubject
+**
+** Pulls the subject from raw certificate data using OpenSSL.
+**
+** Fixme: add error checking for OpenSSL functions?
+**
+** Parameters:
+**  cert      - Input certificate
+**  cert_size - Size of input data
+**  out       - Output data (subject)
+**  out_len   - Length of output data
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_GetCertSubject(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len)
+{
+    CK_RV rv = CKR_OK;
+    BIO *inObject=NULL;
+    X509 *certObject=NULL;
+    X509_NAME *name;
+    BUF_MEM *bptr;
+
+    inObject   = BIO_new_mem_buf(cert, cert_size);
+    certObject = d2i_X509_bio(inObject, NULL);
+
+    name = X509_get_subject_name(certObject);
+
+    if (!out)
+        *out_len = i2d_X509_NAME(name, 0);
+    else
+        *out_len = i2d_X509_NAME(name, &out);
+
+    X509_NAME_free(name);
+    //Fixme: X509_free(certObject);
+    BIO_get_mem_ptr(inObject, &bptr);
+    BIO_set_close(inObject, BIO_NOCLOSE);
+    BIO_free(inObject);
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_GetCertIssuer
+**
+** Pulls the issuer from raw certificate data using OpenSSL.
+**
+** Fixme: add error checking for OpenSSL functions?
+**
+** Parameters:
+**  cert      - Input certificate
+**  cert_size - Size of input data
+**  out       - Output data (issuer)
+**  out_len   - Length of output data
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_GetCertIssuer(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len)
+{
+    CK_RV rv = CKR_OK;
+    BIO *inObject=NULL;
+    X509 *certObject=NULL;
+    X509_NAME *name;
+    BUF_MEM *bptr;
+
+    inObject   = BIO_new_mem_buf(cert, cert_size);
+    certObject = d2i_X509_bio(inObject, NULL);
+
+    name = X509_get_issuer_name(certObject);
+
+    if (!out)
+        *out_len = i2d_X509_NAME(name, 0);
+    else
+        *out_len = i2d_X509_NAME(name, &out);
+
+    X509_NAME_free(name);
+    //Fixme: X509_free(certObject);
+    BIO_get_mem_ptr(inObject, &bptr);
+    BIO_set_close(inObject, BIO_NOCLOSE);
+    BIO_free(inObject);
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_GetCertModulus
+**
+** Pulls the modulus from raw certificate data using OpenSSL.
+**
+** Fixme: add error checking for OpenSSL functions?
+**
+** Parameters:
+**  cert      - Input certificate
+**  cert_size - Size of input data
+**  out       - Output data (modulus)
+**  out_len   - Length of output data
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_GetCertModulus(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len)
+{
+    CK_RV rv = CKR_OK;
+    BIO *inObject=NULL;
+    X509 *certObject=NULL;
+    EVP_PKEY *pkey;
+    BUF_MEM *bptr;
+
+    inObject   = BIO_new_mem_buf(cert, cert_size);
+
+    certObject = d2i_X509_bio(inObject, NULL);
+
+    pkey = X509_get_pubkey(certObject);
+
+    if (!out)
+        *out_len = BN_num_bytes(pkey->pkey.rsa->n);
+    else
+    {
+        *out_len = BN_num_bytes(pkey->pkey.rsa->n);
+        BN_bn2bin(pkey->pkey.rsa->n, out);
+    }
+
+    //Fixme: X509_free(certObject);
+    BIO_get_mem_ptr(inObject, &bptr);
+    BIO_set_close(inObject, BIO_NOCLOSE);
+    BIO_free(inObject);
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_GetCertPubExponent
+**
+** Pulls the public exponent from raw certificate data using OpenSSL.
+**
+** Fixme: add error checking for OpenSSL functions?
+**
+** Parameters:
+**  cert      - Input certificate
+**  cert_size - Size of input data
+**  out       - Output data (public exponent)
+**  out_len   - Length of output data
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_GetCertPubExponent(CK_BYTE *cert, CK_ULONG cert_size, CK_BYTE *out, CK_ULONG *out_len)
+{
+    CK_RV rv = CKR_OK;
+    BIO *inObject=NULL;
+    X509 *certObject=NULL;
+    EVP_PKEY *pkey;
+    BUF_MEM *bptr;
+
+    inObject   = BIO_new_mem_buf(cert, cert_size);
+
+    certObject = d2i_X509_bio(inObject, NULL);
+
+    pkey = X509_get_pubkey(certObject);
+
+    if (!out)
+        *out_len = BN_num_bytes(pkey->pkey.rsa->e);
+    else
+    {
+        *out_len = BN_num_bytes(pkey->pkey.rsa->e);
+        BN_bn2bin(pkey->pkey.rsa->e, out);
+    }
+
+    //Fixme: X509_free(certObject);
+    BIO_get_mem_ptr(inObject, &bptr);
+    BIO_set_close(inObject, BIO_NOCLOSE);
+    BIO_free(inObject);
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_CreateCertificate
+**
+** Creates a new certificate object on the token
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to add to token
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_CreateCertificate(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    P11_Object *object_l;
+    P11_Attrib *attrib;
+    CK_BYTE tag, last;
+
+    if (!(object->msc_obj = (MSCObjectInfo *)calloc(1, sizeof(MSCObjectInfo))))
+        rv = CKR_HOST_MEMORY;
+    else
+    {
+        object_l = slot->objects;
+        tag = 'C';
+        last = 47;
+
+        while (object_l)
+        {
+            if ((object_l != object) &&
+                object_l->msc_obj &&
+                !CKR_ERROR(object_GetAttrib(CKA_CLASS, object_l, &attrib)))
+            {
+                if (*((CK_ULONG *)attrib->attrib.pValue) == CKO_CERTIFICATE)
+                {
+                    tag = object_l->msc_obj->objectID[0];
+                    last = object_l->msc_obj->objectID[1];
+                }
+            }
+
+            object_l = object_l->next;
+        }
+
+        object->msc_obj->objectID[0] = tag;
+        object->msc_obj->objectID[1] = last + 1;
+        object->msc_obj->objectID[2] = 0;
+
+        object->msc_obj->objectSize = 0; /* WriteAttributes will figure out the size */
+        object->msc_obj->objectACL.readPermission = MSC_AUT_ALL;
+        object->msc_obj->objectACL.writePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+        object->msc_obj->objectACL.deletePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+
+        rv = object_WriteAttributes(hSession, object);
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_CreatePublicKey
+**
+** Creates a new public key object on the token (imports RSA key)
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to add to token
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_CreatePublicKey(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    MSC_RV msc_rv;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    CK_BYTE keyNum = 0;
+    MSCKeyInfo keyInfo;
+    P11_Attrib *modulus;
+    P11_Attrib *public_exponent;
+    CK_ULONG keySize = 1024;
+    CK_BYTE *keyBlob;
+    CK_ULONG keyBlobSize;
+
+    if (!(object->msc_key = (MSCKeyInfo *)calloc(1, sizeof(MSCKeyInfo))))
+        rv = CKR_HOST_MEMORY;
+    else
+    {
+        msc_rv = msc_ListKeys(&slot->conn, MSC_SEQUENCE_RESET, &keyInfo);
+        if (!MSC_ERROR(msc_rv))
+            keyNum = keyInfo.keyNum + 1;
+        while (!MSC_ERROR(msc_rv) && !CKR_ERROR(rv))
+        {
+            msc_rv = msc_ListKeys(&slot->conn, MSC_SEQUENCE_NEXT, &keyInfo);
+    
+            if (!MSC_ERROR(msc_rv))
+                keyNum = keyInfo.keyNum + 1;
+        }
+
+        if (!CKR_ERROR(object_GetAttrib(CKA_MODULUS, object, &modulus)))
+            keySize = modulus->attrib.ulValueLen * 8;
+        else
+            return CKR_FUNCTION_FAILED;
+
+        (void)CKR_ERROR(object_GetAttrib(CKA_PUBLIC_EXPONENT, object, &public_exponent));
+
+        keyBlobSize = modulus->attrib.ulValueLen +
+                      public_exponent->attrib.ulValueLen;
+
+        keyBlob = (CK_BYTE *)malloc(keyBlobSize + 14);
+
+        if (!keyBlob)
+            rv = CKR_HOST_MEMORY;
+        else
+        {
+            object->msc_key->keyNum = keyNum;
+            object->msc_key->keyType = MSC_KEY_RSA_PUBLIC;
+            object->msc_key->keySize = (MSCUShort16)keySize;
+            object->msc_key->keyPolicy.cipherDirection = MSC_KEYPOLICY_DIR_VERIFY | MSC_KEYPOLICY_DIR_ENCRYPT;
+            object->msc_key->keyPolicy.cipherMode = MSC_KEYPOLICY_MODE_RSA_NOPAD;
+            object->msc_key->keyACL.readPermission = MSC_AUT_ALL;
+            object->msc_key->keyACL.writePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+            object->msc_key->keyACL.usePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+    
+            keyBlobSize = 0;
+            keyBlob[keyBlobSize++] = MSC_BLOB_ENC_PLAIN;
+            keyBlob[keyBlobSize++] = object->msc_key->keyType;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(object->msc_key->keySize >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)object->msc_key->keySize;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(modulus->attrib.ulValueLen >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)modulus->attrib.ulValueLen;
+            memcpy(&keyBlob[keyBlobSize], modulus->attrib.pValue, modulus->attrib.ulValueLen);
+            keyBlobSize += modulus->attrib.ulValueLen;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(public_exponent->attrib.ulValueLen >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)public_exponent->attrib.ulValueLen;
+            memcpy(&keyBlob[keyBlobSize], public_exponent->attrib.pValue, public_exponent->attrib.ulValueLen);
+            keyBlobSize += public_exponent->attrib.ulValueLen;
+
+            { CK_BYTE *buf;
+              buf = (CK_BYTE *)malloc((keyBlobSize * 3) + 1);
+              object_BinToHex(keyBlob, keyBlobSize, buf);
+              log_Log(LOG_LOW, "Raw keyBlob: %s", buf);
+              free(buf); }
+
+            if (MSC_ERROR(msc_ImportKey(&slot->conn, 
+                                        object->msc_key->keyNum, 
+                                        &object->msc_key->keyACL, 
+                                        keyBlob, 
+                                        keyBlobSize,
+                                        &object->msc_key->keyPolicy, 0, 0)))
+                rv = CKR_FUNCTION_FAILED;
+            else
+                rv = object_WriteAttributes(hSession, object);
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_CreatePrivateKey
+**
+** Creates a new private key object on the token (imports RSA key)
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to add to token
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_CreatePrivateKey(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    MSC_RV msc_rv;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    CK_BYTE keyNum = 0;
+    MSCKeyInfo keyInfo;
+    P11_Attrib *modulus;
+    P11_Attrib *private_exponent;
+    P11_Attrib *public_exponent;
+    P11_Attrib *prime_1;
+    P11_Attrib *prime_2;
+    P11_Attrib *exponent_1;
+    P11_Attrib *exponent_2;
+    P11_Attrib *coefficient;
+    CK_ULONG keySize = 1024;
+    CK_BYTE *keyBlob;
+    CK_ULONG keyBlobSize;
+
+    if (!(object->msc_key = (MSCKeyInfo *)calloc(1, sizeof(MSCKeyInfo))))
+        rv = CKR_HOST_MEMORY;
+    else
+    {
+        msc_rv = msc_ListKeys(&slot->conn, MSC_SEQUENCE_RESET, &keyInfo);
+        if (!MSC_ERROR(msc_rv))
+            keyNum = keyInfo.keyNum + 1;
+        while (!MSC_ERROR(msc_rv) && !CKR_ERROR(rv))
+        {
+            msc_rv = msc_ListKeys(&slot->conn, MSC_SEQUENCE_NEXT, &keyInfo);
+    
+            if (!MSC_ERROR(msc_rv))
+                keyNum = keyInfo.keyNum + 1;
+        }
+
+        if (!CKR_ERROR(object_GetAttrib(CKA_MODULUS, object, &modulus)))
+            keySize = modulus->attrib.ulValueLen * 8;
+
+        (void)CKR_ERROR(object_GetAttrib(CKA_PRIVATE_EXPONENT, object, &private_exponent));
+        (void)CKR_ERROR(object_GetAttrib(CKA_PUBLIC_EXPONENT, object, &public_exponent));
+        (void)CKR_ERROR(object_GetAttrib(CKA_PRIME_1, object, &prime_1));
+        (void)CKR_ERROR(object_GetAttrib(CKA_PRIME_2, object, &prime_2));
+        (void)CKR_ERROR(object_GetAttrib(CKA_EXPONENT_1, object, &exponent_1));
+        (void)CKR_ERROR(object_GetAttrib(CKA_EXPONENT_2, object, &exponent_2));
+        (void)CKR_ERROR(object_GetAttrib(CKA_COEFFICIENT, object, &coefficient));
+
+        keyBlobSize = prime_1->attrib.ulValueLen +
+                      prime_2->attrib.ulValueLen +
+                      coefficient->attrib.ulValueLen +
+                      exponent_1->attrib.ulValueLen +
+                      exponent_2->attrib.ulValueLen;
+
+        keyBlob = (CK_BYTE *)malloc(keyBlobSize + 14);
+
+        if (!keyBlob)
+            rv = CKR_HOST_MEMORY;
+        else
+        {
+            object->msc_key->keyNum = keyNum;
+            object->msc_key->keyType = MSC_KEY_RSA_PRIVATE_CRT;
+            object->msc_key->keySize = (MSCUShort16)keySize;
+            object->msc_key->keyPolicy.cipherDirection = MSC_KEYPOLICY_DIR_SIGN | MSC_KEYPOLICY_DIR_DECRYPT;
+            object->msc_key->keyPolicy.cipherMode = MSC_KEYPOLICY_MODE_RSA_NOPAD;
+            object->msc_key->keyACL.readPermission = MSC_AUT_NONE;
+            object->msc_key->keyACL.writePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+            object->msc_key->keyACL.usePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+    
+            keyBlobSize = 0;
+            keyBlob[keyBlobSize++] = MSC_BLOB_ENC_PLAIN;
+            keyBlob[keyBlobSize++] = object->msc_key->keyType;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(object->msc_key->keySize >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)object->msc_key->keySize;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(prime_1->attrib.ulValueLen >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)prime_1->attrib.ulValueLen;
+            memcpy(&keyBlob[keyBlobSize], prime_1->attrib.pValue, prime_1->attrib.ulValueLen);
+            keyBlobSize += prime_1->attrib.ulValueLen;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(prime_2->attrib.ulValueLen >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)prime_2->attrib.ulValueLen;
+            memcpy(&keyBlob[keyBlobSize], prime_2->attrib.pValue, prime_2->attrib.ulValueLen);
+            keyBlobSize += prime_2->attrib.ulValueLen;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(coefficient->attrib.ulValueLen >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)coefficient->attrib.ulValueLen;
+            memcpy(&keyBlob[keyBlobSize], coefficient->attrib.pValue, coefficient->attrib.ulValueLen);
+            keyBlobSize += coefficient->attrib.ulValueLen;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(exponent_1->attrib.ulValueLen >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)exponent_1->attrib.ulValueLen;
+            memcpy(&keyBlob[keyBlobSize], exponent_1->attrib.pValue, exponent_1->attrib.ulValueLen);
+            keyBlobSize += exponent_1->attrib.ulValueLen;
+            keyBlob[keyBlobSize++] = (CK_BYTE)(exponent_2->attrib.ulValueLen >> 8);
+            keyBlob[keyBlobSize++] = (CK_BYTE)exponent_2->attrib.ulValueLen;
+            memcpy(&keyBlob[keyBlobSize], exponent_2->attrib.pValue, exponent_2->attrib.ulValueLen);
+            keyBlobSize += exponent_2->attrib.ulValueLen;
+
+            { CK_BYTE *buf;
+              buf = (CK_BYTE *)malloc((keyBlobSize * 3) + 1);
+              object_BinToHex(keyBlob, keyBlobSize, buf);
+              log_Log(LOG_LOW, "Raw keyBlob: %s", buf);
+              free(buf); }
+
+            if (MSC_ERROR(msc_ImportKey(&slot->conn, 
+                                        object->msc_key->keyNum, 
+                                        &object->msc_key->keyACL, 
+                                        keyBlob, 
+                                        keyBlobSize,
+                                        &object->msc_key->keyPolicy, 0, 0)))
+                rv = CKR_FUNCTION_FAILED;
+            else
+                rv = object_WriteAttributes(hSession, object);
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_CreateObject
+**
+** Creates a new data object on the token
+**
+** Parameters:
+**  hSession - Session handle
+**  object   - Object to add to token
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV object_CreateObject(CK_SESSION_HANDLE hSession, P11_Object *object)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Slot *slot = &st.slots[session->session.slotID - 1];
+    P11_Object *object_l;
+    P11_Attrib *attrib;
+    CK_BYTE tag, last;
+
+    if (!(object->msc_obj = (MSCObjectInfo *)calloc(1, sizeof(MSCObjectInfo))))
+        rv = CKR_HOST_MEMORY;
+    else
+    {
+        object_l = slot->objects;
+        tag = 'O';
+        last = 47;
+
+        while (object_l)
+        {
+            if ((object_l != object) &&
+                object_l->msc_obj &&
+                !CKR_ERROR(object_GetAttrib(CKA_CLASS, object_l, &attrib)))
+            {
+                if (*((CK_ULONG *)attrib->attrib.pValue) == CKO_CERTIFICATE)
+                {
+                    tag = object_l->msc_obj->objectID[0];
+                    last = object_l->msc_obj->objectID[1];
+                }
+            }
+
+            object_l = object_l->next;
+        }
+
+        object->msc_obj->objectID[0] = tag;
+        object->msc_obj->objectID[1] = last + 1;
+        object->msc_obj->objectID[2] = 0;
+
+        object->msc_obj->objectSize = 0; /* WriteAttributes will figure out the size */
+
+        /* Data objects don't have any attributes that specify permissions so we just */
+        /* default to these.                                                          */
+        object->msc_obj->objectACL.readPermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+        object->msc_obj->objectACL.writePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+        object->msc_obj->objectACL.deletePermission = (MSCUShort16)object_MapPIN(st.prefs.user_pin_num);
+
+        rv = object_WriteAttributes(hSession, object);
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_MapPIN
+**
+** Maps a PIN number to a Musclecard Framework AUT PIN
+**
+** Parameters:
+**  pinNum - P11 PIN number
+**
+** Returns:
+**  MSC_AUT_XXX
+*******************************************************************************/
+CK_ULONG object_MapPIN(CK_ULONG pinNum)
+{
+    CK_RV rv = CKR_OK;
+
+    if (st.prefs.disable_security)
+        return MSC_AUT_ALL;
+    else if (pinNum == 0)
+        return MSC_AUT_PIN_0;
+    else if (pinNum == 1)
+        return MSC_AUT_PIN_1;
+    else if (pinNum == 2)
+        return MSC_AUT_PIN_2;
+    else if (pinNum == 3)
+        return MSC_AUT_PIN_3;
+    else if (pinNum == 4)
+        return MSC_AUT_PIN_4;
+    else
+        return P11_MAX_ULONG;
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: object_UserMode
+**
+** Tries to update the information on "sensitive" objects
+**
+** Parameters:
+**  hSession - session handle
+**
+** Returns:
+**  CKR_XXX
+*******************************************************************************/
+CK_ULONG object_UserMode(CK_SESSION_HANDLE hSession)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+    P11_Object *object_l;
+
+    if (!session)
+        rv = CKR_FUNCTION_FAILED;
+    else
+    {
+        object_l = st.slots[session->session.slotID - 1].objects;
+        while(object_l && object_l->next)
+        {
+            if (object_l->sensitive)
+            {
+                if (object_l->msc_key)
+                    rv = CKR_ERROR(object_UpdateKeyInfo(hSession, (CK_OBJECT_HANDLE *)&object_l, 0));
+                else if (object_l->msc_obj)
+                    rv = CKR_ERROR(object_UpdateObjectInfo(hSession, (CK_OBJECT_HANDLE *)&object_l, 0));
+            }
+    
+            object_l = object_l->next;
+        }
+    }
+
+    return rv;
+}

Added: trunk/SmartCardServices/src/PKCS11/p11x_prefs.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_prefs.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_prefs.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,318 @@
+/******************************************************************************
+** 
+**  $Id: p11x_prefs.c,v 1.2 2003/02/13 20:06:41 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: PKCS #11 preference handling functions
+** 
+******************************************************************************/
+
+#include <stdio.h>
+#include "cryptoki.h"
+
+#ifndef HAVE_STRTOKR
+#undef strtok_r
+#define strtok_r(x,y,z) strtok(x,y)
+#endif
+
+#ifdef WIN32
+#define strcasecmp stricmp
+#endif
+
+/******************************************************************************
+** Function: util_ParsePreference
+**
+** Parse a preference item from a line of text.  The text should be null
+** terminated and buf_size keeps overruns from happening.
+**
+** If a preference item is successfully parsed then it is stored in the 
+** st.prefs settings.
+**
+** This whole function is fairly verbose and could be broken into smaller
+** pieces to handle things like "get true/false pref" but at least this is
+** very straightforward.
+**
+** Fixme: put this in p11x_prefs.c
+**
+** Parameters:
+**  buf      - Null terminated text buffer
+**  buf_size - Size of buffer 
+**
+** Returns:
+**  none
+*******************************************************************************/
+void util_ParsePreference(char *buf, CK_ULONG buf_size)
+{
+    char sep[] = "=\t\r\n ";
+    char *token;
+#ifdef HAVE_STRTOKR
+    char *strtok_ptr;
+#endif
+
+    /* We will be using many unsafe string functions so force a NULL at the */
+    /*     end of the buffer to protect ourselves */
+    buf[buf_size - 1] = 0;
+    token = strchr(buf, '#');
+
+    if (token) 
+        *token = 0;
+
+    token = strtok_r(buf, sep, &strtok_ptr);
+
+    if (token)
+    {
+        if (!strcasecmp("DebugLevel", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"DebugLevel\" failed");
+            else
+            {
+                if (!strcasecmp("LOW", token))
+                    st.prefs.log_level = LOG_LOW;
+                else if (!strcasecmp("MED", token))
+                    st.prefs.log_level = LOG_MED;
+                else
+                    st.prefs.log_level = LOG_HIGH;
+            }
+        }
+        else if (!strcasecmp("LogFilename", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"LogFilename\" failed");
+            else
+                strncpy((char *)st.prefs.log_filename, token, sizeof(st.prefs.log_filename));
+        }
+        else if (!strcasecmp("MultiApp", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"MultiApp\" failed");
+            else
+            {
+                if (!strcasecmp("True", token) || !strcasecmp("Yes", token))
+                    st.prefs.multi_app = 1;
+                else if (!strcasecmp("False", token) || !strcasecmp("No", token))
+                    st.prefs.multi_app = 0;
+                else
+                    log_Log(LOG_HIGH, "Invalid MultiApp preference specified: %s", token);
+            }
+        }
+        else if (!strcasecmp("Threaded", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"Threaded\" failed");
+            else
+            {
+                if (!strcasecmp("True", token) || !strcasecmp("Yes", token))
+                    st.prefs.threaded = 1;
+                else if (!strcasecmp("False", token) || !strcasecmp("No", token))
+                    st.prefs.threaded = 0;
+                else
+                    log_Log(LOG_HIGH, "Invalid Threaded preference specified: %s", token);
+            }
+        }
+        else if (!strcasecmp("SlotStatusThreadScheme", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"SlotStatusThreadScheme\" failed");
+            else
+            {
+                if (!strcasecmp("Full", token))
+                    st.prefs.slot_watch_scheme = P11_SLOT_WATCH_THREAD_FULL;
+                else if (!strcasecmp("Partial", token))
+                    st.prefs.slot_watch_scheme = P11_SLOT_WATCH_THREAD_PARTIAL;
+                else
+                    log_Log(LOG_HIGH, "Invalid SlotStatusThreadScheme specified: %s", token);
+            }
+        }
+        else if (!strcasecmp("ObjectSortOrder", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"ObjectSortOrder\" failed");
+            else
+            {
+                if (!strcasecmp("NewestFirst", token))
+                    st.prefs.obj_sort_order = P11_OBJ_SORT_NEWEST_FIRST;
+                else if (!strcasecmp("NewestLast", token))
+                    st.prefs.obj_sort_order = P11_OBJ_SORT_NEWEST_LAST;
+                else
+                    log_Log(LOG_HIGH, "Invalid ObjectSortOrder specified: %s", token);
+            }
+        }
+        else if (!strcasecmp("CachePIN", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"CachePIN\" failed");
+            else
+            {
+                if (!strcasecmp("True", token) || !strcasecmp("Yes", token))
+                    st.prefs.cache_pin = 1;
+                else if (!strcasecmp("False", token) || !strcasecmp("No", token))
+                    st.prefs.cache_pin = 0;
+                else
+                    log_Log(LOG_HIGH, "Invalid cache_pin preference specified: %s", token);
+            }
+        }
+        else if (!strcasecmp("Version", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"Version\" failed");
+            else
+            {
+                char *pos;
+
+                pos = strchr(token, '.');
+                if (!pos)
+                    P11_ERR("Config option \"Version\" failed");
+                else
+                {
+                    *pos = 0;
+                    st.prefs.version_major = atol(token);
+                    st.prefs.version_minor = atol(pos + 1);
+                }
+            }
+        }
+        else if (!strcasecmp("MaxPinTries", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"MaxPinTries\" failed");
+            else
+                st.prefs.max_pin_tries = atol(token);
+        }
+        else if (!strcasecmp("SOUserPinNum", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"SOUserPinNum\" failed");
+            else
+                st.prefs.so_user_pin_num = atol(token);
+        }
+        else if (!strcasecmp("UserPinNum", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"UserPinNum\" failed");
+            else
+                st.prefs.user_pin_num = atol(token);
+        }
+        else if (!strcasecmp("CertAttribSize", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"CertAttribSize\" failed");
+            else
+                st.prefs.cert_attrib_size = atol(token);
+        }
+        else if (!strcasecmp("PubKeyAttribSize", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"PubKeyAttribSize\" failed");
+            else
+                st.prefs.pubkey_attrib_size = atol(token);
+        }
+        else if (!strcasecmp("PrvKeyAttribSize", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"PrvKeyAttribSize\" failed");
+            else
+                st.prefs.prvkey_attrib_size = atol(token);
+        }
+        else if (!strcasecmp("DataAttribSize", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"DataAttribSize\" failed");
+            else
+                st.prefs.data_attrib_size = atol(token);
+        }
+        else if (!strcasecmp("DisableSecurity", token))
+        {
+            token = strtok_r(0, sep, &strtok_ptr);
+            if (!token)
+                P11_ERR("Config option \"DisableSecurity\" failed");
+            else
+            {
+                if (!strcasecmp("True", token) || !strcasecmp("Yes", token))
+                    st.prefs.disable_security = 1;
+                else if (!strcasecmp("False", token) || !strcasecmp("No", token))
+                    st.prefs.disable_security = 0;
+                else
+                    log_Log(LOG_HIGH, "Invalid DisableSecurity preference specified: %s", token);
+            }
+        }
+    }
+}
+
+/******************************************************************************
+** Function: util_ReadPreferences
+**
+** Gets preferences, if available.  On UNIX, looks for .pkcs11rc
+** in the $HOME directory, or root directory if $HOME is not 
+** defined.  Having a preferences file is optional and it is assumed
+** that most of the time users will not have one unless debug/logging
+** or other special settings are required.
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+#ifndef WIN32
+CK_RV util_ReadPreferences()
+{
+    CK_RV rv = CKR_OK;
+    FILE *fp;
+    char rcfilepath[256];
+    char rcfilename[] = "/.pkcs11rc";
+    char buf[1024];
+
+    strncpy(rcfilepath, getenv("HOME"), sizeof(rcfilepath) - sizeof(rcfilename) - 1);
+    strcat(rcfilepath, rcfilename);
+
+    fp = fopen(rcfilepath, "rb");
+    if (fp)
+    {
+        while (fgets(buf, sizeof(buf), fp))
+            util_ParsePreference(buf, sizeof(buf));
+
+        fclose(fp);
+    }
+
+    return rv;
+}
+#else
+CK_RV util_ReadPreferences()
+{
+    CK_RV rv = CKR_OK;
+    FILE *fp;
+    char rcfilepath[] = "C:\\Program Files\\Muscle\\pkcs11rc";
+    char buf[1024];
+
+    fp = fopen(rcfilepath, "rb");
+    if (fp)
+    {
+        while (fgets(buf, sizeof(buf), fp))
+            util_ParsePreference(buf, sizeof(buf));
+
+        fclose(fp);
+    }
+
+    return rv;
+    
+}
+#endif
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_session.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_session.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_session.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,114 @@
+/******************************************************************************
+** 
+**  $Id: p11x_session.c,v 1.2 2003/02/13 20:06:41 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Session & object management functions
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/******************************************************************************
+** Function: session_AddSession
+**
+** Adds a new session 
+**
+** Parameters:
+**  phSession - Returns a pointer to the new session
+**
+** Returns:
+**  CKR_HOST_MEMORY if memory alloc failed
+**  CKR_OK
+*******************************************************************************/
+CK_RV session_AddSession(CK_SESSION_HANDLE *phSession)
+{
+    CK_RV rv = CKR_OK;
+
+    *phSession = 0;
+
+    if (st.sessions)
+    {
+        st.sessions->prev = (P11_Session *)calloc(1, sizeof(P11_Session));
+        if (!st.sessions->prev)
+            rv = CKR_HOST_MEMORY;
+        else
+        {
+            st.sessions->prev->next = st.sessions;
+            st.sessions = st.sessions->prev;
+            st.sessions->check = st.sessions;
+            *phSession = (CK_SESSION_HANDLE)st.sessions;
+        }
+    }
+    else
+    {
+        st.sessions = (P11_Session *)calloc(1, sizeof(P11_Session));
+        if (!st.sessions)
+            rv = CKR_HOST_MEMORY;
+        else
+        {
+            st.sessions->check = st.sessions;
+            *phSession = (CK_SESSION_HANDLE)st.sessions;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: session_FreeSession
+**
+** Deletes/removes a session
+**
+** Parameters:
+**  hSession - Handle of session to remove
+**
+** Returns:
+**  CKR_SESSION_HANDLE_INVALID if session handle is invalid
+**  CKR_OK
+*******************************************************************************/
+CK_RV session_FreeSession(CK_SESSION_HANDLE hSession)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session = (P11_Session *)hSession;
+
+    if (INVALID_SESSION)
+        rv = CKR_SESSION_HANDLE_INVALID;
+    else
+    {
+        log_Log(LOG_LOW, "Removing session: %lX", hSession);
+
+        if (session->prev) /* Fixme: check for head of list? st.sessions */
+        {
+            session->prev->next = session->next;
+
+            if (session == st.sessions) /* Fixme: Is this needed? */
+                st.sessions = session->prev;
+        }
+
+        if (session->next)
+        {
+            session->next->prev = session->prev;
+
+            if (session == st.sessions)
+                st.sessions = session->next;
+        }
+
+        if (!session->prev && !session->next)
+            st.sessions = 0x00;
+
+        if (session->search_attrib)
+            free(session->search_attrib);
+        
+        /* Clear memory, just to be safe */
+        memset(session, 0x00, sizeof(P11_Session));
+    
+        free(session);
+    }
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_slot.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_slot.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_slot.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1203 @@
+/******************************************************************************
+** 
+**  $Id: p11x_slot.c,v 1.2 2003/02/13 20:06:41 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Slot management functions
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/******************************************************************************
+** Function: slot_BeginTransaction
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV slot_BeginTransaction(CK_ULONG slotID)
+{
+    CK_RV rv = CKR_OK;
+    MSC_RV msc_rv;
+
+    log_Log(LOG_LOW, "Begin transaction: %lu", slotID);
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else if (CKR_ERROR(rv = slot_EstablishConnection(slotID)))
+        rv = rv;
+    else if (MSC_ERROR(msc_rv = msc_BeginTransaction(&st.slots[slotID - 1].conn)))
+    {
+        slot_ReleaseConnection(slotID);
+
+        if ((msc_rv == MSC_TOKEN_RESET) || (msc_rv == MSC_TOKEN_REMOVED))
+            rv = CKR_DEVICE_REMOVED;
+        else
+            rv = CKR_FUNCTION_FAILED;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_EndTransaction
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV slot_EndTransaction(CK_ULONG slotID, CK_ULONG action)
+{
+    CK_RV rv = CKR_OK;
+
+    log_Log(LOG_LOW, "End transaction: %lu", slotID);
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else if (MSC_ERROR(msc_EndTransaction(&st.slots[slotID - 1].conn, action)))
+        rv = CKR_FUNCTION_FAILED;
+    else if (st.prefs.threaded)
+        (void)CKR_ERROR(rv = slot_ReleaseConnection(slotID));
+
+    return rv;
+}
+
+/*
+** Checks for an open RW SO session
+*/
+/******************************************************************************
+** Function: slot_CheckRWSOsession
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_BBOOL slot_CheckRWSOsession(CK_ULONG slotID)
+{
+    CK_BBOOL rv = FALSE;
+    P11_Session *session_l;
+
+    session_l = st.sessions;
+    while (session_l)
+    {
+        if ((session_l->session.slotID == slotID) && 
+            (session_l->session.state == CKS_RW_SO_FUNCTIONS))
+        {
+            rv = TRUE;
+            break;
+        }
+
+        session_l = session_l->next;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_EstablishConnection
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV slot_EstablishConnection(CK_ULONG slotID)
+{
+    CK_RV rv = CKR_OK;
+    MSC_RV msc_rv;
+    MSCTokenInfo token_info;
+    P11_Slot *slot;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else if (CKR_ERROR(rv = slot_TokenPresent(slotID)))
+        /* Return error */;
+    else 
+    {
+        slot = &st.slots[slotID - 1];
+
+        log_Log(LOG_LOW, "Attempting establish");
+
+        if (!slot->conn.hCard)
+        {
+            log_Log(LOG_LOW, "Establish connection");
+
+            memcpy(&token_info, &slot->conn.tokenInfo, sizeof(MSCTokenInfo));
+            if (MSC_ERROR(msc_rv = msc_EstablishConnection(&token_info, 
+                                                 MSC_SHARE_SHARED,
+                                                 NULL, 0,
+                                                 &slot->conn)))
+            {
+                /* memset(&slot->conn, 0x00, sizeof(slot->conn)); */
+                /* memcpy(&slot->conn.tokenInfo, &token_info, sizeof(MSCTokenInfo)); */
+                st.slot_status[slotID - 1] = 0x01;
+                log_Log(LOG_MED, "MSCEstablishConnection failed");
+
+                if ((msc_rv == MSC_TOKEN_RESET) || (msc_rv == MSC_TOKEN_REMOVED))
+                    rv = CKR_DEVICE_REMOVED;
+                else
+                    rv = CKR_FUNCTION_FAILED;
+            }
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_ReleaseConnection
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV slot_ReleaseConnection(CK_ULONG slotID)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session_l;
+    P11_Slot *slot;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else 
+    {
+        slot = &st.slots[slotID - 1];
+        /* Don't close the connection if a session is using it */
+        /* Fixme: this could be sped up by using reference counting instead */
+        log_Log(LOG_LOW, "Attempting release");
+        session_l = st.sessions;
+
+        while (session_l)
+        {
+            if (session_l->session.slotID == slotID)
+                return rv;
+            session_l = session_l->next;
+        }
+
+        if (slot->conn.hCard)
+        {
+            log_Log(LOG_LOW, "Releasing connection (slot_ReleaseConnection)");
+            (void)MSC_ERROR(msc_ReleaseConnection(&slot->conn, MSC_LEAVE_TOKEN));
+            log_Log(LOG_LOW, "Done releasing (slot_ReleaseConnection)");
+        }
+
+        slot->conn.hCard = 0;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_UpdateSlot
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV slot_UpdateSlot(CK_ULONG slotID)
+{
+    CK_RV rv = CKR_OK;
+    P11_Slot *slot;
+    MSCTokenInfo *token_info;
+    CK_SLOT_INFO *slot_info;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else
+    {
+        slot = &st.slots[slotID - 1];
+        token_info = &slot->conn.tokenInfo;
+        slot_info = &slot->slot_info;
+    
+        token_info->tokenState = MSC_STATE_UNAWARE;
+
+        if (MSC_ERROR(msc_WaitForTokenEvent(token_info, 1, 10000)))
+            rv = CKR_FUNCTION_FAILED;
+        else
+        {
+            util_PadStrSet(slot_info->slotDescription, (CK_CHAR *)token_info->slotName, sizeof(slot_info->slotDescription));
+            util_PadStrSet(slot_info->manufacturerID, (CK_CHAR *)"Unknown MFR", sizeof(slot_info->manufacturerID));
+            /* Fixme: If Netscape does not see a token present, it may mark the slot as bad and never use it */
+            slot_info->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT |
+                               (CKR_ERROR(slot_TokenPresent(slotID)) ? 0x00 : CKF_TOKEN_PRESENT);
+            slot_info->hardwareVersion.major = 0x01; /* Fixme: unsupported */
+            slot_info->hardwareVersion.minor = 0x00; /* Fixme: unsupported */
+            slot_info->firmwareVersion.major = 0x01; /* Fixme: unsupported */
+            slot_info->firmwareVersion.minor = 0x00; /* Fixme: unsupported */
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_VerifyPIN
+**
+** Description
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV slot_VerifyPIN(CK_SLOT_ID slotID, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
+{
+    CK_RV rv = CKR_OK;
+    CK_RV msc_rv = MSC_SUCCESS;
+    P11_Slot *slot;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else
+    {
+        slot = &st.slots[slotID - 1];
+
+        if (userType == CKU_SO)
+            (void)MSC_ERROR(msc_rv = msc_VerifyPIN(&slot->conn, (MSCUChar8)st.prefs.so_user_pin_num, pPin, ulPinLen));
+        else if (userType == CKU_USER)
+            (void)MSC_ERROR(msc_rv = msc_VerifyPIN(&slot->conn, (MSCUChar8)st.prefs.user_pin_num, pPin, ulPinLen));
+        else
+            rv = CKR_USER_TYPE_INVALID;
+    
+        if (msc_rv == MSC_AUTH_FAILED)
+        {
+            P11_ERR("PIN INCORRECT");
+            rv = CKR_PIN_INCORRECT;
+        }
+        else if (msc_rv == MSC_IDENTITY_BLOCKED)
+            rv = CKR_PIN_LOCKED;
+        else if (msc_rv != MSC_SUCCESS)
+            rv = CKR_FUNCTION_FAILED;
+        else if (st.prefs.cache_pin && (userType == CKU_SO))
+        {
+            // Fixme: do padding // encryption is disabled
+            // des_ecb3_encrypt(pPin, slot->pins[CKU_SO].pin, st.pin_key[0], st.pin_key[1], st.pin_key[2], 1);
+            memcpy(slot->pins[CKU_SO].pin, pPin, ulPinLen);
+            slot->pins[0].pin_size = ulPinLen;
+        }
+        else if (st.prefs.cache_pin && (userType == CKU_USER))
+        {
+            // Fixme: do padding // encryption is disabled
+            // des_ecb3_encrypt(pPin, slot->pins[CKU_USER].pin, st.pin_key[0], st.pin_key[1], st.pin_key[2], 1);
+            memcpy(slot->pins[CKU_USER].pin, pPin, ulPinLen);
+            slot->pins[1].pin_size = ulPinLen;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_MinRSAKeySize
+**
+** Returns minimum RSA key size
+**
+** Fixme: does Netscape use # bits or # bytes for RSA mechanisms?? 
+**
+** Parameters:
+**  cap - MSC capabilities
+**
+** Returns:
+**  Length
+*******************************************************************************/
+CK_ULONG slot_MinRSAKeySize(MSCULong32 cap)
+{
+    CK_ULONG rv = 0;
+
+    if (cap & MSC_CAPABLE_RSA_512)
+        rv = 64;
+    else if (cap & MSC_CAPABLE_RSA_768)
+        rv = 96;
+    else if (cap & MSC_CAPABLE_RSA_1024)
+        rv = 128;
+    else if (cap & MSC_CAPABLE_RSA_2048)
+        rv = 256;
+    else if (cap & MSC_CAPABLE_RSA_4096)
+        rv = 512;
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_MaxRSAKeySize
+**
+** Returns maximum RSA key size
+**
+** Fixme: does Netscape use # bits or # bytes for RSA mechanisms?? 
+**
+** Parameters:
+**  cap - MSC capabilities
+**
+** Returns:
+**  Length
+*******************************************************************************/
+CK_ULONG slot_MaxRSAKeySize(MSCULong32 cap)
+{
+    CK_ULONG rv = 0;
+
+    if (cap & MSC_CAPABLE_RSA_4096)
+        rv = 512;
+    else if (cap & MSC_CAPABLE_RSA_2048)
+        rv = 256;
+    else if (cap & MSC_CAPABLE_RSA_1024)
+        rv = 128;
+    else if (cap & MSC_CAPABLE_RSA_768)
+        rv = 96;
+    else if (cap & MSC_CAPABLE_RSA_512)
+        rv = 64;
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_UpdateMechanisms
+**
+** Updates information about the token in a specific slot.  Many of the symmetric
+** algorithms are commented out because they are too slow to use on smartcards
+**
+** Parameters:
+**  slotID - Slot number to update
+**
+** Returns:
+**  CKR_SLOT_ID_INVALID if the slot number is invalid
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_UpdateMechanisms(CK_ULONG slotID)
+{
+    CK_RV rv = CKR_OK;
+    P11_Slot *slot;
+    MSCULong32 len = 0;
+    MSCULong32 crypto_alg = 0;
+    MSCULong32 temp_cap = 0;
+    P11_MechInfo *mech;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else
+    {
+        slot = &st.slots[slotID - 1];
+
+        slot_FreeAllMechanisms(slot->mechanisms);
+        slot->mechanisms = 0;
+
+        if (MSC_ERROR(msc_GetCapabilities(&slot->conn, 
+                                         MSC_TAG_SUPPORT_CRYPTOALG, 
+                                         (MSCUChar8 *)&crypto_alg, 
+                                         &len)))
+            P11_ERR("MSCGetCapabilities failed");
+
+        if (crypto_alg & MSC_SUPPORT_RSA)
+        {
+            log_Log(LOG_LOW, "Card supports RSA");
+
+            slot_AddMechanism(slot, CKM_SHA1_RSA_PKCS, &mech);
+            mech->info.ulMinKeySize = slot_MinRSAKeySize(temp_cap);
+            mech->info.ulMaxKeySize = slot_MaxRSAKeySize(temp_cap);
+            /* Fixme: these flags may be wrong */
+            mech->info.flags = CKF_ENCRYPT |
+                               CKF_DECRYPT |
+                               CKF_SIGN |
+                               CKF_SIGN_RECOVER |
+                               CKF_VERIFY |
+                               CKF_VERIFY_RECOVER |
+                               CKF_GENERATE |
+                               CKF_GENERATE_KEY_PAIR |
+                               CKF_WRAP |
+                               CKF_UNWRAP;
+
+            if (!MSC_ERROR(msc_GetCapabilities(&slot->conn, MSC_TAG_CAPABLE_RSA, 
+                            (MSCUChar8 *)&temp_cap, &len)))
+            {
+                if (temp_cap & MSC_CAPABLE_RSA_KEYGEN)
+                {
+                    log_Log(LOG_LOW, "Card supports RSA key gen");
+                    slot_AddMechanism(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &mech);
+
+                    mech->info.ulMinKeySize = slot_MinRSAKeySize(temp_cap);
+                    mech->info.ulMaxKeySize = slot_MaxRSAKeySize(temp_cap);
+                    /* Fixme: these flags may be wrong */
+                    mech->info.flags = CKF_GENERATE |
+                                       CKF_GENERATE_KEY_PAIR;
+                }
+
+                if (temp_cap & (MSC_CAPABLE_RSA_PKCS1 | MSC_CAPABLE_RSA_NOPAD))
+                {
+                    if (temp_cap & MSC_CAPABLE_RSA_NOPAD)
+                        log_Log(LOG_LOW, "Card supports RSA NOPAD");
+                    
+                    if (temp_cap & MSC_CAPABLE_RSA_PKCS1)
+                        log_Log(LOG_LOW, "Card supports RSA PKCS#1");
+                    
+                    slot_AddMechanism(slot, CKM_RSA_PKCS, &mech);
+
+                    mech->info.ulMinKeySize = slot_MinRSAKeySize(temp_cap);
+                    mech->info.ulMaxKeySize = slot_MaxRSAKeySize(temp_cap);
+                    /* Fixme: these flags may be wrong */
+                    mech->info.flags = CKF_ENCRYPT |
+                                       CKF_DECRYPT | 
+                                       CKF_SIGN | 
+                                       CKF_SIGN_RECOVER | 
+                                       CKF_VERIFY | 
+                                       CKF_VERIFY_RECOVER;
+                    
+                    if (temp_cap & MSC_CAPABLE_RSA_NOPAD)
+                         mech->info.flags =  CKF_WRAP |                                                                                CKF_UNWRAP;
+                }
+            }
+        }
+
+        if (crypto_alg & MSC_SUPPORT_DSA)
+        {
+            log_Log(LOG_LOW, "Card supports DSA");
+            slot_AddMechanism(slot, CKM_DSA, &mech);
+
+            if (!MSC_ERROR(msc_GetCapabilities(&slot->conn, MSC_TAG_CAPABLE_DSA, (MSCUChar8 *)&temp_cap, &len)))
+            {
+                if (temp_cap & MSC_CAPABLE_DSA_KEYGEN)
+                    slot_AddMechanism(slot, CKM_DSA_KEY_PAIR_GEN, &mech);
+            }
+        }
+
+        if (crypto_alg & MSC_SUPPORT_ELGAMAL)
+        {
+            log_Log(LOG_LOW, "Card supports ElGamal");
+            /* Fixme: unsupported */
+        }
+
+        if (crypto_alg & MSC_SUPPORT_DES)
+        {
+            log_Log(LOG_LOW, "Card supports DES but not returning mechanism");
+
+            /*
+            ** if (!MSC_ERROR(msc_GetCapabilities(&slot->conn, MSC_TAG_CAPABLE_DES, (MSCUChar8 *)&des_cap, &len)))
+            ** {
+            **     if (des_cap & MSC_CAPABLE_DES_KEYGEN)
+            **         slot_AddMechanism(slot, CKM_DES_KEY_GEN, &mech);
+            **     if (des_cap & MSC_CAPABLE_DES_CBC)
+            **         slot_AddMechanism(slot, CKM_DES_CBC, &mech);
+            **     if (des_cap & MSC_CAPABLE_DES_ECB)
+            **         slot_AddMechanism(slot, CKM_DES_ECB, &mech);
+            ** }
+            */
+        }
+
+        if (crypto_alg & MSC_SUPPORT_3DES)
+        {
+            log_Log(LOG_LOW, "Card supports 3DES but not returning mechanism");
+
+            /*
+            ** if (!MSC_ERROR(msc_GetCapabilities(&slot->conn, MSC_TAG_CAPABLE_3DES, (MSCUChar8 *)&temp_cap, &len)))
+            ** {
+            **    if (temp_cap & MSC_CAPABLE_3DES_KEYGEN)
+            **        slot_AddMechanism(slot, CKM_DES_KEY_GEN, &mech);
+            **    if (des_cap & MSC_CAPABLE_DES_CBC)
+            **        slot_AddMechanism(slot, CKM_DES3_CBC, &mech);
+            **    if (des_cap & MSC_CAPABLE_DES_ECB)
+            **        slot_AddMechanism(slot, CKM_DES3_ECB, &mech);
+            ** }
+            */
+        }
+
+        if (crypto_alg & MSC_SUPPORT_IDEA)
+        {
+            log_Log(LOG_LOW, "Card supports IDEA");
+            /* Fixme: unsupported */
+        }
+
+        if (crypto_alg & MSC_SUPPORT_AES)
+        {
+            log_Log(LOG_LOW, "Card supports AES");
+            /* Fixme: unsupported */
+        }
+
+        if (crypto_alg & MSC_SUPPORT_BLOWFISH)
+        {
+            log_Log(LOG_LOW, "Card supports BLOWFISH");
+            /* Fixme: unsupported */
+        }
+
+        if (crypto_alg & MSC_SUPPORT_TWOFISH)
+        {
+            log_Log(LOG_LOW, "Card supports TWOFISH");
+            /* Fixme: unsupported */
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_MechanismCount
+**
+** Counts the number of mechanisms in the provided linked list
+**
+** Parameters:
+**  mech - Mechanism list
+**
+** Returns:
+**  Count
+*******************************************************************************/
+CK_ULONG slot_MechanismCount(P11_MechInfo *mech)
+{
+    CK_ULONG count = 0;
+    
+    while (mech)
+    {
+        count++;
+        mech = mech->next;
+    }
+
+    return count;
+}
+
+/******************************************************************************
+** Function: slot_FreeAllMechanisms
+**
+** Recursively frees/deletes all mechanisms in list
+**
+** Parameters:
+**  list - List of mechanisms to free
+**
+** Returns:
+**  none
+*******************************************************************************/
+void slot_FreeAllMechanisms(P11_MechInfo *list)
+{
+    if (list)
+    {
+        if (list->next)
+            slot_FreeAllMechanisms(list->next);
+
+        free(list);
+    }
+}
+
+/******************************************************************************
+** Function: slot_AddMechanism
+**
+** Adds a mechanism to a specific slot
+**
+** Parameters:
+**  slot      - Slot to add mechanism to
+**  type      - Mechanism type
+**  mech_info - Returns new mechanism info
+**
+** Returns:
+**  CKR_HOST_MEMORY if memory alloc fails
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_AddMechanism(P11_Slot *slot, CK_MECHANISM_TYPE type, P11_MechInfo **mech_info)
+{
+    CK_RV rv = CKR_OK;
+
+    if (slot->mechanisms)
+    {
+        slot->mechanisms->prev = (P11_MechInfo *)calloc(1, sizeof(P11_MechInfo));
+        if (!slot->mechanisms->prev)
+            rv = CKR_HOST_MEMORY;
+        else
+        {
+            slot->mechanisms->prev->next = slot->mechanisms;
+            slot->mechanisms = slot->mechanisms->prev;
+            slot->mechanisms->type = type;
+
+            if (mech_info)
+                *mech_info = slot->mechanisms;
+        }
+    }
+    else
+    {
+        slot->mechanisms = (P11_MechInfo *)calloc(1, sizeof(P11_MechInfo));
+        if (!slot->mechanisms)
+            rv = CKR_HOST_MEMORY;
+        else
+        {
+            slot->mechanisms->type = type;
+
+            if (mech_info)
+                *mech_info = slot->mechanisms;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_UpdateToken
+**
+** Updates all information about a token in a slot.
+**
+** Parameters:
+**  slotID - Slot number to update
+**
+** Returns:
+**  CKR_SLOT_ID_INVALID if slotID is invalid
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_UpdateToken(CK_ULONG slotID)
+{
+    CK_RV rv = CKR_OK;
+    P11_Slot *slot;
+    P11_Session *session_l;
+    CK_ULONG sess_count, rw_sess_count;
+    MSCUShort16 pin_bit_mask = 0;
+    MSCULong32 support_func = 0;
+    MSCUChar8 cap_pin_maxsize = 0;
+    MSCUChar8 cap_pin_minsize = 0;
+    MSCULong32 len = 0;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else if (CKR_ERROR((rv = slot_TokenPresent(slotID))))
+        (void)CKR_ERROR(slot_DisconnectSlot(slotID, MSC_RESET_TOKEN));
+    else
+    {
+        slot = &st.slots[slotID - 1];
+
+        if (!MSC_ERROR(msc_GetStatus(&slot->conn, &slot->status_info)) &&
+            !MSC_ERROR(msc_GetCapabilities(&slot->conn, MSC_TAG_SUPPORT_FUNCTIONS, (MSCUChar8 *)&support_func, &len)) &&
+            !MSC_ERROR(msc_GetCapabilities(&slot->conn, MSC_TAG_CAPABLE_PIN_MAXSIZE, &cap_pin_maxsize, &len)) &&
+            !MSC_ERROR(msc_GetCapabilities(&slot->conn, MSC_TAG_CAPABLE_PIN_MINSIZE, &cap_pin_minsize, &len)) &&
+            !MSC_ERROR(msc_ListPINs(&slot->conn, &pin_bit_mask))
+            )
+        {
+            session_l = st.sessions;
+            sess_count = rw_sess_count = 0;
+
+            while (session_l)
+            {
+                if (session_l->session.slotID == slotID)
+                {
+                    sess_count++;
+                    if (session_l->session.flags & CKF_RW_SESSION)
+                        rw_sess_count++;
+                }
+
+                session_l = session_l->next;
+            }
+
+            util_PadStrSet(slot->token_info.label, (CK_CHAR *)slot->conn.tokenInfo.tokenName, sizeof(slot->token_info.label));
+            util_PadStrSet(slot->token_info.manufacturerID, (CK_CHAR *)"Unknown MFR", sizeof(slot->token_info.manufacturerID));
+            util_PadStrSet(slot->token_info.model, (CK_CHAR *)"Unknown Model", sizeof(slot->token_info.model));
+            util_PadStrSet(slot->token_info.serialNumber, (CK_CHAR *)"1", sizeof(slot->token_info.serialNumber)); /* Fixme: */
+            slot->token_info.flags = (support_func & MSC_SUPPORT_GETCHALLENGE ? CKF_RNG : 0x00) |
+                                     CKF_LOGIN_REQUIRED |
+                                     (pin_bit_mask & (1 << st.prefs.user_pin_num) ? CKF_USER_PIN_INITIALIZED : 0x00) |
+                                     CKF_TOKEN_INITIALIZED;
+
+            /* None of these  */  /* CKF_WRITE_PROTECTED | */
+            /* are used (yet) */  /* CKR_RESTORE_KEY_NOT_NEEDED | */ /* Not supported */
+                                  /* CKF_CLOCK_ON_TOKEN | */
+                                  /* CKF_PROTECTED_AUTHENICATION_PATH | */
+                                  /* CKF_DUAL_CRYPTO_OPERATIONS | */
+                                  /* CKF_SECONDARY_AUTHENTICATION | */
+                                  /* CKF_USER_PIN_COUNT_LOW | */
+                                  /* CKF_USER_PIN_FINAL_TRY | */
+                                  /* CKF_USER_PIN_LOCKED | */
+                                  /* CKF_USER_PIN_TO_BE_CHANGED | */
+                                  /* CKF_SO_PIN_COUNT_LOW | */
+                                  /* CKF_SO_PIN_FINAL_TRY | */
+                                  /* CKF_SO_PIN_LOCKED | */
+                                  /* CKF_SO_PIN_TO_BE_CHANGED | */
+
+            slot->token_info.ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
+            slot->token_info.ulSessionCount = sess_count;
+            slot->token_info.ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
+            slot->token_info.ulRwSessionCount = rw_sess_count;
+            slot->token_info.ulMaxPinLen = cap_pin_maxsize;
+            slot->token_info.ulMinPinLen = cap_pin_minsize;
+            slot->token_info.ulTotalPublicMemory = slot->status_info.totalMemory;  /* Fixme: Does this conflict */
+            slot->token_info.ulFreePublicMemory = slot->status_info.freeMemory;    /* with the private memory? */
+            slot->token_info.ulTotalPrivateMemory = slot->status_info.totalMemory; /* Fixme: Does this conflict */
+            slot->token_info.ulFreePrivateMemory = slot->status_info.freeMemory;   /* with the public memory? */
+            slot->token_info.hardwareVersion.major = ((char *)(&slot->status_info.swVersion))[0];  /* Fixme: endian?? */;
+            slot->token_info.hardwareVersion.minor = ((char *)(&slot->status_info.swVersion))[1];
+            slot->token_info.firmwareVersion.major = ((char *)(&slot->status_info.appVersion))[0]; /* Fixme: endian?? */
+            slot->token_info.firmwareVersion.minor = ((char *)(&slot->status_info.appVersion))[1];
+            memset(slot->token_info.utcTime, '0', sizeof(slot->token_info.utcTime));
+
+            log_Log(LOG_LOW, "Token: %s", slot->conn.tokenInfo.tokenName);
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_UpdateSlotList
+**
+** Updates information about all connected slots
+**
+** Note: this wipes out all current sessions and objects
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_UpdateSlotList()
+{
+    CK_RV rv = CKR_OK;
+    CK_ULONG i;
+    MSCTokenInfo *tokenArray = 0;
+    MSCULong32 arrayLength = 0;
+
+    /* Fixme: What happens if there are no readers connected? */
+    if (MSC_ERROR(msc_ListTokens(MSC_LIST_SLOTS, NULL, &arrayLength)))
+    {
+        rv = CKR_FUNCTION_FAILED;
+        P11_ERR("MSCListTokens failed");
+    }
+    else
+    {
+        tokenArray = (MSCTokenInfo *)calloc(arrayLength, sizeof(MSCTokenInfo));
+    
+        if (!tokenArray)
+            rv = CKR_HOST_MEMORY;
+        else if (MSC_ERROR(msc_ListTokens(MSC_LIST_SLOTS, tokenArray, &arrayLength)))
+        {
+            rv = CKR_FUNCTION_FAILED;
+            P11_ERR("MSCListTokens failed");
+        }
+        else
+        {
+            slot_FreeAllSlots();
+        
+            st.slots = (P11_Slot *)calloc(arrayLength, sizeof(P11_Slot));
+        
+            if (!st.slots)
+            {
+                rv = CKR_HOST_MEMORY;
+                P11_ERR("calloc failed");
+            }
+            else for (i = 0; i < arrayLength; i++)
+            {
+                memcpy(&st.slots[i].conn.tokenInfo, &tokenArray[i], sizeof(MSCTokenInfo));
+                st.slot_count = i + 1;
+                log_Log(LOG_LOW, "Added reader: %s", tokenArray[i].slotName);
+            }
+        
+            if (CKR_ERROR(rv) && st.slots)
+            {
+                free(st.slots);
+                st.slots = 0;
+            }
+        }
+    }
+
+    if (tokenArray)
+        free(tokenArray);
+        
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_FreeAllSlots
+**
+** Releases all slots and all tokens.  This assumes you are shutting down and
+** therefore cannot fail.
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_FreeAllSlots()
+{
+    CK_RV rv = CKR_OK;
+    CK_ULONG i;
+
+    if (st.slots)
+    {
+        for (i = 1; i <= st.slot_count; i++)
+            slot_DisconnectSlot(i, MSC_RESET_TOKEN); /* Fixme: Don't care if this fails? */
+
+        free(st.slots);
+        log_Log(LOG_LOW, "Freed st.slots");
+
+        st.slots = 0;
+        st.slot_count = 0;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_DisconnectSlot
+**
+** Releases a slot and all information about any tokens in the slot.
+**
+** Parameters:
+**  slotID - Slot number to release
+**  action - A valid MSC card action: MSC_RESET_TOKEN or MSC_LEAVE_TOKEN
+**
+** Returns:
+**  CKR_SLOT_ID_INVALID if slotID is invalid
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_DisconnectSlot(CK_ULONG slotID, CK_ULONG action)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session_l;
+    P11_Slot *slot;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else
+    {
+        slot = &st.slots[slotID - 1];
+        session_l = st.sessions;
+
+        while (session_l)
+        {
+            if (session_l->session.slotID == slotID)
+                session_FreeSession((CK_SESSION_HANDLE)session_l);
+
+            session_l = st.sessions;
+        }
+
+        object_FreeAllObjects(slotID, st.slots[slotID - 1].objects);
+        slot_FreeAllMechanisms(slot->mechanisms);
+        slot->mechanisms = 0;
+        memset(slot->pins, 0x00, sizeof(slot->pins));
+        slot->pin_state = 0;
+        slot_BlankTokenInfo(&slot->token_info);
+
+        memset(&slot->status_info, 0x00, sizeof(slot->status_info));
+
+        if (slot->conn.hCard)
+        {
+            log_Log(LOG_LOW, "Releasing connection (slot_DisconnectSlot)");
+            (void)MSC_ERROR(msc_ReleaseConnection(&slot->conn, action));
+        }
+
+        slot->conn.hCard = 0;
+        slot->slot_info.flags = (slot->slot_info.flags & ~CKF_TOKEN_PRESENT);
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_PublicMode
+**
+** Switchs all sessions of a slot to PUBLIC mode (versus USER or SO mode)
+**
+** Parameters:
+**  slotID - Slot number
+**
+** Returns:
+**  CKR_SLOT_ID_INVALID if slotID is invalid
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_PublicMode(CK_ULONG slotID)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session_l;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else
+    {
+        st.slots[slotID - 1].pin_state = 0; /* Fixme: create #define for this */
+
+        session_l = st.sessions;
+        while (session_l)
+        {
+            if (session_l->session.slotID == slotID)
+            {
+                switch (session_l->session.state)
+                {
+                case CKS_RO_USER_FUNCTIONS:
+                    session_l->session.state = CKS_RO_PUBLIC_SESSION;
+                    break;
+                case CKS_RW_USER_FUNCTIONS:
+                    session_l->session.state = CKS_RW_PUBLIC_SESSION;
+                    break;
+                case CKS_RW_SO_FUNCTIONS: /* Fixme: can't really handle this one well */
+                    session_l->session.state = CKS_RO_PUBLIC_SESSION;
+                    break;
+                default:
+                    break;
+                }
+
+                session_l->session.flags = (session_l->session.flags & ~CKF_RW_SESSION);
+            }
+
+            session_l = session_l->next;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_UserMode
+**
+** Switchs all sessions of a slot to USER mode (versus PUBLIC or SO mode)
+**
+** Parameters:
+**  slotID - Slot number
+**
+** Returns:
+**  CKR_SLOT_ID_INVALID if slotID is invalid
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_UserMode(CK_ULONG slotID)
+{
+    CK_RV rv = CKR_OK;
+    P11_Session *session_l;
+
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else
+    {
+        st.slots[slotID - 1].pin_state = 1; /* Fixme: create #define for this */
+
+        session_l = st.sessions;
+        while (session_l)
+        {
+            if (session_l->session.slotID == slotID)
+            {
+                switch (session_l->session.state)
+                {
+                case CKS_RO_PUBLIC_SESSION:
+                    object_UserMode((CK_SESSION_HANDLE)session_l);
+                    session_l->session.state = CKS_RO_USER_FUNCTIONS;
+                    break;
+                case CKS_RW_PUBLIC_SESSION:
+                    object_UserMode((CK_SESSION_HANDLE)session_l);
+                    session_l->session.state = CKS_RW_USER_FUNCTIONS;
+                    break;
+                default:
+                    break;
+                }
+
+                session_l->session.flags = (session_l->session.flags | CKF_RW_SESSION);
+            }
+
+            session_l = session_l->next;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_TokenPresent
+**
+** Checks if a token is present in a slot
+**
+** Parameters:
+**  slotID - Slot number to check
+**
+** Returns:
+**  CKR_SLOT_ID_INVALID if slotID is invalid
+**  CKR_TOKEN_NOT_PRESENT or CKR_TOKEN_NOT_RECOGNIZED
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_TokenPresent(CK_ULONG slotID)
+{
+    CK_RV rv;
+
+    /* Fixme: Use the MSC tests */
+    if (INVALID_SLOT)
+        rv = CKR_SLOT_ID_INVALID;
+    else if (strcmp(st.slots[slotID - 1].conn.tokenInfo.tokenName, MSC_TOKEN_EMPTY_STR) == 0)
+        rv = CKR_TOKEN_NOT_PRESENT;
+    else if (strcmp(st.slots[slotID - 1].conn.tokenInfo.tokenName, MSC_TOKEN_UNKNOWN_STR) == 0)
+        rv = CKR_TOKEN_NOT_RECOGNIZED;
+    else
+        rv = CKR_OK;
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_TokenChanged
+**
+** Master routine that checks the status of a token.  This calls
+** slot_UpdateToken and slot_UpdateMechanisms to update information about the
+** current token.  If a token status has not changed then this function does
+** not do anything.
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_CRYPTOKI_NOT_INITIALIZED
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_TokenChanged()
+{
+    CK_RV rv = CKR_OK;
+    CK_ULONG i;
+    P11_Session *sess;
+
+    sess = st.sessions;
+    log_Log(LOG_LOW, "Active session list:");
+    while (sess)
+    {
+        log_Log(LOG_LOW, "Session ID: %X", sess);
+        sess = sess->next;
+    }
+
+    if (!st.initialized)
+        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+    else if (!st.slot_status || !st.slots)
+        rv = CKR_FUNCTION_FAILED;
+    else
+        for (i = 0; i < st.slot_count; i++)
+        {
+            if (!st.prefs.threaded && !(st.slots[i].slot_info.flags & CKF_TOKEN_PRESENT))
+            {
+                slot_UpdateSlot(i + 1);
+                if ((st.slots[i].slot_info.flags & CKF_TOKEN_PRESENT))
+                    st.slot_status[i] = 0x01;
+            }
+
+            /* Old code, may still be useful; handles reset differently
+            if (st.slot_status[i] || (st.slots[i].conn.hCard &&
+                (msc_IsTokenReset(&st.slots[i].conn) || msc_IsTokenMoved(&st.slots[i].conn))))
+            */
+
+            if (st.slot_status[i] || (st.slots[i].conn.hCard &&
+                msc_IsTokenMoved(&st.slots[i].conn)))
+            {
+                if (st.slots[i].conn.hCard)
+                    msc_ClearReset(&st.slots[i].conn);
+
+                log_Log(LOG_LOW, "Slot %d changed", i + 1);
+
+                slot_DisconnectSlot(i + 1, MSC_RESET_TOKEN);
+                slot_UpdateSlot(i + 1);
+
+                if (!CKR_ERROR(slot_BeginTransaction(i + 1)))
+                {
+                    (void)CKR_ERROR(slot_UpdateToken(i + 1));
+                    (void)CKR_ERROR(slot_UpdateMechanisms(i + 1));
+                    (void)CKR_ERROR(slot_EndTransaction(i + 1, MSC_LEAVE_TOKEN));
+                }
+    
+                st.slot_status[i] = 0x00;
+
+                if (st.slots[i].conn.hCard)
+                    rv = CKR_DEVICE_REMOVED;
+            }
+        }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: slot_BlankTokenInfo
+**
+** Sets a CK_TOKEN_INFO structure to blank data
+**
+** Parameters:
+**  token_info - Structure to blank
+**
+** Returns:
+**  none
+*******************************************************************************/
+void slot_BlankTokenInfo(CK_TOKEN_INFO *token_info)
+{
+    memset(token_info, 0x00, sizeof(MSCTokenInfo));
+
+    util_PadStrSet(token_info->label, (CK_CHAR *)"", sizeof(token_info->label));
+    util_PadStrSet(token_info->manufacturerID, (CK_CHAR *)"", sizeof(token_info->manufacturerID));
+    util_PadStrSet(token_info->model, (CK_CHAR *)"", sizeof(token_info->model));
+    util_PadStrSet(token_info->serialNumber, (CK_CHAR *)"", sizeof(token_info->serialNumber));
+    memset(token_info->utcTime, '0', sizeof(token_info->utcTime));
+}
+
+/******************************************************************************
+** Function: slot_ReverifyPins()
+**
+** Reverifies cached PIN's.  If any cached PIN fails to verify then this will
+** kill that PIN so that it won't be used again.  This is to prevent the
+** caching mechanism from inadvertantly locking a token.
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  Error from slot_VerifyPIN
+**  CKR_OK
+*******************************************************************************/
+CK_RV slot_ReverifyPins()
+{
+    CK_RV rv = CKR_OK;
+    CK_ULONG i;
+
+    log_Log(LOG_LOW, "Reverifying all cached PIN's");
+
+    for (i = 0; i < st.slot_count; i++)
+    {
+        if (st.slots[i].conn.hCard && msc_IsTokenReset(&st.slots[i].conn))
+        {
+            msc_ClearReset(&st.slots[i].conn);
+
+            if (st.slots[i].pins[CKU_SO].pin_size)
+                rv = slot_VerifyPIN(i + 1, 
+                                    CKU_SO, 
+                                    st.slots[i].pins[CKU_SO].pin, 
+                                    st.slots[i].pins[CKU_SO].pin_size);
+        
+            if (CKR_ERROR(rv))
+            {
+                st.slots[i].pins[CKU_SO].pin_size = 0;
+                memset(st.slots[i].pins[CKU_SO].pin, 0x00, sizeof(st.slots[i].pins[CKU_SO].pin));
+            }
+            else if (st.slots[i].pins[CKU_USER].pin_size)
+            {
+                rv = slot_VerifyPIN(i + 1, 
+                                    CKU_USER, 
+                                    st.slots[i].pins[CKU_USER].pin, 
+                                    st.slots[i].pins[CKU_USER].pin_size);
+        
+                if (CKR_ERROR(rv))
+                {
+                    st.slots[i].pins[CKU_USER].pin_size = 0;
+                    memset(st.slots[i].pins[CKU_USER].pin, 0x00, sizeof(st.slots[i].pins[CKU_USER].pin));
+                }
+                else
+                    slot_UserMode(i + 1);
+            }
+        }
+    }
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_state.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_state.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_state.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,108 @@
+/******************************************************************************
+** 
+**  $Id: p11x_state.c,v 1.2 2003/02/13 20:06:42 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Global state functions
+** 
+******************************************************************************/
+
+#include "cryptoki.h"
+
+/* Global state variable */
+P11_State st = { 0,                             /* initialized             */
+                 { 0,                           /* prefs.multi_app         */
+                   0,                           /* prefs.threaded          */
+                   LOG_HIGH,                    /* prefs.log_level         */
+                   P11_OBJ_SORT_NEWEST_FIRST,   /* prefs.obj_sort_order    */
+                   P11_SLOT_WATCH_THREAD_FULL,  /* prefs.slot_watch_scheme */
+                   0,                           /* prefs.cache_pin         */
+                   PKCS11_MAJOR,                /* prefs.version_major     */
+                   PKCS11_MINOR,                /* prefs.version_minor     */
+                   PKCS11_MAX_PIN_TRIES,        /* prefs.max_pin_tries     */
+                   PKCS11_SO_USER_PIN,          /* prefs.so_user_pin_num   */
+                   PKCS11_USER_PIN,             /* prefs.user_pin_num      */
+                   P11_DEFAULT_CERT_ATTRIB_OBJ_SIZE, /* prefs.cert_attrib_size  */
+                   P11_DEFAULT_ATTRIB_OBJ_SIZE,      /* prefs.pubkey_attrib_size*/
+                   P11_DEFAULT_PRK_ATTRIB_OBJ_SIZE,  /* prefs.prvkey_attrib_size*/
+                   P11_DEFAULT_ATTRIB_OBJ_SIZE,      /* prefs.data_attrib_size  */
+                   0,                                /* prefs.disable_security  */
+                   P11_DEFAULT_LOG_FILENAME },       /* prefs.log_filename      */
+                 0,                             /* slots                   */ 
+                 0,                             /* slot_count              */
+                 0,                             /* sessions                */
+                 0,                             /* slot_status             */
+                 0,                             /* log_lock                */
+                 0,                             /* async_lock              */
+                 0,                             /* native_locks            */
+                 0                              /* create_threads          */
+               };
+
+/******************************************************************************
+** Function: state_Init
+**
+** Initializes global state.  Read preferences via util_ReadPreferences
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_HOST_MEMORY if memory alloc fails
+**  CKR_OK
+*******************************************************************************/
+CK_RV state_Init()
+{
+    CK_RV rv = CKR_OK;
+
+    if (!st.initialized)
+        util_ReadPreferences();
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: state_Free
+**
+** Frees the global state information
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  Error from slot_FreeAllSlots (not checked and everything gets blasted)
+**  CKR_OK
+*******************************************************************************/
+CK_RV state_Free()
+{
+    CK_RV rv = CKR_OK;
+
+    if (st.initialized)
+    {
+        rv = slot_FreeAllSlots();
+    
+        if (st.log_lock)
+        {
+            thread_MutexDestroy(st.log_lock);
+            free(st.log_lock);
+            st.log_lock = 0;
+        }
+    
+        if (st.async_lock)
+        {
+            thread_MutexDestroy(st.async_lock);
+            free(st.async_lock);
+            st.async_lock = 0;
+        }
+    
+        if (st.prefs.threaded)
+            thread_Finalize();
+    
+        st.initialized = 0;
+    }
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_thread.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_thread.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_thread.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,256 @@
+/******************************************************************************
+**
+**  $Id: p11x_thread.c,v 1.2 2003/02/13 20:06:42 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Thread functions.  This should probably just use the Musclecard
+**           framework functions instead (if in native mode).
+**
+******************************************************************************/
+
+#include "cryptoki.h"
+
+#include "thread_generic.h"
+
+static int (*p11_pthread_mutex_init)(PCSCLITE_MUTEX_T mMutex) = 0;
+static int (*p11_pthread_mutex_destroy)(PCSCLITE_MUTEX_T mMutex) = 0;
+static int (*p11_pthread_mutex_lock)(PCSCLITE_MUTEX_T mMutex) = 0;
+static int (*p11_pthread_mutex_unlock)(PCSCLITE_MUTEX_T mMutex) = 0;
+
+static CK_CREATEMUTEX p11_createmutex = 0;
+static CK_DESTROYMUTEX p11_destroymutex = 0;
+static CK_LOCKMUTEX p11_lockmutex = 0;
+static CK_UNLOCKMUTEX p11_unlockmutex = 0;
+
+/******************************************************************************
+** Function: thread_Initialize
+**
+** Initializes the thread subsystem
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_FUNCTION_FAILED on error
+**  CKR_OK
+*******************************************************************************/
+CK_RV thread_Initialize()
+{
+    CK_RV rv = CKR_OK;
+
+#ifdef HAVE_LIBPTHREAD
+    if (st.prefs.threaded && st.native_locks)
+    {
+        p11_pthread_mutex_init = SYS_MutexInit;
+        p11_pthread_mutex_destroy = SYS_MutexDestroy;
+        p11_pthread_mutex_lock = SYS_MutexLock;
+        p11_pthread_mutex_unlock = SYS_MutexUnLock;
+    }
+#else
+    P11_ERR("Trying to initialize thread subsystem while threads are disabled");
+    rv = CKR_FUNCTION_FAILED;
+#endif
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: thread_InitFunctions
+**
+** Initializes the thread subsystem to use external locking mechanisms
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_ARGUMENTS_BAD if any function is null
+**  CKR_FUNCTION_FAILED on error
+**  CKR_OK
+*******************************************************************************/
+CK_RV thread_InitFunctions(CK_CREATEMUTEX fn_createmutex,
+                           CK_DESTROYMUTEX fn_destroymutex,
+                           CK_LOCKMUTEX fn_lockmutex,
+                           CK_UNLOCKMUTEX fn_unlockmutex)
+{
+    CK_RV rv = CKR_OK;
+
+    if (!st.prefs.threaded)
+        rv = CKR_FUNCTION_FAILED;
+    else
+    {
+        if (!fn_createmutex || !fn_destroymutex || !fn_lockmutex || !fn_unlockmutex)
+            rv = CKR_ARGUMENTS_BAD;
+        else
+        {
+            log_Log(LOG_LOW, "Using application supplied locking functions");
+            p11_createmutex = fn_createmutex;
+            p11_destroymutex = fn_destroymutex;
+            p11_lockmutex = fn_lockmutex;
+            p11_unlockmutex = fn_unlockmutex;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: thread_Finalize
+**
+** Unloads the Pthread library
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV thread_Finalize()
+{
+    CK_RV rv = CKR_OK;
+
+    if (st.prefs.threaded)
+    {
+        p11_pthread_mutex_init = 0;
+        p11_pthread_mutex_destroy = 0;
+        p11_pthread_mutex_lock = 0;
+        p11_pthread_mutex_unlock = 0;
+        p11_createmutex = 0;
+        p11_destroymutex = 0;
+        p11_lockmutex = 0;
+        p11_unlockmutex = 0;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: thread_MutexInit
+**
+** Initializes a mutex
+**
+** Parameters:
+**  mutex - Pointer to mutex memory
+**
+** Returns:
+**  CKR_HOST_MEMORY on memory alloc error
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV thread_MutexInit(P11_Mutex *mutex)
+{
+    CK_RV rv = CKR_OK;
+
+    if (st.prefs.threaded)
+    {
+        if (st.native_locks && mutex && p11_pthread_mutex_init)
+        {
+            *mutex = (P11_Mutex *)malloc(sizeof(PCSCLITE_MUTEX));
+
+            if (!*mutex)
+                rv = CKR_HOST_MEMORY;
+            else
+                p11_pthread_mutex_init((PCSCLITE_MUTEX_T)*mutex);
+        }
+        else if (!st.native_locks && mutex && p11_createmutex)
+            p11_createmutex(mutex);
+        else
+            rv = CKR_FUNCTION_FAILED;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: thread_MutexDestroy
+**
+** Destroys a mutex
+**
+** Parameters:
+**  mutex - Pointer to mutex memory
+**
+** Returns:
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV thread_MutexDestroy(P11_Mutex mutex)
+{
+    CK_RV rv = CKR_OK;
+
+    if (st.prefs.threaded)
+    {
+        if (st.native_locks && mutex && p11_pthread_mutex_destroy)
+        {
+            p11_pthread_mutex_destroy((PCSCLITE_MUTEX_T)mutex);
+            free(mutex);
+        }
+        else if (!st.native_locks && mutex && p11_destroymutex)
+            p11_destroymutex(mutex);
+        else
+            rv = CKR_FUNCTION_FAILED;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: thread_MutexLock
+**
+** Locks a mutex
+**
+** Parameters:
+**  mutex - Pointer to mutex memory
+**
+** Returns:
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV thread_MutexLock(P11_Mutex mutex)
+{
+    CK_RV rv = CKR_OK;
+
+    if (st.prefs.threaded)
+    {
+        if (st.native_locks && mutex && p11_pthread_mutex_lock)
+            p11_pthread_mutex_lock((PCSCLITE_MUTEX_T)mutex);
+        else if (!st.native_locks && mutex && p11_lockmutex)
+            p11_lockmutex(mutex);
+        else
+            rv = CKR_FUNCTION_FAILED;
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: thread_MutexUnlock
+**
+** Unlocks a mutex
+**
+** Parameters:
+**  mutex - Pointer to mutex memory
+**
+** Returns:
+**  CKR_FUNCTION_FAILED on general error
+**  CKR_OK
+*******************************************************************************/
+CK_RV thread_MutexUnlock(P11_Mutex mutex)
+{
+    CK_RV rv = CKR_OK;
+
+    if (st.prefs.threaded)
+    {
+        if (st.native_locks && mutex && p11_pthread_mutex_unlock)
+            p11_pthread_mutex_unlock((PCSCLITE_MUTEX_T)mutex);
+        else if (!st.native_locks && mutex && p11_unlockmutex)
+            p11_unlockmutex(mutex);
+        else
+            rv = CKR_FUNCTION_FAILED;
+    }
+
+    return rv;
+}
+

Added: trunk/SmartCardServices/src/PKCS11/p11x_unixdll.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_unixdll.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_unixdll.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,24 @@
+/******************************************************************************
+** 
+**  $Id: p11x_unixdll.c,v 1.2 2003/02/13 20:06:42 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Support for Linux (maybe others) shared library unloading.
+**           This will automatically get called by the runtime system when the
+**           library is finalized (just in case the application hasn't closed
+**           everything down). 
+** 
+******************************************************************************/
+#ifdef __USE_FINI__
+
+#include "cryptoki.h"
+
+void _fini()
+{
+   C_Finalize(0);
+}
+
+#endif

Added: trunk/SmartCardServices/src/PKCS11/p11x_util.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_util.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_util.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,175 @@
+/******************************************************************************
+** 
+**  $Id: p11x_util.c,v 1.2 2003/02/13 20:06:42 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Utility functions
+** 
+******************************************************************************/
+
+#include <stdio.h>
+#include "cryptoki.h"
+
+/******************************************************************************
+** Function: util_byterev
+**
+** Reverses a byte string in-place
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+void util_byterev(CK_BYTE *data, CK_ULONG len)
+{
+    CK_ULONG i;
+    CK_BYTE temp;
+
+    for (i = 0; i < len / 2; i++)
+    {
+        temp = data[i];
+        data[i] = data[len - i - 1];
+        data[len - i - 1] = temp;
+    }
+}
+
+/******************************************************************************
+** Function: util_strpadlen
+**
+** Find length of string that has been padded with spaces
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_ULONG util_strpadlen(CK_CHAR *string, CK_ULONG max_len)
+{
+    CK_ULONG i;
+
+    for (i = max_len; i > 0; i--)
+    {
+        if (string[i - 1] != 0x20)
+            break;
+    }
+
+    return (i);
+}
+
+/******************************************************************************
+** Function: util_PadStrSet
+**
+** Pads a string with spaces (of size length), then sets the value to a null
+** terminated string.
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV util_PadStrSet(CK_CHAR *string, CK_CHAR *value, CK_ULONG size)
+{
+    memset(string, 0x20, size);
+    memcpy((char *)string, value, strnlen((char *)value, size));
+
+    return CKR_OK;
+}
+
+/******************************************************************************
+** Function: util_StripPKCS1
+**
+** Strips PKCS #1 padding
+**
+** Note that this function strips the data in-place so the original information
+** is lost.
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+CK_RV util_StripPKCS1(CK_BYTE *data, CK_ULONG len, CK_BYTE *output, CK_ULONG *out_len)
+{
+    CK_RV rv = CKR_OK;
+    CK_ULONG i, pos, tag;
+
+    pos = tag = 0;
+
+    for (i = 0; i < len; i++)
+    {
+        if (data[i] == 0x02)
+            tag = 1;
+        else if (tag && !data[i] && (i+1 < len))
+        {
+            pos = i + 1;
+            break;
+        }
+    }
+
+    if (!pos)
+        rv = CKR_FUNCTION_FAILED;
+    else
+    {
+        len -= pos;
+
+        if (len > *out_len)
+            rv = CKR_BUFFER_TOO_SMALL;
+        else
+        {
+            memcpy(output, &data[pos], len);
+            *out_len = len;
+        }
+    }
+
+    return rv;
+}
+
+/******************************************************************************
+** Function: strnlen
+**
+** Limited length strlen function (normally included with GNU compiler)
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  none
+*******************************************************************************/
+#ifndef __USE_GNU
+#ifndef WIN32
+size_t strnlen(__const char *__string, size_t __maxlen)
+#else
+size_t strnlen(const char *__string, size_t __maxlen)
+#endif
+{
+    size_t i;
+
+    for (i = 0; i < __maxlen; i++)
+        if (__string[i] == 0x00) break;
+
+    return i;
+}
+#endif
+
+/******************************************************************************
+** Function: util_IsLittleEndian
+**
+** Parameters:
+**  none
+**
+** Returns:
+**  True/False if machine is little endian or not
+*******************************************************************************/
+CK_BBOOL util_IsLittleEndian()
+{
+    CK_ULONG rv = 1;
+
+    return ((char *)&rv)[0];
+}

Added: trunk/SmartCardServices/src/PKCS11/p11x_win32dll.c
===================================================================
--- trunk/SmartCardServices/src/PKCS11/p11x_win32dll.c	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/p11x_win32dll.c	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,53 @@
+/******************************************************************************
+** 
+**  $Id: p11x_win32dll.c,v 1.2 2003/02/13 20:06:42 ghoo Exp $
+**
+**  Package: PKCS-11
+**  Author : Chris Osgood <oznet at mac.com>
+**  License: Copyright (C) 2002 Schlumberger Network Solutions
+**           <http://www.slb.com/sns>
+**  Purpose: Support for WIN32 DLL's
+** 
+******************************************************************************/
+#ifdef WIN32
+
+#include "cryptoki.h"
+
+/******************************************************************************
+** Function: DllMain
+**
+** Required entry point for WIN32 DLL's
+**
+** Parameters:
+**  hModule            -
+**  ul_reason_for_call -
+**  lpReserved         -
+**
+** Returns:
+**  TRUE
+*******************************************************************************/
+BOOL APIENTRY DllMain( HANDLE hModule, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+                     )
+{
+    switch (ul_reason_for_call)
+    {
+        case DLL_PROCESS_ATTACH:
+            log_Log(LOG_LOW, "WIN32DLL: Process attach");
+            break;
+        case DLL_THREAD_ATTACH:
+            log_Log(LOG_LOW, "WIN32DLL: Thread attach");
+            break;
+        case DLL_THREAD_DETACH:
+            log_Log(LOG_LOW, "WIN32DLL: Thread detach");
+            break;
+        case DLL_PROCESS_DETACH:
+            log_Log(LOG_LOW, "WIN32DLL: Process detach");
+            C_Finalize(0);
+            break;
+    }
+    return TRUE;
+}
+
+#endif /* WIN32 */

Added: trunk/SmartCardServices/src/PKCS11/pkcs11.h
===================================================================
--- trunk/SmartCardServices/src/PKCS11/pkcs11.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/pkcs11.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/* pkcs11.h include file for PKCS #11.  2001 June 25 */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 6 platform-specific macros must be defined.  These
+ * macros are described below, and typical definitions for them
+ * are also given.  Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 6 macros, the packing convention
+ * for Cryptoki structures should be set.  The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this.  You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object.  It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
+ * an exportable Cryptoki library function definition out of a
+ * return type and a function name.  It should be used in the
+ * following fashion to define the exposed Cryptoki functions in
+ * a Cryptoki library:
+ *
+ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
+ *   CK_VOID_PTR pReserved
+ * )
+ * {
+ *   ...
+ * }
+ *
+ * If you're using Microsoft Developer Studio 5.0 to define a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ *   returnType __declspec(dllexport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to define a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ *   returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ *   returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name.  It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ *   CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType name
+ *
+ *
+ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name.  It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType (* name)
+ *
+ *
+ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV.  It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType (* name)
+ *
+ *
+ * 6. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h. */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y)      x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST  1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points.  That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST  1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points.  A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library.  This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  __PASTE(CK_,name) name;
+  
+struct CK_FUNCTION_LIST {
+
+  CK_VERSION    version;  /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: trunk/SmartCardServices/src/PKCS11/pkcs11f.h
===================================================================
--- trunk/SmartCardServices/src/PKCS11/pkcs11f.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/pkcs11f.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,915 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/* pkcs11f.h include file for PKCS #11.  2001 June 25 */
+
+/* This function contains pretty much everything about all the */
+/* Cryptoki function prototypes.  Because this information is */
+/* used for more than just declaring function prototypes, the */
+/* order of the functions appearing herein is important, and */
+/* should not be altered. */
+
+
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_VOID_PTR   pInitArgs  /* if this is not NULL_PTR, it gets
+                            * cast to CK_C_INITIALIZE_ARGS_PTR
+                            * and dereferenced */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_VOID_PTR   pReserved  /* reserved.  Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_INFO_PTR   pInfo  /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_FUNCTION_LIST_PTR_PTR ppFunctionList  /* receives pointer to
+                                            * function list */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_BBOOL       tokenPresent,  /* only slots with tokens? */
+  CK_SLOT_ID_PTR pSlotList,     /* receives array of slot IDs */
+  CK_ULONG_PTR   pulCount       /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID       slotID,  /* the ID of the slot */
+  CK_SLOT_INFO_PTR pInfo    /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID        slotID,  /* ID of the token's slot */
+  CK_TOKEN_INFO_PTR pInfo    /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,          /* ID of token's slot */
+  CK_MECHANISM_TYPE_PTR pMechanismList,  /* gets mech. array */
+  CK_ULONG_PTR          pulCount         /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,  /* ID of the token's slot */
+  CK_MECHANISM_TYPE     type,    /* type of mechanism */
+  CK_MECHANISM_INFO_PTR pInfo    /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+  CK_SLOT_ID      slotID,    /* ID of the token's slot */
+  CK_UTF8CHAR_PTR pPin,      /* the SO's initial PIN */
+  CK_ULONG        ulPinLen,  /* length in bytes of the PIN */
+  CK_UTF8CHAR_PTR pLabel     /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pPin,      /* the normal user's PIN */
+  CK_ULONG          ulPinLen   /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pOldPin,   /* the old PIN */
+  CK_ULONG          ulOldLen,  /* length of the old PIN */
+  CK_UTF8CHAR_PTR   pNewPin,   /* the new PIN */
+  CK_ULONG          ulNewLen   /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,        /* the slot's ID */
+  CK_FLAGS              flags,         /* from CK_SESSION_INFO */
+  CK_VOID_PTR           pApplication,  /* passed to callback */
+  CK_NOTIFY             Notify,        /* callback function */
+  CK_SESSION_HANDLE_PTR phSession      /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID     slotID  /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE   hSession,  /* the session's handle */
+  CK_SESSION_INFO_PTR pInfo      /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,             /* session's handle */
+  CK_BYTE_PTR       pOperationState,      /* gets state */
+  CK_ULONG_PTR      pulOperationStateLen  /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR      pOperationState,      /* holds state */
+  CK_ULONG         ulOperationStateLen,  /* holds state length */
+  CK_OBJECT_HANDLE hEncryptionKey,       /* en/decryption key */
+  CK_OBJECT_HANDLE hAuthenticationKey    /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_USER_TYPE      userType,  /* the user type */
+  CK_UTF8CHAR_PTR   pPin,      /* the user's PIN */
+  CK_ULONG          ulPinLen   /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,   /* the object's template */
+  CK_ULONG          ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phObject  /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_OBJECT_HANDLE     hObject,     /* the object's handle */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new object */
+  CK_ULONG             ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phNewObject  /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject    /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,   /* the object's handle */
+  CK_ULONG_PTR      pulSize    /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs; gets vals */
+  CK_ULONG          ulCount     /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs and values */
+  CK_ULONG          ulCount     /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* attribute values to match */
+  CK_ULONG          ulCount     /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE    hSession,          /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject,          /* gets obj. handles */
+ CK_ULONG             ulMaxObjectCount,  /* max handles to get */
+ CK_ULONG_PTR         pulObjectCount     /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the encryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pData,               /* the plaintext data */
+  CK_ULONG          ulDataLen,           /* bytes of plaintext */
+  CK_BYTE_PTR       pEncryptedData,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedDataLen  /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pPart,              /* the plaintext data */
+  CK_ULONG          ulPartLen,          /* plaintext data len */
+  CK_BYTE_PTR       pEncryptedPart,     /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,                /* session handle */
+  CK_BYTE_PTR       pLastEncryptedPart,      /* last c-text */
+  CK_ULONG_PTR      pulLastEncryptedPartLen  /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the decryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pEncryptedData,     /* ciphertext */
+  CK_ULONG          ulEncryptedDataLen, /* ciphertext length */
+  CK_BYTE_PTR       pData,              /* gets plaintext */
+  CK_ULONG_PTR      pulDataLen          /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* encrypted data */
+  CK_ULONG          ulEncryptedPartLen,  /* input length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pLastPart,      /* gets plaintext */
+  CK_ULONG_PTR      pulLastPartLen  /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism  /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pData,        /* data to be digested */
+  CK_ULONG          ulDataLen,    /* bytes of data to digest */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* data to be digested */
+  CK_ULONG          ulPartLen  /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hKey       /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* the data to sign */
+  CK_ULONG          ulPartLen  /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation, 
+ * returning the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism, /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey        /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ *  cannot be recovered from the signature (e.g. DSA). */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */ 
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation, 
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pData,          /* signed data */
+  CK_ULONG          ulDataLen,      /* length of signed data */
+  CK_BYTE_PTR       pSignature,     /* signature */
+  CK_ULONG          ulSignatureLen  /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* signed data */
+  CK_ULONG          ulPartLen  /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pSignature,     /* signature to verify */
+  CK_ULONG          ulSignatureLen  /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* signature to verify */
+  CK_ULONG          ulSignatureLen,  /* signature length */
+  CK_BYTE_PTR       pData,           /* gets signed data */
+  CK_ULONG_PTR      pulDataLen       /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_MECHANISM_PTR     pMechanism,  /* key generation mech. */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new key */
+  CK_ULONG             ulCount,     /* # of attrs in template */
+  CK_OBJECT_HANDLE_PTR phKey        /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair, 
+ * creating new key objects. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,                    /* session
+                                                     * handle */
+  CK_MECHANISM_PTR     pMechanism,                  /* key-gen
+                                                     * mech. */
+  CK_ATTRIBUTE_PTR     pPublicKeyTemplate,          /* template
+                                                     * for pub.
+                                                     * key */
+  CK_ULONG             ulPublicKeyAttributeCount,   /* # pub.
+                                                     * attrs. */
+  CK_ATTRIBUTE_PTR     pPrivateKeyTemplate,         /* template
+                                                     * for priv.
+                                                     * key */
+  CK_ULONG             ulPrivateKeyAttributeCount,  /* # priv.
+                                                     * attrs. */
+  CK_OBJECT_HANDLE_PTR phPublicKey,                 /* gets pub.
+                                                     * key
+                                                     * handle */
+  CK_OBJECT_HANDLE_PTR phPrivateKey                 /* gets
+                                                     * priv. key
+                                                     * handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,      /* the wrapping mechanism */
+  CK_OBJECT_HANDLE  hWrappingKey,    /* wrapping key */
+  CK_OBJECT_HANDLE  hKey,            /* key to be wrapped */
+  CK_BYTE_PTR       pWrappedKey,     /* gets wrapped key */
+  CK_ULONG_PTR      pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* unwrapping mech. */
+  CK_OBJECT_HANDLE     hUnwrappingKey,    /* unwrapping key */
+  CK_BYTE_PTR          pWrappedKey,       /* the wrapped key */
+  CK_ULONG             ulWrappedKeyLen,   /* wrapped key len */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* key deriv. mech. */
+  CK_OBJECT_HANDLE     hBaseKey,          /* base key */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pSeed,     /* the seed material */
+  CK_ULONG          ulSeedLen  /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_BYTE_PTR       RandomData,  /* receives the random data */
+  CK_ULONG          ulRandomLen  /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Functions added in for Cryptoki Version 2.01 or later */
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_FLAGS flags,        /* blocking/nonblocking flag */
+  CK_SLOT_ID_PTR pSlot,  /* location that receives the slot ID */
+  CK_VOID_PTR pRserved   /* reserved.  Should be NULL_PTR */
+);
+#endif

Added: trunk/SmartCardServices/src/PKCS11/pkcs11t.h
===================================================================
--- trunk/SmartCardServices/src/PKCS11/pkcs11t.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/pkcs11t.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,1351 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/* pkcs11t.h include file for PKCS #11.  2001 June 25 */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file. */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#ifndef FALSE
+#define FALSE             0
+#endif
+
+#ifndef TRUE
+#define TRUE              (!FALSE)
+#endif
+
+
+/* an unsigned 8-bit value */
+typedef unsigned char     CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE           CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE           CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE           CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+/* CK_LONG is new for v2.0 */
+typedef long int          CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG          CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE    0
+
+
+typedef CK_BYTE     CK_PTR   CK_BYTE_PTR;
+typedef CK_CHAR     CK_PTR   CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR   CK_UTF8CHAR_PTR;
+typedef CK_ULONG    CK_PTR   CK_ULONG_PTR;
+typedef void        CK_PTR   CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session */
+/* handle or object handle */
+#define CK_INVALID_HANDLE 0
+
+
+typedef struct CK_VERSION {
+  CK_BYTE       major;  /* integer portion of version number */
+  CK_BYTE       minor;  /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+  /* manufacturerID and libraryDecription have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_VERSION    cryptokiVersion;     /* Cryptoki interface ver */
+  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
+  CK_FLAGS      flags;               /* must be zero */
+
+  /* libraryDescription and libraryVersion are new for v2.0 */
+  CK_UTF8CHAR   libraryDescription[32];  /* blank padded */
+  CK_VERSION    libraryVersion;          /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR    CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application */
+/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER       0
+
+
+typedef CK_ULONG          CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+  /* slotDescription and manufacturerID have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_UTF8CHAR   slotDescription[64];  /* blank padded */
+  CK_UTF8CHAR   manufacturerID[32];   /* blank padded */
+  CK_FLAGS      flags;
+
+  /* hardwareVersion and firmwareVersion are new for v2.0 */
+  CK_VERSION    hardwareVersion;  /* version of hardware */
+  CK_VERSION    firmwareVersion;  /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ *      Bit Flag              Mask        Meaning
+ */
+#define CKF_TOKEN_PRESENT     0x00000001  /* a token is there */
+#define CKF_REMOVABLE_DEVICE  0x00000002  /* removable devices*/
+#define CKF_HW_SLOT           0x00000004  /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+  /* label, manufacturerID, and model have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_UTF8CHAR   label[32];           /* blank padded */
+  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
+  CK_UTF8CHAR   model[16];           /* blank padded */
+  CK_CHAR       serialNumber[16];    /* blank padded */
+  CK_FLAGS      flags;               /* see below */
+
+  /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
+   * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
+   * changed from CK_USHORT to CK_ULONG for v2.0 */
+  CK_ULONG      ulMaxSessionCount;     /* max open sessions */
+  CK_ULONG      ulSessionCount;        /* sess. now open */
+  CK_ULONG      ulMaxRwSessionCount;   /* max R/W sessions */
+  CK_ULONG      ulRwSessionCount;      /* R/W sess. now open */
+  CK_ULONG      ulMaxPinLen;           /* in bytes */
+  CK_ULONG      ulMinPinLen;           /* in bytes */
+  CK_ULONG      ulTotalPublicMemory;   /* in bytes */
+  CK_ULONG      ulFreePublicMemory;    /* in bytes */
+  CK_ULONG      ulTotalPrivateMemory;  /* in bytes */
+  CK_ULONG      ulFreePrivateMemory;   /* in bytes */
+
+  /* hardwareVersion, firmwareVersion, and time are new for
+   * v2.0 */
+  CK_VERSION    hardwareVersion;       /* version of hardware */
+  CK_VERSION    firmwareVersion;       /* version of firmware */
+  CK_CHAR       utcTime[16];           /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ *      Bit Flag                    Mask        Meaning 
+ */
+#define CKF_RNG                     0x00000001  /* has random #
+                                                 * generator */
+#define CKF_WRITE_PROTECTED         0x00000002  /* token is
+                                                 * write-
+                                                 * protected */
+#define CKF_LOGIN_REQUIRED          0x00000004  /* user must
+                                                 * login */
+#define CKF_USER_PIN_INITIALIZED    0x00000008  /* normal user's
+                                                 * PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0.  If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state */
+#define CKF_RESTORE_KEY_NOT_NEEDED  0x00000020
+
+/* CKF_CLOCK_ON_TOKEN is new for v2.0.  If it is set, that means
+ * that the token has some sort of clock.  The time on that
+ * clock is returned in the token info structure */
+#define CKF_CLOCK_ON_TOKEN          0x00000040
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0.  If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
+
+/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0.  If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign) */
+#define CKF_DUAL_CRYPTO_OPERATIONS  0x00000200
+
+/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
+ * token has been initialized using C_InitializeToken or an 
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause 
+ * the token to be reinitialized. */
+#define CKF_TOKEN_INITIALIZED       0x00000400
+
+/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is 
+ * true, the token supports secondary authentication for 
+ * private key objects. */
+#define CKF_SECONDARY_AUTHENTICATION  0x00000800
+
+/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an 
+ * incorrect user login PIN has been entered at least once 
+ * since the last successful authentication. */
+#define CKF_USER_PIN_COUNT_LOW       0x00010000
+
+/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect user PIN will it to become locked. */
+#define CKF_USER_PIN_FINAL_TRY       0x00020000
+
+/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the 
+ * user PIN has been locked. User login to the token is not 
+ * possible. */
+#define CKF_USER_PIN_LOCKED          0x00040000
+
+/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true, 
+ * the user PIN value is the default value set by token 
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_USER_PIN_TO_BE_CHANGED   0x00080000
+
+/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an 
+ * incorrect SO login PIN has been entered at least once since 
+ * the last successful authentication. */
+#define CKF_SO_PIN_COUNT_LOW         0x00100000
+
+/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect SO PIN will it to become locked. */
+#define CKF_SO_PIN_FINAL_TRY         0x00200000
+
+/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO 
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED            0x00400000
+
+/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true, 
+ * the SO PIN value is the default value set by token 
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_SO_PIN_TO_BE_CHANGED     0x00800000
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session */
+typedef CK_ULONG          CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR; 
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO    0
+/* Normal user */
+#define CKU_USER  1
+
+
+/* CK_STATE enumerates the session states */
+/* CK_STATE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_STATE;
+#define CKS_RO_PUBLIC_SESSION  0
+#define CKS_RO_USER_FUNCTIONS  1
+#define CKS_RW_PUBLIC_SESSION  2
+#define CKS_RW_USER_FUNCTIONS  3
+#define CKS_RW_SO_FUNCTIONS    4
+
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+  CK_SLOT_ID    slotID;
+  CK_STATE      state;
+  CK_FLAGS      flags;          /* see below */
+
+  /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG      ulDeviceError;  /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ *      Bit Flag                Mask        Meaning
+ */
+#define CKF_RW_SESSION          0x00000002  /* session is r/w */
+#define CKF_SERIAL_SESSION      0x00000004  /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object  */
+typedef CK_ULONG          CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes.  It is defined
+ * as follows: */
+/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+/* CKO_HW_FEATURE is new for v2.10 */
+/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
+#define CKO_DATA              0x00000000
+#define CKO_CERTIFICATE       0x00000001
+#define CKO_PUBLIC_KEY        0x00000002
+#define CKO_PRIVATE_KEY       0x00000003
+#define CKO_SECRET_KEY        0x00000004
+#define CKO_HW_FEATURE        0x00000005
+#define CKO_DOMAIN_PARAMETERS 0x00000006
+#define CKO_VENDOR_DEFINED    0x80000000
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
+ * value that identifies the hardware feature type of an object
+ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
+typedef CK_ULONG          CK_HW_FEATURE_TYPE;
+ 
+/* The following hardware feature types are defined */
+#define CKH_MONOTONIC_COUNTER  0x00000001
+#define CKH_CLOCK           0x00000002
+#define CKH_VENDOR_DEFINED  0x80000000
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG          CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA             0x00000000
+#define CKK_DSA             0x00000001
+#define CKK_DH              0x00000002
+
+/* CKK_ECDSA and CKK_KEA are new for v2.0 */
+/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
+#define CKK_ECDSA           0x00000003
+#define CKK_EC              0x00000003
+#define CKK_X9_42_DH        0x00000004
+#define CKK_KEA             0x00000005
+
+#define CKK_GENERIC_SECRET  0x00000010
+#define CKK_RC2             0x00000011
+#define CKK_RC4             0x00000012
+#define CKK_DES             0x00000013
+#define CKK_DES2            0x00000014
+#define CKK_DES3            0x00000015
+
+/* all these key types are new for v2.0 */
+#define CKK_CAST            0x00000016
+#define CKK_CAST3           0x00000017
+/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
+#define CKK_CAST5           0x00000018
+#define CKK_CAST128         0x00000018
+#define CKK_RC5             0x00000019
+#define CKK_IDEA            0x0000001A
+#define CKK_SKIPJACK        0x0000001B
+#define CKK_BATON           0x0000001C
+#define CKK_JUNIPER         0x0000001D
+#define CKK_CDMF            0x0000001E
+#define CKK_AES             0x0000001F
+
+#define CKK_VENDOR_DEFINED  0x80000000
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type */
+/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG          CK_CERTIFICATE_TYPE;
+
+/* The following certificate types are defined: */
+/* CKC_X_509_ATTR_CERT is new for v2.10 */
+#define CKC_X_509           0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_VENDOR_DEFINED  0x80000000
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type */
+/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
+
+/* The following attribute types are defined: */
+#define CKA_CLASS              0x00000000
+#define CKA_TOKEN              0x00000001
+#define CKA_PRIVATE            0x00000002
+#define CKA_LABEL              0x00000003
+#define CKA_APPLICATION        0x00000010
+#define CKA_VALUE              0x00000011
+
+/* CKA_OBJECT_ID is new for v2.10 */
+#define CKA_OBJECT_ID          0x00000012
+
+#define CKA_CERTIFICATE_TYPE   0x00000080
+#define CKA_ISSUER             0x00000081
+#define CKA_SERIAL_NUMBER      0x00000082
+
+/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new 
+ * for v2.10 */
+#define CKA_AC_ISSUER          0x00000083
+#define CKA_OWNER              0x00000084
+#define CKA_ATTR_TYPES         0x00000085
+
+/* CKA_TRUSTED is new for v2.11 */
+#define CKA_TRUSTED            0x00000086
+
+#define CKA_KEY_TYPE           0x00000100
+#define CKA_SUBJECT            0x00000101
+#define CKA_ID                 0x00000102
+#define CKA_SENSITIVE          0x00000103
+#define CKA_ENCRYPT            0x00000104
+#define CKA_DECRYPT            0x00000105
+#define CKA_WRAP               0x00000106
+#define CKA_UNWRAP             0x00000107
+#define CKA_SIGN               0x00000108
+#define CKA_SIGN_RECOVER       0x00000109
+#define CKA_VERIFY             0x0000010A
+#define CKA_VERIFY_RECOVER     0x0000010B
+#define CKA_DERIVE             0x0000010C
+#define CKA_START_DATE         0x00000110
+#define CKA_END_DATE           0x00000111
+#define CKA_MODULUS            0x00000120
+#define CKA_MODULUS_BITS       0x00000121
+#define CKA_PUBLIC_EXPONENT    0x00000122
+#define CKA_PRIVATE_EXPONENT   0x00000123
+#define CKA_PRIME_1            0x00000124
+#define CKA_PRIME_2            0x00000125
+#define CKA_EXPONENT_1         0x00000126
+#define CKA_EXPONENT_2         0x00000127
+#define CKA_COEFFICIENT        0x00000128
+#define CKA_PRIME              0x00000130
+#define CKA_SUBPRIME           0x00000131
+#define CKA_BASE               0x00000132
+
+/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
+#define CKA_PRIME_BITS         0x00000133
+#define CKA_SUB_PRIME_BITS     0x00000134
+
+#define CKA_VALUE_BITS         0x00000160
+#define CKA_VALUE_LEN          0x00000161
+
+/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
+ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
+ * and CKA_EC_POINT are new for v2.0 */
+#define CKA_EXTRACTABLE        0x00000162
+#define CKA_LOCAL              0x00000163
+#define CKA_NEVER_EXTRACTABLE  0x00000164
+#define CKA_ALWAYS_SENSITIVE   0x00000165
+
+/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
+#define CKA_KEY_GEN_MECHANISM  0x00000166
+
+#define CKA_MODIFIABLE         0x00000170
+
+/* CKA_ECDSA_PARAMS is deprecated in v2.11,
+ * CKA_EC_PARAMS is preferred. */
+#define CKA_ECDSA_PARAMS       0x00000180
+#define CKA_EC_PARAMS          0x00000180
+
+#define CKA_EC_POINT           0x00000181
+
+/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, 
+ * CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
+ * are new for v2.10 */
+#define CKA_SECONDARY_AUTH     0x00000200
+#define CKA_AUTH_PIN_FLAGS     0x00000201
+#define CKA_HW_FEATURE_TYPE    0x00000300
+#define CKA_RESET_ON_INIT      0x00000301
+#define CKA_HAS_RESET          0x00000302
+
+#define CKA_VENDOR_DEFINED     0x80000000
+
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute */
+typedef struct CK_ATTRIBUTE {
+  CK_ATTRIBUTE_TYPE type;
+  CK_VOID_PTR       pValue;
+
+  /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
+  CK_ULONG          ulValueLen;  /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+  CK_CHAR       year[4];   /* the year ("1900" - "9999") */
+  CK_CHAR       month[2];  /* the month ("01" - "12") */
+  CK_CHAR       day[2];    /* the day   ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type */
+/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN      0x00000000
+#define CKM_RSA_PKCS                   0x00000001
+#define CKM_RSA_9796                   0x00000002
+#define CKM_RSA_X_509                  0x00000003
+
+/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
+ * are new for v2.0.  They are mechanisms which hash and sign */
+#define CKM_MD2_RSA_PKCS               0x00000004
+#define CKM_MD5_RSA_PKCS               0x00000005
+#define CKM_SHA1_RSA_PKCS              0x00000006
+
+/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
+ * CKM_RSA_PKCS_OAEP are new for v2.10 */
+#define CKM_RIPEMD128_RSA_PKCS         0x00000007
+#define CKM_RIPEMD160_RSA_PKCS         0x00000008
+#define CKM_RSA_PKCS_OAEP              0x00000009
+
+/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
+ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
+#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000A
+#define CKM_RSA_X9_31                  0x0000000B
+#define CKM_SHA1_RSA_X9_31             0x0000000C
+#define CKM_RSA_PKCS_PSS               0x0000000D
+#define CKM_SHA1_RSA_PKCS_PSS          0x0000000E
+
+#define CKM_DSA_KEY_PAIR_GEN           0x00000010
+#define CKM_DSA                        0x00000011
+#define CKM_DSA_SHA1                   0x00000012
+#define CKM_DH_PKCS_KEY_PAIR_GEN       0x00000020
+#define CKM_DH_PKCS_DERIVE             0x00000021
+
+/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
+ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
+ * v2.11 */
+#define CKM_X9_42_DH_KEY_PAIR_GEN      0x00000030
+#define CKM_X9_42_DH_DERIVE            0x00000031
+#define CKM_X9_42_DH_HYBRID_DERIVE     0x00000032
+#define CKM_X9_42_MQV_DERIVE           0x00000033
+
+#define CKM_RC2_KEY_GEN                0x00000100
+#define CKM_RC2_ECB                    0x00000101
+#define CKM_RC2_CBC                    0x00000102
+#define CKM_RC2_MAC                    0x00000103
+
+/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
+#define CKM_RC2_MAC_GENERAL            0x00000104
+#define CKM_RC2_CBC_PAD                0x00000105
+
+#define CKM_RC4_KEY_GEN                0x00000110
+#define CKM_RC4                        0x00000111
+#define CKM_DES_KEY_GEN                0x00000120
+#define CKM_DES_ECB                    0x00000121
+#define CKM_DES_CBC                    0x00000122
+#define CKM_DES_MAC                    0x00000123
+
+/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
+#define CKM_DES_MAC_GENERAL            0x00000124
+#define CKM_DES_CBC_PAD                0x00000125
+
+#define CKM_DES2_KEY_GEN               0x00000130
+#define CKM_DES3_KEY_GEN               0x00000131
+#define CKM_DES3_ECB                   0x00000132
+#define CKM_DES3_CBC                   0x00000133
+#define CKM_DES3_MAC                   0x00000134
+
+/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
+ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
+ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */
+#define CKM_DES3_MAC_GENERAL           0x00000135
+#define CKM_DES3_CBC_PAD               0x00000136
+#define CKM_CDMF_KEY_GEN               0x00000140
+#define CKM_CDMF_ECB                   0x00000141
+#define CKM_CDMF_CBC                   0x00000142
+#define CKM_CDMF_MAC                   0x00000143
+#define CKM_CDMF_MAC_GENERAL           0x00000144
+#define CKM_CDMF_CBC_PAD               0x00000145
+
+#define CKM_MD2                        0x00000200
+
+/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD2_HMAC                   0x00000201
+#define CKM_MD2_HMAC_GENERAL           0x00000202
+
+#define CKM_MD5                        0x00000210
+
+/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD5_HMAC                   0x00000211
+#define CKM_MD5_HMAC_GENERAL           0x00000212
+
+#define CKM_SHA_1                      0x00000220
+
+/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
+#define CKM_SHA_1_HMAC                 0x00000221
+#define CKM_SHA_1_HMAC_GENERAL         0x00000222
+
+/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC, 
+ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
+ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
+#define CKM_RIPEMD128                  0x00000230
+#define CKM_RIPEMD128_HMAC             0x00000231
+#define CKM_RIPEMD128_HMAC_GENERAL     0x00000232
+#define CKM_RIPEMD160                  0x00000240
+#define CKM_RIPEMD160_HMAC             0x00000241
+#define CKM_RIPEMD160_HMAC_GENERAL     0x00000242
+
+/* All of the following mechanisms are new for v2.0 */
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST_KEY_GEN               0x00000300
+#define CKM_CAST_ECB                   0x00000301
+#define CKM_CAST_CBC                   0x00000302
+#define CKM_CAST_MAC                   0x00000303
+#define CKM_CAST_MAC_GENERAL           0x00000304
+#define CKM_CAST_CBC_PAD               0x00000305
+#define CKM_CAST3_KEY_GEN              0x00000310
+#define CKM_CAST3_ECB                  0x00000311
+#define CKM_CAST3_CBC                  0x00000312
+#define CKM_CAST3_MAC                  0x00000313
+#define CKM_CAST3_MAC_GENERAL          0x00000314
+#define CKM_CAST3_CBC_PAD              0x00000315
+#define CKM_CAST5_KEY_GEN              0x00000320
+#define CKM_CAST128_KEY_GEN            0x00000320
+#define CKM_CAST5_ECB                  0x00000321
+#define CKM_CAST128_ECB                0x00000321
+#define CKM_CAST5_CBC                  0x00000322
+#define CKM_CAST128_CBC                0x00000322
+#define CKM_CAST5_MAC                  0x00000323
+#define CKM_CAST128_MAC                0x00000323
+#define CKM_CAST5_MAC_GENERAL          0x00000324
+#define CKM_CAST128_MAC_GENERAL        0x00000324
+#define CKM_CAST5_CBC_PAD              0x00000325
+#define CKM_CAST128_CBC_PAD            0x00000325
+#define CKM_RC5_KEY_GEN                0x00000330
+#define CKM_RC5_ECB                    0x00000331
+#define CKM_RC5_CBC                    0x00000332
+#define CKM_RC5_MAC                    0x00000333
+#define CKM_RC5_MAC_GENERAL            0x00000334
+#define CKM_RC5_CBC_PAD                0x00000335
+#define CKM_IDEA_KEY_GEN               0x00000340
+#define CKM_IDEA_ECB                   0x00000341
+#define CKM_IDEA_CBC                   0x00000342
+#define CKM_IDEA_MAC                   0x00000343
+#define CKM_IDEA_MAC_GENERAL           0x00000344
+#define CKM_IDEA_CBC_PAD               0x00000345
+#define CKM_GENERIC_SECRET_KEY_GEN     0x00000350
+#define CKM_CONCATENATE_BASE_AND_KEY   0x00000360
+#define CKM_CONCATENATE_BASE_AND_DATA  0x00000362
+#define CKM_CONCATENATE_DATA_AND_BASE  0x00000363
+#define CKM_XOR_BASE_AND_DATA          0x00000364
+#define CKM_EXTRACT_KEY_FROM_KEY       0x00000365
+#define CKM_SSL3_PRE_MASTER_KEY_GEN    0x00000370
+#define CKM_SSL3_MASTER_KEY_DERIVE     0x00000371
+#define CKM_SSL3_KEY_AND_MAC_DERIVE    0x00000372
+
+/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
+ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
+ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH  0x00000373
+#define CKM_TLS_PRE_MASTER_KEY_GEN     0x00000374
+#define CKM_TLS_MASTER_KEY_DERIVE      0x00000375
+#define CKM_TLS_KEY_AND_MAC_DERIVE     0x00000376
+#define CKM_TLS_MASTER_KEY_DERIVE_DH   0x00000377
+
+#define CKM_SSL3_MD5_MAC               0x00000380
+#define CKM_SSL3_SHA1_MAC              0x00000381
+#define CKM_MD5_KEY_DERIVATION         0x00000390
+#define CKM_MD2_KEY_DERIVATION         0x00000391
+#define CKM_SHA1_KEY_DERIVATION        0x00000392
+#define CKM_PBE_MD2_DES_CBC            0x000003A0
+#define CKM_PBE_MD5_DES_CBC            0x000003A1
+#define CKM_PBE_MD5_CAST_CBC           0x000003A2
+#define CKM_PBE_MD5_CAST3_CBC          0x000003A3
+#define CKM_PBE_MD5_CAST5_CBC          0x000003A4
+#define CKM_PBE_MD5_CAST128_CBC        0x000003A4
+#define CKM_PBE_SHA1_CAST5_CBC         0x000003A5
+#define CKM_PBE_SHA1_CAST128_CBC       0x000003A5
+#define CKM_PBE_SHA1_RC4_128           0x000003A6
+#define CKM_PBE_SHA1_RC4_40            0x000003A7
+#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003A8
+#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003A9
+#define CKM_PBE_SHA1_RC2_128_CBC       0x000003AA
+#define CKM_PBE_SHA1_RC2_40_CBC        0x000003AB
+
+/* CKM_PKCS5_PBKD2 is new for v2.10 */
+#define CKM_PKCS5_PBKD2                0x000003B0
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003C0
+#define CKM_KEY_WRAP_LYNKS             0x00000400
+#define CKM_KEY_WRAP_SET_OAEP          0x00000401
+
+/* Fortezza mechanisms */
+#define CKM_SKIPJACK_KEY_GEN           0x00001000
+#define CKM_SKIPJACK_ECB64             0x00001001
+#define CKM_SKIPJACK_CBC64             0x00001002
+#define CKM_SKIPJACK_OFB64             0x00001003
+#define CKM_SKIPJACK_CFB64             0x00001004
+#define CKM_SKIPJACK_CFB32             0x00001005
+#define CKM_SKIPJACK_CFB16             0x00001006
+#define CKM_SKIPJACK_CFB8              0x00001007
+#define CKM_SKIPJACK_WRAP              0x00001008
+#define CKM_SKIPJACK_PRIVATE_WRAP      0x00001009
+#define CKM_SKIPJACK_RELAYX            0x0000100a
+#define CKM_KEA_KEY_PAIR_GEN           0x00001010
+#define CKM_KEA_KEY_DERIVE             0x00001011
+#define CKM_FORTEZZA_TIMESTAMP         0x00001020
+#define CKM_BATON_KEY_GEN              0x00001030
+#define CKM_BATON_ECB128               0x00001031
+#define CKM_BATON_ECB96                0x00001032
+#define CKM_BATON_CBC128               0x00001033
+#define CKM_BATON_COUNTER              0x00001034
+#define CKM_BATON_SHUFFLE              0x00001035
+#define CKM_BATON_WRAP                 0x00001036
+
+/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
+ * CKM_EC_KEY_PAIR_GEN is preferred */
+#define CKM_ECDSA_KEY_PAIR_GEN         0x00001040
+#define CKM_EC_KEY_PAIR_GEN            0x00001040
+
+#define CKM_ECDSA                      0x00001041
+#define CKM_ECDSA_SHA1                 0x00001042
+
+/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
+ * are new for v2.11 */
+#define CKM_ECDH1_DERIVE               0x00001050
+#define CKM_ECDH1_COFACTOR_DERIVE      0x00001051
+#define CKM_ECMQV_DERIVE               0x00001052
+
+#define CKM_JUNIPER_KEY_GEN            0x00001060
+#define CKM_JUNIPER_ECB128             0x00001061
+#define CKM_JUNIPER_CBC128             0x00001062
+#define CKM_JUNIPER_COUNTER            0x00001063
+#define CKM_JUNIPER_SHUFFLE            0x00001064
+#define CKM_JUNIPER_WRAP               0x00001065
+#define CKM_FASTHASH                   0x00001070
+
+/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
+ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
+ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
+ * new for v2.11 */
+#define CKM_AES_KEY_GEN                0x00001080
+#define CKM_AES_ECB                    0x00001081
+#define CKM_AES_CBC                    0x00001082
+#define CKM_AES_MAC                    0x00001083
+#define CKM_AES_MAC_GENERAL            0x00001084
+#define CKM_AES_CBC_PAD                0x00001085
+#define CKM_DSA_PARAMETER_GEN          0x00002000
+#define CKM_DH_PKCS_PARAMETER_GEN      0x00002001
+#define CKM_X9_42_DH_PARAMETER_GEN     0x00002002
+
+#define CKM_VENDOR_DEFINED             0x80000000
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism  */
+typedef struct CK_MECHANISM {
+  CK_MECHANISM_TYPE mechanism;
+  CK_VOID_PTR       pParameter;
+
+  /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG          ulParameterLen;  /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism */
+typedef struct CK_MECHANISM_INFO {
+    CK_ULONG    ulMinKeySize;
+    CK_ULONG    ulMaxKeySize;
+    CK_FLAGS    flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ *      Bit Flag               Mask        Meaning */
+#define CKF_HW                 0x00000001  /* performed by HW */
+
+/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
+ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
+ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
+ * and CKF_DERIVE are new for v2.0.  They specify whether or not
+ * a mechanism can be used for a particular task */
+#define CKF_ENCRYPT            0x00000100
+#define CKF_DECRYPT            0x00000200
+#define CKF_DIGEST             0x00000400
+#define CKF_SIGN               0x00000800
+#define CKF_SIGN_RECOVER       0x00001000
+#define CKF_VERIFY             0x00002000
+#define CKF_VERIFY_RECOVER     0x00004000
+#define CKF_GENERATE           0x00008000
+#define CKF_GENERATE_KEY_PAIR  0x00010000
+#define CKF_WRAP               0x00020000
+#define CKF_UNWRAP             0x00040000
+#define CKF_DERIVE             0x00080000
+
+/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
+ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
+ * describe a token's EC capabilities not available in mechanism
+ * information. */
+#define CKF_EC_F_P	           0x00100000
+#define CKF_EC_F_2M	           0x00200000
+#define CKF_EC_ECPARAMETERS	   0x00400000
+#define CKF_EC_NAMEDCURVE	   0x00800000
+#define CKF_EC_UNCOMPRESS	   0x01000000
+#define CKF_EC_COMPRESS	       0x02000000
+
+#define CKF_EXTENSION          0x80000000  /* FALSE for 2.01 */
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function */
+/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG          CK_RV;
+
+#define CKR_OK                                0x00000000
+#define CKR_CANCEL                            0x00000001
+#define CKR_HOST_MEMORY                       0x00000002
+#define CKR_SLOT_ID_INVALID                   0x00000003
+
+/* CKR_FLAGS_INVALID was removed for v2.0 */
+
+/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
+#define CKR_GENERAL_ERROR                     0x00000005
+#define CKR_FUNCTION_FAILED                   0x00000006
+
+/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
+ * and CKR_CANT_LOCK are new for v2.01 */
+#define CKR_ARGUMENTS_BAD                     0x00000007
+#define CKR_NO_EVENT                          0x00000008
+#define CKR_NEED_TO_CREATE_THREADS            0x00000009
+#define CKR_CANT_LOCK                         0x0000000A
+
+#define CKR_ATTRIBUTE_READ_ONLY               0x00000010
+#define CKR_ATTRIBUTE_SENSITIVE               0x00000011
+#define CKR_ATTRIBUTE_TYPE_INVALID            0x00000012
+#define CKR_ATTRIBUTE_VALUE_INVALID           0x00000013
+#define CKR_DATA_INVALID                      0x00000020
+#define CKR_DATA_LEN_RANGE                    0x00000021
+#define CKR_DEVICE_ERROR                      0x00000030
+#define CKR_DEVICE_MEMORY                     0x00000031
+#define CKR_DEVICE_REMOVED                    0x00000032
+#define CKR_ENCRYPTED_DATA_INVALID            0x00000040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE          0x00000041
+#define CKR_FUNCTION_CANCELED                 0x00000050
+#define CKR_FUNCTION_NOT_PARALLEL             0x00000051
+
+/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
+#define CKR_FUNCTION_NOT_SUPPORTED            0x00000054
+
+#define CKR_KEY_HANDLE_INVALID                0x00000060
+
+/* CKR_KEY_SENSITIVE was removed for v2.0 */
+
+#define CKR_KEY_SIZE_RANGE                    0x00000062
+#define CKR_KEY_TYPE_INCONSISTENT             0x00000063
+
+/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
+ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
+ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
+ * v2.0 */
+#define CKR_KEY_NOT_NEEDED                    0x00000064
+#define CKR_KEY_CHANGED                       0x00000065
+#define CKR_KEY_NEEDED                        0x00000066
+#define CKR_KEY_INDIGESTIBLE                  0x00000067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED        0x00000068
+#define CKR_KEY_NOT_WRAPPABLE                 0x00000069
+#define CKR_KEY_UNEXTRACTABLE                 0x0000006A
+
+#define CKR_MECHANISM_INVALID                 0x00000070
+#define CKR_MECHANISM_PARAM_INVALID           0x00000071
+
+/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
+ * were removed for v2.0 */
+#define CKR_OBJECT_HANDLE_INVALID             0x00000082
+#define CKR_OPERATION_ACTIVE                  0x00000090
+#define CKR_OPERATION_NOT_INITIALIZED         0x00000091
+#define CKR_PIN_INCORRECT                     0x000000A0
+#define CKR_PIN_INVALID                       0x000000A1
+#define CKR_PIN_LEN_RANGE                     0x000000A2
+
+/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
+#define CKR_PIN_EXPIRED                       0x000000A3
+#define CKR_PIN_LOCKED                        0x000000A4
+
+#define CKR_SESSION_CLOSED                    0x000000B0
+#define CKR_SESSION_COUNT                     0x000000B1
+#define CKR_SESSION_HANDLE_INVALID            0x000000B3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED    0x000000B4
+#define CKR_SESSION_READ_ONLY                 0x000000B5
+#define CKR_SESSION_EXISTS                    0x000000B6
+
+/* CKR_SESSION_READ_ONLY_EXISTS and
+ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
+#define CKR_SESSION_READ_ONLY_EXISTS          0x000000B7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS      0x000000B8
+
+#define CKR_SIGNATURE_INVALID                 0x000000C0
+#define CKR_SIGNATURE_LEN_RANGE               0x000000C1
+#define CKR_TEMPLATE_INCOMPLETE               0x000000D0
+#define CKR_TEMPLATE_INCONSISTENT             0x000000D1
+#define CKR_TOKEN_NOT_PRESENT                 0x000000E0
+#define CKR_TOKEN_NOT_RECOGNIZED              0x000000E1
+#define CKR_TOKEN_WRITE_PROTECTED             0x000000E2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID     0x000000F0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE         0x000000F1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT  0x000000F2
+#define CKR_USER_ALREADY_LOGGED_IN            0x00000100
+#define CKR_USER_NOT_LOGGED_IN                0x00000101
+#define CKR_USER_PIN_NOT_INITIALIZED          0x00000102
+#define CKR_USER_TYPE_INVALID                 0x00000103
+
+/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
+ * are new to v2.01 */
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN    0x00000104
+#define CKR_USER_TOO_MANY_TYPES               0x00000105
+
+#define CKR_WRAPPED_KEY_INVALID               0x00000110
+#define CKR_WRAPPED_KEY_LEN_RANGE             0x00000112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID       0x00000113
+#define CKR_WRAPPING_KEY_SIZE_RANGE           0x00000114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT    0x00000115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED         0x00000120
+
+/* These are new to v2.0 */
+#define CKR_RANDOM_NO_RNG                     0x00000121
+
+/* These are new to v2.11 */
+#define CKR_DOMAIN_PARAMS_INVALID             0x00000130
+
+/* These are new to v2.0 */
+#define CKR_BUFFER_TOO_SMALL                  0x00000150
+#define CKR_SAVED_STATE_INVALID               0x00000160
+#define CKR_INFORMATION_SENSITIVE             0x00000170
+#define CKR_STATE_UNSAVEABLE                  0x00000180
+
+/* These are new to v2.01 */
+#define CKR_CRYPTOKI_NOT_INITIALIZED          0x00000190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED      0x00000191
+#define CKR_MUTEX_BAD                         0x000001A0
+#define CKR_MUTEX_NOT_LOCKED                  0x000001A1
+
+#define CKR_VENDOR_DEFINED                    0x80000000
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_NOTIFICATION   event,
+  CK_VOID_PTR       pApplication  /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions */
+/* CK_FUNCTION_LIST is new for v2.0 */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+  CK_VOID_PTR_PTR ppMutex  /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS {
+  CK_CREATEMUTEX CreateMutex;
+  CK_DESTROYMUTEX DestroyMutex;
+  CK_LOCKMUTEX LockMutex;
+  CK_UNLOCKMUTEX UnlockMutex;
+  CK_FLAGS flags;
+  CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ *      Bit Flag                           Mask       Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
+#define CKF_OS_LOCKING_OK                  0x00000002
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK     1
+
+/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10. 
+ * CK_RSA_PKCS_OAEP_MGF_TYPE  is used to indicate the Message 
+ * Generation Function (MGF) applied to a message block when 
+ * formatting a message block for the PKCS #1 OAEP encryption 
+ * scheme. */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+#define CKG_MGF1_SHA1         0x00000001
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10. 
+ * CK_RSA_PKCS_OAEP_SOURCE_TYPE  is used to indicate the source
+ * of the encoding parameter when formatting a message block 
+ * for the PKCS #1 OAEP encryption scheme. */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED    0x00000001
+
+/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
+ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the 
+ * CKM_RSA_PKCS_OAEP mechanism. */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+	CK_MECHANISM_TYPE hashAlg;
+	CK_RSA_PKCS_MGF_TYPE mgf;
+	CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+	CK_VOID_PTR pSourceData;
+	CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
+ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s). */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+	CK_MECHANISM_TYPE    hashAlg;
+	CK_RSA_PKCS_MGF_TYPE mgf;
+	CK_ULONG             sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism */
+/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
+typedef struct CK_KEA_DERIVE_PARAMS {
+  CK_BBOOL      isSender;
+  CK_ULONG      ulRandomLen;
+  CK_BYTE_PTR   pRandomA;
+  CK_BYTE_PTR   pRandomB;
+  CK_ULONG      ulPublicDataLen;
+  CK_BYTE_PTR   pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms.  An instance of CK_RC2_PARAMS just
+ * holds the effective keysize */
+typedef CK_ULONG          CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism */
+typedef struct CK_RC2_CBC_PARAMS {
+  /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
+
+  CK_BYTE       iv[8];            /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism */
+/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
+  CK_ULONG      ulMacLength;      /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+  CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms */
+/* CK_RC5_PARAMS is new for v2.0 */
+typedef struct CK_RC5_PARAMS {
+  CK_ULONG      ulWordsize;  /* wordsize in bits */
+  CK_ULONG      ulRounds;    /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism */
+/* CK_RC5_CBC_PARAMS is new for v2.0 */
+typedef struct CK_RC5_CBC_PARAMS {
+  CK_ULONG      ulWordsize;  /* wordsize in bits */
+  CK_ULONG      ulRounds;    /* number of rounds */
+  CK_BYTE_PTR   pIv;         /* pointer to IV */
+  CK_ULONG      ulIvLen;     /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism */
+/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+  CK_ULONG      ulWordsize;   /* wordsize in bits */
+  CK_ULONG      ulRounds;     /* number of rounds */
+  CK_ULONG      ulMacLength;  /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+  CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms.  Its value is the length of
+ * the MAC */
+/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef CK_ULONG          CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+  CK_ULONG      ulPasswordLen;
+  CK_BYTE_PTR   pPassword;
+  CK_ULONG      ulPublicDataLen;
+  CK_BYTE_PTR   pPublicData;
+  CK_ULONG      ulPAndGLen;
+  CK_ULONG      ulQLen;
+  CK_ULONG      ulRandomLen;
+  CK_BYTE_PTR   pRandomA;
+  CK_BYTE_PTR   pPrimeP;
+  CK_BYTE_PTR   pBaseG;
+  CK_BYTE_PTR   pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+  CK_SKIPJACK_PRIVATE_WRAP_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism */
+/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+  CK_ULONG      ulOldWrappedXLen;
+  CK_BYTE_PTR   pOldWrappedX;
+  CK_ULONG      ulOldPasswordLen;
+  CK_BYTE_PTR   pOldPassword;
+  CK_ULONG      ulOldPublicDataLen;
+  CK_BYTE_PTR   pOldPublicData;
+  CK_ULONG      ulOldRandomLen;
+  CK_BYTE_PTR   pOldRandomA;
+  CK_ULONG      ulNewPasswordLen;
+  CK_BYTE_PTR   pNewPassword;
+  CK_ULONG      ulNewPublicDataLen;
+  CK_BYTE_PTR   pNewPublicData;
+  CK_ULONG      ulNewRandomLen;
+  CK_BYTE_PTR   pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+  CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+  CK_BYTE_PTR      pInitVector;
+  CK_UTF8CHAR_PTR  pPassword;
+  CK_ULONG         ulPasswordLen;
+  CK_BYTE_PTR      pSalt;
+  CK_ULONG         ulSaltLen;
+  CK_ULONG         ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism */
+/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+  CK_BYTE       bBC;     /* block contents byte */
+  CK_BYTE_PTR   pX;      /* extra data */
+  CK_ULONG      ulXLen;  /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
+  CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_RANDOM_DATA {
+  CK_BYTE_PTR  pClientRandom;
+  CK_ULONG     ulClientRandomLen;
+  CK_BYTE_PTR  pServerRandom;
+  CK_ULONG     ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+  CK_SSL3_RANDOM_DATA RandomInfo;
+  CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+  CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+  CK_OBJECT_HANDLE hClientMacSecret;
+  CK_OBJECT_HANDLE hServerMacSecret;
+  CK_OBJECT_HANDLE hClientKey;
+  CK_OBJECT_HANDLE hServerKey;
+  CK_BYTE_PTR      pIVClient;
+  CK_BYTE_PTR      pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+  CK_ULONG                ulMacSizeInBits;
+  CK_ULONG                ulKeySizeInBits;
+  CK_ULONG                ulIVSizeInBits;
+  CK_BBOOL                bIsExport;
+  CK_SSL3_RANDOM_DATA     RandomInfo;
+  CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+  CK_BYTE_PTR pData;
+  CK_ULONG    ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+  CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism.  It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key */
+/* CK_EXTRACT_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
+ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to 
+ * indicate the Pseudo-Random Function (PRF) used to generate 
+ * key bits using PKCS #5 PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+/* The following PRFs are defined in PKCS #5 v2.0. */
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
+
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
+ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the 
+ * source of the salt value when deriving a key using PKCS #5 
+ * PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED        0x00000001
+
+/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
+ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the 
+ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+	CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE           saltSource;
+	CK_VOID_PTR                                pSaltSourceData;
+	CK_ULONG                                   ulSaltSourceDataLen;
+	CK_ULONG                                   iterations;
+	CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+	CK_VOID_PTR                                pPrfData;
+	CK_ULONG                                   ulPrfDataLen;
+	CK_UTF8CHAR_PTR                            pPassword;
+	CK_ULONG_PTR                               ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+#endif

Added: trunk/SmartCardServices/src/PKCS11/thread_generic.h
===================================================================
--- trunk/SmartCardServices/src/PKCS11/thread_generic.h	                        (rev 0)
+++ trunk/SmartCardServices/src/PKCS11/thread_generic.h	2009-01-22 01:00:58 UTC (rev 2)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please
+ * obtain a copy of the License at http://www.apple.com/publicsource and
+ * read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
+ * see the License for the specific language governing rights and
+ * limitations under the License.
+ */
+
+/******************************************************************
+
+	MUSCLE SmartCard Development ( http://www.linuxnet.com )
+	    Title  : thread_generic.h
+	    Package: pcsc lite
+            Author : David Corcoran
+            Date   : 3/24/00
+	    License: Copyright (C) 2000 David Corcoran
+	             <corcoran at linuxnet.com>
+            Purpose: This provides system specific thread calls. 
+	            
+********************************************************************/
+
+#ifndef __thread_generic_h__
+#define __thread_generic_h__
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define PCSCLITE_THREAD_T                pthread_t
+#define PCSCLITE_MUTEX                   pthread_mutex_t
+#define PCSCLITE_MUTEX_T                 pthread_mutex_t*
+
+	int SYS_MutexInit(PCSCLITE_MUTEX_T);
+
+	int SYS_MutexDestroy(PCSCLITE_MUTEX_T);
+
+	int SYS_MutexLock(PCSCLITE_MUTEX_T);
+
+	int SYS_MutexUnLock(PCSCLITE_MUTEX_T);
+
+	int SYS_ThreadCreate(PCSCLITE_THREAD_T *, LPVOID, LPVOID, LPVOID);
+
+	int SYS_ThreadCancel(PCSCLITE_THREAD_T *);
+
+	int SYS_ThreadDetach(PCSCLITE_THREAD_T);
+
+        int SYS_ThreadJoin(PCSCLITE_THREAD_T *, LPVOID*);
+
+	int SYS_ThreadExit(LPVOID);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif							/* __thread_generic_h__ */
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/smartcardservices-changes/attachments/20090121/d57c6a9f/attachment-0001.html>


More information about the SmartcardServices-Changes mailing list