Código

//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//   Program : MSG_EXIT.C, Message Exit.
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Setup :
//
//        Place MY_DLL.DLL in e:\mq\exits\ and configure channel
//        to use MSGEXIT('MY_DLL(My_Exit)')
//
//        On MQ 5.3 GUI, you have to code "MY_DLL(My_Exit)" in the channel
//        "Rutinas de Salida" tab, campo "Nombre Rutina Salida Mensaje".
//
//      Send Channel .-
//
//        The name of the DLL must have been coded in DEFINE CHANNEL,
//        keyword MSGEXIT, with parameter My_Exit.
//
//        Example :
//              DEFINE CHANNEL ... +
//                      CHLTYPE(SDR) +
//                      MSGEXIT('MY_DLL(My_Exit)') +
//
//      Receive channel .-
//
//        The name of the DLL must have been coded in DEFINE CHANNEL,
//        keyword MSGEXIT, with parameter My_Exit.
//        Example :
//              DEFINE CHANNEL ... +
//                      CHLTYPE(RCVR) +
//                      MSGEXIT('MY_DLL(My_Exit)') +
//
//   Input :
//
//        Message channel exit gets control from MQ Agent.
//        Parameters :
//             MQCXP - channel exit parameter structure.
//             MQCD  - channel data structure.
//             MQXQH - transmission queue header structure.
//                  Contains MQMD, message descriptor.
//
//        Exits are passed an agent buffer with contents depending upon
//        type of exit. For Message Exit, the transmission queue header MQXQH
//        and the application message text are retrieved from the queue.
//
//   Output :
//
//        MQCXP.ExitResponse and MQCXP.Feedback, in MQCXP structure.
//        If a channel exit sets the "ExitResponse" field to MQCXX_SUPPRESS_FUNCTION,
//        the "Feedback" field specifies the code that identifies why the
//        message was put on the dead-letter queue.
//
//       "e:\mq\exits\MSG_EXIT.TRC" file is generated if DO_DEBUG is defined not-null.
//       2004 : write "c:\temp\MSG_EXIT.TRC", as maybe disc "E" does not exist.
//
//   How to modify the message :
//
//        a) inplace : modify the message and "DataLength".
//
//        b) into ExitBuffer : ExitResponse2 := MQXR2_USE_EXIT_BUFFER ;
//             1) modify message into ExitBuffer, then
//             2) set ExitResponse2 := MQXR2_USE_EXIT_BUFFER ;
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//   Logic :
//
//        Display parameters ;
//
//        Send Exit :
//
//             Dump_Msg ;
//             Modify message ;
//             Dump_Msg ;
//
//        Receive Exit :
//
//             Dump_Msg ;
//
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//   How to compile it :
//
// CL -I"e:\MQ\tools\c\include" MSG_EXIT.C
//      -o MY_DLL.dll -LD
//      -DEFAULTLIB e:\MQ\tools\lib\mqm.lib e:\MQ\tools\lib\mqmvx.lib msg_exi.def
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//   Some documentation extracts :
//
// MQ Series Distributed Queuing Guide, SC33-1139-06.
//
//  Page 274 :
//      All exits are called with :
//              a channel exit parameter structure (MQCXP)
//              a channel definition structure (MQCD)
//              a prepared data buffer
//              a data length parameter
//              a buffer length parameter.
//      The buffer length must not be exceeded.
//
//  Page 293 :
//      The data structures are :
//              MQCD - channel data structure, page 312.
//              MQCXP - channel exit parameter structure, page 329.
//
// ----------------------------------------------------------------------------
//
// MQ Series Command Reference, SC33-1369-05.
//  Page 69 :
//      MSGEXIT(string) ... on OS/2 is of the form :
//              dllname(funcionname)
//
// ----------------------------------------------------------------------------
//
// MQ Series Application Programming Reference, S33-1673-01.
//
//   Applications that put messages should normally specify MQENC_NATIVE.
//   Applications that retrieve messages should compare this field against
//       the value MQENC_NATIVE; if the values differ, the application
//       may need to convert numeric data in the message.
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//      Releases :
//              1.01,   29-Jun-04 : First release, BBVA.
//              1.02,   30-Jun-04 : Modify message inplace.
//   FIX02      1.03,   15-Oct-04 : verify "AA0" in "Cabecera General".
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//

#define   DO_DEBUG  1                   // debug : 0 = dont write trace, other = do.

#if  DO_DEBUG > 0

// Some external libraries :
#include             // required for FILE.
#include              // required for TIME and CTIME.

#endif                        // debug : dont include the libraries needed to trace into a file.

#include 
#include 

// in T30, C headers are located at "E:\MQ\Tools\c\include" ...

#include "cmqc.h"                       // For MQI datatypes. And MQXQH !
#include "cmqxc.h"                      // For MQI exit-related definitions.

#if  DO_DEBUG > 0

void Traza ( FILE * traceArchivo, char * Texto ) ;
void DumpMsg ( MQBYTE * pDato, int Max_Lng, FILE * Ostr ) ;

#define mTraza(MyArg1,MyArg2) \
     Traza ( MyArg1, MyArg2 )
#else
#define mTraza(MyArg1,MyArg2)
#endif                        // debug : dont define the vars needed to trace into a file.

 /********************************************************************/
 /* Insert the function prototypes for the functions produced by     */
 /* the data conversion utility program.                             */
 /********************************************************************/

 void MQStart ( ) { ; } ;

 void MQENTRY My_Exit (
   PMQVOID   mqcxpptr,       /* Channel exit parameter block  MQCXP in/out */
   PMQVOID   mqcdptr,        /* Channel definition             MQCD in/out */
   PMQLONG   inmsglngptr,    /* Length of data                      in/out */
   PMQLONG   inbuflngptr,    /* Length of agent buffer                  in */
   PMQVOID   inbufptr,       /* Agent buffer             MQXQH+data in/out */
   PMQLONG   outmsglngptr,   /* Length of exit buffer               in/out */
   PMQPTR    outbufptr )     /* Address of exit buffer              in/out */
 {

PMQCXP    pMQCXPptr ;         // channel exit parameter block pointer.
PMQCD     pMQCDptr ;          // channel definition structure pointer.
PMQXQH    pMQXQHptr ;         // transmission queue header pointer.
PMQBYTE   pMsgData ;          // message data pointer.
MQLONG    MsgDataLength ;     // message data length.
PMQBYTE   pMsgDataEnd ;       // message data end pointer.
PMQBYTE   pMsgDataTmp ;       // message data temporal pointer.
MQLONG    LngDataTmp ;        // message data intermediate length.

// MQCXP :
MQLONG    MyMQCXP_StrucVersion = 0 ;
MQLONG    MyMQCXP_ExitId = 0 ;
MQLONG    MyMQCXP_ExitReason = 0 ;

// MQCD :
MQCHAR    MyMQCD_ChannelName [ 20 ] = "\0" ; // Channel definition name.
MQLONG    MyMQCD_StrucVersion = 0;           // Structure version number.
MQLONG    MyMQCD_ChannelType = 0 ;           // Channel type.

// MQXQH :
MQLONG    MyMQXQH_Version = 0 ;              // Structure version number.
MQCHAR48  MyMQXQH_RemoteQName = "\0" ;       // Name of destination queue.
MQCHAR48  MyMQXQH_RemoteQMgrName = "\0" ;    // Name of destination queue manager.
MQCHAR8   MyMQMD_Format = "\0" ;             // Message format (MQFMT_NONE, MQFMT_STRING).
MQBYTE24  MyMQMD_MsgId = "\0" ;              // Message Identifier.
MQBYTE24  MyMQMD_CorrelId = "\0" ;           // Correlation Identifier.
MQLONG    MyMQMD_Report = 0 ;                // Report options.
MQLONG    MyMQMD_Encoding = 0 ;              // Numbers encoding .
MQLONG    MyMQMD_CodedCharSetId = 0 ;        // Coded character set identifier.
#define   CCSID_MVS500   500                 // MVS Coded Character Set Id.
#define   CCSID_850      850                 // ASCII 850 Coded Character Set Id.
#define   CCSID_819      819                 // ASCII 819 Coded Character Set Id.
MQLONG    MyMQMD_MsgType = 0 ;               // Mesage type (Datagram, Request, Reply, Report).
MQLONG    MyMQMD_Feedback = 0 ;              // Feedback or reason code (MQMT_REPORT MsgType only).
MQCHAR48  MyMQMD_ReplyToQ = "\0" ;           // "Reply To" Queue.
MQCHAR48  MyMQMD_ReplyToQMgr = "\0" ;        // "Reply To" Queue Manager.
MQCHAR12  MyMQMD_UserIdentifier ;            // User identifier in MQMD.

// Return codes from MVQTRXIT :
// MQMT_APPL_FIRST is 65535 ...
#define   MyRC_1    65540     // MQCXP Struc Version < 2.
#define   MyRC_2    65541     // MQCD Struc Version < 3.
#define   MyRC_3    65542     // Not a Channel exit.
#define   MyRC_4    65543     // Unknown Channel type (not SND, RCV, REQ, or SRV).

#if  DO_DEBUG > 0

// Some aux vars :
char    * Filename_Trace     = "c:\\TEMP\\MSG_EXIT.TRC" ;  // event trace file name.
FILE    * Trace_log_stream ;                     // stream to write a log.
char    * Separador          = "=================================" ;
char    * MyVersion          = "MY_DLL.DLL trace, version 1.03 a, 15-Oct-04. PTFnone." ;

char      MiDbg_Buffer [ 256 ] = "\0" ;      // string concatenation buffer.
int       cnt = 0 ;                          // sprintf return value.

struct timeb t;

#endif                        // debug : dont define the vars needed to trace into a file.

int       mirc = 0 ;                         // my functions return code.
int       i ;

PMQBYTE   pMsgDataSource ;         // to Modify the message ...
PMQBYTE   pMsgDataDestination ;

int       iMsgNuestro ;       // el mensaje es nuestro ? ("AA0" in Codigo Formato Cabecera ?)
// char      MiHeader_Format_Code [ 4 ] = "\0" ;      // string concatenation buffer.

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++main++++++++++

     pMQCXPptr = (MQCXP *) mqcxpptr ;   // set MQCXP pointer.

#if  DO_DEBUG > 0

     Trace_log_stream = fopen ( Filename_Trace, "a" ) ;     // open to APPEND !

     mTraza ( Trace_log_stream, MyVersion ) ;

     ftime ( & t ) ;

     cnt = sprintf ( MiDbg_Buffer, "Time : (%ld.%d)", t.time, t.millitm ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

#endif                        // debug : dont open the file needed to trace into a file.

#if  DO_DEBUG > 0

     cnt = sprintf ( MiDbg_Buffer, "Param : MQCXP ptr           (%li).", mqcxpptr ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "Param : MQCD ptr            (%li).", mqcdptr ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "Param : Data Lng ptr        (%li).", inmsglngptr ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "Param : Agent Buf Lng ptr   (%li).", inbuflngptr ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "Param : Agent Buf ptr       (%li).", inbufptr ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "Param : Exit Buf Lng ptr    (%li).", outmsglngptr ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "Param : Exit Buf ptr        (%li).", outbufptr ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

#endif                        // debug : dont write input parameters.

// Set pointers from calling parameters, and do type cast :

     pMQCXPptr = (MQCXP *) mqcxpptr ;   // set MQCXP pointer.
     pMQCDptr  = (MQCD *) mqcdptr ;     // set MQCD pointer.
     pMQXQHptr = (MQXQH *) inbufptr ;   // set MQXQH pointer.

     pMsgData = ((MQBYTE *)inbufptr) + sizeof(MQXQH) ;
     MsgDataLength = (*inmsglngptr) - sizeof(MQXQH) ;
     pMsgDataEnd = pMsgData + MsgDataLength ;

#if  DO_DEBUG > 0

     cnt = sprintf ( MiDbg_Buffer, "MQCXPptr is        (%li), size is (%li).", pMQCXPptr, sizeof(MQCXP) ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "MQCDptr is       (%li), size is (%li).", pMQCDptr, sizeof(MQCD) ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "MQXQHptr is      (%li), size is (%li).", pMQXQHptr, sizeof(MQXQH) ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "MsgDataptr is    (%li).", pMsgData ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "DataLng is           (%i).", MsgDataLength ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
     cnt = sprintf ( MiDbg_Buffer, "MsgDataEndptr is (%li).", pMsgDataEnd ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

#endif                        // debug : dont write deduced parameters.

// Get some MQCXP values :

     if ( pMQCXPptr == 0 ) {
          mTraza ( Trace_log_stream, "Error : null MQCXP pointer." ) ;
          goto My_Common_End ;
     } ;
     MyMQCXP_StrucVersion = pMQCXPptr -> Version ;
     MyMQCXP_ExitId       = pMQCXPptr -> ExitId ;
     MyMQCXP_ExitReason   = pMQCXPptr -> ExitReason ;

// Get some MQCD values :

     if ( pMQCDptr == 0 ) {
          mTraza ( Trace_log_stream, "Error : null MQCD pointer." ) ;
          goto My_Common_End ;
     } ;
     strncpy ( MyMQCD_ChannelName, pMQCDptr -> ChannelName, sizeof(pMQCDptr -> ChannelName) ) ;
     MyMQCD_StrucVersion = pMQCDptr -> Version ;
     MyMQCD_ChannelType  = pMQCDptr -> ChannelType ;

#if  DO_DEBUG > 0
     cnt = sprintf ( MiDbg_Buffer, "Channel Name = (%.20s).", MyMQCD_ChannelName ) ;
     mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

#endif                        // debug : dont trace.

// Get some MQXQH values :

     if ( pMQXQHptr != 0 ) {
          mTraza ( Trace_log_stream, "Part get MQMD data." ) ;

          MyMQXQH_Version = pMQXQHptr -> Version ;
          strncpy ( MyMQXQH_RemoteQName, pMQXQHptr -> RemoteQName, sizeof(pMQXQHptr -> RemoteQName) ) ;
          strncpy ( MyMQXQH_RemoteQMgrName, pMQXQHptr -> RemoteQMgrName, sizeof(pMQXQHptr -> RemoteQMgrName) ) ;
          strncpy ( MyMQMD_Format, pMQXQHptr -> MsgDesc.Format, sizeof(pMQXQHptr -> MsgDesc.Format) ) ;

          strncpy ( MyMQMD_MsgId, pMQXQHptr -> MsgDesc.MsgId, sizeof(pMQXQHptr -> MsgDesc.MsgId) ) ;
          strncpy ( MyMQMD_CorrelId, pMQXQHptr -> MsgDesc.CorrelId, sizeof(pMQXQHptr -> MsgDesc.CorrelId) ) ;

          MyMQMD_Report = pMQXQHptr -> MsgDesc.Report ;
          MyMQMD_Encoding = pMQXQHptr -> MsgDesc.Encoding ;
          MyMQMD_CodedCharSetId = pMQXQHptr -> MsgDesc.CodedCharSetId ;
          MyMQMD_MsgType = pMQXQHptr -> MsgDesc.MsgType ;
          MyMQMD_Feedback = pMQXQHptr -> MsgDesc.Feedback ;

          strncpy ( MyMQMD_ReplyToQ,
                    pMQXQHptr -> MsgDesc.ReplyToQ,
                    sizeof(pMQXQHptr -> MsgDesc.ReplyToQ) ) ;
          strncpy ( MyMQMD_ReplyToQMgr,
                    pMQXQHptr -> MsgDesc.ReplyToQMgr,
                    sizeof(pMQXQHptr -> MsgDesc.ReplyToQMgr) ) ;
          strncpy ( MyMQMD_UserIdentifier,
                    pMQXQHptr -> MsgDesc.UserIdentifier,
                    sizeof(pMQXQHptr -> MsgDesc.UserIdentifier) ) ;

#if  DO_DEBUG > 0
          cnt = sprintf ( MiDbg_Buffer, "Destination Q     = (%.48s).", MyMQXQH_RemoteQName ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "Destination Q Mgr = (%.48s).", MyMQXQH_RemoteQMgrName ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "Reply To Q = (%.48s).", MyMQMD_ReplyToQ ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "Reply To Q Mgr = (%.48s).", MyMQMD_ReplyToQMgr ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "User Identifier = (%.12s).", MyMQMD_UserIdentifier ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "MQXQH Format (%.8s).", MyMQMD_Format ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "MQXQH MsgId (%.24s).", MyMQMD_MsgId ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "MQXQH CorrelId (%.24s).", MyMQMD_CorrelId ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "MQXQH Report (%x).", MyMQMD_Report ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          if ( MyMQMD_Report & MQRO_PASS_MSG_ID ) {
               mTraza ( Trace_log_stream, "   PASS MSG ID." ) ;
          } else {
               mTraza ( Trace_log_stream, "   NEW MSG ID." ) ;
          } ;

          if ( MyMQMD_Report & MQRO_PASS_CORREL_ID ) {
               mTraza ( Trace_log_stream, "   PASS CORREL ID." ) ;
          } else {
               mTraza ( Trace_log_stream, "   COPY MSG ID TO CORREL ID." ) ;
          } ;

          if ( MyMQMD_Report & MQRO_COA ) {
               mTraza ( Trace_log_stream, "   COA requested." ) ;
          } else {
               mTraza ( Trace_log_stream, "   COA not requested." ) ;
          } ;

          if ( MyMQMD_Report & MQRO_COD ) {
               mTraza ( Trace_log_stream, "   COD requested." ) ;
          } else {
               mTraza ( Trace_log_stream, "   COD not requested." ) ;
          } ;

          if ( MyMQMD_Report & MQRO_EXCEPTION ) {
               mTraza ( Trace_log_stream, "   EXCEPTION requested." ) ;
          } else {
               mTraza ( Trace_log_stream, "   EXCEPTION not requested." ) ;
          } ;

          if ( MyMQMD_Report & MQRO_EXPIRATION ) {
               mTraza ( Trace_log_stream, "   EXPIRATION requested." ) ;
          } else {
               mTraza ( Trace_log_stream, "   EXPIRATION not requested." ) ;
          } ;

          cnt = sprintf ( MiDbg_Buffer, "MQXQH Encoding (%i).", MyMQMD_Encoding ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          if ( ( MyMQMD_Encoding & MQENC_INTEGER_MASK ) == MQENC_INTEGER_REVERSED ) {
               mTraza ( Trace_log_stream, "   Numbers encoding = Intel (reversed)." ) ;
          } else {
               if ( ( MyMQMD_Encoding & MQENC_INTEGER_MASK ) == MQENC_INTEGER_NORMAL ) {
                    mTraza ( Trace_log_stream, "   Numbers encoding = Host-AIX (normal)." ) ;
               } else {
                    mTraza ( Trace_log_stream, "   Numbers encoding = Unknown." ) ;
               } ;
          } ;

          cnt = sprintf ( MiDbg_Buffer, "MQXQH CCSID (%i).", MyMQMD_CodedCharSetId ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          cnt = sprintf ( MiDbg_Buffer, "MQXQH Msg Type (%i).", MyMQMD_MsgType ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          if ( MyMQMD_MsgType == MQMT_DATAGRAM ) {
               mTraza ( Trace_log_stream, "   Msg Type = Datagram." ) ;
          } else {
               if ( MyMQMD_MsgType == MQMT_REQUEST ) {
                    mTraza ( Trace_log_stream, "   Msg Type = Request." ) ;
               } else {
                    if ( MyMQMD_MsgType == MQMT_REPLY ) {
                         mTraza ( Trace_log_stream, "   Msg Type = Reply." ) ;
                    } else {
                         if ( MyMQMD_MsgType == MQMT_REPORT ) {
                              mTraza ( Trace_log_stream, "   Msg Type = Report." ) ;
                         } else {
                              mTraza ( Trace_log_stream, "   Msg Type = Unknown." ) ;
                         } ;
                    } ;
               } ;
          } ;

          cnt = sprintf ( MiDbg_Buffer, "MQXQH Feedback (%i).", MyMQMD_Feedback ) ;
          mTraza ( Trace_log_stream, MiDbg_Buffer ) ;

          if ( MyMQMD_Feedback == MQFB_NONE ) {
               mTraza ( Trace_log_stream, "   Feedback = None." ) ;
          } else {
               if ( MyMQMD_Feedback == MQFB_COA ) {
                    mTraza ( Trace_log_stream, "   Feedback = COA." ) ;
               } else {
                    if ( MyMQMD_Feedback == MQFB_COD ) {
                         mTraza ( Trace_log_stream, "   Feedback = COD." ) ;
                    } else {
                         mTraza ( Trace_log_stream, "   Feedback = Other. MQFB_APPL_FIRST = 65536." ) ;
                    } ;
               } ;
          } ;
#endif                        // debug : dont trace.

     } ;

// Verify some values :

     mTraza ( Trace_log_stream, "Part Verify Versions." ) ;

     if ( MyMQCXP_StrucVersion < MQCXP_VERSION_2 ) {
          pMQCXPptr -> ExitResponse = MQXCC_SUPPRESS_FUNCTION ;    // indicate ERROR end.
          pMQCXPptr -> Feedback = MyRC_1 ;                         // indicate some detail.
          mTraza ( Trace_log_stream, "Error : MQCXP version." ) ;
          goto My_Common_End ;
     } ; /* endif */

     if ( MyMQCD_StrucVersion < MQCD_VERSION_3 ) {
          pMQCXPptr -> ExitResponse = MQXCC_SUPPRESS_FUNCTION ;    // indicate ERROR end.
          pMQCXPptr -> Feedback = MyRC_2 ;                         // indicate some detail.
          mTraza ( Trace_log_stream, "Error : MQCD version." ) ;
          goto My_Common_End ;
     } ; /* endif */

     if ( MyMQCXP_ExitId != MQXT_CHANNEL_MSG_EXIT ) {
          pMQCXPptr -> ExitResponse = MQXCC_SUPPRESS_FUNCTION ;    // indicate ERROR end.
          pMQCXPptr -> Feedback = MyRC_3 ;                         // indicate some detail.
          mTraza ( Trace_log_stream, "Error : not a channel msg exit." ) ;
          goto My_Common_End ;
     } ; /* endif */

     if ( MyMQCXP_ExitReason == MQXR_INIT ) {
          mTraza ( Trace_log_stream, "End : INIT entry." ) ;
          goto My_Good_End ;
     } ; /* endif */

     if ( MyMQCXP_ExitReason == MQXR_TERM ) {
          mTraza ( Trace_log_stream, "End : TERM entry." ) ;
          goto My_Good_End ;
     } ; /* endif */

// See MQXQH.MsgDesc.Format :

     mTraza ( Trace_log_stream, "Part Ver MsgDesc-Format." ) ;

     if ( strncmp ( MyMQMD_Format, MQFMT_NONE, sizeof(MyMQMD_Format) ) == 0 ) {
          mTraza ( Trace_log_stream, "Work : NONE format." ) ;
     } else {
          if ( strncmp ( MyMQMD_Format, MQFMT_STRING, sizeof(MyMQMD_Format) ) == 0 ) {
               mTraza ( Trace_log_stream, "Work : STRING format." ) ;
          } else {
               if ( strncmp ( MyMQMD_Format, "MQ", sizeof("MQ") ) == 0 ) {
                    mTraza ( Trace_log_stream, "End : MQ format." ) ;
                    goto My_Good_End ;
               } else {

#if  DO_DEBUG > 0
                    cnt = sprintf ( MiDbg_Buffer,
                                    "Work : Other -> NONE format (%.8s).",
                                    MyMQMD_Format ) ; // 131097.
                    mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
#endif                        // debug : dont trace.

                    strncpy ( MyMQMD_Format, MQFMT_NONE, sizeof(pMQXQHptr -> MsgDesc.Format) ) ;

               } ; /* endif */
          } ; /* endif */
     } ; /* endif */

     mTraza ( Trace_log_stream, "Part see Channel Type." ) ;

     switch ( MyMQCD_ChannelType ) {

          case MQCHT_SENDER :
//        *******************

               mTraza ( Trace_log_stream, "Work : SND channel type." ) ;

// Display OLD message.
#if  DO_DEBUG > 0
               DumpMsg ( pMsgData, MsgDataLength, Trace_log_stream ) ;
#endif                        // debug : dont display msg.

// UserID comes right after MD and is 8 chars long (Host User Id size).

#define   LngMsg2Delete  8
#define   Shift2Delete   0

// Copy UserID from message into own area, then to MD.

          memset ( MyMQMD_UserIdentifier, '\0', sizeof(MyMQMD_UserIdentifier) ) ;
          strncpy ( MyMQMD_UserIdentifier, pMsgData, LngMsg2Delete ) ;
          strncpy ( pMQXQHptr -> MsgDesc.UserIdentifier,
                    MyMQMD_UserIdentifier,
                    sizeof(pMQXQHptr -> MsgDesc.UserIdentifier) ) ;

// +++ FIX02

// assign "iMsgNuestro" := 1 if "AA0" in Header Format Code :

          iMsgNuestro = 0 ;   // not ours unless verified

//        memset ( MiHeader_Format_Code, '\0', sizeof(MiHeader_Format_Code) ) ;

// Header Format Code comes after MsgStart plus :
// 8(user), 2(lng), 2(reserved), 8(IMS code), 1(separator) ... total 21.
#define   Shift2HFC      21
// #define   LngMsgHFC2Copy 3
#define   LngMsgHFC2Cmp  3

          pMsgDataSource = pMsgData + Shift2HFC ;

//        strncpy ( pMsgDataSource,
//                  MiHeader_Format_Code,
//                  LngMsgHFC2Copy ) ;

          if ( strncmp ( pMsgDataSource,
                         "AA0",
                         LngMsgHFC2Cmp ) == 0 ) {
               iMsgNuestro = 1 ;   // our code is present in Header.
          } ;

// --- FIX02

// Modify the message inplace (if it is a Request or a Datagram) + ours
// Reflect changes in DataLength !

     if (
         (
          ( MyMQMD_MsgType == MQMT_REQUEST )
          ||
          ( MyMQMD_MsgType == MQMT_DATAGRAM )
         )
        &&
         ( MsgDataLength > LngMsg2Delete )
        &&
         ( MsgDataLength >= Shift2Delete + LngMsg2Delete )
        &&
         ( iMsgNuestro == 1 )
        ) {

          pMsgDataSource = pMsgData + Shift2Delete + LngMsg2Delete ;
          pMsgDataDestination = pMsgData + Shift2Delete ;

          i = MsgDataLength - ( LngMsg2Delete + Shift2Delete ) ;
          while ( i > 0 ) {
               ( * pMsgDataDestination ) = ( * pMsgDataSource ) ;
               pMsgDataSource ++ ;
               pMsgDataDestination ++ ;
               i -- ;
          } ; /* endwhile */
          ( * pMsgDataDestination ) = '\0' ;

          MsgDataLength = MsgDataLength - LngMsg2Delete ;
          (*inmsglngptr) = MsgDataLength + sizeof(MQXQH) ;

     } ; /* endif */

// Display NEW message.
#if  DO_DEBUG > 0
               DumpMsg ( pMsgData, MsgDataLength, Trace_log_stream ) ;
#endif                        // debug : dont display msg.

               goto My_Good_End ;
               break ;

          case MQCHT_RECEIVER :
//        *********************

               mTraza ( Trace_log_stream, "Work : RCV channel type." ) ;

// Debug only : see input msg, Rcv.
#if  DO_DEBUG > 0
               DumpMsg ( pMsgData, MsgDataLength, Trace_log_stream ) ;
#endif                        // debug : dont display msg.

               goto My_Good_End ;
               break ;

          case MQCHT_SERVER :
               mTraza ( Trace_log_stream, "No work : SRV channel type." ) ;
               goto My_Good_End ;
               break ;

          case MQCHT_REQUESTER :
               mTraza ( Trace_log_stream, "No work : REQ channel type." ) ;
               goto My_Good_End ;
               break ;

          default :
               pMQCXPptr -> ExitResponse = MQXCC_SUPPRESS_FUNCTION ;    // indicate ERROR end.
               pMQCXPptr -> Feedback = MyRC_4 ;                         // indicate some detail.
#if  DO_DEBUG > 0
               cnt = sprintf ( MiDbg_Buffer, "MQCD channel type (%i) unknown.", MyMQCD_ChannelType ) ;
               mTraza ( Trace_log_stream, MiDbg_Buffer ) ;
#endif                        // debug : dont trace.
               goto My_Common_End ;
               break ;
     } ; /* endswitch */

My_Good_End:

#if  DO_DEBUG > 0
     mTraza ( Trace_log_stream, "Part Good End." ) ;
#endif                        // debug : dont close the file needed to trace into a file.

     pMQCXPptr  -> ExitResponse = MQXCC_OK ;                   // indicate OK end.
     pMQCXPptr  -> ExitResponse2 = MQXR2_USE_AGENT_BUFFER ;    // indicate OK end.

My_Common_End:

#if  DO_DEBUG > 0
     mTraza ( Trace_log_stream, "End of the trace." ) ;
     mTraza ( Trace_log_stream, Separador ) ;
     fclose ( Trace_log_stream ) ;
#endif                        // debug : dont close the file needed to trace into a file.

     return ;

 } ;    // end of MsgExit.

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#if  DO_DEBUG > 0
void DumpMsg ( MQBYTE * pDato, int Max_Lng, FILE * Ostr )
{
char aux [ 3 ] ;
int  cnt = 0 ;                     // sprintf return value.
int  i ;
char DmpTxt_Buffer [ 256 ] ;       // string concatenation buffer

     cnt = fprintf ( Ostr, "Dump (%i) chars from (%li).\n", Max_Lng, pDato ) ;

     DmpTxt_Buffer [ 0 ] = '\0';
     for ( i = 0 ; i < Max_Lng ; i++ ) {

          sprintf ( aux, "%2.2x", pDato [ i ] ) ;
          strcat ( DmpTxt_Buffer, aux ) ;
          if ( i < Max_Lng -1 ) {
               strcat ( DmpTxt_Buffer, "-" ) ;
          } ; /* endif */

          if ( strlen ( DmpTxt_Buffer ) >= 60  ) {

               strcat ( DmpTxt_Buffer, "\n" ) ;
               cnt = fprintf ( Ostr, DmpTxt_Buffer ) ;     /* output to file */

               DmpTxt_Buffer [ 0 ] = '\0';

          }  /* endif */

     } ; /* endfor */

     if ( strlen ( DmpTxt_Buffer ) > 0  ) {

          strcat ( DmpTxt_Buffer, "\n" ) ;
          cnt = fprintf ( Ostr, DmpTxt_Buffer ) ;          /* output (remaining) to file */
     } ;
} ;
#endif                        // debug : dont display msg.

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#if  DO_DEBUG > 0
void Traza ( FILE * traceArchivo, char * Texto )
{
char      MiTime [ 64 ] ;               // used by _strtime
char      MiTxt_Buffer [ 256 ] ;        // string concatenation buffer
int       cnt ;                         // sprintf return value

time_t    mvqtime_t ;
struct tm * tmptr ;
int       len ;

     time ( & mvqtime_t ) ;
     tmptr = localtime ( & mvqtime_t ) ;
     strcpy ( MiTime, asctime ( tmptr ) ) ;
     len = strlen ( MiTime ) ;
     MiTime [ len -1 ] = '\0' ; // remove CR

     cnt = sprintf ( MiTxt_Buffer, "(%s) %s\n", MiTime, Texto ) ;
     cnt = fprintf ( traceArchivo, MiTxt_Buffer ) ;     /* output to file */
     fflush ( traceArchivo ) ;

} ;  // end of TRAZA.
#endif                        // debug : dont generate the code needed to trace into a file.

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++