/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

#include <Jonah.h>
#ifndef API_DISPLAY_IN_API_LAYER
#include <ApiNotify.h>
#endif
#include <init.h>
#include <JonahOst.h>
#include <JonahIni.h>
#include <stdlib.h>
#include <string.h>
#include <sections.h>
#include <apimsg.h>
#include <JonahMsg.h>
#include <Keystore.h>
#include <StrngLst.h>

#define MAX_STRING_SIZE 1024

#ifdef API_DISPLAY_IN_API_LAYER
#define MESSAGE_TIMESTAMPS 1

static void (* ApiNotifyC)(uint32 eventId, 
			   uint32 eventStatus) = NULL;

static void (* ApiDisplayC)(uint32 eventId, 
			    const utf8String message) = NULL;

void ApiNotify(uint32 eventId, 
	       uint32 eventStatus) {
  if (ApiNotifyC) ApiNotifyC(eventId, eventStatus);
}

void ApiDisplay(uint32 eventId, 
		const utf8String message) {
  utf8String msgCopy = NULL;
  char timeBuf[50] = {0};
  time_t now;

  if (ApiDisplayC) {
#ifdef MESSAGE_TIMESTAMPS    
    now = time(NULL);
    strftime(timeBuf, sizeof(timeBuf), "%a, %x %X : ", localtime(&now));
    timeBuf[sizeof(timeBuf)-1] = 0; // Just in case...
    msgCopy = (utf8String)malloc(strlen((const char *)message)+1+strlen(timeBuf));
    strcpy((char *)msgCopy, timeBuf);
    strcat((char *)msgCopy, (const char *)message);
#else
    msgCopy = (utf8String)malloc(strlen((const char *)message)+1);
    strcpy((char *)msgCopy, (const char *)message);    
#endif
    ApiDisplayC(eventId, msgCopy);
  };
}

#endif

uint32 JNH_start_server(int serverType) {
  switch (serverType) {
  case svrType_RA:
    return Init(Init_RA);
  case svrType_CA:
    return Init(Init_CA);
  default:
    return Init(Init_EE);
  };
}

uint32 JNH_register_callback(void (* JNH_Notify)(uint32 eventId, 
						 uint32 eventStatus)) {
#ifdef API_DISPLAY_IN_API_LAYER  
  ApiNotifyC = JNH_Notify;
  ApiDisplayC = NULL;
  return 0;
#else
  return MscRegisterCallbacks(JNH_Notify, NULL);
#endif
}


uint32 JNH_register_callbacks(
	     void (* JNH_Notify)(uint32 eventId, 
				 uint32 eventStatus),
	     void (* JNH_Display)(uint32 displayType,
				  const utf8String message)) {
#ifdef API_DISPLAY_IN_API_LAYER  
  ApiNotifyC = JNH_Notify;
  ApiDisplayC = JNH_Display;
  return 0;
#else
  return MscRegisterCallbacks(JNH_Notify, JNH_Display);
#endif
}


uint32 JNH_check_configuration(uint32 * state) {
  *state = svrSt_Running;
  return 0;
}

uint32 JNH_list_objects(void) {
  uint32        status;
  status = JnhListActiveObjects(ApiNotify);
  if (status) {
    return status;
  }
  return JnhListSurrogateObjects(ApiNotify);
}

uint32 JNH_list_surrogates(void) {
  return JnhListSurrogateObjects(ApiNotify);
}


uint32 JNH_release_utf8String(utf8String s) {
  free(s);
  return 0;
}

uint32 JNH_release_octetString(octetString s) {
  free(s.data);
  return 0;
}

uint32 JNH_release_octetStrings(uint32 numStrings,
				octetString * s) {
  octetString * ptr = s;
  while (numStrings > 0) {
    JNH_release_octetString(*ptr);
    ptr++; numStrings--;
  };
  free(s);
  return 0;
}

uint32 JNH_release_utf8Strings(uint32 numStrings,
			       utf8String * s) {
  utf8String * ptr = s;
  while (numStrings > 0) {
    JNH_release_utf8String(*ptr);
    ptr++; numStrings--;
  };
  free(s);
  return 0;
}

uint32 JNH_release_ints(uint32 numStrings,
			uint32 * s) {
  free(s);
  return 0;
}

#ifdef OBSOLETE
uint32 JNH_synch_object(uint32 reqId) {
  return JnhSynchObject(reqId);
}
#endif

uint32 JNH_save_object(uint32 reqId) {
  return JnhSynchObject(reqId);
}

uint32 JNH_reserve_object(uint32 objId) {
  return JnhLockObject(objId);
}

uint32 JNH_release_object(uint32 objId) {
  return JnhUnlockObject(objId);
}

uint32 JNH_delete_object(uint32 objId) {
  uint32	status;
  if (IniAmIRA() || IniAmICA()) {
    return API_WRONG_SERVER;
  }
  ApiNotify(objId, ObjStEEGone);
  status = JnhLockObject(objId);
  if (status) 
    return status;
  else
    return JnhDeleteObject(objId);
}

uint32 JNH_INI_readString(const utf8String section,
			  const utf8String key,
			  utf8String * value,
			  const utf8String defaultValue) {
  *value = (utf8String)malloc(MAX_STRING_SIZE);
  if (*value == NULL) return API_MEMORY_ERROR;
  if (IniReadString((const char *)section, 
		    (const char *)key, 
		    (char *)*value, 
		    MAX_STRING_SIZE, 
		    (const char *)defaultValue)) return 0;
  return 1;
}

uint32 JNH_INI_writeString(const utf8String section,
			   const utf8String key,
			   const utf8String value) {
  return IniWriteString((const char *)section, 
			(const char *)key, 
			(const char *)value);
}
 
uint32 JNH_INI_readInteger(const utf8String section,
			   const utf8String key,
			   int * value,
			   int defaultValue) {
  if (IniReadInteger((const char *)section, 
		     (const char *)key, 
		     *value, 
		     defaultValue)) return 0;
  return 1;
}

uint32 JNH_INI_writeInteger(const utf8String section,
			    const utf8String key,
			    int value) {
  return IniWriteInteger((const char *)section, 
			 (const char *)key, 
			 value);
}

uint32 JNH_INI_readBoolean(const utf8String section,
			   const utf8String key,
			   IBOOL * value,
			   IBOOL defaultValue) {
  bool x;
  uint32 st;
  st =IniReadBoolean((const char *)section, 
		     (const char *)key, 
		     x,
		     defaultValue);
  *value = x;
  if (st) return 0;
  return 1;
}

uint32 JNH_INI_writeBoolean(const utf8String section,
			    const utf8String key,
			    IBOOL value) {
  return IniWriteBoolean((const char *)section, 
			 (const char *)key, 
			 value);
}

uint32 JNH_get_default_server_name(utf8String * name) {

  *name = (utf8String)malloc(MAX_STRING_SIZE);
  if (*name == NULL) return API_MEMORY_ERROR;
  if (IniReadString(GEN_SECTION,
                    GEN_NAME,
		    (char *)*name, 
		    MAX_STRING_SIZE, 
		    "<Unnamed>")) return 0;
  return 1;
}


uint32 JNH_get_error(uint32 errorCode,
                     utf8String * errorText) {
// Translate a message code via the catalog
  size_t res;
  *errorText = (utf8String)malloc(MAX_STRING_SIZE);

  res = Jonah_getMsg ((char *)*errorText,
                      MAX_STRING_SIZE,
                      errorCode);
  return 0;
  
}

uint32 JNH_export_credential(uint32 reqId, 
                             const utf8String password, 
                             const utf8String device) {
  
  if (strncmp((const char *)device, "VSC", 3) == 0) {
    if (device[3] == ':')
      return JnhExportCredentialVSC(reqId, password, &(device[4]));
    else return JnhExportCredentialVSC(reqId, password, NULL);
  } else if (strncmp((const char *)device, "TOK", 3) == 0) {
    if (device[3] == ':')
      return JnhExportCredentialTOK(reqId, password, &(device[4]));
    else return JnhExportCredentialTOK(reqId, password, NULL);
  } else if (strncmp((const char *)device, "PKCS12", 6) == 0) {
    if (device[6] == ':') 
      return JnhExportCredentialPKCS12(reqId, password, &(device[7]));
    else return API_MISSING_FILENAME;
  } else return API_BAD_DEVICENAME;

}

uint32 JNH_get_algorithms (uint32 algType,
                           uint32 * numberAlgorithm,
                           utf8String ** names) {
  StringList sl;
  int i;

  switch (algType) {
  case algType_AsymmetricSign:
    IniGetKeys(ASYM_SIG_ALG_SECTION, sl);
    *numberAlgorithm = sl.Count();
    *names = (utf8String *)malloc(*numberAlgorithm * sizeof(utf8String));
    for (i=0; i < *numberAlgorithm; i++) {
      (*names)[i] = (utf8String)malloc(strlen(sl[i]));
      strcpy((char *)((*names)[i]), sl[i]);
    };
    return 0;
  case algType_AsymmetricEncrypt:
    IniGetKeys(ASYM_ENC_ALG_SECTION, sl);
    *numberAlgorithm = sl.Count();
    *names = (utf8String *)malloc(*numberAlgorithm * sizeof(utf8String));
    for (i=0; i < *numberAlgorithm; i++) {
      (*names)[i] = (utf8String)malloc(strlen(sl[i]));
      strcpy((char *)((*names)[i]), sl[i]);
    };
    return 0;
  case algType_Symmetric:
    IniGetKeys(SYM_ENC_ALG_SECTION, sl);
    *numberAlgorithm = sl.Count();
    *names = (utf8String *)malloc(*numberAlgorithm * sizeof(utf8String));
    for (i=0; i < *numberAlgorithm; i++) {
      (*names)[i] = (utf8String)malloc(strlen(sl[i]));
      strcpy((char *)((*names)[i]), sl[i]);
    };
    return 0;
  case algType_AsymmetricKey:
    IniGetKeys(ASYM_KEY_ALG_SECTION, sl);
    *numberAlgorithm = sl.Count();
    *names = (utf8String *)malloc(*numberAlgorithm * sizeof(utf8String));
    for (i=0; i < *numberAlgorithm; i++) {
      (*names)[i] = (utf8String)malloc(strlen(sl[i]));
      strcpy((char *)((*names)[i]), sl[i]);
    };
    return 0;
  default:
    return API_BAD_ALGTYPE;
  }
}

uint32 JNH_OID_to_name(const octetString objectId,
                       utf8String * name) {
  asn_oid oid;
  uint32 status;  
  buffer_t buffer;

  *name = NULL;

  if ((status = oid.set_value(objectId.data, objectId.length)) != 0) return status;
  if ((status = oid.display_name(buffer)) != 0) return status;
  if ((*name = (unsigned char *)malloc(buffer.data_len+1)) == NULL) {
    return API_MEMORY_ERROR;
  };
  memcpy(*name, buffer.data, buffer.data_len);
  (*name)[buffer.data_len] = 0;
  return 0;

}

uint32 JNH_name_to_OID(const utf8String name,
                       octetString * objectId) {

  asn_oid oid;
  uint32 status;  
  buffer_t buffer;

  objectId->data = NULL;
  objectId->length = 0;

  if ((status = oid.set_value((char *)name)) != 0) return status;
  if ((status = oid.get_value(buffer)) != 0) return status;
  if ((objectId->data = (unsigned char *)malloc(buffer.data_len)) == NULL) {
    return API_MEMORY_ERROR;
  };
  memcpy(objectId->data, buffer.data, buffer.data_len);
  objectId->length = buffer.data_len;
  return 0;

}
