/* sockc - A command line for any command string connection oriented
   socket server or QNX message passing server. Rick Smereka,
   Copyright (C) 2000-2006.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, get a copy via the Internet at
   http://gnu.org/copyleft/gpl.html or write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   MA 02111-1307 USA

   You can contact the author via email at rsmereka@future-lab.com

   Original Windows 32bit version Feb/2000, Rick Smereka

   Re-compiled after re-structuring the definition of the common
   send and repy codes. Apr/2000, Rick Smereka

   Changed function 'main' to return an 'init'. Changed function
   'main' to use 'scanf' instead of 'gets' to acquire command
   from user. Fixed bug in functions 'd_socloc_list' and
   'd_socloc_config_list' that 'free'ed allocated memory too
   soon. Added two command line switches. Program syntax now is:

      sockc [-s] [-l log_file]

   Where '-s' will not connect to or use 'socloc' and '-l'
   will specify a client log file name. Added the commands
   'SOCLOC.ON' and 'SOCLOC.OFF' to turn the 'socloc' interface
   on or off while the program is running. Changed the method
   of obtaining the command line from 'scanf' back to 'gets' after
   I realized that 'scanf' will stop parsing when it detects a
   space. May/2000, Rick Smereka

   Re-compiled after adding the new 'clib' module 'ip.c'.
   Jul/2000, Rick Smereka

   Corrected some minor messages and documentation. Jul/2001,
   Rick Smereka

   Modified for use by both socket and QNX message passing servers.
   Ported to QNX V4.23a. Since the 'socloc' interface does not exist 
   with QNX message passing server, the '-s' switch does not exist 
   for this variant. QNX message passing syntax is:

      sockc [-l log_file]

   Oct/2001, Rick Smereka

   Ported to Debian Linux. Jan/2003, Rick Smereka

   Modified for the updated 'socloc' API ('sloc.c') and generic client 
   IPC API ('ipclient.c'). Added support for the commands 'socloc.trans.num',
   'socloc.connect.num', 'trans.num' and 'connect.num'. May/2003,
   Rick Smereka

   Added function 'term_api' which performs an orderly shutdown of
   any sockets in use (TCP) and terminates all API's in use.
   Jun/2003, Rick Smereka

   Code cleanup and changed all logging calls to use the
   'logman' API. Dec/2004, Rick Smereka

   Re-compile after changing the 'socloc' API.
   Jan/2005, Rick Smereka

   Re-compile after modifications to low level TCP socket communication
   module (ipcomm.c). Feb/2006, Rick Smereka */

#include "stdhead.h"
#include "flsocket.h"
#include "ipclient.h"                 /* IPC high level routines */
#ifdef IPC_TCP
#include "ip.h"
#include "ipcomm.h"                   /* TCP low level routines */
#include "socloc.h"                   /* socket locate defines */
#include "sloc.h"                     /* 'socloc' client API */
#include "sconnect.h"                 /* parse connect string */
#endif

#define VERSION "1.14.01-2006.02.23"  /* version ID */
#define APNAME "sockc"

/* default log file definition */

#define SOCKC_LOG_FILE "sockc.log"

/* client/server return/reply codes */

#define SC_OK SOCKET_RC_OK
#define SC_VC_ERROR SOCKET_RC_VC_ERROR
#define SC_NO_SERVER 1
#define SC_MEMORY_FAIL 2

/* send messages */

#define SC_SEND_TERM SOCKET_SEND_TERM
#define SC_SEND_STATUS SOCKET_SEND_STATUS
#define SC_SEND_LOG_OFF SOCKET_SEND_LOG_OFF
#define SC_SEND_LOG_ON SOCKET_SEND_LOG_ON
#define SC_SEND_LOG_STATUS SOCKET_SEND_LOG_STATUS
#define SC_SEND_SERVICE_NAME SOCKET_SEND_SERVICE_NAME
#define SC_SEND_VERSION SOCKET_SEND_VERSION
#define SC_SEND_TRANS_NUM SOCKET_SEND_TRANS_NUM
#define SC_SEND_CONNECT_NUM SOCKET_SEND_CONNECT_NUM

/* command line codes */

#define SCOM_TERM 1
#define SCOM_STATUS 2
#define SCOM_CLIENT_LOG_OFF 3
#define SCOM_CLIENT_LOG_ON 4
#define SCOM_CLIENT_LOG_STATUS 5
#define SCOM_SERVER_LOG_OFF 6
#define SCOM_SERVER_LOG_ON 7
#define SCOM_SERVER_LOG_STATUS 8
#define SCOM_CONNECT 9
#define SCOM_SOCLOC_LIST 10
#define SCOM_SOCLOC_CONFIG_LIST 11
#define SCOM_SOCLOC_GET 12
#define SCOM_SOCLOC_LOG_ON 13
#define SCOM_SOCLOC_LOG_OFF 14
#define SCOM_SOCLOC_LOG_STATUS 15
#define SCOM_SOCLOC_CONNECT 16
#define SCOM_SOCLOC_FIND 17
#define SCOM_SOCLOC_SERVICE_NAME 18
#define SCOM_SERVICE_NAME 19
#define SCOM_SOCLOC_VERSION 20
#define SCOM_VERSION 21
#define SCOM_SOCLOC_CONFIG_FIND 22
#define SCOM_SOCLOC_STATUS 23
#define SCOM_SOCLOC_CLIENT_LIST 24
#define SCOM_SOCLOC_CLIENT_UPDATE 25
#define SCOM_SOCLOC_CLIENT_UPDATE_FILE 26
#define SCOM_SEND 27
#define SCOM_SOCLOC_ADD 28
#define SCOM_SOCLOC_CONFIG_ADD 29
#define SCOM_SOCLOC_DELETE 30
#define SCOM_SOCLOC_CONFIG_DELETE 31
#define SCOM_SOCLOC_DUMP 32
#define SCOM_SOCLOC_CONFIG_DUMP 33
#define SCOM_SOCLOC_TERM 34
#define SCOM_CLIENT_VERSION 35
#define SCOM_SOCLOC_ON 36
#define SCOM_SOCLOC_OFF 37
#define SCOM_SOCLOC_TRANS_NUM 38
#define SCOM_SOCLOC_CONNECT_NUM 39
#define SCOM_TRANS_NUM 40
#define SCOM_CONNECT_NUM 41
#define SCOM_NOT_FOUND -1
#define SCOM_OFF -2
#define SCOM_MAXCOM 41

/* maximum size of socket send/receive buffer */

#define SC_MAXCOMMAND 32767

/* global data */

#ifdef IPC_TCP
#ifdef OS_WIN32
WSADATA wsaData;
#endif

int serverport = 0;                  /* socket server TCP port */
char serverservice[128];             /* socket server service name */
int sk_port = 0;                     /* 'socloc' server TCP port */
char sk_host[128];                   /* 'socloc' server host name */
int sk_flag = TRUE;                  /* 'socloc' on/off flag */
#else
int sk_flag = FALSE;
#endif

char serverhost[128];                /* server host name */
char d_log_file[128];                /* name of client log */

int main(int, char **);
int parse_comline(int, char **);
int d_initialize(void);
int d_socloc_activate(void);
void d_term(char *);
void d_socloc_term(char *);
void d_status(void);
void d_client_log_on(char *);
void d_client_log_off(void);
void d_client_log_status(void);
void d_server_log_on(char *);
void d_server_log_off(void);
void d_server_log_status(void);
void d_socloc_log_on(char *);
void d_socloc_log_off(void);
void d_socloc_log_status(void);
void d_connect(char *);
void d_socloc_connect(char *);
void d_socloc_list(void);
void d_socloc_config_list(void);
void d_socloc_get(void);
void d_socloc_find(char *);
void d_socloc_service_name(void);
void d_service_name(void);
void d_socloc_version(void);
void d_version(void);
void d_client_version(void);
void d_socloc_config_find(char *);
void d_socloc_status(void);
void d_socloc_client_update(void);
void d_socloc_client_update_file(void);
void d_send(char *);
void d_socloc_add(char *);
void d_socloc_config_add(char *);
void d_socloc_delete(char *);
void d_socloc_config_delete(char *);
void d_socloc_on(void);
void d_socloc_off(void);
void d_socloc_dump(void);
void d_socloc_config_dump(void);
void d_socloc_trans_num(void);
void d_socloc_connect_num(void);
void d_trans_num(void);
void d_connect_num(void);
int get_token(char *);
void d_display_connect_status(void);
void d_header(char *);
void d_out(char *,...);
int is_connected(void);
void term_app(void);

#ifdef IPC_TCP
int d_sr(int, char *, char *);
void d_display_list(char *);
void d_display_config_list(char *);
#else
int d_sr(int, char *, char *, int);
#endif

int main(int argc, char **argv)
{
   char *comm;
   int done = FALSE;

   /* set default log file name */

   strcpy(d_log_file, SOCKC_LOG_FILE);

   /* parse any command line parameters */

   if (argc > 1)
      if (!parse_comline(argc, argv))
         return(0);
         
   /* allocate command line buffer */

   if ((comm = malloc(BUFSIZE + 1)) == NULL)
      {
      printf("%s:insufficient memory to run program\n", APNAME);
      return(0);
      }

   /* build logo string based on platform */

#ifndef OS_UNIX
   /* non-Unix */

   printf("%s for %s Version %s\n", APNAME, PLATFORM_STRING, VERSION);
#else
   /* Unix */

   printf("%s for %s Version %s\n", APNAME, SUB_PLATFORM_STRING, VERSION);
#endif

   printf("By Rick Smereka, Copyright (c) 2000-2006\n");

   /* initialize */

   if (!d_initialize())
      {
      free(comm);
      term_app();
      return(0);
      }

   printf("%s comes with ABSOLUTELY NO WARRANTY\n", APNAME);
   printf("This is free software, and you are welcome to redistribute it\n");
   printf("under certain conditions; see 'gpl.txt' for information.\n");
   (void)flag_2_logic_string(sk_flag, comm);
#ifdef IPC_TCP
   printf("%s:socloc interface is %s\n", APNAME, comm);
#endif

   /* interpret loop */

   while(!done)
      {      
      d_display_connect_status();
      printf(">");
      get_rec(stdin, comm);

      if (!do_comm(comm))
         done = TRUE;
      }

   free(comm);
   term_app();
   printf("exit %s\n", APNAME);
   return(0);
}

int parse_comline(int c_count, char **c_parm)
{
   /* Parse the command line for parameters. Function
      returns 'TRUE' if no error was detected, 'FALSE'
      otherwise. */

   char mname[] = "sockc:parse_comline";      
   int parms = 1, done = FALSE;
         
   while(!done)
      {
      if (c_parm[parms][0] == SWITCH_CHAR)
         {
         switch(toupper(c_parm[parms][1]))
            {
            case 'L':                        
               if (strlen(c_parm[parms]) > 2)
                  printf("%s:extraneous input with log file switch, "
                         "ignoring\n", mname);
                         
               parms++;
            
               if (parms >= c_count)
                  {
                  printf("%s:log file switch with no file name, "
                         "program abort\n", mname);
                  return(FALSE);
                  }
               
               strcpy(d_log_file, c_parm[parms]);
               parms++;
               break;

#ifdef IPC_TCP
            case 'S':
               sk_flag = FALSE;
               parms++;
               break;
#endif
               
            default:
               printf("%s:unknown switch[%s], program abort\n",
                      mname, c_parm[parms]);
               return(FALSE);
            };
         }
      else
         {
         printf("%s:unknown parameter[%s], program abort\n",         
                mname, c_parm[parms]);
         return(FALSE);
         }
         
      if (parms >= c_count)
         done = TRUE;
      }

   return(TRUE);
}

int d_initialize(void)
{
   /* Initialize communication, form connection to
      'socloc' server and update the config list if
      'socloc' is turned on (TCP only). Function returns 'TRUE'
      upon success, 'FALSE' otherwise. */

   char mname[] = "d_initialize";
   char *thelist, mes[128];
   int ret;

   logman("%s:enter", mname);

   /* startup WinSock (if Windoze) */

#ifdef OS_WIN32
   if (WSAStartup(WINSOCK_VERSION, &wsaData))
      {
      d_out("%s:unable to start WinSock. "
            "Program abort", mname);
      return(FALSE);
      }
#endif

#ifdef IPC_TCP
   if (sk_flag)
      if (!d_socloc_activate())
         {
         d_out("%s:socloc failure, program abort", mname);
         return(FALSE);
         }
#endif
                  
   serverhost[0] = EOS;

#ifdef IPC_TCP
   serverservice[0] = EOS;
   serverport = 0;
#endif
   logman("%s:exit[TRUE]", mname);
   return(TRUE);
}

int d_socloc_activate(void)
{
   /* Initialize the 'socloc' interface and connect to a
      'socloc' server. Function returns 'TRUE' upon
      success, 'FALSE' otherwise. If the function fails,
      the global 'socloc' flag will be forced down. */

   char mname[] = "d_socloc_activate";
   char *thelist, mes[128];
   int ret;
   
#ifdef IPC_QNX
   d_out("%s:applies only to TCP IPC method", mname);
   return(FALSE);
#else
   /* attempt to connect to a 'socloc' server */

   if ((ret = sloc_initialize()) != SL_OK)
      {
      sl_code_string(ret, mes);
      d_out("%s:bad rc[%s] from 'sloc_initialize'", mname, mes);
      sk_flag = FALSE;
      return(FALSE);
      }

   /* get config list from 'socloc' server and update
      the client list with it */
      
   if ((thelist = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[thelist]", mname);
      sk_flag = FALSE;
      sloc_term_api();
      return(FALSE);
      }

   if ((ret = sloc_config_get_list(thelist)) != SL_OK)
      {
      free(thelist);
      sl_code_string(ret, mes);
      d_out("%s:bad rc[%s] from 'sloc_config_get_list'", mname, mes);
      sk_flag = FALSE;
      sloc_term_api();
      return(FALSE);
      }
      
   if ((ret = sl_config_put_list(thelist)) != SL_OK)
      {
      sl_code_string(ret, mes);
      d_out("%s:bad rc[%s] from 'sl_config_put_list'",
                    mname, mes);
      free(thelist);
      sk_flag = FALSE;
      sloc_term_api();
      return(FALSE);
      }
    
   free(thelist);
   sk_flag = TRUE;
   return(TRUE);
#endif
}
   
int do_comm(char *comm)
{
   /* Dispatch a 'sockc' command. */

   char mname[] = "do_comm";
   char *keywrd;                 /* command keyword */
   int token;                    /* keyword token */
   int nwords;                   /* number of words */
   int len;                      /* length of command */

   logman("%s:enter", mname);
   len = strlen(comm);

   if (!len)
      {
      d_out("empty command");
      return(TRUE);
      }

   if ((keywrd = malloc(SC_MAXCOMMAND + 1)) == NULL)
      {
      d_out("%s:alloc fail[keywrd]", mname);
      return(TRUE);
      }

   if (!word(comm, keywrd, 1))
      {
      d_out("%s:error while retreving keyword, line skipped", mname);
      free(keywrd);
      return(TRUE);
      }

   nwords = words(comm);

   if ((token = get_token(keywrd)) == SCOM_NOT_FOUND)
      {
      d_out("%s:unknown keyword[%s]", mname, keywrd);
      free(keywrd);
      return(TRUE);
      }

   /* process command */

   switch(token)
      {
      case SCOM_TERM:
         d_term(comm);
         break;

      case SCOM_SOCLOC_TERM:
         d_socloc_term(comm);
         break;
         
      case SCOM_STATUS:
         d_status();
         break;

      case SCOM_CLIENT_LOG_ON:
         d_client_log_on(comm);
         break;
      
      case SCOM_CLIENT_LOG_OFF:
         d_client_log_off();
         break;

      case SCOM_CLIENT_LOG_STATUS:
         d_client_log_status();
         break;
         
      case SCOM_SERVER_LOG_ON:
         d_server_log_on(comm);
         break;
      
      case SCOM_SERVER_LOG_OFF:
         d_server_log_off();
         break;

      case SCOM_SERVER_LOG_STATUS:
         d_server_log_status();
         break;
                  
      case SCOM_CONNECT:
         d_connect(comm);
         break;
         
      case SCOM_SOCLOC_LIST:
         d_socloc_list();
         break;

      case SCOM_SOCLOC_CONFIG_LIST:
         d_socloc_config_list();
         break;
        
      case SCOM_SOCLOC_GET:
         d_socloc_get();
         break;

      case SCOM_SOCLOC_LOG_ON:
         d_socloc_log_on(comm);
         break;
         
      case SCOM_SOCLOC_LOG_OFF:
         d_socloc_log_off();
         break;
         
      case SCOM_SOCLOC_LOG_STATUS:
         d_socloc_log_status();
         break;

      case SCOM_SOCLOC_CONNECT:
         d_socloc_connect(comm);
         break;

      case SCOM_SOCLOC_FIND:
         d_socloc_find(comm);
         break;

      case SCOM_SOCLOC_SERVICE_NAME:
         d_socloc_service_name();
         break;
         
      case SCOM_SERVICE_NAME:
         d_service_name();
         break;
       
      case SCOM_SOCLOC_VERSION:
         d_socloc_version();
         break;
         
      case SCOM_VERSION:
         d_version();
         break;

      case SCOM_SOCLOC_CONFIG_FIND:
         d_socloc_config_find(comm);
         break;

      case SCOM_SOCLOC_STATUS:
         d_socloc_status();
         break;

      case SCOM_SOCLOC_CLIENT_LIST:
#ifdef IPC_TCP
         sl_config_list();
#else
         d_out("%s:applies to TCP IPC method only", mname);
#endif
         break;

      case SCOM_SOCLOC_CLIENT_UPDATE:
         d_socloc_client_update();
         break;

      case SCOM_SOCLOC_CLIENT_UPDATE_FILE:
         d_socloc_client_update_file();
         break;

      case SCOM_SEND:
         d_send(comm);
         break;

      case SCOM_SOCLOC_ADD:
         d_socloc_add(comm);
         break;

      case SCOM_SOCLOC_CONFIG_ADD:
         d_socloc_config_add(comm);
         break;

      case SCOM_SOCLOC_DELETE:
         d_socloc_delete(comm);
         break;

      case SCOM_SOCLOC_CONFIG_DELETE:
         d_socloc_config_delete(comm);
         break;
       
      case SCOM_SOCLOC_DUMP:
         d_socloc_dump();
         break;
         
      case SCOM_SOCLOC_CONFIG_DUMP:
         d_socloc_config_dump();
         break;
         
      case SCOM_CLIENT_VERSION:
         d_client_version();
         break;

      case SCOM_SOCLOC_TRANS_NUM:
         d_socloc_trans_num();
         break;

      case SCOM_SOCLOC_CONNECT_NUM:
         d_socloc_connect_num();
         break;

      case SCOM_TRANS_NUM:
         d_trans_num();
         break;

      case SCOM_CONNECT_NUM:
         d_connect_num();
         break;

      case SCOM_SOCLOC_ON:
         d_socloc_on();
         break;
         
      case SCOM_SOCLOC_OFF:
         d_socloc_off();
         break;
                  
      case SCOM_OFF:
         return(FALSE);
         break;

      default:
         d_out("%s:command not found", mname);
         free(keywrd);
         return(TRUE);
      };

   free(keywrd);
   logman("%s:exit 'TRUE'", mname);
   return(TRUE);
}

void d_term(char *comm)
{
   /* Terminate a socket server. Syntax:
   
         term passwd
         
      Where 'passwd' is the termination password. */

   char mname[] = "d_term";
   char passwd[128], parm[128];
   int ret;

   d_header(mname);

   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }

   if (command_words(comm) < 2)
      {
      d_out("%s:no password,access denied", mname);
      return;
      }

   if (!command_word(comm, passwd, 2))
      {
      d_out("%s:error getting password", mname);
      return;
      }

   if (words(passwd) > 1)
      sprintf(parm, "'%s'", passwd);
   else
      strcpy(parm, passwd);
      
#ifdef IPC_TCP
   ret = d_sr(SC_SEND_TERM, parm, passwd);
#else
   ret = d_sr(SC_SEND_TERM, parm, passwd, 128);
#endif
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, passwd);
      
   logman("%s:normal exit", mname);
}

void d_socloc_term(char *comm)
{
   /* Terminate a 'socloc' server. Syntax:
   
         socloc.term passwd
         
      Where 'passwd' is the termination password. */

   char mname[] = "d_socloc_term";
   char passwd[128], mes[128];
   int ret;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);

   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
      
   if (command_words(comm) < 2)
      {
      d_out("%s:no password,access denied", mname);
      return;
      }

   if (!command_word(comm, passwd, 2))
      {
      d_out("%s:error getting password", mname);
      return;
      }

   ret = sloc_terminate(passwd);
   sl_code_string(ret, mes);
   
   if (logman_is_active())   
      logman("%s:normal exit,rc[%d,%s]", mname,
                    ret, mes);
   else
      printf("%s\n", mes);
      
   logman("%s:normal exit", mname);
#endif
}

void d_status(void)
{
   /* Get server status. Syntax:
   
         status */

   char mname[] = "d_status";
   char reply[128];
   int ret;

   d_header(mname);
   
   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }
      
#ifdef IPC_TCP
   ret = d_sr(SC_SEND_STATUS, (char *)NULL, reply);
#else
   ret = d_sr(SC_SEND_STATUS, (char *)NULL, reply, 128);
#endif
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, reply);
      
   logman("%s:normal exit", mname);
}

void d_client_log_on(char *comm)
{
   /* Turn client logging on with optional log file name.
      Syntax:
      
         client.log.on[ log.fname]
         
      Where 'log.fname' is the optional log file name. If no
      log file name is given 'd_log_file' will be used.
      It is an error if client logging is already on.
      Function returns a 'sockc' code. */
      
   char mname[] = "d_client_log_on"; 

   d_header(mname);

   if (logman_is_active())
      {
      d_out("%s:log already on", mname);
      return;
      }

   if (command_words(comm) > 1)
      {
      if (!command_word(comm, d_log_file, 2))
         {
         d_out("%s:error getting log file name", mname);
         return;
         }
       }
    else
       strcpy(d_log_file, SOCKC_LOG_FILE);
         
   if (logman_start(d_log_file, APNAME))
      {
      d_out("%s:error writing log file", mname);
      return;
      }
      
   if (logman_is_active())
      logman("%s:normal exit[0]", mname);
   else
      printf("ok\n");
}

void d_client_log_off(void)
{
   /* Turn client logging off. Syntax:
   
         client.log.off
         
      It is an error if client logging is already off. */
      
   char mname[] = "d_client_log_off";   

   d_header(mname);

   if (!logman_is_active())
      {
      d_out("%s:log already off", mname);
      return;
      }

   if (logman_is_active())
      logman("%s:normal exit[0]", mname);
   else
      printf("ok\n");
      
   logman_end();
}

void d_client_log_status(void)
{
   /* Display status of client logging. Syntax:
   
         client.log.status */
      
   char mname[] = "d_client_log_status";
   
   d_header(mname);
   
   if (logman_is_active())
      logman("%s:exit:client log is on,name=%s", mname, d_log_file);
   else   
      printf("%s:client log is off,name=%s\n", mname, d_log_file);      
}
   
void d_server_log_on(char *comm)
{  
   /* Tell server to turn its logging on. Syntax:
   
         server.log.on[ log_fname]

      If no 'log_fname' is given, the default sever log file
      name will be used. It is an error if server logging is
      already on. */

   char mname[] = "d_server_log_on";
   char tmp[256], slog[256];
   int ret;

   d_header(mname);

   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }
         
   if (command_words(comm) > 1)
      {
      if (!command_word(comm, tmp, 2))
         {
         d_out("%s:error getting server log file name", mname);
         return;
         }
         
      if (words(tmp) > 1)
         sprintf(slog, "'%s'", tmp);
      else
         strcpy(slog, tmp);
         
#ifdef IPC_TCP
      ret = d_sr(SC_SEND_LOG_ON, slog, tmp);
#else
      ret = d_sr(SC_SEND_LOG_ON, slog, tmp, 256);
#endif
      }
   else
#ifdef IPC_TCP
      ret = d_sr(SC_SEND_LOG_ON, (char *)NULL, tmp);
#else
      ret = d_sr(SC_SEND_LOG_ON, (char *)NULL, tmp, 256);
#endif

   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, tmp);
      
   logman("%s:normal exit", mname);      
}

void d_server_log_off(void)
{
   /* Tell server to turn its logging off. Syntax:
   
         server.log.off
         
      It is an error if the server log is already off. */

   char mname[] = "d_server_log_off";
   char reply[128];
   int ret;

   d_header(mname);
   
   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }
      
#ifdef IPC_TCP
   ret = d_sr(SC_SEND_LOG_OFF, (char *)NULL, reply);
#else
   ret = d_sr(SC_SEND_LOG_OFF, (char *)NULL, reply, 128);
#endif
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, reply);
      
   logman("%s:normal exit", mname);   
}

void d_server_log_status(void)
{
   /* Get status of server logging. Syntax:
   
         server.log.status */
   
   char mname[] = "d_server_log_status";
   char reply[128];
   int ret;
   
   d_header(mname);
   
   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }
      
#ifdef IPC_TCP
   ret = d_sr(SC_SEND_LOG_STATUS, (char *)NULL, reply);
#else
   ret = d_sr(SC_SEND_LOG_STATUS, (char *)NULL, reply, 128);
#endif
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, reply);
      
   logman("%s:normal exit", mname);   
}

void d_socloc_log_on(char *comm)
{  
   /* Tell 'socloc' server to turn its logging on. Syntax:
   
         socloc.log.on[ log_fname]

      If no 'log_fname' is given, the default sever log file
      name will be used. It is an error if server logging is
      already on. */

   char mname[] = "d_socloc_log_on";
   char tmp[128], slog[128];
   int ret;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);

   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   if (command_words(comm) > 1)
      {
      if (!command_word(comm, tmp, 2))
         {
         d_out("%s:error getting server log file name", mname);
         return;
         }
         
      if (words(tmp) > 1)
         sprintf(slog, "'%s'", tmp);
      else
         strcpy(slog, tmp);
         
      ret = sloc_log_on(slog);
      }
   else
      ret = sloc_log_on((char *)NULL);
         
   if (logman_is_active())
      logman("%s:normal exit rc[%d]", mname, ret);
   else
      {
      sl_code_string(ret, tmp);
      printf("%s\n", tmp);
      }
#endif
}

void d_socloc_log_off(void)
{
   /* Tell 'socloc' server to turn its logging off. Syntax:
   
         socloc.log.off
         
      It is an error if the server log is already off. */

   char mname[] = "d_socloc_log_off";
   char mes[128];
   int ret;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   ret = sloc_log_off();
   
   if (logman_is_active())
      logman("%s:normal exit rc[%d]", mname, ret);
   else
      {
      sl_code_string(ret, mes);
      printf("%s\n", mes);
      }
#endif
}

void d_socloc_log_status(void)
{
   /* Get status of 'socloc' server logging. Syntax:
   
         socloc.log.status */
   
   char mname[] = "d_socloc_log_status";
   char mes[128];
   int ret, lflag;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   ret = sloc_log_status(&lflag, mes);
    
   if (ret != SL_OK)
      {
      if (logman_is_active())
         logman("%s:normal exit,rc[%d]", mname, ret);
      else
         {
         sl_code_string(ret, mes);
         printf("%s\n", mes);
         }
         
      return;
      }
      
   if (lflag)
      d_out("%s:socloc server log is active,log is %s", mname, mes);
   else
      d_out("%s:socloc server log is inactive,log is %s", mname, mes);
      
   if (logman_is_active())
      logman("%s:normal exit,rc[0]", mname);
#endif
}
   
void d_connect(char *comm)
{
   /* Connect to any server. TCP syntax is:
   
         connect [service s_name][ host hname][ port pnum][ ip ip_ad]
         
      QNX message passing syntax is:

         connect s_name

      QNX message passing variant allow only the service name which
      is mandatory and must exacly match the 'nameloc' name. In TCP
      all parameters except 'connect' keyword are optional. At
      least one parameter must be given. If the 'socloc' interface
      is off, the only keywords that make sense are 'host' and
      'port' both of which must be present. */
      
   char mname[] = "d_connect";
   char mes[128], *service, *hname, *ip_ad;   
   int pos, ret, port, nwords;

   d_header(mname);
   nwords = command_words(comm);

#ifdef IPC_TCP
   if (nwords < 3)
#else
   if (nwords < 2)
#endif
      {
      d_out("%s:at least one parameter must be supplied", mname);         
      return;
      }

   /* alloc details */

#ifdef IPC_TCP
   if ((service = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[service]", mname);
      return;
      } 

   if ((hname = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[hname]", mname);
      free(service);
      return;
      } 

   if ((ip_ad = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[ip_ad]", mname);
      free(service);
      free(hname);      
      return;
      }   
#endif

   /* get the position of the second command word */
   
   pos = command_indxword(comm, 2);
   
   /* if the first char in the second word is a quote,
      'command_indxword' will skip over this, we need to
      backup one position */
      
   if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
      pos--;

#ifdef IPC_TCP
   if (sk_flag)
      {      
      if ((ret = sconnect_parse(&comm[pos], TRUE, service, hname,
                                &port, ip_ad)) != SP_OK)
         {
         sp_code_string(ret, mes);
         d_out("%s:bad rc[%d,%s] from 'sconnect_parse'", mname, ret, mes);         
         free(service);
         free(hname);
         free(ip_ad);      
         return;
         }
            
      /* locate the socket server based on supplied details */
   
      if ((ret = sloc_ll_find(service, hname, &port, ip_ad)) != SL_OK)
         {
         sl_code_string(ret, mes);
         d_out("%s:bad rc[%d,%s] from 'sloc_ll_find'", mname, ret, mes);
         free(service);
         free(hname);
         free(ip_ad);
         return;
         }
         
      logman("%s:match service=%s,host=%s,port=%d", mname, service,
                    hname, port);
      }
   else
      {
      /* if 'socloc' interface is off, make sure host name and
         port number have been given, service name is not allowed */
         
      if ((ret = sconnect_parse(&comm[pos], FALSE, (char *)NULL, hname,
                                &port, ip_ad)) != SP_OK)
         {
         sp_code_string(ret, mes);
         d_out("%s:bad rc[%d,%s] from 'sconnect_parse'", mname, ret, mes);         
         free(service);
         free(hname);
         free(ip_ad);      
         return;
         }

      /* check host name and port */
      
      if (!strlen(hname))
         {
         d_out("%s:host name has not been given", mname);
         free(service);
         free(hname);
         free(ip_ad);      
         return;
         }
         
      if (port == 0)
         {
         d_out("%s:port number has not been given", mname);
         free(service);
         free(hname);
         free(ip_ad);      
         return;
         }
      }
#else
   if (!command_word(comm, serverhost, 2))
      {   
      d_out("%s:error getting 'nameloc' service name", mname);
      free(hname);
      return;
      }
#endif
   
#ifdef IPC_TCP
   strcpy(serverhost, hname);
   
   if (sk_flag)
      strcpy(serverservice, service);
   else
      serverservice[0] = EOS;
      
   serverport = port;
   free(service);
   free(hname);
   free(ip_ad);
   (void)ipc_set_active(serverhost, serverport);
#else
   (void)ipc_set_active(serverhost);
#endif

   if (logman_is_active())   
      logman("%s:normal exit rc[%d]", mname, ret);
   else
      printf("ok\n");
}

void d_socloc_connect(char *comm)
{
   /* Connect to any 'socloc' server. Syntax is:
   
         socloc.connect [host hname][ port pnum][ ip ip_ad]
         
      All parameters except 'connect' keyword are optional. At
      least one parameter must be given. */
      
   char mname[] = "d_socloc_connect";
   char mes[128], *hname, *ip_ad;   
   int pos, ret, port, nwords;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   nwords = command_words(comm);

   if (nwords < 3)
      {
      d_out("%s:at least one parameter must be supplied", mname);         
      return;
      }

   /* alloc details */

   if ((hname = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[hname]", mname);
      return;
      } 

   if ((ip_ad = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[ip_ad]", mname);
      free(hname);      
      return;
      }   

   /* get the position of the second command word */
   
   pos = command_indxword(comm, 2);
   
   /* if the first char in the second word is a quote,
      'command_indxword' will skip over this, we need to
      backup one position */
      
   if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
      pos--;

   /* parse the connect string */
   
   if ((ret = sconnect_parse(&comm[pos], FALSE, (char *)NULL, hname,
                             &port, ip_ad)) != SP_OK)
      {
      sp_code_string(ret, mes);
      d_out("%s:bad rc[%d,%s] from 'sconnect_parse'", mname, ret, mes);         
      free(hname);
      free(ip_ad);      
      return;
      }
      
   /* locate the 'socloc' server based on supplied details */
   
   if ((ret = sloc_config_find(hname, &port, ip_ad)) != SL_OK)
      {
      sl_code_string(ret, mes);
      d_out("%s:bad rc[%d,%s] from 'sloc_config_find'", mname, ret, mes);
      free(hname);
      free(ip_ad);
      return;
      }

   /* try to set active */

   if ((ret = sloc_set_active_socloc(hname, port)) != SL_OK)
      {
      sl_code_string(ret, mes);
      d_out("%s:bad rc[%d,%s] from 'sloc_set_active_socloc'", mname,
            ret, mes);
      free(hname);
      free(ip_ad);
      return;
      }
      
   free(hname);
   free(ip_ad);

   if (logman_is_active())   
      logman("%s:normal exit rc[%d]", mname, ret);
   else
      printf("ok\n");
#endif
}

void d_socloc_list(void)
{
   /* Get the list of available socket servers from 'socloc'.
      Syntax:
      
         socloc.list */
      
   char mname[] = "d_socloc_list";
   char *list_out;
   int ret;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   if ((list_out = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[list_out]", mname);
      return;
      } 

   ret = sloc_get_list(list_out);
                           
   if (ret == SC_OK)
      {
      d_out("current socket servers");
      d_display_list(list_out);
      }      
   
   if (logman_is_active())
      logman("%s:normal exit rc[%d]", mname, ret);
   else
      {
      sl_code_string(ret, list_out);
      printf("%s\n", list_out);
      }
      
   free(list_out);
#endif
}
 
void d_socloc_config_list(void)
{
   /* Get the list of available 'socloc' servers.
      Syntax:
      
         socloc.config.list */
      
   char mname[] = "d_socloc_config_list";
   char *list_out;
   int ret;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);

   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   if ((list_out = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[list_out]", mname);
      return;
      } 

   ret = sloc_config_get_list(list_out);
                           
   if (ret == SC_OK)
      {
      d_out("current 'socloc' servers");
      d_display_config_list(list_out);
      }      
   
   if (logman_is_active())
      logman("%s:normal exit rc[%d]", mname, ret);
   else
      {
      sl_code_string(ret, list_out);
      printf("%s\n", list_out);
      }
      
   free(list_out);
#endif
}

void d_socloc_get(void)
{
   /* Get and display the current 'socloc' server. Syntax:
   
         socloc.get */
      
   char mname[] = "d_socloc_get";
   char hname[256];
   int port;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   hname[0] = EOS;
   port = 0;
   sloc_get_active_socloc(hname, &port);
   
   if (strlen(hname))
      d_out("connected to 'socloc' server '%s' on port %d", hname, port);
   else
      d_out("no current 'socloc' server");
      
   logman("%s:normal exit", mname);
#endif
}   

void d_socloc_find(char *comm)
{
   /* Find the details of one or more socket servers. Syntax is:
   
         socloc.find [service sname][ host hname][ port pnum][ ip ip_ad]
         
      All parameters except 'find' keyword are optional. At
      least one parameter must be given. */
      
   char mname[] = "d_socloc_find";
   char mes[128], *sname, *hname, *ip_ad, *thelist;
   int pos, ret, port, nwords;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   nwords = command_words(comm);

   if (nwords < 3)
      {
      d_out("%s:at least one parameter must be supplied", mname);         
      return;
      }

   /* alloc details */

   if ((sname = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[sname]", mname);
      return;
      } 

   if ((hname = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[hname]", mname);
      free(sname);
      return;
      } 

   if ((ip_ad = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[ip_ad]", mname);
      free(sname);
      free(hname);      
      return;
      }   

   /* get the position of the second command word */
   
   pos = command_indxword(comm, 2);
   
   /* if the first char in the second word is a quote,
      'command_indxword' will skip over this, we need to
      backup one position */
      
   if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
      pos--;

   /* parse the connect string */
   
   if ((ret = sconnect_parse(&comm[pos], TRUE, sname, hname,
                             &port, ip_ad)) != SP_OK)
      {
      sp_code_string(ret, mes);
      d_out("%s:bad rc[%d,%s] from 'sconnect_parse'", mname, ret, mes);         
      free(sname);
      free(hname);
      free(ip_ad);      
      return;
      }

   /* alloc list */
   
   if ((thelist = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[thelist]", mname);
      free(sname);
      free(hname);
      free(ip_ad);
      return;
      }
                  
   /* get a list of socket servers based on supplied details */
   
   if ((ret = sloc_ll_find_list(sname, hname, &port, ip_ad, thelist))
       != SL_OK)
      {
      sl_code_string(ret, mes);
      d_out("%s:bad rc[%d,%s] from 'sloc_ll_find_list'", mname, ret, mes);
      free(sname);
      free(hname);
      free(ip_ad);
      free(thelist);
      return;
      }

   free(sname);
   free(hname);
   free(ip_ad);
   
   /* display list */
   
   if (ret == SC_OK)
      {
      d_out("matched socket servers");
      d_display_list(thelist);
      }
      
   free(thelist);

   if (logman_is_active())   
      logman("%s:normal exit rc[%d]", mname, ret);
   else
      printf("ok\n");
#endif
}

void d_socloc_service_name(void)
{
   /* Display the service name of the current 'socloc' server.
      Syntax:
      
         socloc.service.name */
         
   char mname[] = "d_socloc_service_name";
   char sname[128], mes[128];
   int ret;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   ret = sloc_service_name(sname);
   sl_code_string(ret, mes);
     
   if (logman_is_active()) 
      if (ret != SC_OK)
         logman("%s:bad rc[%d,%s] from 'sloc_service_name",
                       mname, ret, mes);
      else
         logman("%s:service name is '%s'", mname, sname);
   else
      if (ret != SC_OK)
         printf("%s\n", mes);
      else
         printf("%s\nok\n", sname);
      
   logman("%s:normal exit", mname);
#endif
}

void d_service_name(void)
{
   /* Get service name from server. Syntax:
   
         service.name */
         
   char mname[] = "d_service_name";
   char reply[128];
   int ret;

   d_header(mname);
   
   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }
      
#ifdef IPC_TCP
   ret = d_sr(SC_SEND_SERVICE_NAME, (char *)NULL, reply);
#else
   ret = d_sr(SC_SEND_SERVICE_NAME, (char *)NULL, reply, 128);
#endif
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, reply);
      
   logman("%s:normal exit", mname);   
}

void d_socloc_version(void)
{
   /* Display the version ID of the current 'socloc' server.
      Syntax:
      
         socloc.version */
         
   char mname[] = "d_socloc_version";
   char version[50], mes[128];
   int ret;

#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   ret = sloc_version(version);
   sl_code_string(ret, mes);
   
   if (ret != SC_OK)
      if (logman_is_active())      
         logman("%s:bad rc[%d,%s] from 'sloc_version'", mname,
                       ret, mes);
      else
         printf("%s\n", mes);
   else
      if (logman_is_active())
         logman("%s:send rc[ok]:'socloc' reply=%s", mname, version);
      else
         printf("%s\nok\n", version);
      
   logman("%s:normal exit", mname);
#endif
}

void d_version(void)
{
   /* Get the version from the server. Syntax:
   
         version */
         
   char mname[] = "d_version";
   char reply[128];
   int ret;

   d_header(mname);
   
   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }
      
#ifdef IPC_TCP
   ret = d_sr(SC_SEND_VERSION, (char *)NULL, reply);
#else
   ret = d_sr(SC_SEND_VERSION, (char *)NULL, reply, 128);
#endif
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, reply);
      
   logman("%s:normal exit", mname);   
}

void d_client_version(void)
{
   /* Display the 'sockc' client version. */
   
   char mname[] = "d_client_version";
   
   d_header(mname);
   
   if (logman_is_active())
      logman("%s:'sockc' client version is '%s'", mname, VERSION);
   else
      printf("%s\n", VERSION);
}
      
void d_socloc_config_find(char *comm)
{
   /* Find a 'socloc' server. Since all port names are unique and
      running more than one 'socloc' server per host is not allowed,
      this find will only ever match one entry. Syntax:
      
         socloc.config.find [host hname][ port port_num][ ip ip_ad] */
      
   char mname[] = "d_socloc_config_find";
   char *hname, *ip_ad, mes[128];
   int ret, nwords, pos, port;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   nwords = command_words(comm);

   if (nwords < 3)
      {
      d_out("%s:at least one parameter must be supplied", mname);         
      return;
      }

   /* alloc details */

   if ((hname = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[hname]", mname);
      return;
      } 

   if ((ip_ad = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[ip_ad]", mname);
      free(hname);      
      return;
      }   

   /* get the position of the second command word */
   
   pos = command_indxword(comm, 2);
   
   /* if the first char in the second word is a quote,
      'command_indxword' will skip over this, we need to
      backup one position */
      
   if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
      pos--;

   /* parse the connect string */
   
   if ((ret = sconnect_parse(&comm[pos], FALSE, (char *)NULL, hname,
                             &port, ip_ad)) != SP_OK)
      {
      sp_code_string(ret, mes);
      d_out("%s:bad rc[%d,%s] from 'sconnect_parse'", mname, ret, mes);         
      free(hname);
      free(ip_ad);      
      return;
      }   
      
   if ((ret = sloc_config_find(hname, &port, ip_ad)) == SL_OK)
      {
      if (strlen(ip_ad))
         d_out("socloc:host=%s,port=%d,ip=%s", hname, port, ip_ad);
      else
         d_out("socloc:host=%s,port=%d", hname, port);
         
      if (!logman_is_active())
         printf("ok\n");
      }
   else
      {
      sl_code_string(ret, mes);
      
      if (logman_is_active())
         logman("%s:bad rc[%s] from 'sloc_config_find'", mname, mes);
      else
         printf("%s\n", mes);
      }

   free(hname);
   free(ip_ad);
   
   if (logman_is_active())   
      logman("%s:normal exit rc[%d]", mname, ret);   
#endif
}   
   
void d_socloc_status(void)
{
   /* Get the status of the currently connected 'socloc' server.
      Syntax:
      
         socloc.status */
         
   char mname[] = "d_socloc_status";
   char mes[128];
   int ret;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   ret = sloc_status();
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      d_out("%s:normal exit,rc[%d,%s]", mname, ret, mes);
   else
      printf("%s\n", mes);
#endif
}         

void d_socloc_client_update(void)
{
   /* Get the current 'socloc' server list and update the client
      config link list with it. */
      
   char mname[] = "d_socloc_client_update";
   char *thelist, mes[128];
   int ret;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);

   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   if ((thelist = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[thelist]", mname);
      return;
      }
      
   /* get the config list from the first active server */
   
   if ((ret = sloc_config_get_list(thelist)) != SL_OK)
      {
      d_out("%s:bad rc[%d] from 'sloc_config_get_list'",
                    mname, ret);
      free(thelist);
      return;
      }      
   
   /* create a new list in memory */
   
   if ((ret = sl_config_put_list(thelist)) != SL_OK)
      {
      d_out("%s:bad rc[%d] from 'sl_config_put_list'",
                    mname, ret);
      free(thelist);
      return;
      }
      
   free(thelist);
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      logman("%s:normal exit,rc[%d,%s]", mname, ret, mes);
   else   
      printf("%s\n", mes);
#endif
}

void d_socloc_client_update_file(void)
{
   /* Get the current 'socloc' server list and update the client
      config link list with it and write these changes to the
      config file. */
      
   char mname[] = "d_socloc_client_update_file";
   char mes[128];
   int ret;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   ret = sloc_config_update();   
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      logman("%s:normal exit,rc[%d,%s]", mname, ret, mes);
   else   
      printf("%s\n", mes);
#endif
}

void d_send(char *comm)
{
   /* Send a message to the currently conncted socket server. Syntax:
   
         send typ [parm]
         
      Where 'typ' is the numeric command type or code and 'parm' is
      the contents of the message (which may be blank). */

   char mname[] = "d_send";
   char typ_char[128], *reply;
   int ret, pos, typ, nwords;

   d_header(mname);

   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }

   nwords = command_words(comm);
   
   if (nwords < 2)
      {
      d_out("%s:no command type/code", mname);
      return;
      }
      
   if (!command_word(comm, typ_char, 2))
      {
      d_out("%s:error getting send type code", mname);
      return;
      }
      
   /* type code must be numeric */
   
   if (!qatoi(typ_char, &typ))
      {
      d_out("%s:type code must be numeric", mname);
      return;
      }
      
   /* type code must be a positive integer */
   
   if (typ <= 0)
      {
      d_out("%s:type code out of range", mname);
      return;
      }
      
   /* get the position of the third command word */

   if (nwords > 2)
      {
      pos = command_indxword(comm, 3);
   
      /* if the first char in the third word is a quote,
         'command_indxword' will skip over this, we need to
         backup one position */
      
      if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
         pos--;
      }

   if ((reply = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      d_out("%s:alloc fail[reply]", mname);
      return;
      }
      
   if (nwords > 2)      
#ifdef IPC_TCP
      ret = d_sr(typ, &comm[pos], reply);
#else
      ret = d_sr(typ, &comm[pos], reply, SC_MAXCOMMAND);
#endif
   else
#ifdef IPC_TCP
      ret = d_sr(typ, (char *)NULL, reply);
#else
      ret = d_sr(typ, (char *)NULL, reply, SC_MAXCOMMAND);
#endif
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, reply);

   free(reply);      
   logman("%s:normal exit", mname);   
}

void d_socloc_add(char *comm)
{
   /* Add a socket server entry to 'socloc'. Syntax:
   
         socloc.add service host port[ ip]
         
      All parameters must be present except for the optional IP
      address. Any parameter containing spaces must be quoted. */
      
   char mname[] = "d_socloc_add";
   char *sname, *hname, *port_char, *ip_ad;
   char mes[128];
   int ret, nwords, len, port;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   nwords = command_words(comm);
   len = strlen(comm);
   
   if (nwords < 4)
      {
      d_out("%s:parameters absent", mname);
      return;
      }
      
   /* alloc details */
   
   if ((sname = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[sname]", mname);
      return;
      }

   if ((hname = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[hname]", mname);
      free(sname);
      return;
      }
      
   if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[port_char]", mname);
      free(sname);
      free(hname);      
      return;
      }

   if (nwords > 4)
      {
      if ((ip_ad = (char *)malloc(len + 1)) == (char *)NULL)
         {
         d_out("%s:alloc fail[ip_ad]", mname);
         free(sname);
         free(hname);
         free(port_char);
         return;
         }
      }
   else
      ip_ad = (char *)NULL;
      
   /* get details */
   
   if (!command_word(comm, sname, 2))
      {
      d_out("%s:error getting service name", mname);
      free(sname);
      free(hname);
      free(port_char);
      
      if (ip_ad != (char *)NULL)
         free(ip_ad);
         
      return;
      }
      
   if (!command_word(comm, hname, 3))
      {
      d_out("%s:error getting host", mname);
      free(sname);
      free(hname);
      free(port_char);
      
      if (ip_ad != (char *)NULL)
         free(ip_ad);
         
      return;
      }
      
   if (!command_word(comm, port_char, 4))
      {
      d_out("%s:error getting port", mname);
      free(sname);
      free(hname);
      free(port_char);
      
      if (ip_ad != (char *)NULL)
         free(ip_ad);
         
      return;
      }

   if (!qatoi(port_char, &port))
      {
      d_out("%s:port not numeric", mname);
      free(sname);
      free(hname);
      free(port_char);
      
      if (ip_ad != (char *)NULL)
         free(ip_ad);
         
      return;
      }

   free(port_char);
   
   if (nwords > 4)
      if (!command_word(comm, ip_ad, 5))
         {
         d_out("%s:error getting IP address", mname);
         free(sname);
         free(hname);
         free(ip_ad);
         return;
         }
      
   ret = sloc_add(sname, hname, port, ip_ad);
   free(sname);
   free(hname);
   
   if (ip_ad != (char *)NULL)
      free(ip_ad);
      
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      logman("%s:normal exit[%d,%s]", mname, ret, mes);
   else
      printf("%s\n", mes);
#endif
}      

void d_socloc_config_add(char *comm)
{
   /* Add a 'socloc' entry to 'socloc'. Syntax:
   
         socloc.config.add host port[ ip]
         
      All parameters must be present except for the optional IP
      address. Any parameter containing spaces must be quoted. */
      
   char mname[] = "d_socloc_add";
   char *hname, *port_char, *ip_ad;
   char mes[128];
   int ret, nwords, len, port;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   nwords = command_words(comm);
   len = strlen(comm);
   
   if (nwords < 3)
      {
      d_out("%s:parameters absent", mname);
      return;
      }
      
   /* alloc details */
   
   if ((hname = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[hname]", mname);
      return;
      }
      
   if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[port_char]", mname);
      free(hname);      
      return;
      }

   if (nwords > 3)
      {
      if ((ip_ad = (char *)malloc(len + 1)) == (char *)NULL)
         {
         d_out("%s:alloc fail[ip_ad]", mname);
         free(hname);
         free(port_char);
         return;
         }
      }
   else
      ip_ad = (char *)NULL;
      
   /* get details */
   
   if (!command_word(comm, hname, 2))
      {
      d_out("%s:error getting host", mname);
      free(hname);
      free(port_char);
      
      if (ip_ad != (char *)NULL)
         free(ip_ad);
         
      return;
      }
      
   if (!command_word(comm, port_char, 3))
      {
      d_out("%s:error getting port", mname);
      free(hname);
      free(port_char);
      
      if (ip_ad != (char *)NULL)
         free(ip_ad);
         
      return;
      }

   if (!qatoi(port_char, &port))
      {
      d_out("%s:port not numeric", mname);
      free(hname);
      free(port_char);
      
      if (ip_ad != (char *)NULL)
         free(ip_ad);
         
      return;
      }

   free(port_char);
   
   if (nwords > 3)
      if (!command_word(comm, ip_ad, 4))
         {
         d_out("%s:error getting IP address", mname);
         free(hname);
         free(ip_ad);
         return;
         }
      
   ret = sloc_config_add(hname, port, ip_ad);
   free(hname);
   
   if (ip_ad != (char *)NULL)
      free(ip_ad);
      
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      logman("%s:normal exit,rc[%d,%s]", mname, ret, mes);
   else
      printf("%s\n", mes);
#endif
}      

void d_socloc_delete(char *comm)
{
   /* Delete a socket server entry to 'socloc'. Syntax:
   
         socloc.delete port */         
            
   char mname[] = "d_socloc_delete";
   char *port_char;
   char mes[128];
   int ret, nwords, len, port;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   nwords = command_words(comm);
   len = strlen(comm);
   
   if (nwords < 2)
      {
      d_out("%s:parameters absent", mname);
      return;
      }
      
   /* alloc details */
         
   if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[port_char]", mname);        
      return;
      }

   /* get port */
   
   if (!command_word(comm, port_char, 2))
      {
      d_out("%s:error getting port", mname);
      free(port_char);
      return;
      }

   if (!qatoi(port_char, &port))
      {
      d_out("%s:port not numeric", mname);
      free(port_char);
      return;
      }

   free(port_char);
   ret = sloc_delete(port);
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      logman("%s:normal exit,rc[%d,%s]", mname, ret, mes);
   else
      printf("%s\n", mes);
#endif
}      
 
void d_socloc_config_delete(char *comm)
{
   /* Delete a 'socloc' entry. Syntax:
   
         socloc.config.delete port */         
            
   char mname[] = "d_socloc_config_delete";
   char *port_char;
   char mes[128];
   int ret, nwords, len, port;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   nwords = command_words(comm);
   len = strlen(comm);
   
   if (nwords < 2)
      {
      d_out("%s:parameters absent", mname);
      return;
      }
      
   /* alloc details */
         
   if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[port_char]", mname);        
      return;
      }

   /* get port */
   
   if (!command_word(comm, port_char, 2))
      {
      d_out("%s:error getting port", mname);
      free(port_char);
      return;
      }

   if (!qatoi(port_char, &port))
      {
      d_out("%s:port not numeric", mname);
      free(port_char);
      return;
      }

   free(port_char);
   ret = sloc_config_delete(port);
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      logman("%s:normal exit,rc[%d,%s]", mname, ret, mes);
   else
      printf("%s\n", mes);
#endif
}

void d_socloc_on(void)
{
   /* Turn 'socloc' interface on. Check for the interface already
      on. */
      
   char mname[] = "d_socloc_on";   
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   if (sk_flag)
      {
      d_out("%s:socloc interface is already on", mname);
      return;
      }
      
   if (!d_socloc_activate())
      {
      d_out("%s:socloc initialization failure", mname);
      return;
      }
      
   if (logman_is_active())
      logman("%s:normal exit", mname);
   else
      printf("ok\n");
#endif
}

void d_socloc_off(void)
{
   /* Turn 'socloc' interface off. Check for the interface already
      off. */
      
   char mname[] = "d_socloc_off";   
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   if (!sk_flag)
      {
      d_out("%s:socloc interface is already off", mname);
      return;
      }

   sloc_term_api();
   sk_flag = FALSE;
   
   if (logman_is_active())
      logman("%s:normal exit", mname);
   else
      printf("ok\n");
#endif
}
      
void d_socloc_dump(void)
{
   /* Tell the 'socloc' server to dump the socket server list.
      Syntax:
      
         socloc.dump */
         
   char mname[] = "d_socloc_dump";
   char mes[128];
   int ret;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   ret = sloc_dump_debug();
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      logman("%s:normal exit,rc[%d,%s", mname,
                    ret, mes);
   else
      printf("%s\n", mes);
#endif
}

void d_socloc_config_dump(void)
{
   /* Tell the 'socloc' server to dump the 'socloc' server list.
      Syntax:
      
         socloc.config.dump */
         
   char mname[] = "d_socloc_config_dump";
   char mes[128];
   int ret;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }
   
   ret = sloc_config_dump_debug();
   sl_code_string(ret, mes);
   
   if (logman_is_active())
      logman("%s:bad rc[%d,%s] from 'sloc_config_dump_debug", mname,
                    ret, mes);
   else
      printf("%s\n", mes);
#endif
}

void d_socloc_trans_num(void)
{
   /* Get the current transaction count from the 'socloc' server. Syntax:
   
         socloc.trans.num */
   
   char mname[] = "d_socloc_trans_num", mes[128];
   long trans_num;
   int ret;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   ret = sloc_trans_num(&trans_num);
    
   if (ret != SL_OK)
      {
      if (logman_is_active())
         logman("%s:normal exit,rc[%d]", mname, ret);
      else
         {
         sl_code_string(ret, mes);
         printf("%s\n", mes);
         }
         
      return;
      }
      
   d_out("%s:current socloc transaction count is %ld", mname, trans_num);
      
   if (logman_is_active())
      logman("%s:normal exit,rc[0]", mname);
#endif
}

void d_socloc_connect_num(void)
{
   /* Get the current connection count from the 'socloc' server. Syntax:
   
         socloc.connect.num */
   
   char mname[] = "d_socloc_connect_num", mes[128];
   int ret, connect_num;
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   d_header(mname);
   
   if (!sk_flag)
      {
      d_out("%s:socloc interface not active", mname);
      return;
      }

   ret = sloc_connect_num(&connect_num);
    
   if (ret != SL_OK)
      {
      if (logman_is_active())
         logman("%s:normal exit,rc[%d]", mname, ret);
      else
         {
         sl_code_string(ret, mes);
         printf("%s\n", mes);
         }
         
      return;
      }
      
   d_out("%s:current socloc connection count is %d", mname, connect_num);
      
   if (logman_is_active())
      logman("%s:normal exit,rc[0]", mname);
#endif
}

void d_trans_num(void)
{
   /* Get the current transaction count from the current socket server. Syntax:
   
         trans.num */
   
   char mname[] = "d_trans_num", reply[128];
   int ret;
   
   d_header(mname);
   
   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }
      
#ifdef IPC_TCP
   ret = d_sr(SC_SEND_TRANS_NUM, (char *)NULL, reply);
#else
   ret = d_sr(SC_SEND_TRANS_NUM, (char *)NULL, reply, 128);
#endif
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, reply);
      
   logman("%s:normal exit", mname);
}

void d_connect_num(void)
{
   /* Get the current connection count from the current socket server. Syntax:
   
         connect.num */
   
   char mname[] = "d_connect_num", reply[128];
   int ret;
   
   d_header(mname);
   
#ifdef IPC_QNX
   d_out("%s:applies to TCP IPC method only", mname);
   return;
#else
   if (!is_connected())
      {
      d_out("%s:no active connection", mname);
      return;
      }
      
   ret = d_sr(SC_SEND_CONNECT_NUM, (char *)NULL, reply);
   
   if (ret != SC_OK)
      d_out("%s:send fail,rc[%d]", mname, ret);
   else
      d_out("%s:send rc[ok]:server reply=%s", mname, reply);
      
   logman("%s:normal exit", mname);
#endif
}

#ifdef IPC_TCP      
void d_display_list(char *thelist)
{
   /* Display a list of server entries. Only used for socket servers,
      not 'socloc' servers. Each entry in the list
      is delimited by 'SL_LIST_DELIM'. */

   char mname[] = "d_display_list";
   char *entry, *service, *hname, *port_char, *ip_ad;
   int i, len, nentries;
   
   d_header(mname);
   
   if (thelist == (char *)NULL)
      {
      d_out("%s:list is null", mname);
      return;
      }
      
   len = strlen(thelist);
   nentries = ll_words(thelist, SL_LIST_DELIM);
      
   if ((entry = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[entry]", mname);        
      return;
      }

   if ((service = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[service]", mname);        
      free(entry);
      return;
      }
         
   if ((hname = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[hname]", mname);      
      free(entry);
      free(service);
      return;
      }

   if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[port_char]", mname);         
      free(entry);
      free(service);
      free(hname);
      return;
      }

   if ((ip_ad = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[ip_ad]", mname);      
      free(entry);
      free(service);
      free(hname);
      free(port_char);
      return;
      }

   for(i = 1; i <= nentries; i++)
      {
      if (!ll_word(thelist, entry, i, SL_LIST_DELIM))
         {
         d_out("%s:error geting list entry[%d]", mname, i);            
         free(entry);
         free(service);
         free(hname);
         free(port_char);
         free(ip_ad);
         return;
         }        

      if (!command_word(entry, service, 1))
         {
         d_out("%s:error getting service from entry[%d]", mname, i);            
         free(entry);
         free(service);
         free(hname);
         free(port_char);
         free(ip_ad);
         return;
         }
                     
      if (!command_word(entry, hname, 2))
         {
         d_out("%s:error getting host from entry[%d]", mname, i);         
         free(entry);
         free(service);
         free(hname);
         free(port_char);
         free(ip_ad);
         return;
         }
            
      if (!command_word(entry, port_char, 3))
         {
         d_out("%s:error getting port from entry[%d]", mname, i);            
         free(entry);
         free(service);
         free(hname);
         free(port_char);
         free(ip_ad);
         return;
         }
            
      if (command_words(entry) > 3)
         {
         if (!command_word(entry, ip_ad, 4))
            {
            d_out("%s:error getting ip from entry[%d]", mname, i);            
            free(entry);
            free(service);
            free(hname);
            free(port_char);
            free(ip_ad);
            return;
            }
         }
      else
         ip_ad[0] = EOS;                        
         
      if (strlen(ip_ad))
         d_out("server[%d]:service=%s,host=%s,port=%s,ip=%s", i, service,
               hname, port_char, ip_ad);
      else
         d_out("server[%d]:service=%s,host=%s,port=%s", i, service,
               hname, port_char);
      }
         
   free(entry);
   free(service);
   free(hname);
   free(port_char);
   free(ip_ad);
   logman("%s:normal exit", mname);
}

void d_display_config_list(char *thelist)
{
   /* Display a list of 'socloc' server entries. Only used for
      'socloc' servers, not socket servers. Each entry in the list
      is delimited by 'SL_LIST_DELIM'. */

   char mname[] = "d_display_config_list";
   char *entry, *hname, *port_char, *ip_ad;
   int i, len, nentries;
   
   d_header(mname);

   if (thelist == (char *)NULL)
      {
      d_out("%s:list is null", mname);
      return;
      }
      
   len = strlen(thelist);
   nentries = ll_words(thelist, SL_LIST_DELIM);
      
   if ((entry = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[entry]", mname);
      return;
      }
         
   if ((hname = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[hname]", mname);
      free(entry);
      return;
      }

   if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[port_char]", mname);
      free(entry);
      free(hname);
      return;
      }

   if ((ip_ad = (char *)malloc(len + 1)) == (char *)NULL)
      {
      d_out("%s:alloc fail[ip_ad]", mname);
      free(entry);
      free(hname);
      free(port_char);
      return;
      }

   for(i = 1; i <= nentries; i++)
      {
      if (!ll_word(thelist, entry, i, SL_LIST_DELIM))
         {
         d_out("%s:error geting list entry[%d]", mname, i);
         free(entry);
         free(hname);
         free(port_char);
         free(ip_ad);
         return;
         }
            
      if (!command_word(entry, hname, 1))
         {
         d_out("%s:error getting host from entry[%d]", mname, i);
         free(entry);
         free(hname);
         free(port_char);
         free(ip_ad);
         return;
         }
            
      if (!command_word(entry, port_char, 2))
         {
         d_out("%s:error getting port from entry[%d]", mname, i);
         free(entry);
         free(hname);
         free(port_char);
         free(ip_ad);
         return;
         }
            
      if (command_words(entry) > 2)
         {
         if (!command_word(entry, ip_ad, 3))
            {
            d_out("%s:error getting ip from entry[%d]", mname, i);
            free(entry);
            free(hname);
            free(port_char);
            free(ip_ad);
            return;
            }
         }
      else
         ip_ad[0] = EOS;
                        
      if (strlen(ip_ad))
         d_out("socloc[%d]:host=%s,port=%s,ip=%s", i, hname, 
               port_char, ip_ad);
      else
         d_out("socloc[%d]:host=%s,port=%s", i, hname, port_char);
      }
         
   free(entry);
   free(hname);
   free(port_char);
   free(ip_ad);
   logman("%s:normal exit", mname);
}
#endif

#ifdef IPC_TCP
int d_sr(int typ, char *parm, char *reply)
#else
int d_sr(int typ, char *parm, char *reply, int size_reply)
#endif
{
   /* Send and receive a message to the server. Its ok if 'parm'
      is NULL or empty. Upon success, server reply load loaded
      into 'reply' which must be already allocated to
      sufficient size. Function returns a 'sockc' code. */

   char mname[] = "d_sr";
   char *mess;

   logman("%s:enter", mname);
   
   /* make sure we are connected */

   if (!is_connected())
      {
      logman("%s:not connected to any server", mname);
      return(SC_NO_SERVER);
      }

   if ((mess = (char *)malloc(SC_MAXCOMMAND)) == (char *)NULL)
      {
      logman("%s:alloc fail[mess]", mname);
      return(SC_MEMORY_FAIL);
      }

   memset(mess, 0, SC_MAXCOMMAND);

   // format send string

   if (parm == (char *)NULL || !strlen(parm))
      sprintf(mess, "%d", typ);
   else
      sprintf(mess, "%d %s", typ, parm);

   logman("%s:send buf=%s,l=%d", mname, mess, strlen(mess));
   
#ifdef IPC_TCP
   if (!ipc_send_receive(mess, reply))
#else
   if (!ipc_send_receive(mess, reply, size_reply))
#endif
      {
      logman("%s:error communicating with server", mname);
      free(mess);
#ifdef IPC_TCP
      serverport = 0;
      serverservice[0] = EOS;
#endif
      serverhost[0] = EOS;
      return(SC_VC_ERROR);
      }
         
   free(mess);
   logman("%s:normal exit,rc[ok],reply=%s,l=%d", mname,
                 reply, strlen(reply));
   return(SC_OK);
}

int get_token(char *keywrd)
{
   /* Get keyword token. */

   char mname[] = "get_token";
   int i;
   int token = SCOM_NOT_FOUND;

   /* static array of command words, notice the dummy zero position */

   static char *coms[] = { " ", "TERM", "STATUS", "CLIENT.LOG.OFF",
                           "CLIENT.LOG.ON", "CLIENT.LOG.STATUS",
                           "SERVER.LOG.OFF", "SERVER.LOG.ON",
                           "SERVER.LOG.STATUS", "CONNECT",
                           "SOCLOC.LIST", "SOCLOC.CONFIG.LIST",
                           "SOCLOC.GET", "SOCLOC.LOG.ON",
                           "SOCLOC.LOG.OFF", "SOCLOC.LOG.STATUS",
                           "SOCLOC.CONNECT", "SOCLOC.FIND",
                           "SOCLOC.SERVICE.NAME", "SERVICE.NAME",
                           "SOCLOC.VERSION", "VERSION",
                           "SOCLOC.CONFIG.FIND", "SOCLOC.STATUS",
                           "SOCLOC.CLIENT.LIST", "SOCLOC.CLIENT.UPDATE",
                           "SOCLOC.CLIENT.UPDATE.FILE", "SEND",
                           "SOCLOC.ADD", "SOCLOC.CONFIG.ADD",
                           "SOCLOC.DELETE", "SOCLOC.CONFIG.DELETE",
                           "SOCLOC.DUMP", "SOCLOC.CONFIG.DUMP",
                           "SOCLOC.TERM", "CLIENT.VERSION",
                           "SOCLOC.ON", "SOCLOC.OFF", "SOCLOC.TRANS.NUM",
                           "SOCLOC.CONNECT.NUM", "TRANS.NUM", "CONNECT.NUM" };

   logman("%s:enter,keywrd='%s'", mname, keywrd);
   
   /* check for 'OFF' keyword separately */

   if (!stricmp(keywrd, "OFF"))
      {
      logman("%s:found 'OFF' keyword", mname);      
      return(SCOM_OFF);
      }

   for(i = 1; i <= SCOM_MAXCOM; i++)      
      if (!stricmp(keywrd, coms[i]))
         {
         token = i;        
         break;
         }

   logman("%s:normal exit,token=%d", mname, token);
   return(token);
}

void d_display_connect_status(void)
{
   /* Display to the screen the status of the connected 'socloc'
      server and socket server keeping in mind the 'socloc'
      on/off flag. */

#ifdef IPC_TCP
   if (sk_flag)
      {      
      sloc_get_active_socloc(sk_host, &sk_port);      
      
      if (sk_port == 0)
         printf("%s:warning, no active socloc, use 'socloc.connect'\n",
                APNAME);
      
      if (is_connected())
         printf("%s:%s,%d/%s,%s,%d\n", APNAME, sk_host, sk_port, serverservice,
                serverhost, serverport);
      else
         printf("%s:%s,%d/?\n", APNAME, sk_host, sk_port);
      }
   else
      {
      if (is_connected())
         printf("%s:x/%s,%d\n", APNAME, serverhost, serverport);
      else
         printf("%s:x/?\n", APNAME);
      }
#else
   if (is_connected())
      printf("%s:%s\n", APNAME, serverhost);
   else
      printf("%s:x\n", APNAME);
#endif
}      
      
void d_header(char *mname)
{
   /* Output the function enter header if logging. */
   
   if (is_connected())
#ifdef IPC_TCP
      logman("%s:enter,host=%s,port=%d", mname, serverhost,
                    serverport);
#else
      logman("%s:enter:service=%s", mname, serverhost);
#endif
   else
      logman("%s:enter,no connection", mname);
}
      
void d_out(char *fmt,...)
{
   /* Output a message to the screen or use 'logman' to
      log the message. Output method depends on personal (client)
      logging status. Do not put a cr/lf at the end of the message.
      This will be automatically written to the end of the message. */

   char mes[MAXMES];
   va_list argptr;

   va_start(argptr, fmt);
   vsprintf(mes, fmt, argptr);
   
   if (logman_is_active())
      logman_nf(mes);
   else
      printf("%s\n", mes);
}

int is_connected(void)
{
   /* Indicate whether there is an active connection.
      Function returns 'TRUE' if there is a connection,
      'FALSE' otherwise. */

#ifdef IPC_TCP
   if (strlen(serverhost) && serverport != 0)
#else
   if (strlen(serverhost))
#endif
      return(TRUE);

   return(FALSE);
}

void term_app(void)
{
   // Close sockets in use (TCP) and shutdown all API's.

#ifdef IPC_TCP
   if (sk_flag)
      sloc_term_api();

   if (is_connected())
      (void)ipc_close();

#ifdef OS_WIN32
   WSACleanup();
#endif
#endif

   if (logman_is_active())
      logman_end();
}
