home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- *
- * MODULE NAME: CPICERR.C
- *
- * COPYRIGHTS:
- * This module contains code made available by IBM
- * Corporation on an AS IS basis. Any one receiving the
- * module is considered to be licensed under IBM copyrights
- * to use the IBM-provided source code in any way he or she
- * deems fit, including copying it, compiling it, modifying
- * it, and redistributing it, with or without
- * modifications. No license under any IBM patents or
- * patent applications is to be implied from this copyright
- * license.
- *
- * A user of the module should understand that IBM cannot
- * provide technical support for the module and will not be
- * responsible for any consequences of use of the program.
- *
- * Any notices, including this one, are not to be removed
- * from the module without the prior written consent of
- * IBM.
- *
- * AUTHOR: Peter J. Schwaller
- * VNET: PJS at RALVM6 Tie Line: 444-4376
- * Internet: pjs@ralvm6.vnet.ibm.com (919) 254-4376
- *
- * John Q. Walker
- * VNET: JOHNQ at RALVM6 Tie Line: 444-4414
- * Internet: johnq@ralvm6.vnet.ibm.com (919) 254-4414
- *
- * FUNCTION: Contains procedures to be called for handling
- * unexpected CPI-C return codes.
- * Contains procedures to be called for handling the
- * CPI-C error information cpicerr.
- *
- * AVAILABILITY:
- * These sample programs and source are also available on
- * CompuServe through the APPC Information Exchange. To get
- * to the APPC forum just type 'GO APPC' from any CompuServe
- * prompt. The samples are available in the Sample Programs
- * library section. Just search on the keyword CPICPGMS to
- * find all the samples in this series.
- *
- * Updates for the sample programs and support for many more
- * CPI-C platforms will also be made available on CompuServe.
- *
- * RELATED FILES:
- * CPICERR.H
- *
- * CHANGE HISTORY:
- * Date Description
- * 08/05/92 Version 2.31 of APING, ATELL and AREXEC released to CompuServe.
- * This version was also distributed at the APPC/APPN Platform
- * Developer's Conference held in Raleigh, NC.
- * 08/13/92 Changed all printf and fprintf calls to use a write_*() call.
- * Changed cpicerr_handle_rc() to a macro referencing a new call,
- * cpicerr_handle_rc_extended(). The macro adds the current
- * source file and line number to improve source code debugging.
- * 08/15/92 Changed cpicerr_exchange_version() to receive 128 bytes
- * instead of 3 bytes. This change was also made to the
- * NS/DOS ship code.
- * 08/18/92 Removed extra newline in cpicerr_show_rc().
- * 09/02/92 Fixed bug in cpicerr_log_cpicerr() when the log_file_path
- * was a zero length string.
- * 11/15/92 Changed reply structure to include 2 byte indicator.
- * 11/17/92 Added send/receipt of operating system string.
- * Added cpicerr_exchange_version_plus() to return the string.
- *
- *****************************************************************************/
-
- /*****************************************************************************
- *
- * OVERVIEW OF CPICERR CALLS
- *
- * cpicerr_new() Creates a CPICERR object.
- * This must be done before any other
- * cpicerr calls can be used.
- *
- * These calls set values in the cpicerr object structure and affect how
- * cpicerr_handle_rc reacts to errors.
- *
- * cpicerr_set_conv_id() Used to extract conversation state info
- * cpicerr_set_exit_level() Level of error on which to exit
- * cpicerr_set_log_file_name() What filename to use for logging
- * cpicerr_set_log_file_path() Where the filename is
- * cpicerr_set_log_level() Level of error on which to log errors
- * cpicerr_set_major_version() 8 bit int - see cpicerr_exchange_version
- * cpicerr_set_minor_version() 8 bit int - see cpicerr_exchange_version
- * cpicerr_set_program_name() String - Output as part of log info
- * cpicerr_set_program_info() String - Output as part of log info
- * cpicerr_set_show_level() Level of error on which to show errors
- *
- * cpicerr_handle_rc() Should be called by the program for all
- * UNEXPECTED return codes.
- * Functions performed are:
- * Classification of the return code
- * Showing partial info to end user
- * Logging complete info to disk
- * This is a macro that actually expands
- * to cpicerr_handle_rc_extended().
- *
- * cpicerr_exchange_version() Exchanges version numbers with the
- * partner. Very useful when supporting
- * multiple versions of a program.
- *
- * cpicerr_destroy() Destroys the CPICERR object.
- *
- *
- * cpicerr_classify_rc() These are internal calls used by
- * cpicerr_show_rc() other cpicerr_handle_rc.
- * cpicerr_log_rc()
- * cpicerr_log_cpicerr()
- * cpicerr_get_message()
- * cpicerr_set_rc_info()
- * cpicerr_show_product_info()
- *
- *****************************************************************************/
- #if defined(WIN32) || defined(WINDOWS) /*WIN32*/
- #include <windows.h> /*WIN32*/
- #define GET_OS2_SENSE_DATA /*WIN32*/
- #endif /*WIN32*/
-
- #include "wincpic.h"
-
- #ifdef GET_OS2_SENSE_DATA
- #include <winappc.h>
- #endif
-
- /* Set up constant declarations */
- #include "cpicdefs.h"
-
- /* Collection of routines with special ported version for each platform */
- #include "cpicport.h"
-
- #include <stdio.h> /* C library includes */
- #include <stdlib.h>
- #include <string.h>
-
- #include <time.h>
-
- #include "cpicerrs.h" /* CPI-C error handling vars. */
-
- /*
- * Each of the following is a list of messages, which are actually defined
- * in this file below. The messages are grouped together. For example,
- * all of the return code messages are in the cpicerr_return_codes list.
- */
- extern CPICERR_MESSAGE cpicerr_verbs_short[];
- extern CPICERR_MESSAGE cpicerr_verbs_long[];
- extern CPICERR_MESSAGE cpicerr_return_codes[];
- extern CPICERR_MESSAGE cpicerr_rc_classes[];
- extern CPICERR_MESSAGE cpicerr_states_conv[];
- extern CPICERR_MESSAGE cpicerr_conv_types[];
- extern CPICERR_MESSAGE cpicerr_sync_levels[];
-
- /*****************************************************************************
- * Function prototypes for internal routines. In general, these should
- * not be called directly by an application program.
- *****************************************************************************/
- void cpicerr_classify_rc( CM_RETURN_CODE conv_rc,
- CPIC_RC_HANDLING * classification);
- void cpicerr_show_rc( CPICERR * cpicerr);
- void cpicerr_log_rc( CPICERR * cpicerr,
- FILE * log_file);
- int cpicerr_log_cpicerr( CPICERR * cpicerr,
- char * file_name,
- int file_line);
- char * cpicerr_get_message( CPICERR_MESSAGE_TYPE message_type,
- CM_INT32 index);
- void cpicerr_set_rc_info( CPICERR * cpicerr,
- CPIC_VERB_INDEX verb_index,
- CM_RETURN_CODE conv_rc);
- void cpicerr_show_product_info(CPICERR * cpicerr);
-
- /*****************************************************************************
- * The following function prototypes and macros are used only by the
- * OS/2 specific code used to obtain the sense data after an
- * allocation failure. They are not necessary, if GET_OS2_SENSE_DATA
- * has not been externally defined (with the -D compile flag).
- *****************************************************************************/
- #ifdef GET_OS2_SENSE_DATA
- int cpicerr_os2_appc_allocate(CPICERR * cpicerr);
-
- int
- parse_destination(char * in_string,
- char * plu_alias,
- char * fqplu_name);
-
-
-
-
- /* Macro BLANK_STRING sets string to all blanks */
- #define BLANK_STRING(str) memset(str,(int)' ',sizeof(str))
-
- #undef CLEAR_VCB
- /* Macro CLEAR_VCB sets the APPC verb control block to zeros */
- #define CLEAR_VCB(vcb) memset((char *)&vcb,(int)'\0',sizeof(vcb))
-
- /* convert a string to uppercase, up to length specified */
- #define TOUPPER_STRING(str,length) \
- {int i; for (i=0;i < length;i ++) \
- {str[i] = (char)toupper(str[i]);}}
-
- /* convert an ASCII blank padded string to an ASCIIZ string without pads */
- #define SNA2STRING(outstr, instr, max_length) \
- {int i; for (i=0;i < max_length && instr[i] != ' ';i ++) \
- {outstr[i] = instr[i];} outstr[i] = '\0';}
-
- #endif
-
-
- /*
- * The error REPLY routines below are experimental and may change
- * at any time!
- */
-
- void
- cpicerr_show_reply(CPICERR_REPLY * reply)
- {
- unsigned short length;
- unsigned short offset;
- unsigned short indicator;
- int rc = 0;
-
- if (reply->length >= CPICERR_REPLY_MIN_LENGTH) {
- write_error(
- "\nAn application error was detected by the partner:\n");
- indicator =
- convert_short_from_network(
- *((unsigned short*)&reply->buffer[CPICERR_REPLY_INDICATOR]));
- if (indicator == CPICERR_REPLY_INDICATOR_VALUE) {
- write_error("Response: %d\n",
- (int)reply->buffer[CPICERR_REPLY_RESPONSE]);
- write_error("Message Category: %u\n",
- convert_short_from_network(
- *((unsigned short*)&reply->buffer[CPICERR_REPLY_CATEGORY])));
- write_error("Primary Code: %ld\n",
- convert_long_from_network(
- *((unsigned long *)&reply->buffer[CPICERR_REPLY_PRIMARY])));
- write_error("Secondary Code: %ld\n",
- convert_long_from_network(
- *((unsigned long *)&reply->buffer[CPICERR_REPLY_SECONDARY])));
-
-
- if (reply->length >=
- (unsigned int)(CPICERR_REPLY_MIN_LENGTH + 2)) {
- length = convert_short_from_network(
- *((unsigned short *)
- &reply->buffer[CPICERR_REPLY_PRIMARY_LENGTH]));
-
- if (reply->length >=
- (unsigned int)(CPICERR_REPLY_PRIMARY_TEXT+length)) {
- reply->buffer[length + CPICERR_REPLY_PRIMARY_TEXT - 1] =
- '\0';
- write_error("%s\n",
- &reply->buffer[CPICERR_REPLY_PRIMARY_TEXT]);
- offset = CPICERR_REPLY_PRIMARY_TEXT + length;
- if (reply->length >= 2+offset) {
- length = convert_short_from_network(
- *((unsigned short *)&reply->buffer[offset]));
- if (reply->length >= (offset+ 2 +length)) {
- reply->buffer[length + offset + 2] = '\0';
- write_error("%s\n", &reply->buffer[offset+2]);
- }
- else {
- rc = 1;
- }
- }
- else {
- rc = 1;
- }
- }
- else {
- rc = 1;
- }
- }
- else {
- write_error("No text strings were sent.\n");
- }
- }
- else {
- write_error("Record received was not a reply structure.\n");
- }
-
- }
- else {
- rc = 1;
- }
- if (rc) {
- write_error("Reply length error in cpicerr_show_reply().\n");
- }
- }
-
-
- CPICERR_REPLY *
- cpicerr_create_reply(unsigned int primary_message_buffer_size,
- unsigned int secondary_message_buffer_size)
- {
- CPICERR_REPLY * reply;
-
- reply = calloc(1, sizeof(CPICERR_REPLY));
- if (reply == NULL) {
- return NULL;
- }
-
- reply->buffer_length = CPICERR_REPLY_MIN_LENGTH+
- primary_message_buffer_size+1 +
- secondary_message_buffer_size+1 +
- 4; /* two length fields */
- reply->buffer = calloc(reply->buffer_length, 1);
- if (reply == NULL) {
- return NULL;
- }
-
- return reply;
- }
-
- void
- cpicerr_destroy_reply(CPICERR_REPLY * reply)
- {
- /*
- * Make sure we don't free any NULL pointers!
- */
- if (reply != NULL) {
- if (reply->buffer != NULL) {
- free(reply->buffer);
- }
- free(reply);
- }
- }
-
-
-
- /*
- * Requires that cpicerr_set_conv_id() has been called.
- */
- int cpicerr_recv_appl_error(CPICERR * cpicerr,
- CPICERR_REPLY * reply)
- {
- CM_RETURN_CODE cm_rc;
- CM_INT32 rts_received;
- CM_INT32 max_receive_len;
- CM_INT32 what_received;
- CM_INT32 received_len;
- CM_INT32 status_received;
-
- max_receive_len = reply->buffer_length;
-
- cmrcv (cpicerr->conversation_id,
- reply->buffer,
- &max_receive_len,
- &what_received,
- &received_len,
- &status_received,
- &rts_received,
- &cm_rc);
-
- reply->length = (unsigned int)received_len;
-
- return reply->buffer[0];
- }
-
-
- void
- cpicerr_set_error_reply(CPICERR_REPLY * reply,
- REPLY_RESPONSE response,
- unsigned int message_category,
- unsigned long primary_code,
- char * primary_message_text,
- unsigned long secondary_code,
- char * secondary_message_text)
- {
- unsigned int length = 0;
- unsigned short string_length;
-
- /*
- * Check and see that there is at least enough space in the reply_buffer
- * to sent the required fields. If there is not enough space, return
- * 0 (zero) to the caller, indicating that no bytes were copied into
- * the reply_buffer.
- */
- if (reply->buffer_length < CPICERR_REPLY_MIN_LENGTH) {
- reply->length = 0;
- return/* 0 */;
- }
-
- *((unsigned short *)&reply->buffer[CPICERR_REPLY_INDICATOR]) =
- convert_short_to_network(CPICERR_REPLY_INDICATOR_VALUE);
- reply->buffer[CPICERR_REPLY_RESPONSE] = (char)response;
- reply->buffer[CPICERR_REPLY_RESERVED] = 0; /* set reserved byte to zero */
- *((unsigned short *)&reply->buffer[CPICERR_REPLY_CATEGORY]) =
- convert_short_to_network(message_category);
- *((unsigned long *)&reply->buffer[CPICERR_REPLY_PRIMARY]) =
- convert_long_to_network(primary_code);
- *((unsigned long *)&reply->buffer[CPICERR_REPLY_SECONDARY]) =
- convert_long_to_network(secondary_code);
- length = CPICERR_REPLY_MIN_LENGTH;
-
-
- /* check length of buffer!!! */
-
- /*
- * Copy the length and text of the primary message.
- */
- string_length = strlen(primary_message_text) + 1;
- *((unsigned short *)&reply->buffer[CPICERR_REPLY_PRIMARY_LENGTH]) =
- convert_short_to_network(string_length);
- memcpy(&reply->buffer[CPICERR_REPLY_PRIMARY_TEXT],
- primary_message_text,
- string_length);
- convert_to_ascii(&reply->buffer[CPICERR_REPLY_PRIMARY_TEXT],
- string_length);
-
- length += 2 + string_length;
-
- /*
- * Copy the length and text of the secondary message.
- */
- string_length = strlen(secondary_message_text) + 1;
- *((unsigned short *)&reply->buffer[length]) =
- convert_short_to_network(string_length);
- memcpy(&reply->buffer[length+2],
- secondary_message_text,
- string_length);
- convert_to_ascii(&reply->buffer[length+2],
- string_length);
-
- length += 2 + string_length;
-
- reply->length = length;
-
- return /* length */;
- }
-
-
-
-
- /*
- * Requires that cpicerr_set_conv_id() has been called.
- */
-
- int
- cpicerr_send_appl_error( CPICERR * cpicerr,
- NEXT_STATE next_state,
- CPICERR_REPLY * reply)
- {
- CM_RETURN_CODE cm_rc;
- CM_INT32 length;
- CM_INT32 rts_received;
- CM_SEND_TYPE send_type;
-
- cmserr(cpicerr->conversation_id,
- &rts_received,
- &cm_rc);
-
-
- switch (next_state) {
- case NEXT_DEALLOCATE:
- case NEXT_DEALLOCATE_AND_EXIT:
- send_type = CM_SEND_AND_DEALLOCATE;
- {
- CM_INT32 deallocate_type = CM_DEALLOCATE_FLUSH;
- cmsdt(cpicerr->conversation_id,
- &deallocate_type,
- &cm_rc);
- }
- break;
- case NEXT_SEND:
- send_type = CM_SEND_AND_FLUSH;
- break;
- case NEXT_RECEIVE:
- send_type = CM_SEND_AND_PREP_TO_RECEIVE;
- {
- CM_PREPARE_TO_RECEIVE_TYPE ptr_type;
- ptr_type = CM_PREP_TO_RECEIVE_FLUSH;
- cmsptr (cpicerr->conversation_id,
- &ptr_type,
- &cm_rc);
- }
- break;
- }
-
- cmsst (cpicerr->conversation_id,
- &send_type,
- &cm_rc);
- #if 1
- if (cm_rc != CM_OK) {
- printf("Ouch!!!!!!!!\n");
- }
- else {
- }
- #endif
-
- length = reply->length;
-
- cmsend (cpicerr->conversation_id,
- reply->buffer,
- &length,
- &rts_received,
- &cm_rc);
-
- if (next_state == NEXT_DEALLOCATE_AND_EXIT) {
- exit(EXIT_FAILURE);
- }
-
- #if 1
- printf("didn't exit\n");
- #endif
-
- return 0;
-
- }
-
-
-
- /*****************************************************************************
- *
- * cpicerr_new()
- *
- * Usage:
- * This function creates a CPICERR object which should be used on all
- * subsequent calls to cpicerr. If an error occurs and a valid object
- * cannot be created, NULL will be returned.
- *
- *****************************************************************************/
- CPICERR *
- cpicerr_new(void)
- {
- CPICERR * cpicerr;
-
- /*-----------------------------------------------------------------------*
- * Allocate a block for the CPICERR structure. calloc() will initialize
- * all bytes to 0.
- *-----------------------------------------------------------------------*/
- cpicerr = (CPICERR *) calloc(1, sizeof(*cpicerr));
- if (cpicerr == NULL) {
- return NULL;
- }
-
-
- /*-----------------------------------------------------------------------*
- * Save the time of program initialization.
- *-----------------------------------------------------------------------*/
- cpicerr->program_start_time = time(NULL);
-
- /*-----------------------------------------------------------------------*
- * Indicate that the conversation id field has not been set.
- *-----------------------------------------------------------------------*/
- cpicerr->conv_id_set = FALSE;
-
-
- /*-----------------------------------------------------------------------*
- * Initialize version levels. 0 indicates they have not been set.
- *-----------------------------------------------------------------------*/
- cpicerr->major_version = 0;
- cpicerr->minor_version = 0;
-
- /*-----------------------------------------------------------------------*
- * Initialize to always exit after an error occurs.
- *-----------------------------------------------------------------------*/
- cpicerr->exit_level = ALL_ERRORS;
-
- /*-----------------------------------------------------------------------*
- * Initialize to always show errors.
- *-----------------------------------------------------------------------*/
- cpicerr->show_level = ALL_ERRORS;
-
- /*-----------------------------------------------------------------------*
- * Initialize to always log errors.
- *-----------------------------------------------------------------------*/
- cpicerr->log_level = ALL_ERRORS;
-
- /*-----------------------------------------------------------------------*
- * Indicate that cpicerr should process all ERROR_RECEIVED return codes
- * (indicating our partner issued Send_Error())
- *-----------------------------------------------------------------------*/
- cpicerr->handle_error = TRUE;
-
- /*-----------------------------------------------------------------------*
- * Initialize strings to NULL in case 0 != NULL
- *-----------------------------------------------------------------------*/
- cpicerr->program_name = NULL;
- cpicerr->program_info = NULL;
- cpicerr->log_file_name = NULL;
- cpicerr->log_file_path = NULL;
-
-
- /*-----------------------------------------------------------------------*
- * Set the conversation characteristics to invalid values. If this
- * isn't done, we could display seemingly valid values for these
- * parameters even though they were never set properly.
- *-----------------------------------------------------------------------*/
- cpicerr->conversation_type = MAX_MESSAGE;
- cpicerr->conversation_state = MAX_MESSAGE;
- cpicerr->sync_level = MAX_MESSAGE;
-
- return cpicerr;
- }
-
- /*****************************************************************************
- *
- * cpicerr_set_conv_id
- *
- * Usage:
- * This call should be used just before the cmallc call (for clients),
- * or just after the cmaccp call (for servers).
- *
- * This routine will save the conversation id, as well as partner information
- * and conversation status which can be extracted from CPI-C.
- *
- * This information is often helpful for debugging and in many cases cannot
- * be obtained after an error occurs, since you no longer have a valid
- * conversation id after the conversation has been deallocated.
- *
- * Returns 0 if everything was processed successfully.
- * Returns 1 if an error occurred. In general, the only reason for an
- * error to occur is if one of the passed parameters is invalid. Since
- * this is just storing information in the footprint, we will not
- * attempt to do sophisticated error processing in this procedure.
- *
- *****************************************************************************/
- int
- cpicerr_set_conv_id(CPICERR * cpicerr,
- unsigned char * conversation_id)
- {
- CM_RETURN_CODE conv_rc; /* Return code from CPI-C call */
- int rc; /* return value for function */
-
-
- if (cpicerr != (CPICERR *)NULL) {
- /*-------------------------------------------------------------------*
- * Save the conversation ID.
- * This can often be used in conjunction with error logs or trace
- * utilities.
- *-------------------------------------------------------------------*/
- memcpy(cpicerr->conversation_id,
- conversation_id,
- sizeof(cpicerr->conversation_id));
-
- /*
- * Extract the conversation type.
- */
- cmect(conversation_id, /* Current conversation ID */
- &cpicerr->conversation_type, /* Returned conversation type */
- &conv_rc); /* Put the return code here */
- if (conv_rc != CM_OK) {
- /*
- * Set the conversation type to an invalid value and set
- * the return code to indicate an error.
- */
- cpicerr->conversation_type = MAX_MESSAGE;
- rc = 1;
- }
-
- /*
- * Extract the mode name used for this conversation.
- */
- cmemn(conversation_id, /* Current conversation ID */
- cpicerr->mode_name, /* Returned mode name */
- &(cpicerr->mode_name_length), /* Returned mode name length */
- &conv_rc); /* Put the return code here */
- if (conv_rc != CM_OK) {
- /*
- * Make sure the mode name is reset to uninitialized and
- * set the return code to indicate an error.
- */
- cpicerr->mode_name_length = 0;
- rc = 1;
- }
- /* make sure we place the null terminator at the end of the string */
- cpicerr->mode_name[(int)cpicerr->mode_name_length] = '\0';
-
- /*-------------------------------------------------------------------*
- * Extract the partner's LU name.
- *-------------------------------------------------------------------*/
- cmepln(conversation_id, /* Current conversation ID */
- cpicerr->partner_LU_name, /* Returned partner LU */
- &(cpicerr->partner_LU_name_length),/* Partner LU name length */
- &conv_rc); /* Put the return code here */
- if (conv_rc != CM_OK) {
- /*
- * Make sure the partner LU name is reset to uninitialized and
- * set the return code to indicate an error.
- */
- cpicerr->partner_LU_name_length = 0;
- rc = 1;
- }
- /* make sure we place the null terminator at the end of the string */
- cpicerr->partner_LU_name[(int)cpicerr->partner_LU_name_length] = '\0';
-
- /*-------------------------------------------------------------------*
- * Extract the conversation sync level.
- *-------------------------------------------------------------------*/
- cmesl(conversation_id, /* Current conversation ID */
- &cpicerr->sync_level, /* Returned sync level */
- &conv_rc); /* Put the return code here */
- if (conv_rc != CM_OK) {
- /*
- * Set the sync level to an invalid value and set
- * the return code to indicate an error.
- */
- cpicerr->sync_level = MAX_MESSAGE;
- rc = 1;
- }
-
- rc = 0;
- } else {
- rc = 1;
- }
- return rc;
- }
-
- /*****************************************************************************
- *
- * cpicerr_set_exit_level
- *
- * Usage:
- * Specify the CPI-C error classification as the exit level.
- * When cpicerr_handle_rc() is called, the return code will be classified.
- * If the classification is above the exit level, the program will be
- * terminated (after conversation cleanup).
- *
- * A value of ALL_ERRORS can be used to force an exit on any call to
- * cpicerr_handle_rc(). This is the DEFAULT value.
- *
- * A value of NO_ERRORS can be used to indicate that cpicerr should never
- * cause an exit. Your application should handle all exit termination.
- * This is especially useful when using more than one conversation.
- *
- * Also see:
- * cpicerr_set_log_level
- * cpicerr_set_show_level
- *****************************************************************************/
- int
- cpicerr_set_exit_level(CPICERR * cpicerr,
- CPIC_RC_HANDLING exit_level)
- {
- cpicerr->exit_level = exit_level;
- return 0;
- }
-
- /*****************************************************************************
- *
- * cpicerr_set_log_file_name
- *
- * Usage:
- * Sets the name of the log file to be used in cpicerr_handle_rc() to
- * log complete error information. No attempt is made to verify that
- * the log_file_name specified is a valid filename or whether the file
- * can be opened. If the log_file_name cannot be opened when logging
- * needs to be done, all log output will be sent to stderr instead.
- *
- * For environments that support directory structures, you should specify
- * the filename on cpicerr_set_log_file_name and the directory on
- * cpicerr_set_log_file_path. This allows your program to be isolated
- * from changes in environments that only support a single level
- * of directory (for example, VM).
- *
- * Also see:
- * cpicerr_set_log_file_path
- * cpicerr_log_cpicerr (internal)
- *****************************************************************************/
- int
- cpicerr_set_log_file_name(CPICERR * cpicerr,
- char * log_file_name)
- {
- /*-----------------------------------------------------------------------*
- * Initialize the name of the log file.
- *-----------------------------------------------------------------------*/
- cpicerr->log_file_name = (char *) malloc(strlen(log_file_name)+1);
- if (cpicerr->log_file_name != NULL) {
- strcpy(cpicerr->log_file_name, log_file_name);
- return 0;
- } else {
- return 1;
- }
-
- }
-
- /*****************************************************************************
- *
- * cpicerr_set_log_file_path
- *
- * Usage:
- * Specifies the path qualifier for the log file name specified in the
- * cpicerr_set_log_file_name call. If cpicerr_set_log_file_path is used
- * without setting the log file name, no error logging will occur.
- *
- * If you specify a string whose first character is a $, the rest of the
- * string will be looked for as an environment variable. For example,
- * in OS/2, you put the following in your CONFIG.SYS:
- * SET LOGPATH=d:\logfiles
- *
- * then specify $LOGPATH as a parameter on cpicerr_set_log_file_path.
- *
- *****************************************************************************/
- int
- cpicerr_set_log_file_path(CPICERR * cpicerr,
- char * log_file_path)
- {
- char * path;
- int rc;
-
- /*-----------------------------------------------------------------------*
- * Initialize the name of the log file.
- * If the first character is a dollar sign ('$'), then try to extract
- * the log file path from the environment. If not, use the path
- * as specified.
- *-----------------------------------------------------------------------*/
- if (log_file_path[0] == '$') {
- path = getenv(&log_file_path[1]);
- } else {
- path = log_file_path;
- }
-
- /*-----------------------------------------------------------------------*
- * Check that we have a valid log file path string, allocate memory for
- * the string and copy it into the cpicerr structure.
- *-----------------------------------------------------------------------*/
- if (path != NULL) {
- cpicerr->log_file_path = (char *) malloc(strlen(path)+1);
- if (cpicerr->log_file_path != NULL) {
- strcpy(cpicerr->log_file_path, path);
- rc = 0;
- } else {
- rc = 1;
- }
- }
- else {
- rc = 1;
- }
- return rc;
-
- }
-
- /*****************************************************************************
- *
- * cpicerr_set_log_level
- *
- * Usage:
- * Specify the CPI-C error classification as the log level.
- * When cpicerr_handle_rc() is called, the return code will be classified.
- * If the classification is above the log level, the return code and
- * conversation information will be logged to the log file specified
- * with the cpicerr_set_log_file_name and cpicerr_set_log_file_path.
- *
- * A value of ALL_ERRORS can be used to force logging on any call to
- * cpicerr_handle_rc(). This is the DEFAULT value. This is especially
- * useful when used on servers.
- *
- * A value of NO_ERRORS can be used to indicate that cpicerr should never
- * cause an error log. Your application should handle all error logging.
- *
- * Also see:
- * cpicerr_set_log_file_name
- * cpicerr_set_log_file_path
- * cpicerr_log_cpicerr (internal)
- * cpicerr_set_exit_level
- * cpicerr_set_show_level
- *****************************************************************************/
- int
- cpicerr_set_log_level(CPICERR * cpicerr,
- CPIC_RC_HANDLING log_level)
- {
- cpicerr->log_level = log_level;
- return 0;
- }
-
- /*****************************************************************************
- *
- * cpicerr_set_major_version
- *
- * Usage:
- * Sets the major version number for the application.
- * The version number can be 0-255.
- *
- * The version number is used on error logging and by the
- * cpicerr_exchange_version() call.
- *
- * Also see:
- * cpicerr_set_minor_version
- *****************************************************************************/
- int
- cpicerr_set_major_version(CPICERR * cpicerr,
- unsigned char major_version)
- {
- cpicerr->major_version = major_version;
- return 0;
- }
-
- /*****************************************************************************
- *
- * cpicerr_set_minor_version
- *
- * Usage:
- * Sets the minor version number for the application.
- * The version number can be 0-255.
- *
- * The version number is used on error logging and by the
- * cpicerr_exchange_version() call.
- *
- * Also see:
- * cpicerr_set_major_version
- *****************************************************************************/
- int
- cpicerr_set_minor_version(CPICERR * cpicerr,
- unsigned char minor_version)
- {
- cpicerr->minor_version = minor_version;
- return 0;
- }
-
-
- /*****************************************************************************
- *
- * cpicerr_set_program_info
- *
- * Usage:
- * Sets a program information string that is included in the log information.
- *****************************************************************************/
- int
- cpicerr_set_program_info( CPICERR * cpicerr,
- char * program_info)
- {
- int rc;
-
- /*-----------------------------------------------------------------------*
- * Save the application's program information string
- *-----------------------------------------------------------------------*/
- cpicerr->program_info = (char *) malloc(strlen(program_info)+1);
- if (cpicerr->program_info != NULL) {
- strcpy(cpicerr->program_info, program_info);
- rc = 0;
- } else {
- rc = 1;
- }
- return rc;
- }
-
-
- /*****************************************************************************
- *
- * cpicerr_set_program_name
- *
- * Usage:
- * Sets a program name string that is included in the log information.
- *****************************************************************************/
- int
- cpicerr_set_program_name(CPICERR * cpicerr,
- char * program_name)
- {
- int rc;
- /*-----------------------------------------------------------------------*
- * Save the local program name.
- *-----------------------------------------------------------------------*/
- cpicerr->program_name = (char *) malloc(strlen(program_name)+1);
- if (cpicerr->program_name != NULL) {
- strcpy(cpicerr->program_name, program_name);
- rc = 0;
- } else {
- rc = 1;
- }
- return rc;
- }
-
-
- /*****************************************************************************
- *
- * cpicerr_set_show_level
- *
- * Usage:
- * Specify the CPI-C error classification as the show level.
- * When cpicerr_handle_rc() is called, the return code will be classified.
- * If the classification is above the show level, the return code and
- * some conversation information will be shown to the user.
- *
- * A value of ALL_ERRORS can be used to force showing of all calls to
- * cpicerr_handle_rc(). This is the DEFAULT value.
- *
- * A value of NO_ERRORS can be used to indicate that cpicerr should never
- * cause an error to be shown to the user.
- *
- * Also see:
- * cpicerr_set_exit_level
- * cpicerr_set_log_level
- *****************************************************************************/
- int
- cpicerr_set_show_level(CPICERR * cpicerr,
- CPIC_RC_HANDLING show_level)
- {
- cpicerr->show_level = show_level;
- return 0;
- }
-
-
- /******************************************************************************
- *
- * cpicerr_handle_rc_extended
- *
- * Note:
- * applications should use the cpicerr_handle_rc() macro.
- *
- * Usage:
- * This function should be called to handle any unexpected CPI-C return
- * codes. The exact function of this routine depends upon the settings
- * that have been made to the CPICERR object.
- *
- * Functions include:
- * Determining the current conversation state
- * Classifying the return code (CPIC_RC_HANDLING enum)
- * Showing return code info to the user
- * Logging the return code and conversation info to disk
- * Deallocate the conversation and exit
- *
- * Also see:
- * cpicerr_set_exit_level
- * cpicerr_set_log_level
- * cpicerr_set_show_level
- *
- *****************************************************************************/
- CPIC_RC_HANDLING
- cpicerr_handle_rc_extended(CPICERR * cpicerr,
- CPIC_VERB_INDEX verb_index,
- CM_RETURN_CODE conv_rc,
- char * file_name,
- int file_line)
-
- {
- /* Displays the CPI-C return code and the verb name. */
-
- CM_RETURN_CODE cm_rc; /* Return code from CPI-C call */
- CPIC_RC_HANDLING classification; /* Returned RC classification */
- char * string; /* temp var for output strings */
- CM_CONVERSATION_STATE conversation_state; /* Current conv. state */
-
- /*-----------------------------------------------------------------------*
- * Extract the current conversation state.
- * This will not be useful if the conversation has failed or a deallocate
- * return code has been received. The conversation state is most useful
- * when a state check has occurred.
- *-----------------------------------------------------------------------*/
- #ifndef ECS_NOT_SUPPORTED
- cmecs(cpicerr->conversation_id,
- &conversation_state,
- &cm_rc);
- if (cm_rc == CM_OK) {
- cpicerr->conversation_state = conversation_state;
- }
- else {
- cpicerr->conversation_state = CMECS_NOT_SUPPORTED;
- }
- #else
- cpicerr->conversation_state = CMECS_NOT_SUPPORTED;
- #endif
-
- /*-----------------------------------------------------------------------*
- * Store the error information in the cpicerr structure
- *-----------------------------------------------------------------------*/
- cpicerr_set_rc_info(cpicerr, verb_index, conv_rc);
-
- /*-----------------------------------------------------------------------*
- * Get the classification for this return code.
- *-----------------------------------------------------------------------*/
- cpicerr_classify_rc(conv_rc, &classification);
-
-
- if (classification == ERROR_RECEIVED && cpicerr->handle_error == TRUE) {
- CPICERR_REPLY * reply;
- reply = cpicerr_create_reply(1000,1000);
- cpicerr_recv_appl_error(cpicerr, reply);
- cpicerr_show_reply(reply);
- if (classification >= cpicerr->exit_level) {
- CM_INT32 deallocate_type;
- /*
- * Exit the application, rather than returning to the caller.
- */
- deallocate_type = CM_DEALLOCATE_ABEND;
-
- cmsdt(cpicerr -> conversation_id,
- &deallocate_type,
- &cm_rc);
-
- cmdeal(cpicerr -> conversation_id,
- &cm_rc);
-
- do_exit(EXIT_FAILURE);
- }
- return classification;
- }
-
-
- /*-----------------------------------------------------------------------*
- * Show the CPI-C verb and return code.
- *-----------------------------------------------------------------------*/
- if (classification >= cpicerr->show_level) {
- cpicerr_show_rc(cpicerr);
- }
-
-
- /*-----------------------------------------------------------------------*
- * Show the classification for this return code.
- *-----------------------------------------------------------------------*/
- if (classification >= cpicerr->show_level) {
- string = cpicerr_get_message(CPIC_RC_CLASSES, classification);
- write_error(" return code class: %s\n", string);
- /*-------------------------------------------------------------------*
- * Show product specific information associated with this error.
- *-------------------------------------------------------------------*/
- cpicerr_show_product_info(cpicerr);
- }
-
-
- /*-----------------------------------------------------------------------*
- * Log this error, along with the infomation in its cpicerr.
- *-----------------------------------------------------------------------*/
- if (classification >= cpicerr->log_level) {
- cpicerr_log_cpicerr(cpicerr, file_name, file_line);
- }
-
-
- if (classification >= cpicerr->exit_level) {
- CM_INT32 deallocate_type;
- /*-------------------------------------------------------------------*
- * Exit the application, rather than returning to the caller.
- *-------------------------------------------------------------------*/
- deallocate_type = CM_DEALLOCATE_ABEND;
-
- cmsdt(cpicerr -> conversation_id,
- &deallocate_type,
- &cm_rc);
-
- cmdeal(cpicerr -> conversation_id,
- &cm_rc);
-
- do_exit(EXIT_FAILURE); /* Set a failure return code */
- }
- return classification;
- }
-
- /******************************************************************************
- *
- * cpicerr_exchange_version
- *
- * Usage:
- * Calls cpicerr_exchange_version_plus()
- *
- *****************************************************************************/
- int
- cpicerr_exchange_version(CPICERR * cpicerr,
- unsigned char * cm_conv_id,
- CM_INT32 conv_state,
- unsigned char * partner_major_version,
- unsigned char * partner_minor_version)
- {
- return cpicerr_exchange_version_plus(cpicerr,
- cm_conv_id,
- conv_state,
- partner_major_version,
- partner_minor_version,
- NULL,
- 0);
-
-
-
-
- }
-
- /******************************************************************************
- *
- * cpicerr_exchange_version_plus
- *
- * Usage:
- * Send our two version number bytes to the partner and receive our
- * partner's two version numbers. The input parameter conv_state
- * determines whether our version numbers are sent first, or whether
- * we receive the partner's numbers first.
- *
- * Also will return the remote operating system string, if sent.
- *
- *****************************************************************************/
- int
- cpicerr_exchange_version_plus(CPICERR * cpicerr,
- unsigned char * cm_conv_id,
- CM_INT32 conv_state,
- unsigned char * partner_major_version,
- unsigned char * partner_minor_version,
- unsigned char * opsys_string,
- unsigned int opsys_string_length)
- {
- CM_SEND_TYPE send_type; /* CPI-C send type */
- CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive; /* CPI-C prepare to receive */
- CM_INT32 cm_rc; /* CPI-C return code */
- CM_INT32 length; /* generic length variable */
- CM_INT32 rts_received; /* request to send received */
- CM_INT32 max_receive_len; /* Max receive length on CMRCV */
- CM_INT32 what_received; /* What received parm from CMRCV */
- CM_INT32 received_len; /* Amount of data rcvd on CMRCV */
- CM_INT32 status_received; /* Status from CMRCV */
- unsigned char buffer[EXCHANGE_BUFFER_SIZE]; /* data buffer */
-
- *partner_major_version = 0;
- *partner_minor_version = 0;
-
- prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
- cmsptr(cm_conv_id, /* Set prepare to receive type */
- &prep_to_receive,
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK) return cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
-
- send_type = CM_BUFFER_DATA;
- cmsst(cm_conv_id, /* Set send type */
- &send_type,
- &cm_rc);
- if (cm_rc != CM_OK) return cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
-
-
- switch (conv_state) {
- case CM_SEND_STATE:
- buffer[0] = CPICERR_EXCHANGE_VERSION;
- buffer[1] = cpicerr->major_version;
- buffer[2] = cpicerr->minor_version;
- length = 3;
- cmsend(cm_conv_id,
- buffer,
- &length,
- &rts_received,
- &cm_rc);
- /* The only expected return code is CM_OK */
- if (cm_rc != CM_OK)
- return cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
- /* this falls through to the receive code!!! */
- case CM_RECEIVE_STATE:
- max_receive_len = sizeof(buffer);
- cmrcv (cm_conv_id,
- buffer,
- &max_receive_len,
- &what_received,
- &received_len,
- &status_received,
- &rts_received,
- &cm_rc);
- if (cm_rc == CM_OK) {
- if (what_received != CM_NO_DATA_RECEIVED) {
- if (received_len > 2 && buffer[0]==CPICERR_EXCHANGE_VERSION) {
- *partner_major_version = buffer[1];
- *partner_minor_version = buffer[2];
- }
- if (opsys_string != NULL && opsys_string_length > 1) {
- if (received_len > 4 &&
- buffer[3]==CPICERR_EXCHANGE_OPSYS_STRING) {
- if (received_len < sizeof(buffer)) {
- buffer[received_len] = '\0';
- }
- else {
- buffer[sizeof(buffer)] = '\0';
- }
- {
- unsigned int string_length;
-
- string_length = strlen(&buffer[4]);
- convert_from_ascii(&buffer[4], string_length);
-
- memcpy(opsys_string,
- &buffer[4],
- min(string_length, opsys_string_length-1));
-
- opsys_string[min(string_length, opsys_string_length-1)]
- = '\0';
-
- }
-
- }
- else {
- opsys_string[0] = '\0';
- }
- }
- else {
- }
-
- }
- switch (status_received) {
- case CM_CONFIRM_RECEIVED:
- cmcfmd(cm_conv_id,
- &cm_rc);
- if (cm_rc != CM_OK)
- return cpicerr_handle_rc(cpicerr, MSG_CMCFMD, cm_rc);
- break;
- case CM_SEND_RECEIVED:
- /* This is good, we don't have to do anything. */
- break;
- default:
- ;
- /* should do a reply_error here */
-
- }
- } else {
- return cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
- }
- break;
- default:
- /* do a reply error here */
- return UNRECOVERABLE;
- }
-
- if ((conv_state == CM_RECEIVE_STATE) &&
- (status_received == CM_SEND_RECEIVED)) {
-
- char * local_opsys_string;
- unsigned int local_opsys_string_length;
-
- buffer[0] = CPICERR_EXCHANGE_VERSION;
- buffer[1] = cpicerr->major_version;
- buffer[2] = cpicerr->minor_version;
- local_opsys_string = OPSYS_STRING;
- local_opsys_string_length = strlen(local_opsys_string);
- if ((local_opsys_string_length + 1+ 3 +1) < sizeof(buffer)) {
- buffer[3] = CPICERR_EXCHANGE_OPSYS_STRING;
- memcpy(&buffer[4],
- local_opsys_string,
- local_opsys_string_length);
- convert_to_ascii(&buffer[4], local_opsys_string_length);
- buffer[4+local_opsys_string_length] ='\0';
- length = 4 + local_opsys_string_length + 1;
- }
- else {
-
-
- length = 3;
- }
-
- cmsend(cm_conv_id,
- buffer,
- &length,
- &rts_received,
- &cm_rc);
- /* The only expected return code is CM_OK */
-
- if (cm_rc != CM_OK)
- return cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
-
- cmptr(cm_conv_id,
- &cm_rc);
- if (cm_rc != CM_OK)
- return cpicerr_handle_rc(cpicerr, MSG_CMPTR, cm_rc);
- }
- return RC_OK;
- }
-
- /*****************************************************************************
- *
- * cpicerr_destroy()
- *
- * Destroys a CPICERR structure created with cpicerr_new().
- * All memory assocated with the input CPICERR pointer is freed.
- *
- *****************************************************************************/
- void
- cpicerr_destroy(CPICERR * cpicerr)
- {
- /*
- * Make sure we don't free() a NULL pointer!!!
- */
- if (cpicerr != NULL) {
- if (cpicerr->program_name != NULL) {
- free(cpicerr->program_name);
- }
-
- if (cpicerr->program_info != NULL) {
- free(cpicerr->program_info);
- }
-
- if (cpicerr->log_file_name != NULL) {
- free(cpicerr->log_file_name);
- }
-
- if (cpicerr->log_file_path != NULL) {
- free(cpicerr->log_file_path);
- }
-
- free(cpicerr);
- }
- return;
- }
-
-
-
- /*****************************************************************************
- *
- * cpicerr_set_rc_info
- *
- * Internal call which makes it easier to store return code information
- * in the CPICERR structure. Called from cpicerr_handle_rc().
- *
- *****************************************************************************/
- void
- cpicerr_set_rc_info(CPICERR * cpicerr,
- CPIC_VERB_INDEX verb_index,
- CM_RETURN_CODE conv_rc)
- /* Store the verb return code information into the cpicerr structure */
- {
- cpicerr->verb_index = verb_index;
- cpicerr->conv_rc = conv_rc;
- }
-
- /*****************************************************************************
- *
- * cpicerr_show_rc
- *
- * Internal call which will display information about the unexpected
- * return code encountered. Called from cpicerr_handle_rc().
- *
- *****************************************************************************/
- void
- cpicerr_show_rc(CPICERR * cpicerr)
- {
- write_error("\n Unexpected CPI-C return code encountered...\n");
-
- /*-----------------------------------------------------------------------*
- * Find the CPI-C verb's name, and show it.
- *-----------------------------------------------------------------------*/
- write_error( " CPI-C verb name: %s, %s\n",
- cpicerr_get_message(CPIC_VERBS_SHORT,
- (CM_INT32)cpicerr->verb_index),
- cpicerr_get_message(CPIC_VERBS_LONG,
- (CM_INT32)cpicerr->verb_index));
-
- /*-----------------------------------------------------------------------*
- * Find the CPI-C return code's name, and show it.
- *-----------------------------------------------------------------------*/
- write_error( " CPI-C return code: %lu, %s\n",
- cpicerr->conv_rc,
- cpicerr_get_message(CPIC_RETURN_CODES, cpicerr->conv_rc));
-
- return;
- }
-
- /*****************************************************************************
- *
- * cpicerr_log_rc
- *
- * Internal call which will log information about the unexpected
- * return code encountered. Called from cpicerr_handle_rc().
- *
- *****************************************************************************/
- void
- cpicerr_log_rc(CPICERR * cpicerr,
- FILE * log_file)
- {
- write_log(log_file, " Unexpected CPI-C return code encountered...\n");
-
- /*-----------------------------------------------------------------------*
- * Find the CPI-C verb's name, and show it.
- *-----------------------------------------------------------------------*/
- write_log(log_file,
- " CPI-C verb name: %s, %s\n",
- cpicerr_get_message(CPIC_VERBS_SHORT,
- (CM_INT32)cpicerr->verb_index),
- cpicerr_get_message(CPIC_VERBS_LONG,
- (CM_INT32)cpicerr->verb_index));
-
- /*-----------------------------------------------------------------------*
- * Find the CPI-C return code's name, and show it.
- *-----------------------------------------------------------------------*/
- write_log(log_file,
- " CPI-C return code: %lu, %s\n",
- cpicerr->conv_rc,
- cpicerr_get_message(CPIC_RETURN_CODES, cpicerr->conv_rc));
-
- return;
- }
-
-
- /*****************************************************************************
- *
- * cpicerr_classify_rc
- *
- * Internal call which takes a CPI-C return code and classifies it
- * into one of the categories that we have defined.
- * Called from cpicerr_handle_rc().
- *
- *****************************************************************************/
- void
- cpicerr_classify_rc (CM_RETURN_CODE conv_rc,
- CPIC_RC_HANDLING * classification)
- {
- switch (conv_rc) {
-
- case CM_ALLOCATE_FAILURE_NO_RETRY:
- /* configuration defect or protocol defect, local or partner */
- case CM_TP_NOT_AVAILABLE_NO_RETRY:
- /* partner program could not be sucessfully started */
- case CM_RESOURCE_FAILURE_NO_RETRY:
- /* communication failure or protocol defect, local or partner */
-
- case CM_DEALLOCATED_ABEND:
- /* unrecoverable error in the partner TP */
- case CM_DEALLOCATED_ABEND_SVC:
- /* unrecoverable error in the partner TP */
- case CM_DEALLOCATED_ABEND_TIMER:
- /* unrecoverable error in the partner TP */
-
- case CM_CONVERSATION_TYPE_MISMATCH:
- case CM_PIP_NOT_SPECIFIED_CORRECTLY:
-
- /* configuration defect or mismatch with the partner */
-
- case CM_OK:
- /* application design defect, local or partner program */
- case CM_DEALLOCATED_NORMAL:
- /* TP design defect, local or partner program */
- case CM_PARAMETER_ERROR:
- /* local program design or coding defect */
- case CM_PROGRAM_PARAMETER_CHECK:
- /* local program design or coding defect */
- case CM_PROGRAM_STATE_CHECK:
- /* local program design or coding defect */
- *classification = UNRECOVERABLE;
- break;
-
- case CM_ALLOCATE_FAILURE_RETRY:
- /* configuration defect or route temporarily down */
- case CM_TP_NOT_AVAILABLE_RETRY:
- /* congestion at the partner operating system */
- case CM_RESOURCE_FAILURE_RETRY:
- /* route temporarily down */
- *classification = RETRY_CONV;
- break;
-
- case CM_UNSUCCESSFUL:
- /* verb could not be completed now */
- *classification = RETRY_VERB;
- break;
-
- case CM_PROGRAM_ERROR_NO_TRUNC:
- case CM_SVC_ERROR_NO_TRUNC:
- /* partner failed while building a record to send */
- case CM_PROGRAM_ERROR_PURGING:
- case CM_SVC_ERROR_PURGING:
- /* partner failed while processing a received record */
- case CM_PROGRAM_ERROR_TRUNC:
- case CM_SVC_ERROR_TRUNC:
- /* partner failed after partially sending a record */
- *classification = ERROR_RECEIVED;
- break;
-
- case CM_PRODUCT_SPECIFIC_ERROR:
- /********************************/
- /* Examine each of these. */
- /* In some cases, you may want */
- /* to return CONTINUE. */
- /********************************/
- *classification = UNRECOVERABLE;
- break;
-
- case CM_SECURITY_NOT_VALID:
- *classification = SECURITY_NOT_VALID;
- break;
-
- default:
- *classification = UNRECOVERABLE;
- break;
- }
- return;
- }
-
-
-
-
- /*****************************************************************************
- *
- * cpicerr_log_cpicerr()
- *
- * Internal call which logs complete conversation and error information
- * to a log file. Called by cpicerr_handle_rc().
- *
- *****************************************************************************/
- int
- cpicerr_log_cpicerr(CPICERR * cpicerr,
- char * file_name,
- int file_line)
- {
- int rc; /* return value */
- FILE * log_file; /* log file handle */
- unsigned count; /* used to extract text strings */
- char filepath[256]; /* actual file path for logging */
- char last_char;
-
- if (cpicerr != (CPICERR *)NULL) {
-
- /*-------------------------------------------------------------------*
- * Save the time of the call to this procedure.
- *-------------------------------------------------------------------*/
- cpicerr->program_error_time = time(NULL);
-
- filepath[0] = '\0';
- if (cpicerr->log_file_path != NULL &&
- cpicerr->log_file_path[0] != '\0') {
- strcpy(filepath, cpicerr->log_file_path);
- last_char =
- cpicerr->log_file_path[strlen(cpicerr->log_file_path)-1];
- if (!(last_char == '\\' || last_char == '/')) {
- strcat(filepath, "/");
- }
- }
- if (cpicerr->log_file_name != NULL) {
- strcat(filepath, cpicerr->log_file_name);
- }
-
- if ((strlen(filepath) == 0) ||
- ((log_file = fopen(filepath, "a")) == NULL )) {
- log_file = stderr;
- }
-
- write_log(log_file,
- "------------------------------------------------------\n");
-
- if (cpicerr->program_name != NULL) {
- write_log(log_file, " CPI-C error in program: \"%s\"",
- cpicerr->program_name);
- }
-
- if (cpicerr->program_info != NULL) {
- write_log(log_file, ", %s\n", cpicerr->program_info);
- }
-
- if (cpicerr->major_version != 0 || cpicerr->minor_version != 0) {
- write_log(log_file, " Program version: %u.%u\n",
- (unsigned int)cpicerr->major_version,
- (unsigned int)cpicerr->minor_version);
- }
-
- cpicerr_log_rc(cpicerr, log_file);
-
- if (cpicerr->partner_LU_name[0] != '\0') {
- cpicerr->partner_LU_name[(int)cpicerr->partner_LU_name_length]
- = '\0';
- }
- if (cpicerr->mode_name[0] != '\0') {
- cpicerr->mode_name[(int)cpicerr->mode_name_length] = '\0';
- }
- write_log(log_file, " Partner LU name: %s\n",
- cpicerr->partner_LU_name);
- write_log(log_file, " Mode name: %s\n",
- cpicerr->mode_name);
-
- write_log(log_file, " CPI-C conversation ID: ");
-
- for (count = 0; count<sizeof(cpicerr->conversation_id); count++ ) {
- write_log(log_file, "%02X",
- (unsigned int)cpicerr->conversation_id[count]);
- }
- write_log(log_file, "\n");
-
- write_log(log_file, "CPI-C conversation state: %lu, %s\n",
- cpicerr->conversation_state,
- cpicerr_get_message(CPIC_STATES_CONV, cpicerr->conversation_state));
-
- write_log(log_file, " CPI-C conversation type: %lu, %s\n",
- cpicerr->conversation_type,
- cpicerr_get_message( CPIC_CONV_TYPES, cpicerr->conversation_type));
-
- write_log(log_file, " Conversation sync level: %lu, %s\n",
- cpicerr->sync_level,
- cpicerr_get_message( CPIC_SYNC_LEVELS, cpicerr->sync_level));
-
-
-
-
- write_log(log_file, " Program start time: %s",
- ctime(&(cpicerr->program_start_time)));
- write_log(log_file, " Program error time: %s",
- ctime(&(cpicerr->program_error_time)));
- write_log(log_file, " Called from source file: %s\n", file_name);
- write_log(log_file, " at line: %d\n", file_line);
-
- fclose(log_file);
-
- rc = 0;
- } else {
- rc = 1;
- }
-
- return rc;
- }
-
-
-
-
- CPICERR_MESSAGE cpicerr_verbs_short[] = {
- MSG_CMACCP, "CMACCP",
- MSG_CMALLC, "CMALLC",
- MSG_CMCFM, "CMCFM",
- MSG_CMCFMD, "CMCFMD",
- MSG_CMDEAL, "CMDEAL",
- MSG_CMECS, "CMECS",
- MSG_CMECT, "CMECT",
- MSG_CMEMN, "CMEMN",
- MSG_CMEPLN, "CMEPLN",
- MSG_CMESL, "CMESL",
- MSG_CMFLUS, "CMFLUS",
- MSG_CMINIT, "CMINIT",
- MSG_CMPTR, "CMPTR",
- MSG_CMRCV, "CMRCV",
- MSG_CMRTS, "CMRTS",
- MSG_CMSCT, "CMSCT",
- MSG_CMSDT, "CMSDT",
- MSG_CMSED, "CMSED",
- MSG_CMSEND, "CMSEND",
- MSG_CMSERR, "CMSERR",
- MSG_CMSF, "CMSF",
- MSG_CMSLD, "CMSLD",
- MSG_CMSMN, "CMSMN",
- MSG_CMSPLN, "CMSPLN",
- MSG_CMSPTR, "CMSPTR",
- MSG_CMSRC, "CMSRC",
- MSG_CMSRT, "CMSRT",
- MSG_CMSSL, "CMSSL",
- MSG_CMSST, "CMSST",
- MSG_CMSTPN, "CMSTPN",
- MSG_CMTRTS, "CMTRTS",
- MSG_XCSCSU, "XCSCSU",
- MSG_XCSCSP, "XCSCSP",
- MSG_XCSCST, "XCSCST",
- MSG_XCECST, "XCECST",
- MSG_XCECSU, "XCECSU",
- MSG_XCMSSI, "XCMSSI",
- MSG_XCMESI, "XCMESI",
- MSG_XCMDSI, "XCMDSI",
- MAX_MESSAGE, "ERROR "
- };
-
- CPICERR_MESSAGE cpicerr_verbs_long[] = {
- MSG_CMACCP, "Accept_Conversation",
- MSG_CMALLC, "Allocate",
- MSG_CMCFM, "Confirm",
- MSG_CMCFMD, "Confirmed",
- MSG_CMDEAL, "Deallocate",
- MSG_CMECS, "Extract_Conversation_State",
- MSG_CMECT, "Extract_Conversation_Type",
- MSG_CMEMN, "Extract_Mode_Name",
- MSG_CMEPLN, "Extract_Partner_LU_Name",
- MSG_CMESL, "Extract_Sync_Level",
- MSG_CMFLUS, "Flush",
- MSG_CMINIT, "Initialize_Conversation",
- MSG_CMPTR, "Prepare_To_Receive",
- MSG_CMRCV, "Receive",
- MSG_CMRTS, "Request_To_Send",
- MSG_CMSCT, "Set_Conversation_Type",
- MSG_CMSDT, "Set_Deallocate_Type",
- MSG_CMSED, "Set_Error_Direction",
- MSG_CMSEND, "Send_Data",
- MSG_CMSERR, "Send_Error",
- MSG_CMSF, "Set_Fill",
- MSG_CMSLD, "Set_Log_Data",
- MSG_CMSMN, "Set_Mode_Name",
- MSG_CMSPLN, "Set_Partner_LU_Name",
- MSG_CMSPTR, "Set_Prepare_To_Receive_Type",
- MSG_CMSRC, "Set_Return_Control",
- MSG_CMSRT, "Set_Receive_Type",
- MSG_CMSSL, "Set_Sync_Level",
- MSG_CMSST, "Set_Send_Type",
- MSG_CMSTPN, "Set_TP_Name",
- MSG_CMTRTS, "Test_Request_To_Send_Received",
- MSG_XCSCSU, "Set Conversation Security Userid",
- MSG_XCSCSP, "Set Conversation Security Password",
- MSG_XCSCST, "Set Conversation Security Type",
- MSG_XCECST, "Extract_Conversation_Security_Type",
- MSG_XCECSU, "Extract_Conversation_Security_Userid",
- MSG_XCMSSI, "Set_CPIC_Side_Information",
- MSG_XCMESI, "Extract_CPIC_Side_Information",
- MSG_XCMDSI, "Delete_CPIC_Side_Information",
- MAX_MESSAGE, "Invalid verb name"
- };
-
- CPICERR_MESSAGE cpicerr_return_codes[] = {
- CM_OK, "CM_OK",
- CM_ALLOCATE_FAILURE_NO_RETRY, "CM_ALLOCATE_FAILURE_NO_RETRY",
- CM_ALLOCATE_FAILURE_RETRY, "CM_ALLOCATE_FAILURE_RETRY",
- CM_CONVERSATION_TYPE_MISMATCH, "CM_CONVERSATION_TYPE_MISMATCH",
- CM_PIP_NOT_SPECIFIED_CORRECTLY, "CM_PIP_NOT_SPECIFIED_CORRECTLY",
- CM_SECURITY_NOT_VALID, "CM_SECURITY_NOT_VALID",
- CM_TP_NOT_AVAILABLE_NO_RETRY, "CM_TP_NOT_AVAILABLE_NO_RETRY",
- CM_TP_NOT_AVAILABLE_RETRY, "CM_TP_NOT_AVAILABLE_RETRY",
- CM_DEALLOCATED_ABEND, "CM_DEALLOCATED_ABEND",
- CM_DEALLOCATED_NORMAL, "CM_DEALLOCATED_NORMAL",
- CM_PARAMETER_ERROR, "CM_PARAMETER_ERROR",
- CM_PRODUCT_SPECIFIC_ERROR, "CM_PRODUCT_SPECIFIC_ERROR",
- CM_PROGRAM_ERROR_NO_TRUNC, "CM_PROGRAM_ERROR_NO_TRUNC",
- CM_PROGRAM_ERROR_PURGING, "CM_PROGRAM_ERROR_PURGING",
- CM_PROGRAM_ERROR_TRUNC, "CM_PROGRAM_ERROR_TRUNC",
- CM_PROGRAM_PARAMETER_CHECK, "CM_PROGRAM_PARAMETER_CHECK",
- CM_PROGRAM_STATE_CHECK, "CM_PROGRAM_STATE_CHECK",
- CM_RESOURCE_FAILURE_NO_RETRY, "CM_RESOURCE_FAILURE_NO_RETRY",
- CM_RESOURCE_FAILURE_RETRY, "CM_RESOURCE_FAILURE_RETRY",
- CM_UNSUCCESSFUL, "CM_UNSUCCESSFUL",
- CM_DEALLOCATED_ABEND_SVC, "CM_DEALLOCATED_ABEND_SVC",
- CM_DEALLOCATED_ABEND_TIMER, "CM_DEALLOCATED_ABEND_TIMER",
- CM_SVC_ERROR_NO_TRUNC, "CM_SVC_ERROR_NO_TRUNC",
- CM_SVC_ERROR_PURGING, "CM_SVC_ERROR_PURGING",
- CM_SVC_ERROR_TRUNC, "CM_SVC_ERROR_TRUNC",
- MAX_MESSAGE, "Invalid Return Code Value"
- };
-
- CPICERR_MESSAGE cpicerr_rc_classes[] = {
- BACKOUT_RECEIVED, "BACKOUT_RECEIVED",
- CONTINUE, "CONTINUE",
- ERROR_RECEIVED, "ERROR_RECEIVED",
- SECURITY_NOT_VALID, "SECURITY_NOT_VALID",
- RETRY_CONV, "RETRY_CONVERSATION",
- RETRY_CONV_BO, "RETRY_CONVERSATION_BACKOUT",
- RETRY_VERB, "RETRY_LAST_VERB",
- UNRECOVERABLE, "UNRECOVERABLE",
- UNRECOVERABLE_BO, "UNRECOVERABLE_BACKOUT",
- MAX_MESSAGE, "Invalid Return Code Class"
- };
-
- CPICERR_MESSAGE cpicerr_states_conv[] = {
- CM_INITIALIZE_STATE, "Initialize state",
- CM_SEND_STATE, "Send state",
- CM_RECEIVE_STATE, "Receive state",
- CM_SEND_PENDING_STATE, "Send pending state",
- CM_CONFIRM_STATE, "Confirm state",
- CM_CONFIRM_SEND_STATE, "Confirm send state",
- CM_CONFIRM_DEALLOCATE_STATE, "Confirm deallocate state",
- CMECS_NOT_SUPPORTED, "CMECS not supported",
- MAX_MESSAGE, "Invalid Conversation State value"
- };
-
- CPICERR_MESSAGE cpicerr_sync_levels[] = {
- CM_NONE, "None",
- CM_CONFIRM, "Confirm",
- MAX_MESSAGE, "Invalid Sync Level value"
- };
-
- CPICERR_MESSAGE cpicerr_conv_types[] = {
- CM_BASIC_CONVERSATION , "Basic",
- CM_MAPPED_CONVERSATION, "Mapped",
- MAX_MESSAGE, "Invalid conversation type value"
- };
-
- CPICERR_MESSAGE_LIST message_list[] = {
- CPIC_SYNC_LEVELS, cpicerr_sync_levels,
- CPIC_CONV_TYPES, cpicerr_conv_types,
- CPIC_STATES_CONV, cpicerr_states_conv,
- CPIC_RC_CLASSES, cpicerr_rc_classes,
- CPIC_RETURN_CODES, cpicerr_return_codes,
- CPIC_VERBS_SHORT, cpicerr_verbs_short,
- CPIC_VERBS_LONG, cpicerr_verbs_long,
- MAX_MESSAGE, NULL
- };
-
- /*****************************************************************************
- *
- * cpicerr_get_message()
- *
- * Loop through the message arrays looking for the message type and
- * message index. Return a pointer to the appropriate string.
- *
- * This procedure will never return NULL, thus is safe to use in
- * printf() type calls.
- *
- *****************************************************************************/
- char *
- cpicerr_get_message(CPICERR_MESSAGE_TYPE message_type, CM_INT32 index)
- {
- unsigned int count; /* counter through the array */
-
- CPICERR_MESSAGE * messages;
-
- for (count = 0; message_list[count].type < MAX_MESSAGE ; count++ ) {
- if (message_list[count].type == message_type) break;
- }
-
- if ( (messages = message_list[count].list) == NULL ) {
- return "Message list not found.";
- }
-
- for (count = 0; messages[count].index < MAX_MESSAGE; count++) {
- if (messages[count].index == index) break;
- }
- return messages[count].message;
- }
-
-
-
- /*****************************************************************************
- *
- * cpicerr_show_product_info
- *
- *****************************************************************************/
- void
- cpicerr_show_product_info(CPICERR * cpicerr)
- {
- if (cpicerr->conv_rc == CM_ALLOCATE_FAILURE_NO_RETRY ||
- cpicerr->conv_rc == CM_ALLOCATE_FAILURE_RETRY ) {
- #if defined(GET_OS2_SENSE_DATA)
- #if defined(FAPI)
- if (get_machine_mode()) {
- #endif
- write_error(
- "\n Retrying Allocate to extract OS/2 sense data:\n");
- cpicerr_os2_appc_allocate(cpicerr);
- #if defined(FAPI)
- }
- #endif
- #endif
-
- }
- }
-
- #ifdef GET_OS2_SENSE_DATA
-
- cpicerr_os2_appc_allocate(CPICERR * cpicerr)
- /*
- * This procedure retries the allocate that failed in CPI-C. We are not
- * retrying the allocate to establish the connection, but to get more
- * error information about why the first allocate failed.
- *
- * The OS/2 APPC api is used to extract the sense data, which provides
- * a more specify reason for an allocation failure.
- */
- {
- TP_STARTED tp_started; /* Declare a verb control block */
- TP_STARTED *ptr_tp_started = (TP_STARTED *)&tp_started;
- int length; /* length of lu_alias */
- char plu_alias[8+1];
- char fqplu_name[17+1];
-
- ALLOCATE allocate; /* Declare a verb control block */
- ALLOCATE *ptr_allocate = (ALLOCATE *)&allocate;
-
- TP_ENDED tp_ended; /* Declare a verb control block */
- TP_ENDED *ptr_tp_ended = (TP_ENDED *)&tp_ended;
-
-
- CLEAR_VCB(tp_started); /* Zero the verb control block */
- tp_started.opcode = AP_TP_STARTED; /* APPC verb - TP_STARTED */
-
- memset( tp_started.lu_alias, (int)'\0', sizeof(tp_started.lu_alias));
-
- BLANK_STRING(tp_started.tp_name); /* Set 64-byte string to blanks */
- ascii_to_ebcdic_field(tp_started.tp_name,
- sizeof(tp_started.tp_name));
-
- APPC ((ULONG) (TP_STARTED far *)ptr_tp_started); /* Issue the verb */
-
- if (tp_started.primary_rc == AP_OK) {
- CLEAR_VCB(allocate); /* Zero the vcb */
- allocate.opcode = AP_B_ALLOCATE; /* Verb - ALLOCATE */
- allocate.opext = AP_MAPPED; /* Basic Conversation type */
-
- /* Set the TP_ID */
- memcpy (allocate.tp_id, tp_started.tp_id, sizeof(allocate.tp_id));
- allocate.sync_level = AP_CONFIRM; /* Sync level-confirm */
- allocate.rtn_ctl = AP_WHEN_SESSION_FREE;/* avoid deadlock */
- allocate.security = AP_NONE; /* Set security type */
-
- if (!parse_destination(cpicerr->partner_LU_name,
- plu_alias,
- fqplu_name)) {
- if ((length = strlen(plu_alias)) != 0) {
- BLANK_STRING(allocate.plu_alias);
- memcpy ( allocate.plu_alias,
- plu_alias,
- min(length, sizeof(allocate.plu_alias)));
- /* Set PLU_ALIAS */
- } else {
- memset (allocate.plu_alias,(int)'\0',sizeof(allocate.plu_alias));
- BLANK_STRING(allocate.fqplu_name); /* Set FQ PLU NAME */
- memcpy ( allocate.fqplu_name,
- fqplu_name,
- min(strlen(fqplu_name), sizeof(allocate.fqplu_name)));
- TOUPPER_STRING(allocate.fqplu_name, 17);
- ascii_to_ebcdic_field(allocate.fqplu_name,
- sizeof(allocate.fqplu_name));
- }
-
-
- } else {
- BLANK_STRING(allocate.plu_alias);
- memcpy ( allocate.plu_alias,
- "UNKNOWN",
- 7);
- }
-
-
- BLANK_STRING(allocate.tp_name); /* Set 64-byte string to blanks */
- ascii_to_ebcdic_field(allocate.tp_name,
- sizeof(allocate.tp_name));
-
- BLANK_STRING(allocate.mode_name); /* Set 8-byte string to blanks */
- memcpy ( allocate.mode_name,
- cpicerr->mode_name,
- min(strlen(cpicerr->mode_name),
- sizeof(allocate.mode_name)));
- TOUPPER_STRING(allocate.mode_name, 8);
- ascii_to_ebcdic_field(allocate.mode_name,
- sizeof(allocate.mode_name));
-
- APPC((ULONG) (ALLOCATE far *) ptr_allocate); /* Issue the verb */
-
- if (allocate.primary_rc != AP_OK) {
- write_error(
- "\t OS/2 Sense Data: %08lX\n", SWAP4(allocate.sense_data));
-
- }
-
- } else { /* Save the returned tp_id */
- return (tp_started.primary_rc);
- }
- CLEAR_VCB(tp_ended); /* Zero the verb control block */
- tp_ended.opcode = AP_TP_ENDED; /* Set the verb opcode */
- /* Set the tp_id */
- memcpy (tp_ended.tp_id, tp_started.tp_id, sizeof(tp_ended.tp_id));
- tp_ended.type = AP_SOFT; /* type: AP_HARD or AP_SOFT */
-
- APPC((ULONG) (TP_ENDED far *) ptr_tp_ended); /* Issue the verb. */
- }
-
-
-
- int
- parse_destination(char * in_string,
- char * plu_alias,
- char * fqplu_name)
- /*
- * This procedure is used by cpicerr_os2_appc_allocate verb
- */
- {
- if (strchr(in_string, '.') != NULL) {
- if (in_string[0] == '.') {
- in_string++;
- }
- strcpy(fqplu_name, in_string);
- plu_alias[0] = '\0';
- } else {
- strcpy(plu_alias, in_string);
- fqplu_name[0] = '\0';
- }
- return 0;
-
- }
-
- #endif
-