Sun Java System Messaging Server 6 2005Q4 MTA Developer's Reference

A Simple Decoding Example

This sample program found in Example 5–1 decodes a MIME formatted message using mtaDecodeMessage(). This is not a channel program. The actual message to be decoded is compiled into the program rather than being drawn from a channel queue.

After the Messaging Server product is installed, these programs can be found in the following location:

msg_server_base/examples/mtasdk/

Some lines of code are immediately preceded by a comment of the format:

/* See explanatory comment N */

where N is a number. The numbers are links to some corresponding explanatory text in the section that follows this code, see Explanatory Text for Numbered Comments in the Simple Decoding Example.

For the sample output generated by this program, see MIME Message Decoding Simple Example Output.


Example 5–1 Decoding MIME Messages Simple Example


/*
 *  decode_simple.c
 *
 *    Decode a multipart MIME message.
 *
 */
#include <stdio.h>
#include <string.h>
#include "mtasdk.h"

/* 
 *  Inline data for a sample message to decode
 * See explanatory comment 1 
 */
static const char message[] = 
  "From: sue@siroe.com\n"
  "Date: 31 Mar 2003 09:32:47 -0800\n"
  "Subject: test message\n"
  "Content-type: multipart/mixed; boundary=BoundaryMarker\n"
  "\n\n"
  "--BoundaryMarker\n"
  "Content-type: text/plain; charset=us-ascii\n"
  "Content-disposition: inline\n"
  "\n"
  "This is a\n"
  "  test message!\n"
  "--BoundaryMarker\n"
  "Content-type: application/postscript\n"
  "Content-disposition: attachment; filename='a.ps'\n"
  "Content-transfer-encoding: base64\n"
  "\n"
  "IyFQUwoxMDAgMTAwIG1vdmV0byAzMDAgMzAwIGxpbmV0byBzdHJva2UKc2hv"  "3Bh\n"
  "Z2UK\n"
  "--BoundaryMarker--\n";

static mta_decode_read_t decode_read;
static mta_decode_inspect_t decode_inspect;
typedef struct {
     const char *cur_position;
     const char *end_position;
} position_t;

main()
{
     position_t pos;

     /*
      * Initialize the MTA SDK
      */
     if ((ires = mtaInit(0)))
     {
         mtaLog("mtaInit() returned %d; %s\n", ires, 
                mtaStrError(ires, 0));
         return(1);
     }

     /* 
      *  For a context to pass to mtaDecodeMessage(), we pass a
      *  pointer to the message data to be parsed.  The 
      *  decode_read() routine uses this information when 
      *  supplying data to mtaDecodeMessage().
      *  See explanatory comment 2 
      */
     pos.cur_position = message;
     pos.end_position = message + strlen(message);

     /*
      *  Invoke mtaDecodeMessage():
      *    1. Use decode_read() as the input routine to supply the 
      *       message to be MIME decoded,
      *    2. Use decode_inspect() as the routine to inspect each 
      *       MIME decoded message part,
      *    3. Do not specify an output routine to write the 
      *       resulting, MIME message, and
      *    4. Indicate that the input message source uses LF 
      *       record terminators. 
      *  See explanatory comment 3 
      */
     mtaDecodeMessage((void *)&pos, MTA_DECODE_PROC, 
                      (void *)decode_read,
                      0, NULL, decode_inspect, MTA_TERM_LF, 0);
}

/* 
 *  decode_read -- Provide message data to mtaDecodeMessage(). 
 *                 The entire message could just as easily be 
 *                 given to mtaDecodeMessage()at once. However, 
 *                 for illustration purposes, the message is 
 *                 provided in 200 byte chunks.
 *  See explanatory comment 4 
 */
static int decode_read(void *ctx, const char **line, size_t 
                       *line_len)
{
     position_t *pos = (position_t *)ctx;

     if (!pos)
          return(MTA_NO);
     else if (pos->cur_position >= pos->end_position)
          return(MTA_EOF);
     *line = pos->cur_position;
     *line_len = ((pos->cur_position + 200) < 
                 pos->end_position) ? 200 : 
                 (pos->end_position - pos->cur_position);
     pos->cur_position += *line_len;
     return(MTA_OK);
}

/* 
 *  decode_inspect -- Called by mtaDecodeMessage() to output a 
 *                    a line of the parsed message.  The line is 
 *                    simply output with additional information 
 *                    indicating whether the line comes from a 
 *                    header, text part, or binary part.
 *  See explanatory comment 5 
*/
static int decode_inspect (void *ctx, mta_decode_t *dctx, int 
                           data_type, const char *data,
                           size_t data_len)
{
     static const char *types[] = {"N", "H", "T", "B"};

     /* See explanatory comment 6 */
     if (data_type == MTA_DATA_NONE)
          return(MTA_OK);

     /* See explanatory comment 7 */
     printf("%d%s: %.*s\n",
            mtaDecodeMessageInfoInt(dctx, 
                                    MTA_DECODE_PART_NUMBER), 
                                    types[data_type], data_len, 
                                    data);

            return(MTA_OK);
}

Explanatory Text for Numbered Comments in the Simple Decoding Example

The following numbered explanatory text corresponds to the numbered comments in Example 5–1.

  1. The MIME message to be decoded. It is a multipart message with two parts. The first part contains text, the second part a PostScriptTM attachment.

  2. The private context to be passed to mtaDecodeMessage() and, in turn, passed by it to the supplied input routine, decode_read(). The input routine uses this context to track how many bytes of the input message it has supplied to mtaDecodeMessage().

  3. The call to mtaDecodeMessage(). An input routine, decode_read(), is supplied to provide the message to be decoded. Since the message source has each record terminated by line feeds, the MTA_TERM_LF option is also specified. The routine decode_inspect() is passed for use as an inspection routine.

  4. The input routine, decode_read(). This routine provides the message to be decoded 200 bytes at a time. Note that providing only 200 bytes at a time is arbitrary: the routine could, if it chose, provide the entire message, or 2000 bytes at a time, or a random number of bytes on each call. After the entire message has been supplied, subsequent calls to decode_read() return the MTA_EOF status.

  5. The inspection routine, decode_inspect(). For each atomic message part, this routine is called repeatedly. The repeated calls provide, line by line, the part’s header and decoded content.

  6. For a given message part, the final call to decode_inspect() provides no part data. This final call serves to give decode_inspect() a last chance to accept or discard the part when outputting the final form of the message via an optional output routine supplied to mtaDecodeMessage(). That optional routine is not used here.

  7. The part number for this message part is obtained with a call to mtaDecodeMessageInfoInt().

MIME Message Decoding Simple Example Output

The following shows the output generated by the program in Example 5–1.


1H: Content-type: text/plain; charset=us-ascii
1H: Content-disposition: inline
1T: This is a
1T:   test message!
2H: Content-type: application/postscript
2H: Content-transfer-encoding: base64
2H: Content-disposition: attachment; filename="a.ps"
2B: #!PS
100 100 moveto 300 300 lineto stroke
showpage