Skip to content

Remote LAN Access Product Adapter

Chapter 12-14
Remote LAN Access Product Adapter

Introduction

Overview

This chapter describes how to write an adapter to go between Notes and a remote access product. This allows Notes users to use a remote access product other than Microsoft Remote Access Service (RAS) or AppleTalk Remote Access (ARA). Examples of other remote access products include Lan Distance, NetWare Connect, and Shiva.

The adapter, which is referred to here as an RLAN adapter, must be a DLL or shared object. It must reside in the Notes executable directory.

The use of this adapter requires a modification to the Server Connection document of type Remote LAN Service in the user's Address Book. You must add an option corresponding to the new remote access service type and provide fields to store any required parameters. To do this, you must create a new subform and add it to the user's Address Book, as described in the next section. After you add the subform, you can create a Server Connection document, select Remote LAN Service as the Connection Type, and select your remote access method as the service type.

Release 4 of Notes supported Version 0 of the Remote LAN interface. Release 5 of Notes supports Version 1 of the Remote LAN interface. This chapter documents Version 1. Additional entry points have been added since version 0 and the form of the connection document subform has been redefined. Connection documents created to version 0 of the interface should still function in this new definition.

Creating a Remote LAN Service Subform

To make a new, different, or modified remote LAN technique available to end users, you must create a new subform and add it to the users' Address Book. This subform must include the full name of the adapter and an abbreviated name that matches the adapter's filename. Follow these steps to create the subform:

1. Open the Address book and select Create - Design - Subform to open the subform design window.

2. Select Design - Subform Properties to open the Subform infobox.

3. Enter the name of the new subform. The subform name must be made up of three parts, separated by vertical bars:

      • $RLAN, followed by the driver name (without a platform prefix)
      • The descriptive string displayed to users when they open the Connection document and choose a Remote LAN Service type
      • The driver name (without platform prefix)

    For example:
      $RLANRAS | Microsoft Remote Access Service | RAS
  1. The subform must consist of ten fields, consisting of five pairs of fields. Each pair consists of a static text field and its associated user input field, as described below:
      • The first five fields must be called StaticTag, Static1, Static2, Static3, and Static4. Even if you don't use all the fields, each must be present and must contain the following type of formula:
        - the driver name (without platform prefix), followed by
        - the three characters "$%^", followed by
        - the string representing the static text you want to display for each of the input values

        If you do not have any text to display, the formula still must contain the name of the driver and the three characters. For example:

        "ARA$%^Connection document location:"
        "RAS$%^"

        The static fields should be hidden on the subform and appear above the layout region.
      • The second five fields must be called RLANTag, RLAN1, RLAN2, RLAN3, and RLAN4. These fields should be placed in a layout region that contains at least these five fields plus the same static text used in the the static fields describing the input fields (see above). There are no restrictions on the default, input translation, or validation formulas for the input fields. As with the static fields, even if you don't need five input fields, each must be on the subform. If you do not need the user to input any data into one of the input fields, it can be hidden.
  1. The subform and the driver must be installed on the machine that will use the Remote LAN Access Product. Note that for the user to fill out a connection record, only the subform is required.

  2. Check "Do not allow design refresh/replace to modify" to ensure that the subform is not deleted when Design Replace or Refresh is run on the Address Book. As an alternative, you can specify a different template to inherit from instead of the standard Address book design template.



    The following sections list the API calls designed for the RLAN adapter and show a pseudocode program of an example adapter.


    Header Files

    The RLAN adapter may require the following HCL C API header files for Domino and Notes:

include "global.h"

include "misc.h"

include "net.h"

include "neterr.h"

include "oserr.h"

include "osmisc.h"


Required Adapter Functions

The RLAN adapter must define two functions that Notes will call. The first function is an initialization routine that registers the adapter with Notes by providing the address of the second function. The second function provides a single entry point to perform all other functions of this adapter.

Under Windows, any legal function name is valid for the initialization function. Under Windows, you must declare the function in the EXPORTS section of the add-in's module definition (.DEF) file and assign it an ordinal value of 1. Notes calls this function by using the ordinal value of 1.

The second function may have any legal function name and need not be assigned an ordinal value, since Notes will use its address to call this function.

MainEntryPoint
STATUS LNCALLBACK MainEntryPoint(
WORD pVersion,
PREMOTE_LAN_SERVICE_ENTRY
rtnGeneralEntryPoint,
PREMOTE_LAN_STATUS_CALLBACK Callback)

This initializes the Notes interface. It receives and records the status callback function address and returns the address of the general entry point (the entry point that performs all other functions) to this DLL or shared object. It is called once for each process in which Remote LAN is used.


Inputs:
pVersion Pointer to a location containing the Remote LAN version supported by the calling version of Notes. Notes release 4.5 and 4.6 support Remote LAN Version 0. Notes Release 5 support Version 1.

Callback Address of a routine in Notes to call from the adapter to report ongoing status (see StatusDisplayCallback below).

Outputs:
pVersion Address in which to return the Remote LAN version supported by this adapter. Notes will adapt its expectations to this version. It must be equal to or less than the value supplied by Notes.

*rtnGeneralEntryPoint Address in which to return the general entry point for all other calls to this DLL or shared object.


(routine) A Notes error code. Return NOERROR if no error has occurred.


GeneralEntryPoint
STATUS LNCALLBACK GeneralEntryPoint(
VARARG_PTR ap)

This is the single entry point to perform all functions of this interface. The first five parameters are standard. They are the same for all types of calls (as determined by the Type parameter; see below). After the standard parameters, there may be additional parameters specific to the particular action being performed. The interpretation of the additional parameters is a function of the remote LAN service.

Inputs:
These standard parameters must appear in the order shown below.

WORD Type Type of action to perform:

              REMOTE_LAN_SERVICE_CONNECT dials the connection (or skips dialing if already connected).

              REMOTE_LAN_SERVICE_DISCONNECT hangs up the connection (or skips hanging up if the connection is already terminated).

              REMOTE_LAN_SERVICE_CHECK_CONNECTED checks whether a connection already exists. If currently connected, returns (STATUS) 1. If not connected, returns (STATUS) 0. (The native error code and message text are ignored.)

              REMOTE_LAN_SERVICE_GET_EXISTING_LINKS returns (if possible) a list of existing connections to this RLAN program. The list is a single string with entries separated by tab characters. Before creating this string, the adapter program must convert the names from the native character set to Domino multibyte character set. The list is copied into the error buffer supplied by Notes RLAN when this call is made. Many dialers can't provide this information. In this case (if connected to anything), return one string entry with the value, "(Unknown)".
              REMOTE_LAN_SERVICE_TERMINATE performs any needed one-time termination functions. This is called once for each process that called the INIT entry point.

              REMOTE_LAN_SERVICE_GET_DIAL_ENTRY_INFO returns the phone number, area code and country code from the native dial entry information. This is not supported by Version 0 of the Remote LAN interface. It is supported by Version 1 of the Remote LAN interface.

              REMOTE_LAN_SERVICE_CREATE_DIAL_ENTRY_DIALOG causes the native dialer to bring up a dialog which allows the user to create a dial information entry. This is not supported by Version 0 of the Remote LAN interface. It is supported by Version 1 of the Remote LAN interface.

              REMOTE_LAN_SERVICE_GET_DIAL_ENTRY_LIST returns a tab-separated list of native dial entries. This is not supported by Version 0 of the Remote LAN interface. It is supported by Version 1 of the Remote LAN interface.


DWORD pNativeError Place to store native error code.

DWORD
pConnectionHandle
Address of native handle of the connection (to put to or get from, depending on the type).

char *pErrorBuffer Place to store error messages for display and logging by Notes. Note that if type is REMOTE_LAN_SERVICE_TERMINATE, this address will be NULL.

WORD ErrorBufferSize Size of error buffer supplied.

Additional arguments
for REMOTE_LAN_SERVICE_CONNECT:

    char *pEntryName Name of native dial information entry.
    char *pLoginName Name to use to login to the remote network.
    char *pPassword Password to use to login to the remote network.
    char *pPhoneNo Phone number to dial.
    char *pDialbackNo Phone number for the remote access server to call back to to complete the connection.


for REMOTE_LAN_SERVICE_DISCONNECT:

    char *pEntryName Name of native dial information entry.


for REMOTE_LAN_SERVICE_CHECK_CONNECTED:

    char *pEntryName Name of native dial information entry.


for REMOTE_LAN_SERVICE_GET_EXISTING_LINKS

    None.


for REMOTE_LAN_SERVICE_TERMINATE

    None.


for REMOTE_LAN_SERVICE_GET_DIAL_ENTRY_INFO

    char *pPhoneNo For return of the phone number in the dial entry.
    char *pAreaCode For return of the area code in the dial entry.
    char *pCountryCode For return of the country code in the dial entry.
    WORD Size of each of the previous three buffers.


for REMOTE_LAN_SERVICE_CREATE_DIAL_ENTRY_DIALOG

    None.

for REMOTE_LAN_SERVICE_GET_DIAL_ENTRY_LIST

    char *pReturnBuffer For return of tab-separated list of dial entry names, terminated by zero.
    WORD BufSize Size of storage allocated in the return buffer
    WORD *BufCount Number of characters returned, including the Null terminator.


Note that all strings passed to the adapter and returned from the adapter are stored in multibyte character (LMBCS) format. To convert these to and from a format acceptable to the operating system, the program must use the OSTranslate function.

Outputs:
pConnectionHandle Address for returning the native handle of the connection after a successful connect (used for call of type REMOTE_LAN_SERVICE_CONNECT).

pErrorBuffer Return error string in buffer at this address.

(routine) Notes error code. The following error codes have special meaning for dial-up connections:

              NOERROR
              ERR_DEVICE_IN_USE
              ERR_CANCEL (that is, the user has aborted)
              ERR_REMOTE_BUSY
              ERR_NO_ANSWER
              ERR_NO_CARRIER
              ERR_NO_DIALTONE

              For all other error conditions, use:
              ERR_REMOTE_LAN_ERROR



Using the Notes Callback to Display Connection Process Status

For connections that can proceed asynchronously, Notes provides a callback function for use in reporting ongoing status and to detect a user abort from within Notes. This callback capability is not required, but may be useful for asynchronous connections. This function's address is provided in the call to the RLAN adapter's initialization function. Below is an outline of the function:

BOOL LNCALLBACK StatusDisplayCallback(
WORD Action,
STATUS StatusCode,
char *pErrText)

The RLAN adapter calls this function when it wants Notes to display status or error information. It also checks for a user abort condition. The adapter can call this function on a thread that is different from the one on which Notes called the adapter. In this case, Notes must be told about the new thread. Therefore, before any status messages can be displayed, the adapter must call this function with the Action REMOTE_LAN_INIT_THREAD. Once the connection has been made (or has failed), it must be called with the Action REMOTE_LAN_TERM_THREAD. The initialize and terminate calls may be made any number of times for a thread, but the number of termination calls must match the number of initialization calls before the thread is terminated.

Inputs:
Action The type of operation needed. Possible values are:

              REMOTE_LAN_INIT_THREAD
              Make sure this thread is known to Notes.

              REMOTE_LAN_TERM_THREAD
              Decrement the Notes use count on this thread.

              REMOTE_LAN_DISPLAY_STATUS
              Map a remote LAN status code to a Notes status message and display it.

              REMOTE_LAN_CHECK_ABORT
              Check user abort condition.

              REMOTE_LAN_DISPLAY_ERR0R_TEXT
              Display an error message in the language provided by the remote LAN service.


StatusCode A Remote LAN status code, if type is REMOTE_LAN_DISPLAY_STATUS (see below)

pErrText The error string, if type is REMOTE_LAN_DISPLAY_ERROR_TEXT.

Outputs:
(routine) The return argument is of type BOOL. This is used to return an abort condition if one has occurred. It should be TRUE (1) if operation should continue, and FALSE (0) if the user has asked for an abort (e.g. ctl+break for a PC).

Status codes:
Status codes that are handled are defined in net.h. They are:

REMOTE_LAN_STATUS_STARTING_CONNECTION
REMOTE_LAN_STATUS_PHYSICALLY_CONNECTED
REMOTE_LAN_STATUS_AUTHENTICATING
REMOTE_LAN_STATUS_AUTHENTICATED
REMOTE_LAN_STATUS_WAITING_FOR_CALLBACK
REMOTE_LAN_STATUS_LINK_ESTABLISHED
REMOTE_LAN_STATUS_LINK_FAILED
REMOTE_LAN_STATUS_HANGING_UP
REMOTE_LAN_STATUS_HANGUP_COMPLETE


Sketch of a Remote LAN Adapter

/ Notes interface to an external remote access capability  /

/ This module interfaces the Notes Remote LAN capability to an external remote
  access capability. The DLL is explicitly loaded by Notes and once loaded by
  a Notes process, the initialization function (MainEntryPoint) is called.
  Thereafter, calls to this module are made to the standard entry point
  (GeneralEntryPoint).  Upon termination, the last process calls
  the standard entry point to allow any needed termination activity, and the
  library is unloaded by Notes.


   This file is pseudo-code and is intended to explain how the Remote LAN
  interface works.  It is laid out with this purpose in mind. Some
  declarations have been abbreviated or left out. It will not compile or
  execute.
/


/ Needed C API header files /

#include "global.h"

include "misc.h"

include "net.h"

include "neterr.h"

include "oserr.h"

include "osmisc.h"


#define ThisInterfaceVersion 1    / (This has been increased by 1 from Notes R4)

/

MainEntryPoint


   This initializes the Notes interface.  It records the status
  callback function address, and returns the address of the standard entry
  point to this DLL. It is called once for each process that Remote LAN is
  used in.


 Inputs:
  pVersion         Version number currently provided by Notes.
  Callback          Address of a routine to call to report ongoing
                    status.


 Outputs:

   
rtnGeneralEntryPoint   The entry point for normal calls to this DLL.
  (routine)               Notes error code
/



STATUS LNCALLBACK MainEntryPoint(
  WORD
pVersion,
  PREMOTE_LAN_SERVICE_ENTRY rtnGeneralEntryPoint,
  PREMOTE_LAN_STATUS_CALLBACK Callback)
{
  STATUS error = NOERROR;


   /
Negotiate the version number (example) /
  VersioninUse = MIN(
pVersion, ThisInterfaceVersion);
  pVersion = VersioninUse;


   /
   If you return zero for the version, Notes will make calls and expect
        return values appropriate to Notes R4. /



   
rtnGeneralEntryPoint = (PREMOTE_LAN_SERVICE_ENTRY) GeneralEntryPoint;
  StatusCallback = Callback;


   / Load required modules as necessary. /

   / Perform one-time initializations. /

   / Set error = ERR_REMOTE_LAN_NOT_INSTALLED if unable to initialize. /

   return error;
}


/
GeneralEntryPoint


   This is the single entry point to perform all the functions of this
  interface.  It is called with a standard first 5 parameters, which
  are the same for  all types of call (as determined by the Type parameter)
  After the standard parameters there may be additional ones specific to the
  particular action being performed.


 Inputs (standard parameters):

   1st arg: Type              The type of action to perform
  2nd arg: pNativeError      Place to store Native error code
  3rd arg: pConnectionHandle Address of handle (to put to or get from)
  4th arg: pErrorBuffer      Place to store error messages for logging.
  5th arg: ErrorBufferSize   Size of argument buffer
  Additional arguments depending on the function


 Outputs:

 
pConnectionHandle   The handle after a successful connect.
  pErrorBuffer        Error string for logging


   (routine)         STATUS  error code
/

STATUS LNCALLBACK GeneralEntryPoint(VARARG_PTR ap)
{
  STATUS   error = NOERROR;
  WORD  Type;
  DWORD    pNativeError;
  DWORD    
pConnectionHandle;
  char  pErrorBuffer;
  WORD  ErrorBufferSize;
  TCHAR    CallDescription[MAX_REMOTE_LAN_PARAM_STRING];
  char  
pLMBCSCallDescription; / Name of place where call information is kept /
 
  / Get the common arguments /
 
  Type = VARARG_GET(ap,  WORD);
  pNativeError = VARARG_GET(ap, DWORD );
  pConnectionHandle = VARARG_GET(ap, DWORD
);
  pErrorBuffer = VARARG_GET(ap, char );
  ErrorBufferSize = VARARG_GET(ap, WORD);
 
pNativeError = 0;


   switch (Type)
  {


      case REMOTE_LAN_SERVICE_CONNECT:
     
        /    
           6th Arg: The Call descriptor name, where the call info is kept.
           7th Arg: Remote Network login ID (optional)
           8th Arg: Remote Network password (optional)
           9th Arg: Phone number (optional)
          10th Arg: Dial-back number (optional)   - new for Version 1 (R5)
          Two more optional arguments are possible which can be carried
          from the connection record designed for the specific remote
          access method.
       
/


         pLMBCSCallDescription = VARARG_GET(ap, char );  / Get the call desciptor name /
           


         /
 Convert the call descriptor name from Domino multibyte
           characters to multibyte characters expected by the OS.
        /


         OSTranslate(OS_TRANSLATE_LMBCS_TO_NATIVE, pLMBCSCallDescription,
           MAXWORD, CallDescription, sizeof (CallDescription));
           
        /
Convert any other optional arguments as well. /

         /
Dial the connection here.  Skip this if it already is connected.
           If there is an error, store the native error code in pNativeError,
           the text of the error message if available in pErrorBuffer,
           and return a Notes status code.
           
/


         break;



      case REMOTE_LAN_SERVICE_DISCONNECT:
       
        / 6th Arg: The Call descriptor name, where the call info is kept. /


         pLMBCSCallDescription = VARARG_GET(ap, char );  / Name of call desciptor /

         /
Convert the call descriptor name from Domino multibyte
           characters to multibyte characters expected by the OS.
        /


         OSTranslate(OS_TRANSLATE_LMBCS_TO_NATIVE, pLMBCSCallDescription,
           MAXWORD, CallDescription, sizeof (CallDescription));


         /
Hang up the connection here.  Skip this if it no longer
           connected.  If there is an error, store the native error code in
           pNativeError, the text of the error message if available in
           pErrorBuffer, and return a Notes status code.
       
/


         break;
       


      case REMOTE_LAN_SERVICE_CHECK_CONNECTED:
        / Return argument logic changed for Version 1 (R5) /
       
        / 6th Arg: The Call descriptor name, where the call info is kept. /


         pLMBCSCallDescription = VARARG_GET(ap, char );  / Name of call desciptor /

         /
Convert the call descriptor name from Domino multibyte
           characters to multibyte characters expected by the OS.
        /


         OSTranslate(OS_TRANSLATE_LMBCS_TO_NATIVE, pLMBCSCallDescription,
           MAXWORD, CallDescription, sizeof (CallDescription));


         /
Check if connection exists.  If you can get a list of existing
           connections, see if this connection is in the list. You will
           have to use a comparison function that works with the multibyte
           character set.  Return the result as the (coerced) status code.
           
           If you can't obtain a list of existing connections, keep the
           list of connections you know about locally and use it.
           
           If currently connected, set pNativeError = 1
           If not connected,    set
pNativeError = 0
           
           The function should return NOERROR.


         /
       
        break;


         
     case REMOTE_LAN_SERVICE_GET_EXISTING_LINKS:


         /
No additional args /

         /
If you can get a list of existing connections, return this list
           in a single string with entries separated by tab characters.
           Before creating this string, convert the names from the native
           character set to Domino multibyte character set.
        */


         BOOL  bOnline = FALSE;

      char  *p;

      *pErrorBuffer = '\0';

          /* Here find out from the dialer if any connection exists and set
             bOnline = TRUE if so */
          if (bOnline)
          {
             p = "(Unknown)";
             /* substitute favorite string copy routine here. */
             Cstrncpy(pErrorBuffer, p, ErrorBufferSize - 1);  
           }

          break;


           
     case REMOTE_LAN_SERVICE_GET_DIAL_ENTRY_LIST:
        / New in Version 1 (R5) /
       
        pReturnBuffer = VARARG_GET(ap, char );
        MaxBufferSize = VARARG_GET(ap, WORD);
        pReturnCount = VARARG_GET(ap, WORD
);
       
        / If available, return a list of phonebook entry names, tab
           delimited, null terminated. Else return an empty buffer.
/
       
        break;


      case REMOTE_LAN_SERVICE_CREATE_DIAL_ENTRY_DIALOG:
        / New in Version 1 (R5) /


         / Bring up the native remote access interface for creating
           dialup connection information. There is no return information
           needed, except an error code if it fails.
/


         break;


      case REMOTE_LAN_SERVICE_GET_DIAL_ENTRY_INFO:
        / New in Version 1 (R5) /


         char retLMBCSPhone, retLMBCSAreaCode, retLMBCSCountry;

         /
Get Address book entry name /
        pLMBCSPhonebookEntry = VARARG_GET(ap, char
);
        OSTranslate(OS_TRANSLATE_LMBCS_TO_NATIVE, pLMBCSPhonebookEntry,
           MAXWORD, PhonebookEntry, sizeof (PhonebookEntry));


         retLMBCSPhone = VARARG_GET(ap, char );

         retLMBCSAreaCode = VARARG_GET(ap, char
);

         retLMBCSCountry = VARARG_GET(ap, char );

         MaxBufferSize = VARARG_GET(ap, WORD);


         /
Call the native remote access capability to get the phone number
           information stored in it. Return these values.  /


         break;


      case REMOTE_LAN_SERVICE_TERMINATE:
       
        /
Perform any need one-time termination functions. /
       
        break;


      default:

         break;
  }


   return error;
}



/

GetExistingConnections


   This returns a list of Remote LAN connections that are currently
  connected.  


 Inputs:

   pBuf     Buffer to put conection list in. The list is tab separated and
           zero terminated.
  Bufsize  Size of return buffer allocated.


 Outputs:

   None
/


void GetExistingConnections(char
pBuf, WORD BufSize)
{
  unsigned i;
  char  NativeConnections[MAXCONNECTIONS];
  DWORD    nConn;
  char  
p;
 
  BufSize--;     / leave room for a final terminator /
 
  GetArrayOfNativeConnections(NativeConnections, ...);
   
  for (i = 0, p = pBuf; i < nConn && (pBuf + BufSize - p) > 1; i++)
  {
     / Delimit entries with a tab char  /
     if (i != 0)
        p++ = '\t';  / add a tab, overwriting the previous '\0' /
       
     /
Translate to LMBCS - it returns the number of bytes not incl. '\0'/
     p += OSTranslate(OS_TRANSLATE_NATIVE_TO_LMBCS, NativeConnections[i],
           MAXWORD, p, (WORD)(pBuf + BufSize - p));
  }
 
p = '\0';   / terminate the string /
}



/
AsyncConnect


   This calls the remote LAN to set up a connection, and waits for the
  connection to be completed.  


/

static DWORD AsyncConnect(arguments...)
{


   Err = DialAsync (DialCallback, &hCallHandle, ...);
  if (Err)
     return Err;


   / Wait until the connection is completed /
 
  for ( ; ; )
  {
     Sleep (500);   / 500 msec /


      Err = GetConnectStatus(hCallHandle, &Status);
     if (Err)
        break;


      / Break if connection succeded /
     
     if (Status == Connected)
        break;


      / Check for user abort /
     
     if ((StatusCallback)(REMOTE_LAN_CHECK_ABORT, NULL, NULL) != NOERROR)
     {
        /
Hang up connection /
        break;
     }
  }


}


/

DialCallback


   This is a callback function, called by the remote access service to show
  ongoing status of a connection.  


/


DialCallback (ConnState, Error, ...)
{
  STATUS   status = NOERROR;
  char  ErrorString [MAXSPRINTF];



   /
Map remote access status codes to Notes Remote LAN status codes. /
 
  switch(ConnState)
  {
     case Starting:
        status = REMOTE_LAN_STATUS_STARTING_CONNECTION;
        break;
     case Connected:
        status = REMOTE_LAN_STATUS_PHYSICALLY_CONNECTED;
        break;
     case Authenticating:
        status = REMOTE_LAN_STATUS_AUTHENTICATING;
        break;
     case Authenticated:
        status = REMOTE_LAN_STATUS_AUTHENTICATED;
        break;
     case WaitingForCallback:
        status = REMOTE_LAN_STATUS_WAITING_FOR_CALLGBACK;
        break;
     case Connected:
        status = REMOTE_LAN_STATUS_LINK_ESTABLISHED;
        break;
     case Disconnected:
        status = REMOTE_LAN_STATUS_LINK_FAILED;
        break;
  }




   if (!Error)
  {


      /
Display status message in Notes /

      if (status)
     {
        /
If a new thread has just been created by the remote access program
           for this status message, We must make the thread known to Notes /
         (
StatusCallback) (REMOTE_LAN_INIT_THREAD, NULL, NULL);


         / Send status to callback in notes /
        (StatusCallback) (REMOTE_LAN_DISPLAY_STATUS, status, NULL);


         /
In case this is the last time the status callback will be called,
           we must tell Notes the thread is going away /
        (
StatusCallback) (REMOTE_LAN_TERM_THREAD, NULL, NULL);
     }
  }
     


   else
  {
 
     / Display error message in Notes /
     
     / Tell Notes about the thread. /
     (StatusCallback) (REMOTE_LAN_INIT_THREAD, NULL, NULL);
     
     /
 Convert Error code to string and have Notes display it. /
     GetErrorString(Error, ErrorString);
     (
StatusCallback) (REMOTE_LAN_DISPLAY_ERR0R_TEXT, NULL, ErrorString);
           
     / Now tell Notes to forget it. /
     (StatusCallback) (REMOTE_LAN_TERM_THREAD, NULL, NULL);
  }  


}

/

MapError


   This maps a native remote access error code to a Notes error code.

 Inputs:

   Error       The remote access error code


 Outputs:

   (routine)      The Notes error code
/



STATUS MapError (DWORD Error)
{
  STATUS error;  /
Notes error code */

   switch(Error)
  {
     case 0:
        error = NOERROR;
        break;
     
     case ERROR_PORT_ALREADY_OPEN:
        error = ERR_DEVICE_IN_USE;
        break;
     
     case ERROR_USER_DISCONNECTION:
        error = ERR_CANCEL;
        break;
       
     case ERROR_LINE_BUSY:
        error = ERR_REMOTE_BUSY;
        break;
       
     case ERROR_NO_ANSWER:
        error = ERR_NO_ANSWER;
        break;
       
     case ERROR_NO_CARRIER:
        error = ERR_NO_CARRIER;
        break;
       
     case ERROR_NO_DIALTONE:
        error = ERR_NO_DIALTONE;
        break;
       
     default:
        error = ERR_REMOTE_LAN_ERROR;
        break;
  }
  return error;
}