home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / sna / shared / cpicerr.c < prev    next >
C/C++ Source or Header  |  1997-04-09  |  78KB  |  2,048 lines

  1. /*****************************************************************************
  2.  *
  3.  *  MODULE NAME: CPICERR.C
  4.  *
  5.  *  COPYRIGHTS:
  6.  *             This module contains code made available by IBM
  7.  *             Corporation on an AS IS basis.  Any one receiving the
  8.  *             module is considered to be licensed under IBM copyrights
  9.  *             to use the IBM-provided source code in any way he or she
  10.  *             deems fit, including copying it, compiling it, modifying
  11.  *             it, and redistributing it, with or without
  12.  *             modifications.  No license under any IBM patents or
  13.  *             patent applications is to be implied from this copyright
  14.  *             license.
  15.  *
  16.  *             A user of the module should understand that IBM cannot
  17.  *             provide technical support for the module and will not be
  18.  *             responsible for any consequences of use of the program.
  19.  *
  20.  *             Any notices, including this one, are not to be removed
  21.  *             from the module without the prior written consent of
  22.  *             IBM.
  23.  *
  24.  *  AUTHOR:    Peter J. Schwaller
  25.  *             VNET:     PJS at RALVM6           Tie Line: 444-4376
  26.  *             Internet: pjs@ralvm6.vnet.ibm.com     (919) 254-4376
  27.  *
  28.  *             John Q. Walker
  29.  *             VNET:     JOHNQ at RALVM6         Tie Line: 444-4414
  30.  *             Internet: johnq@ralvm6.vnet.ibm.com   (919) 254-4414
  31.  *
  32.  *  FUNCTION:  Contains procedures to be called for handling
  33.  *             unexpected CPI-C return codes.
  34.  *             Contains procedures to be called for handling the
  35.  *             CPI-C error information cpicerr.
  36.  *
  37.  *  AVAILABILITY:
  38.  *             These sample programs and source are also available on
  39.  *             CompuServe through the APPC Information Exchange.  To get
  40.  *             to the APPC forum just type 'GO APPC' from any CompuServe
  41.  *             prompt.  The samples are available in the Sample Programs
  42.  *             library section.  Just search on the keyword CPICPGMS to
  43.  *             find all the samples in this series.
  44.  *
  45.  *             Updates for the sample programs and support for many more
  46.  *             CPI-C platforms will also be made available on CompuServe.
  47.  *
  48.  *  RELATED FILES:
  49.  *             CPICERR.H
  50.  *
  51.  *  CHANGE HISTORY:
  52.  *  Date       Description
  53.  *  08/05/92   Version 2.31 of APING, ATELL and AREXEC released to CompuServe.
  54.  *             This version was also distributed at the APPC/APPN Platform
  55.  *             Developer's Conference held in Raleigh, NC.
  56.  *  08/13/92   Changed all printf and fprintf calls to use a write_*() call.
  57.  *             Changed cpicerr_handle_rc() to a macro referencing a new call,
  58.  *             cpicerr_handle_rc_extended().  The macro adds the current
  59.  *             source file and line number to improve source code debugging.
  60.  *  08/15/92   Changed cpicerr_exchange_version() to receive 128 bytes
  61.  *             instead of 3 bytes.  This change was also made to the
  62.  *             NS/DOS ship code.
  63.  *  08/18/92   Removed extra newline in cpicerr_show_rc().
  64.  *  09/02/92   Fixed bug in cpicerr_log_cpicerr() when the log_file_path
  65.  *             was a zero length string.
  66.  *  11/15/92   Changed reply structure to include 2 byte indicator.
  67.  *  11/17/92   Added send/receipt of operating system string.
  68.  *             Added cpicerr_exchange_version_plus() to return the string.
  69.  *
  70.  *****************************************************************************/
  71.  
  72. /*****************************************************************************
  73.  *
  74.  * OVERVIEW OF CPICERR CALLS
  75.  *
  76.  * cpicerr_new()                      Creates a CPICERR object.
  77.  *                                    This must be done before any other
  78.  *                                    cpicerr calls can be used.
  79.  *
  80.  * These calls set values in the cpicerr object structure and affect how
  81.  * cpicerr_handle_rc reacts to errors.
  82.  *
  83.  * cpicerr_set_conv_id()              Used to extract conversation state info
  84.  * cpicerr_set_exit_level()           Level of error on which to exit
  85.  * cpicerr_set_log_file_name()        What filename to use for logging
  86.  * cpicerr_set_log_file_path()        Where the filename is
  87.  * cpicerr_set_log_level()            Level of error on which to log errors
  88.  * cpicerr_set_major_version()        8 bit int - see cpicerr_exchange_version
  89.  * cpicerr_set_minor_version()        8 bit int - see cpicerr_exchange_version
  90.  * cpicerr_set_program_name()         String - Output as part of log info
  91.  * cpicerr_set_program_info()         String - Output as part of log info
  92.  * cpicerr_set_show_level()           Level of error on which to show errors
  93.  *
  94.  * cpicerr_handle_rc()                Should be called by the program for all
  95.  *                                    UNEXPECTED return codes.
  96.  *                                    Functions performed are:
  97.  *                                       Classification of the return code
  98.  *                                       Showing partial info to end user
  99.  *                                       Logging complete info to disk
  100.  *                                    This is a macro that actually expands
  101.  *                                    to cpicerr_handle_rc_extended().
  102.  *
  103.  * cpicerr_exchange_version()         Exchanges version numbers with the
  104.  *                                    partner.  Very useful when supporting
  105.  *                                    multiple versions of a program.
  106.  *
  107.  * cpicerr_destroy()                  Destroys the CPICERR  object.
  108.  *
  109.  *
  110.  * cpicerr_classify_rc()              These are internal calls used by
  111.  * cpicerr_show_rc()                  other cpicerr_handle_rc.
  112.  * cpicerr_log_rc()
  113.  * cpicerr_log_cpicerr()
  114.  * cpicerr_get_message()
  115.  * cpicerr_set_rc_info()
  116.  * cpicerr_show_product_info()
  117.  *
  118.  *****************************************************************************/
  119. #if defined(WIN32) || defined(WINDOWS)                                /*WIN32*/
  120. #include <windows.h>                                                  /*WIN32*/
  121. #define GET_OS2_SENSE_DATA                                            /*WIN32*/
  122. #endif                                                                /*WIN32*/
  123.  
  124. #include "wincpic.h"
  125.  
  126. #ifdef GET_OS2_SENSE_DATA
  127. #include <winappc.h>
  128. #endif
  129.  
  130. /* Set up constant declarations */
  131. #include "cpicdefs.h"
  132.  
  133. /* Collection of routines with special ported version for each platform */
  134. #include "cpicport.h"
  135.  
  136. #include <stdio.h>                          /* C library includes            */
  137. #include <stdlib.h>
  138. #include <string.h>
  139.  
  140. #include <time.h>
  141.  
  142. #include "cpicerrs.h"                       /* CPI-C error handling vars.    */
  143.  
  144. /*
  145.  * Each of the following is a list of messages, which are actually defined
  146.  * in this file below.  The messages are grouped together.  For example,
  147.  * all of the return code messages are in the cpicerr_return_codes list.
  148.  */
  149. extern CPICERR_MESSAGE cpicerr_verbs_short[];
  150. extern CPICERR_MESSAGE cpicerr_verbs_long[];
  151. extern CPICERR_MESSAGE cpicerr_return_codes[];
  152. extern CPICERR_MESSAGE cpicerr_rc_classes[];
  153. extern CPICERR_MESSAGE cpicerr_states_conv[];
  154. extern CPICERR_MESSAGE cpicerr_conv_types[];
  155. extern CPICERR_MESSAGE cpicerr_sync_levels[];
  156.  
  157. /*****************************************************************************
  158.  * Function prototypes for internal routines.  In general, these should
  159.  * not be called directly by an application program.
  160.  *****************************************************************************/
  161. void   cpicerr_classify_rc(      CM_RETURN_CODE       conv_rc,
  162.                                  CPIC_RC_HANDLING *   classification);
  163. void   cpicerr_show_rc(          CPICERR *            cpicerr);
  164. void   cpicerr_log_rc(           CPICERR *            cpicerr,
  165.                                  FILE *               log_file);
  166. int    cpicerr_log_cpicerr(      CPICERR *            cpicerr,
  167.                                  char *               file_name,
  168.                                  int                  file_line);
  169. char * cpicerr_get_message(      CPICERR_MESSAGE_TYPE message_type,
  170.                                  CM_INT32             index);
  171. void   cpicerr_set_rc_info(      CPICERR *            cpicerr,
  172.                                  CPIC_VERB_INDEX      verb_index,
  173.                                  CM_RETURN_CODE       conv_rc);
  174. void   cpicerr_show_product_info(CPICERR *            cpicerr);
  175.  
  176. /*****************************************************************************
  177.  * The following function prototypes and macros are used only by the
  178.  * OS/2 specific code used to obtain the sense data after an
  179.  * allocation failure.  They are not necessary, if GET_OS2_SENSE_DATA
  180.  * has not been externally defined (with the -D compile flag).
  181.  *****************************************************************************/
  182. #ifdef GET_OS2_SENSE_DATA
  183. int    cpicerr_os2_appc_allocate(CPICERR *            cpicerr);
  184.  
  185. int
  186. parse_destination(char * in_string,
  187.                   char * plu_alias,
  188.                   char * fqplu_name);
  189.  
  190.  
  191.  
  192.  
  193. /* Macro BLANK_STRING sets string to all blanks */
  194. #define BLANK_STRING(str)  memset(str,(int)' ',sizeof(str))
  195.  
  196. #undef CLEAR_VCB
  197. /* Macro CLEAR_VCB sets the APPC verb control block to zeros */
  198. #define CLEAR_VCB(vcb)     memset((char *)&vcb,(int)'\0',sizeof(vcb))
  199.  
  200. /* convert a string to uppercase, up to length specified */
  201. #define TOUPPER_STRING(str,length) \
  202.                            {int i; for (i=0;i < length;i ++) \
  203.                            {str[i] = (char)toupper(str[i]);}}
  204.  
  205. /* convert an ASCII blank padded string to an ASCIIZ string without pads */
  206. #define SNA2STRING(outstr, instr, max_length) \
  207.                    {int i; for (i=0;i < max_length && instr[i] != ' ';i ++) \
  208.                    {outstr[i] = instr[i];} outstr[i] = '\0';}
  209.  
  210. #endif
  211.  
  212.  
  213. /*
  214.  * The error REPLY routines below are experimental and may change
  215.  * at any time!
  216.  */
  217.  
  218. void
  219. cpicerr_show_reply(CPICERR_REPLY * reply)
  220. {
  221.     unsigned short length;
  222.     unsigned short offset;
  223.     unsigned short indicator;
  224.     int            rc = 0;
  225.  
  226.     if (reply->length >= CPICERR_REPLY_MIN_LENGTH) {
  227.         write_error(
  228.             "\nAn application error was detected by the partner:\n");
  229.         indicator =
  230.           convert_short_from_network(
  231.               *((unsigned short*)&reply->buffer[CPICERR_REPLY_INDICATOR]));
  232.         if (indicator == CPICERR_REPLY_INDICATOR_VALUE) {
  233.             write_error("Response:              %d\n",
  234.                         (int)reply->buffer[CPICERR_REPLY_RESPONSE]);
  235.             write_error("Message Category:      %u\n",
  236.               convert_short_from_network(
  237.                   *((unsigned short*)&reply->buffer[CPICERR_REPLY_CATEGORY])));
  238.             write_error("Primary Code:          %ld\n",
  239.               convert_long_from_network(
  240.                   *((unsigned long *)&reply->buffer[CPICERR_REPLY_PRIMARY])));
  241.             write_error("Secondary Code:        %ld\n",
  242.               convert_long_from_network(
  243.                  *((unsigned long *)&reply->buffer[CPICERR_REPLY_SECONDARY])));
  244.  
  245.  
  246.             if (reply->length >=
  247.                 (unsigned int)(CPICERR_REPLY_MIN_LENGTH + 2)) {
  248.                 length = convert_short_from_network(
  249.                 *((unsigned short *)
  250.                                &reply->buffer[CPICERR_REPLY_PRIMARY_LENGTH]));
  251.  
  252.                 if (reply->length >=
  253.                     (unsigned int)(CPICERR_REPLY_PRIMARY_TEXT+length)) {
  254.                     reply->buffer[length + CPICERR_REPLY_PRIMARY_TEXT - 1] =
  255.                                                                           '\0';
  256.                     write_error("%s\n",
  257.                                 &reply->buffer[CPICERR_REPLY_PRIMARY_TEXT]);
  258.                     offset = CPICERR_REPLY_PRIMARY_TEXT + length;
  259.                     if (reply->length >= 2+offset) {
  260.                         length = convert_short_from_network(
  261.                                   *((unsigned short *)&reply->buffer[offset]));
  262.                         if (reply->length >= (offset+ 2 +length)) {
  263.                             reply->buffer[length + offset + 2] = '\0';
  264.                             write_error("%s\n", &reply->buffer[offset+2]);
  265.                         }
  266.                         else {
  267.                             rc = 1;
  268.                         }
  269.                     }
  270.                     else {
  271.                         rc = 1;
  272.                     }
  273.                 }
  274.                 else {
  275.                     rc = 1;
  276.                 }
  277.             }
  278.             else {
  279.                 write_error("No text strings were sent.\n");
  280.             }
  281.         }
  282.         else {
  283.             write_error("Record received was not a reply structure.\n");
  284.         }
  285.  
  286.     }
  287.     else {
  288.         rc = 1;
  289.     }
  290.     if (rc) {
  291.         write_error("Reply length error in cpicerr_show_reply().\n");
  292.     }
  293. }
  294.  
  295.  
  296. CPICERR_REPLY *
  297. cpicerr_create_reply(unsigned int primary_message_buffer_size,
  298.                      unsigned int secondary_message_buffer_size)
  299. {
  300.     CPICERR_REPLY * reply;
  301.  
  302.     reply = calloc(1, sizeof(CPICERR_REPLY));
  303.     if (reply == NULL) {
  304.         return NULL;
  305.     }
  306.  
  307.     reply->buffer_length = CPICERR_REPLY_MIN_LENGTH+
  308.                            primary_message_buffer_size+1 +
  309.                            secondary_message_buffer_size+1 +
  310.                            4;          /* two length fields */
  311.     reply->buffer = calloc(reply->buffer_length, 1);
  312.     if (reply == NULL) {
  313.         return NULL;
  314.     }
  315.  
  316.     return reply;
  317. }
  318.  
  319. void
  320. cpicerr_destroy_reply(CPICERR_REPLY * reply)
  321. {
  322.     /*
  323.      * Make sure we don't free any NULL pointers!
  324.      */
  325.     if (reply != NULL) {
  326.         if (reply->buffer != NULL) {
  327.             free(reply->buffer);
  328.         }
  329.         free(reply);
  330.     }
  331. }
  332.  
  333.  
  334.  
  335. /*
  336.  * Requires that cpicerr_set_conv_id() has been called.
  337.  */
  338. int    cpicerr_recv_appl_error(CPICERR *  cpicerr,
  339.                                CPICERR_REPLY * reply)
  340. {
  341.     CM_RETURN_CODE cm_rc;
  342.     CM_INT32  rts_received;
  343.     CM_INT32  max_receive_len;
  344.     CM_INT32  what_received;
  345.     CM_INT32  received_len;
  346.     CM_INT32  status_received;
  347.  
  348.     max_receive_len = reply->buffer_length;
  349.  
  350.     cmrcv (cpicerr->conversation_id,
  351.            reply->buffer,
  352.            &max_receive_len,
  353.            &what_received,
  354.            &received_len,
  355.            &status_received,
  356.            &rts_received,
  357.            &cm_rc);
  358.  
  359.     reply->length = (unsigned int)received_len;
  360.  
  361.     return reply->buffer[0];
  362. }
  363.  
  364.  
  365. void
  366. cpicerr_set_error_reply(CPICERR_REPLY * reply,
  367.                         REPLY_RESPONSE  response,
  368.                         unsigned int    message_category,
  369.                         unsigned long   primary_code,
  370.                         char *          primary_message_text,
  371.                         unsigned long   secondary_code,
  372.                         char *          secondary_message_text)
  373. {
  374.     unsigned int length = 0;
  375.     unsigned short string_length;
  376.  
  377.     /*
  378.      * Check and see that there is at least enough space in the reply_buffer
  379.      * to sent the required fields.  If there is not enough space, return
  380.      * 0 (zero) to the caller, indicating that no bytes were copied into
  381.      * the reply_buffer.
  382.      */
  383.     if (reply->buffer_length < CPICERR_REPLY_MIN_LENGTH) {
  384.         reply->length = 0;
  385.         return/* 0 */;
  386.     }
  387.  
  388.     *((unsigned short *)&reply->buffer[CPICERR_REPLY_INDICATOR]) =
  389.                        convert_short_to_network(CPICERR_REPLY_INDICATOR_VALUE);
  390.     reply->buffer[CPICERR_REPLY_RESPONSE] = (char)response;
  391.     reply->buffer[CPICERR_REPLY_RESERVED] = 0; /* set reserved byte to zero  */
  392.     *((unsigned short *)&reply->buffer[CPICERR_REPLY_CATEGORY]) =
  393.                             convert_short_to_network(message_category);
  394.     *((unsigned long *)&reply->buffer[CPICERR_REPLY_PRIMARY]) =
  395.                             convert_long_to_network(primary_code);
  396.     *((unsigned long *)&reply->buffer[CPICERR_REPLY_SECONDARY]) =
  397.                             convert_long_to_network(secondary_code);
  398.     length = CPICERR_REPLY_MIN_LENGTH;
  399.  
  400.  
  401.     /* check length of buffer!!! */
  402.  
  403.     /*
  404.      * Copy the length and text of the primary message.
  405.      */
  406.     string_length = strlen(primary_message_text) + 1;
  407.     *((unsigned short *)&reply->buffer[CPICERR_REPLY_PRIMARY_LENGTH]) =
  408.                   convert_short_to_network(string_length);
  409.     memcpy(&reply->buffer[CPICERR_REPLY_PRIMARY_TEXT],
  410.            primary_message_text,
  411.            string_length);
  412.     convert_to_ascii(&reply->buffer[CPICERR_REPLY_PRIMARY_TEXT],
  413.                      string_length);
  414.  
  415.     length += 2 + string_length;
  416.  
  417.     /*
  418.      * Copy the length and text of the secondary message.
  419.      */
  420.     string_length = strlen(secondary_message_text) + 1;
  421.     *((unsigned short *)&reply->buffer[length]) =
  422.               convert_short_to_network(string_length);
  423.     memcpy(&reply->buffer[length+2],
  424.            secondary_message_text,
  425.            string_length);
  426.     convert_to_ascii(&reply->buffer[length+2],
  427.                      string_length);
  428.  
  429.     length += 2 + string_length;
  430.  
  431.     reply->length = length;
  432.  
  433.     return /* length */;
  434. }
  435.  
  436.  
  437.  
  438.  
  439. /*
  440.  * Requires that cpicerr_set_conv_id() has been called.
  441.  */
  442.  
  443. int
  444. cpicerr_send_appl_error( CPICERR *       cpicerr,
  445.                          NEXT_STATE      next_state,
  446.                          CPICERR_REPLY * reply)
  447. {
  448.     CM_RETURN_CODE  cm_rc;
  449.     CM_INT32        length;
  450.     CM_INT32        rts_received;
  451.     CM_SEND_TYPE    send_type;
  452.  
  453.     cmserr(cpicerr->conversation_id,
  454.            &rts_received,
  455.            &cm_rc);
  456.  
  457.  
  458.     switch (next_state) {
  459.         case NEXT_DEALLOCATE:
  460.         case NEXT_DEALLOCATE_AND_EXIT:
  461.             send_type = CM_SEND_AND_DEALLOCATE;
  462.             {
  463.             CM_INT32 deallocate_type = CM_DEALLOCATE_FLUSH;
  464.             cmsdt(cpicerr->conversation_id,
  465.                   &deallocate_type,
  466.                   &cm_rc);
  467.             }
  468.             break;
  469.         case NEXT_SEND:
  470.             send_type = CM_SEND_AND_FLUSH;
  471.             break;
  472.         case NEXT_RECEIVE:
  473.             send_type = CM_SEND_AND_PREP_TO_RECEIVE;
  474.             {
  475.             CM_PREPARE_TO_RECEIVE_TYPE ptr_type;
  476.             ptr_type = CM_PREP_TO_RECEIVE_FLUSH;
  477.             cmsptr (cpicerr->conversation_id,
  478.                     &ptr_type,
  479.                     &cm_rc);
  480.             }
  481.             break;
  482.     }
  483.  
  484.     cmsst (cpicerr->conversation_id,
  485.            &send_type,
  486.            &cm_rc);
  487. #if 1
  488.     if (cm_rc != CM_OK) {
  489.         printf("Ouch!!!!!!!!\n");
  490.     }
  491.     else {
  492.     }
  493. #endif
  494.  
  495.     length = reply->length;
  496.  
  497.     cmsend (cpicerr->conversation_id,
  498.             reply->buffer,
  499.             &length,
  500.             &rts_received,
  501.             &cm_rc);
  502.  
  503.     if (next_state == NEXT_DEALLOCATE_AND_EXIT) {
  504.         exit(EXIT_FAILURE);
  505.     }
  506.  
  507. #if 1
  508.     printf("didn't exit\n");
  509. #endif
  510.  
  511.     return    0;
  512.  
  513. }
  514.  
  515.  
  516.  
  517. /*****************************************************************************
  518.  *
  519.  *  cpicerr_new()
  520.  *
  521.  *  Usage:
  522.  *  This function creates a CPICERR object which should be used on all
  523.  *  subsequent calls to cpicerr.  If an error occurs and a valid object
  524.  *  cannot be created, NULL will be returned.
  525.  *
  526.  *****************************************************************************/
  527. CPICERR *
  528. cpicerr_new(void)
  529. {
  530.     CPICERR *  cpicerr;
  531.  
  532.     /*-----------------------------------------------------------------------*
  533.      * Allocate a block for the CPICERR structure.  calloc() will initialize
  534.      * all bytes to 0.
  535.      *-----------------------------------------------------------------------*/
  536.     cpicerr = (CPICERR *) calloc(1, sizeof(*cpicerr));
  537.     if (cpicerr == NULL) {
  538.         return NULL;
  539.     }
  540.  
  541.  
  542.     /*-----------------------------------------------------------------------*
  543.      * Save the time of program initialization.
  544.      *-----------------------------------------------------------------------*/
  545.     cpicerr->program_start_time = time(NULL);
  546.  
  547.     /*-----------------------------------------------------------------------*
  548.      * Indicate that the conversation id field has not been set.
  549.      *-----------------------------------------------------------------------*/
  550.     cpicerr->conv_id_set = FALSE;
  551.  
  552.  
  553.     /*-----------------------------------------------------------------------*
  554.      * Initialize version levels.  0 indicates they have not been set.
  555.      *-----------------------------------------------------------------------*/
  556.     cpicerr->major_version = 0;
  557.     cpicerr->minor_version = 0;
  558.  
  559.     /*-----------------------------------------------------------------------*
  560.      * Initialize to always exit after an error occurs.
  561.      *-----------------------------------------------------------------------*/
  562.     cpicerr->exit_level = ALL_ERRORS;
  563.  
  564.     /*-----------------------------------------------------------------------*
  565.      * Initialize to always show errors.
  566.      *-----------------------------------------------------------------------*/
  567.     cpicerr->show_level = ALL_ERRORS;
  568.  
  569.     /*-----------------------------------------------------------------------*
  570.      * Initialize to always log errors.
  571.      *-----------------------------------------------------------------------*/
  572.     cpicerr->log_level = ALL_ERRORS;
  573.  
  574.     /*-----------------------------------------------------------------------*
  575.      * Indicate that cpicerr should process all ERROR_RECEIVED return codes
  576.      * (indicating our partner issued Send_Error())
  577.      *-----------------------------------------------------------------------*/
  578.     cpicerr->handle_error = TRUE;
  579.  
  580.     /*-----------------------------------------------------------------------*
  581.      * Initialize strings to NULL in case 0 != NULL
  582.      *-----------------------------------------------------------------------*/
  583.     cpicerr->program_name  = NULL;
  584.     cpicerr->program_info  = NULL;
  585.     cpicerr->log_file_name = NULL;
  586.     cpicerr->log_file_path = NULL;
  587.  
  588.  
  589.     /*-----------------------------------------------------------------------*
  590.      * Set the conversation characteristics to invalid values.  If this
  591.      * isn't done, we could display seemingly valid values for these
  592.      * parameters even though they were never set properly.
  593.      *-----------------------------------------------------------------------*/
  594.     cpicerr->conversation_type  = MAX_MESSAGE;
  595.     cpicerr->conversation_state = MAX_MESSAGE;
  596.     cpicerr->sync_level         = MAX_MESSAGE;
  597.  
  598.     return cpicerr;
  599. }
  600.  
  601. /*****************************************************************************
  602.  *
  603.  *  cpicerr_set_conv_id
  604.  *
  605.  *  Usage:
  606.  *  This call should be used just before the cmallc call (for clients),
  607.  *  or just after the cmaccp call (for servers).
  608.  *
  609.  *  This routine will save the conversation id, as well as partner information
  610.  *  and conversation status which can be extracted from CPI-C.
  611.  *
  612.  *  This information is often helpful for debugging and in many cases cannot
  613.  *  be obtained after an error occurs, since you no longer have a valid
  614.  *  conversation id after the conversation has been deallocated.
  615.  *
  616.  *  Returns 0 if everything was processed successfully.
  617.  *  Returns 1 if an error occurred.  In general, the only reason for an
  618.  *     error to occur is if one of the passed parameters is invalid.  Since
  619.  *     this is just storing information in the footprint, we will not
  620.  *     attempt to do sophisticated error processing in this procedure.
  621.  *
  622.  *****************************************************************************/
  623. int
  624. cpicerr_set_conv_id(CPICERR *       cpicerr,
  625.                     unsigned char * conversation_id)
  626. {
  627.     CM_RETURN_CODE        conv_rc;          /* Return code from CPI-C call   */
  628.     int                   rc;               /* return value for function     */
  629.  
  630.  
  631.     if (cpicerr != (CPICERR *)NULL) {
  632.         /*-------------------------------------------------------------------*
  633.          * Save the conversation ID.
  634.          * This can often be used in conjunction with error logs or trace
  635.          * utilities.
  636.          *-------------------------------------------------------------------*/
  637.         memcpy(cpicerr->conversation_id,
  638.                conversation_id,
  639.                sizeof(cpicerr->conversation_id));
  640.  
  641.         /*
  642.          * Extract the conversation type.
  643.          */
  644.         cmect(conversation_id,              /* Current conversation ID       */
  645.               &cpicerr->conversation_type,  /* Returned conversation type    */
  646.               &conv_rc);                    /* Put the return code here      */
  647.         if (conv_rc != CM_OK) {
  648.             /*
  649.              * Set the conversation type to an invalid value and set
  650.              * the return code to indicate an error.
  651.              */
  652.             cpicerr->conversation_type = MAX_MESSAGE;
  653.             rc = 1;
  654.         }
  655.  
  656.         /*
  657.          * Extract the mode name used for this conversation.
  658.          */
  659.         cmemn(conversation_id,              /* Current conversation ID       */
  660.               cpicerr->mode_name,           /* Returned mode name            */
  661.               &(cpicerr->mode_name_length), /* Returned mode name length     */
  662.               &conv_rc);                    /* Put the return code here      */
  663.         if (conv_rc != CM_OK) {
  664.             /*
  665.              * Make sure the mode name is reset to uninitialized and
  666.              * set the return code to indicate an error.
  667.              */
  668.             cpicerr->mode_name_length = 0;
  669.             rc = 1;
  670.         }
  671.         /* make sure we place the null terminator at the end of the string   */
  672.         cpicerr->mode_name[(int)cpicerr->mode_name_length] = '\0';
  673.  
  674.         /*-------------------------------------------------------------------*
  675.          * Extract the partner's LU name.
  676.          *-------------------------------------------------------------------*/
  677.         cmepln(conversation_id,             /* Current conversation ID       */
  678.                cpicerr->partner_LU_name,    /* Returned partner LU           */
  679.                &(cpicerr->partner_LU_name_length),/* Partner LU name length  */
  680.                &conv_rc);                   /* Put the return code here      */
  681.         if (conv_rc != CM_OK) {
  682.             /*
  683.              * Make sure the partner LU name is reset to uninitialized and
  684.              * set the return code to indicate an error.
  685.              */
  686.             cpicerr->partner_LU_name_length = 0;
  687.             rc = 1;
  688.         }
  689.         /* make sure we place the null terminator at the end of the string   */
  690.         cpicerr->partner_LU_name[(int)cpicerr->partner_LU_name_length] = '\0';
  691.  
  692.         /*-------------------------------------------------------------------*
  693.          * Extract the conversation sync level.
  694.          *-------------------------------------------------------------------*/
  695.         cmesl(conversation_id,              /* Current conversation ID       */
  696.               &cpicerr->sync_level,         /* Returned sync level           */
  697.               &conv_rc);                    /* Put the return code here      */
  698.         if (conv_rc != CM_OK) {
  699.             /*
  700.              * Set the sync level to an invalid value and set
  701.              * the return code to indicate an error.
  702.              */
  703.             cpicerr->sync_level = MAX_MESSAGE;
  704.             rc = 1;
  705.         }
  706.  
  707.         rc = 0;
  708.     } else {
  709.         rc = 1;
  710.     }
  711.     return rc;
  712. }
  713.  
  714. /*****************************************************************************
  715.  *
  716.  *  cpicerr_set_exit_level
  717.  *
  718.  *  Usage:
  719.  *  Specify the CPI-C error classification as the exit level.
  720.  *  When cpicerr_handle_rc() is called, the return code will be classified.
  721.  *  If the classification is above the exit level, the program will be
  722.  *  terminated (after conversation cleanup).
  723.  *
  724.  *  A value of ALL_ERRORS can be used to force an exit on any call to
  725.  *  cpicerr_handle_rc().  This is the DEFAULT value.
  726.  *
  727.  *  A value of NO_ERRORS can be used to indicate that cpicerr should never
  728.  *  cause an exit.  Your application should handle all exit termination.
  729.  *  This is especially useful when using more than one conversation.
  730.  *
  731.  *  Also see:
  732.  *      cpicerr_set_log_level
  733.  *      cpicerr_set_show_level
  734.  *****************************************************************************/
  735. int
  736. cpicerr_set_exit_level(CPICERR *        cpicerr,
  737.                        CPIC_RC_HANDLING exit_level)
  738. {
  739.     cpicerr->exit_level = exit_level;
  740.     return 0;
  741. }
  742.  
  743. /*****************************************************************************
  744.  *
  745.  *  cpicerr_set_log_file_name
  746.  *
  747.  *  Usage:
  748.  *  Sets the name of the log file to be used in cpicerr_handle_rc() to
  749.  *  log complete error information.  No attempt is made to verify that
  750.  *  the log_file_name specified is a valid filename or whether the file
  751.  *  can be opened.  If the log_file_name cannot be opened when logging
  752.  *  needs to be done, all log output will be sent to stderr instead.
  753.  *
  754.  *  For environments that support directory structures, you should specify
  755.  *  the filename on cpicerr_set_log_file_name and the directory on
  756.  *  cpicerr_set_log_file_path.  This allows your program to be isolated
  757.  *  from changes in environments that only support a single level
  758.  *  of directory (for example, VM).
  759.  *
  760.  *  Also see:
  761.  *      cpicerr_set_log_file_path
  762.  *      cpicerr_log_cpicerr (internal)
  763.  *****************************************************************************/
  764. int
  765. cpicerr_set_log_file_name(CPICERR * cpicerr,
  766.                           char *    log_file_name)
  767. {
  768.     /*-----------------------------------------------------------------------*
  769.      * Initialize the name of the log file.
  770.      *-----------------------------------------------------------------------*/
  771.     cpicerr->log_file_name = (char *) malloc(strlen(log_file_name)+1);
  772.     if (cpicerr->log_file_name != NULL) {
  773.         strcpy(cpicerr->log_file_name, log_file_name);
  774.         return 0;
  775.     } else {
  776.         return 1;
  777.     }
  778.  
  779. }
  780.  
  781. /*****************************************************************************
  782.  *
  783.  *  cpicerr_set_log_file_path
  784.  *
  785.  *  Usage:
  786.  *  Specifies the path qualifier for the log file name specified in the
  787.  *  cpicerr_set_log_file_name call.  If cpicerr_set_log_file_path is used
  788.  *  without setting the log file name, no error logging will occur.
  789.  *
  790.  *  If you specify a string whose first character is a $, the rest of the
  791.  *  string will be looked for as an environment variable.  For example,
  792.  *  in OS/2, you put the following in your CONFIG.SYS:
  793.  *  SET LOGPATH=d:\logfiles
  794.  *
  795.  *  then specify $LOGPATH as a parameter on cpicerr_set_log_file_path.
  796.  *
  797.  *****************************************************************************/
  798. int
  799. cpicerr_set_log_file_path(CPICERR * cpicerr,
  800.                           char *    log_file_path)
  801. {
  802.     char * path;
  803.     int    rc;
  804.  
  805.     /*-----------------------------------------------------------------------*
  806.      * Initialize the name of the log file.
  807.      * If the first character is a dollar sign ('$'), then try to extract
  808.      * the log file path from the environment.  If not, use the path
  809.      * as specified.
  810.      *-----------------------------------------------------------------------*/
  811.     if (log_file_path[0] == '$') {
  812.         path = getenv(&log_file_path[1]);
  813.     } else {
  814.         path = log_file_path;
  815.     }
  816.  
  817.     /*-----------------------------------------------------------------------*
  818.      * Check that we have a valid log file path string, allocate memory for
  819.      * the string and copy it into the cpicerr structure.
  820.      *-----------------------------------------------------------------------*/
  821.     if (path != NULL) {
  822.         cpicerr->log_file_path = (char *) malloc(strlen(path)+1);
  823.         if (cpicerr->log_file_path != NULL) {
  824.             strcpy(cpicerr->log_file_path, path);
  825.             rc = 0;
  826.         } else {
  827.             rc = 1;
  828.         }
  829.     }
  830.     else {
  831.         rc = 1;
  832.     }
  833.     return rc;
  834.  
  835. }
  836.  
  837. /*****************************************************************************
  838.  *
  839.  *  cpicerr_set_log_level
  840.  *
  841.  *  Usage:
  842.  *  Specify the CPI-C error classification as the log level.
  843.  *  When cpicerr_handle_rc() is called, the return code will be classified.
  844.  *  If the classification is above the log level, the return code and
  845.  *  conversation information will be logged to the log file specified
  846.  *  with the cpicerr_set_log_file_name and cpicerr_set_log_file_path.
  847.  *
  848.  *  A value of ALL_ERRORS can be used to force logging on any call to
  849.  *  cpicerr_handle_rc().  This is the DEFAULT value.  This is especially
  850.  *  useful when used on servers.
  851.  *
  852.  *  A value of NO_ERRORS can be used to indicate that cpicerr should never
  853.  *  cause an error log.  Your application should handle all error logging.
  854.  *
  855.  *  Also see:
  856.  *      cpicerr_set_log_file_name
  857.  *      cpicerr_set_log_file_path
  858.  *      cpicerr_log_cpicerr (internal)
  859.  *      cpicerr_set_exit_level
  860.  *      cpicerr_set_show_level
  861.  *****************************************************************************/
  862. int
  863. cpicerr_set_log_level(CPICERR *        cpicerr,
  864.                       CPIC_RC_HANDLING log_level)
  865. {
  866.     cpicerr->log_level = log_level;
  867.     return 0;
  868. }
  869.  
  870. /*****************************************************************************
  871.  *
  872.  *  cpicerr_set_major_version
  873.  *
  874.  *  Usage:
  875.  *  Sets the major version number for the application.
  876.  *  The version number can be 0-255.
  877.  *
  878.  *  The version number is used on error logging and by the
  879.  *  cpicerr_exchange_version() call.
  880.  *
  881.  *  Also see:
  882.  *      cpicerr_set_minor_version
  883.  *****************************************************************************/
  884. int
  885. cpicerr_set_major_version(CPICERR *     cpicerr,
  886.                           unsigned char major_version)
  887. {
  888.     cpicerr->major_version = major_version;
  889.     return 0;
  890. }
  891.  
  892. /*****************************************************************************
  893.  *
  894.  *  cpicerr_set_minor_version
  895.  *
  896.  *  Usage:
  897.  *  Sets the minor version number for the application.
  898.  *  The version number can be 0-255.
  899.  *
  900.  *  The version number is used on error logging and by the
  901.  *  cpicerr_exchange_version() call.
  902.  *
  903.  *  Also see:
  904.  *      cpicerr_set_major_version
  905.  *****************************************************************************/
  906. int
  907. cpicerr_set_minor_version(CPICERR *     cpicerr,
  908.                           unsigned char minor_version)
  909. {
  910.     cpicerr->minor_version = minor_version;
  911.     return 0;
  912. }
  913.  
  914.  
  915. /*****************************************************************************
  916.  *
  917.  *  cpicerr_set_program_info
  918.  *
  919.  *  Usage:
  920.  *  Sets a program information string that is included in the log information.
  921.  *****************************************************************************/
  922. int
  923. cpicerr_set_program_info( CPICERR * cpicerr,
  924.                           char * program_info)
  925. {
  926.     int rc;
  927.  
  928.     /*-----------------------------------------------------------------------*
  929.      * Save the application's program information string
  930.      *-----------------------------------------------------------------------*/
  931.     cpicerr->program_info = (char *) malloc(strlen(program_info)+1);
  932.     if (cpicerr->program_info != NULL) {
  933.         strcpy(cpicerr->program_info, program_info);
  934.         rc = 0;
  935.     } else {
  936.         rc = 1;
  937.     }
  938.     return rc;
  939. }
  940.  
  941.  
  942. /*****************************************************************************
  943.  *
  944.  *  cpicerr_set_program_name
  945.  *
  946.  *  Usage:
  947.  *  Sets a program name string that is included in the log information.
  948.  *****************************************************************************/
  949. int
  950. cpicerr_set_program_name(CPICERR * cpicerr,
  951.                          char * program_name)
  952. {
  953.     int rc;
  954.     /*-----------------------------------------------------------------------*
  955.      * Save the local program name.
  956.      *-----------------------------------------------------------------------*/
  957.     cpicerr->program_name = (char *) malloc(strlen(program_name)+1);
  958.     if (cpicerr->program_name != NULL) {
  959.         strcpy(cpicerr->program_name, program_name);
  960.         rc = 0;
  961.     } else {
  962.         rc = 1;
  963.     }
  964.     return rc;
  965. }
  966.  
  967.  
  968. /*****************************************************************************
  969.  *
  970.  *  cpicerr_set_show_level
  971.  *
  972.  *  Usage:
  973.  *  Specify the CPI-C error classification as the show level.
  974.  *  When cpicerr_handle_rc() is called, the return code will be classified.
  975.  *  If the classification is above the show level, the return code and
  976.  *  some conversation information will be shown to the user.
  977.  *
  978.  *  A value of ALL_ERRORS can be used to force showing of all calls to
  979.  *  cpicerr_handle_rc().  This is the DEFAULT value.
  980.  *
  981.  *  A value of NO_ERRORS can be used to indicate that cpicerr should never
  982.  *  cause an error to be shown to the user.
  983.  *
  984.  *  Also see:
  985.  *      cpicerr_set_exit_level
  986.  *      cpicerr_set_log_level
  987.  *****************************************************************************/
  988. int
  989. cpicerr_set_show_level(CPICERR *        cpicerr,
  990.                        CPIC_RC_HANDLING show_level)
  991. {
  992.     cpicerr->show_level = show_level;
  993.     return 0;
  994. }
  995.  
  996.  
  997. /******************************************************************************
  998.  *
  999.  *  cpicerr_handle_rc_extended
  1000.  *
  1001.  *  Note:
  1002.  *  applications should use the cpicerr_handle_rc() macro.
  1003.  *
  1004.  *  Usage:
  1005.  *  This function should be called to handle any unexpected CPI-C return
  1006.  *  codes.  The exact function of this routine depends upon the settings
  1007.  *  that have been made to the CPICERR object.
  1008.  *
  1009.  *  Functions include:
  1010.  *      Determining the current conversation state
  1011.  *      Classifying the return code (CPIC_RC_HANDLING enum)
  1012.  *      Showing return code info to the user
  1013.  *      Logging the return code and conversation info to disk
  1014.  *      Deallocate the conversation and exit
  1015.  *
  1016.  *  Also see:
  1017.  *      cpicerr_set_exit_level
  1018.  *      cpicerr_set_log_level
  1019.  *      cpicerr_set_show_level
  1020.  *
  1021.  *****************************************************************************/
  1022. CPIC_RC_HANDLING
  1023. cpicerr_handle_rc_extended(CPICERR *       cpicerr,
  1024.                            CPIC_VERB_INDEX verb_index,
  1025.                            CM_RETURN_CODE  conv_rc,
  1026.                            char *          file_name,
  1027.                            int             file_line)
  1028.  
  1029. {
  1030.    /* Displays the CPI-C return code and the verb name. */
  1031.  
  1032.     CM_RETURN_CODE   cm_rc;                 /* Return code from CPI-C call   */
  1033.     CPIC_RC_HANDLING classification;        /* Returned RC classification    */
  1034.     char *           string;                /* temp var for output strings   */
  1035.     CM_CONVERSATION_STATE conversation_state; /* Current conv. state         */
  1036.  
  1037.     /*-----------------------------------------------------------------------*
  1038.      * Extract the current conversation state.
  1039.      * This will not be useful if the conversation has failed or a deallocate
  1040.      * return code has been received.  The conversation state is most useful
  1041.      * when a state check has occurred.
  1042.      *-----------------------------------------------------------------------*/
  1043. #ifndef ECS_NOT_SUPPORTED
  1044.      cmecs(cpicerr->conversation_id,
  1045.            &conversation_state,
  1046.            &cm_rc);
  1047.      if (cm_rc == CM_OK) {
  1048.          cpicerr->conversation_state = conversation_state;
  1049.      }
  1050.      else {
  1051.          cpicerr->conversation_state = CMECS_NOT_SUPPORTED;
  1052.      }
  1053. #else
  1054.      cpicerr->conversation_state = CMECS_NOT_SUPPORTED;
  1055. #endif
  1056.  
  1057.     /*-----------------------------------------------------------------------*
  1058.      * Store the error information in the cpicerr structure
  1059.      *-----------------------------------------------------------------------*/
  1060.      cpicerr_set_rc_info(cpicerr, verb_index, conv_rc);
  1061.  
  1062.     /*-----------------------------------------------------------------------*
  1063.      * Get the classification for this return code.
  1064.      *-----------------------------------------------------------------------*/
  1065.     cpicerr_classify_rc(conv_rc, &classification);
  1066.  
  1067.  
  1068.     if (classification == ERROR_RECEIVED && cpicerr->handle_error == TRUE) {
  1069.         CPICERR_REPLY * reply;
  1070.         reply = cpicerr_create_reply(1000,1000);
  1071.         cpicerr_recv_appl_error(cpicerr, reply);
  1072.         cpicerr_show_reply(reply);
  1073.         if (classification >= cpicerr->exit_level) {
  1074.             CM_INT32 deallocate_type;
  1075.             /*
  1076.              * Exit the application, rather than returning to the caller.
  1077.              */
  1078.             deallocate_type = CM_DEALLOCATE_ABEND;
  1079.  
  1080.             cmsdt(cpicerr -> conversation_id,
  1081.                   &deallocate_type,
  1082.                   &cm_rc);
  1083.  
  1084.             cmdeal(cpicerr -> conversation_id,
  1085.                    &cm_rc);
  1086.  
  1087.             do_exit(EXIT_FAILURE);
  1088.         }
  1089.         return classification;
  1090.     }
  1091.  
  1092.  
  1093.     /*-----------------------------------------------------------------------*
  1094.      * Show the CPI-C verb and return code.
  1095.      *-----------------------------------------------------------------------*/
  1096.     if (classification >= cpicerr->show_level) {
  1097.         cpicerr_show_rc(cpicerr);
  1098.     }
  1099.  
  1100.  
  1101.     /*-----------------------------------------------------------------------*
  1102.      * Show the classification for this return code.
  1103.      *-----------------------------------------------------------------------*/
  1104.     if (classification >= cpicerr->show_level) {
  1105.         string = cpicerr_get_message(CPIC_RC_CLASSES, classification);
  1106.         write_error("       return code class: %s\n", string);
  1107.         /*-------------------------------------------------------------------*
  1108.          * Show product specific information associated with this error.
  1109.          *-------------------------------------------------------------------*/
  1110.         cpicerr_show_product_info(cpicerr);
  1111.     }
  1112.  
  1113.  
  1114.     /*-----------------------------------------------------------------------*
  1115.      * Log this error, along with the infomation in its cpicerr.
  1116.      *-----------------------------------------------------------------------*/
  1117.     if (classification >= cpicerr->log_level) {
  1118.         cpicerr_log_cpicerr(cpicerr, file_name, file_line);
  1119.     }
  1120.  
  1121.  
  1122.     if (classification >= cpicerr->exit_level) {
  1123.         CM_INT32 deallocate_type;
  1124.         /*-------------------------------------------------------------------*
  1125.          * Exit the application, rather than returning to the caller.
  1126.          *-------------------------------------------------------------------*/
  1127.         deallocate_type = CM_DEALLOCATE_ABEND;
  1128.  
  1129.         cmsdt(cpicerr -> conversation_id,
  1130.               &deallocate_type,
  1131.               &cm_rc);
  1132.  
  1133.         cmdeal(cpicerr -> conversation_id,
  1134.                &cm_rc);
  1135.  
  1136.         do_exit(EXIT_FAILURE);              /* Set a failure return code     */
  1137.     }
  1138.     return classification;
  1139. }
  1140.  
  1141. /******************************************************************************
  1142.  *
  1143.  *  cpicerr_exchange_version
  1144.  *
  1145.  *  Usage:
  1146.  *  Calls cpicerr_exchange_version_plus()
  1147.  *
  1148.  *****************************************************************************/
  1149. int
  1150. cpicerr_exchange_version(CPICERR *       cpicerr,
  1151.                          unsigned char * cm_conv_id,
  1152.                          CM_INT32        conv_state,
  1153.                          unsigned char * partner_major_version,
  1154.                          unsigned char * partner_minor_version)
  1155. {
  1156.     return cpicerr_exchange_version_plus(cpicerr,
  1157.                                          cm_conv_id,
  1158.                                          conv_state,
  1159.                                          partner_major_version,
  1160.                                          partner_minor_version,
  1161.                                          NULL,
  1162.                                          0);
  1163.  
  1164.  
  1165.  
  1166.  
  1167. }
  1168.  
  1169. /******************************************************************************
  1170.  *
  1171.  *  cpicerr_exchange_version_plus
  1172.  *
  1173.  *  Usage:
  1174.  *  Send our two version number bytes to the partner and receive our
  1175.  *  partner's two version numbers.  The input parameter conv_state
  1176.  *  determines whether our version numbers are sent first, or whether
  1177.  *  we receive the partner's numbers first.
  1178.  *
  1179.  *  Also will return the remote operating system string, if sent.
  1180.  *
  1181.  *****************************************************************************/
  1182. int
  1183. cpicerr_exchange_version_plus(CPICERR *       cpicerr,
  1184.                               unsigned char * cm_conv_id,
  1185.                               CM_INT32        conv_state,
  1186.                               unsigned char * partner_major_version,
  1187.                               unsigned char * partner_minor_version,
  1188.                               unsigned char * opsys_string,
  1189.                               unsigned int    opsys_string_length)
  1190. {
  1191.     CM_SEND_TYPE send_type;                 /* CPI-C send type               */
  1192.     CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive; /* CPI-C prepare to receive  */
  1193.     CM_INT32    cm_rc;                      /* CPI-C return code             */
  1194.     CM_INT32    length;                     /* generic length variable       */
  1195.     CM_INT32    rts_received;               /* request to send received      */
  1196.     CM_INT32    max_receive_len;            /* Max receive length on CMRCV   */
  1197.     CM_INT32    what_received;              /* What received parm from CMRCV */
  1198.     CM_INT32    received_len;               /* Amount of data rcvd on CMRCV  */
  1199.     CM_INT32    status_received;            /* Status from CMRCV             */
  1200.     unsigned char buffer[EXCHANGE_BUFFER_SIZE]; /* data buffer               */
  1201.  
  1202.     *partner_major_version = 0;
  1203.     *partner_minor_version = 0;
  1204.  
  1205.     prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
  1206.     cmsptr(cm_conv_id,                      /* Set prepare to receive type   */
  1207.            &prep_to_receive,
  1208.            &cm_rc);
  1209.     /* The only expected return code is CM_OK */
  1210.     if (cm_rc != CM_OK) return cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
  1211.  
  1212.     send_type = CM_BUFFER_DATA;
  1213.     cmsst(cm_conv_id,                       /* Set send type                 */
  1214.           &send_type,
  1215.           &cm_rc);
  1216.     if (cm_rc != CM_OK) return cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  1217.  
  1218.  
  1219.     switch (conv_state) {
  1220.     case CM_SEND_STATE:
  1221.         buffer[0] = CPICERR_EXCHANGE_VERSION;
  1222.         buffer[1] = cpicerr->major_version;
  1223.         buffer[2] = cpicerr->minor_version;
  1224.         length = 3;
  1225.         cmsend(cm_conv_id,
  1226.                buffer,
  1227.                &length,
  1228.                &rts_received,
  1229.                &cm_rc);
  1230.         /* The only expected return code is CM_OK */
  1231.         if (cm_rc != CM_OK)
  1232.             return cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  1233.         /* this falls through to the receive code!!! */
  1234.     case CM_RECEIVE_STATE:
  1235.         max_receive_len = sizeof(buffer);
  1236.         cmrcv (cm_conv_id,
  1237.                buffer,
  1238.                &max_receive_len,
  1239.                &what_received,
  1240.                &received_len,
  1241.                &status_received,
  1242.                &rts_received,
  1243.                &cm_rc);
  1244.         if (cm_rc == CM_OK) {
  1245.             if (what_received != CM_NO_DATA_RECEIVED) {
  1246.                 if (received_len > 2 && buffer[0]==CPICERR_EXCHANGE_VERSION) {
  1247.                     *partner_major_version = buffer[1];
  1248.                     *partner_minor_version = buffer[2];
  1249.                 }
  1250.                 if (opsys_string != NULL && opsys_string_length > 1) {
  1251.                     if (received_len > 4 &&
  1252.                         buffer[3]==CPICERR_EXCHANGE_OPSYS_STRING) {
  1253.                         if (received_len < sizeof(buffer)) {
  1254.                             buffer[received_len] = '\0';
  1255.                         }
  1256.                         else {
  1257.                             buffer[sizeof(buffer)] = '\0';
  1258.                         }
  1259.                         {
  1260.                         unsigned int string_length;
  1261.  
  1262.                         string_length = strlen(&buffer[4]);
  1263.                         convert_from_ascii(&buffer[4], string_length);
  1264.  
  1265.                         memcpy(opsys_string,
  1266.                                &buffer[4],
  1267.                                min(string_length, opsys_string_length-1));
  1268.  
  1269.                         opsys_string[min(string_length, opsys_string_length-1)]
  1270.                                                                         = '\0';
  1271.  
  1272.                         }
  1273.  
  1274.                     }
  1275.                     else {
  1276.                         opsys_string[0] = '\0';
  1277.                     }
  1278.                 }
  1279.                 else {
  1280.                 }
  1281.  
  1282.             }
  1283.             switch (status_received) {
  1284.             case CM_CONFIRM_RECEIVED:
  1285.                 cmcfmd(cm_conv_id,
  1286.                        &cm_rc);
  1287.                 if (cm_rc != CM_OK)
  1288.                     return cpicerr_handle_rc(cpicerr, MSG_CMCFMD, cm_rc);
  1289.                 break;
  1290.             case CM_SEND_RECEIVED:
  1291.                 /* This is good, we don't have to do anything. */
  1292.                 break;
  1293.             default:
  1294.                 ;
  1295.                 /* should do a reply_error here */
  1296.  
  1297.             }
  1298.         } else {
  1299.             return cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
  1300.         }
  1301.         break;
  1302.     default:
  1303.         /* do a reply error here */
  1304.         return UNRECOVERABLE;
  1305.     }
  1306.  
  1307.     if ((conv_state == CM_RECEIVE_STATE) &&
  1308.          (status_received == CM_SEND_RECEIVED)) {
  1309.  
  1310.         char *       local_opsys_string;
  1311.         unsigned int local_opsys_string_length;
  1312.  
  1313.         buffer[0] = CPICERR_EXCHANGE_VERSION;
  1314.         buffer[1] = cpicerr->major_version;
  1315.         buffer[2] = cpicerr->minor_version;
  1316.         local_opsys_string = OPSYS_STRING;
  1317.         local_opsys_string_length = strlen(local_opsys_string);
  1318.         if ((local_opsys_string_length + 1+ 3 +1) < sizeof(buffer)) {
  1319.             buffer[3] = CPICERR_EXCHANGE_OPSYS_STRING;
  1320.             memcpy(&buffer[4],
  1321.                    local_opsys_string,
  1322.                    local_opsys_string_length);
  1323.             convert_to_ascii(&buffer[4], local_opsys_string_length);
  1324.             buffer[4+local_opsys_string_length] ='\0';
  1325.             length = 4 + local_opsys_string_length + 1;
  1326.         }
  1327.         else {
  1328.  
  1329.  
  1330.             length = 3;
  1331.         }
  1332.  
  1333.         cmsend(cm_conv_id,
  1334.                buffer,
  1335.                &length,
  1336.                &rts_received,
  1337.                &cm_rc);
  1338.         /* The only expected return code is CM_OK */
  1339.  
  1340.         if (cm_rc != CM_OK)
  1341.             return cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  1342.  
  1343.         cmptr(cm_conv_id,
  1344.               &cm_rc);
  1345.         if (cm_rc != CM_OK)
  1346.             return cpicerr_handle_rc(cpicerr, MSG_CMPTR, cm_rc);
  1347.     }
  1348.     return RC_OK;
  1349. }
  1350.  
  1351. /*****************************************************************************
  1352.  *
  1353.  *  cpicerr_destroy()
  1354.  *
  1355.  *  Destroys a CPICERR structure created with cpicerr_new().
  1356.  *  All memory assocated with the input CPICERR pointer is freed.
  1357.  *
  1358.  *****************************************************************************/
  1359. void
  1360. cpicerr_destroy(CPICERR * cpicerr)
  1361. {
  1362.     /*
  1363.      * Make sure we don't free() a NULL pointer!!!
  1364.      */
  1365.     if (cpicerr != NULL) {
  1366.         if (cpicerr->program_name != NULL) {
  1367.             free(cpicerr->program_name);
  1368.         }
  1369.  
  1370.         if (cpicerr->program_info != NULL) {
  1371.             free(cpicerr->program_info);
  1372.         }
  1373.  
  1374.         if (cpicerr->log_file_name != NULL) {
  1375.             free(cpicerr->log_file_name);
  1376.         }
  1377.  
  1378.         if (cpicerr->log_file_path != NULL) {
  1379.             free(cpicerr->log_file_path);
  1380.         }
  1381.  
  1382.         free(cpicerr);
  1383.     }
  1384.     return;
  1385. }
  1386.  
  1387.  
  1388.  
  1389. /*****************************************************************************
  1390.  *
  1391.  *  cpicerr_set_rc_info
  1392.  *
  1393.  *  Internal call which makes it easier to store return code information
  1394.  *  in the CPICERR structure.  Called from cpicerr_handle_rc().
  1395.  *
  1396.  *****************************************************************************/
  1397. void
  1398. cpicerr_set_rc_info(CPICERR *       cpicerr,
  1399.                     CPIC_VERB_INDEX verb_index,
  1400.                     CM_RETURN_CODE  conv_rc)
  1401. /* Store the verb return code information into the cpicerr structure */
  1402. {
  1403.     cpicerr->verb_index = verb_index;
  1404.     cpicerr->conv_rc =    conv_rc;
  1405. }
  1406.  
  1407. /*****************************************************************************
  1408.  *
  1409.  *  cpicerr_show_rc
  1410.  *
  1411.  *  Internal call which will display information about the unexpected
  1412.  *  return code encountered.  Called from cpicerr_handle_rc().
  1413.  *
  1414.  *****************************************************************************/
  1415. void
  1416. cpicerr_show_rc(CPICERR * cpicerr)
  1417. {
  1418.     write_error("\n  Unexpected CPI-C return code encountered...\n");
  1419.  
  1420.     /*-----------------------------------------------------------------------*
  1421.      * Find the CPI-C verb's name, and show it.
  1422.      *-----------------------------------------------------------------------*/
  1423.     write_error( "         CPI-C verb name: %s, %s\n",
  1424.             cpicerr_get_message(CPIC_VERBS_SHORT,
  1425.                                 (CM_INT32)cpicerr->verb_index),
  1426.             cpicerr_get_message(CPIC_VERBS_LONG,
  1427.                                 (CM_INT32)cpicerr->verb_index));
  1428.  
  1429.     /*-----------------------------------------------------------------------*
  1430.      * Find the CPI-C return code's name, and show it.
  1431.      *-----------------------------------------------------------------------*/
  1432.     write_error( "       CPI-C return code: %lu, %s\n",
  1433.             cpicerr->conv_rc,
  1434.             cpicerr_get_message(CPIC_RETURN_CODES, cpicerr->conv_rc));
  1435.  
  1436.     return;
  1437. }
  1438.  
  1439. /*****************************************************************************
  1440.  *
  1441.  *  cpicerr_log_rc
  1442.  *
  1443.  *  Internal call which will log information about the unexpected
  1444.  *  return code encountered.  Called from cpicerr_handle_rc().
  1445.  *
  1446.  *****************************************************************************/
  1447. void
  1448. cpicerr_log_rc(CPICERR * cpicerr,
  1449.                FILE *    log_file)
  1450. {
  1451.     write_log(log_file, "  Unexpected CPI-C return code encountered...\n");
  1452.  
  1453.     /*-----------------------------------------------------------------------*
  1454.      * Find the CPI-C verb's name, and show it.
  1455.      *-----------------------------------------------------------------------*/
  1456.     write_log(log_file,
  1457.               "         CPI-C verb name: %s, %s\n",
  1458.               cpicerr_get_message(CPIC_VERBS_SHORT,
  1459.                                   (CM_INT32)cpicerr->verb_index),
  1460.               cpicerr_get_message(CPIC_VERBS_LONG,
  1461.                                   (CM_INT32)cpicerr->verb_index));
  1462.  
  1463.     /*-----------------------------------------------------------------------*
  1464.      * Find the CPI-C return code's name, and show it.
  1465.      *-----------------------------------------------------------------------*/
  1466.     write_log(log_file,
  1467.               "       CPI-C return code: %lu, %s\n",
  1468.               cpicerr->conv_rc,
  1469.               cpicerr_get_message(CPIC_RETURN_CODES, cpicerr->conv_rc));
  1470.  
  1471.     return;
  1472. }
  1473.  
  1474.  
  1475. /*****************************************************************************
  1476.  *
  1477.  *  cpicerr_classify_rc
  1478.  *
  1479.  *  Internal call which takes a CPI-C return code and classifies it
  1480.  *  into one of the categories that we have defined.
  1481.  *  Called from cpicerr_handle_rc().
  1482.  *
  1483.  *****************************************************************************/
  1484. void
  1485. cpicerr_classify_rc (CM_RETURN_CODE conv_rc,
  1486.                      CPIC_RC_HANDLING * classification)
  1487. {
  1488.     switch (conv_rc) {
  1489.  
  1490.         case CM_ALLOCATE_FAILURE_NO_RETRY:
  1491.             /* configuration defect or protocol defect, local or partner */
  1492.         case CM_TP_NOT_AVAILABLE_NO_RETRY:
  1493.             /* partner program could not be sucessfully started */
  1494.         case CM_RESOURCE_FAILURE_NO_RETRY:
  1495.             /* communication failure or protocol defect, local or partner */
  1496.  
  1497.         case CM_DEALLOCATED_ABEND:
  1498.             /* unrecoverable error in the partner TP */
  1499.         case CM_DEALLOCATED_ABEND_SVC:
  1500.             /* unrecoverable error in the partner TP */
  1501.         case CM_DEALLOCATED_ABEND_TIMER:
  1502.             /* unrecoverable error in the partner TP */
  1503.  
  1504.         case CM_CONVERSATION_TYPE_MISMATCH:
  1505.         case CM_PIP_NOT_SPECIFIED_CORRECTLY:
  1506.  
  1507.             /* configuration defect or mismatch with the partner */
  1508.  
  1509.         case CM_OK:
  1510.             /* application design defect, local or partner program */
  1511.         case CM_DEALLOCATED_NORMAL:
  1512.             /* TP design defect, local or partner program */
  1513.         case CM_PARAMETER_ERROR:
  1514.             /* local program design or coding defect */
  1515.         case CM_PROGRAM_PARAMETER_CHECK:
  1516.             /* local program design or coding defect */
  1517.         case CM_PROGRAM_STATE_CHECK:
  1518.             /* local program design or coding defect */
  1519.             *classification = UNRECOVERABLE;
  1520.             break;
  1521.  
  1522.         case CM_ALLOCATE_FAILURE_RETRY:
  1523.             /* configuration defect or route temporarily down */
  1524.         case CM_TP_NOT_AVAILABLE_RETRY:
  1525.             /* congestion at the partner operating system */
  1526.         case CM_RESOURCE_FAILURE_RETRY:
  1527.             /* route temporarily down */
  1528.             *classification = RETRY_CONV;
  1529.             break;
  1530.  
  1531.         case CM_UNSUCCESSFUL:
  1532.             /* verb could not be completed now */
  1533.             *classification = RETRY_VERB;
  1534.             break;
  1535.  
  1536.         case CM_PROGRAM_ERROR_NO_TRUNC:
  1537.         case CM_SVC_ERROR_NO_TRUNC:
  1538.             /* partner failed while building a record to send */
  1539.         case CM_PROGRAM_ERROR_PURGING:
  1540.         case CM_SVC_ERROR_PURGING:
  1541.             /* partner failed while processing a received record */
  1542.         case CM_PROGRAM_ERROR_TRUNC:
  1543.         case CM_SVC_ERROR_TRUNC:
  1544.             /* partner failed after partially sending a record */
  1545.             *classification = ERROR_RECEIVED;
  1546.             break;
  1547.  
  1548.         case CM_PRODUCT_SPECIFIC_ERROR:
  1549.             /********************************/
  1550.             /* Examine each of these.       */
  1551.             /* In some cases, you may want  */
  1552.             /* to return CONTINUE.          */
  1553.             /********************************/
  1554.             *classification = UNRECOVERABLE;
  1555.             break;
  1556.  
  1557.         case CM_SECURITY_NOT_VALID:
  1558.             *classification = SECURITY_NOT_VALID;
  1559.             break;
  1560.  
  1561.         default:
  1562.             *classification = UNRECOVERABLE;
  1563.             break;
  1564.     }
  1565.     return;
  1566. }
  1567.  
  1568.  
  1569.  
  1570.  
  1571. /*****************************************************************************
  1572.  *
  1573.  *  cpicerr_log_cpicerr()
  1574.  *
  1575.  *  Internal call which logs complete conversation and error information
  1576.  *  to a log file.  Called by cpicerr_handle_rc().
  1577.  *
  1578.  *****************************************************************************/
  1579. int
  1580. cpicerr_log_cpicerr(CPICERR * cpicerr,
  1581.                     char *    file_name,
  1582.                     int       file_line)
  1583. {
  1584.     int      rc;                            /* return value                  */
  1585.     FILE *   log_file;                      /* log file handle               */
  1586.     unsigned count;                         /* used to extract text strings  */
  1587.     char     filepath[256];                 /* actual file path for logging  */
  1588.     char     last_char;
  1589.  
  1590.     if (cpicerr != (CPICERR *)NULL) {
  1591.  
  1592.         /*-------------------------------------------------------------------*
  1593.          * Save the time of the call to this procedure.
  1594.          *-------------------------------------------------------------------*/
  1595.         cpicerr->program_error_time = time(NULL);
  1596.  
  1597.         filepath[0] = '\0';
  1598.         if (cpicerr->log_file_path != NULL &&
  1599.             cpicerr->log_file_path[0] != '\0') {
  1600.             strcpy(filepath, cpicerr->log_file_path);
  1601.             last_char =
  1602.                     cpicerr->log_file_path[strlen(cpicerr->log_file_path)-1];
  1603.             if (!(last_char == '\\' || last_char == '/')) {
  1604.                 strcat(filepath, "/");
  1605.             }
  1606.         }
  1607.         if (cpicerr->log_file_name != NULL) {
  1608.             strcat(filepath, cpicerr->log_file_name);
  1609.         }
  1610.  
  1611.         if ((strlen(filepath) == 0) ||
  1612.                                ((log_file = fopen(filepath, "a")) == NULL  )) {
  1613.             log_file = stderr;
  1614.         }
  1615.  
  1616.         write_log(log_file,
  1617.                   "------------------------------------------------------\n");
  1618.  
  1619.         if (cpicerr->program_name != NULL) {
  1620.             write_log(log_file, "  CPI-C error in program: \"%s\"",
  1621.                                                      cpicerr->program_name);
  1622.         }
  1623.  
  1624.         if (cpicerr->program_info != NULL) {
  1625.             write_log(log_file, ", %s\n", cpicerr->program_info);
  1626.         }
  1627.  
  1628.         if (cpicerr->major_version != 0 || cpicerr->minor_version != 0) {
  1629.             write_log(log_file, "         Program version: %u.%u\n",
  1630.                                        (unsigned int)cpicerr->major_version,
  1631.                                        (unsigned int)cpicerr->minor_version);
  1632.         }
  1633.  
  1634.         cpicerr_log_rc(cpicerr, log_file);
  1635.  
  1636.         if (cpicerr->partner_LU_name[0] != '\0') {
  1637.             cpicerr->partner_LU_name[(int)cpicerr->partner_LU_name_length]
  1638.                                                                        = '\0';
  1639.         }
  1640.         if (cpicerr->mode_name[0] != '\0') {
  1641.             cpicerr->mode_name[(int)cpicerr->mode_name_length] = '\0';
  1642.         }
  1643.         write_log(log_file, "         Partner LU name: %s\n",
  1644.                                                      cpicerr->partner_LU_name);
  1645.         write_log(log_file, "               Mode name: %s\n",
  1646.                                                      cpicerr->mode_name);
  1647.  
  1648.         write_log(log_file, "   CPI-C conversation ID: ");
  1649.  
  1650.         for (count = 0; count<sizeof(cpicerr->conversation_id); count++ ) {
  1651.             write_log(log_file, "%02X",
  1652.                                (unsigned int)cpicerr->conversation_id[count]);
  1653.         }
  1654.         write_log(log_file, "\n");
  1655.  
  1656.         write_log(log_file, "CPI-C conversation state: %lu, %s\n",
  1657.            cpicerr->conversation_state,
  1658.            cpicerr_get_message(CPIC_STATES_CONV, cpicerr->conversation_state));
  1659.  
  1660.         write_log(log_file, " CPI-C conversation type: %lu, %s\n",
  1661.            cpicerr->conversation_type,
  1662.            cpicerr_get_message( CPIC_CONV_TYPES, cpicerr->conversation_type));
  1663.  
  1664.         write_log(log_file, " Conversation sync level: %lu, %s\n",
  1665.                 cpicerr->sync_level,
  1666.                 cpicerr_get_message( CPIC_SYNC_LEVELS, cpicerr->sync_level));
  1667.  
  1668.  
  1669.  
  1670.  
  1671.         write_log(log_file, "      Program start time: %s",
  1672.                                         ctime(&(cpicerr->program_start_time)));
  1673.         write_log(log_file, "      Program error time: %s",
  1674.                                         ctime(&(cpicerr->program_error_time)));
  1675.         write_log(log_file, " Called from source file: %s\n", file_name);
  1676.         write_log(log_file, "                 at line: %d\n", file_line);
  1677.  
  1678.         fclose(log_file);
  1679.  
  1680.         rc = 0;
  1681.     } else {
  1682.         rc = 1;
  1683.     }
  1684.  
  1685.     return rc;
  1686. }
  1687.  
  1688.  
  1689.  
  1690.  
  1691. CPICERR_MESSAGE cpicerr_verbs_short[] = {
  1692.     MSG_CMACCP,         "CMACCP",
  1693.     MSG_CMALLC,         "CMALLC",
  1694.     MSG_CMCFM,          "CMCFM",
  1695.     MSG_CMCFMD,         "CMCFMD",
  1696.     MSG_CMDEAL,         "CMDEAL",
  1697.     MSG_CMECS,          "CMECS",
  1698.     MSG_CMECT,          "CMECT",
  1699.     MSG_CMEMN,          "CMEMN",
  1700.     MSG_CMEPLN,         "CMEPLN",
  1701.     MSG_CMESL,          "CMESL",
  1702.     MSG_CMFLUS,         "CMFLUS",
  1703.     MSG_CMINIT,         "CMINIT",
  1704.     MSG_CMPTR,          "CMPTR",
  1705.     MSG_CMRCV,          "CMRCV",
  1706.     MSG_CMRTS,          "CMRTS",
  1707.     MSG_CMSCT,          "CMSCT",
  1708.     MSG_CMSDT,          "CMSDT",
  1709.     MSG_CMSED,          "CMSED",
  1710.     MSG_CMSEND,         "CMSEND",
  1711.     MSG_CMSERR,         "CMSERR",
  1712.     MSG_CMSF,           "CMSF",
  1713.     MSG_CMSLD,          "CMSLD",
  1714.     MSG_CMSMN,          "CMSMN",
  1715.     MSG_CMSPLN,         "CMSPLN",
  1716.     MSG_CMSPTR,         "CMSPTR",
  1717.     MSG_CMSRC,          "CMSRC",
  1718.     MSG_CMSRT,          "CMSRT",
  1719.     MSG_CMSSL,          "CMSSL",
  1720.     MSG_CMSST,          "CMSST",
  1721.     MSG_CMSTPN,         "CMSTPN",
  1722.     MSG_CMTRTS,         "CMTRTS",
  1723.     MSG_XCSCSU,         "XCSCSU",
  1724.     MSG_XCSCSP,         "XCSCSP",
  1725.     MSG_XCSCST,         "XCSCST",
  1726.     MSG_XCECST,         "XCECST",
  1727.     MSG_XCECSU,         "XCECSU",
  1728.     MSG_XCMSSI,         "XCMSSI",
  1729.     MSG_XCMESI,         "XCMESI",
  1730.     MSG_XCMDSI,         "XCMDSI",
  1731.     MAX_MESSAGE,        "ERROR "
  1732. };
  1733.  
  1734. CPICERR_MESSAGE cpicerr_verbs_long[] = {
  1735.     MSG_CMACCP,         "Accept_Conversation",
  1736.     MSG_CMALLC,         "Allocate",
  1737.     MSG_CMCFM,          "Confirm",
  1738.     MSG_CMCFMD,         "Confirmed",
  1739.     MSG_CMDEAL,         "Deallocate",
  1740.     MSG_CMECS,          "Extract_Conversation_State",
  1741.     MSG_CMECT,          "Extract_Conversation_Type",
  1742.     MSG_CMEMN,          "Extract_Mode_Name",
  1743.     MSG_CMEPLN,         "Extract_Partner_LU_Name",
  1744.     MSG_CMESL,          "Extract_Sync_Level",
  1745.     MSG_CMFLUS,         "Flush",
  1746.     MSG_CMINIT,         "Initialize_Conversation",
  1747.     MSG_CMPTR,          "Prepare_To_Receive",
  1748.     MSG_CMRCV,          "Receive",
  1749.     MSG_CMRTS,          "Request_To_Send",
  1750.     MSG_CMSCT,          "Set_Conversation_Type",
  1751.     MSG_CMSDT,          "Set_Deallocate_Type",
  1752.     MSG_CMSED,          "Set_Error_Direction",
  1753.     MSG_CMSEND,         "Send_Data",
  1754.     MSG_CMSERR,         "Send_Error",
  1755.     MSG_CMSF,           "Set_Fill",
  1756.     MSG_CMSLD,          "Set_Log_Data",
  1757.     MSG_CMSMN,          "Set_Mode_Name",
  1758.     MSG_CMSPLN,         "Set_Partner_LU_Name",
  1759.     MSG_CMSPTR,         "Set_Prepare_To_Receive_Type",
  1760.     MSG_CMSRC,          "Set_Return_Control",
  1761.     MSG_CMSRT,          "Set_Receive_Type",
  1762.     MSG_CMSSL,          "Set_Sync_Level",
  1763.     MSG_CMSST,          "Set_Send_Type",
  1764.     MSG_CMSTPN,         "Set_TP_Name",
  1765.     MSG_CMTRTS,         "Test_Request_To_Send_Received",
  1766.     MSG_XCSCSU,         "Set Conversation Security Userid",
  1767.     MSG_XCSCSP,         "Set Conversation Security Password",
  1768.     MSG_XCSCST,         "Set Conversation Security Type",
  1769.     MSG_XCECST,         "Extract_Conversation_Security_Type",
  1770.     MSG_XCECSU,         "Extract_Conversation_Security_Userid",
  1771.     MSG_XCMSSI,         "Set_CPIC_Side_Information",
  1772.     MSG_XCMESI,         "Extract_CPIC_Side_Information",
  1773.     MSG_XCMDSI,         "Delete_CPIC_Side_Information",
  1774.     MAX_MESSAGE,        "Invalid verb name"
  1775. };
  1776.  
  1777. CPICERR_MESSAGE cpicerr_return_codes[] = {
  1778.     CM_OK,                          "CM_OK",
  1779.     CM_ALLOCATE_FAILURE_NO_RETRY,   "CM_ALLOCATE_FAILURE_NO_RETRY",
  1780.     CM_ALLOCATE_FAILURE_RETRY,      "CM_ALLOCATE_FAILURE_RETRY",
  1781.     CM_CONVERSATION_TYPE_MISMATCH,  "CM_CONVERSATION_TYPE_MISMATCH",
  1782.     CM_PIP_NOT_SPECIFIED_CORRECTLY, "CM_PIP_NOT_SPECIFIED_CORRECTLY",
  1783.     CM_SECURITY_NOT_VALID,          "CM_SECURITY_NOT_VALID",
  1784.     CM_TP_NOT_AVAILABLE_NO_RETRY,   "CM_TP_NOT_AVAILABLE_NO_RETRY",
  1785.     CM_TP_NOT_AVAILABLE_RETRY,      "CM_TP_NOT_AVAILABLE_RETRY",
  1786.     CM_DEALLOCATED_ABEND,           "CM_DEALLOCATED_ABEND",
  1787.     CM_DEALLOCATED_NORMAL,          "CM_DEALLOCATED_NORMAL",
  1788.     CM_PARAMETER_ERROR,             "CM_PARAMETER_ERROR",
  1789.     CM_PRODUCT_SPECIFIC_ERROR,      "CM_PRODUCT_SPECIFIC_ERROR",
  1790.     CM_PROGRAM_ERROR_NO_TRUNC,      "CM_PROGRAM_ERROR_NO_TRUNC",
  1791.     CM_PROGRAM_ERROR_PURGING,       "CM_PROGRAM_ERROR_PURGING",
  1792.     CM_PROGRAM_ERROR_TRUNC,         "CM_PROGRAM_ERROR_TRUNC",
  1793.     CM_PROGRAM_PARAMETER_CHECK,     "CM_PROGRAM_PARAMETER_CHECK",
  1794.     CM_PROGRAM_STATE_CHECK,         "CM_PROGRAM_STATE_CHECK",
  1795.     CM_RESOURCE_FAILURE_NO_RETRY,   "CM_RESOURCE_FAILURE_NO_RETRY",
  1796.     CM_RESOURCE_FAILURE_RETRY,      "CM_RESOURCE_FAILURE_RETRY",
  1797.     CM_UNSUCCESSFUL,                "CM_UNSUCCESSFUL",
  1798.     CM_DEALLOCATED_ABEND_SVC,       "CM_DEALLOCATED_ABEND_SVC",
  1799.     CM_DEALLOCATED_ABEND_TIMER,     "CM_DEALLOCATED_ABEND_TIMER",
  1800.     CM_SVC_ERROR_NO_TRUNC,          "CM_SVC_ERROR_NO_TRUNC",
  1801.     CM_SVC_ERROR_PURGING,           "CM_SVC_ERROR_PURGING",
  1802.     CM_SVC_ERROR_TRUNC,             "CM_SVC_ERROR_TRUNC",
  1803.     MAX_MESSAGE,                    "Invalid Return Code Value"
  1804. };
  1805.  
  1806. CPICERR_MESSAGE cpicerr_rc_classes[] = {
  1807.     BACKOUT_RECEIVED,   "BACKOUT_RECEIVED",
  1808.     CONTINUE,           "CONTINUE",
  1809.     ERROR_RECEIVED,     "ERROR_RECEIVED",
  1810.     SECURITY_NOT_VALID, "SECURITY_NOT_VALID",
  1811.     RETRY_CONV,         "RETRY_CONVERSATION",
  1812.     RETRY_CONV_BO,      "RETRY_CONVERSATION_BACKOUT",
  1813.     RETRY_VERB,         "RETRY_LAST_VERB",
  1814.     UNRECOVERABLE,      "UNRECOVERABLE",
  1815.     UNRECOVERABLE_BO,   "UNRECOVERABLE_BACKOUT",
  1816.     MAX_MESSAGE,        "Invalid Return Code Class"
  1817. };
  1818.  
  1819. CPICERR_MESSAGE cpicerr_states_conv[] = {
  1820.     CM_INITIALIZE_STATE,            "Initialize state",
  1821.     CM_SEND_STATE,                  "Send state",
  1822.     CM_RECEIVE_STATE,               "Receive state",
  1823.     CM_SEND_PENDING_STATE,          "Send pending state",
  1824.     CM_CONFIRM_STATE,               "Confirm state",
  1825.     CM_CONFIRM_SEND_STATE,          "Confirm send state",
  1826.     CM_CONFIRM_DEALLOCATE_STATE,    "Confirm deallocate state",
  1827.     CMECS_NOT_SUPPORTED,            "CMECS not supported",
  1828.     MAX_MESSAGE,                    "Invalid Conversation State value"
  1829. };
  1830.  
  1831. CPICERR_MESSAGE cpicerr_sync_levels[] = {
  1832.     CM_NONE,            "None",
  1833.     CM_CONFIRM,         "Confirm",
  1834.     MAX_MESSAGE,        "Invalid Sync Level value"
  1835. };
  1836.  
  1837. CPICERR_MESSAGE cpicerr_conv_types[] = {
  1838.     CM_BASIC_CONVERSATION , "Basic",
  1839.     CM_MAPPED_CONVERSATION, "Mapped",
  1840.     MAX_MESSAGE,            "Invalid conversation type value"
  1841. };
  1842.  
  1843. CPICERR_MESSAGE_LIST message_list[] = {
  1844.     CPIC_SYNC_LEVELS,   cpicerr_sync_levels,
  1845.     CPIC_CONV_TYPES,    cpicerr_conv_types,
  1846.     CPIC_STATES_CONV,   cpicerr_states_conv,
  1847.     CPIC_RC_CLASSES,    cpicerr_rc_classes,
  1848.     CPIC_RETURN_CODES,  cpicerr_return_codes,
  1849.     CPIC_VERBS_SHORT,   cpicerr_verbs_short,
  1850.     CPIC_VERBS_LONG,    cpicerr_verbs_long,
  1851.     MAX_MESSAGE,        NULL
  1852. };
  1853.  
  1854. /*****************************************************************************
  1855.  *
  1856.  *  cpicerr_get_message()
  1857.  *
  1858.  *  Loop through the message arrays looking for the message type and
  1859.  *  message index.  Return a pointer to the appropriate string.
  1860.  *
  1861.  *  This procedure will never return NULL, thus is safe to use in
  1862.  *  printf() type calls.
  1863.  *
  1864.  *****************************************************************************/
  1865. char *
  1866. cpicerr_get_message(CPICERR_MESSAGE_TYPE message_type, CM_INT32 index)
  1867. {
  1868.     unsigned int count;                     /* counter through the array     */
  1869.  
  1870.     CPICERR_MESSAGE * messages;
  1871.  
  1872.     for (count = 0; message_list[count].type < MAX_MESSAGE ; count++ ) {
  1873.         if (message_list[count].type == message_type) break;
  1874.     }
  1875.  
  1876.     if ( (messages = message_list[count].list) == NULL ) {
  1877.         return "Message list not found.";
  1878.     }
  1879.  
  1880.     for (count = 0; messages[count].index < MAX_MESSAGE; count++) {
  1881.        if (messages[count].index == index) break;
  1882.     }
  1883.     return messages[count].message;
  1884. }
  1885.  
  1886.  
  1887.  
  1888. /*****************************************************************************
  1889.  *
  1890.  *  cpicerr_show_product_info
  1891.  *
  1892.  *****************************************************************************/
  1893. void
  1894. cpicerr_show_product_info(CPICERR * cpicerr)
  1895. {
  1896.     if (cpicerr->conv_rc == CM_ALLOCATE_FAILURE_NO_RETRY ||
  1897.         cpicerr->conv_rc == CM_ALLOCATE_FAILURE_RETRY ) {
  1898. #if defined(GET_OS2_SENSE_DATA)
  1899. #if defined(FAPI)
  1900.         if (get_machine_mode()) {
  1901. #endif
  1902.              write_error(
  1903.              "\n  Retrying Allocate to extract OS/2 sense data:\n");
  1904.             cpicerr_os2_appc_allocate(cpicerr);
  1905. #if defined(FAPI)
  1906.         }
  1907. #endif
  1908. #endif
  1909.  
  1910.     }
  1911. }
  1912.  
  1913. #ifdef GET_OS2_SENSE_DATA
  1914.  
  1915. cpicerr_os2_appc_allocate(CPICERR * cpicerr)
  1916. /*
  1917.  * This procedure retries the allocate that failed in CPI-C.  We are not
  1918.  * retrying the allocate to establish the connection, but to get more
  1919.  * error information about why the first allocate failed.
  1920.  *
  1921.  * The OS/2 APPC api is used to extract the sense data, which provides
  1922.  * a more specify reason for an allocation failure.
  1923.  */
  1924. {
  1925.    TP_STARTED tp_started;                    /* Declare a verb control block */
  1926.    TP_STARTED *ptr_tp_started = (TP_STARTED *)&tp_started;
  1927.    int    length;                            /* length of lu_alias           */
  1928.    char   plu_alias[8+1];
  1929.    char   fqplu_name[17+1];
  1930.  
  1931.    ALLOCATE allocate;                        /* Declare a verb control block */
  1932.    ALLOCATE *ptr_allocate = (ALLOCATE *)&allocate;
  1933.  
  1934.    TP_ENDED tp_ended;                        /* Declare a verb control block */
  1935.    TP_ENDED *ptr_tp_ended = (TP_ENDED *)&tp_ended;
  1936.  
  1937.  
  1938.    CLEAR_VCB(tp_started);                    /* Zero the verb control block  */
  1939.    tp_started.opcode = AP_TP_STARTED;        /* APPC verb - TP_STARTED       */
  1940.  
  1941.    memset( tp_started.lu_alias, (int)'\0', sizeof(tp_started.lu_alias));
  1942.  
  1943.    BLANK_STRING(tp_started.tp_name);         /* Set 64-byte string to blanks */
  1944.    ascii_to_ebcdic_field(tp_started.tp_name,
  1945.                          sizeof(tp_started.tp_name));
  1946.  
  1947.    APPC ((ULONG) (TP_STARTED far *)ptr_tp_started); /* Issue the verb        */
  1948.  
  1949.    if (tp_started.primary_rc == AP_OK) {
  1950.        CLEAR_VCB(allocate);                  /* Zero the vcb                 */
  1951.        allocate.opcode = AP_B_ALLOCATE;      /* Verb - ALLOCATE              */
  1952.        allocate.opext = AP_MAPPED;           /* Basic Conversation type      */
  1953.  
  1954.                                              /* Set the TP_ID */
  1955.        memcpy (allocate.tp_id, tp_started.tp_id, sizeof(allocate.tp_id));
  1956.        allocate.sync_level = AP_CONFIRM;     /* Sync level-confirm           */
  1957.        allocate.rtn_ctl = AP_WHEN_SESSION_FREE;/* avoid deadlock             */
  1958.        allocate.security = AP_NONE;          /* Set security type            */
  1959.  
  1960.        if (!parse_destination(cpicerr->partner_LU_name,
  1961.                               plu_alias,
  1962.                               fqplu_name)) {
  1963.           if ((length = strlen(plu_alias)) != 0) {
  1964.              BLANK_STRING(allocate.plu_alias);
  1965.              memcpy ( allocate.plu_alias,
  1966.                       plu_alias,
  1967.                       min(length, sizeof(allocate.plu_alias)));
  1968.                                              /* Set PLU_ALIAS                */
  1969.           } else {
  1970.              memset (allocate.plu_alias,(int)'\0',sizeof(allocate.plu_alias));
  1971.              BLANK_STRING(allocate.fqplu_name);  /* Set FQ PLU NAME          */
  1972.              memcpy ( allocate.fqplu_name,
  1973.                       fqplu_name,
  1974.                       min(strlen(fqplu_name), sizeof(allocate.fqplu_name)));
  1975.              TOUPPER_STRING(allocate.fqplu_name, 17);
  1976.              ascii_to_ebcdic_field(allocate.fqplu_name,
  1977.                                    sizeof(allocate.fqplu_name));
  1978.           }
  1979.  
  1980.  
  1981.        } else {
  1982.           BLANK_STRING(allocate.plu_alias);
  1983.           memcpy ( allocate.plu_alias,
  1984.                    "UNKNOWN",
  1985.                    7);
  1986.        }
  1987.  
  1988.  
  1989.        BLANK_STRING(allocate.tp_name);       /* Set 64-byte string to blanks */
  1990.        ascii_to_ebcdic_field(allocate.tp_name,
  1991.                              sizeof(allocate.tp_name));
  1992.  
  1993.        BLANK_STRING(allocate.mode_name);     /* Set 8-byte string to blanks  */
  1994.           memcpy ( allocate.mode_name,
  1995.                    cpicerr->mode_name,
  1996.                    min(strlen(cpicerr->mode_name),
  1997.                        sizeof(allocate.mode_name)));
  1998.           TOUPPER_STRING(allocate.mode_name, 8);
  1999.        ascii_to_ebcdic_field(allocate.mode_name,
  2000.                              sizeof(allocate.mode_name));
  2001.  
  2002.        APPC((ULONG) (ALLOCATE far *) ptr_allocate);  /* Issue the verb       */
  2003.  
  2004.        if (allocate.primary_rc != AP_OK) {
  2005.         write_error(
  2006.         "\t OS/2 Sense Data: %08lX\n", SWAP4(allocate.sense_data));
  2007.  
  2008.        }
  2009.  
  2010.    } else {                                  /* Save the returned tp_id      */
  2011.        return (tp_started.primary_rc);
  2012.    }
  2013.    CLEAR_VCB(tp_ended);                      /* Zero the verb control block  */
  2014.    tp_ended.opcode = AP_TP_ENDED;            /* Set the verb opcode          */
  2015.                                              /* Set the tp_id  */
  2016.    memcpy (tp_ended.tp_id, tp_started.tp_id, sizeof(tp_ended.tp_id));
  2017.    tp_ended.type = AP_SOFT;                  /* type: AP_HARD or AP_SOFT     */
  2018.  
  2019.    APPC((ULONG) (TP_ENDED far *) ptr_tp_ended); /* Issue the verb.           */
  2020. }
  2021.  
  2022.  
  2023.  
  2024. int
  2025. parse_destination(char * in_string,
  2026.                   char * plu_alias,
  2027.                   char * fqplu_name)
  2028. /*
  2029.  * This procedure is used by cpicerr_os2_appc_allocate verb
  2030.  */
  2031. {
  2032.    if (strchr(in_string, '.') != NULL) {
  2033.       if (in_string[0] == '.') {
  2034.           in_string++;
  2035.       }
  2036.       strcpy(fqplu_name, in_string);
  2037.       plu_alias[0] = '\0';
  2038.    } else {
  2039.       strcpy(plu_alias, in_string);
  2040.       fqplu_name[0] = '\0';
  2041.    }
  2042.    return 0;
  2043.  
  2044. }
  2045.  
  2046. #endif
  2047.  
  2048.