/***************************************************************************
 $RCSfile: medium.h,v $
                             -------------------
    cvs         : $Id: medium.h,v 1.30 2003/06/07 20:22:20 aquamaniac Exp $
    begin       : Sun Nov 18 2001
    copyright   : (C) 2001 by Martin Preuss
    email       : openhbci@aquamaniac.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 medium.h
 *
 * @short Abstract base class HBCI::Medium and its C wrapper @ref HBCI_Medium.
 */
#ifndef HBCIMEDIUM_H
#define HBCIMEDIUM_H

#ifdef __cplusplus
#include <string>
#endif

#include <openhbci/dllimport.h>
#include <openhbci/pointer.h>
#include <openhbci/error.h>

#ifdef __cplusplus
namespace HBCI {
    class Medium;
};
/** @ingroup HBCI_Mediumg */
typedef struct HBCI::Medium HBCI_Medium;
#else /* __cplusplus */
typedef struct HBCI_Medium HBCI_Medium;
#endif /* __cplusplus */

/**
 * This enum describes the different medium types OpenHBCI knows about.
 */
typedef enum MediumType {
  /**
   * Unknown type
   */
  MediumTypeUnknown=0,
  /**
   * Card
   */
  MediumTypeCard,

  /**
   * File
   */
  MediumTypeFile
} MediumType;


#include <openhbci/user.h>
#include <openhbci/hbci.h>


#ifdef __cplusplus
namespace HBCI {
/**
 * @short Abstract base class for any security medium in OpenHBCI.
 *
 * This is the abstract base class for accessing security media. It is
 * implemented by RSA file-based media and DES-based chip cards, or
 * maybe even more. The actual type of this medium can be queried
 * through Medium::securityMode.
 *
 * @author Martin Preuss<openhbci@aquamaniac.de> */
class DLLIMPORT Medium {
protected:
  const Hbci *_hbci;
  int _version;
  Pointer<User> _owner;

  string ripe(const string &source);

public:
  /**
   *
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  Medium(const Hbci *hbci);

  virtual ~Medium();

  const Hbci *hbci() const { return _hbci;};

  void setOwner(Pointer<User> u) { _owner=u;};
  Pointer<User> owner() { return _owner;};

  /** @name Medium management
   *
   */
  /*@{*/
  /**
   * Since some media (like hbci chip cards) are able to store multiple
   * account entries you have to select one.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  virtual Error selectContext(int country,
			      const string &instcode,
			      const string &userid)=0;

  /**
   * Mounts a medium and makes its crypto methods available.
   * When reimplementing this you should have a counter to allow
   * nested mounting and unmounting.
   *
   * @param pin The secret PIN that is needed to actually mount this
   * medium. If omitted the user will be asked for it when needed.
   *
   * @author Martin Preuss<openhbci@aquamaniac.de>
   *
   * @return An HBCI::Error, where Error.isOk()==true if medium mounted
   */
  virtual Error mountMedium(const string &pin="")=0;

  /**
   * Unmounts a medium so that it may be removed.
   * See @ref mountMedium() about nested mounts.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @param pin if omitted the user will be asked for it when needed
   * @return nothing, but throws an Error when unmounting fails.
   */
  virtual Error unmountMedium(const string &pin="")=0;

  /**
   * Returns a unique sequence number.
   *
   * This method <i>MUST</i> never return a sequence number it
   * returned before! Therefore the medium will probably <i>save</i>
   * the current sequence number before returning a new
   * one. (Depends on the actual implementation class, of course.)
   *
   * @author Martin Preuss<openhbci@aquamaniac.de> */
  virtual unsigned int nextSEQ()=0;

  /**
   * Change the PIN that is used to protect the medium data.<br>
   * The old and new PIN is requested via the Hbci::interactor()
   */
  virtual Error changePIN()=0;

  /**
   * Change data that is stored on the medium.<br>
   * Note: Each paramter you don't specify is <b>not</b> changed.<br>
   * Note: Not every medium supports all of these parameters, see the
   * medium implementations for details!
   * @param context Some medium types support multiple contexts, use this 
   * parameter to select it (1..n)
   * @param country The new country code (280 for Germany)
   * @param instcode The new institute code
   * @param userid The new user id
   * @param custid The new customer id
   * @param server The new server address
   */
  virtual Error changeContext(int context, int country=0,
			      const string instcode="",
			      const string userid="",
			      const string custid="",
			      const string server="")=0;

  /*@}*/

  /** @name Medium information */
  /*@{*/
  /**
   * Checks whether the medium is mounted.
   *
   * This method checks whether the CORRECT medium is mounted and
   * returns false if no medium or even the wrong medium is
   * mounted.
   *
   * If internal class flags think the medium is mounted but in
   * reality it is not (e.g. chip card was removed from drive), then
   * the internal class flags will be reset accordingly. Hence this
   * method is not <code>const</code>.
   *
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return true if medium mounted, false if not (or on error) */
  virtual bool isMounted() =0;

  /**
   * Returns the id of the medium. For DDV this is the CID of the chip
   * card, for RDH this is the system ID assigned to us by an institute.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  virtual string mediumId() const =0;

  /** Returns the security mode of this
   * medium. E.g. HBCI_SECURITY_DDV or HBCI_SECURITY_RDH.
   *
   * @author Martin Preuss<openhbci@aquamaniac.de> */
  virtual int securityMode() const =0;

  /**
   * Returns the id of the medium.
   *
   * For DDV this is the card number. For RDH this is the name of the file.
   * This is used when saving HBCIUser data to refer to the medium used.
   */
  virtual const string& mediumName() const =0;

  /**
   * Returns the type this medium is of.
   *
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  virtual MediumType mediumType() const =0;

  /**
   * Returns the type name. This is needed to find the responsible
   * MediumPlugin.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  virtual string mediumTypeName() const =0;

  /**
   * Returns the number of the sign key. RDH-media return
   * the number of the users private sign key.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  virtual int signKeyNumber() const =0;

  /**
   * Returns the version of the crypt key. RDH-media return
   * the version of the users private sign key.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  virtual int signKeyVersion() const =0;

  /**
   * Returns the number of the crypt key. RDH-media return
   * the number of the institutes public crypt key.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  virtual int cryptKeyNumber() const =0;

  /**
   * Returns the version of the crypt key. RDH-media return
   * the version of the institutes public crypt key.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   */
  virtual int cryptKeyVersion() const =0;

  /**
   * Returns the context with the given number.
   *
   * Some media are able of storing multiple contexts (like chip
   * cards).  Please note that the medium <i>has to be mounted</i>
   * prior to calling this method.
   *
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return true if a context with that number exists, false on error
   * @param num number of the context (starting with 1)
   * @param countrycode reference to an int var to receive the country code
   * of the context (280 for Germany)
   * @param instcode reference to a string variable to receive the institute
   * code of that context (German "Bankleitzahl")
   * @param userid reference to a string variable to receive the user id of
   * the context (assigned to you by the institute)
   * @param server reference to a string to receive the server address */
  virtual Error getContext(int num,
			   int &countrycode,
			   string &instcode,
			   string &userid,
			   string &server) const =0;
  /*@}*/

  /** @name Cryptographic methods */
  /*@{*/
  /**
   * Creates a key for encryption of data.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return false on error
   */
  virtual string createMessageKey() const =0;

  /**
   * Lets the medium encrypt the key.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return false on error
   * @param srckey the key to encode
   */
  virtual string encryptKey(const string &srckey)=0;

  /**
   * Lets the medium decrypt the key.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return false on error
   * @param srckey the key to decode
   */
  virtual string decryptKey(const string &srckey)=0;

  /**
   * Verify the signature of given data
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return false on error
   * @param data data whose signatur is to be verified
   * @param signature signature to compare against
   */
  virtual Error verify(const string &data, const string &signature)=0;

  /**
   * Sign data
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return false on error
   * @param data data whose signatur is to be created
   */
  virtual string sign(const string &data)=0;

  /**
   * Encrypt data.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return false on error
   * @param src string to encode
   * @param key the key to use for encryption
   */
  virtual string encrypt(const string &src, const string &key);

  /**
   * Decrypt data.
   * @author Martin Preuss<openhbci@aquamaniac.de>
   * @return false on error
   * @param src string to decode
   * @param key the key to use for decryption
   */
  virtual string decrypt(const string &src, const string &key);
  /*@}*/

  /** @name Property handling
   *
   * A property defines a medium type specific attribute.
   * This mechanism can be used to change the behaviour of a medium without
   * the need to recompile or redefine the API of OpenHBCI.
   * A property is defined by a name and a value.
   * It depends on the medium type which property names are recognized.
   * The builtin medium RDHFile currently does not have any properties,
   * but future plugins will.
   */
  /*@{*/
  /**
   * Returns the value of a given property.
   * If the property is not supported by the medium the error code
   * <b>HBCI_ERROR_CODE_UNKNOWN_PROPERTY</b> will be returned.
   * is returned.
   *
   */
  virtual Error getProperty(const string &propertyName,
			    string &propertyValue);

  /**
   * Set the given property to the given value.
   * The following error code can be expected:
   * <ul>
   * <li><b>HBCI_ERROR_CODE_PROPERTY_READONLY</b>: Property is readonly,
   * you cannot change its content</li>
   * <li><b>HBCI_ERROR_CODE_UNKNOWN_PROPERTY</b>: Property is not known to the
   * medium</li>
   * <li><b>HBCI_ERROR_CODE_INVALID_VALUE</b>: Property valuer is invalid</li>
   * </ul>
   */
  virtual Error setProperty(const string &propertyName,
			    const string &propertyValue);

  /*@}*/

};

} /* namespace HBCI */

extern "C" {
#endif /* __cplusplus */

  /** @defgroup HBCI_Mediumg HBCI_Medium and derivations */
  /*@{*/
  /** @name Medium management */
  /*@{*/
  /**
   * Since some media (like hbci chip cards) are able to store multiple
   * account entries you have to select one.
   */
  extern HBCI_Error * HBCI_Medium_selectContext(HBCI_Medium *h,
						int country,
						const char *instcode,
						const char *userid);
  /**
   * Mounts a medium and makes its crypto methods available.
   *
   * @param h The medium to perform this action on.
   *
   * @param pin The secret PIN that is needed to actually mount this
   * medium (FIXME: is this correct?). May be NULL.
   * @return NULL if medium mounted, or the HBCI_Error if one occurred.
   */
  extern HBCI_Error *
    HBCI_Medium_mountMedium(HBCI_Medium *h, const char *pin);

  /**
   * Unmounts a medium so that it may be removed.
   * See @ref mountMedium() about nested mounts.
   * @param h The medium to perform this action on.
   * @param pin The secret PIN that is needed to actually mount this
   * medium. May be NULL.
   * @return NULL if medium unmounted, or the HBCI_Error if one occurred.
   */
  extern HBCI_Error *
    HBCI_Medium_unmountMedium(HBCI_Medium *h, const char *pin);
  /*@}*/

  /** @name Medium information */
  /*@{*/
  /**
   * Checks whether the medium is mounted.
   * This method should check if the CORRECT medium is mounted and return
   * false if no medium or even a false medium is mounted.
   * @param h The medium to perform this action on.
   * @return TRUE (1) if medium mounted, FALSE (0) if not (or on error)
   */
  extern int HBCI_Medium_isMounted(HBCI_Medium *h);

  /**
   * Returns the id of the medium. For DDV this is the CID of the chip
   * card, for RDH this is the system ID assigned to us by an institute.
   * @param h The medium to perform this action on.
   * @return Pointer to the string with the Id. MUST be free'd by the
   * caller when no longer needed.
   */
  extern char *HBCI_Medium_mediumId(const HBCI_Medium *h);

  /**
   * Returns the security mode of this medium (DDV, RDH)
   */
  extern int HBCI_Medium_securityMode(const HBCI_Medium *h);

  /**
   * Returns the name of the medium.
   *
   * For DDV this is the card number. For RDH this is the name of the file.
   * This is used when saving HBCIUser data to refer to the medium used.
   */
  extern const char *HBCI_Medium_mediumName(const HBCI_Medium *h);

  /**
   * Returns the context with the given number.
   * Some media are able of storing multiple contexts (like chip cards).
   * Please note that the medium has to be mounted prior to calling this
   * method.
   *
   * @return NULL if a context with that number exists, or HBCI_Error
   * on error. 
   *
   * @param h The medium to perform this action on.
   * @param num number of the context (starting with 1)
   * @param countrycode reference to an int var to receive the country code
   * of the context (280 for Germany)
   *
   * @param instcode reference to a string variable to receive the
   * institute code of that context (German "Bankleitzahl"). To be
   * free'd by the caller, but only if this method didn't return a
   * HBCI_Error, in which case this parameter is left unchanged.
   *
   * @param userid reference to a string variable to receive the user
   * id of the context (assigned to you by the institute). To be
   * free'd by the caller, but only if this method didn't return a
   * HBCI_Error, in which case this parameter is left unchanged.
   *
   * @param server reference to a string to receive the server
   * address.  To be free'd by the caller, but only if this method
   * didn't return a HBCI_Error, in which case this parameter is left
   * unchanged.
   */
  extern HBCI_Error * HBCI_Medium_getContext(const HBCI_Medium *h,
					     int num,
					     int *countrycode,
					     char **instcode,
					     char **userid,
					     char **server);
  /*@}*/
  /*@}*/

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif

