text/plain
: Text content (type) in plain
format (subtype). image/gif
: An image
file (type) in gif
format (subtype).
Figure 3.1 Parts of a MIME message
|
Figure 3.2 Translating a MIME Message
pNewMessage
.
mime_message_t *pNewMimeMessage =Then, add two components, in either order.
(mime_message_t *) mime_malloc (sizeof (mime_message_t));
name:value
pairs that conform to the requirements of RFC 822. For more information, see Adding Message Headers.mime_message_create
, a convenience function that builds a MIME message structure:
int mime_message_create (char * in_pText,You provide the filename of an attachment or text; one of these is required. Also, supply the file encoding type to use (either Base64, Quoted Printable, or -1 to use a default). This function creates a message, to which you add the headers. One of the sample applications in the
char * in_pFileFullName,
mime_encoding_type in_perf_file_encoding,
mime_message_t ** out_ppMessage);
examples
directory of the SDK illustrates building a message using this function.
The following section of code demonstrates using mime_message_create
to build a MIME message with text, a data buffer, and a file.
/* Build a MIME Message with "text" and the file "/tmp/testfile.txt" */
ret = mime_message_create (pBuf, "/tmp/testfile.txt", enc, &pMsg);
/* Build a message with just text and NO file. */
ret = mime_message_create (pBuf, NULL, 0, &pMsg);
/* Build a message with just a file and NO text. */
ret = mime_message_create (NULL, "/tmp/testfile.txt", 0, &pMsg);Next, add the headers to the message. See Adding Message Headers. [Top]
mime_header_new
function. You supply the header name and value. This function creates a header entry as a name:value
pair and adds it to the message.
mime_header_t * pHdr = mime_Header_new (To create a header, this function populates a
char * in_pName, char * in_pValue);
mime_header_t
structure with the name and value parameters you specify. Now you can add this header to the RFC 822 header part of the MIME message.
The following section of code creates RFC 822-compliant headers for a MIME message.
mime_header_new ("From", "prasad@netscape.com");
mime_header_new ("To", "smith@netscape.com");
mime_header_new ("Subject", "Using MIME");
mime_header_new ("X-Msg-SDK-HDR", "X-Test-Value1");When the headers are created, add them to the
rfc822_headers
member of the MIME message structure
mime_messagePart_t
.
Next, you can add any of the other message parts or attachments that the message requires. See Adding Content to the Message.
[Top]
mime_basicPart_t
. This is the common structure for the leaf parts, text, audio, video, image, and application.
Create the basic part by defining the
mime_basicPart_t
structure and setting up the attributes of the part, including elements such as content description, content type, and headers, including X-headers.
After you set up the basic part structure and its attributes, you can add the body data to the structure. To do this, use either
mime_basicPart_setDataBuf
or
mime_basicPart_setDataStream
, depending on the source of the data.
int mime_basicPart_setDataBuf (The
mime_basicPart_t * in_pBasicPart,
unsigned int in_size,
const char * in_pDataBuf,
BOOLEAN in_fCopyData);
in_pBasicPart
parameter identifies the basic part that you are adding the data to; you must already have created this part. The in_pDataBuf
parameter represents the data source. Use the in_fCopyData
parameter to specify whether to the function should copy the data or keep a reference to the data buffer.
Repeat this for each basic part you add to the multipart.
The mime_basicPart_setDataStream
function works in the same way, except that the data source is an input stream.
int mime_basicPart_setDataStream (Now you can add this part to the message. See Adding Parts to the Message. [Top]
mime_basicPart_t * in_pBasicPart,
mime_inputstream_t * in_ptheDataStream,
BOOLEAN in_fCopyData);
mime_multiPart_t * pMultiPart = (mime_multiPart_t *)To add basic parts to a multipart, use one of these MIME API functions:
mime_malloc (sizeof (mime_multiPart _t);
mime_multiPart_addBasicPart
. Adds an existing basic part to a multipart. See Adding a Basic Part to a Multipart.
mime_multiPart_addMessagePart
. Adds an existing message part to a multipart.
mime_multiPart_addMultiPart
. Adds an existing multipart to a multipart.
mime_multiPart_addFile
. A convenience function that adds the specified file as a basic part to a multipart. mime_multiPart_addBasicPart
.
int mime_multiPart_addBasicPart (You supply the existing basic part that you are adding, the multipart to add it to, and the index at which you want to add it. Use the
mime_multiPart_t * in_pMultiPart,
mime_basicPart_t * in_pBasicPart,
BOOLEAN in_fClone,
int * out_index_assigned);
in_fClone
parameter to specify whether to the function should keep a reference to the body part object itself or a cloned copy. Repeat this for each basic part you add to the multipart.
After creating and assembling the multipart, the next step is to add the multipart to the message. See Adding Parts to the Message.
[Top]
mime_message_addBasicPart
. Adds a basic part to a message.
mime_message_addMessagePart
. Adds a message part to a message.
mime_message_addMultiPart
. Adds a multipart to a message.mime_message_addBasicPart
function, shown here:
int mime_message_addBasicPart (The basic part becomes the body of the message. The content-type of the message is set according to the content type of the basic part. If the message already has a message body, an error occurs. Use the
mime_message_t * in_pMessage,
mime_basicPart_t * in_pBasicPart,
BOOLEAN in_fClone);
in_fClone
parameter to specify whether to the function should keep a reference to the body part object itself or a cloned copy.
You can simplify the process of building and adding content to a message by using the convenience function
mime_message_create
. You supply text, a file to attach, and the encoding type. The function creates a message, to which you add the headers. For more information about this function, see Building the MIME Message.
[Top]int mime_messagePart_fromMessage (This function takes the message structure and returns it as a message part. To add the message part as the body of the message, use this function.
mime_message_t * in_pMessage,
mime_messagePart_t ** out_ppMessagePart()
int mime_message_addMessagePart (This function fails if a message body already exists. The
mime_message_t * in_pMessage,
mime_messagePart_t * in_pMessagePart,
BOOLEAN in_fClone);
clone
parameter should contain true
if the function should clone a copy of the message or false
if it should store a reference to the passed object.
[Top]
mime_basicPart_deleteData
. Deletes the body data for a part.
mime_multiPart_deletePart
. Deletes a body part from a multipart.
mime_messagePart_deleteMessage
. Deletes a MIME message that is the body of a message part.
mime_message_deleteBody
. Deletes the body of a message.mime_message_putByteStream
function. Encoding puts messages into MIME canonical form, so that they can be transmitted over SMTP and other transport functions.
int mime_message_putByteStream (The function required pointers to the message that contains data to encode and to the MIME output stream for the encoded data. For the SDK functions that create input and output streams, see Shared Functions. After the message is encoded, you can send it using SMTP. For information about SMTP, see Chapter 2, "Sending Mail with SMTP." The following section of code writes the MIME-encoded message to the specified target, in this case, a file.
mime_message_t * in_pMessagePart,
mime_outputstream_t * in_pOutput_stream);
/* Writes the MIME encoded message to a file */
sprintf (filename, "%s%s", TMPDIR, "sdkCEnc.out");
file_outputStream_create (filename, &pOS);
mime_message_putByteStream (pMsg, pOS);
file_outputStream_close (pOS->rock);
nsStream_free (pOS);[Top]
mime_message_putByteStream
function could call either of two encoding utility functions, mime_encodeBase64
or mime_encodeQP
, based on whether the requested encoding type is Base64 (default for non-text types) or Quoted Printable. These utility functions each provide a single form of encoding. Like mime_message_putByteStream
, these functions take an input stream and encode it. If an application requires only Base64 or QP-encoded data, you can use one of these functions in place of mime_message_putByteStream
.
mime_encodeBase64
. Base64 encodes data and writes it to an output stream.
mime_encodeQP
. Quoted Printable encodes the data from an input stream and writes to output stream.
parseEntireMessage
and
parseEntireMessageInputstream
functions, which parse and decode encoded messages, could call either of two decoding utility methods, mime_decodeBase64
or mime_decodeQP
, based on the requested encoding type. These utility methods each provide a single form of decoding, and could be used instead of parseEntireMessage
if an application only needs to decode Base64 or QP-encoded data.
mime_decodeBase64
. Base64 decodes the data from an input stream and writes to an output stream.
mime_decodeQP
. Quoted Printable decodes the data from an input stream and writes to an output stream.
mime_encodeHeaderString
. Encodes an RFC 2047-compliant header from an input stream, using Base64 or Q encoding. You can select the character set for the input stream. The header string can be used as the value of unstructured headers or in the comments section of structured headers.
mime_decodeHeaderString
. Decodes only the RFC 2047-compliant header of a message.mimeparser.h
.
To parse a message from a data buffer, use parseEntireMessage
:
mime_message_t * parseEntireMessage (char *pData,Supply a pointer to the message data and the length of the data. The function returns the parsed message. To parse a message from an input stream, use
int nLen,
struct mime_message ** ppMimeMessage);
parseEntireMessageInputstream
:
int parseEntireMessageInputstream(Supply the identifier for the stream that is the source of the data and the destination of the message. For the SDK functions that create input and output streams, see Shared Functions. The following section of code uses
struct nsmail_inputstream *pInput,
struct mime_message **ppMimeMessage);
parseEntireMessageInputstream
, which parses the encoded message from an input stream, as part of a routine that parses an entire file.
void main( int argc, char *argv[ ] )
{
parseEntireFile( "mimefile.txt" );
}
void parseEntireFile( char *szFilename )
{
nsmail_inputstream_t *pInput;
if ( file_inputstream_create( szFilename, &pInput ) == MIME_OK )
{
mime_message_t *pMessage;
/* Parse the MIME Message */
if ( parseEntireMessageInputstream( pInput, &pMessage ) == MIME_OK )
{
showObject( pMessage, MIME_MESSAGE );
mime_message_free( pMessage );
}
pInput -> close();
nsStream_free (pInput);
}
}[Top]
parseEntireMessage
function does not use callbacks; instead, it passes the entire parsed message to the user after parsing is complete.
mime_decodeBase64
and
mime_decodeQP
.mimeparser.h
.
[Top]
mimeDataSink_t
structure. The data sink is made up of function pointers and opaque data, which are set to null
when the sink is initialized. For general information about the data sink, see SDK Response Sinks for C.
After creating the data sink, the application passes it to the parser. As the parser encounters information, it sends this on to the caller through callbacks in the data sink. The MIME data sink contains a call for each piece of information that the parser can return.
To initialize and allocate the data sink, call the mimeDataSink_new
function and pass in the sink you want to use. If successful, this function returns
NSMAIL_OK
.
int mimeDataSink_new ( mimeDataSink_t **pp );You can create parsers with different data sinks, based on what you want the messaging application to do. For example, you can define data sinks that create a brief header, a normal header, or list all header lines, each of which can be invoked with a different parser invocation. To add headers, define the ones your application requires within the data sink structure. The following section of code creates the data sink and sets the sink function pointers.
/* Create the functions for the data sink */
void mimeDataSink_header( mimeDataSinkPtr_t pSink,
void *pCallbackObject, char *name, char *value )
{
sprintf( achTemp, "header() name = [%s]
value = [%s]\n", name, value );
output( achTemp );
}
void mimeDataSink_contentType( mimeDataSinkPtr_t pSink,
void *pCallbackObject, int nContentType )
{
sprintf( achTemp, "contentType() = [%d]\n", nContentType );
output( achTemp );
}
void mimeDataSink_contentSubType( mimeDataSinkPtr_t pSink,
void *pCallbackObject, char * contentSubType )
{
sprintf( achTemp, "contentSubType() = [%s]\n", contentSubType );
output( achTemp );
}
void mimeDataSink_contentTypeParams( mimeDataSinkPtr_t pSink,
void *pCallbackObject, char * contentTypeParams
)
{
sprintf( achTemp, "contentTypeParams() = [%s]\n",
contentTypeParams ); output( achTemp );
}
void mimeDataSink_contentID( mimeDataSinkPtr_t pSink,
void *pCallbackObject, char *contentID )
{
sprintf( achTemp, "contentID() = [%s]\n", contentID );
output( achTemp );
}
/* Create the data sink */
mimeDataSink_new (&pDataSink );
/* Add the functions to the data sink */
pDataSink->header = &mimeDataSink_header;
pDataSink->contentType = &mimeDataSink_contentType;
pDataSink->contentSubType = &mimeDataSink_contentSubType;
pDataSink->contentTypeParams = &mimeDataSink_contentTypeParams;
pDataSink->contentID = &mimeDataSink_contentID;
/* Continue as required */When a session is finished, you must free any memory associated with the data sink. Use this function:
void mimeDataSink_free( mimeDataSink_t **pp );This function frees the data sink structure. The user must free any pointers to opaque data. After you create the data sink, the next step is Creating the Dynamic Parser. [Top] [Creating a Data Sink]
mimeDynamicParser_new
function to create a new parser and identify the data sink to use.
int mimeDynamicParser_new( mimeDataSink_t *pDataSink,Supply the identifier for the data sink and the parser to use. The following section of code creates a dynamic parser.
struct mimeParser **pp);
/* Initialize sink first, as described in Creating a Data Sink */
if ( mimeDynamicParser_new( pDataSink, &p) != MIME_OK )When a session is finished, you must free any memory associated with the dynamic parser. Use this function:
void mimeDynamicParser_free( struct mimeParser **pp );This function frees the dynamic parser structure and its data members. After you create the dynamic parser, the next step is Running the Parser. [Top]
int beginDynamicParse( struct mimeParser *p );This function requires the identifier of the parser created with
mimeDynamicParser_new
.
To continue parsing, use the function that is appropriate for the data source, either an input stream or a data buffer. Continue to call this function until there is no more data left.
Use this function to parse data from an input stream:
int dynamicParseInputstream( struct mimeParser *p,This function requires the identifier of the parser and the input stream to use. For the SDK functions that create input and output streams, see Shared Functions. Use this function to parse data from a data buffer.
struct nsmail_inputstream_t *pInput );
int dynamicParse( struct mimeParser *p, char *pData, int nLen );This function requires the identifier of the parser in use, the data buffer to use, and the length of the data to parse. When no more data remains to be parsed, call this function to indicate that parsing is complete:
int endDynamicParse( struct mimeParser *p );The parser ends the operation. To initiate another parsing cycle, you can call
beginDynamicParse
again.
The following section of code creates a dynamic parser, parses data from an input stream, and ends the parse operation.
/* Create the dynamic parser; see Creating the Dynamic Parser */
( mimeDynamicParser_new( pDataSink, &p );
( file_inputstream_create( szFilename, &pInput );
/* Start dynamic parsing */
beginDynamicParse( p );
for ( len = pInput->read( pInput->rock, buffer, BUFFER_SIZE2 );
len > 0;
len = pInput->read( pInput->rock, buffer, BUFFER_SIZE2 ) )
/* Continue dynamic parsing until no more data remains */
{
if ( dynamicParse( p, buffer, len ) != MIME_OK )
break;
}
/* When data is finished, stop the dynamic parser */
endDynamicParse(p);
/* Free the data sink used by the parser */
/* See Creating a Data Sink */
{
mimeDataSink_free( &pDataSink );
}[Top]
Last Updated: June 3, 1998