/*! 
  -----------------------------------------------------------------------------
 
  module: vcn11.h
 
  -----------------------------------------------------------------------------
 
  responsible:  BerndV
 
  special area: dbmgetf
 
  description:  implementation of command line DB-File-Get-Application

  version:      7.2. / 6.2 

  -----------------------------------------------------------------------------
 
                          Copyright (c) 1998-2005 SAP AG
 
  -----------------------------------------------------------------------------



    ========== licence begin  GPL
    Copyright (c) 1998-2005 SAP AG

    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, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end




*/

/* 
  -----------------------------------------------------------------------------
  includes
  -----------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>

#include "hcn14.h"


/* 
  -----------------------------------------------------------------------------
  something special for using the same code in 7.1 and 6.2
  -----------------------------------------------------------------------------
*/
#ifdef CN62

  /* bool for some compilers */
  #if defined (HP) || defined (AIX) || defined (OSF1) || defined (SUN)
    #define     bool    unsigned char
    #define     true    1
    #define     false   0
  #endif

#endif

/* 
  -----------------------------------------------------------------------------
  private declarations
  -----------------------------------------------------------------------------
*/
#define C_SWITCH         _T('-')
#define SW_NODE          _T("n")
#define SW_KEY           _T("k")
#define SW_FILE          _T("f")
#define SW_DATABASE      _T("d")
#define SW_QUIET         _T("q")
#define SW_USER          _T("u")
#define SW_LIST          _T("l")
#define SW_PARAM         _T("p")
#define SW_OPERATION     _T("op")
#define SW_TPSYSID       _T("tpi")
#define SW_TPCONN        _T("tpc")
#define SW_TPPROF        _T("tpp")

#define PRG_FATAL        1001
#define PRG_VERYFATAL    1002

#define DBM_OK           _T("OK")
#define DBM_END          _T("END")
#define DBM_CONTINUE     _T("CONTINUE")

typedef struct tcn11Options {
    const _TCHAR *   szApp;
    const _TCHAR *   szDB;
    const _TCHAR *   szUser;
    const _TCHAR *   szSysId;
    const _TCHAR *   szConn;
    const _TCHAR *   szProfile;
    const _TCHAR *   szNode;
    const _TCHAR *   szKey;
    const _TCHAR *   szFile;
    const _TCHAR *   szParam;
    const _TCHAR *   szOperation;
    int              nShow;
    bool       bQuiet;
    bool       bList;
    void   *   pSession;
    tsp00_Int4   nMaxData;
} tcn11Options;

/* 
  -----------------------------------------------------------------------------
  function: cn11FatalError
  -----------------------------------------------------------------------------
*/
static void cn11FatalError
      ( const char * errmsg,
        int          nExitCode )
{
    fprintf (stderr, _T("%s\n"), errmsg);
    exit (nExitCode);
} // end cn11FatalError

/* 
  -----------------------------------------------------------------------------
  function: cn11Usage
  -----------------------------------------------------------------------------
*/
static void cn11Usage 
      (tcn11Options * pOpt)
{
  fprintf (stderr, _T("usage: %s [<options>]\n"), pOpt->szApp);
  fprintf (stderr, _T("  <options>:\n"));
  fprintf (stderr, _T("    -%-4s dbname   (name of datbase)                \n"), SW_DATABASE);
  fprintf (stderr, _T("    -%-4s user,pwd (user for authorization)         \n"), SW_USER);
  fprintf (stderr, _T("    -%-4s node     (name of servernode)             \n"), SW_NODE);
  fprintf (stderr, _T("    -%-4s id       (id of database file)            \n"), SW_KEY);
  fprintf (stderr, _T("    -%-4s file     (name for local file - optional) \n"), SW_FILE);
  fprintf (stderr, _T("    -%-4s          (quiet mode)                     \n"), SW_QUIET);
  fprintf (stderr, _T("    -%-4s          (list file id's)                 \n"), SW_LIST);
  fprintf (stderr, _T("    -%-4s <param>  (DATE or LINE parameter)         \n"), SW_PARAM);
  fprintf (stderr, _T("    -%-4s <opid>   (SHRINK or DELETE operation)     \n"), SW_OPERATION);
  cn11FatalError(_T(""), PRG_FATAL);
} /* end cn11Usage */

/* 
  -----------------------------------------------------------------------------
  function: cn11ReadNextArg
  -----------------------------------------------------------------------------
*/
static char * cn11ReadNextArg
      ( char * szArgs[],
        int  & nCurArg,
        int    nMaxArgs,
        bool   bSwitch = false)
{
  int    nCurrent  = nCurArg + 1;
  char * pArgument = NULL;

  if (nCurrent < nMaxArgs) {
    if (bSwitch && szArgs[nCurrent][0] == C_SWITCH) {
      pArgument = &(szArgs[nCurrent][1]);
      nCurArg   = nCurrent;
    } else if (!bSwitch && szArgs[nCurrent][0] != C_SWITCH) {
      pArgument = szArgs[nCurrent];
      nCurArg   = nCurrent;
    } // end if
  } // end if

  return pArgument;
} // end cn11ReadNextArg

/* 
  -----------------------------------------------------------------------------
  function: cn11ParseOptions
  -----------------------------------------------------------------------------
*/
static void cn11ParseOptions 
      ( tcn11Options       * pOpt, 
        int                  argc, 
        char               * argv[] )
{
  int    argI      = 0;
  char * pSwitch   = NULL;
  char * pValue    = NULL;

  /* init options struct */
  pOpt->szApp      = argv[0];
  pOpt->szDB       = NULL;
  pOpt->szUser     = NULL;
  pOpt->szSysId    = NULL;
  pOpt->szConn     = NULL;
  pOpt->szProfile  = NULL;
  pOpt->szKey      = NULL;
  pOpt->szFile     = NULL;
  pOpt->szParam    = NULL;
  pOpt->szOperation= NULL;
  pOpt->nShow      = 0;
  pOpt->szNode     = "";
  pOpt->bQuiet     = false;
  pOpt->bList      = false;

  /* read options form command line into struct */
  pSwitch = cn11ReadNextArg(argv, argI, argc, true);

  while (pSwitch != NULL) {

    // * Node -n ******************************
    if (strcmp(pSwitch, SW_NODE) == 0) {
      pOpt->szNode = cn11ReadNextArg(argv, argI, argc);
      if (pOpt->szNode == NULL) {
        cn11FatalError ("Error, missing node name!", PRG_VERYFATAL);
      } // end if

    // * Database -d **************************
    } else if (strcmp(pSwitch, SW_DATABASE) == 0) {
      pOpt->szDB = cn11ReadNextArg(argv, argI, argc);

    // * User -u ******************************
    } else if (strcmp(pSwitch, SW_USER) == 0) {
      pOpt->szUser = cn11ReadNextArg(argv, argI, argc);

    // * TP sysid -tpi ************************
    } else if (strcmp(pSwitch, SW_TPSYSID) == 0) {
      pOpt->szSysId = cn11ReadNextArg(argv, argI, argc);

    // * TP conn -tpc *************************
    } else if (strcmp(pSwitch, SW_TPCONN) == 0) {
      pOpt->szConn = cn11ReadNextArg(argv, argI, argc);

    // * TP prifile -tpp **********************
    } else if (strcmp(pSwitch, SW_TPPROF) == 0) {
      pOpt->szProfile = cn11ReadNextArg(argv, argI, argc);

    // * File -f ******************************
    } else if (strcmp(pSwitch, SW_FILE) == 0) {
      pOpt->szFile = cn11ReadNextArg(argv, argI, argc);

    // * Param -p *****************************
    } else if (strcmp(pSwitch, SW_PARAM) == 0) {
      pOpt->szParam = cn11ReadNextArg(argv, argI, argc);

    // * Operation -op ************************
    } else if (strcmp(pSwitch, SW_OPERATION) == 0) {
      pOpt->szOperation = cn11ReadNextArg(argv, argI, argc);

    // * Key -k *******************************
    } else if (strcmp(pSwitch, SW_KEY) == 0) {
      pOpt->szKey = cn11ReadNextArg(argv, argI, argc);

    // * Quiet -q *****************************
    } else if (strcmp(pSwitch, SW_QUIET) == 0) {
      pOpt->bQuiet = true;

    // * List -l ******************************
    } else if (strcmp(pSwitch, SW_LIST) == 0) {
      pOpt->bList = true;
      pValue = cn11ReadNextArg(argv, argI, argc);
      if (pValue != NULL) {
        pOpt->nShow = atoi(pValue);
      } // end if

    // ****************************************
    } else {
      cn11Usage (pOpt);
    } // end if

    pSwitch = cn11ReadNextArg(argv, argI, argc, true);
  } /* end while */

  if (pOpt->szDB == NULL) {
    cn11FatalError ("Error, missing database name!", PRG_VERYFATAL);
  } // end if
  if (pOpt->szKey == NULL && !pOpt->bList) {
    cn11FatalError ("Error, missing file identifier!", PRG_VERYFATAL);
  } // end if
  if (pOpt->szKey != NULL && pOpt->bList) {
    cn11FatalError ("Error, don't specify -l with -k!", PRG_VERYFATAL);
  } // end if
  if (pOpt->szUser != NULL && (pOpt->szSysId != NULL || pOpt->szConn != NULL || pOpt->szProfile != NULL)) {
    cn11FatalError ("Error, don't specify -u with -tpi/-tpc/-tpp!", PRG_VERYFATAL);
  } // end if
  if ( ( pOpt->szConn != NULL || pOpt->szSysId != NULL || pOpt->szProfile != NULL ) &&
       ( pOpt->szConn == NULL || pOpt->szSysId == NULL || pOpt->szProfile == NULL )    ) {
    cn11FatalError ("Error, incomplete TP data (-tpi/-tpc/-tpp)!", PRG_VERYFATAL);
  } // end if

} // end cn11ParseOptions

/* 
  -----------------------------------------------------------------------------
  function: cn11CheckFile
  -----------------------------------------------------------------------------
*/
static void cn11CheckFile
      ( tcn11Options       * pOpt )
{
  FILE   * hFile;
  char     cAnswer;

  // only if quiet -q not specified
  if (!pOpt->bQuiet && pOpt->szFile != NULL) {
    // open for reading
    hFile = fopen(pOpt->szFile, "r");
    
    if (hFile != NULL) {
      // Ooops, file exists -> ask the user
      fclose(hFile);
      fprintf(stderr, "File %s exists! Overwrite (y/n)?\n", pOpt->szFile);
      cAnswer = getchar();
      switch (cAnswer) {
        case 'y':
        case 'Y':
          // ok, go on
          break;
        default:
          // in other case terminate
          cn11FatalError ("Execution aborted!", PRG_FATAL);
          break;
      } // end switch
    } // end if
  } // end if

} // end cn11CheckFile

/* 
  -----------------------------------------------------------------------------
  function: cn11Command 
  -----------------------------------------------------------------------------
*/
static char * cn11Command 
      ( tcn11Options       * pOpt,
        char               * pData,
        tsp00_Int4           * nReply)
{
  bool             bRc     = true;
  tsp00_ErrTextc   szErr;
  tsp00_Int4         commErr = DBMAPI_OK_CN14;
  long             nCmdLen       = 0;
  tsp00_Int4         nReplyLen     = 0;
  char           * pReply;

  // compute command len and reply position
  nCmdLen = (long) strlen (pData) + 1; /* null byte!!! */
  pReply = pData + nCmdLen;

  // execute  command
  nReplyLen = pOpt->nMaxData - nCmdLen;
  commErr = cn14cmdExecute (pOpt->pSession, pData, nCmdLen, pReply, &nReplyLen, szErr);

  // something wrong?
  if (commErr != DBMAPI_OK_CN14) {
    fprintf (stderr, "\nDBM-Api error (%d %s)\n", commErr, (char *) szErr);
    pReply = NULL;
  } // end if 

  *nReply = nReplyLen;

  return pReply;
} // end cn11Command 

/* 
  -----------------------------------------------------------------------------
  function: cn11CopyFile
  -----------------------------------------------------------------------------
*/
static int cn11CopyFile
      ( tcn11Options       * pOpt )
{
  char          * pData        = NULL;
  const char    * pReply       = NULL;
  long            nHandle      = 0;
  FILE          * hFile        = NULL;
  bool            bContinue    = true;
  bool            bTmpContinue = true;
  const char    * pNewLine     = NULL;
  long            nSize        = 0;
  long            nFullSize    = 0;
  long            nWritten     = 0;
  long            nPacketSize  = 0;
  int             nReturn      = 0;
  tsp00_Int4        nReplyLen    = 0; 
  const char    * pPayLoad     = NULL;
  tsp00_ErrTextc  szError;
  tsp00_Int4        nError       = 0;
  tsp00_Int4        nDummy1;
  tsp00_Int4        nDummy2;

  cn14packetstats(pOpt->pSession, &(pOpt->nMaxData), &nDummy1, &nDummy2);
  pData = new char[pOpt->nMaxData];

  if (pData != NULL) {

    if (pOpt->szFile != NULL) {
      hFile = fopen(pOpt->szFile, "wb");
    } else {
      hFile = stdout;
    } // end if

    if (hFile) {

      // DBMServer Command
      sprintf (pData, "file_getfirst %s %s", pOpt->szKey, pOpt->szParam == NULL ? "" : pOpt->szParam);
      pReply = cn11Command(pOpt, pData, &nReplyLen);

      // read DBMServer Reply
      while (pReply != NULL && bContinue) {

        bContinue    = false;
        bTmpContinue = false;

        if (cn14analyzeDbmAnswer (pOpt->pSession, 
                                  (const void **) &pPayLoad, 
                                  &nReplyLen, 
                                  &nError, 
                                  szError) != DBMAPI_OK_CN14) {
          fprintf(stderr, "\nError while receiving data! Operation aborted!\n");
          fprintf(stderr, "%ld, %s\n", (long) nError, (char *) szError);
          if (pPayLoad != NULL) {
            fprintf(stderr, "%.*s\n", (int) nReplyLen, (char *) pPayLoad);
          } // end if
          nReturn = PRG_FATAL;
        } else {
          // look for Handle
          if (pPayLoad != NULL) {
            pReply = pPayLoad;
            pNewLine = strstr(pReply, "\n");
            if (pNewLine != NULL) {
              nHandle = atol(pReply);
            
              // Look for end/continue
              pReply = pNewLine + 1;
              pNewLine = strstr(pReply, "\n");
              if (pNewLine != NULL) {
                if (strstr(pReply, DBM_CONTINUE) != NULL) {
                  bTmpContinue = true;
                } // end if

                // Look for packetsize
                pReply = pNewLine + 1;
                pNewLine = strstr(pReply, "\n");
                if (pNewLine != NULL) {
                  sscanf(pReply, "%ld %ld", &nSize, &nPacketSize);
                  nFullSize = nSize == 0 ? nFullSize : nSize;
                  // look for data
                  pReply = pNewLine + 1;
                  if (nPacketSize > 0) {
                    if (fwrite(pReply, nPacketSize, 1, hFile) == 1) {
                      bContinue = bTmpContinue;
                      nWritten = nWritten + nPacketSize;
                      if (!pOpt->bQuiet && pOpt->szFile != NULL) {
                        fprintf(stdout, "%10ld Bytes of %10ld Bytes received!\r", nWritten, nFullSize);
                      } // end if
                    } else {
                      fprintf(stderr, "\nError while writing file %s! Operation aborted!\n", pOpt->szFile);
                      nReturn = PRG_FATAL;
                    } // end if
                  } // end if
                } // end if
              } // end if
            } // end if
          } // end if

        } /* end if */
            
        if (bContinue) {
          // DBMServer Command
          sprintf (pData, "file_getnext %s %ld", pOpt->szKey, nHandle);
          pReply = cn11Command(pOpt, pData, &nReplyLen);
        } // end if
      } // end while

      // print statistic and close file
      if (!pOpt->bQuiet) {
        if (pOpt->szFile == NULL) {
          fprintf(stdout, "** EOF **\n");
        } // end if
        fprintf(stdout, "%10ld Bytes of %10ld Bytes received!\n", nWritten, nFullSize);
      } // end if
      if (pOpt->szFile != NULL) {
        fclose(hFile);
      } // end if
    } else {
      fprintf(stderr, "Error during open file %s! Operation aborted!\n", pOpt->szFile);
      nReturn = PRG_FATAL;
    } // end if

    delete pData;
  } else {
    fprintf(stderr, "Error during memory allocation! Operation aborted!\n");
    nReturn = PRG_FATAL;
  } // end if

  return nReturn;
} // end cn11CopyFile

/* 
  -----------------------------------------------------------------------------
  function: cn11ListIds
  -----------------------------------------------------------------------------
*/
static int cn11ListIds
      ( tcn11Options       * pOpt )
{
  char           * pData        = NULL;
  char           * pReply       = NULL;
  FILE           * hFile        = NULL;
  const _TCHAR   * pLine        = NULL;
  const _TCHAR   * pKomma       = NULL;
  int              nReturn      = 0;
  tsp00_Int4         nReplyLen    = 0; 
  const char     * pPayLoad     = NULL;
  tsp00_ErrTextc   szError;
  tsp00_Int4         nError       = 0;
  tsp00_Int4         nDummy1;
  tsp00_Int4         nDummy2;

  cn14packetstats(pOpt->pSession, &(pOpt->nMaxData), &nDummy1, &nDummy2);
  pData = new char[pOpt->nMaxData];

  if (pData != NULL) {

    if (pOpt->szFile != NULL) {
      hFile = fopen(pOpt->szFile, "wb");
    } else {
      hFile = stdout;
    } // end if

    if (hFile) {

      // DBMServer Command
      if (pOpt->nShow > 0) {
        sprintf (pData, "file_getlist %d", pOpt->nShow);
      } else {
        sprintf (pData, "file_getlist");
      } // end if
      pReply = cn11Command(pOpt, pData, &nReplyLen);

      // read DBMServer Reply
      if (cn14analyzeDbmAnswer (pOpt->pSession, 
                                (const void **) &pPayLoad, 
                                &nReplyLen, 
                                &nError, 
                                szError) != DBMAPI_OK_CN14) {
        if (nError ==  -24946) {
          sprintf (pData, "file_getlist");
          pReply = cn11Command(pOpt, pData, &nReplyLen);
          if (cn14analyzeDbmAnswer (pOpt->pSession, 
                                    (const void **) &pPayLoad, 
                                    &nReplyLen, 
                                    &nError, 
                                    szError) != DBMAPI_OK_CN14) {
            fprintf(stderr, "\nError while receiving data! Operation aborted!\n");
            fprintf(stderr, "%ld, %s\n", (long) nError, (char *) szError);
            nReturn = PRG_FATAL;
          } // end if
        } else {
          fprintf(stderr, "\nError while receiving data! Operation aborted!\n");
          fprintf(stderr, "%ld, %s\n", (long) nError, (char *) szError);
          nReturn = PRG_FATAL;
        } // end if
      } // end if

      if (nReturn != PRG_FATAL) {
        if (pPayLoad != NULL) {
          pLine = pPayLoad;
          pLine = strstr(pLine, _T("\n"));

          while (pLine != NULL) {
            pLine++;
            pKomma = strstr(pLine, _T("\t")); 
            if (pKomma != NULL) {
              fprintf(hFile, "%.*s\n", (int) (pKomma - pLine), pLine);
            } // end if

            pLine = strstr(pLine, _T("\n"));
          } // end while

        } // end if
      } // end if

      if (pOpt->szFile != NULL) {
        fclose(hFile);
      } // end if
    } else {
      fprintf(stderr, "Error during open file %s! Operation aborted!\n", pOpt->szFile);
      nReturn = PRG_FATAL;
    } // end if

    delete pData;
  } else {
    fprintf(stderr, "Error during memory allocation! Operation aborted!\n");
    nReturn = PRG_FATAL;
  } // end if

  return nReturn;

} // end cn11ListIds

/* 
  -----------------------------------------------------------------------------
  function: cn11ModifyFile
  -----------------------------------------------------------------------------
*/
static int cn11ModifyFile
      ( tcn11Options       * pOpt )
{
  char           * pData        = NULL;
  char           * pReply       = NULL;
  FILE           * hFile        = NULL;
  const _TCHAR   * pLine        = NULL;
  const _TCHAR   * pKomma       = NULL;
  int              nReturn      = 0;
  tsp00_Int4         nReplyLen    = 0; 
  const char     * pPayLoad     = NULL;
  tsp00_ErrTextc   szError;
  tsp00_Int4         nError       = 0;
  tsp00_Int4         nDummy1;
  tsp00_Int4         nDummy2;

  cn14packetstats(pOpt->pSession, &(pOpt->nMaxData), &nDummy1, &nDummy2);
  pData = new char[pOpt->nMaxData];

  if (pData != NULL) {

    if (pOpt->szFile != NULL) {
      hFile = fopen(pOpt->szFile, "wb");
    } else {
      hFile = stdout;
    } // end if

    if (hFile) {

      // DBMServer Command
      sprintf (pData, "file_operation %s OP=%s %s",  pOpt->szKey, pOpt->szOperation,
                                                     pOpt->szParam == NULL ? "" : pOpt->szParam);
      pReply = cn11Command(pOpt, pData, &nReplyLen);

      // read DBMServer Reply
      if (cn14analyzeDbmAnswer (pOpt->pSession, 
                                (const void **) &pPayLoad, 
                                &nReplyLen, 
                                &nError, 
                                szError) != DBMAPI_OK_CN14) {
        fprintf(stderr, "\nError while receiving data! Operation aborted!\n");
        fprintf(stderr, "%ld, %s\n", (long) nError, (char *) szError);
        nReturn = PRG_FATAL;
      } // end if

      if (nReturn != PRG_FATAL) {
        fprintf(hFile, "OK\n");
      } // end if

      if (pOpt->szFile != NULL) {
        fclose(hFile);
      } // end if
    } else {
      fprintf(stderr, "Error during open file %s! Operation aborted!\n", pOpt->szFile);
      nReturn = PRG_FATAL;
    } // end if

    delete pData;
  } else {
    fprintf(stderr, "Error during memory allocation! Operation aborted!\n");
    nReturn = PRG_FATAL;
  } // end if

  return nReturn;

} // end cn11ModifyFile

/* 
  -----------------------------------------------------------------------------
  function: main
  -----------------------------------------------------------------------------
*/
int main (int argc, char* argv[])
{
  int                 nExit    = 0;
  tcn11Options        aOpt;
  tsp00_Int4            commErr;
  tsp00_ErrTextc      szErr;
  tsp00_ErrTextc      szError;
  tsp00_NodeIdc       szNode;
  tsp00_DbNamec       szDB;
  tsp00_VFilenamec    szFile;
  tsp00_C64c          szUser;
  tsp00_C8c           szSysId;
  tsp00_C30c          szConn;
  tsp00_Pathc         szProfile;

  // read arguments
  cn11ParseOptions (&aOpt, argc, argv);

  // check the output file
  cn11CheckFile(&aOpt);

  // connect  
  if (aOpt.szUser != NULL) {
    commErr = cn14connectDBMUsr (szNode.rawAssign(aOpt.szNode), 
                                 szDB.rawAssign(aOpt.szDB), 
                                 szFile.rawAssign(""), 
                                 szUser.rawAssign(aOpt.szUser), 
                                 &(aOpt.pSession), 
                                 szErr);
  } else if (aOpt.szSysId != NULL) {
    commErr = cn14connectDBMTp (szNode.rawAssign(aOpt.szNode), 
                                szDB.rawAssign(aOpt.szDB), 
                                szFile.rawAssign(""), 
                                szSysId.rawAssign(aOpt.szSysId), 
                                szConn.rawAssign(aOpt.szConn), 
                                szProfile.rawAssign(aOpt.szProfile),  
                                &(aOpt.pSession), 
                                szErr);
  } else {
    commErr = cn14connectDBM (szNode.rawAssign(aOpt.szNode), 
                              szDB.rawAssign(aOpt.szDB), 
                              szFile.rawAssign(""), 
                              &(aOpt.pSession), 
                              szErr);
  } // end if

  if (commErr != DBMAPI_OK_CN14) {
    sprintf (szError, "Connection failed to %s at %s: %s\n",  DEFAULT_DBMPGM_CN14, aOpt.szNode, (char *) szErr);
	  cn11FatalError(szError, PRG_FATAL);
  } /* end if */

  // copy the file
  if (aOpt.bList) {
    nExit = cn11ListIds(&aOpt);
  } else if (aOpt.szOperation != NULL) {
    nExit = cn11ModifyFile(&aOpt);
  } else {
    nExit = cn11CopyFile(&aOpt);
  } // end if

  // always disconnect 
  cn14release (&(aOpt.pSession));

  // exit program
  exit (nExit);

  return (nExit);
} // end main
