/* **************************************************************************

  $Archive: /njcl/src/com/novell/service/session/nds/NDSTreeSessionState.java $
  $Revision: 16 $
  $Modtime: 4/07/98 5:45p $

  Copyright (c) 1997 Novell, Inc.  All Rights Reserved.

  THIS WORK IS  SUBJECT  TO  U.S.  AND  INTERNATIONAL  COPYRIGHT  LAWS  AND
  TREATIES.   NO  PART  OF  THIS  WORK MAY BE  USED,  PRACTICED,  PERFORMED
  COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,  ABRIDGED, CONDENSED,
  EXPANDED,  COLLECTED,  COMPILED,  LINKED,  RECAST, TRANSFORMED OR ADAPTED
  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION
  OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
  CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/
//#define DEBUG_OUT
//#define DEBUG_SEM

#include <sys_api.h>
#include "com_novell_service_jncpv2r_clx_ClxJNI.h"
#include "JNIString.h"
#include <jni.h>

#include <ntypes.h>
#include <nwbindry.h>
#include <nwserver.h>
#include <nwapidef.h>
#include <nwclxcon.h>
#include <nwconnec.h>
#include <nwmsg.h>
#include <nwcalls.h>
#include <nwnet.h>
#include <nwdsmisc.h>
#include <nwerror.h>
#include <nwlocale.h>

#ifdef N_PLAT_NLM

#include <nwadv.h>
#include <nwenvrn.h>
#include <nwdsdc.h>
#include <nwdsasa.h>
#include <nwdserr.h>
#include <nlm\nwconn.h>
#include <nlm\nds.h>

#include <string.h>

#include <stdio.h>
#include <nwconio.h>

#include <assert.h>

#include <signal.h>

#include <nwdebug.h>
#include <nwthread.h>
#endif

#include "jncp.h"
#include "nlmsem.h"
#include "xjni.h"

#ifdef N_PLAT_NLM
#define PRINTF ConsolePrintf
//#define PRINTF JNCPprintf
#define THREADSWITCH ThreadSwitch()
//#define THREADSWITCH
#else
#define PRINTF printf
#define THREADSWITCH
#endif

#define XPLATPKG         "com/novell/service/session/xplat/"

#define __MAX(a,b) ((a) > (b) ? (a): (b))
#define MAX_PASSWORD_LEN   129

#ifdef N_PLAT_NLM


#else

#  define JNCPprintf   printf

#endif

static unicode SpecialPasswordPrefix[] = { 0, 2, 0x9fff, 0xd7fe, 0xf8fd };
#define SPECIAL_PREFIX_LENGTH     sizeof(SpecialPasswordPrefix)
#define SPECIAL_PREFIX_CHARS      (SPECIAL_PREFIX_LENGTH / sizeof(*SpecialPasswordPrefix))

static void debugDumpString(JNIEnv* Env, const char* utf8Buf, nuint32 utf8BufLen, jstring jPassword)
{
    nuint32 x;
    const jchar* unicodeBuf;
    nuint32 unicodeBufLen;

    printf("debugDumpString ENTER\n");

    printf("UTF8Password Length = %X\n", utf8BufLen);
    for(x=0; x<utf8BufLen; x++)
    {
        printf("UTF8Password[%X]=%X\n", x, (nuint32)utf8Buf[x]);
    }
    
    unicodeBuf = (*Env)->GetStringChars(Env, jPassword, 0);
    unicodeBufLen = (*Env)->GetStringLength(Env, jPassword);
    printf("UnicodePassword Length = %X\n", unicodeBufLen);
    for(x=0; x<unicodeBufLen; x++)
    {
        printf("UnicodePassword[%X]=%X\n", x, (nuint32)unicodeBuf[x]);
    }
    (*Env)->ReleaseStringChars(Env, jPassword, unicodeBuf);

    printf("debugDumpString EXIT\n");
}

static NWCCODE getUTFChars(JNIEnv* Env, jstring jPassword, pnstr8 Password, nuint32 Length)
{
    const char* tempBuf;
    nuint32 jPasswordLength;
    NWCCODE ccode = 0;

    tempBuf = (*Env)->GetStringUTFChars(Env, jPassword, 0);
    if(NULL == tempBuf)
        return -1;

    jPasswordLength = (*Env)->GetStringUTFLength(Env, jPassword);
    if((jPasswordLength+1) > Length)
        ccode = -1;
    else
    {
        memcpy(Password, tempBuf, jPasswordLength);
        Password[jPasswordLength] = 0x0;
    }

    //debugDumpString(Env, tempBuf, jPasswordLength, jPassword);
    
    (*Env)->ReleaseStringUTFChars(Env, jPassword, tempBuf);
    return ccode;
}
static NWCCODE getPassword(JNIEnv* Env, jstring jPassword, pnstr8 Password, nuint32 Length, nuint32 extCharPassFlag)
{
    punicode uniPassword;
    nuint32 jLength;
    nuint32 i;
    NWCCODE ccode;

    jclass class;
    if(jPassword == NULL)
    {
        class = (*Env)->FindClass(Env, "com/novell/service/jncp/NSIException");
        if(NULL == class)
            goto THROW_FATAL_ERROR;
        if(!(*Env)->ThrowNew(Env, class, "NULL password"))
            return -1;
        THROW_FATAL_ERROR:
        (*Env)->FatalError(Env, "Problem throwing exception");
        return -1;
    }
    
    uniPassword = (punicode) (*Env)->GetStringChars(Env, jPassword, 0);
    jLength = (*Env)->GetStringLength(Env, jPassword);
    ccode = 0;
    
    if (uniPassword == NULL)
        return -1;

    if (jLength >= SPECIAL_PREFIX_CHARS && memcmp(uniPassword, SpecialPasswordPrefix, sizeof(SPECIAL_PREFIX_LENGTH)) == 0) {
        
        jLength -= SPECIAL_PREFIX_CHARS;
        
        if (jLength > Length - 1)
            jLength = Length - 1;
            
        for (i = 0; i < jLength; i++)
            Password[i] = (nstr8) uniPassword[i + SPECIAL_PREFIX_CHARS];

        Password[i] = 0;
    }
    else
    {
        if(extCharPassFlag)
           ccode = getUTFChars(Env, jPassword, Password, Length);
        else
           ccode = __UnicodePathToLocalStr(Password, Length, uniPassword, jLength);
    }

    (*Env)->ReleaseStringChars(Env, jPassword, uniPassword);
    
    return ccode;
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWLoginToFileServer
(
      JNIEnv   *env,
      jclass   obj,
      jint     connHandle,
      jstring  objectName,
      jint     objectType,
      jstring  password
)
{
   NWCCODE ccode;
   nstr8 cObjectName[NW_MAX_USER_NAME_LEN];
   nstr8 cPassword[MAX_PASSWORD_LEN];
   punicode uniObjectName;//, uniPassword;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWLoginToFileServer\n");
      THREADSWITCH;
   #endif

   // Convert Java variable into 'C' variable
   uniObjectName = (punicode) (*env)->GetStringChars (env, objectName, 0);
//   uniPassword = (punicode) (*env)->GetStringChars (env, password, 0);

   ccode = __UnicodeToLocalStr (
               cObjectName,
               sizeof (cObjectName),
               uniObjectName,
               (*env)->GetStringLength (env, objectName));
   if (ccode != 0)
      goto EXIT;

//   ccode = __UnicodePathToLocalStr (
//               cPassword,
//               sizeof (cPassword),
//               uniPassword,
//               (*env)->GetStringLength (env, password));
    ccode = getPassword(env, password, cPassword, sizeof(cPassword), 0);

   if (ccode != 0)
      goto EXIT;

   ccode = NWLoginToFileServer (
                  (NWCONN_HANDLE) connHandle,
                  cObjectName,
                  (nuint16) objectType,
                  cPassword);

EXIT:

   (*env)->ReleaseStringChars (env, objectName, uniObjectName);
//   (*env)->ReleaseStringChars (env, password, uniPassword);

   return ((jint) ccode);
} /* ...NWLoginToFileServer () */


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWChangeObjectPassword
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jstring  objectName,
   jint     objectType,
   jstring  oldPassword,
   jstring  newPassword
)
{
   NWCCODE ccode;
   nstr8 cObjectName[NW_MAX_USER_NAME_LEN];
   nstr8 cOldPassword[MAX_PASSWORD_LEN];
   nstr8 cNewPassword[MAX_PASSWORD_LEN];
   punicode uniObjectName;//, uniOldPassword, uniNewPassword;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWChangeObjectPassword\n");
      THREADSWITCH;
   #endif

   // Convert Java variable into 'C' variable
   uniObjectName = (punicode) (*env)->GetStringChars (env, objectName, 0);
//   uniOldPassword = (punicode) (*env)->GetStringChars (env, oldPassword, 0);
//   uniNewPassword = (punicode) (*env)->GetStringChars (env, newPassword, 0);

   ccode = __UnicodeToLocalStr (
               cObjectName,
               sizeof (cObjectName),
               uniObjectName,
               (*env)->GetStringLength (env, objectName));
   if (ccode != 0)
      goto EXIT;

//   ccode = __UnicodePathToLocalStr (
//               cOldPassword,
//               sizeof (cOldPassword),
//               uniOldPassword,
//               (*env)->GetStringLength (env, oldPassword));
    ccode = getPassword(env, oldPassword, cOldPassword, sizeof(cOldPassword), 0);
    
   if (ccode != 0)
      goto EXIT;

//   ccode = __UnicodePathToLocalStr (
//               cNewPassword,
//               sizeof (cNewPassword),
//               uniNewPassword,
//               (*env)->GetStringLength (env, newPassword));
    ccode = getPassword(env, newPassword, cNewPassword, sizeof(cNewPassword), 0);

   if (ccode != 0)
      goto EXIT;

   ccode = NWChangeObjectPassword (
                  (NWCONN_HANDLE) connHandle,
                  cObjectName,
                  (nuint16) objectType,
                  cOldPassword,
                  cNewPassword);

EXIT:

   (*env)->ReleaseStringChars (env, objectName, uniObjectName);
//   (*env)->ReleaseStringChars (env, oldPassword, uniOldPassword);
//   (*env)->ReleaseStringChars (env, newPassword, uniNewPassword);

   return ((jint) ccode);
} /* ...NWChangeObjectPassword () */


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWVerifyObjectPassword
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jstring  objectName,
   jint     objectType,
   jstring  password
)
{
   NWCCODE ccode;
   nstr8 cObjectName[NW_MAX_USER_NAME_LEN];
   nstr8 cPassword[MAX_PASSWORD_LEN];
   punicode uniObjectName;//, uniPassword;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWVerifyObjectPassword\n");
      THREADSWITCH;
   #endif

   // Convert Java variable into 'C' variable
   uniObjectName = (punicode) (*env)->GetStringChars (env, objectName, 0);
//   uniPassword = (punicode) (*env)->GetStringChars (env, password, 0);

   ccode = __UnicodeToLocalStr (
               cObjectName,
               sizeof (cObjectName),
               uniObjectName,
               (*env)->GetStringLength (env, objectName));
   if (ccode != 0)
      goto EXIT;

//   ccode = __UnicodePathToLocalStr (
//               cPassword,
//               sizeof (cPassword),
//               uniPassword,
//               (*env)->GetStringLength (env, password));
    ccode = getPassword(env, password, cPassword, sizeof(cPassword), 0);
    
   if (ccode != 0)
      goto EXIT;

   ccode = NWVerifyObjectPassword (
                  (NWCONN_HANDLE) connHandle,
                  cObjectName,
                  (nuint16) objectType,
                  cPassword);

EXIT:

   (*env)->ReleaseStringChars (env, objectName, uniObjectName);
//   (*env)->ReleaseStringChars (env, password, uniPassword);

   return ((jint) ccode);
} /* ...NWVerifyObjectPassword () */


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWLogoutFromFileServer
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWLogoutFromFileServer\n");
      THREADSWITCH;
   #endif
   return ((jint) NWLogoutFromFileServer ((NWCONN_HANDLE) connHandle));
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetDefNameContext
(
   JNIEnv   *env,
   jclass   obj,
   jobject  context  // out, StringBuffer
)
{
   NWRCODE ccode;
   nuint8 cContext[257]; /* max context length -not defined in public hdr */

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetDefNameContext\n");
      THREADSWITCH;
   #endif

   ccode = NWGetDefaultNameContext(sizeof(cContext), cContext);

   if (ccode == 0)
   {
      jclass cls;
      jmethodID mid;
      jstring javaString;
      unicode uniBuf[sizeof (cContext)];

      ccode = __LocalToJavaStr (
                  env,
                  &javaString,
                  uniBuf,
                  cContext);
      if (ccode != 0)
         return ((jint) ccode);
      cls = (*env)->GetObjectClass(env, context);
      mid = (*env)->GetMethodID(env, cls, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
      if (0 == mid)  // method not found
         return(-1);
      (*env)->CallObjectMethod(env, context, mid, javaString);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetPrefServerName
(
   JNIEnv   *env,
   jclass   obj,
   jobject  s
)
{
   NWRCODE ccode;
   char servName[NW_MAX_SERVER_NAME_LEN];

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCCGetPrefServerName\n");
      THREADSWITCH;
   #endif

   ccode = NWCCGetPrefServerName(sizeof(servName), servName);

   if (0 == ccode)
   {
      jclass cls;
      jmethodID mid;
      jstring javaString;
      unicode uniBuf[sizeof (servName)];

      ccode = __LocalToJavaStr (
                  env,
                  &javaString,
                  uniBuf,
                  servName);
      if (ccode != 0)
         return ((jint) ccode);
      cls = (*env)->GetObjectClass(env, s);
      mid = (*env)->GetMethodID(env, cls, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
      if (0 == mid)  // method not found
         return(-1);
      (*env)->CallObjectMethod(env, s, mid, javaString);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetPrefDsTreeName
(
   JNIEnv   *env,
   jclass   obj,
   jobject  returnString
)
{
   NWRCODE ccode;
   nuint8 treeName[MAX_DN_BYTES], nameType;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetPrefDsTreeName\n");
      THREADSWITCH;
   #endif

   ccode = NWGetPreferredConnName (treeName, &nameType);

   if (0 == ccode && NWNDS_CONNECTION == nameType)
   {
      jclass cls;
      jmethodID mid;
      jstring javaString;
      unicode uniBuf[sizeof (treeName)];

      ccode = __LocalToJavaStr (
                  env,
                  &javaString,
                  uniBuf,
                  treeName);
      if (ccode != 0)
         return ((jint) ccode);
      cls = (*env)->GetObjectClass(env, returnString);
      mid = (*env)->GetMethodID(env, cls, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
      if (0 == mid)  // method not found
         return(-1);
      (*env)->CallObjectMethod(env, returnString, mid, javaString);
   }

/* NOTE: this is here until a real API is coded, where we don't have to
   worry about the type of name that comes back, it will always be a
   tree name */
   if (NWNDS_CONNECTION != nameType)
      return (NWE_DS_PREFERRED_NOT_SPECIFIED);
/* NOTE: end of section */

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetRequesterVersion
(
   JNIEnv   *env,
   jclass   obj,
   jobject  version
)
{
   nuint8 majorVersion, minorVersion, revision, betaRelease;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetRequesterVersion\n");
      THREADSWITCH;
   #endif

   NWCCGetCLXVersion(&majorVersion, &minorVersion, &revision, &betaRelease);

   cls = (*env)->GetObjectClass(env, version);
   mid = (*env)->GetMethodID(env, cls, "setMajor","(I)V");
   if (0 == mid)
   {
      return(-1);
   }
   (*env)->CallVoidMethod(env, version, mid, majorVersion);

   mid = (*env)->GetMethodID(env, cls, "setMinor","(I)V");
   if (0 == mid)
   {
      return(-1);
   }
   (*env)->CallVoidMethod(env, version, mid, minorVersion);

   mid = (*env)->GetMethodID(env, cls, "setRevision","(I)V");
   if (0 == mid)
   {
      return(-1);
   }
   (*env)->CallVoidMethod(env, version, mid, revision);
   // betaRelease is irrelavant for NWVersion

   return ((jint) 0);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWGetNWNetVersion
(
   JNIEnv   *env,
   jclass   obj,
   jobject  version
)
{
   nuint8 majorVersion, minorVersion, revision, betaRelease;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWGetNWNetVersion\n");
      THREADSWITCH;
   #endif

   NWGetNWNetVersion(&majorVersion, &minorVersion, &revision, &betaRelease);

   cls = (*env)->GetObjectClass(env, version);
   mid = (*env)->GetMethodID(env, cls, "setMajor","(I)V");
   if (0 == mid)
   {
      return(-1);
   }
   (*env)->CallVoidMethod(env, version, mid, majorVersion);

   mid = (*env)->GetMethodID(env, cls, "setMinor","(I)V");
   if (0 == mid)
   {
      return(-1);
   }
   (*env)->CallVoidMethod(env, version, mid, minorVersion);

   mid = (*env)->GetMethodID(env, cls, "setRevision","(I)V");
   if (0 == mid)
   {
      return(-1);
   }
   (*env)->CallVoidMethod(env, version, mid, revision);
   // betaRelease is irrelavant for NWVersion

   return ((jint) 0);
}


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetSecurityFlags
(
   JNIEnv   *env,
   jclass   obj,
   jobject  enabled,    // out, optional
   jobject  preferred,
   jobject  required
)
{
   nuint32 flags[3];
   NWRCODE ccode;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetSecurityFlags\n");
      THREADSWITCH;
   #endif

   ccode = NWCCGetSecurityFlags(&flags[0], &flags[1], &flags[2]);

   if (0 == ccode)
   {
      jclass cls;
      jmethodID mid;

      if (NULL != enabled)
      {
         cls = (*env)->GetObjectClass (env, enabled);
         mid = (*env)->GetMethodID (env, cls, "setValue", "(I)V");

         (*env)->CallVoidMethod (env, enabled, mid, (jint) flags[0]);
      }

      if (NULL != preferred)
      {
         cls = (*env)->GetObjectClass (env, preferred);
         mid = (*env)->GetMethodID (env, cls, "setValue", "(I)V");

         (*env)->CallVoidMethod (env, preferred, mid, (jint) flags[1]);
      }

      if (NULL != required)
      {
         cls = (*env)->GetObjectClass (env, required);
         mid = (*env)->GetMethodID (env, cls, "setValue", "(I)V");

         (*env)->CallVoidMethod (env, required, mid, (jint) flags[2]);
      }
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCQueryFeature

(
   JNIEnv   *env,
   jclass   obj,
   jint     featureCode
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWCQueryFeature\n");
      THREADSWITCH;
   #endif

   return ((jint) NWCCQueryFeature((nuint) featureCode));
}


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCSetDefNameContext

(
   JNIEnv   *env,
   jclass   obj,
   jstring  context
)
{
   NWRCODE ccode;
   nuint8 cContext[257]; /* assumed max context -not defin. in public hdr */
   punicode uniContext;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCSetDefNameContext\n");
      THREADSWITCH;
   #endif

   //convert java to C  (strings)
   uniContext = (punicode) (*env)->GetStringChars (env, context, 0);

   ccode = __UnicodeToLocalStr (
               cContext,
               sizeof (cContext),
               uniContext,
               (*env)->GetStringLength (env, context));
   if (ccode != 0)
      goto EXIT;

   ccode = NWSetDefaultNameContext (
               (nuint16) NWLmblen (cContext, sizeof (cContext)),
               cContext);

EXIT:

   (*env)->ReleaseStringChars (env, context, uniContext);

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCSetPrefServerName

(
   JNIEnv   *env,
   jclass   obj,
   jstring  newServer
)
{
   NWRCODE ccode;
   nstr8 cNewServer[NW_MAX_SERVER_NAME_LEN];
   punicode uniNewServer;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCSetPrefServerName\n");
      THREADSWITCH;
   #endif

   uniNewServer = (punicode) (*env)->GetStringChars (env, newServer, 0);

   ccode = __UnicodeToLocalStr (
               cNewServer,
               sizeof (cNewServer),
               uniNewServer,
               (*env)->GetStringLength (env, newServer));
   if (ccode != 0)
      goto EXIT;

   ccode = NWCCSetPrefServerName (cNewServer);

EXIT:

   (*env)->ReleaseStringChars (env, newServer, uniNewServer);

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCSetPrefDsTreeName

(
   JNIEnv   *env,
   jclass   obj,
   jstring  newTree
)
{
   NWRCODE ccode;
   nstr8 treeStr[NW_MAX_TREE_NAME_LEN];
   punicode uniTreeStr;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCSetPrefDsTreeName\n");
      THREADSWITCH;
   #endif

   //convert java to C  (strings)
   uniTreeStr = (punicode) (*env)->GetStringChars (env, newTree, 0);

   ccode = __UnicodeToLocalStr (
               treeStr,
               sizeof (treeStr),
               uniTreeStr,
               (*env)->GetStringLength (env, newTree));
   if (ccode != 0)
      goto EXIT;

   ccode = NWSetPreferredDSTree(
               (nuint16) NWLmblen (treeStr, sizeof (treeStr)),
               treeStr);

EXIT:

   (*env)->ReleaseStringChars (env, newTree, uniTreeStr);

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCSetSecurityFlags

(
   JNIEnv   *env,
   jclass   obj,
   jint     preferred,
   jint     required
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWCSetSecurityFlags\n");
      THREADSWITCH;
   #endif

   return ((jint) NWCCSetSecurityFlags((nuint32) preferred,
         (nuint32) required));
}


//
// NWConnection
//

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetConnInfoAddress
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jint     connRef,
   jobject  outAddress /* com.novell.service.session.xplat.Address */
)
{
   NWRCODE ccode;
   NWCCTranAddr addr;
   jbyteArray byteArr;
   jbyte      *pByte;
   nuint32 luAddrLen;
   jclass cls;
   jmethodID mid;
   int i;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetConnInfoAddress\n");
      THREADSWITCH;
   #endif

   /* lightweight connection, so let's look for the length of the address,
      so that we can alllocate an appropriate array */
   if (0 == connHandle)
   {
      ccode = NWCCGetConnRefAddressLength (
                  (nuint32) connRef,
                  &luAddrLen);
   }
   else
   {
      ccode = NWCCGetConnAddressLength (
                  (NWCONN_HANDLE) connHandle,
                  &luAddrLen);
   }

   if (0 != ccode)   // 0 means success in getting address length
      return ((jint) ccode);

   /* size of needed buffer is in luAddrLen */
   /* next we allocate a byte[] with the needed space to store the address */
   byteArr = (*env)->NewByteArray (env, luAddrLen);
   if (NULL == byteArr)    // out of memory
      return (-1);

   addr.buffer = sysMalloc(luAddrLen);
   if (NULL == addr.buffer)
      return (-1);

   /* then we hook the newly allocated byte[] up with the NWCCTranAdddr
      structure, so that we now will get a filled Java byte[] when
      NWCCGetConnAddress returns */

   /* lightweight connection, so let's treat it like that */
   if (0 == connHandle)
   {
      ccode = NWCCGetConnRefAddress (
                  (nuint32) connRef,
                  luAddrLen,
                  &addr);
   }
   else
   {
      ccode = NWCCGetConnAddress (
                  (NWCONN_HANDLE) connHandle,
                  luAddrLen,
                  &addr);
   }

   if (0 == ccode)
   {
      // COPY addr.buffer into byteArr
      pByte = (*env)->GetByteArrayElements(env, byteArr, 0);
      for (i = 0; i < (int)addr.len; i++)
         *(pByte + i) = addr.buffer[i];
      (*env)->ReleaseByteArrayElements(env, byteArr, pByte, 0); //copy back to array

      cls = (*env)->GetObjectClass(env, outAddress);
      mid = (*env)->GetMethodID(env, cls, "setAddress","(I[B)V");
      if (0 == mid)
         return (-1);
      (*env)->CallVoidMethod(env, outAddress, mid, addr.type, byteArr);

      sysFree(addr.buffer);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetConnInfoLong

(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jint     connRef,
   jint     infoLevel,
   jobject  outLong
)
{
   NWRCODE ccode;
   nuint uVal;
   nuint32 luVal;
   long finalValue;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetConnInfoLong\n");
      THREADSWITCH;
   #endif

   switch (infoLevel)
   {
      /* if we're getting a "nuint", then... */
      case NWCC_INFO_AUTHENT_STATE:
      case NWCC_INFO_BCAST_STATE:
      case NWCC_INFO_CONN_NUMBER:
      case NWCC_INFO_NDS_STATE:
      case NWCC_INFO_MAX_PACKET_SIZE:
      case NWCC_INFO_LICENSE_STATE:
      case NWCC_INFO_DISTANCE:
         if (0 == connHandle)
         {
            ccode = NWCCGetConnRefInfo (
                        (nuint32) connRef,
                        (nuint) infoLevel,
                        sizeof(uVal),
                        &uVal);
         }
         else
         {
            ccode = NWCCGetConnInfo (
                        (NWCONN_HANDLE) connHandle,
                        (nuint) infoLevel,
                        sizeof(uVal),
                        &uVal);
         }
         finalValue = (long) uVal;
         break;

      /* if we're getting a "nuint32", then... */
      case NWCC_INFO_CONN_REF:
      case NWCC_INFO_USER_ID:
         if (0 == connHandle)
         {
            ccode = NWCCGetConnRefInfo (
                        (nuint32) connRef,
                        (nuint) infoLevel,
                        sizeof(luVal),
                        &luVal);
         }
         else
         {
            ccode = NWCCGetConnInfo (
                        (NWCONN_HANDLE) connHandle,
                        (nuint) infoLevel,
                        sizeof(luVal),
                        &luVal);
         }
         finalValue = (long) luVal;
         break;

      default:
         return (NWE_INVALID_LEVEL);
   }

   if (0 == ccode)
   {
      cls = (*env)->GetObjectClass(env, outLong);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)  // method not found
         return(-1);
      (*env)->CallVoidMethod(env, outLong, mid, finalValue);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetConnInfoString
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jint     connRef,
   jint     infoLevel,
   jobject  outString
)
{
   NWRCODE ccode;

   /* buffer is as long as the longest of: NW_MAX_TREE_NAME_LEN,
      NW_MAX_SERVER_NAME_LEN */
   nstr8 buffer[__MAX(NW_MAX_TREE_NAME_LEN, NW_MAX_SERVER_NAME_LEN)];

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetConnInfoString\n");
      THREADSWITCH;
   #endif

   switch ((int) infoLevel)
   {
      case NWCC_INFO_TREE_NAME:
      case NWCC_INFO_SERVER_NAME:
         break;
      default:
         return (NWE_INVALID_LEVEL);
   }

   /* if lightweight connection, then handle it like one */
   if (0 == connHandle)
   {
      ccode = NWCCGetConnRefInfo (
                  (nuint32) connRef,
                  (nuint) infoLevel,
                  sizeof(buffer),
                  buffer);
   }
   else
   {
      ccode = NWCCGetConnInfo (
                  (NWCONN_HANDLE) connHandle,
                  (nuint) infoLevel,
                  sizeof(buffer),
                  buffer);
   }

   if (0 == ccode)
   {
      jclass cls;
      jmethodID mid;
      jstring javaString;
      unicode uniBuf[sizeof (buffer)];

      ccode = __LocalToJavaStr (
                  env,
                  &javaString,
                  uniBuf,
                  buffer);
      if (ccode != 0)
         return ((jint) ccode);

      cls = (*env)->GetObjectClass(env, outString);
      mid = (*env)->GetMethodID(env, cls, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
      if (0 == mid)
         return(-1);
      (*env)->CallObjectMethod(env, outString, mid, javaString);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetConnInfoVersion
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jint     connRef,
   jint     infoLevel,
   jobject  outVersion
)
{
   NWRCODE ccode;
   NWCCVersion ver;
   jmethodID mid;
   jclass cls;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetConnInfoVersion\n");
      THREADSWITCH;
   #endif

   if ((int) infoLevel != NWCC_INFO_SERVER_VERSION)
      return (NWE_INVALID_LEVEL);

   if (0 == connHandle)
   {
      ccode = NWCCGetConnRefInfo (
                  (nuint32) connRef,
                  (nuint) infoLevel,
                  sizeof(ver),
                  &ver);
   }
   else
   {
      ccode = NWCCGetConnInfo (
                  (NWCONN_HANDLE) connHandle,
                  (nuint) infoLevel,
                  sizeof(ver),
                  &ver);
   }

   if (0 == ccode)
   {
      cls = (*env)->GetObjectClass(env, outVersion);
      mid = (*env)->GetMethodID(env, cls, "setMajor","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, outVersion, mid, (jint) ver.major);

      mid = (*env)->GetMethodID(env, cls, "setMinor","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, outVersion, mid, (jint) ver.minor);

      mid = (*env)->GetMethodID(env, cls, "setRevision","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, outVersion, mid, (jint) ver.revision);

      // betaRelease is irrelavant for NWVersion
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCLicenseConn

(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle
)
{
   NWRCODE ccode;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCLicenseConn\n");
      THREADSWITCH;
   #endif

   ccode = NWCCLicenseConn((NWCONN_HANDLE) connHandle);

//
// !!!IMPORTANT!!! for NLM only
//
// NOTE:
// NOTES & EXPLANATIONS: 18.Dec.97 jgs
// On MOAB servers, the license function returns 0x7B for an already
// licensed connection.  On 4.x servers, no error code was returned.
//

#ifdef N_PLAT_NLM

   if (ccode == 0x7B)
      ccode = 0;

#endif

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCSpecialLicenseConn

(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle
)
{
   NWRCODE ccode = 0;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCLicenseConn\n");
      THREADSWITCH;
   #endif

#ifndef N_PLAT_NLM

   ccode = NWCCLicenseConn((NWCONN_HANDLE) connHandle);

#endif

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCRenegotiateSecurityLevel
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jint     securityLevel
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWCRenegotiateSecurityLevel\n");
      THREADSWITCH;
   #endif

   return ((jint) NWCCRenegotiateSecurityLevel ((NWCONN_HANDLE) connHandle,
         (nuint32) securityLevel));
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCSetConnInfoLong
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jint     infoLevel,
   jobject  value
)
{
   NWRCODE ccode;
   nuint uValueToChange;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCSetConnInfoLong\n");
      THREADSWITCH;
   #endif

   // currently, we cannot set any other parameters in this manner other
   // than the broadcast state
   if (NWCC_INFO_BCAST_STATE != infoLevel)
      return (NWE_INVALID_LEVEL);

   cls = (*env)->GetObjectClass(env, value);
   mid = (*env)->GetMethodID(env, cls, "getIntValue","()I");
   if (0 == mid)
      return(-1);
   uValueToChange =  (nuint)(*env)->CallIntMethod(env, value, mid);

   ccode = NWSetBroadcastMode (
               (NWCONN_HANDLE) connHandle,
               (nuint16) uValueToChange);

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCUnlicenseConn
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWCUnlicenseConn\n");
      THREADSWITCH;
   #endif

   return ((jint) NWCCUnlicenseConn((NWCONN_HANDLE) connHandle));
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCScanConnInfoLong
(
   JNIEnv   *env,
   jclass   obj,
   jobject  iterator,
   jint     infoLevel,
   jobject  scanValue,
   jint     scanFlags,
   jobject  outConnRef
)
{
   NWRCODE ccode;
   nuint32 luScanIterator;
   nuint32 luConnRef;
   nuint32 luScanValue;
   int found;
   nuint uInput;
   nuint32 luInput;
   nuint uScanSize = 0;
   nptr pInput = NULL;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCScanConnInfoLong\n");
      THREADSWITCH;
   #endif

   if (NULL != scanValue)
   {
      cls = (*env)->GetObjectClass(env, scanValue);
      mid = (*env)->GetMethodID(env, cls, "getIntValue","()I");
      if (0 == mid)
         return(-1);
      luScanValue = (nuint32)(*env)->CallIntMethod(env, scanValue, mid);


      /* uScanSize and pInput are by default 0 and NULL */
      switch ((int) infoLevel)
      {
         case 0:        /* searching for no particular value */
            break;
         case NWCC_INFO_AUTHENT_STATE:
         case NWCC_INFO_BCAST_STATE:
         case NWCC_INFO_CONN_NUMBER:
         case NWCC_INFO_NDS_STATE:
         case NWCC_INFO_MAX_PACKET_SIZE:
         case NWCC_INFO_LICENSE_STATE:
         case NWCC_INFO_DISTANCE:
            uScanSize = sizeof(nuint);
            pInput = (nptr) &uInput;    /* pass pointer to nuint type */
            break;
         case NWCC_INFO_CONN_REF:
         case NWCC_INFO_USER_ID:
            uScanSize = sizeof(nuint32);
            pInput = (nptr) &luInput;    /* pass pointer to nuint32 type */
            break;
         default:
            return (NWE_INVALID_LEVEL);
      }
   }
   else  /* if there is no 'scanValue' then search for no value */
      infoLevel = 0;

   cls = (*env)->GetObjectClass(env, iterator);
   mid = (*env)->GetMethodID(env, cls, "getIntValue","()I");
   if (0 == mid)
      return(-1);
   luScanIterator =  (nuint32)(*env)->CallIntMethod(env, iterator, mid);

   found = 0;
   ccode = 0;
   while (0 == ccode && !found)
   {
      ccode = NWCCScanConnRefs (
                  &luScanIterator,
                  &luConnRef);

      if (0 != ccode)
         goto EXIT;

      if (0 == infoLevel)  /* if there is nothing to compare, then move on */
      {
         found = 1;
         continue;
      }

      ccode = NWCCGetConnRefInfo (
                  luConnRef,
                  (nuint) infoLevel,
                  uScanSize,
                  pInput);

      if (0 != ccode)
         goto EXIT;

      found = 0;
      if (&uInput == pInput && uInput == luScanValue)  /* nuint */
         found = 1;
      else if (&luInput == pInput && luInput == luScanValue) /* nuint32 */
         found = 1;
   }

   if (0 == ccode && !found)
      ccode = NWE_NO_MORE_ENTRIES;

   if (0 == ccode)
   {
      /* record current state of iterator in the Java object */
      cls = (*env)->GetObjectClass(env, iterator);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, iterator, mid, luScanIterator);

      /* pass the returned connection reference back to Java level */
      cls = (*env)->GetObjectClass(env, outConnRef);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, outConnRef, mid, luConnRef);
   }

EXIT:

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCScanConnInfoString
(
   JNIEnv   *env,
   jclass   obj,
   jobject  iterator,
   jint     infoLevel,
   jstring  scanValue,
   jint     scanFlags,
   jobject  outConnRef
)
{
   NWRCODE ccode;
   nuint32 luScanIterator;
   nuint32 luConnRef;

   /* buffer and tmpBuffer are as long as the longest of:
      NW_MAX_SERVICE_TYPE_LEN, NW_MAX_SERVER_NAME_LEN, and
      NW_MAX_SERVICE_TYPE_LEN */
   nstr8 buffer[__MAX(__MAX(NW_MAX_SERVICE_TYPE_LEN, NW_MAX_SERVER_NAME_LEN),
         NW_MAX_SERVICE_TYPE_LEN)];
   nstr8 tmpBuffer[sizeof (buffer)];
   punicode uniValue;
   int found;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCScanConnInfoString\n");
      THREADSWITCH;
   #endif

   if (NULL != scanValue)
   {
      /* uScanSize and pInput are by default NULL */
      switch ((int) infoLevel)
      {
         case 0:     /* search for no value */
            break;
         case NWCC_INFO_TREE_NAME:
         case NWCC_INFO_SERVER_NAME:
            uniValue = (punicode) (*env)->GetStringChars (env, scanValue, 0);
            #ifdef DEBUG_OUT
//               PRINTF("Value before: 0x%X\n", uniValue);
//            THREADSWITCH;
            #endif

            ccode = __UnicodeToLocalStr (
                        buffer,
                        sizeof (buffer),
                        uniValue,
                        (*env)->GetStringLength (env, scanValue));

            // if the translated length of 'scanValue' is greater than
            //   sizeof(buffer), then the new unicode APIs return
            //   NWU_BUFFER_FULL (-530) for buffer overflow.
            // it's best here to just ignore it and return no more entries
            if (ccode == NWU_BUFFER_FULL)
               ccode = NWE_NO_MORE_ENTRIES;

   #ifdef DEBUG_OUT
//      PRINTF("OUTPUT utolstr: (%d) 0x%X NWCScanConnInfoString (%s)\n", ccode, ccode, buffer);
//      THREADSWITCH;
   #endif
            #ifdef DEBUG_OUT
//               PRINTF("Value after: 0x%X\n", uniValue);
//               THREADSWITCH;
            #endif

            (*env)->ReleaseStringChars (env, scanValue, uniValue);

            #ifdef DEBUG_OUT
//               PRINTF("Strings released: 0x%X\n", uniValue);
//               THREADSWITCH;
            #endif

            if (ccode != 0)
               goto EXIT;

            break;
         default:
            ccode = NWE_INVALID_LEVEL;
            goto EXIT;
      }
   }
   else  /* if there is no 'scanValue' then search for no value */
      infoLevel = 0;

   cls = (*env)->GetObjectClass(env, iterator);
   mid = (*env)->GetMethodID(env, cls, "getIntValue","()I");

   if (0 == mid)
   {
      ccode = -1;
      goto EXIT;
   }
   luScanIterator = (nuint32)(*env)->CallIntMethod(env, iterator, mid);

   ccode = 0;
   found = 0;
   while (0 == ccode && !found)
   {
      ccode = NWCCScanConnRefs (
                  &luScanIterator,
                  &luConnRef);

   #ifdef DEBUG_OUT
      PRINTF("OUTPUT scan: (%d) 0x%X NWCScanConnInfoString (0x%X)\n", ccode, ccode, luConnRef);
      THREADSWITCH;
   #endif
      if (0 != ccode)
         goto EXIT;

      ccode = NWCCGetConnRefInfo (
                  luConnRef,
                  (nuint) infoLevel,
                  sizeof (tmpBuffer),
                  tmpBuffer);

   #ifdef DEBUG_OUT
      PRINTF("OUTPUT get: (%d) 0x%X NWCScanConnInfoString (%s)\n", ccode, ccode, tmpBuffer);
      THREADSWITCH;
   #endif
      if (0 != ccode)
         goto EXIT;

      if (0 == infoLevel)
         found = 1;
      else
         found = (NWLstricmp (buffer, tmpBuffer) == 0);
   }

   if (0 == ccode && !found)
      ccode = NWE_NO_MORE_ENTRIES;

   if (0 == ccode)
   {
      /* record current state of iterator in the Java object */
      cls = (*env)->GetObjectClass(env, iterator);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
      {
         ccode = -1;
         goto EXIT;
      }
      (*env)->CallVoidMethod(env, iterator, mid, luScanIterator);

      /* pass the returned connection reference back to Java level */
      cls = (*env)->GetObjectClass(env, outConnRef);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
      {
         ccode = -1;
         goto EXIT;
      }
      (*env)->CallVoidMethod(env, outConnRef, mid, luConnRef);
   }

EXIT:

   #ifdef DEBUG_OUT
      PRINTF("OUT: NWCScanConnInfoString (%d) 0x%X\n", ccode, ccode);
      THREADSWITCH;
   #endif
   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCScanConnInfoVersion
(
   JNIEnv   *env,
   jclass   obj,
   jobject  iterator,
   jint     infoLevel,
   jobject  scanValue,
   jint     scanFlags,
   jobject  outConnRef
)
{
   NWRCODE ccode;
   NWCCVersion ver, tmpVer;
   nuint32 luScanIterator;
   nuint32 luConnRef;
   nuint uScanSize = 0;
   nptr pInput = NULL;
   int found;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCScanConnInfoVersion\n");
      THREADSWITCH;
   #endif

   if (NULL != scanValue)
   {
      /* uScanSize and pInput are by default NULL */
      switch ((int) infoLevel)
      {
         case 0:
            break;
         case NWCC_INFO_SERVER_VERSION:
            /* set up the NWCCVersion for the scan */
            cls = (*env)->GetObjectClass(env, scanValue);
            mid = (*env)->GetMethodID(env, cls, "getMajor","()I");
            if (0 == mid)
               return(-1);
            ver.major =  (nuint)(*env)->CallIntMethod(env, scanValue, mid);
            cls = (*env)->GetObjectClass(env, scanValue);
            mid = (*env)->GetMethodID(env, cls, "getMinor","()I");
            if (0 == mid)
               return(-1);
            ver.minor =  (nuint)(*env)->CallIntMethod(env, scanValue, mid);
            cls = (*env)->GetObjectClass(env, scanValue);
            mid = (*env)->GetMethodID(env, cls, "getRevision","()I");
            if (0 == mid)
               return(-1);
            ver.revision =  (nuint)(*env)->CallIntMethod(env, scanValue, mid);

            uScanSize = sizeof(tmpVer);
            pInput = (nptr) &tmpVer;
            break;
         default:
            return (NWE_INVALID_LEVEL);
      }
   }
   else  /* if there is no 'scanValue' then search for no value */
      infoLevel = 0;
   cls = (*env)->GetObjectClass(env, iterator);
   mid = (*env)->GetMethodID(env, cls, "getIntValue","()I");
   if (0 == mid)
      return(-1);
   luScanIterator =  (nuint32)(*env)->CallIntMethod(env, iterator, mid);

   ccode = 0;
   found = 0;
   while (0 == ccode && !found)
   {
      ccode = NWCCScanConnRefs (
                  &luScanIterator,
                  &luConnRef);

      if (0 != ccode)
         goto EXIT;

      ccode = NWCCGetConnRefInfo (
                  luConnRef,
                  (nuint) infoLevel,
                  uScanSize,
                  pInput);

      if (0 != ccode)
         goto EXIT;

      if (0 == infoLevel)
         found = 1;
      else
      {
         found = 0;

         if (ver.major == tmpVer.major &&
             ver.minor == tmpVer.minor &&
             ver.revision == tmpVer.revision)
         {
            found = 1;
         }
      }
   }

   if (0 == ccode && !found)
      ccode = NWE_NO_MORE_ENTRIES;

   if (0 == ccode)
   {
      /* record current state of iterator in the Java object */
      cls = (*env)->GetObjectClass(env, iterator);
      mid = (*env)->GetMethodID(env, cls, "setIntValue","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, iterator, mid, luScanIterator);

      /* pass the returned connection reference back to Java level */
      cls = (*env)->GetObjectClass(env, outConnRef);
      mid = (*env)->GetMethodID(env, cls, "setIntValue","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, outConnRef, mid, luConnRef);
   }

EXIT:

   return ((jint) ccode);
}


//
// NWConnectionManager
//

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCCloseConn
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWCCloseConn\n");
      THREADSWITCH;
   #endif

   return ((jint) NWCCCloseConn ((NWCONN_HANDLE) connHandle));
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCSysCloseConnRef
(
   JNIEnv   *env,
   jclass   obj,
   jint     connRef
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWCSysCloseConnRef\n");
      THREADSWITCH;
   #endif

   return ((jint) NWCCSysCloseConnRef((nuint32) connRef));
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetNumConns
(
   JNIEnv   *env,
   jclass   obj,
   jobject  maxConns,
   jobject  publicConns,
   jobject  myPrivateConns,
   jobject  otherPrivateConns
)
{
   NWRCODE ccode;
   nuint uPublic, uMyPrivate, uOtherPrivate;
   nuint16 suMax;
   nuint32 luIterator, luUnused;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetNumConns\n");
      THREADSWITCH;
   #endif

   /* private connections are not supported */
   uMyPrivate = uOtherPrivate = 0;

   NWGetMaximumConnections(&suMax);

   uPublic = 0;
   ccode = 0;
   luIterator = 0;
   while (0 == ccode)
   {
      ccode = NWCCScanConnRefs (&luIterator, &luUnused);
      if (0 == ccode)
         uPublic += 1;
   }
   if (NWE_NO_MORE_ENTRIES == ccode)
      ccode = 0;

   if (0 == ccode)
   {
      if (NULL != maxConns)
      {
            cls = (*env)->GetObjectClass(env, maxConns);
            mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
            if (0 == mid)
            {
               return(-1);
            }
            (*env)->CallVoidMethod(env, maxConns, mid, suMax);
      }

      if (NULL != publicConns)
      {
         cls = (*env)->GetObjectClass(env, publicConns);
         mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
         if (0 == mid)
         {
            return(-1);
         }
         (*env)->CallVoidMethod(env, publicConns, mid, uPublic);

      }
      if (NULL != myPrivateConns)
      {
         cls = (*env)->GetObjectClass(env, myPrivateConns);
         mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
         if (0 == mid)
         {
            return(-1);
         }
         (*env)->CallVoidMethod(env, myPrivateConns, mid, uMyPrivate);

      }

      if (NULL != otherPrivateConns)
      {
         cls = (*env)->GetObjectClass(env, otherPrivateConns);
         mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
         if (0 == mid)
         {
            return(-1);
         }
         (*env)->CallVoidMethod(env, otherPrivateConns, mid, uOtherPrivate);

      }
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetPrimConnRef
(
   JNIEnv   *env,
   jclass   obj,
   jobject  connRef
)
{
   NWRCODE ccode;
   nuint32 luConnRef;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetPrimConnRef\n");
      THREADSWITCH;
   #endif

   ccode = NWCCGetPrimConnRef(&luConnRef);

   if (0 == ccode)
   {
      cls = (*env)->GetObjectClass(env, connRef);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, connRef, mid, luConnRef);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCMakeConnPermanent
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWCMakeConnPermanent\n");
      THREADSWITCH;
   #endif

   return ((jint) NWCCMakeConnPermanent((NWCONN_HANDLE) connHandle));
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCOpenConnByAddress
(
   JNIEnv   *env,
   jclass   obj,
   jint     connFlags,
   jobject  address, /* com.novell.service.session.xplat.Address */
   jobject  connHandle /*NWLong*/ /*out*/
)
{
   NWRCODE ccode;
   NWCCTranAddr tranAddr;
   jbyteArray addressHandle;
   NWCONN_HANDLE newConnHandle;
   jclass cls;
   jmethodID mid;

   #ifdef N_PLAT_NLM
   nint currentThreadGroup = GetThreadGroupID();
   nint newThreadGroup = GimmeNewThreadGroupAndUserPlease();
   #endif

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCOpenConnByAddress\n");
      THREADSWITCH;
   #endif

   /* get address type */
   cls = (*env)->GetObjectClass(env, address);
   mid = (*env)->GetMethodID(env, cls, "getType","()I");
   if (0 == mid)
      return(-1);
   tranAddr.type =(*env)->CallIntMethod(env, address, mid);

   /* get address byte array from address object */
   cls = (*env)->GetObjectClass(env, address);
   mid = (*env)->GetMethodID(env, cls, "getAddress","()[B");
   if (0 == mid)
      return(-1);
   addressHandle = (*env)->CallObjectMethod(env, address, mid);

   if (NULL == addressHandle)    /* handle error in getting byte array */
   {
      __ThrowException (env, JAVAPKG "NullPointerException",
            "client.NWCOpenConnByAddress calling address.getAddress() - NATIVE");
      return (-1);
   }

   /* get number of bytes in the address array */
   tranAddr.len = (nuint32)(*env)->GetArrayLength(env, addressHandle);

   /* assign pointer reference to internal array of bytes in address array */
   tranAddr.buffer = (char *) (*env)->GetByteArrayElements(env,
         addressHandle, NULL);

   #ifdef N_PLAT_NLM
   SetThreadGroupID(newThreadGroup);
   #endif

   ccode = NWCCOpenConnByAddr (
               &tranAddr,
               (nuint) connFlags,
               (nuint) NWCC_RESERVED,  /* reserved */
               &newConnHandle);

   #ifdef N_PLAT_NLM
   SetThreadGroupID(currentThreadGroup);
   DoneWithThisThreadGroupAndUserThankYou(newThreadGroup);
   #endif

   (*env)->ReleaseByteArrayElements(env, addressHandle,
         (jbyte *) tranAddr.buffer, JNI_ABORT);

   if (0 == ccode)
   {
#ifdef N_PLAT_NLM
//      ccode = NLMAuthNewConnection (newConnHandle);
//      if (ccode != 0)
//         return ((jint) ccode);
#endif
      cls = (*env)->GetObjectClass(env, connHandle);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
      {
         return(-1);
      }
      (*env)->CallVoidMethod(env, connHandle, mid, newConnHandle);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSOpenConnToNDSServer
(
   JNIEnv *env,
   jclass unused,
   jint threadGroup,
   jint context,
   jstring serverName,
   jobject connHandle //IntegerBuffer out
)
{
   NWDSCCODE   ccode;
   unicode     cServerName[MAX_DN_CHARS + 1];
   NWCONN_HANDLE cConnHandle;

#ifdef N_PLAT_NLM
   nint saveThreadGroup;
#endif

   // Convert Java variable to 'C' variable
   jstring2unicode (env, serverName, cServerName, sizeof(cServerName));

#ifdef N_PLAT_NLM
   ccode = wrapContext(&saveThreadGroup, threadGroup, context);
   if (0 != ccode)
      return ccode;
#endif

   // Make C API call
   ccode = NWDSOpenConnToNDSServer(
               (NWDSContextHandle)context,
               (pnstr8)cServerName,
               &cConnHandle);

#ifdef N_PLAT_NLM
   unwrapContext(saveThreadGroup);
#endif

   // Copy cMajorVersion into Java majorVersion
   if (ccode == N_SUCCESS)
   {
      jclass      cls;
      jmethodID   mid;

      cls = (*env)->GetObjectClass(env, connHandle);
      mid = (*env)->GetMethodID (env, cls, "setValue","(I)V");
      (*env)->CallVoidMethod(env, connHandle, mid, (jint)cConnHandle);
   }
   return ccode;

}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCOpenConnByName
(
   JNIEnv   *env,
   jclass   obj,
   jint     startConnHandle,
   jstring  serverName,
   jint     nameFormatType,
   jint     connFlags,
   jobject  connHandle
)
{
   NWRCODE ccode;
   nstr8 serverBuf[NW_MAX_SERVER_NAME_LEN];
   punicode uniServerBuf;
   jclass cls;
   jmethodID mid;
   NWCONN_HANDLE newConnHandle;

   #ifdef N_PLAT_NLM
   nint currentThreadGroup = GetThreadGroupID();
   nint newThreadGroup = GimmeNewThreadGroupAndUserPlease();
   #endif

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCOpenConnByName\n");
      THREADSWITCH;
   #endif

   uniServerBuf = (punicode) (*env)->GetStringChars(env,serverName,0);

   ccode = __UnicodeToLocalStr (
               serverBuf,
               sizeof (serverBuf),
               uniServerBuf,
               (*env)->GetStringLength (env, serverName));

   // if the translated length of 'serverName' is greater than
   //   sizeof(uniServerBuf), then the new unicode APIs return
   //   NWU_BUFFER_FULL (-530) for buffer overflow.
   // it's best here to just ignore it and return server not found
   if (ccode == NWU_BUFFER_FULL)
      ccode = NWE_SERVER_NOT_FOUND;

   (*env)->ReleaseStringChars(env,serverName,uniServerBuf);

   if (ccode != 0)
      return ((jint) ccode);

   #ifdef N_PLAT_NLM
   SetThreadGroupID(newThreadGroup);
   #endif

   ccode = NWCCOpenConnByName (
               (NWCONN_HANDLE) startConnHandle,
               serverBuf,
               (nuint) nameFormatType,
               (nuint) connFlags,
               NWCC_RESERVED,
               &newConnHandle);

   #ifdef N_PLAT_NLM
   SetThreadGroupID(currentThreadGroup);
   DoneWithThisThreadGroupAndUserThankYou(newThreadGroup);
   #endif

   if (0 == ccode)
   {
      cls = (*env)->GetObjectClass(env, connHandle);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, connHandle, mid, newConnHandle);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCOpenConnByPref
(
   JNIEnv   *env,
   jclass   obj,
   jint     connFlags,
   jint     tranType,
   jobject  connHandle
)
{
   NWRCODE ccode;

#if defined (N_PLAT_MSW) && defined (N_ARCH_32)
   NWCONN_HANDLE newHandle;
#endif

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCOpenConnByPref\n");
      THREADSWITCH;
   #endif

#if defined (N_PLAT_MSW) && defined (N_ARCH_32)
   ccode = NWCCOpenConnByPref (
               (nuint) tranType,
               (nuint) connFlags,
               NWCC_RESERVED,
               &newHandle);
   if (0 == ccode)
   {
      jclass cls;
      jmethodID mid;

      cls = (*env)->GetObjectClass(env, connHandle);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
      {
         return(-1);
      }
      (*env)->CallVoidMethod(env, connHandle, mid, newHandle);
   }

#else
// NWCCOpenConnByPref not available on this platform (non-WIN32)
   ccode = -1;
#endif

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCOpenConnDefault
(
   JNIEnv   *env,
   jclass   obj,
   jobject  defaultConnHandle
)
{
   NWRCODE ccode = -1;
   NWCONN_HANDLE newConnHandle;
   jclass cls;
   jmethodID mid;

#ifdef N_PLAT_NLM
   nstr8 serverBuf[49*2];
//   nuint32 iterator = 0;
//   nuint32 connRef;
   nint currentThreadGroup = GetThreadGroupID();
   nint newThreadGroup = GimmeNewThreadGroupAndUserPlease();
#endif

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCOpenConnDefault\n");
      THREADSWITCH;
   #endif

#ifdef N_PLAT_NLM
   GetFileServerName (0, serverBuf);

#if 0
   /* The server will always open a new connection so lets see if
    * we have one to ourselves already first
    */
   ccode = NWCCScanConnInfo (
                  &iterator,
                  NWCC_INFO_SERVER_NAME,
                  serverBuf,
                  NWCC_MATCH_EQUALS,
                  NWCC_INFO_VERSION_1,
                  NWCC_INFO_NONE,
                  NULL,
                  &connRef);
   if (0 == ccode)
   {  /* We found it so we need to turn the conn ref into a conn handle */
      ccode = NWCCOpenConnByRef (
                  connRef,
                  NWCC_OPEN_LICENSED,
                  NWCC_RESERVED,
                  &newConnHandle);
   }
#endif
   if (0 != ccode)      /* This catches two possible error cases */
   {
      SetThreadGroupID(newThreadGroup);
      ccode = NWCCOpenConnByName(-1,
                                 serverBuf,
                                 NWCC_NAME_FORMAT_BIND,
                                 NWCC_OPEN_LICENSED,
                                 NWCC_RESERVED,
                                 &newConnHandle);
      SetThreadGroupID(currentThreadGroup);
      DoneWithThisThreadGroupAndUserThankYou(newThreadGroup);
   }
   if (ccode != 0)
      return ((jint) ccode);

#else
   ccode = NWGetDefaultConnectionID (&newConnHandle);
#endif

   if (0 == ccode)
   {

      cls = (*env)->GetObjectClass(env, defaultConnHandle);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, defaultConnHandle, mid, newConnHandle);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCOpenConnByReference
(
   JNIEnv   *env,
   jclass   obj,
   jint     connReference,
   jint     connFlags,
   jobject  connHandle
)
{
   NWRCODE ccode;
   NWCONN_HANDLE newConnHandle;
   jclass cls;
   jmethodID mid;

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCOpenConnByReference\n");
      THREADSWITCH;
   #endif

   ccode = NWCCOpenConnByRef (
               (nuint32) connReference,
               (nuint) connFlags,
               NWCC_RESERVED,
               &newConnHandle);

   if (0 == ccode)
   {

#ifdef N_PLAT_NLM
//      ccode = NLMAuthNewConnection (newConnHandle);
//      if (ccode != 0)
//         return ((jint) ccode);
#endif
      cls = (*env)->GetObjectClass(env, connHandle);
      mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
      if (0 == mid)
         return(-1);
      (*env)->CallVoidMethod(env, connHandle, mid, newConnHandle);
   }
   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCGetInfoString
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle,
   jint     infoLevel,
   jobject  strToFill
)
{
   NWRCODE ccode;
   /* strBuffer is as long as the longest of: NW_MAX_TREE_NAME_LEN,
      NW_MAX_SERVER_NAME_LEN */
   nstr8 strBuffer[__MAX(NW_MAX_TREE_NAME_LEN, NW_MAX_SERVER_NAME_LEN)];

   #ifdef DEBUG_OUT
      PRINTF("IN: NWCGetInfoString\n");
      THREADSWITCH;
   #endif

   switch ((int) infoLevel)
   {
      case NWCC_INFO_TREE_NAME:
      case NWCC_INFO_SERVER_NAME:
         break;
      default:
         return (NWE_INVALID_LEVEL);
   }

   ccode = NWCCGetConnInfo (
               (NWCONN_HANDLE) connHandle,
               (nuint) infoLevel,
               sizeof(strBuffer),
               strBuffer);

   if (0 == ccode)
   {
      jclass cls;
      jmethodID mid;
      jstring javaString;
      unicode uniBuf[sizeof (strBuffer)];

      ccode = __LocalToJavaStr (
                  env,
                  &javaString,
                  uniBuf,
                  strBuffer);
      if (ccode != 0)
         return ((jint) ccode);
       cls = (*env)->GetObjectClass(env, strToFill);
       mid = (*env)->GetMethodID(env, cls, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
       if (0 == mid)
          return(-1);
       (*env)->CallObjectMethod(env, strToFill, mid, javaString);
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWCSetPrimConn
(
   JNIEnv   *env,
   jclass   obj,
   jint     connHandle
)
{
   #ifdef DEBUG_OUT
      PRINTF("IN: NWCSetPrimConn\n");
      THREADSWITCH;
   #endif

   return ((jint) NWCCSetPrimConn((NWCONN_HANDLE) connHandle));
}


//
// NDSSession
//

/* *
 * NWDSCreateContextHandle.
 *
 * Differs from NWDSCreateContext in that the return code may now specify
 * codes indicative of the reason for the failure.
 */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSCreateContextHandle
(
   JNIEnv      *env,
   jclass      obj,
   jintArray   newThreadGroup,
   jintArray   newHandle
)
{
   NWDSCCODE ccode;
   NWDSContextHandle cContextHandle;
   nint cNewThreadGroup;

   ccode = xNWDSCreateContextHandle(&cNewThreadGroup, &cContextHandle);

   if (0 == ccode)
   {
      jint temp = (jint) cNewThreadGroup;
      (*env)->SetIntArrayRegion(env, newThreadGroup, 0, 1, &temp);

      temp = (jint) cContextHandle;
      (*env)->SetIntArrayRegion(env, newHandle, 0, 1, &temp);
   }

   return ((jint) ccode);

} /* NWDSCreateContextHandle () */

/* *
 * NWDSDuplicateContextHandle
 *
 * Differs from  NWDSDuplicateContext in that the return code may now
 * specify codes indicative of the reason for the failure.
 */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSDuplicateContextHandle

(
   JNIEnv      *env,
   jclass      obj,
   jint        threadGroup,
   jint        srcContextHandle,
   jintArray   destContextHandle
)
{
   NWDSCCODE ccode;
   NWDSContextHandle cDestContextHandle;

   ccode = xNWDSDuplicateContextHandle (
               (nint) threadGroup,
               srcContextHandle,
               &cDestContextHandle);

   if (0 == ccode)
   {
      jint temp = (jint) cDestContextHandle;

      (*env)->SetIntArrayRegion(env, destContextHandle, 0, 1, &temp);
   }

   return ((jint) ccode);

} /* NWDSDuplicateContextHandle () */

/* *
 * NWDSFreeContext
 *
 * Frees a previously allocated Directory context .
 */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSFreeContext
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context
)
{
   jint ccode;

   ccode = xNWDSFreeContext ((nint) threadGroup, context);

   return ccode;
} /* NWDSFreeContext () */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSLogin
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jint     optionsFlag,
   jstring  objectName,
   jstring  password,
   jint     validityPeriod,
   jboolean extendedCharPasswordFlag
)
{
   NWDSCCODE ccode;
   nstr8 passwordStr[MAX_DN_BYTES + 1]; //max 257 bytes; 128 local chars + NULL
//   punicode uniPassword;
   unicode cuObjectName[MAX_DN_CHARS + 1];
   nuint32 extCharPassFlag = (nuint32)extendedCharPasswordFlag;

//   uniPassword = (punicode) (*env)->GetStringChars(env,password,0);

//   ccode = __UnicodePathToLocalStr (
//               passwordStr,
//               sizeof (passwordStr),
//               uniPassword,
//               (*env)->GetStringLength (env, password));

// (*env)->ReleaseStringChars(env,password,uniPassword);

   ccode = getPassword(env, password, passwordStr, sizeof(passwordStr), extCharPassFlag);

   if (ccode != 0)
      return ((jint) ccode);

   jstring2unicode (env, objectName, cuObjectName, sizeof (cuObjectName));

   ccode = xNWDSLogin (
               env,
               (nint) threadGroup,
               (NWDSContextHandle) context,
               (nflag32) optionsFlag,
               (char *) cuObjectName, // assuming unicode.
               passwordStr,
               validityPeriod,
               extCharPassFlag);

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NASLogin
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jstring  objectName,
   jstring  password,
   jobject  identity,
   jboolean extendedCharPasswordFlag
)
{
   NWDSCCODE ccode;
   nstr8 passwordStr[MAX_DN_BYTES + 1]; //max 257 bytes; 128 local chars + NULL
   unicode cuObjectName[MAX_DN_CHARS + 1];
   nint32 nmasID;
   unicode authenticatedFDN[MAX_DN_CHARS + 1];
   jclass cls;
   jmethodID mid;
   jstring authFDN;
   nuint32 extCharPassFlag = (nuint32)extendedCharPasswordFlag;

   ccode = getPassword(env, password, passwordStr, sizeof(passwordStr), extCharPassFlag);
   if (ccode != 0)
      return ((jint) ccode);

   jstring2unicode (env, objectName, cuObjectName, sizeof (cuObjectName));

   ccode = xNASLogin((nint)threadGroup, (NWDSContextHandle)context, cuObjectName,
      passwordStr, &nmasID, authenticatedFDN);

   if(ccode == 0)
   {
      cls = (*env)->GetObjectClass(env, identity);
      mid = (*env)->GetMethodID(env, cls, "setNMASID", "(I)V");
      (*env)->CallVoidMethod(env, identity, mid, nmasID);
      
      authFDN = (*env)->NewString(env, authenticatedFDN, unilen(authenticatedFDN));
      mid = (*env)->GetMethodID(env, cls, "setAuthenticatedFDN", "(Ljava/lang/String;)V");
      (*env)->CallVoidMethod(env, identity, mid, authFDN);
   }
   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSLoginAsService
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jint     optionsFlag,
   jstring  objectName,
   jint     validityPeriod
)
{
   NWDSCCODE ccode;
   unicode cuObjectName[MAX_DN_CHARS + 1];

   jstring2unicode (env, objectName, cuObjectName, sizeof (cuObjectName));

   ccode = xNWDSLoginAsService (
               (nint) threadGroup,
               (NWDSContextHandle) context,
               (nflag32) optionsFlag,
               (char *) cuObjectName, // assuming unicode.
               validityPeriod);

   return ((jint) ccode);
}


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSWhoami
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jobject  objectName
)
{
   NWDSCCODE ccode;
   unicode objectNameStr[MAX_DN_CHARS + 1];
   jclass cls;
   jmethodID mid;
   jstring string;

   ccode = xNWDSWhoAmI (
               (nint) threadGroup,
               (NWDSContextHandle) context,
               (char *) objectNameStr);

   if (0 == ccode && NULL != objectName)
   {
      if (NULL == objectNameStr)
      {
         __ThrowException (env, JAVAPKG "OutOfMemoryError", NULL);
         return (-1);
      }

      cls = (*env)->GetObjectClass(env, objectName);
      mid = (*env)->GetMethodID(env, cls, "append","(Ljava/lang/String;)Ljava/lang/StringBuffer;");
      if (0 == mid)
      {
         return(-1);
      }
      string = (*env)->NewString(env, objectNameStr, unilen (objectNameStr));
      (*env)->CallObjectMethod(env, objectName, mid, string);
   }
   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSChangeObjectPassword
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jint     optionsFlag,
   jstring  objectName,
   jstring  oldPassword,
   jstring  newPassword,
   jboolean extendedCharPasswordFlag
)
{
   NWDSCCODE ccode;
   nstr8 cOldPassword[MAX_DN_BYTES + 1];
   nstr8 cNewPassword[MAX_DN_BYTES + 1];
//   punicode uniOldPassword, uniNewPassword;
   unicode uObjectName[MAX_DN_CHARS + 1];
   nuint32 extCharPassFlag = (nuint32)extendedCharPasswordFlag;

   jstring2unicode (env, objectName, uObjectName, sizeof (uObjectName));

//   uniOldPassword = (punicode) (*env)->GetStringChars (env, oldPassword, 0);
//   uniNewPassword = (punicode) (*env)->GetStringChars (env, newPassword, 0);

//   ccode = __UnicodePathToLocalStr (
//               cOldPassword,
//               sizeof (cOldPassword),
//               uniOldPassword,
//               (*env)->GetStringLength (env, oldPassword));
    ccode = getPassword(env, oldPassword, cOldPassword, sizeof(cOldPassword), extCharPassFlag);
    
   if (ccode != 0)
      goto EXIT;

//   ccode = __UnicodePathToLocalStr (
//               cNewPassword,
//               sizeof (cNewPassword),
//               uniNewPassword,
//               (*env)->GetStringLength (env, newPassword));
    ccode = getPassword(env, newPassword, cNewPassword, sizeof(cNewPassword), extCharPassFlag);
    
   if (ccode != 0)
      goto EXIT;

   ccode = xNWDSChangeObjectPassword (
               env,
               (nint) threadGroup,
               (NWDSContextHandle) context,
               (nflag32) optionsFlag,
               (char *) uObjectName,
               cOldPassword,
               cNewPassword,
               extCharPassFlag);

EXIT:

//   (*env)->ReleaseStringChars (env, oldPassword, uniOldPassword);
//   (*env)->ReleaseStringChars (env, newPassword, uniNewPassword);

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSGenerateObjectKeyPair
(
   JNIEnv *env,
   jclass unused,
   jint     threadGroup,
   jint context,        /*in*/
   jstring objectName,  /*in*/ /*String*/
   jstring password,    /*in*/ /*String*/
   jint flags,          /*in*/
   jboolean extendedCharPasswordFlag /*in*/
)
{
   // NWNet variables
   NWDSCCODE ccode;
   nstr8 cPassword[MAX_DN_BYTES + 1];
//   punicode uniPassword;
   unicode uObjectName[MAX_DN_CHARS + 1];
   nuint32 extCharPassFlag = (nuint32)extendedCharPasswordFlag;

   // put the java unicode string into c unicode style.
   jstring2unicode (env, objectName, uObjectName, sizeof (uObjectName));

   // put the java unicode string into c ansi style.
//   uniPassword = (punicode) (*env)->GetStringChars (env, password, 0);

//   ccode = __UnicodePathToLocalStr (
//               cPassword,
//               sizeof (cPassword),
//               uniPassword,
//               (*env)->GetStringLength (env, password));
    ccode = getPassword(env, password, cPassword, sizeof(cPassword), extCharPassFlag);
    
   if (ccode != 0)
      goto EXIT;

   // Make C API call
   ccode = xNWDSGenerateObjectKeyPair(
               env,
               (nint) threadGroup,
               (NWDSContextHandle) context,
               (char *) uObjectName,
               cPassword,
               (nflag32) flags,
               extCharPassFlag);

EXIT:

//   (*env)->ReleaseStringChars (env, password, uniPassword);

   return ((jint) ccode);

} /* NWDSGenerateObjectKeyPair () */


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSVerifyObjectPassword
(
   JNIEnv *env,
   jclass unused,
   jint     threadGroup,
   jint context,        /*in*/
   jint flags,           /*in*/
   jstring objectName,  /*in*/ /*String*/
   jstring password,    /*in*/ /*String*/
   jboolean extendedCharPasswordFlag /*in*/
)
{
   // NWNet variables
   NWDSCCODE ccode;
   nstr8 cPassword[MAX_DN_BYTES + 1];
//   punicode uniPassword;
   unicode uObjectName[MAX_DN_CHARS + 1];
   nuint32 extCharPassFlag = (nuint32)extendedCharPasswordFlag;

   // put the java unicode string into c unicode style.
   jstring2unicode (env, objectName, uObjectName, sizeof (uObjectName));

   // put the java unicode string into c ansi style.
//   uniPassword = (punicode) (*env)->GetStringChars (env, password, 0);

//   ccode = __UnicodePathToLocalStr (
//               cPassword,
//               sizeof (cPassword),
//               uniPassword,
//               (*env)->GetStringLength (env, password));
    ccode = getPassword(env, password, cPassword, sizeof(cPassword), extCharPassFlag);
    
   if (ccode != 0)
      goto EXIT;

   // Make C API call
   ccode = xNWDSVerifyObjectPassword(
               env,
               (nint) threadGroup,
               (NWDSContextHandle) context,
               (nflag32) flags,
               (char *) uObjectName,
               cPassword,
               extCharPassFlag);

EXIT:

//   (*env)->ReleaseStringChars (env, password, uniPassword);

   return ((jint) ccode);

} /* NWDSVerifyObjectPassword () */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSGetContext

(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jint     key,
   jobject  value /*NDSContextInfo*/ /*out*/
)
{
   NWDSCCODE ccode;
   jobject object;
   jclass cls;
   jmethodID mid;

   switch (key)
   {
      case DCK_FLAGS:
      case DCK_DSI_FLAGS:
      case DCK_CONFIDENCE:
      case DCK_TRANSPORT_TYPE:
      case DCK_REFERRAL_SCOPE:
      case DCK_NAME_CACHE_DEPTH:
      {
         nuint32 cValue;

         ccode = xNWDSGetContext (
                     (nint) threadGroup,
                     (NWDSContextHandle) context,
                     (nint) key,
                     &cValue);

         if (N_SUCCESS != ccode)
         {
            return ((jint) ccode);
         }
         cls = (*env)->FindClass(env, "java/lang/Integer");
         mid = (*env)->GetMethodID(env, cls, "<init>","(I)V");
         if (0 == mid)
         {
            return(-1);
         }
         object = (*env)->NewObject(env, cls, mid, cValue);
         break;
      }

      case DCK_LAST_CONNECTION:
      {
         NWCONN_HANDLE cConnHandle;

         ccode = xNWDSGetContext (
                     (nint) threadGroup,
                     (NWDSContextHandle) context,
                     (nint) key,
                     &cConnHandle);

         if (N_SUCCESS != ccode)
         {
            return ((jint) ccode);
         }

         cls = (*env)->FindClass(env, "java/lang/Integer");
         mid = (*env)->GetMethodID(env, cls, "<init>","(I)V");
         if (0 == mid)
         {
            return(-1);
         }
         object = (*env)->NewObject(env, cls, mid, cConnHandle);
         break;
      }

      case DCK_TREE_NAME:
         /* MAX_TREE_NAME_CHARS+1 */
      case DCK_NAME_CONTEXT:
      {
         unicode buf[(MAX_DN_CHARS+1)*2];

         ccode = xNWDSGetContext (
                     (nint) threadGroup,
                     (NWDSContextHandle) context,
                     (nint) key,
                     buf);

         if (N_SUCCESS != ccode)
         {
            return ((jint) ccode);
         }
         object = (*env)->NewString(env, buf, unilen (buf));

         break;
      }

      default:
      {
         return (ERR_BAD_KEY);
      }

   } /* switch (key) */
   cls = (*env)->GetObjectClass(env, value);
   mid = (*env)->GetMethodID(env, cls, "setValue","(Ljava/lang/Object;)V");
   if (0 == mid)
   {
      return(-1);
   }
   (*env)->CallVoidMethod(env, value, mid, object);

   return ((jint) ccode);

}  /* com_novell_service_jncpv2r_clx_ClxJNINWDSGetContext */


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSSetContext

(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jint     key,
   jobject  value
)
{
   NWDSCCODE ccode;
   jclass cls;
   jmethodID mid;

   switch (key)
   {
      case DCK_FLAGS:
      case DCK_DSI_FLAGS:
      case DCK_CONFIDENCE:
      case DCK_TRANSPORT_TYPE:
      case DCK_REFERRAL_SCOPE:
      case DCK_NAME_CACHE_DEPTH:
      {
         nuint32 cValue;

         cls = (*env)->FindClass(env, "java/lang/Integer");
         mid = (*env)->GetMethodID(env, cls, "intValue","()I");
         if (0 == mid)
         {
            return(-1);
         }
         cValue = (nuint32)(*env)->CallIntMethod(env, value, mid);

         ccode = xNWDSSetContext (
                     (nint) threadGroup,
                     (NWDSContextHandle) context,
                     (nint) key,
                     &cValue);
         break;
      }

      case DCK_LAST_CONNECTION:
      {
         NWCONN_HANDLE cConnHandle;

         cls = (*env)->FindClass(env, "java/lang/Integer");
         mid = (*env)->GetMethodID(env, cls, "intValue","()I");
         if (0 == mid)
         {
            return(-1);
         }
         cConnHandle = (nuint32)(*env)->CallIntMethod(env, value, mid);

         ccode = xNWDSSetContext (
                     (nint) threadGroup,
                     (NWDSContextHandle) context,
                     (nint) key,
                     &cConnHandle);
         break;
      }

      case DCK_TREE_NAME:
         /* MAX_TREE_NAME_CHARS+1 */
      case DCK_NAME_CONTEXT:
      {
         unicode buf[MAX_DN_CHARS + 1];

         jstring2unicode (env, (jstring)value, buf, sizeof (buf));
         ccode = xNWDSSetContext (
                     (nint) threadGroup,
                     (NWDSContextHandle) context,
                     (nint) key,
                     buf);
         break;
      }

      default:
      {
         ccode = ERR_BAD_KEY;
      }

   } /* switch (key) */

   return ((jint) ccode);
}  /* com_novell_service_jncpv2r_clx_ClxJNINWDSSetContext */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSLogout
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context
)
{
   NWDSCCODE ccode;

   ccode = xNWDSLogout (
               (nint) threadGroup,
               (NWDSContextHandle) context);

   return ((jint) ccode);
} /* NWDSLogout () */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NASLogout
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jint     nmasID
)
{
   NWDSCCODE ccode;

   ccode = xNASLogout (
               (nint) threadGroup,
               (NWDSContextHandle) context,
               nmasID);

   return ((jint) ccode);
} /* NWDSLogout () */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSCanDSAuthenticate
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context
)
{
   NWDSCCODE ccode;

   ccode = xNWDSCanDSAuthenticate (
               (nint) threadGroup,
               (NWDSContextHandle) context);

   return ((jint) ccode);
} /* NWDSCanDSAuthenticate () */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSSpecialIsDSAuthenticated
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context
)
{
   NWDSCCODE ccode;

   ccode = xNWDSSpecialIsDSAuthenticated((nint) threadGroup, context);

   return ((jint) ccode);
} /* NWDSCaNSASSenticate () */

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSAuthenticateConn
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup,
   jint     context,
   jint     connHandle
)
{
   NWDSCCODE ccode;

   ccode = xNWDSAuthenticateConn (
               (nint) threadGroup,
               (NWDSContextHandle) context,
               (NWCONN_HANDLE) connHandle);

   return ((jint) ccode);
} /* NWDSAuthenticateConn () */


JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_shutDownThreadGroup
(
   JNIEnv   *env,
   jclass   obj,
   jint     threadGroup
)
{
#ifdef N_PLAT_NLM
   return shutDownThreadGroup(threadGroup);
#else
   return 0;
#endif
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSGetDSVerInfo
(
   JNIEnv   *env,
   jclass   unused,
   jint     connHandle,
   jobject  rootMostEntryDepth,      /*IntegerBuffer*/ /*out*/
   jobject  dsVersion,    /*IntegerBuffer*/ /*out*/
   jobject  flags       /*IntegerBuffer*/ /*out*/
)
{
   NWDSCCODE      ccode;
   nuint32       cDsVersion;
   nuint32       cRootMostEntryDepth;
   nuint32       cFlags;
   jclass         cls;
   jmethodID      mid;

   // Make C API call
   ccode = NWDSGetDSVerInfo(
      (NWCONN_HANDLE)  connHandle,
      &cDsVersion,
      &cRootMostEntryDepth,
      NULL,
      &cFlags,
      NULL);

   if (ccode == 0)
   {
      // Convert 'C' variable to Java variable
      // Copy cDsVersioninto Java dsVersion
      if (0 != dsVersion)
      {
         cls = (*env)->GetObjectClass(env, dsVersion);
         mid = (*env)->GetMethodID (env, cls, "setValue","(I)V");
         (*env)->CallVoidMethod(env, dsVersion, mid, (jint)cDsVersion);
      }

      // Copy cRootMostEntryDepth into Java rootMostEntryDepth
      if (0 != rootMostEntryDepth)
      {
         cls = (*env)->GetObjectClass(env, rootMostEntryDepth);
         mid = (*env)->GetMethodID (env, cls, "setValue","(I)V");
         (*env)->CallVoidMethod(env, rootMostEntryDepth, mid, (jint)cRootMostEntryDepth);
      }

      // Copy cFlags into Java flags
      if (0 != flags)
      {
         cls = (*env)->GetObjectClass(env, flags);
         mid = (*env)->GetMethodID (env, cls, "setValue","(I)V");
         (*env)->CallVoidMethod(env, flags, mid, (jint)cFlags);
      }
   }

   return ((jint) ccode);
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2r_clx_ClxJNI_NWDSGetServerDN
(
   JNIEnv   *env,
   jclass   unused,
   jint     threadGroup,   /*in*/
   jint     context,       /*in*/
   jint     connHandle,    /*in*/
   jobject  serverDN       /*StringBuffer*/ /*out*/
)
{
   // NWNet variables
   NWDSCCODE ccode;
   unicode cServerDN[MAX_DN_CHARS + 1];

#ifdef N_PLAT_NLM
   nint saveThreadGroup;
#endif

#ifdef N_PLAT_NLM
   ccode = wrapContext(&saveThreadGroup, threadGroup, context);
   if (0 != ccode)
      return ccode;
#endif

   // Make C API call
   ccode = NWDSGetServerDN(
               (NWDSContextHandle) context,
               (NWCONN_HANDLE)  connHandle,
               (char *) cServerDN);

#ifdef N_PLAT_NLM
   unwrapContext(saveThreadGroup);
#endif

   // Convert 'C' variable to Java variable
   if (0 == ccode)
   {
      // JNI variables
      jclass cls;
      jmethodID appendMid;

      // StringBuffer method
      cls = (*env)->GetObjectClass (env, serverDN);
      appendMid = (*env)->GetMethodID (
                              env,
                              cls,
                              "append",
                              "(Ljava/lang/String;)Ljava/lang/StringBuffer;");

      // Copy the cServerDN into the Java serverDN StringBuffer
      (*env)->CallObjectMethod (
                  env,
                  serverDN,
                  appendMid,
                  (*env)->NewString (env, cServerDN, unilen (cServerDN)));
   }

   return ((jint) ccode);
}

