/***************************************************************************
    begin       : Wed Mar 16 2005
    copyright   : (C) 2005-2010 by Martin Preuss
    email       : martin@libchipcard.de

 ***************************************************************************
 *          Please see toplevel file COPYING for license details           *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#define DISABLE_DEBUGLOG


#include "ct_p.h"
#include "i18n_l.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/gui.h>



GWEN_INHERIT_FUNCTIONS(GWEN_CRYPT_TOKEN)
GWEN_LIST_FUNCTIONS(GWEN_CRYPT_TOKEN, GWEN_Crypt_Token)
GWEN_LIST2_FUNCTIONS(GWEN_CRYPT_TOKEN, GWEN_Crypt_Token)





GWEN_CRYPT_TOKEN *GWEN_Crypt_Token_new(GWEN_CRYPT_TOKEN_DEVICE dev,
                                       const char *typeName,
                                       const char *tokenName)
{
  GWEN_CRYPT_TOKEN *ct;

  assert(typeName);

  GWEN_NEW_OBJECT(GWEN_CRYPT_TOKEN, ct);
  ct->refCount=1;
  GWEN_INHERIT_INIT(GWEN_CRYPT_TOKEN, ct);
  GWEN_LIST_INIT(GWEN_CRYPT_TOKEN, ct);

  ct->device=dev;
  ct->typeName=strdup(typeName);
  if (tokenName)
    ct->tokenName=strdup(tokenName);

  return ct;
}



void GWEN_Crypt_Token_free(GWEN_CRYPT_TOKEN *ct)
{
  if (ct) {
    assert(ct->refCount);
    if (ct->refCount==1) {
      GWEN_LIST_FINI(GWEN_CRYPT_TOKEN, ct);
      GWEN_INHERIT_FINI(GWEN_CRYPT_TOKEN, ct);
      free(ct->tokenName);
      free(ct->typeName);
      ct->refCount=0;
      GWEN_FREE_OBJECT(ct);
    }
    else {
      ct->refCount--;
    }
  }
}



GWEN_CRYPT_TOKEN_DEVICE GWEN_Crypt_Token_GetDevice(const GWEN_CRYPT_TOKEN *ct)
{
  assert(ct);
  assert(ct->refCount);

  return ct->device;
}



const char *GWEN_Crypt_Token_GetTypeName(const GWEN_CRYPT_TOKEN *ct)
{
  assert(ct);
  assert(ct->refCount);

  return ct->typeName;
}



const char *GWEN_Crypt_Token_GetTokenName(const GWEN_CRYPT_TOKEN *ct)
{
  assert(ct);
  assert(ct->refCount);

  return ct->tokenName;
}



void GWEN_Crypt_Token_SetTokenName(GWEN_CRYPT_TOKEN *ct, const char *s)
{
  assert(ct);
  assert(ct->refCount);

  assert(s);

  free(ct->tokenName);
  ct->tokenName=strdup(s);
}



const char *GWEN_Crypt_Token_GetFriendlyName(const GWEN_CRYPT_TOKEN *ct)
{
  assert(ct);
  assert(ct->refCount);

  return ct->friendlyName;
}



void GWEN_Crypt_Token_SetFriendlyName(GWEN_CRYPT_TOKEN *ct, const char *s)
{
  assert(ct);
  assert(ct->refCount);

  assert(s);

  free(ct->friendlyName);
  ct->friendlyName=strdup(s);
}



uint32_t GWEN_Crypt_Token_GetFlags(const GWEN_CRYPT_TOKEN *ct)
{
  assert(ct);
  assert(ct->refCount);

  return ct->flags;
}



void GWEN_Crypt_Token_SetFlags(GWEN_CRYPT_TOKEN *ct, uint32_t f)
{
  assert(ct);
  assert(ct->refCount);

  ct->flags=f;
}



void GWEN_Crypt_Token_AddFlags(GWEN_CRYPT_TOKEN *ct, uint32_t f)
{
  assert(ct);
  assert(ct->refCount);

  ct->flags|=f;
}



void GWEN_Crypt_Token_SubFlags(GWEN_CRYPT_TOKEN *ct, uint32_t f)
{
  assert(ct);
  assert(ct->refCount);

  ct->flags&=~f;
}



uint32_t GWEN_Crypt_Token_GetModes(const GWEN_CRYPT_TOKEN *ct)
{
  assert(ct);
  assert(ct->refCount);

  return ct->modes;
}



void GWEN_Crypt_Token_SetModes(GWEN_CRYPT_TOKEN *ct, uint32_t f)
{
  assert(ct);
  assert(ct->refCount);

  ct->modes=f;
}



void GWEN_Crypt_Token_AddModes(GWEN_CRYPT_TOKEN *ct, uint32_t f)
{
  assert(ct);
  assert(ct->refCount);

  ct->modes|=f;
}



void GWEN_Crypt_Token_SubModes(GWEN_CRYPT_TOKEN *ct, uint32_t f)
{
  assert(ct);
  assert(ct->refCount);

  ct->modes&=~f;
}



int GWEN_Crypt_Token_Open(GWEN_CRYPT_TOKEN *ct, int admin, uint32_t gid)
{
  int rv;

  assert(ct);
  assert(ct->refCount);

  if (ct->openCount) {
    ct->openCount++;
    return 0;
  }

  if (ct->openFn)
    rv=ct->openFn(ct, admin, gid);
  else
    rv=GWEN_ERROR_NOT_IMPLEMENTED;

  if (rv==0)
    ct->openCount++;
  return rv;
}



int GWEN_Crypt_Token_Create(GWEN_CRYPT_TOKEN *ct, uint32_t gid)
{
  int rv;

  assert(ct);
  assert(ct->refCount);

  if (ct->createFn)
    rv=ct->createFn(ct, gid);
  else
    rv=GWEN_ERROR_NOT_IMPLEMENTED;

  if (rv==0)
    ct->openCount++;
  return rv;
}



int GWEN_Crypt_Token_Close(GWEN_CRYPT_TOKEN *ct, int abandon, uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount>1 && !abandon) {
    ct->openCount--;
    return 0;
  }

  if (ct->closeFn) {
    int rv;

    rv=ct->closeFn(ct, abandon, gid);
    if (abandon)
      ct->openCount=0;
    else if (rv==0)
      ct->openCount--;
    return rv;
  }
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



int GWEN_Crypt_Token_IsOpen(const GWEN_CRYPT_TOKEN *ct)
{
  assert(ct);
  assert(ct->refCount);

  return (ct->openCount!=0);
}



int GWEN_Crypt_Token_GetKeyIdList(GWEN_CRYPT_TOKEN *ct,
                                  uint32_t *pIdList,
                                  uint32_t *pCount,
                                  uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->getKeyIdListFn)
    return ct->getKeyIdListFn(ct, pIdList, pCount, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



const GWEN_CRYPT_TOKEN_KEYINFO *GWEN_Crypt_Token_GetKeyInfo(GWEN_CRYPT_TOKEN *ct,
                                                            uint32_t id,
                                                            uint32_t flags,
                                                            uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1) {
    DBG_INFO(GWEN_LOGDOMAIN, "Token not open");
    return NULL;
  }

  if (ct->getKeyInfoFn)
    return ct->getKeyInfoFn(ct, id, flags, gid);
  else
    return NULL;
}



int GWEN_Crypt_Token_SetKeyInfo(GWEN_CRYPT_TOKEN *ct,
                                uint32_t id,
                                const GWEN_CRYPT_TOKEN_KEYINFO *ki,
                                uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->setKeyInfoFn)
    return ct->setKeyInfoFn(ct, id, ki, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



int GWEN_Crypt_Token_GetContextIdList(GWEN_CRYPT_TOKEN *ct,
                                      uint32_t *pIdList,
                                      uint32_t *pCount,
                                      uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->getContextIdListFn)
    return ct->getContextIdListFn(ct, pIdList, pCount, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



const GWEN_CRYPT_TOKEN_CONTEXT *GWEN_Crypt_Token_GetContext(GWEN_CRYPT_TOKEN *ct,
                                                            uint32_t id,
                                                            uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1) {
    DBG_INFO(GWEN_LOGDOMAIN, "Token not open");
    return NULL;
  }

  if (ct->getContextFn)
    return ct->getContextFn(ct, id, gid);
  else
    return NULL;
}



int GWEN_Crypt_Token_SetContext(GWEN_CRYPT_TOKEN *ct,
                                uint32_t id,
                                const GWEN_CRYPT_TOKEN_CONTEXT *ctx,
                                uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->setContextFn)
    return ct->setContextFn(ct, id, ctx, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



int GWEN_Crypt_Token_Sign(GWEN_CRYPT_TOKEN *ct,
                          uint32_t keyId,
                          GWEN_CRYPT_PADDALGO *a,
                          const uint8_t *pInData,
                          uint32_t inLen,
                          uint8_t *pSignatureData,
                          uint32_t *pSignatureLen,
                          uint32_t *pSeqCounter,
                          uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->signFn)
    return ct->signFn(ct, keyId, a, pInData, inLen, pSignatureData, pSignatureLen,
                      pSeqCounter, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



int GWEN_Crypt_Token_Verify(GWEN_CRYPT_TOKEN *ct,
                            uint32_t keyId,
                            GWEN_CRYPT_PADDALGO *a,
                            const uint8_t *pInData,
                            uint32_t inLen,
                            const uint8_t *pSignatureData,
                            uint32_t signatureLen,
                            uint32_t seqCounter,
                            uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->verifyFn)
    return ct->verifyFn(ct, keyId, a, pInData, inLen, pSignatureData, signatureLen,
                        seqCounter, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



int GWEN_Crypt_Token_Encipher(GWEN_CRYPT_TOKEN *ct,
                              uint32_t keyId,
                              GWEN_CRYPT_PADDALGO *a,
                              const uint8_t *pInData,
                              uint32_t inLen,
                              uint8_t *pOutData,
                              uint32_t *pOutLen,
                              uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->encipherFn)
    return ct->encipherFn(ct, keyId, a, pInData, inLen, pOutData, pOutLen, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



int GWEN_Crypt_Token_Decipher(GWEN_CRYPT_TOKEN *ct,
                              uint32_t keyId,
                              GWEN_CRYPT_PADDALGO *a,
                              const uint8_t *pInData,
                              uint32_t inLen,
                              uint8_t *pOutData,
                              uint32_t *pOutLen,
                              uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->decipherFn)
    return ct->decipherFn(ct, keyId, a, pInData, inLen, pOutData, pOutLen, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}




int GWEN_Crypt_Token_GenerateKey(GWEN_CRYPT_TOKEN *ct,
                                 uint32_t keyId,
                                 const GWEN_CRYPT_CRYPTALGO *a,
                                 uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->generateKeyFn)
    return ct->generateKeyFn(ct, keyId, a, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



int GWEN_Crypt_Token_ChangePin(GWEN_CRYPT_TOKEN *ct, int admin, uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->changePinFn)
    return ct->changePinFn(ct, admin, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}



int  GWEN_Crypt_Token_ActivateKey(GWEN_CRYPT_TOKEN *ct, uint32_t id, uint32_t gid)
{
  assert(ct);
  assert(ct->refCount);

  if (ct->openCount<1)
    return GWEN_ERROR_NOT_OPEN;

  if (ct->activateKeyFn)
    return ct->activateKeyFn(ct, id, gid);
  else
    return GWEN_ERROR_NOT_IMPLEMENTED;
}






GWEN_CRYPT_TOKEN_OPEN_FN GWEN_Crypt_Token_SetOpenFn(GWEN_CRYPT_TOKEN *ct,
                                                    GWEN_CRYPT_TOKEN_OPEN_FN f)
{
  GWEN_CRYPT_TOKEN_OPEN_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->openFn;
  ct->openFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_CREATE_FN GWEN_Crypt_Token_SetCreateFn(GWEN_CRYPT_TOKEN *ct,
                                                        GWEN_CRYPT_TOKEN_CREATE_FN f)
{
  GWEN_CRYPT_TOKEN_CREATE_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->createFn;
  ct->createFn=f;

  return of;

}



GWEN_CRYPT_TOKEN_CLOSE_FN GWEN_Crypt_Token_SetCloseFn(GWEN_CRYPT_TOKEN *ct,
                                                      GWEN_CRYPT_TOKEN_CLOSE_FN f)
{
  GWEN_CRYPT_TOKEN_CLOSE_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->closeFn;
  ct->closeFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_GETKEYIDLIST_FN GWEN_Crypt_Token_SetGetKeyIdListFn(GWEN_CRYPT_TOKEN *ct,
                                                                    GWEN_CRYPT_TOKEN_GETKEYIDLIST_FN f)
{
  GWEN_CRYPT_TOKEN_GETKEYIDLIST_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->getKeyIdListFn;
  ct->getKeyIdListFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_GETKEYINFO_FN GWEN_Crypt_Token_SetGetKeyInfoFn(GWEN_CRYPT_TOKEN *ct,
                                                                GWEN_CRYPT_TOKEN_GETKEYINFO_FN f)
{
  GWEN_CRYPT_TOKEN_GETKEYINFO_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->getKeyInfoFn;
  ct->getKeyInfoFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_SETKEYINFO_FN GWEN_Crypt_Token_SetSetKeyInfoFn(GWEN_CRYPT_TOKEN *ct,
                                                                GWEN_CRYPT_TOKEN_SETKEYINFO_FN f)
{
  GWEN_CRYPT_TOKEN_SETKEYINFO_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->setKeyInfoFn;
  ct->setKeyInfoFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_GETCONTEXTIDLIST_FN GWEN_Crypt_Token_SetGetContextIdListFn(GWEN_CRYPT_TOKEN *ct,
                                                                            GWEN_CRYPT_TOKEN_GETCONTEXTIDLIST_FN f)
{
  GWEN_CRYPT_TOKEN_GETCONTEXTIDLIST_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->getContextIdListFn;
  ct->getContextIdListFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_GETCONTEXT_FN GWEN_Crypt_Token_SetGetContextFn(GWEN_CRYPT_TOKEN *ct,
                                                                GWEN_CRYPT_TOKEN_GETCONTEXT_FN f)
{
  GWEN_CRYPT_TOKEN_GETCONTEXT_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->getContextFn;
  ct->getContextFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_SETCONTEXT_FN GWEN_Crypt_Token_SetSetContextFn(GWEN_CRYPT_TOKEN *ct,
                                                                GWEN_CRYPT_TOKEN_SETCONTEXT_FN f)
{
  GWEN_CRYPT_TOKEN_SETCONTEXT_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->setContextFn;
  ct->setContextFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_SIGN_FN GWEN_Crypt_Token_SetSignFn(GWEN_CRYPT_TOKEN *ct,
                                                    GWEN_CRYPT_TOKEN_SIGN_FN f)
{
  GWEN_CRYPT_TOKEN_SIGN_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->signFn;
  ct->signFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_VERIFY_FN GWEN_Crypt_Token_SetVerifyFn(GWEN_CRYPT_TOKEN *ct,
                                                        GWEN_CRYPT_TOKEN_VERIFY_FN f)
{
  GWEN_CRYPT_TOKEN_VERIFY_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->verifyFn;
  ct->verifyFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_ENCIPHER_FN GWEN_Crypt_Token_SetEncipherFn(GWEN_CRYPT_TOKEN *ct,
                                                            GWEN_CRYPT_TOKEN_ENCIPHER_FN f)
{
  GWEN_CRYPT_TOKEN_ENCIPHER_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->encipherFn;
  ct->encipherFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_DECIPHER_FN GWEN_Crypt_Token_SetDecipherFn(GWEN_CRYPT_TOKEN *ct,
                                                            GWEN_CRYPT_TOKEN_DECIPHER_FN f)
{
  GWEN_CRYPT_TOKEN_DECIPHER_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->decipherFn;
  ct->decipherFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_GENERATEKEY_FN GWEN_Crypt_Token_SetGenerateKeyFn(GWEN_CRYPT_TOKEN *ct,
                                                                  GWEN_CRYPT_TOKEN_GENERATEKEY_FN f)
{
  GWEN_CRYPT_TOKEN_GENERATEKEY_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->generateKeyFn;
  ct->generateKeyFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_CHANGEPIN_FN GWEN_Crypt_Token_SetChangePinFn(GWEN_CRYPT_TOKEN *ct,
                                                              GWEN_CRYPT_TOKEN_CHANGEPIN_FN f)
{
  GWEN_CRYPT_TOKEN_CHANGEPIN_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->changePinFn;
  ct->changePinFn=f;

  return of;
}



GWEN_CRYPT_TOKEN_ACTIVATEKEY_FN GWEN_Crypt_Token_SetActivateKeyFn(GWEN_CRYPT_TOKEN *ct,
                                                                  GWEN_CRYPT_TOKEN_ACTIVATEKEY_FN f)
{
  GWEN_CRYPT_TOKEN_ACTIVATEKEY_FN of;

  assert(ct);
  assert(ct->refCount);
  of=ct->activateKeyFn;
  ct->activateKeyFn=f;

  return of;
}





int GWEN_Crypt_Token__CreatePasswordName(GWEN_CRYPT_TOKEN *ct,
                                         GWEN_CRYPT_PINTYPE pt,
                                         GWEN_BUFFER *nbuf)
{
  const char *tname;
  const char *dname;

  tname=GWEN_Crypt_Token_GetTypeName(ct);
  assert(tname);
  dname=GWEN_Crypt_Token_GetTokenName(ct);
  if (!dname) {
    DBG_ERROR(GWEN_LOGDOMAIN, "Token has no name");
    return GWEN_ERROR_INVALID;
  }

  GWEN_Buffer_AppendString(nbuf, "PASSWORD_");
  GWEN_Buffer_AppendString(nbuf, tname);
  GWEN_Buffer_AppendString(nbuf, "_");
  GWEN_Buffer_AppendString(nbuf, dname);
  if (pt==GWEN_Crypt_PinType_Manage)
    GWEN_Buffer_AppendString(nbuf, ":MANAGE");

  return 0;
}



int GWEN_Crypt_Token_GetPin(GWEN_CRYPT_TOKEN *ct,
                            GWEN_CRYPT_PINTYPE pt,
                            GWEN_CRYPT_PINENCODING pe,
                            uint32_t flags,
                            unsigned char *pwbuffer,
                            unsigned int minLength,
                            unsigned int maxLength,
                            unsigned int *pinLength,
                            uint32_t gid)
{
  int rv;
  const char *dname;
  const char *mode;
  const char *numeric_warning = "";
  char buffer[512];
  GWEN_BUFFER *nameBuffer;

  assert(ct);
  assert(ct->refCount);

  dname=GWEN_Crypt_Token_GetFriendlyName(ct);
  if (!dname || !*dname)
    dname=GWEN_Crypt_Token_GetTokenName(ct);

  if (pt==GWEN_Crypt_PinType_Access)
    mode=I18N("access password");
  else if (pt==GWEN_Crypt_PinType_Manage)
    mode=I18N("manager password");
  else
    mode=I18N("password");

  buffer[0]=0;
  buffer[sizeof(buffer)-1]=0;
  if (flags & GWEN_GUI_INPUT_FLAGS_NUMERIC) {
    numeric_warning = I18N("\nYou must only enter numbers, not letters.");
  }

  if (flags & GWEN_GUI_INPUT_FLAGS_CONFIRM) {
    snprintf(buffer, sizeof(buffer)-1,
             I18N("Please enter a new %s for \n"
                  "%s\n"
                  "The password must be at least %d characters long.%s"
                  "<html>"
                  "Please enter a new %s for <i>%s</i>. "
                  "The password must be at least %d characters long.%s"
                  "</html>"),
             mode,
             dname,
             minLength,
             numeric_warning,
             mode,
             dname,
             minLength,
             numeric_warning);
  }
  else {
    snprintf(buffer, sizeof(buffer)-1,
             I18N("Please enter the %s for \n"
                  "%s\n"
                  "%s<html>"
                  "Please enter the %s for <i>%s</i>.%s"
                  "</html>"),
             mode,
             dname,
             numeric_warning,
             mode,
             dname,
             numeric_warning);
  }

  nameBuffer=GWEN_Buffer_new(0, 256, 0, 1);
  GWEN_Crypt_Token__CreatePasswordName(ct, pt, nameBuffer);
  rv=GWEN_Gui_GetPassword(flags,
                          GWEN_Buffer_GetStart(nameBuffer),
                          I18N("Enter Password"),
                          buffer,
                          (char *)pwbuffer,
                          minLength,
                          maxLength,
                          GWEN_Gui_PasswordMethod_Text, NULL,
                          gid);
  GWEN_Buffer_free(nameBuffer);
  if (rv) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  *pinLength=strlen((char *)pwbuffer);

  if (pe!=GWEN_Crypt_PinEncoding_Ascii) {
    rv=GWEN_Crypt_TransformPin(GWEN_Crypt_PinEncoding_Ascii,
                               pe,
                               pwbuffer,
                               maxLength,
                               pinLength);
    if (rv) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  return 0;
}



int GWEN_Crypt_Token_SetPinStatus(GWEN_CRYPT_TOKEN *ct,
                                  GWEN_CRYPT_PINTYPE pt,
                                  GWEN_CRYPT_PINENCODING pe,
                                  GWEN_UNUSED uint32_t flags,
                                  const unsigned char *buffer,
                                  unsigned int pinLength,
                                  int isOk,
                                  uint32_t gid)
{
  GWEN_BUFFER *nameBuffer;
  int rv;
  unsigned char ibuffer[256];

  assert(ct);
  assert(ct->refCount);

  if (pe!=GWEN_Crypt_PinEncoding_Ascii) {
    if (pinLength>=sizeof(ibuffer)) {
      DBG_ERROR(GWEN_LOGDOMAIN, "Pin too long");
      return GWEN_ERROR_BUFFER_OVERFLOW;
    }
    memset(ibuffer, 0, sizeof(ibuffer));
    memmove(ibuffer, buffer, pinLength);
    rv=GWEN_Crypt_TransformPin(pe,
                               GWEN_Crypt_PinEncoding_Ascii,
                               ibuffer,
                               sizeof(ibuffer)-1,
                               &pinLength);
    if (rv) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
    buffer=ibuffer;
  }

  nameBuffer=GWEN_Buffer_new(0, 256, 0, 1);
  GWEN_Crypt_Token__CreatePasswordName(ct, pt, nameBuffer);
  rv=GWEN_Gui_SetPasswordStatus(GWEN_Buffer_GetStart(nameBuffer),
                                (const char *)buffer,
                                isOk?GWEN_Gui_PasswordStatus_Ok:
                                GWEN_Gui_PasswordStatus_Bad, gid);
  memset(ibuffer, 0, sizeof(ibuffer));
  GWEN_Buffer_free(nameBuffer);
  return rv;

}



uint32_t GWEN_Crypt_Token_BeginEnterPin(GWEN_UNUSED GWEN_CRYPT_TOKEN *ct,
                                        GWEN_UNUSED GWEN_CRYPT_PINTYPE pt,
                                        uint32_t gid)
{
  int rv;

  rv=GWEN_Gui_ProgressLog(gid, GWEN_LoggerLevel_Warning, I18N("Waiting for pin entry on card reader..."));
  if (rv<0)
    return 0;
  return 0xffffffff;
}



int GWEN_Crypt_Token_EndEnterPin(GWEN_UNUSED GWEN_CRYPT_TOKEN *ct,
                                 GWEN_UNUSED GWEN_CRYPT_PINTYPE pt,
                                 GWEN_UNUSED int ok,
                                 uint32_t gid)
{
  return GWEN_Gui_ProgressLog(gid, GWEN_LoggerLevel_Warning, I18N("Pin entry on card reader finished."));
}



int GWEN_Crypt_Token_InsertToken(GWEN_CRYPT_TOKEN *ct, uint32_t gid)
{
  int rv;
  char buffer[512];
  const char *dname;

  assert(ct);
  assert(ct->refCount);

  buffer[0]=0;
  buffer[sizeof(buffer)-1]=0;

  dname=GWEN_Crypt_Token_GetFriendlyName(ct);
  if (!dname || !*dname)
    dname=GWEN_Crypt_Token_GetTokenName(ct);

  if (GWEN_Crypt_Token_GetDevice(ct)==GWEN_Crypt_Token_Device_File)
    snprintf(buffer, sizeof(buffer)-1,
             I18N("Please insert the security disc\nfor %s"
                  "<html>"
                  "Please insert the security disc for <i>%s</i>"
                  "</html>"), dname, dname);
  else
    snprintf(buffer, sizeof(buffer)-1,
             I18N("Please insert the chip card\nfor %s"
                  "<html>"
                  "Please insert the chip card for <i>%s</i>"
                  "</html>"), dname, dname);

  rv=GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_WARN |
                         GWEN_GUI_MSG_FLAGS_SEVERITY_NORMAL |
                         GWEN_GUI_MSG_FLAGS_CONFIRM_B1,
                         I18N("Insert Medium"),
                         buffer,
                         I18N("OK"), I18N("Abort"), 0, gid);
  if (rv==2) {
    DBG_ERROR(GWEN_LOGDOMAIN, "User aborted");
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Notice,
                         I18N("Aborted by user."));
    return GWEN_ERROR_USER_ABORTED;
  }
  else if (rv!=1) {
    GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_ERROR |
                        GWEN_GUI_MSG_FLAGS_SEVERITY_DANGEROUS |
                        GWEN_GUI_MSG_FLAGS_CONFIRM_B1,
                        I18N("Error"),
                        I18N("An internal error occurred."),
                        I18N("Dismiss"), 0, 0, gid);
    return -1;
  }

  return 0;
}



int GWEN_Crypt_Token_InsertCorrectToken(GWEN_CRYPT_TOKEN *ct, uint32_t gid)
{
  int rv;
  char buffer[512];
  const char *dname;

  assert(ct);
  assert(ct->refCount);

  buffer[0]=0;
  buffer[sizeof(buffer)-1]=0;

  dname=GWEN_Crypt_Token_GetFriendlyName(ct);
  if (!dname || !*dname)
    dname=GWEN_Crypt_Token_GetTokenName(ct);

  if (GWEN_Crypt_Token_GetDevice(ct)==GWEN_Crypt_Token_Device_File)
    snprintf(buffer, sizeof(buffer)-1,
             I18N("Please insert the correct security disc\nfor %s"
                  "<html>"
                  "Please insert the correct security disc for <i>%s</i>"
                  "</html>"), dname, dname);
  else {
    if (dname && *dname) {
      snprintf(buffer, sizeof(buffer)-1,
               I18N("The wrong chipcard has been inserted.\n"
                    "Please insert the chipcard with the number\n"
                    "  %s\n"
                    "into the card reader.\n"
                    "<html>"
                    "<p>The wrong card has been inserted.</p>"
                    "<p>Please insert the chipcard with the number"
                    "<b>%s</b> into the card reader.</p>"
                    "</html>"),
               dname,
               dname);
    }
    else
      snprintf(buffer, sizeof(buffer)-1,
               I18N("Please insert the correct chipcard\nfor %s"
                    "<html>"
                    "Please insert the correct chipcard for <i>%s</i>"
                    "</html>"), dname, dname);
  }

  rv=GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_WARN |
                         GWEN_GUI_MSG_FLAGS_SEVERITY_DANGEROUS |
                         GWEN_GUI_MSG_FLAGS_CONFIRM_B1,
                         I18N("Insert Medium"),
                         buffer,
                         I18N("OK"), I18N("Abort"), 0, gid);
  if (rv==2) {
    DBG_ERROR(GWEN_LOGDOMAIN, "User aborted");
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Notice,
                         I18N("Aborted by user."));
    return GWEN_ERROR_USER_ABORTED;
  }
  else if (rv!=1) {
    GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_ERROR |
                        GWEN_GUI_MSG_FLAGS_SEVERITY_DANGEROUS |
                        GWEN_GUI_MSG_FLAGS_CONFIRM_B1,
                        I18N("Error"),
                        I18N("An internal error occurred."),
                        I18N("Dismiss"), 0, 0, gid);
    return -1;
  }

  return 0;
}



GWEN_CRYPT_TOKEN_DEVICE GWEN_Crypt_Token_Device_fromString(const char *s)
{
  assert(s);
  if (strcasecmp(s, "none")==0)
    return GWEN_Crypt_Token_Device_None;
  else if (strcasecmp(s, "file")==0)
    return GWEN_Crypt_Token_Device_File;
  else if (strcasecmp(s, "card")==0)
    return GWEN_Crypt_Token_Device_Card;
  else if (strcasecmp(s, "any")==0)
    return GWEN_Crypt_Token_Device_Any;
  return GWEN_Crypt_Token_Device_Unknown;
}



const char *GWEN_Crypt_Token_Device_toString(GWEN_CRYPT_TOKEN_DEVICE d)
{
  switch (d) {
  case GWEN_Crypt_Token_Device_None:
    return "none";
  case GWEN_Crypt_Token_Device_File:
    return "file";
  case GWEN_Crypt_Token_Device_Card:
    return "card";
  case GWEN_Crypt_Token_Device_Any:
    return "any";
  default:
    return "unknown";
  }
}






