/***************************************************************************
  $RCSfile: ctcard.h,v $
                             -------------------
    cvs         : $Id: ctcard.h,v 1.14 2003/02/11 03:29:57 aquamaniac Exp $
    begin       : Tue Aug 28 2001
    copyright   : (C) 2001 by Martin Preuss
    email       : martin@libchipcard.de


 ***************************************************************************
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
 *   MA  02111-1307  USA                                                   *
 *                                                                         *
 ***************************************************************************/

/**
 * @file ctcard.h
 * @short Contains the definition of CTCard.
 */

/**
 * @mainpage Libchipcard Ducumentation Main Page
 *
 * @section quickstart Quickstart
 * The main class you'll have to deal with is @ref CTCard and its derived
 * classes. So if you want immediately start coding please go to the
 * documentation of @ref CTCard.<br>
 * If you are more interested in the new Card File System then
 * @ref CTCardFS is your friend.
 *
 * @section whatis What Is Libchipcard ?
 * %Libchipcard is a library for easy access to smart cards. It is written
 * in C++ and should therefore work on most Unix-like platforms, and it also
 * works under WIN32.
 *
 * @section whatneed What Does Libchipcard Need ?
 * It needs
 * <ul>
 *  <li>
 *   card reader terminal supported by your operating system
 *  </li>
 *  <li>
 *   a driver for that reader (called CTAPI). The homepage of
 *   <a href="http://www.libchipcard.de">libchipcard</a> provides a list of
 *   links to drivers for some readers.
 *  </li>
 *  <li>
 *   OpenSSL: This is needed for encryption of data on a smart card using
 *   the @ref CTCardFS and for encryption of traffic between client and
 *   server.
 *  </li>
 * </ul>
 *
 * @section whatrec What Is Recommended ?
 * %Libchipcard works best when the following packages are provided:
 * <ul>
 *  <li>
 *   QT/KDE: %Libchipcard provides some KDE-tools. You will need KDE and QT
 *   in order to use them. KDE/QT 2 and 3 are supported.
 *  </li>
 * </ul>
 *
 * @section authors Authors
 * Martin Preu&szlig; &lt;
 * <a href="mailto:martin@libchipcard.de">martin@libchipcard.de</a>
 * &gt;
 *
 */

/**
 * @defgroup c_api C API
 *
 * This group contains the functions of the C core API of LibChipCard. This
 * is internally used by the @ref CTCard and derived classes.
 */

/**
 * @defgroup cards Card Classes
 *
 * This group contains card classes
 */

/**
 * @defgroup gcards General Card Classes
 * @ingroup cards
 *
 * This group contains general card classes (for memory cards and processor
 * cards)
 */

/**
 * @defgroup scards Special Card Classes
 *
 * This group contains classes which deal with special cards (like HBCI
 * cards and others)
 */

/**
 * @defgroup misc This and That
 *
 * This group contains several classes which do not belong to any other
 * group.
 */

/**
 * @defgroup status Status and error classes
 *
 * Contains classes that flag errors or give a kind of status.
 */


/**
 * @defgroup cardfs Card File System
 *
 * This group contains the classes of the LibChipcard Card File System.
 */

/**
 * @defgroup corecardfs Core of the Card File System
 * @ingroup cardfs
 *
 * This group contains classes of the core of the Card File System.
 */

/**
 * @defgroup llcardfs Low Level Card File System
 * @ingroup cardfs
 * This group contains quite low level classes for direct access to the
 * Card File System
 */

/**
 * @defgroup hlcardfs Higher Level Card File System
 * @ingroup cardfs
 *
 * This group contains higher level classes of the Card File System.
 * The main class here is @ref CTCardFS.
 */


/**
 * @defgroup netrpc Networking and RPC
 *
 * Classes which deal with network operations or perform remote procedure
 * calls.
 */


#ifndef CTCARD_H
#define CTCARD_H

class CTCard;

#define k_CTCARD_READSIZE 255


#include <string>
#include <list>

#include "chipcard/libchipcard.h"
#include "chipcard/cterror.h"
#include "chipcard/ctpointer.h"
#include "chipcard/ctcommand.h"



/**
 * This is just to let you mount/unmount a card, request its status
 * etc. It is very general. Special things are done in the classes
 * which inherit this one (like @ref CTMemoryCard and @ref CTProcessorCard.
 * This class (and its children) is the C++ interface to libchipcard.
 * When there is interaction with the card reader/card necessary then this
 * class will automatically create all other objects/structs whatsoever on
 * the fly. These things are all hidden from you, so you only have to
 * concentrate on this class here.
 * @ingroup gcards
 * @short This class describes a chipcard.
 * @author Martin Preuss<martin@libchipcard.de>
 */
class CHIPCARD_API CTCard {
public:
  typedef enum {
    CallBackContinue=0,
    CallBackAbort
  } CallBackResult;

  /**
   * The callback is called when CTCard is waiting for a server response.
   * You can set the callback with @ref setCallBack().
   * The first parameter is true if this is the first call (false otherwise).
   * The second parameter is that one given to setCallBack().
   */
  typedef CallBackResult (*CallBack)(bool first, void *p);

private:
  int _terminalId;
  int _terminalHandle;
  string _readerName;
  string _readerType;
  unsigned int _readerFlags;
  string _atr;
  int _preferredFlags;
  int _preferredFlagsMask;

  int _openCount;
  int _termOpenCount;
  unsigned int _cardStatus;
  unsigned int _memsize;
  unsigned int _timeout;

  CallBack _callback;
  void *_callbackParam;

  string _cmdSelectFile;
  string _cmdSelectFileId;
  string _cmdReadBinary;
  string _cmdUpdateBinary;

  int _openLibrary();
  int _responseLoop(int reqid, int maxloop);
  int _findTerminal(int *termid,
		    unsigned int flags,
		    unsigned int flagsMask);
  int _allocTerminal(int termid, int *termhandle,
		     CHIPCARD_READERDESCR **rd);
  int _connectTerminal(int tid);
  int _disconnectTerminal(int tid);
  int _statTerminal(unsigned int *status);
  int _releaseTerminal(int tid);
  int _openCard();
  int  _closeCard(bool force, bool eject);
  int _openTerminal();
  int _closeTerminal(bool force);
  CTError _locateCommandReader(const string &command,
			       const string &reader,
			       string &result);
  CTError _locateCommand(const string &command,
			 string &result);


public:
  /** @name Constructors/Destructor
   *
   */
  //@{
  /**
   * Constructor. This one does no interaction with the terminal reader.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  CTCard();

  /**
   * This constructor is mainly used by derived classes to transform
   * a basic CTCard object to a more special one. This allows opening a
   * card as a CTCard object and then create e.g. a CTMemoryCard from
   * this one. The source card will be immediately closed. The only thing
   * you should do with it is to delete it. You should NOT use it any
   * longer !!
   * @param c reference to the CTCard object to be transformed
   * @author Martin Preuss<martin@libchipcard.de>
   */
  CTCard(CTCard &c);

  virtual ~CTCard();
  //@}

  /** @name Opening and closing operations
   *
   * Methods to connect and disconnect the card. Most other methods
   * only work if the card is open.
   */
  //@{
  /**
   * Opens the card for usage.
   * This way the card is powered on.
   * This method does some basic checks and retrieves basic information
   * about the card (whether it is a memory card or a processor card,
   * the size of the memory etc).
   * When this method successfully returns the card may be used.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   */
  virtual CTError openCard();

  /**
   * Call this if you have finished working with the card. After this
   * method is called you may safely remove the card from the reader.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   */
  virtual CTError closeCard(bool force=false, bool eject=false);

  /**
   * Returns true if card is open, false otherwise
   * @author Martin Preuss<martin@libchipcard.de>
   */
  bool isOpen() const { return _openCount>0;};

  /**
   * When this method is called normally the card is already opened by
   * means of @ref openCard(). However, it is likely that openCard() has
   * been called assuming this card is only a CTCard() object, nothing
   * special. You may then call THIS method here on all known card classes
   * to check for the type of this card.
   * This method must assume that any file on the card is already selected,
   * so it is in most cases a good idea to select the MF as the first action
   * of this method.
   * If the executing class finds that the card inserted is not of a type
   * it can handle then it MUST return an error.
   */
  virtual CTError reopenCard();
  //@}

  /** @name Informational methods
   *
   * These methods tell you about the type and the status of the card.
   */
  //@{
  /**
   * This method returns a short name of the class which handles this card.
   * A HBCI card for example returns "HBCICard". So you can use this method
   * to check for the type of the card.
   */
  virtual string cardType();

  /**
   * This method returns a comma separated list of all card types this card
   * inherits including the type of this card, e.g. a HBCI card would
   * return "CTProcessorCard, HBCICard". If you overload this method in your
   * own class (you SHOULD) you simply have to call this method of the
   * class it directly inherits. That class will then do the same, so that
   * there is a list upon return.
   */
  virtual string cardTypes();

  /**
   * Returns true if the card is a processor card.
   * This is only valid if the card is open.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  bool isProcessorCard();

  /**
   * Returns the size of the memory on the card. Mostly used with
   * memory cards, while processor cards sometimes return 0 (like the
   * hbci card does). Please note that some cards seem to be lieing about
   * their size !
   * This is only valid if the card is open.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return size of memory in bytes
   */
  unsigned int memorySize() const { return _memsize;};

  /**
   * Returns the ATR-String. This string is received upon reset of a
   * chip card and holds interesting information about the card.
   * This class itself gathers much information from this answer, but you
   * rarely need this.
   * This is only valid if the card is open.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return the ATR string
   */
  const string &atr() const { return _atr;};

  /**
   * Returns the reader flags of the currently used reader
   * Possible flags are (bits can be ORed):
   * <ul>
   *  <li>CHIPCARD_READERFLAGS_KEYPAD</li>
   *  <li>CHIPCARD_READERFLAGS_DISPLAY</li>
   * </ul>
   * These flags are only valid if the card is open.
   */
  unsigned int readerFlags() const { return _readerFlags;};

  /**
   * Checks if a card is inserted (does not check if the card is
   * CONNECTED, it only checks if there IS a card).
   * @author Martin Preuss<martin@libchipcard.de>
   * @return true if a card is inserted
   */
  bool isInserted();

  /**
   * Checks if a card is connected.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return true if a card is connected
   */
  bool isConnected();

  /**
   * This method waits for a special card to be inserted.
   * It first waits for a card, then opens the card and calls @ref checkCard.
   * If checkCard shows that the currently inserted card is that card we want
   * then this method returns with success.
   * If the checkCard shows that this card is not the requested one then this
   * card is closed and this method waits for the next card.
   * This method calls @ref doCallBack.
   * If this methd successfully returns then the card is already open, so you
   * will need to close it later!
   * (new since 0.7.3)
   * @author Martin Preuss<martin@libchipcard.de>
   * @return error (call isOk() on it to see if there's an error)
   * @param timeout timeout in seconds for the whole operation
   * @param next see @ref startWaitForCard
   * @param readerFlags see @ref startWaitForCard
   * @param readerFlagsMask see @ref startWaitForCard
   * @param status see @ref startWaitForCard
   * @param statusMask see @ref startWaitForCard
   */
  CTError getCard(int timeout=0,
		  bool next=false,
		  unsigned int readerFlags=0,
		  unsigned int readerFlagsMask=0,
		  unsigned int status=0,
		  unsigned int statusMask=CHIPCARD_STATUS_LOCKED_BY_OTHER);

  /**
   * This is the callback method called by @ref getCard(). The default
   * implementation simply returns "OK", but your own class may overload this
   * method in order to check for a special card (using a serial number or
   * whatever). If the returned error code is k_CTERROR_API and subcode1()
   * is CHIPCARD_ERROR_ABORTED then getCard() will abort upon return from
   * this method here.
   * (new since 0.7.3)
   * @author Martin Preuss<martin@libchipcard.de>
   * @return CTError
   * @param readerFlags flags describing the reader
   * (see @ref startWaitForCard)
   * @param readerStatus status of the reader (see @ref startWaitForCard)
   */
  virtual CTError checkCard(unsigned int readerFlags,
			    unsigned int readerStatus);

  /**
   * This method waits for any reader whose status and flags match the
   * given criteria. If a matching reader could be found it will
   * automatically be selected for the next call to @ref openCard.
   * This is just a conveniance method which calls @ref startWaitForCard(),
   * @ref checkWaitForCard() and @ref stopWaitForCard()
   * DEPRECATED(0.8). Please use @ref getCard instead.
   */
  bool waitForCard(int timeout,
		   bool next,
		   unsigned int &readerFlags,
		   unsigned int readerFlagsMask,
		   unsigned int &status,
		   unsigned int statusMask);

  /**
   * Starts waiting for cards. This will send a request to the server telling
   * him to notify us about changes in status of all readers matching the
   * given specs.
   * The flags/status an their masks are used as follows:
   * The first gives the flags which have to match those of a reader, the
   * second is the mask. Only those flags whose corresponding mask bit
   * contains a "1" will be compared. An example:<br>
   * You want to wait for a processor card in a reader which has a keypad.
   * So you'll have to call this:<br>
   * unsigned int readerflags, readerstatus;
   * readerflags=CHIPCARD_READERFLAGS_KEYPAD;
   * readerstatus=CHIPCARD_STATUS_INSERTED|CHIPCARD_STATUS_PROCESSOR;
   * startWaitForCard(TIMEOUT,
   *                  readerflags,
   *                  CHIPCARD_READERFLAGS_KEYPAD,
   *                  readerstatus,
   *                  CHIPCARD_STATUS_INSERTED|CHIPCARD_STATUS_PROCESSOR)<br>
   * When looking for a memory card in such a reader, the call would be<br>
   * unsigned int readerflags, readerstatus;
   * readerflags=CHIPCARD_READERFLAGS_KEYPAD;
   * readerstatus=CHIPCARD_STATUS_INSERTED;
   * startWaitForCard(TIMEOUT,
   *                  readerflags,
   *                  CHIPCARD_READERFLAGS_KEYPAD,
   *                  readerstatus,
   *                  CHIPCARD_STATUS_INSERTED|CHIPCARD_STATUS_PROCESSOR)<br>
   * If a matching card is inserted into a matching reader it will be
   * selected for use by subsequent calls to @ref openCard().
   * @return true if a reader with a matching status has been found
   * @param timeout limit of time to wait in seconds
   * @param next if true then we want the <b>next</b> card compared. That
   * means that an already inserted card will not match unless it is removed
   * and reinserted again. You can use this flag when waiting for a card after
   * having inspected the currently inserted one.
   * @param readerFlags this holds the readerFlags the reader has to
   * match. Currently the following values are valid:
   * <ul>
   * <li>CHIPCARD_READERFLAGS_KEYPAD</li>
   * <li>CHIPCARD_READERFLAGS_DISPLAY</li>
   * </ul>
   * Upon return this variable contains the full real flags of the reader, if
   * the return value is true.
   * @param readerFlagsMask this argument is used to select the readerflags
   * you want to be matching. When checking for a match only those readerflags
   * whose corresponding mask shows a "1" will be compared.
   * @param status the status of the reader to match. Currently the following
   * status values (which can be ORed) are valid:
   * <ul>
   * <li>CHIPCARD_STATUS_INSERTED</li>
   * <li>CHIPCARD_STATUS_CONNECTED</li>
   * <li>CHIPCARD_STATUS_PROCESSOR</li>
   * <li>CHIPCARD_STATUS_LOCKED_BY_OTHER</li>
   * </ul>
   * Upon return this variable contains the full real status of the reader, if
   * the return value is true.
   * DEPRECATED(0.8). Please use @ref getCard instead.
   * @param statusMask mask for the status to match (only those status bits
   * which have a "1" in their mask will match)
   */
  int startWaitForCard(int &requestid,
		       bool next,
		       unsigned int readerFlags,
		       unsigned int readerFlagsMask,
		       unsigned int status,
		       unsigned int statusMask);

  /**
   * Check whether there are responses from the server in this matter.
   * If there was any, then the reader returned by the server will be
   * selected for the next call to openCard().
   * DEPRECATED(0.8). Please use @ref getCard instead.
   */
  int checkWaitForCard(int requestid,
		       int timeout,
		       unsigned int &readerFlags,
		       unsigned int &status);

  /**
   * This tells the server that we are not interested in change notifications
   * specified by the requestid anymore. The requestid is that returned by
   * DEPRECATED(0.8). Please use @ref getCard instead.
   * @ref startWaitForCard().
   * @return true if ok, false on error
   * @param requestid id returned by @ref startWaitForCard()
   */
  int stopWaitForCard(int requestid);

  /**
   * Checks whether a matching reader exists. You can use this to select a
   * reader by features (such as hasKeypad, hasDisplay).
   * If a reader has been found it will be selected for subsequent calls
   * to @ref openCard().
   * @return true if reader found, false otherwise
   */
  bool findReader(unsigned int readerFlags,
		  unsigned int readerFlagsMask);

  /**
   * This method allows setting a callback function. This will be called
   * while the class is waiting for a response from a server. You can use
   * this to keep the GUI of your application updated or to allow the user
   * to abort an action.
   * @param cb callback (choose 0 to stop the callback mechanism)
   * @param p user defined parameter to be passed to the callback as its 2nd
   * argument
   */
  void setCallBack(CallBack cb, void *p);

  /**
   * This method is called whenever a user defined callback is to be called.
   * This is the cases when in a loop waiting for a server response.
   * The default implementation calls the callback given by
   * @ref setCallBack(). However, you may overload this method to handle the
   * call back stuff yourself.
   * @param first if this is true then it is the first call to the call back
   * in this waiting-for-response loop, otherwise it is not
   */
  virtual CallBackResult doCallBack(bool first);

  /**
   * Set the timeout when waiting for a server response (default is
   * 30 seconds).
   * @param t timeout in seconds
   */
  void setTimeout(int t) { _timeout=t;};

  /**
   * Get the timeout when waiting for a server response (default is
   * 30 seconds).
   */
  int timeout() { return _timeout;};

  //@}


  /** @name Commands
   *
   * These methods allow you to send a command to the card. Of course the
   * card needs to be already open.
   */
  //@{
  /**
   * Sends a command to the card reader terminal and retrieves its answer.
   * When this method returns the members lr, sw1,
   * sw2 and data are changed to reflect the answer.
   * This method is used by EVERY other command method
   * (like @ref selectFile(), @ref readBinary() etc).
   * @author Martin Preuss<martin@libchipcard.de>
   * @param cmd reference to the CTCommand struct
   * @return @ref CTError object that holds the result (call isOk() to see if
   * there was an error)
   */
  CTError execCommand(CTCommand &cmd);

  /**
   * This method sends a raw APDU to the card reader and returns the answer.
   */
  CTError sendAPDU(const string &apdu, string &response);

  /**
   * This method sends a command using the config file driven command engine.
   * You specify the name of the command (like "read_binary" and the
   * parameters to it (for "read_binary" this would be the offset and size of
   * the data to read).
   * @return reuslt of the operation (call isOk() on it)
   * @param command name of the command to execute
   * @param cmdCache this string will be used to store the fully resolved
   * path and name of the command. The command given (e.g. "read_binary") will
   * be looked up internally, thereby taking into account the type of the
   * reader and the card to which the command is to be applied. If the command
   * has been found its full path will be stored in this variable. However,
   * if this string is not empty upon call this method assumes that the cache
   * already contains the full path, so it will not be looked up.
   * @param response reference to a string to receive the response
   * @param param1 first parameter to the command
   * @param param2 2nd parameter to the command
   * @param param3 3rd parameter to the command
   */
  CTError doCommand(const string &command,
		    string &cmdCache,
		    string &response,
		    const string &param1="",
		    const string &param2="",
		    const string &param3="",
		    const string &param4="",
		    const string &param5="");

  /**
   * This is the simplest form of the select file command.
   * It should work with every card.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   * @param fcp a reference to a string to receive the FCI
   * @param fid the two byte file identifier
   */
  CTError selectFile(string &fcp, unsigned short fid);

  /**
   * This is the simplest form of the select file command.
   * It should work with every card.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   * @param fcp a reference to a string to receive the FCI
   * @param fid file identifier
   */
  CTError selectFile(string &fcp, const string &fid);

  /**
   * Reads data from the currently selected file.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param data reference to a string to receive the data
   * @param offset guess what ;-)
   * @param size how many bytes do you want to read today ?
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   */
  CTError readBinary(string &data,
		     unsigned int offset,
		     unsigned int size);

  CTError readBinaryRaw(string &data,
			unsigned short offset,
			unsigned char size);

  /**
   * Writes data into the currently selected file.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   * @param data reference to a string to be send
   * @param offset guess what ;-) Please note that some cards do not allow
   * to write the first 26 bytes !
   * @param number of bytes to send
   */
  CTError updateBinary(const string &data,
		       unsigned int offset);


  CTError updateBinaryRaw(const string &data,
			  unsigned short offset);
  //@}
};






#endif






