diff --git a/msgsdk/C/protocol/MIME/include/mime.h b/msgsdk/C/protocol/MIME/include/mime.h new file mode 100644 index 000000000000..c2c565816a5b --- /dev/null +++ b/msgsdk/C/protocol/MIME/include/mime.h @@ -0,0 +1,480 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +#ifndef MIME_H +#define MIME_H + +#include "nsmail.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIME_OK 0 +#define MIME_ERR_UNINITIALIZED -1 /* don't modify */ +#define MIME_ERR_INVALIDPARAM -2 +#define MIME_ERR_OUTOFMEMORY -3 +#define MIME_ERR_UNEXPECTED -4 +#define MIME_ERR_IO -5 +#define MIME_ERR_IO_READ -6 +#define MIME_ERR_IO_WRITE -7 +#define MIME_ERR_IO_SOCKET -8 +#define MIME_ERR_IO_SELECT -9 +#define MIME_ERR_IO_CONNECT -10 +#define MIME_ERR_IO_CLOSE -11 +#define MIME_ERR_PARSE -12 +#define MIME_ERR_TIMEOUT -13 +#define MIME_ERR_INVALID_INDEX -14 +#define MIME_ERR_CANTOPENFILE -15 +#define MIME_ERR_CANT_SET -16 +#define MIME_ERR_ALREADY_SET -17 +#define MIME_ERR_CANT_DELETE -18 +#define MIME_ERR_CANT_ADD -19 +/* reserved by nsmail.h codes -20 through -30 */ + +#define MIME_ERR_EOF -82 +#define MIME_ERR_EMPTY_DATASINK -83 +#define MIME_ERR_ENCODE -84 +#define MIME_ERR_NO_SUCH_HEADER -85 +#define MIME_ERR_NO_HEADERS -86 +#define MIME_ERR_NOT_SET -87 +#define MIME_ERR_NO_BODY -88 +#define MIME_ERR_NOT_FOUND -89 +#define MIME_ERR_NO_CONTENT_SUBTYPE -90 +#define MIME_ERR_INVALID_ENCODING -91 +#define MIME_ERR_INVALID_BASICPART -92 +#define MIME_ERR_INVALID_MULTIPART -93 +#define MIME_ERR_INVALID_MESSAGEPART -94 +#define MIME_ERR_INVALID_MESSAGE -95 +#define MIME_ERR_INVALID_CONTENTTYPE -96 +#define MIME_ERR_INVALID_CONTENTID -97 +#define MIME_ERR_NO_DATA -98 +#define MIME_ERR_NOTIMPL -99 +#define MIME_ERR_EMPTY_BODY -100 +#define MIME_ERR_EMPTY_BODY -100 +#define MIME_ERR_UNSUPPORTED_PARTIAL_SUBTYPE -101 +#define MIME_ERR_MAX_NESTED_PARTS_REACHED -102 + +#define MIME_BUFSIZE 1024 + +struct mimeDataSink; + +/* ----------------------------- */ +typedef enum mime_encoding_type +{ + MIME_ENCODING_UNINITIALIZED = -1, /* don't modify */ + MIME_ENCODING_BASE64 = 1, + MIME_ENCODING_QP, + MIME_ENCODING_7BIT, /* 7 bit data with NO transfer encoding */ + MIME_ENCODING_8BIT, /* 8 bit data with NO transfer encoding */ + MIME_ENCODING_BINARY /* Binary data with NO transfer encoding */ + +} mime_encoding_type; + + +typedef enum mime_disp_type +{ + MIME_DISPOSITION_UNINITIALIZED = -1, /* don't modify */ + MIME_DISPOSITION_INLINE = 1, + MIME_DISPOSITION_ATTACHMENT + +} mime_disp_type; + + +typedef enum mime_content_type +{ + MIME_CONTENT_UNINITIALIZED = -1, /* don't modify */ + MIME_CONTENT_TEXT, + MIME_CONTENT_AUDIO, + MIME_CONTENT_IMAGE, + MIME_CONTENT_VIDEO, + MIME_CONTENT_APPLICATION, + MIME_CONTENT_MULTIPART, + MIME_CONTENT_MESSAGEPART + +} mime_content_type; + + + +typedef struct mime_header +{ + char *name; + char *value; + struct mime_header *next; + +} mime_header_t; + + + +/* Common structure for leaf parts: Text, Audio, Video, Image and Application */ +typedef struct mime_basicPart +{ + char * content_description; + mime_disp_type content_disposition; + char * content_disp_params; /* content disposition parameters */ + mime_content_type content_type; + char * content_subtype; + char * content_type_params; + char * contentID; + mime_header_t * extra_headers; /* additional X- and Content- headers */ + char * contentMD5; /* MD5 CRC code */ + mime_encoding_type encoding_type; + void *pInternal; /* Stuff that client can not directly manipulate */ + +} mime_basicPart_t; + + + +typedef struct mime_messagePart +{ + char * content_description; + mime_disp_type content_disposition; + char * content_disp_params; /* content disposition parameters */ + mime_content_type content_type; + char * content_subtype; + char * content_type_params; + char * contentID; + mime_header_t * extra_headers; /* additional X- and Content- headers */ + mime_encoding_type encoding_type; + mime_header_t * extern_headers; /* for extern-body */ + void *pInternal; /* Stuff that client can not directly manipulate */ + +} mime_messagePart_t; + + + +typedef struct mime_multiPart +{ + char * content_description; + mime_disp_type content_disposition; + char * content_disp_params; /* content disposition parameters */ + mime_content_type content_type; + char * content_subtype; + char * content_type_params; + mime_encoding_type encoding_type; + char * contentID; + mime_header_t * extra_headers; /* additional X- and Content- headers */ + char * preamble; + void *pInternal; /* Stuff that client can not directly manipulate */ + +} mime_multiPart_t; + + +typedef struct mime_message +{ + mime_header_t * rfc822_headers; /* message headers */ + void *pInternal; /* Stuff that client can not directly manipulate */ + +} mime_message_t; + + +typedef struct file_mime_type +{ + mime_content_type content_type; + char * content_subtype; + char * content_params; + mime_encoding_type mime_encoding; +/* char * file_extn; */ +/* char * file_shortname; */ +} file_mime_type; + + + + +/*************************************************************************/ +/** BASIC (LEAF) BODY PART TYPES **/ +/*************************************************************************/ + +/* Set the body-data for this part from an input stream. + * This can only be done on a (new) mime_basicPart with empty bodydata. + */ +int mime_basicPart_setDataStream (mime_basicPart_t * in_pBasicPart, + nsmail_inputstream_t *in_pTheDataStream, + BOOLEAN in_fCopyData); + +/* Set the body-data for this part from a buffer. + * This can only be done on a (new) mime_basicPart with empty bodydata. + */ +int mime_basicPart_setDataBuf (mime_basicPart_t * in_pBasicPart, + unsigned int in_size, + const char * in_pDataBuf, + BOOLEAN in_fCopyData); + +/* Deletes the bodyData for this part. */ +int mime_basicPart_deleteData (mime_basicPart_t * in_pBasicPart); + +/* gives the size of the body-data in bytes */ +int mime_basicPart_getSize (mime_basicPart_t * in_pBasicPart, + unsigned int * out_pSize); + +/* returns the body-data after any decoding in an input stream */ +/* If in_pFileName is NULL returns a memory based input-stream */ +/* If in_pFileName is not NULL, returns the specified file based */ +/* input-stream to the data */ +int mime_basicPart_getDataStream (mime_basicPart_t *in_ppBasicPart, + char * in_pFileName, + nsmail_inputstream_t **out_ppDataStream); + +/* returns the body-data after any decoding in a buffer */ +int mime_basicPart_getDataBuf (mime_basicPart_t * in_pBasicPart, + unsigned int * out_pSize, + char **out_ppDataBuf ); + +/* Writes out byte stream for this part with MIME headers and encoded body-data */ +int mime_basicPart_putByteStream (mime_basicPart_t * in_pBasicPart, + nsmail_outputstream_t *in_pOutput_stream); + +/* Frees up the basic-part and all internal structures. User should set in_pBasicPart = NULL up on return*/ +int mime_basicPart_free_all (mime_basicPart_t * in_pBasicPart); + + +/*************************************************************************/ +/** COMPOSITE BODY PART TYPES **/ +/*************************************************************************/ + +/*=========================== MULTI PART =================================*/ + +/* Adds a file as basic part to the multi-part. */ +/* If in_pref_file_encoding > 0 attempts to use the encoding */ +/* for the file-attachment. If encoding is not valid for the */ +/* file-type overrides with the correct value. */ +int mime_multiPart_addFile (mime_multiPart_t * in_pMultiPart, + char * in_pFileFullName, + mime_encoding_type in_pref_file_encoding, + int * out_pIndex_assigned); + +/* Adds a basic part to the multi-part. */ +int mime_multiPart_addBasicPart (mime_multiPart_t * in_pMultiPart, + mime_basicPart_t * in_pBasicPart, + BOOLEAN in_fClone, + int * out_pIndex_assigned); + +/* Adds a message part to the multi-part. */ +int mime_multiPart_addMessagePart (mime_multiPart_t * in_pMultiPart, + mime_messagePart_t * in_pMessagePart, + BOOLEAN in_fClone, + int * out_pIndex_assigned); + +/* Adds a message part to the multi-part. */ +int mime_multiPart_addMultiPart (mime_multiPart_t * in_pMultiPart, + mime_multiPart_t * in_pMultiPartToAdd, + BOOLEAN in_fClone, + int * out_pIndex_assigned); + +/* Deletes the bodyPart at the requested index from this multi-part */ +int mime_multiPart_deletePart (mime_multiPart_t * in_pMultiPart, + int in_index); + +/* returns the count of the body parts in this multi-part */ +int mime_multiPart_getPartCount (mime_multiPart_t * in_pMultiPart, + int * out_count); + +/* returns the body part at the specified index */ +int mime_multiPart_getPart (mime_multiPart_t * in_pMultiPart, + int in_index, + mime_content_type * out_pContentType, + void **out_ppTheBodyPart /* Client can cast based on pContentType */ + ); + +/* Writes out byte stream for this part with MIME headers and encoded body-data */ +int mime_multiPart_putByteStream (mime_multiPart_t * in_pMultiPart, + nsmail_outputstream_t *in_pOutput_stream); + +/* Frees up the multi-part and all internal structures. User should set in_pMultiPart = NULL up on return*/ +int mime_multiPart_free_all (mime_multiPart_t * in_pMultiPart); + + +/*=========================== MESSAGE PART =================================*/ + +/* creates a message part from a message structure */ +int mime_messagePart_fromMessage (mime_message_t * in_pMessage, + mime_messagePart_t ** out_ppMessagePart); + +/* retrieves the message from the message part */ +int mime_messagePart_getMessage (mime_messagePart_t * in_pMessagePart, + mime_message_t ** out_ppMessage); + +/* deletes the mime message that is the body of this part */ +int mime_messagePart_deleteMessage (mime_messagePart_t * in_pMessagePart); + +/* Sets the passed message as body of this message-part. It is error to set message + when it is already set. */ +int mime_messagePart_setMessage (mime_messagePart_t * in_pMessagePart, + mime_message_t * in_pMessage); + +/* Writes out byte stream for this part to the output stream */ +int mime_messagePart_putByteStream (mime_messagePart_t * in_pMessagePart, + nsmail_outputstream_t *in_pOutput_stream); + +/* Frees up the message-part and all internal structures. User should set in_pMessagePart = NULL up on return*/ +int mime_messagePart_free_all (mime_messagePart_t * in_pMessagePart); + +/*============================== MESSAGE ===================================*/ + +/* Creates a message given text-data and a file to attach. */ +/* The file-name supplied must be fully-qualified file-name. */ +/* If either in_pText or in_pFileFullName are NULL creates a */ +/* MIME message with the non-NULL one. It is an error to pass */ +/* NULL for both text and file-name parameters. */ +/* If in_pref_file_encoding > 0 attempts to use the encoding */ +/* for the file-attachment. If encoding is not valid for the */ +/* file-type overrides with the correct value. */ +/* Returns MIME_OK on success and an error code otherwise. */ +/* */ +/* Copies the data in in_pText. User responsible for freeing */ +/* in_pText up on return as needed. in_pFileFullName can also */ +/* be free'd up on return. */ +int mime_message_create (char * in_pText, + char * in_pFileFullName, + mime_encoding_type in_pref_file_encoding, + mime_message_t ** out_ppMessage); + +/* Adds a basic part as the body of the message. */ +/* Error if Body is already present. */ +/* Sets content-type accordingly. */ +int mime_message_addBasicPart (mime_message_t * in_pMessage, + mime_basicPart_t * in_pBasicPart, + BOOLEAN in_fClone); + +/* Adds the message part as the body of the message. */ +/* Error if Body is already present. */ +/* Sets content-type accordingly. */ +int mime_message_addMessagePart (mime_message_t * in_pMessage, + mime_messagePart_t * in_pMessagePart, + BOOLEAN in_fClone); + +/* Adds the multipart as the body of the message */ +/* Error if Body is already present. */ +/* Sets content-type accordingly. */ +int mime_message_addMultiPart (mime_message_t * in_pMessage, + mime_multiPart_t * in_pMultiPart, + BOOLEAN in_fClone); + +/* Deletes the bodyPart that constitutes the body of this message */ +int mime_message_deleteBody (mime_message_t * pMessage); + +/* returns the content_type of this message */ +int mime_message_getContentType (mime_message_t * in_pMessage, + mime_content_type * out_content_type); + +/* returns the content_subtype of this message */ +int mime_message_getContentSubType (mime_message_t * in_pMessage, + char ** out_ppSubType); + +/* returns the content_type params of this message */ +int mime_message_getContentTypeParams (mime_message_t * in_pMessage, + char ** out_ppParams); + +/* gets the value of the specified header.*/ +int mime_message_getHeader (mime_message_t * in_pMessage, + char * in_pName, + char ** out_ppValue); + + +/* Returns the body part at the specified index */ +/* Client to free the returned body-part. See: */ +/* mime_basicPart_free_all() */ +/* mime_multiPart_free_all() and */ +/* mime_messagePart_free_all() */ +int mime_message_getBody (mime_message_t * pMessage, + mime_content_type * out_pContentType, + void ** out_ppTheBodyPart /* Client to cast this based on pContentType */ + ); + +/* Writes out byte stream for this part to the output stream */ +int mime_message_putByteStream (mime_message_t * in_pMessage, + nsmail_outputstream_t *in_pOutput_stream); + +/* Frees up the message and all internal structures. User should set in_pMessage = NULL up on return*/ +int mime_message_free_all (mime_message_t * in_pMessage); + + +/*************************************************************************/ +/** UTILITY ROUTINES */ +/*************************************************************************/ + +/* Builds and returns a mime_header given name and value */ +/* Returns NULL if either name or value is a NULL */ +mime_header_t * mime_header_new (char * in_pName, char * in_pValue); + +/* Frees a mime_header_t structure. User should set in_pHdr = NULL up on return */ +int mime_header_free (mime_header_t * in_pHdr); + +/* Encode a header string per RFC 2047. The encoded string can be used as the + value of unstructured headers or in the comments section of structured headers. + Below, encoding must be one of 'Q' or 'B' */ +int mime_encodeHeaderString (char * in_pString, + char * in_charset, /* charset the input string is in */ + char in_encoding, + char ** out_ppString); + +/* If the input string is not encoded (per RFC 2047), returns the same. + Otherwise, decodes and returns the decoded string */ +int mime_decodeHeaderString (char * in_pString, + char ** out_ppString); + +/* Base64 encodes the data from input_stream and writes to output_stream */ +int mime_encodeBase64 (nsmail_inputstream_t * in_pInput_stream, + nsmail_outputstream_t * in_pOutput_stream); + +/* QuotedPrintable encodes the data from input_stream and writes to output_stream */ +int mime_encodeQP (nsmail_inputstream_t * in_pInput_stream, + nsmail_outputstream_t * in_pOutput_stream); + +/* Base64 decodes the data from input_stream and writes to output_stream */ +int mime_decodeBase64 (nsmail_inputstream_t * in_pInput_stream, + nsmail_outputstream_t * in_pOutput_stream); + +/* QuotedPrintable decodes the data from input_stream and writes to output_stream */ +int mime_decodeQP (nsmail_inputstream_t * in_pInput_stream, + nsmail_outputstream_t * in_pOutput_stream); + +/* Returns file's MIME type info based on file's extension. */ +/* By default returns application/octet-stream. */ +/* If filename_ext is null returns application/octet-stream.*/ +int getFileMIMEType (char * in_pFilename_ext, file_mime_type * in_pFileMIMEType); + +/* Allocates memory of specified size. Recommended to be used instead of + malloc() for memory allocated to use with mime API. Avoids heap space + conflicts when the application links with two or more libraries that + support malloc / free. Internally simply invokes malloc() and hence the + simantics and usage are identical to malloc(). */ +void * mime_malloc (unsigned int in_size); + +/* To be used for freeing any memory allocated by the sdk. + Example: Data buffer returned by mime_basicPart_getDataBuf(). + Another example: Memory allocated using mime_malloc(). + Internally simply invokes free() and hence the simantics and + usage are identical to free().*/ +void mime_memfree (void * in_pMem); + + +#ifdef __cplusplus +} +#endif + + +#endif /* MIME_H */ diff --git a/msgsdk/C/protocol/MIME/include/mime_internal.h b/msgsdk/C/protocol/MIME/include/mime_internal.h new file mode 100644 index 000000000000..71b902ded60b --- /dev/null +++ b/msgsdk/C/protocol/MIME/include/mime_internal.h @@ -0,0 +1,231 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +/**** mime_internal.h ****/ + +#ifndef MIME_INTERNAL_H +#define MIME_INTERNAL_H + +#include "nsmail.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MIME_INFO 1 +#define MIME_HEADER 2 +#define MIME_XHEADER 3 +#define MIME_MESSAGE_DATA 4 +#define MIME_PARAM 5 +#define MIME_BOUNDARY 6 +#define MIME_CRLF 7 + +#define MIME_MESSAGE 20 +#define MIME_BASICPART MIME_CONTENT_TEXT +#define MIME_MULTIPART MIME_CONTENT_MULTIPART +#define MIME_MESSAGEPART MIME_CONTENT_MESSAGEPART +#define MIME_PARSE_ALL 30 +#define MIME_MP_MAX_PARTS 50 /* Max 50 parts in a multi-part */ +#define BUFFER_INCREMENT 1024 /* buffer increases by this when it runs out of space */ + + + +/* used by parser to store general message information */ +typedef struct mimeInfo +{ + int nType; /* mimeInfo type */ + int nContentType; /* current message content type */ + char *szName; /* name */ + char *szValue; /* value */ + Vector *pVectorParam; /* extra parameters */ + +} mimeInfo_t; + + +typedef struct mime_mp_partInfo +{ + mime_content_type nContentType; /* content type of the part */ + char *contentID; /* content ID */ + void *pThePart; /* pointer to actual part */ + +} mime_mp_partInfo_t; + + +typedef struct mime_basicPart_internal +{ + nsmail_inputstream_t *pTheDataStream; /* pointer to bodydata STREAM! */ + char *szMessageBody; /* message body data */ + long nMessageSize; /* size of decoded message body data */ + long nRawMessageSize; /* size of raw message body data */ + int nStartMessageDataIndex; /* start of message vector index */ + int nEndMessageDataIndex; /* end of message vector index */ + BOOLEAN bDecodedData; /* TRUE if data has been decoded */ + int nDynamicBufferSize; /* dynamic buffer size, only 4 callbacks */ + void *pUserObject; /* user object */ + +} mime_basicPart_internal_t; + + +typedef struct mime_multiPart_internal +{ + int nPartCount; + mime_mp_partInfo_t partInfo [MIME_MP_MAX_PARTS]; + char *szBoundary; + void *pUserObject; + BOOLEAN fParsedPart; + +} mime_multiPart_internal_t; + + +typedef struct mime_messagePart_internal +{ + struct mime_message *pTheMessage; + void *pUserObject; + +} mime_messagePart_internal_t; + + +typedef struct mime_message_internal +{ + mime_basicPart_t *pMimeBasicPart; + mime_multiPart_t *pMimeMultiPart; + mime_messagePart_t *pMimeMessagePart; + + /* callback support */ + void *pUserObject; /* user object */ + struct mimeDataSink *pDataSink; /* user's datasink. NULL if not using dynamic parsing */ + +} mime_message_internal_t; + + + +/* ---------------- BasicPart ---------------- */ +struct mime_basicPart * mime_basicPart_new(); +int mime_basicPart_free (struct mime_basicPart *p); +struct mime_basicPart * mime_basicPart_clone (struct mime_basicPart *p); + +mime_basicPart_internal_t * mime_basicPart_internal_new(); +int mime_basicPart_internal_free (mime_basicPart_internal_t *p); +mime_basicPart_internal_t * mime_basicPart_internal_clone (mime_basicPart_internal_t *p); + + +/* ---------------- Multi-part ---------------- */ +struct mime_multiPart * mime_multiPart_new(); +int mime_multiPart_free (struct mime_multiPart *p); +struct mime_multiPart * mime_multiPart_clone (struct mime_multiPart *p); + +int mime_multiPart_addPart (struct mime_multiPart *pMultiPart, + void *pMessage, + mime_content_type nContentType, + int *index_assigned ); + +int mime_multiPart_addPart_clonable( struct mime_multiPart *pMultiPart, + void * pMessage, + mime_content_type nContentType, + BOOLEAN clone, + int * pIndex_assigned); + +int mime_multiPart_getPart2 (struct mime_multiPart *pMultiPart, + int index, + char *contentID, + mime_content_type *pContentType, + void **ppTheBodyPart ); + +mime_multiPart_internal_t * mime_multiPart_internal_new(); +int mime_multiPart_internal_free (mime_multiPart_internal_t *p); +mime_multiPart_internal_t * mime_multiPart_internal_clone (mime_multiPart_internal_t *p); + + +/* ---------------- MessagePart ---------------- */ +struct mime_messagePart * mime_messagePart_new(); +int mime_messagePart_free (struct mime_messagePart *p); +struct mime_messagePart * mime_messagePart_clone (struct mime_messagePart *p); +BOOLEAN mime_messagePart_isEmpty (struct mime_messagePart *pMessage); + +mime_messagePart_internal_t * mime_messagePart_internal_new(); +int mime_messagePart_internal_free (mime_messagePart_internal_t *p); +mime_messagePart_internal_t * mime_messagePart_internal_clone (mime_messagePart_internal_t *p); + + +/* ---------------- Message ---------------- */ +mime_message_internal_t * mime_message_internal_new(); +int mime_message_internal_free (mime_message_internal_t *p); +mime_message_internal_t * mime_message_internal_clone (mime_message_internal_t *p); + + +/* common constructor for both regular and dynamic parsing versions + * pass in a NULL parameter means regular parsing + * pass in a proper datasink to turn on dynamic parsing + */ +mime_message_t * mime_message_new (struct mimeDataSink *pDataSink); +int mime_message_free (struct mime_message *p); +struct mime_message * mime_message_clone (struct mime_message *p ); +int mime_message_addBasicPart_clonable (struct mime_message * pMessage, + struct mime_basicPart * pBasicPart, + BOOLEAN clone ); +int mime_message_addMultiPart_clonable (struct mime_message * pMessage, + struct mime_multiPart * pMultiPart, + BOOLEAN clone ); +int mime_message_addMessagePart_clonable (struct mime_message * pMessage, + struct mime_messagePart * pMessagePart, + BOOLEAN clone ); +BOOLEAN mime_message_isEmpty (struct mime_message *pMessage); + + +/* ---------------- Header ---------------- */ +/*struct mime_header * mime_header_new (char *szName, char *szValue); */ +int mime_header_add (struct mime_header *pStart, char *szName, char *szValue); +int mime_header_apend( mime_header_t *pStart, char *szName, char *szValue ); +/*int mime_header_free (struct mime_header *p); */ +int mime_header_freeAll (struct mime_header *pStart); +struct mime_header * mime_header_clone (struct mime_header *pMimeHeader); + + + +/* -------------- Generic -------------- */ +int mime_getStructType (void *pStruct); + +void * mime_clone_any_part (void * pThePart, mime_content_type nContentType); + +int mime_translateMimeInfo (char *name, char *value); +int mime_translateMimeEncodingType (char *s); +int mime_translateDispType (char *s, char **ppParam); + +struct mimeInfo *mimeInfo_new(); +int mimeInfo_free (struct mimeInfo *p); +int mimeInfo_init (struct mimeInfo *p, int nType1, char *szName1); +int mimeInfo_init2 (struct mimeInfo *p, int nType1, char *szName1, char *szValue1); +struct mimeInfo *mimeInfo_clone (struct mimeInfo *p); + + + +#ifdef __cplusplus +} +#endif + + +#endif /* MIME_INTERNAL_H */ diff --git a/msgsdk/C/protocol/MIME/include/mimeparser.h b/msgsdk/C/protocol/MIME/include/mimeparser.h new file mode 100644 index 000000000000..a5ba35a1a943 --- /dev/null +++ b/msgsdk/C/protocol/MIME/include/mimeparser.h @@ -0,0 +1,132 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + +/* +* mimeparser.h +* carsonl, jan 8,97 +* +*/ + +#ifndef MIMEPARSER_H +#define MIMEPARSER_H + +#include "nsmail.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ---------------------------------------------- mimeDataSink ------------------------------------------- */ + +/* forward declaration */ +struct mime_basicPart; +struct mime_multiPart; +struct mime_messagePart; +struct mime_message; + +/* Forward declaration of the MIME data sink. */ +typedef struct mimeDataSink * mimeDataSinkPtr_t; + + +typedef struct mimeDataSink +{ + /* Client data Opaque to the API. allocated / freed and managed by the client*/ + void * pOpaqueData; + + void (*header)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char *name, char *value ); /* mime headers */ + void (*addHeader)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char *name, char *value); /* additional header value */ + void (*endMessageHeader)(mimeDataSinkPtr_t pSink, void *pCallbackObject); /* end of message hdrs */ + void (*contentType)(mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentType ); /* content type */ + void (*contentSubType)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentSubType );/* content sub type */ + void (*contentTypeParams)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentTypeParams );/* content type parameters */ + void (*contentID)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentID ); /* content ID */ + void (*contentMD5)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentMD5 ); /* content MD5 */ + void (*contentDisposition)(mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentDisposition ); /* content disposition */ + void (*contentDispParams)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentDispParams ); /* content disposition parameters */ + void (*contentDescription)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentDescription );/* content description */ + void (*contentEncoding)(mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentEncoding ); /* content encoding */ + void *(*startMessage)(mimeDataSinkPtr_t pSink); /* signal start of message */ + void (*endMessage)(mimeDataSinkPtr_t pSink, void *pCallbackObject ); /* signal end of message */ + + void *(*startBasicPart)(mimeDataSinkPtr_t pSink); /* signal start of basicpart */ + void (*bodyData)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char bodyData[], int len ); /* message data */ + void (*endBasicPart)(mimeDataSinkPtr_t pSink, void *pCallbackObject ); /* signal end of basicpart */ + + void *(*startMultiPart)(mimeDataSinkPtr_t pSink); /* signal start of multipart */ + void (*boundary)(mimeDataSinkPtr_t pSink, void *pCallbackObject, char * boundary ); /**/ + void (*endMultiPart)(mimeDataSinkPtr_t pSink, void *pCallbackObject ); /* signal end of multipart */ + + void *(*startMessagePart)(mimeDataSinkPtr_t pSink); /* signal start of messagepart */ + void (*endMessagePart)(mimeDataSinkPtr_t pSink, void *pCallbackObject ); /* signal end of messagepart */ + +} mimeDataSink_t; + + + +int mimeDataSink_new (mimeDataSink_t ** out_ppDataSink); /* constructor */ +void mimeDataSink_free (mimeDataSink_t ** in_ppDataSink); /* destructor */ + + +/* ---------------------------------------------- mimeParser ------------------------------------------- */ + + +struct mimeParser; + +/* constructor */ +int mimeDynamicParser_new (mimeDataSink_t * in_pDataSink, + struct mimeParser ** out_ppParser); + +/* destructor */ +void mimeDynamicParser_free (struct mimeParser ** in_ppParser); + +/* begin parsing new message */ +int beginDynamicParse (struct mimeParser * in_pParser); + +/* parse more data (given as an input-stream) */ +int dynamicParseInputstream (struct mimeParser * in_pParser, + struct nsmail_inputstream *in_pInput); + +/* parse more data (given as a data-buffer) */ +int dynamicParse (struct mimeParser * in_pParser, char * in_pData, int in_nLen); + +/* Tell the parser no more data to parse */ +int endDynamicParse (struct mimeParser * in_pParser); + +/* Parse an entire message in one shot. Data given as an input-stream */ +int parseEntireMessageInputstream (struct nsmail_inputstream * in_pInput, + struct mime_message ** out_ppMimeMessage); + +/* Parse an entire message in one shot. Data given as data-buffer */ +int parseEntireMessage (char * in_pData, int in_nLen, + struct mime_message ** in_ppMimeMessage); + + +#ifdef __cplusplus +} +#endif + + +#endif /* MIMEPARSER_H */ diff --git a/msgsdk/C/protocol/MIME/include/mimeparser_internal.h b/msgsdk/C/protocol/MIME/include/mimeparser_internal.h new file mode 100644 index 000000000000..92e6fe5d56a1 --- /dev/null +++ b/msgsdk/C/protocol/MIME/include/mimeparser_internal.h @@ -0,0 +1,167 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +/* +* mimeparser_internal.h +* carsonl, jan 8,97 +* +*/ + +#ifndef MIMEPARSER_INTERNAL_H +#define MIMEPARSER_INTERNAL_H + +#include "nsmail.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef XP_UNIX +#define BOOLEAN int +#define FALSE 0 +#define TRUE 1 +#endif + + +#define MAX_MULTIPART 40 /* maximum number of multipart per message */ +#define START_BOUNDARY 11 /* start of boundary */ +#define END_BOUNDARY 21 /* end of boundary */ +#define NOT_A_BOUNDARY 31 /* not a boundary */ +#define UNINITIALIZED -1 /* uninitialized */ /* don't modify */ +#define BUFFER_SIZE 1024 /* base64 buffer size */ +#define SUBTYPE_RFC822 1 +#define SUBTYPE_EXTERNAL_BODY 2 + + + +typedef struct currentParent +{ + int type; + void *p; + +} currentParent_t; + + + +typedef struct mimeParser +{ + /* parser related */ + Vector *pVectorMimeInfo; /* mimeInfo, preparse storage */ + Vector *pVectorMessageData; /* message data */ + int bStartData; /* TRUE if next line is message data */ + + /* api related */ + mime_content_type nMessageType; /* message type for entire message */ + mime_content_type nCurrentMessageType; /* for current message */ + void *pCurrentMessage; /* current message structure */ + mime_message_t *pMimeMessage; /* mimeMessage structure where all data will reside */ + BOOLEAN bDeleteMimeMessage; /* FALSE if you want the data to persist outside the parser */ + int nEmptyLineNo; /* number of consecutive blank lines */ + + /* callback fields */ + mimeDataSink_t *pDataSink; /* user's datasink, NULL for no callbacks */ + char *pLeftoverBuffer; /* base64 left over buffer */ + char *pInputBuffer; /* base64 input buffer */ + int nLeftoverBytes; /* base64 left over bytes */ + int out_byte; /* base64 output byte */ + int out_bits; /* base64 output bits */ + BOOLEAN bParseEntireFile; /* TRUE to parse entire file, which means no dynamic parsing, */ + /* data is treated as the entire mimeMessage each time it's parsed */ + int nLineType; /* line type */ + + int QPNoOfLeftOverBytes; /* number of lefted over QP bytes */ + char achQPLeftOverBytes[4]; /* lefted over QP bytes */ + + currentParent_t aCurrentParent[MAX_MULTIPART]; /* current message parent */ + int nCurrentParent; /* current parent index */ + mime_message_t *pCurrentMimeMessage; /* current mime message */ + + BOOLEAN bDecodeData; /* TRUE to turn on decoding before sending it to user */ + BOOLEAN bLocalStorage; /* TRUE to let parser manage storage */ + + mime_message_t *pNextMimeMessage; + int nLastBoundry; + Vector *pMimeInfoQueue; + Vector *pHeaderQueue; + BOOLEAN bQPEncoding; + BOOLEAN bReadCR; + currentParent_t tHeaderParent; + currentParent_t tNextHeaderParent; + void *szPreviousHeaderName; + int nMessagePartSubType; + BOOLEAN fSeenBoundary; + BOOLEAN fEndMessageHeader; + +} mimeParser_t; + + + +/* ------------------- internal routines ---------------------- */ + +mimeParser_t *mimeParser_new_internal(); /* internal constructor */ +mimeParser_t *mimeParser_new_internal2( mime_message_t * pMimeMessage ); /* internal constructor */ +int mimeParser_checkForLineType( mimeParser_t *pp, char *s, int len ); /* check for line type */ +int mimeParser_parseLine( mimeParser_t *pp, char *s, int len, BOOLEAN lastLine ); /* parse a line */ + +int mimeParser_parseMimeInfo( mimeParser_t *pp, mimeInfo_t *pmi ); /* parse mimeInfo structure */ +mime_content_type mimeParser_nGetContentType( char *s, char *szSubtype, char **ppParam ); /* get content type */ +char *mimeParser_parseForBoundary( char *s ); /* parse a line for boundary */ +int nNewMessageStructure( mimeParser_t *p, char *s ); /* create a new message structure */ +int nAddMessage( mimeParser_t *p, void *pMessage, mime_content_type nContentType ); /* add a new message */ + +int mimeParser_setData( mimeParser_t *p, mimeInfo_t *pMimeInfo ); /* extra data from mimeInfo structure and set fields */ +int mimeParser_parseMimeMessage( mimeParser_t *p, nsmail_inputstream_t *pInput, char *pData, int nLen, int nContentType, void **ppReturn ); /* core parser routine */ +void decodeDataBuffer( mimeParser_t *p ); /* decode message data */ +char *mimeParser_getCurrentBoundary( mimeParser_t *p ); /* get current boundary */ +int mimeParser_bIsStartBoundary( mimeParser_t *p, char *s ); /* TRUE if current line is a starting boundary */ + +int mimeParser_nBoundaryCheck( mimeParser_t *p, char *s, int len ); /* type of boundary */ +void setUserObject( void *pMessage, int nType, void *pUserObject ); /* set user object */ +void *getUserObject( void *pMessage, int nType ); /* get user object */ +void *getUserObject2 ( void *pMessage, int nType ); /* get user object version 2 */ +BOOLEAN IsLocalStorage( mimeParser_t *p ); /* TRUE for local storage, default to TRUE for non callbacks */ +BOOLEAN IsDecodeData( mimeParser_t *p ); /* TRUE to decode message data, default to TRUE */ + +void saveBodyData( mimeParser_t *p, char *pBuffer, int nLen, mime_basicPart_t *pMimeBasicPart ); /* save body data to message structure */ +char *decodeBase64LeftOverBytes( int out_bits, int out_byte, int *pLen ); /* base64, leftover decoding */ + +int nGetCurrentParentType( mimeParser_t *p ); +void *pGetCurrentParent( mimeParser_t *p ); +void vAddCurrentParent( mimeParser_t *p, int nType, void *pParent ); +void mimeParser_unwindCurrentBoundary( mimeParser_t *p, char *s, BOOLEAN bDelete ); + +void addHeader( mimeParser_t *p, char *name, char *value, BOOLEAN addToQueue ); +BOOLEAN checkForEmptyMessages( mimeParser_t *p, void *pMessage, int type ); +int setCurrentMessage( mimeParser_t *p, void *pMessage, int nMessageType ); + + +#ifdef __cplusplus +} +#endif + + +#endif /* MIMEPARSER_INTERNAL_H */ diff --git a/msgsdk/C/protocol/MIME/include/nsmail_inputstream.h b/msgsdk/C/protocol/MIME/include/nsmail_inputstream.h new file mode 100644 index 000000000000..e0001fb314ed --- /dev/null +++ b/msgsdk/C/protocol/MIME/include/nsmail_inputstream.h @@ -0,0 +1,72 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + +/* +* nsmail_inputstream.h +* prasad jan 8,98 +* +* basic inputstream implementation for file i/o +*/ + +#ifndef NSMAIL_INPUTSTREAM_H +#define NSMAIL_INPUTSTREAM_H + +#include "nsmail.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* carson's additions -------------------------------------- */ + + +typedef struct fileRock /* my custom rock for persisting to a file */ +{ + char *filename; + FILE *f; + char *buffer; + int offset; + +} fileRock_t; + + + +int fileRock_new( char *filename, fileRock_t **ppRock ); /* constructor */ +void fileRock_free( fileRock_t **ppRock ); /* destructor */ +int fileRock_read( void *pRock, char *buf, unsigned size ); /* read */ +void fileRock_rewind( void *pRock ); /* rewind */ +void fileRock_close( void *pRock ); /* close */ + +int nsmail_inputstream_new( char *filename, nsmail_inputstream_t **ppInput ); /* constructor */ +void nsmail_inputstream_free( nsmail_inputstream_t **ppInput ); /* destructor */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* NSMAIL_INPUTSTREAM_H */ diff --git a/msgsdk/C/protocol/MIME/include/util.h b/msgsdk/C/protocol/MIME/include/util.h new file mode 100644 index 000000000000..c84b363e6152 --- /dev/null +++ b/msgsdk/C/protocol/MIME/include/util.h @@ -0,0 +1,157 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + +/* +* util.h +* prasad +* carsonl, oct 10,97 +*/ + +#ifndef UTIL_H +#define UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define null NULL +#define TRUE 1 +#define FALSE 0 +#define LOG_FILE "error.log" +#define BASE64_NOFIT -1 +#define BASE64_SOMELEFT -2 + + + +/* log structure */ +typedef struct errorLog +{ + FILE *m_pFile; /* file pointer */ + char m_achFilename[128]; /* log filename */ + BOOLEAN m_bActive; /* TRUE if you want output to log file */ + +} errorLog_t; + + +typedef struct buf_instream_tracker +{ + char * pDataBuf; /* data buffer */ + long total_size; /* totoal buffer size */ + long bytes_read; /* number of bytes read */ + char * pNext; + +} buf_instream_tracker_t; + + +typedef struct file_instream_tracker +{ + FILE * fp; + char * file_name; + long bytes_read; + +} file_instream_tracker_t; + +typedef struct file_outstream_tracker +{ + FILE * fp; + char * file_name; + long bytes_written; + +} file_outstream_tracker_t; + + + +/* string utilities */ +int bStringEquals( char *s1, char *s2 ); /* equals */ +char *szTrim( char *s ); /* all trim */ +char *szRTrim( char *s ); /* right trim */ +char *szLTrim( char *s ); /* left trim */ +char *szStringClone( char *s ); /* clone */ +BOOLEAN bIsBasicPart( int nType ); /* test if type is a basicpart */ + + +/* base64 utilities */ +int decodeBase64 (char *szInput, char *szOutput, + int nInputBufferSize, int nMaxBufferSize, + int *pOut_byte, int *pOut_bits); + +int decodeBase64Vector (int nStart, int nEnd, Vector *v, + char **szDecodedBuffer, int nRawMessageSize, + int *pOut_byte, int *pOut_bits ); + +/* quoted printable utilities */ +int decodeQP (char *szInput, char *szOutput, int nMaxBufferSize); +int decodeQPVector (int nStart, int nEnd, Vector *v, + char **szDecodedBuffer, int nRawMessageSize, char *szLeftOverBytes, + int *nNoOfLeftOverBytes); + +/* misc */ +char *decodeHeader (char *szInputString); +int nConvertHexToDec (int nFirstByte, int nSecondByte); +char * generateBoundary(); +int append_str (char * dest, char * src); + +/* If s1 equals s2, returns TRUE, FALSE otherwise. */ +BOOLEAN equalsIgnoreCase (char * s1, char * s2); + +char * getFileExtn (char * fileName); +char * getFileShortName (char * fileName); + +/* inputstream utilities */ +long get_inputstream_size (struct nsmail_inputstream * pTheStream); +int buf_instream_create (char * pDataBuf, long data_size, + struct nsmail_inputstream ** ppRetInputStream); +int buf_instream_read (void * rock, char *buf, int size); +void buf_instream_rewind (void * rock); +void buf_instream_close (void * rock); + +int file_instream_create (char * fileName, struct nsmail_inputstream ** ppRetInputStream); +void file_instream_close (void * rock); +void file_instream_rewind (void * rock); +int file_instream_read (void * rock, char *buf, int size); + +int file_outstream_create (char * fileName, nsmail_outputstream_t ** ppRetOutputStream); +void file_outstream_close (void * rock); + + +/* log utilities */ +errorLog_t *errorLog_new( char *szFilename ); /* constructor */ +void errorLog_free( errorLog_t *pLog ); /* destructor, calls closeLog() automatically */ +void initErrorLog( char *szFilename ); /* init */ +void closeErrorLog(); /* close log */ +void errorLog (char *szOwner, int nError); /* report error to log */ +void errorLog2 (errorLog_t *pLog, char *szOwner, int nError); /* report error to log */ +void errorLogMsg( char *szMsg ); /* display custom error message */ +void errorLogMsg2 (errorLog_t *pLog, char *szMsg); /* display custom error message */ +void errorLogOn(); /* turn log on */ +void errorLogOff(); /* turn log off */ + +#ifdef __cplusplus +} +#endif + + +#endif /* UTIL_H */ diff --git a/msgsdk/C/protocol/MIME/include/vector.h b/msgsdk/C/protocol/MIME/include/vector.h new file mode 100644 index 000000000000..420598c6a0e4 --- /dev/null +++ b/msgsdk/C/protocol/MIME/include/vector.h @@ -0,0 +1,72 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + +/* vector.h +* +* carsonl, oct 1,97 +*/ + +#ifndef VECTOR_H +#define VECTOR_H + +#include "nsmail.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define INITIAL_SIZE 16 +#define VECTOR_TYPE_STRING 1 +#define VECTOR_TYPE_MIMEINFO 2 + + +/* private */ +typedef struct Vector +{ + int nMaxSize; /* max size */ + int nSize; /* current size */ + int nType; /* content type */ + void **pt; /* pointer to object */ + +} Vector; + + +Vector *Vector_new( int nType1 ); +int Vector_free( Vector *v ); +int Vector_size( Vector *v ); +int Vector_addElement( Vector *v, void *pObject, int nObjectSize ); +void *Vector_elementAt( Vector *v, int nIndex ); +Vector *Vector_clone( Vector *v ); +int Vector_deleteAll( Vector *v ); +void *Vector_deleteLastElement (Vector *v); +void *Vector_popLastElement (Vector *v); + + +#ifdef __cplusplus +} +#endif + + +#endif /* VECTOR_H */ diff --git a/msgsdk/C/protocol/MIME/src/Makefile b/msgsdk/C/protocol/MIME/src/Makefile new file mode 100644 index 000000000000..458b0deb829d --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/Makefile @@ -0,0 +1,76 @@ + +# GNU Makefile for MIME +# + +MSGSDK_ROOT = ../../../../C +CONFIG_ROOT = ../../../../CONFIG +BUILD_ROOT = ../../../../C +MKDIR = mkdir -p + +LIBDIR = $(OBJDIR)/lib +OBJDEST = $(LIBDIR)/libmime +LIBNAME = libmime + +include $(CONFIG_ROOT)/msgsdk.mk + +LOCAL_INCDIR = ../include +GLOBAL_INCDIR = ../../../include +CFLAGS += -I$(LOCAL_INCDIR) -I$(GLOBAL_INCDIR) + +ifeq ($(ARCH), AIX) +LIBNAME = libmime +DLL_SUFFIX = a +endif + + +# +# Build full target library file and path +# +ifeq ($(ARCH), AIX) +LIBTARGET = $(addsuffix _shr.a, \ + $(addprefix $(LIBDIR)/, $(LIBNAME))) +else +LIBTARGET = $(addsuffix .$(DLL_SUFFIX), \ + $(addprefix $(LIBDIR)/, $(LIBNAME))) +endif + +MIME_OBJS= mime.o mime_internal.o mimeparser.o util.o vector.o mimeDataSink.o + +OBJS = $(addprefix $(OBJDEST)/, $(MIME_OBJS)) + +all: $(OBJDEST) $(LIBDIR) $(LIBTARGET) + +clean: + rm -rf $(OBJDEST)* + rm -rf $(OBJDEST)/* + +$(LIBDIR): + echo creating $(LIBDIR) + $(MKDIR) $(LIBDIR) + +$(OBJDEST): + echo creating $(OBJDEST) + $(MKDIR) $(OBJDEST) + +ifeq ($(ARCH), WINNT) +$(LIBTARGET): $(OBJS) + $(PURIFY) $(LINK_DLL) /DEF:mime.def $(OBJS) +else +ifeq ($(ARCH), AIX) +$(LIBTARGET): $(OBJS) + $(LD) -o $(LIBTARGET) $(OBJS) $(DLL_LDFLAGS) -bE:mime.exp -lc_r +else +ifeq ($(ARCH), IRIX) +$(LIBTARGET): $(OBJS) + $(LD) $(DLL_LDFLAGS) -exports_file mime.exp -soname $(LIBNAME).so -o $(LIBTARGET) $(OBJS) +else +ifeq ($(ARCH), IRIX64) +$(LIBTARGET): $(OBJS) + $(LD) $(DLL_LDFLAGS) -exports_file mime.exp -soname $(LIBNAME).so -o $(LIBTARGET) $(OBJS) +else +$(LIBTARGET): $(OBJS) + $(LD) $(DLL_LDFLAGS) -o $(LIBTARGET) $(OBJS) +endif +endif +endif +endif diff --git a/msgsdk/C/protocol/MIME/src/mime.c b/msgsdk/C/protocol/MIME/src/mime.c new file mode 100644 index 000000000000..e91fafddf4e1 --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/mime.c @@ -0,0 +1,4353 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + +/* mime.c +* +* prasad, Jan 98 +* carsonl, Jan 98 +* +*/ + +#include +#include +#include +#include + +#include "nsmail.h" +#include "vector.h" +#include "util.h" +#include "mime.h" +#include "mime_internal.h" +#include "mimeparser.h" +#include "mimeparser_internal.h" + +static BOOLEAN fNeedPreamble = FALSE; +static BOOLEAN fStartedStream = FALSE; +#define MIME_ENCODING_NOTSET 0 + + +#ifdef DEBUG +#define outmsg(x) (fprintf(stderr,"%s:%d>%s\n",__FILE__,__LINE__,x)) +#else +#define outmsg(x) +#endif + + +static char base64map [] = +{/* 0 1 2 3 4 5 6 7 */ + 'A','B','C','D','E','F','G','H', /* 0 */ + 'I','J','K','L','M','N','O','P', /* 1 */ + 'Q','R','S','T','U','V','W','X', /* 2 */ + 'Y','Z','a','b','c','d','e','f', /* 3 */ + 'g','h','i','j','k','l','m','n', /* 4 */ + 'o','p','q','r','s','t','u','v', /* 5 */ + 'w','x','y','z','0','1','2','3', /* 6 */ + '4','5','6','7','8','9','+','/' /* 7 */ +}; + + +static char hexmap [] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +char * dupDataBuf (char * buf, int size) +{ + char * newbuf; + + newbuf = (char *) malloc (size+1); + if (newbuf == NULL) + return NULL; + + memset (newbuf, 0, size+1); + /*strncpy (newbuf, buf, size);*/ + memcpy (newbuf, buf, size); + return newbuf; +} + + +/* -------------------------------------------- */ + + +void freeFMT (file_mime_type * pFMT) +{ + free (pFMT->content_subtype); + free (pFMT->content_params); +} + + +void freeParts (mime_basicPart_t * pBp1, mime_basicPart_t * pBp2, + mime_multiPart_t * pMP, mime_message_t *pMsg) +{ + if (pBp1 != NULL) + mime_basicPart_free_all (pBp1); + + if (pBp2 != NULL) + mime_basicPart_free_all (pBp2); + + if (pMP != NULL) + mime_multiPart_free_all (pMP); + + if (pMsg != NULL) + mime_message_free_all (pMsg); +} + +/* +* Prasad, jan 8,98 +* Set the body-data for this part from an input stream. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_setDataStream (mime_basicPart_t * pBasicPart, + nsmail_inputstream_t *pTheDataStream, + BOOLEAN fCopyData) +{ + mime_basicPart_internal_t *pBasicPartInternal=NULL; + char * pLocalBuf=NULL, * pDest=NULL; + long stream_size=0, total_read = 0; + int bytes_read = 0; + + if (pBasicPart == NULL || pTheDataStream == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pBasicPart->pInternal == NULL) + pBasicPart->pInternal = (void *) mime_basicPart_internal_new(); + + pBasicPartInternal = (mime_basicPart_internal_t *) pBasicPart->pInternal; + + if (pBasicPartInternal->szMessageBody != NULL || pBasicPartInternal->pTheDataStream != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + stream_size = get_inputstream_size (pTheDataStream); + + if (stream_size <= 0) + { + return MIME_ERR_IO_READ; + } + + + if (fCopyData == FALSE) + { + /* save ref to the stream */ + pBasicPartInternal->pTheDataStream = pTheDataStream; + pBasicPartInternal->nMessageSize = stream_size; + return MIME_OK; + } + + pLocalBuf = (char *) malloc (stream_size + 1); + + if (pLocalBuf == NULL) + return MIME_ERR_OUTOFMEMORY; + + pDest = pLocalBuf; + + while (total_read <= stream_size) + { + bytes_read = pTheDataStream->read (pTheDataStream->rock, pDest, MIME_BUFSIZE); + + if (bytes_read <= 0) + { + break; + } + else + { + total_read += bytes_read; + pDest += bytes_read; + } + } /* while */ + + if (total_read <= 0) + { + free (pLocalBuf); + + return MIME_ERR_IO_READ; + } + + pBasicPartInternal->szMessageBody = (char *) pLocalBuf; + pBasicPartInternal->nMessageSize = total_read; + + return MIME_OK; + +} /* mime_basicPart_setDataStream */ + + + +/* +* Prasad, jan 8,98 +* Set the body-data for this part from a buffer. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_setDataBuf (mime_basicPart_t * pBasicPart, + unsigned int size, + const char * pDataBuf, + BOOLEAN fCopyData) +{ + mime_basicPart_internal_t * pBasicPartInternal=NULL; + char * pLocalBuf=NULL; + + if ( pBasicPart == NULL || pDataBuf == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if (size == 0) + { + return MIME_ERR_INVALIDPARAM; + } + + if (size > strlen (pDataBuf)) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pBasicPart->pInternal == NULL) + pBasicPart->pInternal = (void *) mime_basicPart_internal_new(); + + pBasicPartInternal = (mime_basicPart_internal_t *) pBasicPart->pInternal; + + if (pBasicPartInternal->szMessageBody != NULL || pBasicPartInternal->pTheDataStream != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + if (fCopyData == FALSE) + { + pBasicPartInternal->szMessageBody = (char *) pDataBuf; + pBasicPartInternal->nMessageSize = size; + return MIME_OK; + } + + /* Copy the data. The user might FREE pDataBuf */ + + pLocalBuf = (char *) malloc (size); + /*bcopy (pDataBuf, pLocalBuf, size);*/ + memcpy (pLocalBuf, pDataBuf, size); + pBasicPartInternal->szMessageBody = (char *) pLocalBuf; + pBasicPartInternal->nMessageSize = size; + + return MIME_OK; +} + + + + +/* +* Prasad, jan 8,98 +* Deletes the bodyData for this part. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_deleteData (mime_basicPart_t * pBasicPart) +{ + mime_basicPart_internal_t *pBasicPartInternal=NULL; + + if (pBasicPart == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pBasicPartInternal = (mime_basicPart_internal_t *) pBasicPart->pInternal; + + if (pBasicPartInternal != NULL && pBasicPartInternal->szMessageBody != NULL) + { + free (pBasicPartInternal->szMessageBody); + pBasicPartInternal->szMessageBody = NULL; + pBasicPartInternal->nMessageSize = 0; + + return MIME_OK; + } + + if (pBasicPartInternal != NULL && pBasicPartInternal->pTheDataStream != NULL) + { + pBasicPartInternal->pTheDataStream = NULL; + pBasicPartInternal->nMessageSize = 0; + return MIME_OK; + } + + /* Delete with no Data O.K. */ + + return MIME_OK; +} + + + +/* +* gives the size of the body-data in bytes +* +* parameter : +* +* pBasicPart : basicPart +* pSize : (output) size of message data +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_getSize (mime_basicPart_t * pBasicPart, unsigned int * pSize) +{ + mime_basicPart_internal_t *pBasicPartInternal=NULL; + + if ( pBasicPart == NULL || pSize == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + pBasicPartInternal = (mime_basicPart_internal_t *) pBasicPart->pInternal; + + if ( pBasicPartInternal != NULL ) + { + *pSize = pBasicPartInternal->nMessageSize; + + return MIME_OK; + } + else + { + return 0; + } +} + + + +/* +* Prasad, jan 8,98 +* returns the body-data after any decoding in an input stream +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_getDataStream (mime_basicPart_t * pBasicPart, + char * pFileName, + nsmail_inputstream_t ** ppDataStream) +{ + char * pLocalBuf=NULL; + mime_basicPart_internal_t * pBasicPartInternal=NULL; + FILE * fp; + char * pDest=NULL; + nsmail_inputstream_t * pDataStream=NULL; + int bytes_read=0, total_read=0, stream_size=0; + + if (pBasicPart == NULL || ppDataStream == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pBasicPartInternal = (mime_basicPart_internal_t *) pBasicPart->pInternal; + + if (pBasicPartInternal != NULL && pBasicPartInternal->szMessageBody != NULL) + { + + if (pFileName == NULL) + { + pLocalBuf = dupDataBuf (pBasicPartInternal->szMessageBody, + pBasicPartInternal->nMessageSize); + + return buf_instream_create (pLocalBuf, + pBasicPartInternal->nMessageSize, + ppDataStream); + } + else + { + /* Return the specified file-based input-stream */ + if ((fp = fopen(pFileName, "wb")) == (FILE *) NULL) + { + return MIME_ERR_CANTOPENFILE; + + } + + fwrite (pBasicPartInternal->szMessageBody, sizeof (char), pBasicPartInternal->nMessageSize, fp); + + fclose (fp); + free (pLocalBuf); + pLocalBuf = NULL; + + return file_instream_create (pFileName, + ppDataStream); + } + } + else if (pBasicPartInternal != NULL && pBasicPartInternal->pTheDataStream != NULL) + { + pDataStream = pBasicPartInternal->pTheDataStream; + stream_size = pBasicPartInternal->nMessageSize; + + if (pFileName != NULL) + { + /* Return the specified file-based input-stream */ + if ((fp = fopen(pFileName, "wb")) == (FILE *) NULL) + { + return MIME_ERR_CANTOPENFILE; + } + + pLocalBuf = (char *) malloc (MIME_BUFSIZE); + memset (pLocalBuf, 0, MIME_BUFSIZE); + + while (total_read <= stream_size) + { + + bytes_read = pDataStream->read (pDataStream->rock, + pLocalBuf, MIME_BUFSIZE); + + if (bytes_read <= 0) + { + break; + } + else + { + total_read += bytes_read; + fwrite (pLocalBuf, sizeof (char), bytes_read, fp); + memset (pLocalBuf, 0, MIME_BUFSIZE); + } + } + + if (total_read <= 0) + { + fclose (fp); + free (pLocalBuf); + pLocalBuf = NULL; + return MIME_ERR_IO_READ; + } + + fclose (fp); + free (pLocalBuf); + pLocalBuf = NULL; + + return file_instream_create (pFileName, + ppDataStream); + + } + else + { + /* Return a buf-based input-stream */ + + pLocalBuf = (char *) malloc (stream_size +1); + memset (pLocalBuf, 0, stream_size+1); + + if (pLocalBuf == NULL) + return MIME_ERR_OUTOFMEMORY; + + pDest = pLocalBuf; + pDataStream->rewind (pDataStream->rock); + + while (total_read <= stream_size) + { + bytes_read = pDataStream->read (pDataStream->rock, + pDest, MIME_BUFSIZE); + + if (bytes_read <= 0) + { + break; + } + else + { + total_read += bytes_read; + pDest += bytes_read; + } + } /* while */ + + if (total_read <= 0) + { + free (pLocalBuf); + pLocalBuf = NULL; + return MIME_ERR_IO_READ; + } + + pDest[ stream_size ] = NULL; + + return buf_instream_create (pLocalBuf, + stream_size, + ppDataStream); + + } +/* + * *ppDataStream = pBasicPartInternal->pTheDataStream; + * (*ppDataStream)->rewind ((*ppDataStream)->rock); + * return MIME_OK; + */ + } + + return MIME_ERR_NO_DATA; + +} /* mime_basicPart_getDataStream() */ + + + +/* +* Prasad, jan 8,98 +* returns the body-data after any decoding in a buffer +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_getDataBuf (mime_basicPart_t * pBasicPart, + unsigned int * pSize, + char **ppDataBuf ) +{ + mime_basicPart_internal_t * pBasicPartInternal=NULL; + nsmail_inputstream_t * pDataStream=NULL; + char * pDest=NULL; + int bytes_read=0, total_read=0, stream_size=0; + + if (pBasicPart == NULL || pSize == NULL || ppDataBuf == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pBasicPartInternal = (mime_basicPart_internal_t *) pBasicPart->pInternal; + + if (pBasicPartInternal != NULL && pBasicPartInternal->szMessageBody != NULL) + { + *pSize = pBasicPartInternal->nMessageSize; + /* *ppDataBuf = szStringClone( pBasicPartInternal->szMessageBody );*/ + /**ppDataBuf = strdup (pBasicPartInternal->szMessageBody);*/ + *ppDataBuf = dupDataBuf (pBasicPartInternal->szMessageBody, + pBasicPartInternal->nMessageSize); + if (*ppDataBuf == NULL) + return MIME_ERR_OUTOFMEMORY; + + return MIME_OK; + } + else if (pBasicPartInternal != NULL && pBasicPartInternal->pTheDataStream != NULL) + { + pDataStream = pBasicPartInternal->pTheDataStream; + stream_size = pBasicPartInternal->nMessageSize; + + *ppDataBuf = (char *) malloc (stream_size +1); + + if (*ppDataBuf == NULL) + return MIME_ERR_OUTOFMEMORY; + + pDest = *ppDataBuf; + pDataStream->rewind (pDataStream->rock); + + while (total_read <= stream_size) + { + bytes_read = pDataStream->read (pDataStream->rock, + pDest, MIME_BUFSIZE); + + if (bytes_read <= 0) + { + break; + } + else + { + total_read += bytes_read; + pDest += bytes_read; + } + } /* while */ + + if (total_read <= 0) + { + free (*ppDataBuf); + *ppDataBuf = NULL; + return MIME_ERR_IO_READ; + } + + pDest[ stream_size ] = NULL; + + return MIME_OK; + } + else + { + return MIME_ERR_NO_DATA; + } + +} /* mime_basicPart_getDataBuf */ + + + +/* +* Prasad, jan 8,98 +* Writes out byte stream for this part with MIME headers and encoded body-data +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_putByteStream (mime_basicPart_t * pBasicPart, + nsmail_outputstream_t *pOutput_stream) +{ + mime_basicPart_internal_t *pBasicPartInternal=NULL; + static char * hdrbuf = NULL; + char * pHdr = NULL; + mime_header_t * pEHdr = NULL; + int len=0, ret=0, read_len=0; + mime_encoding_type encoding; + nsmail_inputstream_t * pInput_stream = NULL; + BOOLEAN fDatainBuf = FALSE, fWroteVersion = FALSE; + + outmsg("Entered mime_basicPart_putByteStream()"); + + if (pBasicPart == NULL || pOutput_stream == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pBasicPartInternal = (mime_basicPart_internal_t *) pBasicPart->pInternal; + + if (pBasicPartInternal == NULL || (pBasicPartInternal->szMessageBody == NULL + && pBasicPartInternal->pTheDataStream == NULL)) + { + return MIME_ERR_NO_BODY; + } + + if (pBasicPartInternal->szMessageBody != NULL) + { + outmsg("fDatainBuf = TRUE"); + fDatainBuf = TRUE; + } + + /* Write out the headers first */ + + if (hdrbuf==NULL) + { + hdrbuf = (char *) malloc (MIME_BUFSIZE); + + if (hdrbuf == NULL) + return MIME_ERR_NO_BODY; + } + + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + outmsg("Writing out content_type/sub-type; params!"); + + /* Content-Type */ + switch (pBasicPart->content_type) + { + + case MIME_CONTENT_TEXT: + len = append_str (pHdr, "Content-Type: text/"); + pHdr += len; + + if (pBasicPart->content_subtype != NULL) + { + len = append_str (pHdr, pBasicPart->content_subtype); + pHdr += len; + } + else + { + len = append_str (pHdr, "plain"); + pHdr += len; + } + + if (pBasicPart->content_type_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pBasicPart->content_type_params); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + else + { +#if (0) /* removed */ + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, "charset=us-ascii\r\n"); +#endif + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + break; + + case MIME_CONTENT_AUDIO: + len = append_str (pHdr, "Content-Type: audio/"); + pHdr += len; + + if (pBasicPart->content_subtype != NULL) + { + len = append_str (pHdr, pBasicPart->content_subtype); + pHdr += len; + } + else + { + /*l_hdrbuf.append ("basic"); */ + return MIME_ERR_NO_CONTENT_SUBTYPE; + } + + if (pBasicPart->content_type_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pBasicPart->content_type_params); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + else + { + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + break; + + case MIME_CONTENT_IMAGE: + len = append_str (pHdr, "Content-Type: image/"); + pHdr += len; + + if (pBasicPart->content_subtype != NULL) + { + len = append_str (pHdr, pBasicPart->content_subtype); + pHdr += len; + } + else + { + /*l_hdrbuf.append ("jpeg"); */ + return MIME_ERR_NO_CONTENT_SUBTYPE; + } + + if (pBasicPart->content_type_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pBasicPart->content_type_params); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + else + { + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + break; + + case MIME_CONTENT_VIDEO: + len = append_str (pHdr, "Content-Type: video/"); + pHdr += len; + + if (pBasicPart->content_subtype != NULL) + { + len = append_str (pHdr, pBasicPart->content_subtype); + pHdr += len; + } + else + { + /*l_hdrbuf.append ("mpeg"); */ + return MIME_ERR_NO_CONTENT_SUBTYPE; + } + + if (pBasicPart->content_type_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pBasicPart->content_type_params); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + else + { + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + break; + + case MIME_CONTENT_APPLICATION: + len = append_str (pHdr, "Content-Type: application/"); + pHdr += len; + + if (pBasicPart->content_subtype != NULL) + { + len = append_str (pHdr, pBasicPart->content_subtype); + pHdr += len; + } + else + { + len = append_str (pHdr, "octet-stream"); + pHdr += len; + } + + if (pBasicPart->content_type_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pBasicPart->content_type_params); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + else + { + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + break; + + case MIME_CONTENT_MULTIPART: + case MIME_CONTENT_MESSAGEPART: + + default: + return MIME_ERR_INVALID_CONTENTTYPE; + } + + /* write out content-type */ + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + outmsg("DONE Writing out content_type/sub-type; params!"); + + /* contentID */ + if (pBasicPart->contentID != NULL) + { + len = append_str (pHdr, "Content-ID: "); + pHdr += len; + len = append_str (pHdr, pBasicPart->contentID); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* contentMD5 */ + if (pBasicPart->contentMD5 != NULL) + { + len = append_str (pHdr, "Content-MD5: "); + pHdr += len; + len = append_str (pHdr, pBasicPart->contentMD5); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* contentDisposition */ + if (pBasicPart->content_disposition != MIME_DISPOSITION_UNINITIALIZED && pBasicPart->content_disposition > 0) + { + fprintf (stderr, "Disp = %d\n", pBasicPart->content_disposition); + len = append_str (pHdr, "Content-Disposition: "); + pHdr += len; + + switch (pBasicPart->content_disposition) + { + case MIME_DISPOSITION_INLINE: + len = append_str (pHdr, "inline"); + pHdr += len; + break; + case MIME_DISPOSITION_ATTACHMENT: + len = append_str (pHdr, "attachment"); + pHdr += len; + break; + } + + if (pBasicPart->content_disp_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pBasicPart->content_disp_params); + pHdr += len; + } + + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* content-Description */ + if (pBasicPart->content_description != NULL) + { + len = append_str (pHdr, "Content-Description: "); + pHdr += len; + len = append_str (pHdr, pBasicPart->content_description); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + outmsg("Writing out content-Transfer-Encoding"); + + /* content-transfer-encoding */ + if (pBasicPart->encoding_type != MIME_ENCODING_UNINITIALIZED && pBasicPart->encoding_type != MIME_ENCODING_NOTSET) + { + switch (pBasicPart->encoding_type) + { + case MIME_ENCODING_BASE64: + encoding = MIME_ENCODING_BASE64; + len = append_str (pHdr, "Content-Transfer-Encoding: base64\r\n"); + pHdr += len; + break; + case MIME_ENCODING_QP: + encoding = MIME_ENCODING_QP; + len = append_str (pHdr, "Content-Transfer-Encoding: quoted-printable\r\n"); + pHdr += len; + break; + case MIME_ENCODING_7BIT: + encoding = MIME_ENCODING_7BIT; + len = append_str (pHdr, "Content-Transfer-Encoding: 7bit\r\n"); + pHdr += len; + break; + case MIME_ENCODING_8BIT: + encoding = MIME_ENCODING_8BIT; + len = append_str (pHdr, "Content-Transfer-Encoding: 8bit\r\n"); + pHdr += len; + break; + case MIME_ENCODING_BINARY: + encoding = MIME_ENCODING_BINARY; + len = append_str (pHdr, "Content-Transfer-Encoding: binary\r\n"); + pHdr += len; + break; +#if (0) + case MIME_ENCODING_UNINITIALIZED: + if (pBasicPart->content_type == MIME_CONTENT_TEXT) + { + encoding = MIME_ENCODING_7BIT; + len = append_str (pHdr, "Content-Transfer-Encoding: 7bit\r\n"); + pHdr += len; +#ifdef XP_UNIX + if ((strlen (pBasicPart->content_type_params) == 8) && + (strncasecmp (pBasicPart->content_type_params, "us-ascii", 8) == 0)) +#else + if ((strlen (pBasicPart->content_type_params) == 8) && + bStringEquals (pBasicPart->content_type_params, "us-ascii")) +#endif + { + encoding = MIME_ENCODING_7BIT; + len = append_str (pHdr, "Content-Transfer-Encoding: 7bit\r\n"); + pHdr += len; + } + else + { + encoding = MIME_ENCODING_BASE64; + len = append_str (pHdr, "Content-Transfer-Encoding: base64\r\n"); + pHdr += len; + } + } + else + { + encoding = MIME_ENCODING_BASE64; + len = append_str (pHdr, "Content-Transfer-Encoding: base64\r\n"); + pHdr += len; + } + break; +#endif + default: + return MIME_ERR_INVALID_ENCODING; + } /* switch */ + + /* write-out encoding line */ + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + outmsg("DONE Writing out content-Transfer-Encoding"); + } + else + encoding = MIME_ENCODING_7BIT; /* for use with writing body-data only */ + + + fWroteVersion = FALSE; + /* Write-out all the additional headers if any */ + if (pBasicPart->extra_headers != NULL) + { + for (pEHdr = pBasicPart->extra_headers; + pEHdr != NULL; + /*pEHdr != NULL, pEHdr->name != NULL, pEHdr->value != NULL; */ + pEHdr = pEHdr->next) + { + if (pEHdr->name != NULL && pEHdr->value != NULL) + { + if (bStringEquals (pEHdr->name, "MIME-Version")) + { + if (fWroteVersion) + continue; + else + fWroteVersion = TRUE; + } + len = append_str (pHdr, pEHdr->name); + pHdr += len; + len = append_str (pHdr, ": "); + pHdr += len; + len = append_str (pHdr, pEHdr->value); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + + } + + pHdr = hdrbuf; + } /* for */ + } /* end extra hdrs */ + + /* extra line after headers */ + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + outmsg("DONE Writing out Header"); + + if (fDatainBuf == TRUE) + { + outmsg("Doing buf_instream_create()"); + + ret = buf_instream_create (pBasicPartInternal->szMessageBody, + pBasicPartInternal->nMessageSize, + &pInput_stream); + if (ret != MIME_OK) + return ret; + } + else + { + pInput_stream = pBasicPartInternal->pTheDataStream; + pInput_stream->rewind (pInput_stream->rock); + } + + if (pInput_stream == NULL) + { + return MIME_ERR_UNEXPECTED; + } + + switch (encoding) + { + case MIME_ENCODING_BASE64: + outmsg("Invoking mime_encodeBase64()"); + + ret = mime_encodeBase64 (pInput_stream, pOutput_stream); + if (ret < 0) + return ret; + break; + + case MIME_ENCODING_QP: + outmsg("Invoking mime_encodeQP()"); + + ret = mime_encodeQP (pInput_stream, pOutput_stream); + if (ret < 0) + return ret; + break; + + case MIME_ENCODING_7BIT: + case MIME_ENCODING_8BIT: + case MIME_ENCODING_BINARY: + case MIME_ENCODING_NOTSET: + + outmsg("No encoding!"); + + read_len = pInput_stream->read (pInput_stream->rock, hdrbuf, MIME_BUFSIZE); + + while (read_len > 0) + { + outmsg("Writing data out"); +#ifdef DEBUG + fprintf (stderr, "read_len=%d\n", read_len); +#endif + pOutput_stream->write (pOutput_stream->rock, hdrbuf, read_len); + + read_len = pInput_stream->read (pInput_stream->rock, hdrbuf, MIME_BUFSIZE); + } + break; + + default: +#ifdef DEBUG + errorLog( "mime_basicPart_putByteStream()", MIME_ERR_INVALID_ENCODING ); +#endif + + return MIME_ERR_INVALID_ENCODING; + } + +#if (0) + /* final touch */ + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + len = append_str (pHdr, "\r\n\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); +#endif + + return MIME_OK; + +} /* mime_basicPart_putByteStream() */ + + + +/* +* Frees up all parts of the basic part including internal structures. +* +* parameter : +* +* pBasicPart : basicPart +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_free_all (mime_basicPart_t * pBasicPart) +{ + if ( pBasicPart == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + return mime_basicPart_free( pBasicPart ); +} + + + + +/*************************************************************************/ +/** COMPOSITE BODY PART TYPES **/ +/*************************************************************************/ + + +/*=========================== MULTI PART =================================*/ + + +/* +* creates a multi part from an input stream. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +/* + * int mime_multiPart_create (nsmail_inputstream_t *pInput_stream, + * mime_multiPart_t ** ppMultiPart) + * { + * if ( pInput_stream == NULL || ppMultiPart == NULL ) + * { + * errorLog( "mime_multiPart_create()", MIME_ERR_INVALIDPARAM ); + * return MIME_ERR_INVALIDPARAM; + * } + * + * return mime_multiPart_decode( pInput_stream, ppMultiPart); + * } + */ + + +/* +* Prasad, Jan 98 +* Adds a file as basic part to the multi-part. +* If in_pref_file_encoding > 0 attempts to use the encoding +* for the file-attachment. If encoding is not valid for the +* file-type overrides with the correct value. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_addFile (mime_multiPart_t * pMultiPart, + char * pFileFullName, + mime_encoding_type pref_file_encoding, + int * pIndex_assigned) +{ + nsmail_inputstream_t * pInput_stream = NULL; + mime_basicPart_t * pFilePart = NULL; + file_mime_type fmt; + char * extn = NULL, *short_file_name = NULL; + int ret = 0, idx = 0; + + if (pMultiPart == NULL) + { + return MIME_ERR_INVALID_MULTIPART; + } + + if (pFileFullName == NULL || pIndex_assigned == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pFileFullName != NULL) + { + outmsg("Creating File Part"); + + extn = getFileExtn (pFileFullName); + + ret = getFileMIMEType (extn, &fmt); + + if (pref_file_encoding > 0 && pref_file_encoding <= MIME_ENCODING_BINARY) + { + if (fmt.mime_encoding != MIME_ENCODING_BASE64) + fmt.mime_encoding = pref_file_encoding; + + } + + /* Create and return a Message from file */ + pFilePart = (mime_basicPart_t *) malloc (sizeof (mime_basicPart_t)); + + if (pFilePart == NULL) + { + free (extn); + freeFMT (&fmt); + return MIME_ERR_OUTOFMEMORY; + } + else memset (pFilePart, 0, sizeof (mime_basicPart_t)); + + ret = file_instream_create (pFileFullName, &pInput_stream); + + if (ret != MIME_OK) + { + free (extn); + freeFMT (&fmt); + freeParts (NULL, pFilePart, NULL, NULL); + free (pFilePart); + return ret; + } + + pFilePart->content_type = fmt.content_type; + pFilePart->content_subtype = fmt.content_subtype; + pFilePart->content_type_params = fmt.content_params; + pFilePart->encoding_type = fmt.mime_encoding; + + short_file_name = getFileShortName (pFileFullName); + if (short_file_name != NULL) + pFilePart->content_description = short_file_name; + + /* Set to FALSE below if performance becomes a factor!!! */ + ret = mime_basicPart_setDataStream (pFilePart, pInput_stream, TRUE); + + if (ret != MIME_OK) + { + pInput_stream->close (pInput_stream->rock); + free (pInput_stream); + free (extn); + freeFMT (&fmt); + + freeParts (NULL, pFilePart, NULL, NULL); + free (pFilePart); + return ret; + } + + outmsg ("adding basic part to multi-part"); + + ret = mime_multiPart_addBasicPart (pMultiPart, pFilePart, FALSE, &idx); + +#ifdef DEBUG + fprintf (stderr, "Index assigned = %d\n", idx); +#endif + + if (ret != MIME_OK) + { + if (pInput_stream != NULL) + pInput_stream->close (pInput_stream->rock); + free (pInput_stream); + free (extn); + freeFMT (&fmt); + freeParts (NULL, pFilePart, NULL, NULL); + free (pFilePart); + return ret; + } + + *pIndex_assigned = idx; + + return MIME_OK; + } + +} +/*=============*/ + + +/* +* Prasad, jan 8,98 +* Adds a basic part to the multi-part. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_addBasicPart (mime_multiPart_t * pMultiPart, + mime_basicPart_t * pBasicPart, + BOOLEAN clone, + int * pIndex_assigned) +{ + if (pMultiPart == NULL) + { + return MIME_ERR_INVALID_MULTIPART; + } + + if (pBasicPart == NULL) + { + return MIME_ERR_INVALID_BASICPART; + } + + if (pIndex_assigned == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pBasicPart->content_type <= MIME_CONTENT_UNINITIALIZED) + { + return MIME_ERR_INVALID_CONTENTTYPE; + } + + return mime_multiPart_addPart_clonable (pMultiPart, (void *) pBasicPart, + pBasicPart->content_type, clone, pIndex_assigned); +} + + + + +/* +* Prasad, jan 8,98 +* Adds a message part to the multi-part. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_addMessagePart (mime_multiPart_t * pMultiPart, + mime_messagePart_t * pMessagePart, + BOOLEAN clone, + int * pIndex_assigned) +{ + if (pMultiPart == NULL) + { + return MIME_ERR_INVALID_MULTIPART; + } + + if (pMessagePart == NULL || pIndex_assigned == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + return mime_multiPart_addPart_clonable (pMultiPart, (void *) pMessagePart, + MIME_CONTENT_MESSAGEPART, clone, pIndex_assigned); +} + + + + +/* +* Prasad, jan 8,98 +* Adds a message part to the multi-part. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_addMultiPart (mime_multiPart_t * pMultiPart, + mime_multiPart_t * pMultiPart2, + BOOLEAN clone, + int * pIndex_assigned) +{ + if (pMultiPart == NULL || pMultiPart2 == NULL) + { + return MIME_ERR_INVALID_MULTIPART; + } + + if (pIndex_assigned == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + return mime_multiPart_addPart_clonable (pMultiPart, (void *) pMultiPart2, + MIME_CONTENT_MULTIPART, clone, pIndex_assigned); +} + + + +/* +* Prasad, jan 8,98 +* Deletes the bodyPart at the requested index from this multi-part +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_deletePart (mime_multiPart_t * pMultiPart, + int index) +{ + int partCount=0, i=0; + mime_mp_partInfo_t * pPartInfo=NULL; + mime_mp_partInfo_t * pNextPartInfo=NULL; + mime_multiPart_internal_t * pMultiPartInternal=NULL; + + if (pMultiPart == NULL) + { + return MIME_ERR_INVALID_MULTIPART; + } + + if (index <= 0) + { + return MIME_ERR_INVALID_INDEX; + } + + pMultiPartInternal = (mime_multiPart_internal_t *) pMultiPart->pInternal; + + if (pMultiPartInternal == NULL) + { + return MIME_ERR_UNINITIALIZED; + } + + partCount = pMultiPartInternal->nPartCount; + + if (partCount < index) + { + return MIME_ERR_INVALID_INDEX; + } + + pPartInfo = &pMultiPartInternal->partInfo [index]; + + switch (pPartInfo->nContentType) + { + case MIME_CONTENT_TEXT: + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + mime_basicPart_free ((mime_basicPart_t *) pPartInfo->pThePart); + break; + case MIME_CONTENT_MULTIPART: + mime_multiPart_free ((mime_multiPart_t *) pPartInfo->pThePart); + break; + case MIME_CONTENT_MESSAGEPART: + mime_messagePart_free ((mime_messagePart_t *) pPartInfo->pThePart); + break; + default: + return MIME_ERR_UNEXPECTED; + } /* switch */ + + pPartInfo->pThePart = NULL; + + if (pPartInfo->contentID != NULL) + { + free (pPartInfo->contentID); + pPartInfo->contentID = NULL; + } + + /* update links */ + if (index < partCount) + { + for (i=index+1; i <= partCount; i++) + { + + pPartInfo = &pMultiPartInternal->partInfo [i-1]; + pNextPartInfo = &pMultiPartInternal->partInfo [i]; + + pPartInfo->nContentType = pNextPartInfo->nContentType; + pPartInfo->contentID = pNextPartInfo->contentID; + pPartInfo->pThePart = pNextPartInfo->pThePart; + } + } + + pPartInfo = &pMultiPartInternal->partInfo [partCount]; + pPartInfo->nContentType = MIME_CONTENT_UNINITIALIZED; + pPartInfo->contentID = NULL; + pPartInfo->pThePart = NULL; + + partCount--; + + return MIME_OK; +} + + + +/* +* returns the count of the body parts in this multi-part +* +* parameter : +* +* pMultiPart : multiPart +* pCount : (output) number of parts +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_getPartCount (mime_multiPart_t * pMultiPart, + int * pCount) +{ + mime_multiPart_internal_t * pMultiPartInternal=NULL; + + if (pMultiPart == NULL || pCount == NULL) + { + return MIME_ERR_INVALID_MULTIPART; + } + + pMultiPartInternal = (mime_multiPart_internal_t *) pMultiPart->pInternal; + + if (pMultiPartInternal != NULL) + { + *pCount = pMultiPartInternal->nPartCount; + + return MIME_OK; + } + + return MIME_ERR_UNINITIALIZED; +} + + + +/* +* returns the body part at the specified index +* index always starts with 1 +* +* parameter : +* +* pMultiPart : multiPart +* index : which part within the multipart +* pContentType : (output) content type of part returned +* pptheBodyPart : (output) part returned +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_getPart (mime_multiPart_t * pMultiPart, + int index, + mime_content_type *pContentType, + void **ppTheBodyPart /* Client can cast this based on pContentType */ + ) +{ + if (pMultiPart == NULL || pContentType == NULL || ppTheBodyPart == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + return mime_multiPart_getPart2 (pMultiPart, index, NULL, pContentType, ppTheBodyPart); +} + + + +/* +* carsonl, jan 8,98 +* returns the body part with the specified contentID +* +* parameter : +* +* pMultiPart : multiPart +* contentID : content ID +* pContentType : (output) content type of part returned +* pptheBodyPart : (output) part returned, cast this based on pContent_type +* +* returns : MIME_OK if successful +*/ +/* +int mime_multiPart_getCIDPart (mime_multiPart_t * pMultiPart, + char * contentID, + mime_content_type * pContentType, + void **ppTheBodyPart + ) +{ + if (pMultiPart == NULL) + { + errorLog( "mime_multiPart_getCIDPart()", MIME_ERR_INVALID_MULTIPART ); + return MIME_ERR_INVALID_MULTIPART; + } + + if (contentID == NULL || pContentType == NULL || ppTheBodyPart == NULL) + { + errorLog( "mime_multiPart_getCIDPart()", MIME_ERR_INVALIDPARAM ); + return MIME_ERR_INVALIDPARAM; + } + + return mime_multiPart_getPart2 (pMultiPart, -1, contentID, pContentType, ppTheBodyPart); +} +*/ + + +/* +* Small utility routine to output boundary, in other words write the boundary to the outputstream +* +* parameter : +* +* pBoundary : boundary string +* pOutput_stream : output stream +* +* returns : MIME_OK if successful +*/ +static void mime_output_boundary (char * pBoundary, nsmail_outputstream_t *pOutput_stream) +{ + char * pHdr = NULL; + static char * hdrbuf = NULL; + int len=0; + + if (hdrbuf==NULL) + { + hdrbuf = (char *) malloc (100); + if (hdrbuf == NULL) + return; + } + + memset (hdrbuf, 0, 100); + pHdr = hdrbuf; + + /*len = append_str (pHdr, "\r\n\r\n");*/ + len = append_str (pHdr, "\r\n"); + pHdr += len; + len = append_str (pHdr, "--"); + pHdr += len; + len = append_str (pHdr, pBoundary); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf )); +} + + +static void mime_output_trail_boundary (char * pBoundary, nsmail_outputstream_t *pOutput_stream) +{ + static char * hdrbuf = NULL; + char * pHdr = NULL; + int len=0; + + + if (hdrbuf==NULL) + { + hdrbuf = (char *) malloc (100); + if (hdrbuf == NULL) + return; + } + + memset (hdrbuf, 0, 100); + pHdr = hdrbuf; + + /*len = append_str (pHdr, "\r\n\r\n");*/ + len = append_str (pHdr, "\r\n"); + pHdr += len; + len = append_str (pHdr, "--"); + pHdr += len; + len = append_str (pHdr, pBoundary); + pHdr += len; + len = append_str (pHdr, "--"); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); +} + + + +/* +* Prasad, jan 8,98 +* Writes out byte stream for this part with MIME headers and encoded body-data +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_putByteStream (mime_multiPart_t * pMultiPart, + nsmail_outputstream_t *pOutput_stream) +{ + char * pHdr=NULL, * pBoundary=NULL; + mime_header_t * pEHdr=NULL; + int fwriteit = 0, len=0, bpCount=0, idx=0; + static char * hdrbuf=NULL; + mime_multiPart_internal_t * pMultiPartInternal = NULL; + mime_mp_partInfo_t * pPartInfo = NULL; + BOOLEAN fquoteBounds = FALSE; + + mime_basicPart_t * pBasicPart2 = NULL; + mime_multiPart_t * pMultiPart2 = NULL; + mime_messagePart_t * pMessagePart2 = NULL; + + + outmsg("Entered mime_multiPart_putByteStream()"); + + if (pMultiPart == NULL || pOutput_stream == NULL) + { + return MIME_ERR_INVALID_MULTIPART; + } + + pMultiPartInternal = (mime_multiPart_internal_t *) pMultiPart->pInternal; + + if (pMultiPartInternal == NULL) + { + return MIME_ERR_NO_BODY; + } + + bpCount = pMultiPartInternal->nPartCount; + +#ifdef DEBUG + fprintf (stderr, "%s:%d> bpCount = %d\n", __FILE__, __LINE__, bpCount); +#endif + + if (bpCount < 1) + { + return MIME_ERR_NO_BODY; + } + + + if (hdrbuf==NULL) + { + hdrbuf = (char *) malloc (MIME_BUFSIZE); + if (hdrbuf == NULL) + return MIME_ERR_OUTOFMEMORY; + } + + + /* Write the Headers out first */ + + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + /* Content-Type */ + len = append_str (pHdr, "Content-Type: multipart/"); + pHdr += len; + + if (pMultiPart->content_subtype != NULL) + { + len = append_str (pHdr, pMultiPart->content_subtype); + pHdr += len; + } + else + { + return MIME_ERR_NO_CONTENT_SUBTYPE; + } + + if (pMultiPart->content_type_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pMultiPart->content_type_params); + pHdr += len; + } + + if (pMultiPartInternal->szBoundary == NULL) + pBoundary = (char *) generateBoundary(); + else + { + pBoundary = strdup (pMultiPartInternal->szBoundary); + fquoteBounds = TRUE; + } + + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, "boundary="); + pHdr += len; + if (fquoteBounds == TRUE) + *pHdr++ = '"'; + len = append_str (pHdr, pBoundary); + pHdr += len; + if (fquoteBounds == TRUE) + *pHdr++ = '"'; + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /* write out content-type */ + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + /* contentID */ + if (pMultiPart->contentID != NULL) + { + len = append_str (pHdr, "Content-ID: "); + pHdr += len; + len = append_str (pHdr, pMultiPart->contentID); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* contentDisposition */ + if (pMultiPart->content_disposition != MIME_DISPOSITION_UNINITIALIZED && pMultiPart->content_disposition > 0) + { + len = append_str (pHdr, "Content-Disposition: "); + pHdr += len; + + switch (pMultiPart->content_disposition) + { + case MIME_DISPOSITION_INLINE: + len = append_str (pHdr, "inline"); + pHdr += len; + break; + case MIME_DISPOSITION_ATTACHMENT: + len = append_str (pHdr, "attachment"); + pHdr += len; + break; + } + + if (pMultiPart->content_disp_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pMultiPart->content_disp_params); + pHdr += len; + } + + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* content-Description */ + if (pMultiPart->content_description != NULL) + { + len = append_str (pHdr, "Content-Description: "); + pHdr += len; + len = append_str (pHdr, pMultiPart->content_description); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* Should I handle the extra-header? Multi-parts should not have these! */ + /* Write-out all the additional headers if any */ + if (pMultiPart->extra_headers != NULL) + { + for (pEHdr = pMultiPart->extra_headers; + pEHdr != NULL; + /*pEHdr != NULL, pEHdr->name != NULL, pEHdr->value != NULL; */ + pEHdr = pEHdr->next) + { + if (pEHdr->name != NULL && pEHdr->value != NULL) + { + len = append_str (pHdr, pEHdr->name); + pHdr += len; + len = append_str (pHdr, ": "); + pHdr += len; + len = append_str (pHdr, pEHdr->value); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + } + + pHdr = hdrbuf; + + } /* for */ + } /* end extra hdrs */ + + if (fNeedPreamble == TRUE && pMultiPart->encoding_type >= MIME_ENCODING_7BIT) + { + /* write out any content-encoding */ + fwriteit = 0; + switch (pMultiPart->encoding_type) + { + case MIME_ENCODING_7BIT: + len = append_str (pHdr, "Content-Transfer-Encoding: 7bit\r\n"); + pHdr += len; + fwriteit = 1; + break; + case MIME_ENCODING_8BIT: + len = append_str (pHdr, "Content-Transfer-Encoding: 8bit\r\n"); + pHdr += len; + fwriteit = 1; + break; + case MIME_ENCODING_BINARY: + len = append_str (pHdr, "Content-Transfer-Encoding: binary\r\n"); + pHdr += len; + fwriteit = 1; + break; + } /* switch */ + + if (fwriteit) + { + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + } + + /* extra line after headers */ + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + if (pMultiPart->preamble != NULL) + { + /* write it out */ + len = append_str (pHdr, pMultiPart->preamble); + pHdr += len; + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + /* Need to conditionally output Pre-amble here ! */ + else if (fNeedPreamble == TRUE && pMultiPartInternal->fParsedPart == FALSE) + { + fNeedPreamble = FALSE; + + len = append_str (pHdr, "\r\nThis is a multi-part message in MIME format\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* make sure boundary starts on a new line + put the extra -- in the beginning */ + /*mime_output_boundary (pBoundary, pOutput_stream);*/ + + /* For each part in bodyParts, output boundary and call putByteStream passing OS */ + + for (idx = 1; idx <= bpCount; idx++) + { + pPartInfo = &pMultiPartInternal->partInfo [idx]; + + switch (pPartInfo->nContentType) + { + case MIME_CONTENT_TEXT: + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + mime_output_boundary (pBoundary, pOutput_stream); + pBasicPart2 = (mime_basicPart_t *) pPartInfo->pThePart; + mime_basicPart_putByteStream (pBasicPart2, pOutput_stream); + break; + case MIME_CONTENT_MULTIPART: + mime_output_boundary (pBoundary, pOutput_stream); + pMultiPart2 = (mime_multiPart_t *) pPartInfo->pThePart; + mime_multiPart_putByteStream (pMultiPart2, pOutput_stream); + break; + case MIME_CONTENT_MESSAGEPART: + mime_output_boundary (pBoundary, pOutput_stream); + pMessagePart2 = (mime_messagePart_t *) pPartInfo->pThePart; + mime_messagePart_putByteStream (pMessagePart2, pOutput_stream); + break; + + default: + free (pBoundary); + return MIME_ERR_INVALID_CONTENTTYPE; + } /* switch */ + } + + /* Trailing boundary. */ + mime_output_trail_boundary (pBoundary, pOutput_stream); + free (pBoundary); + + return MIME_OK; +} + + + +/* +* Frees up all parts of the multi-part including internal structures. +* +* parameter : +* +* pMultiPart : multipart +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_free_all (mime_multiPart_t * pMultiPart) +{ + if ( pMultiPart == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + return mime_multiPart_free( pMultiPart ); +} + + + +/*=========================== MESSAGE PART =================================*/ + + + +/* +* creates a message part from an input stream. +* +* parameter : +* +* pInput_stream : input stream +* +* returns : MIME_OK if successful +*/ +/* +int mime_messagePart_create (nsmail_inputstream_t *pInput_stream, + mime_messagePart_t ** ppMessagePart) +{ + if ( pInput_stream == NULL || ppMessagePart == NULL ) + { + errorLog( "mime_multiPart_create()", MIME_ERR_INVALIDPARAM ); + return MIME_ERR_INVALIDPARAM; + } + + return mime_messagePart_decode( pInput_stream, ppMessagePart); +} +*/ + + + +/* +* Prasad, jan 8,98 +* creates a message part from a message structure +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_messagePart_fromMessage (mime_message_t * pMessage, + mime_messagePart_t ** ppMessagePart) +{ + mime_messagePart_t * pNewMessagePart=NULL; + mime_messagePart_internal_t * pInternal=NULL; + + if (pMessage == NULL || ppMessagePart == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pNewMessagePart = mime_messagePart_new(); + + if (pNewMessagePart == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + pNewMessagePart->content_type = MIME_CONTENT_MESSAGEPART; + + pInternal = (mime_messagePart_internal_t *) pNewMessagePart->pInternal; + + if (pInternal == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + pInternal->pTheMessage = mime_message_clone (pMessage); + + if (pInternal->pTheMessage == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + *ppMessagePart = pNewMessagePart; + + return MIME_OK; +} + + + +/* +* Prasad, jan 8,98 +* Retrieves the message that constitutes the body of the message part +* from the message part. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_messagePart_getMessage (mime_messagePart_t * pMessagePart, + mime_message_t ** ppMessage) +{ + mime_message_t *pNewMessage=NULL; + mime_messagePart_internal_t *pInternal=NULL; + + if (pMessagePart == NULL || ppMessage == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pInternal = (mime_messagePart_internal_t *) pMessagePart->pInternal; + + if (pInternal == NULL) + { + return MIME_ERR_INVALID_MESSAGEPART; + } + + pNewMessage = mime_message_clone (pInternal->pTheMessage); + + if (pNewMessage == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + *ppMessage = pNewMessage; + + return MIME_OK; +} + + + +/* +* Prasad, jan 8,98 +* deletes the mime message that is the body of this part +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_messagePart_deleteMessage (mime_messagePart_t * pMessagePart) +{ + mime_messagePart_internal_t * pInternal=NULL; + + if (pMessagePart == NULL) + { + return MIME_ERR_INVALID_MESSAGEPART; + } + + pInternal = (mime_messagePart_internal_t *) pMessagePart->pInternal; + + if (pInternal == NULL) + { + return MIME_ERR_UNINITIALIZED; + } + + mime_message_free (pInternal->pTheMessage); + pInternal->pTheMessage = NULL; + + return MIME_OK; +} + + + +/* +* Prasad, jan 8,98 +* Sets the passed message as body of this message-part. +* It is an error to set message when it is already set. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_messagePart_setMessage (mime_messagePart_t * pMessagePart, + mime_message_t * pMessage) +{ + mime_messagePart_internal_t * pInternal=NULL; + + if (pMessagePart == NULL) + { + return MIME_ERR_INVALID_MESSAGEPART; + } + + if (pMessage == NULL) + { + return MIME_ERR_INVALID_MESSAGE; + } + + if (pMessagePart->pInternal == NULL) /* New MessagePart. Allocate internal stuff */ + { + pMessagePart->pInternal = (void *) mime_messagePart_internal_new(); + + if (pMessagePart->pInternal == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + } + + pInternal = (mime_messagePart_internal_t *) pMessagePart->pInternal; + + if (pInternal->pTheMessage != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + pInternal->pTheMessage = mime_message_clone (pMessage); + + if (pInternal->pTheMessage == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + return MIME_OK; +} + + + +/* +* Prasad, jan 8,98 +* Writes out byte stream for this part to the output stream +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_messagePart_putByteStream (mime_messagePart_t * pMessagePart, + nsmail_outputstream_t *pOutput_stream) +{ + int len=0, ret=0; + mime_header_t * pEHdr=NULL; + static char * hdrbuf=NULL; + char * pHdr=NULL; + mime_encoding_type encoding; + mime_messagePart_internal_t * pMsgPartInternal=NULL; + mime_message_t * pMsg=NULL; + BOOLEAN fExternal_body = FALSE, fMsgPartial = FALSE; + BOOLEAN fFirstExternalHeader = TRUE; + + if ( pMessagePart == NULL || pOutput_stream == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + +#ifdef XP_UNIX + if ((pMessagePart->content_subtype != NULL) && (strlen (pMessagePart->content_subtype) == 13) && + (strncasecmp(pMessagePart->content_subtype, "external-body", 13) ==0)) + fExternal_body = TRUE; + else if ((pMessagePart->content_subtype != NULL) && (strlen (pMessagePart->content_subtype) == 7) && + (strncasecmp (pMessagePart->content_subtype, "partial", 7) == 0)) + fMsgPartial = TRUE; +#else + if ((pMessagePart->content_subtype != NULL) && (strlen (pMessagePart->content_subtype) == 13) && + bStringEquals (pMessagePart->content_subtype, "external-body") ) + fExternal_body = TRUE; + else if ((pMessagePart->content_subtype != NULL) && (strlen (pMessagePart->content_subtype) == 7) && + bStringEquals (pMessagePart->content_subtype, "partial") ) + fMsgPartial = TRUE; +#endif + + pMsgPartInternal = (mime_messagePart_internal_t * ) pMessagePart->pInternal; + + if ((pMsgPartInternal == NULL) && fMsgPartial != TRUE && fExternal_body != TRUE) + { + return MIME_ERR_NO_BODY; + + } + + if (pMsgPartInternal != NULL && !fMsgPartial && !fExternal_body) + { + pMsg = (mime_message_t *) pMsgPartInternal->pTheMessage; + + if ((pMsg == NULL) && (fMsgPartial != TRUE)) + { + return MIME_ERR_NO_BODY; + } + } + + + + if (hdrbuf==NULL) + { + hdrbuf = (char *) malloc (MIME_BUFSIZE); + if (hdrbuf == NULL) + return MIME_ERR_OUTOFMEMORY; + } + + /* Write out the headers first */ + + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + /* Content-Type */ + len = append_str (pHdr, "Content-Type: message/"); + pHdr += len; + + if (pMessagePart->content_subtype != NULL) + { + len = append_str (pHdr, pMessagePart->content_subtype); + pHdr += len; + } + else + { + if (pMsg != NULL) + { + len = append_str (pHdr, "rfc822"); /* default */ + pHdr += len; + } + else + { + return MIME_ERR_NO_CONTENT_SUBTYPE; + } + } + + if (pMessagePart->content_type_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pMessagePart->content_type_params); + pHdr += len; + } + + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /* write out content-type */ + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + /* contentID */ + if (pMessagePart->contentID != NULL) + { + len = append_str (pHdr, "Content-ID: "); + pHdr += len; + len = append_str (pHdr, pMessagePart->contentID); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* contentDisposition */ + if (pMessagePart->content_disposition != MIME_DISPOSITION_UNINITIALIZED && pMessagePart->content_disposition > 0) + { + len = append_str (pHdr, "Content-Disposition: "); + pHdr += len; + + switch (pMessagePart->content_disposition) + { + case MIME_DISPOSITION_INLINE: + len = append_str (pHdr, "inline"); + pHdr += len; + break; + case MIME_DISPOSITION_ATTACHMENT: + len = append_str (pHdr, "attachment"); + pHdr += len; + break; + } + + if (pMessagePart->content_disp_params != NULL) + { + len = append_str (pHdr, "; "); + pHdr += len; + len = append_str (pHdr, pMessagePart->content_disp_params); + pHdr += len; + } + + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* content-Description */ + if (pMessagePart->content_description != NULL) + { + len = append_str (pHdr, "Content-Description: "); + pHdr += len; + len = append_str (pHdr, pMessagePart->content_description); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + if (pMessagePart->encoding_type != MIME_ENCODING_UNINITIALIZED) + { + if (pMessagePart->encoding_type == 0) + encoding = MIME_ENCODING_7BIT; + else + encoding = pMessagePart->encoding_type; + + if ((fMsgPartial == TRUE) || (fExternal_body == TRUE)) + encoding = MIME_ENCODING_7BIT; /* As mandated by MIME spec */ + + if ((encoding != MIME_ENCODING_7BIT) && + (encoding != MIME_ENCODING_8BIT) && + (encoding != MIME_ENCODING_BINARY)) + { + return MIME_ERR_INVALID_ENCODING; + } + + /* content-transfer-encoding */ + switch (encoding) + { + case MIME_ENCODING_7BIT: + encoding = MIME_ENCODING_7BIT; + len = append_str (pHdr, "Content-Transfer-Encoding: 7bit\r\n"); + pHdr += len; + break; + case MIME_ENCODING_8BIT: + encoding = MIME_ENCODING_8BIT; + len = append_str (pHdr, "Content-Transfer-Encoding: 8bit\r\n"); + pHdr += len; + break; + case MIME_ENCODING_BINARY: + encoding = MIME_ENCODING_BINARY; + len = append_str (pHdr, "Content-Transfer-Encoding: binary\r\n"); + pHdr += len; + break; + default: + return MIME_ERR_INVALID_ENCODING; + } /* switch */ + + /* write-out encoding line */ + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + /* Write-out all the additional headers if any */ + if (pMessagePart->extra_headers != NULL) + { + for (pEHdr = pMessagePart->extra_headers; + pEHdr != NULL; + /*pEHdr != NULL, pEHdr->name != NULL, pEHdr->value != NULL;*/ + pEHdr = pEHdr->next) + { + + /* + *if (fExternal_body == TRUE) + * fprintf (stderr, "got an extern header: %s:%s\n", pEHdr->name,pEHdr->value); + */ + + if (pEHdr->name != NULL && pEHdr->value != NULL) + { + len = append_str (pHdr, pEHdr->name); + pHdr += len; + len = append_str (pHdr, ": "); + pHdr += len; + len = append_str (pHdr, pEHdr->value); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + } + + pHdr = hdrbuf; + + } /* for */ + } /* end extra hdrs */ + + /* extra line after headers */ + len = append_str (pHdr, "\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + + if (fExternal_body != TRUE) + { + ret = mime_message_putByteStream (pMsg, pOutput_stream); + + if (ret != MIME_OK) + return ret; + } + else if (pMessagePart->extern_headers != NULL) + /* Write-out the extern headers if any */ + { + for (pEHdr = pMessagePart->extern_headers; + pEHdr != NULL; + /*pEHdr != NULL, pEHdr->name != NULL, pEHdr->value != NULL;*/ + pEHdr = pEHdr->next) + { + if (pEHdr->name != NULL && pEHdr->value != NULL) + { + if (fFirstExternalHeader == TRUE) + { + fFirstExternalHeader = FALSE; + len = append_str (pHdr, "\r\n"); + pHdr += len; + } + + len = append_str (pHdr, pEHdr->name); + pHdr += len; + len = append_str (pHdr, ": "); + pHdr += len; + len = append_str (pHdr, pEHdr->value); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + } + pHdr = hdrbuf; + } /* for */ + + } /* end extern hdrs */ + + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + return MIME_OK; +} + + + +/* +* Frees up all parts of the message-part including internal structures. +* +* parameter : +* +* pMessagePart : messagePart +* +* returns : MIME_OK if successful +*/ +int mime_messagePart_free_all (mime_messagePart_t * pMessagePart) +{ + if ( pMessagePart == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + return mime_messagePart_free( pMessagePart ); +} + + + +/*============================== MESSAGE ===================================*/ + + +/* read from inputstream into a mime_message */ +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +/* +int parseMimeMessage( mime_message_t * pMimeMessage, nsmail_inputstream_t *pInput_stream, BOOLEAN bStart, BOOLEAN bEnd ) +{ + struct mime_message_internal *pMimeMessageInternal = NULL; + mimeParser_t *p=NULL; + int nRet = MIME_ERR_OUTOFMEMORY; + + if ( pInput_stream == NULL || pMimeMessage == NULL ) + { + errorLog( "parseMimeMessage()", MIME_ERR_INVALIDPARAM ); + return MIME_ERR_INVALIDPARAM; + } + + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessageInternal != NULL && pMimeMessageInternal->pParser == NULL ) + { + p = mimeParser_new_internal2( pMimeMessage ); + pMimeMessageInternal->pParser = p; + } + + else + { + p = pMimeMessageInternal->pParser; + p->pMimeMessage = pMimeMessage; + } + + if ( p != NULL ) + { + p->bDeleteMimeMessage = FALSE; + nRet = mimeParser_parseMimeMessage( p, pInput_stream, NULL, 0, MIME_PARSE_ALL, NULL ); + } + + if ( bEnd ) + mimeParser_free(p); + + return nRet; +} +*/ + +/* Creates a message given text-data and a file to attach. */ +/* The file-name supplied must be fully-qualified file-name. */ +/* If either in_pText or in_pFileFullName are NULL creates a */ +/* MIME message with the non-NULL one. It is an error to pass */ +/* NULL for both text and file-name parameters. */ +/* If pref_file_encoding > 0 attempts to use the encoding */ +/* for the file-attachment. If encoding is not valid for the */ +/* file-type overrides with the correct value. */ +/* Returns MIME_OK on success and an error code otherwise. */ +/* */ +/* Copies the data in pText. User responsible for free'ing */ +/* pText up on return as needed. pFileFullName can also */ +/* be free'd up on return. */ +int mime_message_create (char * pText, + char * pFileFullName, + mime_encoding_type pref_file_encoding, + mime_message_t ** ppMessage) +{ + nsmail_inputstream_t * pInput_stream = NULL; + mime_multiPart_t * pMultiPart=NULL; + mime_basicPart_t * pTextPart = NULL, * pFilePart = NULL; + mime_message_t * pMessage = NULL; + file_mime_type fmt; + char * extn = NULL, *short_file_name = NULL; + int ret = 0, idx = 0; + BOOLEAN fMultiPart = FALSE; + + + if (pText == NULL && pFileFullName == NULL) + return MIME_ERR_INVALIDPARAM; + + if (pText != NULL && pFileFullName != NULL) + { + outmsg("fMultiPart is TRUE"); + + fMultiPart = TRUE; + } + + if (pText != NULL) + { + outmsg("Creating Text Part"); + + pTextPart = (mime_basicPart_t *) malloc (sizeof (mime_basicPart_t)); + + if (pTextPart == NULL) + return MIME_ERR_OUTOFMEMORY; + else + memset (pTextPart, 0, sizeof (mime_basicPart_t)); + + pTextPart->content_type = MIME_CONTENT_TEXT; + pTextPart->content_subtype = strdup ("plain"); + pTextPart->content_type_params = strdup ("charset=us-ascii"); + pTextPart->encoding_type = MIME_ENCODING_7BIT; + + ret = mime_basicPart_setDataBuf (pTextPart, strlen (pText), pText, TRUE); + + if (ret != MIME_OK) + { +#ifdef DEBUG + fprintf(stderr, "mime_basicPart_setDataBuf failed! ret=%d\n", ret); +#endif + mime_basicPart_free_all (pTextPart); + free (pTextPart); + return ret; + } + } + + + if (pFileFullName != NULL) + { + outmsg("Creating File Part"); + + extn = getFileExtn (pFileFullName); + + ret = getFileMIMEType (extn, &fmt); + + if (pref_file_encoding > 0 && pref_file_encoding <= MIME_ENCODING_BINARY) + { + /*if (fmt.mime_encoding != MIME_ENCODING_BASE64)*/ + fmt.mime_encoding = pref_file_encoding; + + } + + /* Create and return a Message from file */ + pFilePart = (mime_basicPart_t *) malloc (sizeof (mime_basicPart_t)); + + if (pFilePart == NULL) + { + free (extn); + freeFMT (&fmt); + freeParts (pTextPart, NULL, NULL, NULL); + free (pTextPart); + return MIME_ERR_OUTOFMEMORY; + } + else + memset (pFilePart, 0, sizeof (mime_basicPart_t)); + + ret = file_instream_create (pFileFullName, &pInput_stream); + + if (ret != MIME_OK) + { + free (extn); + freeFMT (&fmt); + freeParts (pTextPart, pFilePart, NULL, NULL); + free (pTextPart); + free (pFilePart); + return ret; + } + + pFilePart->content_type = fmt.content_type; + pFilePart->content_subtype = fmt.content_subtype; + pFilePart->content_type_params = fmt.content_params; + pFilePart->encoding_type = fmt.mime_encoding; + + short_file_name = getFileShortName (pFileFullName); + if (short_file_name != NULL) + pFilePart->content_description = short_file_name; + + /* Set to FALSE below if performance becomes a factor!!! */ + ret = mime_basicPart_setDataStream (pFilePart, pInput_stream, TRUE); + + if (ret != MIME_OK) + { + pInput_stream->close (pInput_stream->rock); + free (pInput_stream); + free (extn); + freeFMT (&fmt); + + freeParts (pTextPart, pFilePart, NULL, NULL); + free (pTextPart); + free (pFilePart); + return ret; + } + } + + if (fMultiPart) + { + outmsg("Creating Multi Part"); + + /* Create and return a multi-part Message */ + pMultiPart = (mime_multiPart_t *) malloc (sizeof (mime_multiPart_t)); + + if (pMultiPart == NULL) + return MIME_ERR_OUTOFMEMORY; + else + memset (pMultiPart, 0, sizeof (mime_multiPart_t)); + + pMultiPart->content_subtype = strdup ("mixed"); + + outmsg ("adding basic part to multi-part"); + + ret = mime_multiPart_addBasicPart (pMultiPart, pTextPart, FALSE, &idx); + +#ifdef DEBUG + fprintf (stderr, "Index assigned = %d\n", idx); +#endif + + if (ret != MIME_OK) + { + if (pInput_stream != NULL) + pInput_stream->close (pInput_stream->rock); + free (pInput_stream); + free (extn); + freeFMT (&fmt); + freeParts (pTextPart, pFilePart, pMultiPart, NULL); + free (pTextPart); + free (pFilePart); + free (pMultiPart); + return ret; + } + + outmsg ("adding basic part to multi-part"); + + ret = mime_multiPart_addBasicPart (pMultiPart, pFilePart, FALSE, &idx); + +#ifdef DEBUG + fprintf (stderr, "Index assigned = %d\n", idx); +#endif + + if (ret != MIME_OK) + { + if (pInput_stream != NULL) + pInput_stream->close (pInput_stream->rock); + free (pInput_stream); + free (extn); + freeFMT (&fmt); + freeParts (pTextPart, pFilePart, pMultiPart, NULL); + free (pTextPart); + free (pFilePart); + free (pMultiPart); + return ret; + } + } /* multi-part */ + + outmsg("Creating Message"); + + pMessage = (mime_message_t *) malloc (sizeof (mime_message_t)); + + if (pMessage == NULL) + { + if (pInput_stream != NULL) + pInput_stream->close (pInput_stream->rock); + free (pInput_stream); + free (extn); + freeFMT (&fmt); + freeParts (pTextPart, pFilePart, pMultiPart, NULL); + free (pTextPart); + free (pFilePart); + free (pMultiPart); + return ret; + } + else + memset (pMessage, 0, sizeof (mime_message_t)); + + if (fMultiPart) + { + outmsg("Adding Multi Part to message"); + + ret = mime_message_addMultiPart (pMessage, pMultiPart, FALSE); + } + else if (pText != NULL) + { + outmsg("Adding Text Part to message"); + ret = mime_message_addBasicPart (pMessage, pTextPart, FALSE); + } + else + { + outmsg("Adding Text Part to message"); + ret = mime_message_addBasicPart (pMessage, pFilePart, FALSE); + } + + if (ret != MIME_OK) + { + outmsg("Adding Part to message Failed!"); + + if (pInput_stream != NULL) + pInput_stream->close (pInput_stream->rock); + free (pInput_stream); + free (extn); + freeFMT (&fmt); + freeParts (pTextPart, pFilePart, pMultiPart, NULL); + free (pTextPart); + free (pFilePart); + free (pMultiPart); + free (pMessage); + return ret; + } + + outmsg("Adding Part to message Good!"); + + *ppMessage = pMessage; + + + /* Remove these if perf becomes a problem ! */ + if (pInput_stream != NULL) + { + outmsg("closing the inputStream"); + pInput_stream->close (pInput_stream->rock); + free (pInput_stream); + } + + outmsg("mime_message_create() returning ok!"); + + return MIME_OK; + +} /* mime_message_create () */ + +/* +* Prasad, jan 8,98 +* Adds a basic part as the body of the message. +* Error if Body is already present. +* Sets content-type accordingly. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_message_addBasicPart (mime_message_t * pMessage, + mime_basicPart_t * pBasicPart, + BOOLEAN fClone) +{ + outmsg("In mime_message_addBasicPart"); + return mime_message_addBasicPart_clonable( pMessage, pBasicPart, fClone); +} + + + +/* +* Prasad, jan 8,98 +* Adds the message part as the body of the message. +* Error if Body is already present. +* Sets content-type accordingly. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_message_addMessagePart (mime_message_t * pMessage, + mime_messagePart_t * pMessagePart, + BOOLEAN fClone) +{ + return mime_message_addMessagePart_clonable( pMessage, pMessagePart, fClone); +} + + + +/* +* Prasad, jan 8,98 +* Adds the multipart as the body of the message +* Error if Body is already present. +* Sets content-type accordingly. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_message_addMultiPart (mime_message_t * pMessage, + mime_multiPart_t * pMultiPart, + BOOLEAN fClone) +{ + return mime_message_addMultiPart_clonable( pMessage, pMultiPart, fClone); +} + + + +/* +* Prasad, jan 8,98 +* Deletes the bodyPart that constitutes the body of this message +* +* parameter : +* +* pMessage : mimeMessage +* +* returns : MIME_OK if successful +*/ +int mime_message_deleteBody (mime_message_t * pMessage) +{ + mime_message_internal_t *pInternal=NULL; + + if (pMessage == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if (pInternal == NULL) + return MIME_OK; /* does not have body */ + + if (pInternal->pMimeBasicPart != NULL) + { + mime_basicPart_free (pInternal->pMimeBasicPart); + pInternal->pMimeBasicPart = NULL; + return MIME_OK; + } + + if ( pInternal->pMimeMultiPart != NULL ) + { + mime_multiPart_free (pInternal->pMimeMultiPart); + pInternal->pMimeMultiPart = NULL; + return MIME_OK; + } + + if (pInternal->pMimeMessagePart != NULL) + { + mime_messagePart_free( pInternal->pMimeMessagePart ); + pInternal->pMimeMessagePart = NULL; + return MIME_OK; + } + + return MIME_OK; /* Never had body */ +} + + + +/* +* returns the content_type of this message +* +* parameter : +* +* pMessage : mimeMessage +* content_type : (output) content type +* +* returns : MIME_OK if successful +*/ +int mime_message_getContentType (mime_message_t * pMessage, + mime_content_type * content_type) +{ + mime_message_internal_t *pInternal=NULL; + + if (pMessage == NULL || content_type == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if ( pInternal != NULL ) + { + if ( pInternal->pMimeBasicPart != NULL ) + { + *content_type = pInternal->pMimeBasicPart->content_type; + return MIME_OK; + } + + else if ( pInternal->pMimeMultiPart != NULL ) + { + *content_type = pInternal->pMimeMultiPart->content_type; + return MIME_OK; + } + + else if ( pInternal->pMimeMessagePart != NULL ) + { + *content_type = pInternal->pMimeMessagePart->content_type; + return MIME_OK; + } + } + + return MIME_ERR_NO_BODY; +} + + + +/* +* Prasad, jan 8,98 +* returns the content_subtype of this message +* NOTE: Assumes user has allocated enough space in pSubType +* +* parameter : +* +* pMessage : mimeMessage +* pSubType : (output) sub type +* +* returns : MIME_OK if successful +*/ +int mime_message_getContentSubType (mime_message_t * pMessage, + char ** ppSubType) +{ + mime_message_internal_t *pInternal=NULL; + + if ( pMessage == NULL || ppSubType == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if (pInternal != NULL) + { + if (pInternal->pMimeBasicPart != NULL && + pInternal->pMimeBasicPart->content_subtype != NULL) + { + /*strcpy( pSubType, pInternal->pMimeBasicPart->content_subtype );*/ + *ppSubType = strdup (pInternal->pMimeBasicPart->content_subtype); + return MIME_OK; + } + + else if (pInternal->pMimeMultiPart != NULL && + pInternal->pMimeMultiPart->content_subtype != NULL) + { + /*strcpy( pSubType, pInternal->pMimeMultiPart->content_subtype );*/ + *ppSubType = strdup (pInternal->pMimeMultiPart->content_subtype); + return MIME_OK; + } + + else if (pInternal->pMimeMessagePart != NULL && + pInternal->pMimeMessagePart->content_subtype != NULL) + { + /*strcpy( pSubType, pInternal->pMimeMessagePart->content_subtype );*/ + *ppSubType = strdup (pInternal->pMimeMessagePart->content_subtype); + return MIME_OK; + } + } + else + { + return MIME_ERR_NO_BODY; + } + + return MIME_ERR_NOT_SET; +} + + + +/* +* Prasad, jan 8,98 +* returns the content_type params of this message +* NOTE: Assumes user has allocated enough space in pParams +* +* parameter : +* +* pMessage : mimeMessage +* pParams : (output) content type parameters +* +* returns : MIME_OK if successful +*/ +int mime_message_getContentTypeParams (mime_message_t * pMessage, + char **ppParams) +{ + mime_message_internal_t *pInternal=NULL; + + if ( pMessage == NULL || ppParams == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if (pInternal != NULL) + { + if (pInternal->pMimeBasicPart != NULL ) + { + if ( pInternal->pMimeBasicPart->content_type_params != NULL ) + /*strcpy( pParams, pInternal->pMimeBasicPart->content_type_params );*/ + *ppParams = strdup (pInternal->pMimeBasicPart->content_type_params ); + else + *ppParams = NULL; + /*pParams[0] = NULL;*/ + + return MIME_OK; + } + else if (pInternal->pMimeMultiPart != NULL ) + { + if ( pInternal->pMimeMultiPart->content_type_params != NULL ) + /*strcpy(pParams, pInternal->pMimeMultiPart->content_type_params);*/ + *ppParams = strdup (pInternal->pMimeMultiPart->content_type_params ); + else + *ppParams = NULL; + /*pParams[0] = NULL;*/ + + return MIME_OK; + } + else if (pInternal->pMimeMessagePart != NULL ) + { + if ( pInternal->pMimeMessagePart->content_type_params != NULL ) + /*strcpy(pParams, pInternal->pMimeMessagePart->content_type_params);*/ + *ppParams = strdup (pInternal->pMimeMessagePart->content_type_params ); + else + *ppParams = NULL; + /*pParams[0] = NULL;*/ + + return MIME_OK; + } + + } + else + { + return MIME_ERR_NO_BODY; + } +} + +int mime_message_getHeader (mime_message_t * pMessage, + char * pName, + char **ppValue) +{ + mime_header_t * pRfcHdr = NULL; + + if (pMessage == NULL || pName == NULL || ppValue == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pMessage->rfc822_headers == NULL) + { + return MIME_ERR_NO_HEADERS; + } + + pRfcHdr = pMessage->rfc822_headers; + + while (pRfcHdr != NULL) + { + if (bStringEquals (pName, pRfcHdr->name)) + { + *ppValue = strdup (pRfcHdr->value); + return MIME_OK; + } + + pRfcHdr = pRfcHdr->next; + + } /* end while */ + + *ppValue = NULL; + return MIME_ERR_NO_SUCH_HEADER; +} + + +/* +* Prasad, jan 8,98 +* Returns the bodyPart that constitues the Body of the message. +* +* parameter : +* +* pMessage : mimeMessage +* pContentType : (output) body / part type +* ppTheBodyPart : (output) the message part +* +* returns : MIME_OK if successful +*/ +int mime_message_getBody (mime_message_t * pMessage, + mime_content_type * pContentType, + void **ppTheBodyPart /* Client can cast this based on pContentType */ + ) +{ + mime_message_internal_t *pInternal=NULL; + + if (pMessage == NULL || pContentType == NULL || ppTheBodyPart == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if (pInternal != NULL) + { + if (pInternal->pMimeBasicPart != NULL) + { + *pContentType = pInternal->pMimeBasicPart->content_type; + *ppTheBodyPart = mime_basicPart_clone (pInternal->pMimeBasicPart); + return MIME_OK; + } + + else if (pInternal->pMimeMultiPart != NULL) + { + *pContentType = MIME_CONTENT_MULTIPART; + *ppTheBodyPart = mime_multiPart_clone (pInternal->pMimeMultiPart); + return MIME_OK; + } + + else if (pInternal->pMimeMessagePart != NULL) + { + *pContentType = MIME_CONTENT_MESSAGEPART; + *ppTheBodyPart = mime_messagePart_clone (pInternal->pMimeMessagePart); + return MIME_OK; + } + + } + + return MIME_ERR_NO_BODY; +} + + + +/* +* Prasad, jan 8,98 +* Writes out byte stream for this part to the output stream +* +* parameter : +* +* returns : +*/ +int mime_message_putByteStream (mime_message_t * pMessage, + nsmail_outputstream_t *pOutput_stream) +{ + int len=0, ret=0; + static char * hdrbuf = NULL; + char * pHdr = NULL; + mime_header_t * pRfcHdr = NULL; + mime_message_internal_t *pInternal = NULL; + mime_basicPart_t * pBasicPart = NULL; + mime_multiPart_t * pMultiPart = NULL; + mime_messagePart_t * pMessagePart = NULL; + BOOLEAN fWroteVersion = FALSE; + + outmsg("Entered mime_message_putByteStream()"); + + if (pMessage == NULL || pOutput_stream == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if (pInternal == NULL) + { + return MIME_ERR_NO_BODY; + } + + if ((pInternal->pMimeBasicPart == NULL) && + (pInternal->pMimeMultiPart == NULL) && + (pInternal->pMimeMessagePart == NULL)) + { + return MIME_ERR_NO_BODY; + } + + if (hdrbuf==NULL) + { + hdrbuf = (char *) malloc (MIME_BUFSIZE); + + if (hdrbuf == NULL) + return MIME_ERR_NO_BODY; + } + + pRfcHdr = pMessage->rfc822_headers; + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + outmsg("Writing out headers"); + + while (pRfcHdr != NULL) + { + if (pRfcHdr->name != NULL && pRfcHdr->value != NULL) /* py 4/03 */ + { + len = append_str (pHdr, pRfcHdr->name); + pHdr += len; + len = append_str (pHdr, ": "); + pHdr += len; + len = append_str (pHdr, pRfcHdr->value); + pHdr += len; + len = append_str (pHdr, "\r\n"); + pHdr += len; + + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + + if (!fWroteVersion && bStringEquals (pRfcHdr->name, "MIME-Version")) + fWroteVersion = TRUE; + + } + + pRfcHdr = pRfcHdr->next; + + } /* while */ + + if (fWroteVersion == FALSE) + { + outmsg("Writing out MIME Version Hdr"); + + /* MIME Version. */ + len = append_str (pHdr, "MIME-Version: 1.0\r\n"); + pHdr += len; + /*pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf +1));*/ + pOutput_stream->write (pOutput_stream->rock, hdrbuf, (pHdr - hdrbuf)); + memset (hdrbuf, 0, MIME_BUFSIZE); + pHdr = hdrbuf; + } + + if (pInternal->pMimeBasicPart != NULL) + { + outmsg("Its a BasicPart! Invoking mime_basicPart_putByteStream"); + + pBasicPart = (mime_basicPart_t *) pInternal->pMimeBasicPart; + return mime_basicPart_putByteStream (pBasicPart, pOutput_stream); + } + else if (pInternal->pMimeMultiPart != NULL) + { + outmsg("Its a MultiPart! Invoking mime_multiPart_putByteStream"); + + pMultiPart = (mime_multiPart_t *) pInternal->pMimeMultiPart; + fNeedPreamble = TRUE; + ret = mime_multiPart_putByteStream (pMultiPart, pOutput_stream); + fNeedPreamble = FALSE; + return (ret); + } + else if (pInternal->pMimeMessagePart != NULL) + { + outmsg("Its a MessagePart! Invoking mime_messagePart_putByteStream"); + + pMessagePart = (mime_messagePart_t *) pInternal->pMimeMessagePart; + return mime_messagePart_putByteStream (pMessagePart, pOutput_stream); + } + + return MIME_ERR_NO_BODY; +} + + + +/* +* Frees up all parts of the message including internal structures. +* +* parameter : +* +* pMessage : mimeMessage to free +* +* returns : MIME_OK if successful +*/ +int mime_message_free_all (mime_message_t * pMessage) +{ + if ( pMessage == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + return mime_message_free( pMessage ); +} + + + +/* +int mime_message_setCallback( mime_message_t * pMimeMessage, mimeDataSink_t *pDataSink ) +{ + mime_message_internal_t *pMimeMessageInternal = NULL; + + if ( pMimeMessage == NULL || pDataSink == NULL ) + return MIME_ERR_INVALIDPARAM; + + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessageInternal != NULL ) + pMimeMessageInternal->pDataSink = pDataSink; + + return MIME_OK; +} +*/ + + + +/*************************************************************************/ +/** UTILITY ROUTINES */ +/*************************************************************************/ + + + +/* +* Prasad, jan 8,98 +* Base64 encodes the data from input_stream and writes to output_stream. +* Returns the number of bytes written to the output_stream or an +* error-code (< 0) in case of an error. +* +* parameter : +* +* returns : +*/ +int mime_encodeBase64 (nsmail_inputstream_t * pInput_stream, + nsmail_outputstream_t * pOutput_stream) +{ + char buf[3], * pOutbuf=NULL; + static char * outbuf=NULL; + char a, b, c; + int linelen = 0, written = 0, bytes_read = 0, len=0; + + + bytes_read = pInput_stream->read (pInput_stream->rock, buf, 3); + + if (bytes_read <= 0) + { + return MIME_ERR_NO_DATA; + } + + if (outbuf == NULL) + { + outbuf = (char *) malloc (80); + + if (outbuf == NULL) + return MIME_ERR_OUTOFMEMORY; + } + + memset (outbuf, 0, 80); + pOutbuf = outbuf; + + while (bytes_read > 0) + { + if (bytes_read <= 0) + break; + + if (bytes_read == 3) + { + a = buf[0]; + b = buf[1]; + c = buf[2]; + + *pOutbuf++ = base64map[(a >> 2) & 0x3F]; + *pOutbuf++ = base64map[((a << 4) & 0x30) | ((b >> 4) & 0xf)], + *pOutbuf++ = base64map[((b << 2) & 0x3c) | ((c >> 6) & 0x3)], + *pOutbuf++ = base64map[c & 0x3F], + + linelen += 4; + written += 4; + } + else if (bytes_read == 2) + { + a = buf[0]; + b = buf[1]; + c = 0; + + *pOutbuf++ = base64map[(a >> 2) & 0x3F]; + *pOutbuf++ = base64map[((a << 4) & 0x30) | ((b >> 4) & 0xf)], + *pOutbuf++ = base64map[((b << 2) & 0x3c) | ((c >> 6) & 0x3)], + *pOutbuf++ = '='; + + linelen += 4; + written += 4; + } + else if (bytes_read == 1) + { + a = buf[0]; + b = 0; + c = 0; + + *pOutbuf++ = base64map[(a >> 2) & 0x3F]; + *pOutbuf++ = base64map[((a << 4) & 0x30) | ((b >> 4) & 0xf)], + *pOutbuf++ = '='; + *pOutbuf++ = '='; + + linelen += 4; + written += 4; + } + + if (linelen > 71) + { + len = append_str (pOutbuf, "\r\n"); + linelen += len; + written += len; + pOutput_stream->write (pOutput_stream->rock, outbuf, linelen); + memset (outbuf, 0, 80); + pOutbuf = outbuf; + linelen = 0; + } + + bytes_read = pInput_stream->read (pInput_stream->rock, buf, 3); + + } /* while */ + + if (linelen > 0) + { + len = append_str (pOutbuf, "\r\n"); + linelen += len; + written += len; + pOutput_stream->write (pOutput_stream->rock, outbuf, linelen); + } + + return written; +} + + + +/* +* Prasad, jan 8,98 +* QuotedPrintable encodes the data from input_stream and writes to output_stream +* +* parameter : +* +* returns : +*/ +int mime_encodeQP (nsmail_inputstream_t * pInput_stream, + nsmail_outputstream_t * pOutput_stream) +{ + static char CR = '\r'; + static char LF = '\n'; + static char HT = '\t'; + static char * outbuf=NULL, * buf=NULL; + char * pOutbuf=NULL; + unsigned char current, previous, tmp; + int i=0, len=0, read_len=0, linelen=0, written=0, lastspace=0; + int nullCount=0, idx; + + if (buf == NULL) + { + buf = (char *) malloc (MIME_BUFSIZE); + + if (buf == NULL) + return MIME_ERR_OUTOFMEMORY; + } + + if (outbuf == NULL) + { + outbuf = (char *) malloc (80); + + if (outbuf == NULL) + return MIME_ERR_OUTOFMEMORY; + } + + + memset (buf, 0, MIME_BUFSIZE); + read_len = pInput_stream->read (pInput_stream->rock, buf, MIME_BUFSIZE); + + memset (outbuf, 0, 80); + pOutbuf = outbuf; + + while (read_len > 0) + { + + for (i=0; i < read_len; i++) + { + current = buf[i]; + + if (current == 0x00) + { + nullCount++; + previous = current; + lastspace = 0; + continue; + } + else if (nullCount > 0) + { + /* write out all nulls and fall through to process current char.*/ + for (idx = 1; idx <= nullCount ; idx++) + { + tmp = (unsigned char)0x00; + *pOutbuf++ = '='; + *pOutbuf++ = hexmap [(tmp >> 4)]; + *pOutbuf++ = hexmap [(tmp & 0xF)]; + linelen += 3; + written += 3; + + if (linelen > 74) + { + len = append_str (pOutbuf, "=\r\n"); + pOutbuf += len; + linelen += len; + + pOutput_stream->write (pOutput_stream->rock, outbuf, linelen); + memset (outbuf, 0, 80); + pOutbuf = outbuf; + written += len; + linelen = 0; + } + } + + previous = 0; + nullCount = 0; + } + + if ((current > ' ') && (current < 0x7F) && (current != '=')) + { + /* Printable chars */ + *pOutbuf++ = current; + linelen += 1; + written += 1; + lastspace = 0; + previous = current; + } + else if ((current == ' ') || (current == HT)) + { + *pOutbuf++ = current; + linelen += 1; + written += 1; + lastspace = 1; + previous = current; + } + else if ((current == LF) && (previous == CR)) + { + /* handled this already. Ignore. */ + previous = 0; + } + else if ((current == CR ) || (current == LF)) + { + /* Need to emit a soft line break if last char was SPACE/HT or + if we have a period on a line by itself. */ + if ((lastspace == 1) || ((previous == '.') && (linelen == 1))) + { + len = append_str (pOutbuf, "=\r\n"); + pOutbuf += len; + linelen += len; + written += len; + /*written += 3;*/ + } + + len = append_str (pOutbuf, "\r\n"); + pOutbuf += len; + linelen += len; + written += len; + + pOutput_stream->write (pOutput_stream->rock, outbuf, linelen); + memset (outbuf, 0, 80); + pOutbuf = outbuf; + + lastspace = 0; + linelen = 0; + previous = current; + } + else if ( (current < ' ') || (current == '=') || (current >= 0x7F) ) + { + /* Special Chars */ + *pOutbuf++ = '='; + *pOutbuf++ = hexmap [(current >> 4)]; + *pOutbuf++ = hexmap [(current & 0xF)]; + lastspace = 0; + linelen += 3; + written += 3; + previous = current; + } + else + { + *pOutbuf++ = current; + lastspace = 0; + linelen += 1; + written += 1; + previous = current; + } + + if (linelen > 74) + { + len = append_str (pOutbuf, "=\r\n"); + pOutbuf += len; + linelen += len; + + pOutput_stream->write (pOutput_stream->rock, outbuf, linelen); + memset (outbuf, 0, 80); + pOutbuf = outbuf; + written += len; + + linelen = 0; + previous = 0; + } + } /* for */ + + memset (buf, 0, MIME_BUFSIZE); + read_len = pInput_stream->read (pInput_stream->rock, buf, MIME_BUFSIZE); + + } /* while */ + + if (linelen > 0) + { + len = append_str (pOutbuf, "\r\n"); + linelen += len; + written += len; + pOutput_stream->write (pOutput_stream->rock, outbuf, linelen); + } + + return written; +} + + + +/* +* Prasad, jan 8,98 +* Q encodes the data from input_stream and writes to output_stream +* +* parameter : +* +* returns : +*/ +int mime_encodeQ (nsmail_inputstream_t * pInput_stream, + nsmail_outputstream_t * pOutput_stream) +{ + static char * outbuf=NULL, * buf=NULL; + char * pOutbuf=NULL, current; + int i=0, read_len=0, written=0; + BOOLEAN encode = FALSE; + + + if (buf == NULL) + { + buf = (char *) malloc (MIME_BUFSIZE); + + if (buf == NULL) + return MIME_ERR_OUTOFMEMORY; + } + + if (outbuf == NULL) + { + outbuf = (char *) malloc (80); + + if (outbuf == NULL) + return MIME_ERR_OUTOFMEMORY; + } + + memset (buf, 0, MIME_BUFSIZE); + read_len = pInput_stream->read (pInput_stream->rock, buf, MIME_BUFSIZE); + + memset (outbuf, 0, 80); + pOutbuf = outbuf; + + while (read_len > 0) + { + + for (i=0; i < read_len; i++) + { + current = buf[i]; + + if ((current >= 0x30 && current <= 0x39) || /* 0-9 */ + (current >= 0x41 && current <= 0x5A) || /* A-Z */ + (current >= 0x61 && current <= 0x7A) || /* a-z */ + (current == 0x21 || current == 0x2A) || /* !* */ + (current == 0x2B || current == 0x2D) || /* +- */ + (current == 0x2F || current == 0x5F)) /* /_ */ + { + encode = FALSE; + } + else + encode = TRUE; + + if (encode == TRUE) + { + /* Special Chars */ + *pOutbuf++ = '='; + *pOutbuf++ = hexmap [(current >> 4)]; + *pOutbuf++ = hexmap [(current & 0xF)]; + pOutput_stream->write (pOutput_stream->rock, outbuf, 3); + memset (outbuf, 0, 80); + pOutbuf = outbuf; + written += 3; + } + else + { + buf[0] = current; + pOutput_stream->write (pOutput_stream->rock, buf, 1); + written += 1; + } + } /* for */ + + } /* while */ + + return written; +} + + + +/* +* Prasad, jan 8,98 +* Q encodes the data from inBuf and write to outBuf. +* Caller responsible for both inBuf and outBuf. +* +* parameter : +* +* returns : +*/ +int mime_bufEncodeQ (char * pInBuf, + char ** ppOutBuf) +{ + char current, * pOutbuf; + int i, in_len=0, written=0; + BOOLEAN encode = FALSE; + + if (pInBuf == NULL || ppOutBuf == NULL) + { + return -1; + } + + in_len = strlen (pInBuf); + + pOutbuf = *ppOutBuf; + + if (in_len > 0) + { + + for (i=0; i < in_len; i++) + { + current = *pInBuf++; + + if ((current >= 0x30 && current <= 0x39) || /* 0-9 */ + (current >= 0x41 && current <= 0x5A) || /* A-Z */ + (current >= 0x61 && current <= 0x7A) || /* a-z */ + (current == 0x21 || current == 0x2A) || /* !* */ + (current == 0x2B || current == 0x2D) || /* +- */ + (current == 0x2F || current == 0x5F)) /* /_ */ + { + encode = FALSE; + } + else + encode = TRUE; + + if (encode == TRUE) + { + /* Special Chars */ + *pOutbuf++ = '='; + *pOutbuf++ = hexmap [(current >> 4)]; + *pOutbuf++ = hexmap [(current & 0xF)]; + written += 3; + } + else + { + *pOutbuf++ = current; + written += 1; + } + } /* for */ + + } /* if */ + else + return -1; + + return written; +} + + + +/* +* Prasad, jan 8,98 +* base64 encodes the data from inBuf and write to outBuf. +* Caller responsible for both inBuf and outBuf. +* It is expected that data in pInBuf <= 71 chars +* +* parameter : +* +* returns : +*/ +int mime_bufEncodeB64 (char * pInBuf, + char ** ppOutBuf) +{ + char buf[3], * pOutbuf; + char a, b, c; + int in_len = 0, enclen = 0; + + in_len = strlen (pInBuf); + + if (in_len <= 0) + { + return MIME_ERR_NO_DATA; + } + + if (in_len >= 71) + { + return MIME_ERR_ENCODE; + } + + pOutbuf = * ppOutBuf; + + while (in_len >= 3) + { + strncpy (buf, pInBuf, 3); + pInBuf += 3; + in_len -= 3; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + + *pOutbuf++ = base64map[(a >> 2) & 0x3F]; + *pOutbuf++ = base64map[((a << 4) & 0x30) | ((b >> 4) & 0xf)], + *pOutbuf++ = base64map[((b << 2) & 0x3c) | ((c >> 6) & 0x3)], + *pOutbuf++ = base64map[c & 0x3F], + + enclen += 4; + + } /* while */ + + if (in_len == 2) + { + strncpy (buf, pInBuf, 2); + pInBuf += 3; + a = buf[0]; + b = buf[1]; + c = 0; + + *pOutbuf++ = base64map[(a >> 2) & 0x3F]; + *pOutbuf++ = base64map[((a << 4) & 0x30) | ((b >> 4) & 0xf)], + *pOutbuf++ = base64map[((b << 2) & 0x3c) | ((c >> 6) & 0x3)], + *pOutbuf++ = '='; + + enclen += 4; + } + else if (in_len == 1) + { + strncpy (buf, pInBuf, 1); + a = buf[0]; + b = 0; + c = 0; + + *pOutbuf++ = base64map[(a >> 2) & 0x3F]; + *pOutbuf++ = base64map[((a << 4) & 0x30) | ((b >> 4) & 0xf)], + *pOutbuf++ = '='; + *pOutbuf++ = '='; + + enclen += 4; + } + + return enclen; +} + + + +/* +* Prasad, jan 8,98 +* Encode a header string per RFC 2047. The encoded string can be used as the +* value of unstructured headers or in the comments section of structured headers. +* Below, encoding must be one of 'B' or 'Q'. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_encodeHeaderString (char * inString, + char * pCharset, /* charset the input string is in */ + char encoding, + char ** ppOutString) +{ + int i, l_encoding = -1, enclen, csetlen; + char * pBuf, buf [1024], * pOutString; + + if (inString == NULL || pCharset == NULL || ppOutString == NULL || *ppOutString == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + csetlen = strlen (pCharset); + + if (csetlen <= 0) + { + return MIME_ERR_INVALIDPARAM; + } + + if (encoding == 'B' || encoding == 'b') + l_encoding = 1; + else if (encoding == 'Q' || encoding == 'q') + l_encoding = 2; + else + { + return MIME_ERR_INVALIDPARAM; + } + + pOutString = *ppOutString; + pBuf = buf; + + + switch (encoding) + { + case 1: /* Base64 */ + enclen = mime_bufEncodeB64 (inString, &pBuf); + break; + case 2: /* Q */ + enclen = mime_bufEncodeQ (inString, &pBuf); + break; + } + + if (enclen <= 0) + MIME_ERR_ENCODE; + + *pOutString++ = '='; + *pOutString++ = '?'; + + for (i = 0; i < csetlen; i++) + *pOutString++ = *pCharset++; + + *pOutString++ = '?'; + if (encoding == 1) + *pOutString++ = 'B'; + else + *pOutString++ = 'Q'; + *pOutString++ = '?'; + + for (i = 0; i < enclen; i++) + *pOutString++ = buf[i]; /* encoded stuff */ + + *pOutString++ = '?'; + *pOutString++ = '='; + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* If the input string is not encoded (per RFC 2047), returns the same. +* Otherwise, decodes and returns the decoded string +* +* =? charset ? encoding(q/b) ? encoded text ?= +* +* parameter : +* +* inString : input string +* outString : (output) decoded header string +* +* returns : MIME_OK if successful +*/ + +int mime_decodeHeaderString (char * inString, + char ** outString) +{ + + if ( inString == NULL || outString == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + *outString = decodeHeader (inString); + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* Base64 decodes the data from input_stream and writes to output_stream +* +* parameter : +* +* pInput_stream : inputstream +* pOutput_stream : (output) output stream +* +* returns : MIME_OK if successful +*/ +int mime_decodeBase64 (nsmail_inputstream_t * pInput_stream, + nsmail_outputstream_t * pOutput_stream) +{ + char achReadBuffer[BUFFER_SIZE]; + char achWriteBuffer[BUFFER_SIZE]; + int nBytesRead = 0; + int nBytesWrite = 0; + int out_byte = 0; + int out_bits = 0; + + if ( pInput_stream == NULL || pOutput_stream == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + for ( nBytesRead = pInput_stream->read( pInput_stream->rock, achReadBuffer, BUFFER_SIZE ); + nBytesRead > 0; + nBytesRead = pInput_stream->read( pInput_stream->rock, achReadBuffer, BUFFER_SIZE ) ) + { + nBytesWrite = decodeBase64( achReadBuffer, achWriteBuffer, nBytesRead, BUFFER_SIZE, &out_byte, &out_bits ); + + if ( nBytesWrite > 0 ) + pOutput_stream->write( pOutput_stream->rock, achWriteBuffer, nBytesWrite ); + } + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* QuotedPrintable decodes the data from input_stream and writes to output_stream +* +* parameter : +* +* pInput_stream : inputstream +* pOutput_stream : (output) output stream +* +* returns : MIME_OK if successful +*/ +int mime_decodeQP (nsmail_inputstream_t * pInput_stream, + nsmail_outputstream_t * pOutput_stream) +{ + char achReadBuffer[BUFFER_SIZE]; + char achWriteBuffer[BUFFER_SIZE]; + int nBytesRead = 0; + int nBytesWrite = 0; + int i = 0; + int j = 0; + char ch; + + if ( pInput_stream == NULL || pOutput_stream == NULL ) + { + return MIME_ERR_INVALIDPARAM;; + } + + for ( nBytesRead = pInput_stream->read( pInput_stream->rock, achReadBuffer, BUFFER_SIZE ); + nBytesRead > 0; + nBytesRead = pInput_stream->read( pInput_stream->rock, achReadBuffer, BUFFER_SIZE ) ) + { + for ( i = 0, j = 0, ch = achReadBuffer[i]; + ch != -1 && i < nBytesRead; + i++, ch = achReadBuffer[i] ) + { + if ( ( ch >= 33 && ch <= 60 ) || ( ch >= 62 && ch <= 126 ) || ( ch == 9 || ch == 32 ) ) + { + achWriteBuffer[j++] = ch; + } + + else if ( ch == '=' ) + { + achWriteBuffer[j++] = nConvertHexToDec( achReadBuffer[++i], achReadBuffer[++i] ); + } + } + + pOutput_stream->write( pOutput_stream->rock, achWriteBuffer, j ); + nBytesWrite += j; + } + + return MIME_OK; +} + + +/* Returns file's MIME type info based on file's extension. */ +/* By default (or if filename_ext is null) returns application/octet-stream. */ +int getFileMIMEType (char * filename_ext, file_mime_type * pFmt) +{ + if (pFmt == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (filename_ext == NULL) + { + + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("octet-stream"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } else + if (equalsIgnoreCase (filename_ext, "txt") || equalsIgnoreCase (filename_ext, "java") || + equalsIgnoreCase (filename_ext, "c") || equalsIgnoreCase (filename_ext, "C") || + equalsIgnoreCase (filename_ext, "cc") || equalsIgnoreCase (filename_ext, "CC") || + equalsIgnoreCase (filename_ext, "h") || equalsIgnoreCase (filename_ext, "hxx") || + equalsIgnoreCase (filename_ext, "bat") || equalsIgnoreCase (filename_ext, "rc") || + equalsIgnoreCase (filename_ext, "ini") || equalsIgnoreCase (filename_ext, "cmd") || + equalsIgnoreCase (filename_ext, "awk") || equalsIgnoreCase (filename_ext, "html") || + equalsIgnoreCase (filename_ext, "sh") || equalsIgnoreCase (filename_ext, "ksh") || + equalsIgnoreCase (filename_ext, "pl") || equalsIgnoreCase (filename_ext, "DIC") || + equalsIgnoreCase (filename_ext, "EXC") || equalsIgnoreCase (filename_ext, "LOG") || + equalsIgnoreCase (filename_ext, "SCP") || equalsIgnoreCase (filename_ext, "WT") || + equalsIgnoreCase (filename_ext, "mk") || equalsIgnoreCase (filename_ext, "htm")) + { + pFmt->content_type = MIME_CONTENT_TEXT; + if (equalsIgnoreCase (filename_ext, "html") || + equalsIgnoreCase (filename_ext, "htm")) + pFmt->content_subtype = strdup ("html"); + else + pFmt->content_subtype = strdup ("plain"); + pFmt->content_params = strdup ("us-ascii"); + pFmt->mime_encoding = MIME_ENCODING_7BIT; + } + else if (equalsIgnoreCase (filename_ext, "pdf")) + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("pdf"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "AIF") || + equalsIgnoreCase (filename_ext, "AIFC") || + equalsIgnoreCase (filename_ext, "AIFF")) + { + pFmt->content_type = MIME_CONTENT_AUDIO; + pFmt->content_subtype = strdup ("aiff"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "AU") || + equalsIgnoreCase (filename_ext, "SND")) + { + pFmt->content_type = MIME_CONTENT_AUDIO; + pFmt->content_subtype = strdup ("basic"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "WAV")) + { + pFmt->content_type = MIME_CONTENT_AUDIO; + pFmt->content_subtype = strdup ("wav"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "gif") ) + { + pFmt->content_type = MIME_CONTENT_IMAGE; + pFmt->content_subtype = strdup ("gif"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "jpg") ) + { + pFmt->content_type = MIME_CONTENT_IMAGE; + pFmt->content_subtype = strdup ("jpeg"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "jpeg") ) + { + pFmt->content_type = MIME_CONTENT_IMAGE; + pFmt->content_subtype = strdup ("jpeg"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "tif") ) + { + pFmt->content_type = MIME_CONTENT_IMAGE; + pFmt->content_subtype = strdup ("tiff"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "XBM") ) + { + pFmt->content_type = MIME_CONTENT_IMAGE; + pFmt->content_subtype = strdup ("x-xbitmap"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "avi") ) + { + pFmt->content_type = MIME_CONTENT_VIDEO; + pFmt->content_subtype = strdup ("avi"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "mpeg") ) + { + pFmt->content_type = MIME_CONTENT_VIDEO; + pFmt->content_subtype = strdup ("mpeg"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "ps") || + equalsIgnoreCase (filename_ext, "EPS")) + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("postscript"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "tar") ) + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("x-tar"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "zip") ) + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("zip"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "js") ) + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("x-javascript"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "doc") ) + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("msword"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "nsc") ) + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("x-conference"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else if (equalsIgnoreCase (filename_ext, "ARC") || + equalsIgnoreCase (filename_ext, "ARJ") || + equalsIgnoreCase (filename_ext, "B64") || + equalsIgnoreCase (filename_ext, "BHX") || + equalsIgnoreCase (filename_ext, "GZ") || + equalsIgnoreCase (filename_ext, "HQX")) + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("x-gzip"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + else + { + pFmt->content_type = MIME_CONTENT_APPLICATION; + pFmt->content_subtype = strdup ("octet-stream"); + pFmt->content_params = null; + pFmt->mime_encoding = MIME_ENCODING_BASE64; + } + + return MIME_OK; +} + +void * mime_malloc (unsigned int size) +{ + return (void *) malloc (size); +} + +void mime_memfree (void * pMem) +{ + free (pMem); +} diff --git a/msgsdk/C/protocol/MIME/src/mime.def b/msgsdk/C/protocol/MIME/src/mime.def new file mode 100644 index 000000000000..cba36d1c4e5f --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/mime.def @@ -0,0 +1,87 @@ +LIBRARY LIBMIME +DESCRIPTION "MIME Client exported functions." +EXPORTS + mime_basicPart_setDataStream @1 + mime_basicPart_setDataBuf @2 + mime_basicPart_deleteData @3 + mime_basicPart_getSize @4 + mime_basicPart_getDataStream @5 + mime_basicPart_getDataBuf @6 + mime_basicPart_putByteStream @7 + mime_basicPart_free_all @8 + mime_multiPart_addBasicPart @9 + mime_multiPart_addMessagePart @10 + mime_multiPart_addMultiPart @11 + mime_multiPart_deletePart @12 + mime_multiPart_getPartCount @13 + mime_multiPart_getPart @14 + mime_multiPart_putByteStream @15 + mime_multiPart_free_all @16 + mime_messagePart_fromMessage @17 + mime_messagePart_getMessage @18 + mime_messagePart_deleteMessage @19 + mime_messagePart_setMessage @20 + mime_messagePart_putByteStream @21 + mime_messagePart_free_all @22 + mime_message_new @23 + mime_message_addBasicPart @24 + mime_message_addMessagePart @25 + mime_message_addMultiPart @26 + mime_message_deleteBody @27 + mime_message_getContentType @28 + mime_message_getContentSubType @29 + mime_message_getContentTypeParams @30 + mime_message_getBody @31 + mime_message_putByteStream @32 + mime_message_free_all @33 + mime_encodeHeaderString @34 + mime_decodeHeaderString @35 + mime_encodeBase64 @36 + mime_encodeQP @37 + mime_decodeBase64 @38 + mime_decodeQP @39 + mimeDynamicParser_new @40 + mimeDynamicParser_free @41 + beginDynamicParse @42 + dynamicParseInputstream @43 + dynamicParse @44 + endDynamicParse @45 + parseEntireMessageInputstream @46 + parseEntireMessage @47 + decodeBase64 @48 + decodeQP @49 + decodeHeader @50 + nConvertHexToDec @51 + generateBoundary @52 + get_inputstream_size @53 + buf_instream_create @54 + buf_instream_read @55 + buf_instream_rewind @56 + buf_instream_close @57 + file_instream_create @58 + file_instream_close @59 + file_instream_rewind @60 + file_instream_read @61 + append_str @62 + errorLog_new @63 + errorLog_free @64 + initErrorLog @65 + closeErrorLog @66 + errorLog @67 + errorLog2 @68 + errorLogMsg @69 + errorLogMsg2 @70 + errorLogOn @71 + errorLogOff @72 + file_outstream_create @73 + mime_message_create @74 + file_outstream_close @75 + mime_multiPart_addFile @76 + mimeDataSink_new @77 + mimeDataSink_free @78 + mime_message_getHeader @79 + mime_header_new @80 + mime_header_free @81 + mime_malloc @82 + mime_memfree @83 + getFileMIMEType @84 diff --git a/msgsdk/C/protocol/MIME/src/mime.exp b/msgsdk/C/protocol/MIME/src/mime.exp new file mode 100644 index 000000000000..4a14fc513cab --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/mime.exp @@ -0,0 +1,84 @@ +mime_basicPart_setDataStream +mime_basicPart_setDataBuf +mime_basicPart_deleteData +mime_basicPart_getSize +mime_basicPart_getDataStream +mime_basicPart_getDataBuf +mime_basicPart_putByteStream +mime_basicPart_free_all +mime_multiPart_addBasicPart +mime_multiPart_addMessagePart +mime_multiPart_addMultiPart +mime_multiPart_deletePart +mime_multiPart_getPartCount +mime_multiPart_getPart +mime_multiPart_putByteStream +mime_multiPart_free_all +mime_messagePart_fromMessage +mime_messagePart_getMessage +mime_messagePart_deleteMessage +mime_messagePart_setMessage +mime_messagePart_putByteStream +mime_messagePart_free_all +mime_message_new +mime_message_addBasicPart +mime_message_addMessagePart +mime_message_addMultiPart +mime_message_deleteBody +mime_message_getContentType +mime_message_getContentSubType +mime_message_getContentTypeParams +mime_message_getBody +mime_message_putByteStream +mime_message_free_all +mime_encodeHeaderString +mime_decodeHeaderString +mime_encodeBase64 +mime_encodeQP +mime_decodeBase64 +mime_decodeQP +mimeDynamicParser_new +mimeDynamicParser_free +beginDynamicParse +dynamicParseInputstream +dynamicParse +endDynamicParse +parseEntireMessageInputstream +parseEntireMessage +decodeBase64 +decodeQP +decodeHeader +nConvertHexToDec +generateBoundary +get_inputstream_size +buf_instream_create +buf_instream_read +buf_instream_rewind +buf_instream_close +file_instream_create +file_instream_close +file_instream_rewind +file_instream_read +append_str +errorLog_new +errorLog_free +initErrorLog +closeErrorLog +errorLog +errorLog2 +errorLogMsg +errorLogMsg2 +errorLogOn +errorLogOff +file_outstream_create +mime_message_create +file_outstream_close +mime_multiPart_addFile +mimeDataSink_new +mimeDataSink_free +mime_message_getHeader +mime_header_new +mime_header_free +mime_malloc +mime_memfree +getFileMIMEType diff --git a/msgsdk/C/protocol/MIME/src/mimeDataSink.c b/msgsdk/C/protocol/MIME/src/mimeDataSink.c new file mode 100644 index 000000000000..6baea0437546 --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/mimeDataSink.c @@ -0,0 +1,155 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +/* +* mimeparser.c +* carsonl, Jan 8,97 +* +*/ + +#include +#include +#include + +#include "nsmail.h" +#include "vector.h" +#include "util.h" +#include "mime.h" +#include "mime_internal.h" +#include "mimeparser.h" + + + +/* +* carsonl, jan 7,97 +* default do nothing callback methods +* +* NOTE : by default all callbacks do nothing, it's up to the user to override the methods they're interested in +*/ +void mimeDataSink_header(mimeDataSink_t *pSink, void *pCallbackObject, char *name, char *value ) { return; } +void mimeDataSink_contentType(mimeDataSink_t *pSink, void *pCallbackObject, int nContentType ) { return; } +void mimeDataSink_contentSubType(mimeDataSink_t *pSink, void *pCallbackObject, char * contentSubType ) { return; } +void mimeDataSink_contentTypeParams(mimeDataSink_t *pSink, void *pCallbackObject, char * contentTypeParams ) { return; } +void mimeDataSink_contentID(mimeDataSink_t *pSink, void *pCallbackObject, char * contentID ) { return; } +void mimeDataSink_contentMD5(mimeDataSink_t *pSink, void *pCallbackObject, char * contentMD5 ) { return; } +void mimeDataSink_contentDisposition(mimeDataSink_t *pSink, void *pCallbackObject, int nContentDisposition ) { return; } +void mimeDataSink_contentDispParams(mimeDataSink_t *pSink, void *pCallbackObject, char * contentDispParams ) { return; } +void mimeDataSink_contentDescription(mimeDataSink_t *pSink, void *pCallbackObject, char * contentDescription ) { return; } +void mimeDataSink_contentEncoding(mimeDataSink_t *pSink, void *pCallbackObject, int nContentEncoding ) { return; } + +void *mimeDataSink_startMessage(mimeDataSink_t *pSink) { return NULL; } +void mimeDataSink_endMessage(mimeDataSink_t *pSink, void *pCallbackObject ) { return; } + +void *mimeDataSink_startBasicPart(mimeDataSink_t *pSink) { return NULL; } +void mimeDataSink_bodyData(mimeDataSink_t *pSink, void *pCallbackObject, char bodyData[], int len ) { return; } +void mimeDataSink_endBasicPart(mimeDataSink_t *pSink, void *pCallbackObject ) { return; } + +void *mimeDataSink_startMultiPart(mimeDataSink_t *pSink) { return NULL; } +void mimeDataSink_boundary(mimeDataSink_t *pSink, void *pCallbackObject, char * boundary ) { return; } +void mimeDataSink_endMultiPart(mimeDataSink_t *pSink, void *pCallbackObject ) { return; } + +void *mimeDataSink_startMessagePart(mimeDataSink_t *pSink) { return NULL; } +void mimeDataSink_endMessagePart(mimeDataSink_t *pSink, void *pCallbackObject ) { return; } + +void mimeDataSink_addHeader(mimeDataSinkPtr_t pSink, void *pCallbackObject, char *name, char *value) { return; } +void mimeDataSink_endMessageHeader(mimeDataSinkPtr_t pSink, void *pCallbackObject) { return; } + + +/* +* carsonl, jan 7,97 +* datasink constructor +* +* parameter : none +* +* returns : instance of newly created datasink +* +* NOTE : by default all callbacks do nothing, it's up to the user to override the methods they're interested in +*/ +int mimeDataSink_new( mimeDataSink_t **pp ) +{ + if ( pp == NULL ) + return MIME_ERR_INVALIDPARAM; + + *pp = (mimeDataSink_t *) malloc( sizeof( mimeDataSink_t ) ); + + if ( *pp == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + + (*pp)->pOpaqueData = NULL; + (*pp)->header = &mimeDataSink_header; + (*pp)->addHeader = &mimeDataSink_addHeader; + (*pp)->endMessageHeader = &mimeDataSink_endMessageHeader; + (*pp)->contentType = &mimeDataSink_contentType; + (*pp)->contentSubType = &mimeDataSink_contentSubType; + (*pp)->contentTypeParams = &mimeDataSink_contentTypeParams; + (*pp)->contentID = &mimeDataSink_contentID; + (*pp)->contentMD5 = &mimeDataSink_contentMD5; + (*pp)->contentDisposition = &mimeDataSink_contentDisposition; + (*pp)->contentDispParams = &mimeDataSink_contentDispParams; + (*pp)->contentDescription = &mimeDataSink_contentDescription; + (*pp)->contentEncoding = &mimeDataSink_contentEncoding; + + (*pp)->startMessage = &mimeDataSink_startMessage; + (*pp)->endMessage = &mimeDataSink_endMessage; + + (*pp)->startBasicPart = &mimeDataSink_startBasicPart; + (*pp)->bodyData = &mimeDataSink_bodyData; + (*pp)->endBasicPart = &mimeDataSink_endBasicPart; + + (*pp)->startMultiPart = &mimeDataSink_startMultiPart; + (*pp)->boundary = &mimeDataSink_boundary; + (*pp)->endMultiPart = &mimeDataSink_endMultiPart; + + (*pp)->startMessagePart = &mimeDataSink_startMessagePart; + (*pp)->endMessagePart = &mimeDataSink_endMessagePart; + + return MIME_OK; +} + + + +/* +* carsonl, jan 7,97 +* datasink destructor +* +* parameter : +* +* mimeDataSink_t *p : instance of datasink +* +* returns : nothing +*/ +void mimeDataSink_free( mimeDataSink_t **pp ) +{ + if ( pp != NULL && *pp != NULL ) + { + free( *pp ); + *pp = NULL; + } +} + + diff --git a/msgsdk/C/protocol/MIME/src/mime_internal.c b/msgsdk/C/protocol/MIME/src/mime_internal.c new file mode 100644 index 000000000000..9005bbd7bf77 --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/mime_internal.c @@ -0,0 +1,2389 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +/* +* mime_internal.c +* +* the routines in this file are internal and not exposed to the user +* +* Prasad, oct 97 +* carsonl, oct 97 +*/ + + +#include +#include +#include + +#include "nsmail.h" +#include "vector.h" +#include "util.h" +#include "mime.h" +#include "mime_internal.h" +#include "mimeparser.h" + +#ifdef DEBUG +#define outmsg(x) (fprintf(stderr,"%s:%d>%s\n",__FILE__,__LINE__,x)) +#else +#define outmsg(x) +#endif + + +/* -------------------------------------------- */ + + + +/* +* return NULL if unsuccessful +* +* parameter : +* +* szName : name +* szValue : value +* +* returns : MIME_OK if successful +*/ +mime_header_t *mime_header_new( char *szName, char *szValue ) +{ + mime_header_t *p; + + if ( szName == NULL || szValue == NULL ) + { + return NULL; + } + + p = (mime_header_t *) malloc( sizeof( mime_header_t ) ); + + if ( p == NULL ) + { + return NULL; + } + else + memset (p, 0, sizeof (mime_header_t)); + + p->name = szStringClone( szName ); + p->value = szStringClone( szValue ); + p->next = NULL; + + return p; +} + + + +/* +* carsonl, jan 8,98 +* Add additional header structures after the initial one is created +* create and append header to end of list +* return MIME_OK if success +* +* parameter : +* +* pStart : starting header +* szName : name +* szValue : value +* +* returns : MIME_OK if successful +*/ +int mime_header_add( mime_header_t *pStart, char *szName, char *szValue ) +{ + mime_header_t *p = NULL; + mime_header_t *pNew = NULL; + + if ( pStart == NULL || szName == NULL || szValue == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + for ( p = pStart; p->next != NULL; p = p->next ) + ; + + pNew = (mime_header_t *) malloc( sizeof( mime_header_t ) ); + + if ( pNew == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + else + memset (pNew, 0, sizeof (mime_header_t)); + + pNew->name = szStringClone( szName ); + pNew->value = szStringClone( szValue ); + pNew->next = NULL; + p->next = pNew; + + return MIME_OK; +} + + +/* +* carsonl, jan 8,98 +* Append header values to an existing header structure +* return MIME_OK if success +* +* parameter : +* +* pStart : starting header +* szName : name +* szValue : value +* +* returns : MIME_OK if successful +*/ +int mime_header_apend( mime_header_t *pStart, char *szName, char *szValue ) +{ + mime_header_t *p = NULL; + mime_header_t *pNew = NULL; + char achTemp[512]; + + if ( pStart == NULL || szName == NULL || szValue == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* first try to add to the last one if matches */ + for (p = pStart; p->next != NULL; p = p->next); + + if (p != NULL) + { + if (strcmp (szName, p->name) == 0) + { + strcpy( achTemp, p->value ); + strcat( achTemp, szValue ); + + if ( p->value != NULL ) + free( p->value ); + + p->value = szStringClone( achTemp ); + + return MIME_OK; + } + } + + /* Try to add to the matching one */ + + for ( p = pStart; p != NULL; p = p->next ) + { + if ( strcmp( szName, p->name ) == 0 ) + { + strcpy( achTemp, p->value ); + strcat( achTemp, szValue ); + + if ( p->value != NULL ) + free( p->value ); + + p->value = szStringClone( achTemp ); + + return MIME_OK; + } + } + + return MIME_ERR_NOT_FOUND; +} + + + +/* +* parameter : +* +* p : mime header to free +* +* returns : MIME_OK if successful +*/ +int mime_header_free( mime_header_t *p ) +{ + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( p->name != NULL ) + { + free( p->name ); + p->name = NULL; + } + + if ( p->value != NULL ) + { + free( p->value ); + p->value = NULL; + } + + free( p ); + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* free all header structures +* to a max of 256 headers +* +* parameter : pStart : starting header ( headers are linked together using a link list ) +* +* returns : MIME_OK if successful +*/ +int mime_header_freeAll( mime_header_t *pStart ) +{ + mime_header_t *pt[256]; /* 256 headers max */ + int i=0; + mime_header_t *p = NULL; + + if ( pStart == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + for ( pt[0] = pStart, i = 1, p = pStart->next; + p != NULL && p->next != NULL && i < 255; + p = p->next, i++ ) + { + pt[i] = p; + } + + pt[i] = p; + + for ( ; i >= 0; i-- ) + { + if ( pt[i] != NULL ) + mime_header_free( pt[i] ); + } + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* create new instance and clone of mime_header +* +* parameter : +* +* p : mime header +* +* returns : MIME_OK if successful +*/ +mime_header_t *mime_header_clone( mime_header_t *p ) +{ + mime_header_t *pNew; + mime_header_t *p2; + mime_header_t *pNextMimeHeader; + BOOLEAN firstOne = TRUE; + + if ( p == NULL ) + { + return NULL; + } + + pNew = mime_header_new( p->name, p->value ); + + if ( pNew != NULL ) + { + for ( p2 = pNew, pNextMimeHeader = p->next; + pNextMimeHeader != NULL; + p2 = p2->next, pNextMimeHeader = pNextMimeHeader->next ) + { + if (pNextMimeHeader == NULL) + break; + + p2->next = mime_header_new( pNextMimeHeader->name, pNextMimeHeader->value ); + } + } + + return pNew; +} + + + + +/* ----------------------------------- */ + + + +/* +* Constructor. +* Return NULL if unsuccessful. +* +* parameter : +* +* returns : new basicPart +*/ +mime_basicPart_internal_t *mime_basicPart_internal_new() +{ + mime_basicPart_internal_t *p = (mime_basicPart_internal_t *) + malloc( sizeof( mime_basicPart_internal_t ) ); + + if ( p == NULL ) + { + return NULL; + } + else + memset (p, 0, sizeof (mime_basicPart_internal_t)); + + p->pTheDataStream = NULL; + p->szMessageBody = NULL; + p->nMessageSize = 0; + p->nRawMessageSize = 0; + p->nStartMessageDataIndex = -1; + p->nEndMessageDataIndex = -1; + p->bDecodedData = FALSE; + p->pUserObject = NULL; + p->nDynamicBufferSize = 0; + + return p; +} + + + +/* +* Destructor. +* +* parameter : +* +* p : basicPart internal +* +* returns : MIME_OK if successful +*/ +int mime_basicPart_internal_free (mime_basicPart_internal_t * p) +{ + if (p == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (p->szMessageBody != NULL) + { + free (p->szMessageBody); + p->szMessageBody = NULL; + } + + if (p->pTheDataStream != NULL) + { + p->pTheDataStream->close (p->pTheDataStream->rock); + p->pTheDataStream = NULL; + } + + free (p); + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* Free message pointed to by the "pNext" pointer. +* +* parameter : +* +* returns : MIME_OK if successful +*/ +/* +int next_free( void *p, mime_content_type nContentType ) +{ + if ( p == NULL ) + { +#ifdef DEBUG + errorLog( "next_free()", MIME_ERR_INVALIDPARAM ); +#endif + return MIME_ERR_INVALIDPARAM; + } + + if ( nContentType == MIME_CONTENT_MESSAGEPART ) + mime_messagePart_free( (mime_messagePart_t *) p ); + + else if ( nContentType == MIME_CONTENT_MULTIPART ) + mime_multiPart_free( (mime_multiPart_t *) p ); + + else if ( bIsBasicPart( nContentType ) ) + mime_basicPart_free( (mime_basicPart_t *) p ); + + return MIME_OK; +} +*/ + + + +/* +* parameter : +* +* p : original mime_basicPart_internal +* +* returns : new mime_basicPart_internal +*/ +mime_basicPart_internal_t * mime_basicPart_internal_clone (mime_basicPart_internal_t *p) +{ + mime_basicPart_internal_t *pNew = NULL; + void *buffer; + + if ( p == NULL ) + { + return NULL; + } + + pNew = mime_basicPart_internal_new(); + + if ( pNew != NULL ) + { + if (p->szMessageBody != NULL) + { + buffer = (void *) malloc( p->nMessageSize + 1 ); + + if ( buffer == NULL ) + { + mime_basicPart_internal_free( pNew ); + + return NULL; + } + + memset (buffer, 0, p->nMessageSize + 1 ); + memcpy( buffer, p->szMessageBody, p->nMessageSize ); + pNew->szMessageBody = buffer; + } + else + pNew->szMessageBody = NULL; + + pNew->nMessageSize = p->nMessageSize; + pNew->nRawMessageSize = p->nRawMessageSize; + pNew->nStartMessageDataIndex = p->nStartMessageDataIndex; + pNew->nEndMessageDataIndex = p->nEndMessageDataIndex; + pNew->pUserObject = p->pUserObject; + } + + return pNew; +} + + + +/* +* carsonl, jan 8,98 +* set dynamic buffer size +* +* parameter : +* +* p : mime parser +* nSize : new buffer size +* +* returns : none +* NOTE : this is useful for speed optimization if you know what the message size ahead of time +*/ +/* +void setDynamicBufferSize( mimeParser_t *p, int nSize ) +{ + char *szNewBuffer; + + if ( p == NULL && nSize <= 0 ) + { +#ifdef DEBUG + errorLog( "setDynamicBufferSize()", MIME_ERR_INVALIDPARAM ); +#endif + return; + } + + if ( p->szDynamicBuffer == NULL ) + { + p->szDynamicBuffer = (char*) malloc( nSize ); + + if ( p->szDynamicBuffer == NULL ) + { +#ifdef DEBUG + errorLog( "setDynamicBufferSize()", MIME_ERR_OUTOFMEMORY ); +#endif + } + + p->nDynamicBufferSize = nSize; + } + + szNewBuffer = (char*) malloc( nSize ); + + if ( szNewBuffer == NULL ) + { +#ifdef DEBUG + errorLog( "setDynamicBufferSize()", MIME_ERR_OUTOFMEMORY ); +#endif + return; + } + + memcpy( szNewBuffer, p->szDynamicBuffer, p->nDynamicBufferSize > nSize ? nSize : p->nDynamicBufferSize ); + + p->szDynamicBuffer = szNewBuffer; + p->nDynamicBufferSize = nSize; +} +*/ + + + +/* ----------------------------------- */ + + + + +/* +* Constructor +* return NULL if unsuccessful. +* +* parameter : +* +* returns : new instance of basicPart +*/ +mime_basicPart_t *mime_basicPart_new() +{ + mime_basicPart_t *p = (mime_basicPart_t *) malloc( sizeof( mime_basicPart_t ) ); + + if ( p == NULL ) + { + return NULL; + } + else + memset (p, 0, sizeof (mime_basicPart_t)); + + p->content_description = NULL; + p->content_disposition = MIME_DISPOSITION_UNINITIALIZED; + p->content_disp_params = NULL; + p->content_type = MIME_BASICPART; + p->content_subtype = NULL; + p->content_type_params = NULL; + p->contentID = NULL; + p->extra_headers = NULL; + p->contentMD5 = NULL; + p->encoding_type = MIME_ENCODING_UNINITIALIZED; + p->pInternal = (void *) mime_basicPart_internal_new(); + + return p; +} + + + + +/* +* destructor +* +* parameter : +* +* p : basicPart +* +* returns : MIME_OK if successful +* NOTE : will also free it's internal structure as well +*/ +int mime_basicPart_free (mime_basicPart_t *p) +{ + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( p->content_description != NULL ) + { + free (p->content_description); + p->content_description = NULL; + } + + if ( p->content_disp_params != NULL ) + { + free( p->content_disp_params ); + p->content_disp_params = NULL; + } + + if ( p->content_subtype != NULL ) + { + free( p->content_subtype ); + p->content_subtype = NULL; + } + + if ( p->content_type_params != NULL ) + { + free( p->content_type_params ); + p->content_type_params = NULL; + } + + if ( p->contentID != NULL ) + { + free( p->contentID ); + p->contentID = NULL; + } + + if ( p->extra_headers != NULL ) + { + mime_header_freeAll( p->extra_headers ); + p->extra_headers = NULL; + } + + if ( p->contentMD5 != NULL ) + { + free( p->contentMD5 ); + p->contentMD5 = NULL; + } + + if ( p->pInternal != NULL ) + { + mime_basicPart_internal_free( (mime_basicPart_internal_t *) p->pInternal ); + p->pInternal = NULL; + } + + free( p ); + + return MIME_OK; +} + + + + +/* +* carsonl, jan 8,98 +* Read from input stream into a basicPart +* +* parameter : +* +* pInput_stream : input stream +* ppBasicPart : (output) basicPart +* +* returns : MIME_OK if successful +*/ +/* +int mime_basicPart_decode( nsmail_inputstream_t *pInput_stream, mime_basicPart_t **ppBasicPart) +{ + mimeParser_t *p; + int nRet = MIME_ERR_OUTOFMEMORY; + + if ( pInput_stream == NULL || ppBasicPart == NULL ) + { +#ifdef DEBUG + errorLog( "mime_basicPart_decode()", MIME_ERR_INVALIDPARAM ); +#endif + return MIME_ERR_INVALIDPARAM; + } + + p = mimeParser_new_internal(); + + if ( p != NULL ) + { + p->bDeleteMimeMessage = FALSE; + nRet = mimeParser_parseMimeMessage(p, pInput_stream, NULL, 0, MIME_CONTENT_TEXT, (void **) ppBasicPart); + mimeParser_free (p); + } + + return nRet; +} +*/ + + + +/* +* Create new instance and clone +* +* parameter : +* +* p : original basicPart +* +* returns : new instance of basicPart +*/ +mime_basicPart_t *mime_basicPart_clone( mime_basicPart_t *p ) +{ + mime_basicPart_t *pNew = NULL; + + outmsg("In mime_basicPart_clone()"); + + if ( p == NULL ) + { + return NULL; + } + + outmsg("doing mime_basicPart_new()"); + + pNew = mime_basicPart_new(); + + if ( pNew != NULL ) + { + outmsg("Copying content* fileds etc. to new basicPart"); + + pNew->content_description = szStringClone( p->content_description ); + pNew->content_disposition = p->content_disposition; + pNew->content_disp_params = szStringClone( p->content_disp_params ); + pNew->content_type = p->content_type; + pNew->content_subtype = szStringClone( p->content_subtype ); + pNew->content_type_params = szStringClone( p->content_type_params ); + pNew->contentID = szStringClone( p->contentID ); + pNew->extra_headers = mime_header_clone( p->extra_headers ); + pNew->contentMD5 = szStringClone( p->contentMD5 ); + pNew->encoding_type = p->encoding_type; + + outmsg("doing mime_basicPart_new()"); + + pNew->pInternal = mime_basicPart_internal_clone( p->pInternal ); + } + + return pNew; +} + + + +/* ----------------------------------- */ + + + + +/* +* Constructor. +* Return NULL if unsuccessful. +* +* parameter : +* +* returns : new instance of messagePart +*/ +mime_messagePart_t *mime_messagePart_new() +{ + mime_messagePart_t *p = (mime_messagePart_t *) malloc( sizeof( mime_messagePart_t ) ); + + if ( p == NULL ) + { + return NULL; + } + else + memset (p, 0, sizeof (mime_messagePart_t)); + + p->content_description = NULL; + p->content_disposition = MIME_DISPOSITION_UNINITIALIZED; + p->encoding_type = MIME_ENCODING_UNINITIALIZED; + p->content_disp_params = NULL; + p->content_type = MIME_MESSAGEPART; + p->content_subtype = NULL; + p->content_type_params = NULL; + p->contentID = NULL; + p->extra_headers = NULL; + p->pInternal = (void *) mime_messagePart_internal_new(); + + return p; +} + + +/* +* destructor +* +* parameter : +* +* p : messagePart to free +* +* returns : MIME_OK if successful +*/ +int mime_messagePart_free( mime_messagePart_t *p ) +{ + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( p->content_description != NULL ) + { + free (p->content_description); + p->content_description = NULL; + } + + if ( p->content_disp_params != NULL ) + { + free( p->content_disp_params ); + p->content_disp_params = NULL; + } + + if ( p->content_subtype != NULL ) + { + free( p->content_subtype ); + p->content_subtype = NULL; + } + + if ( p->content_type_params != NULL ) + { + free( p->content_type_params ); + p->content_type_params = NULL; + } + + if ( p->contentID != NULL ) + { + free( p->contentID ); + p->contentID = NULL; + } + + if ( p->extra_headers != NULL ) + { + mime_header_freeAll( p->extra_headers ); + p->extra_headers = NULL; + } + + if ( p->pInternal != NULL ) + { + mime_messagePart_internal_free ((mime_messagePart_internal_t *) p->pInternal); + p->pInternal = NULL; + } + + free( p ); + + return MIME_OK; +} + + + +/* +* read from input stream into a messagepart +* +* parameter : +* +* pInput_stream : input stream +* ppMessagePart : (output) decoded and populated messagePart +* +* returns : MIME_OK if successful +*/ +/* +int mime_messagePart_decode( nsmail_inputstream_t *pInput_stream, mime_messagePart_t ** ppMessagePart) +{ + mimeParser_t *p; + int nRet = MIME_ERR_OUTOFMEMORY; + + if ( pInput_stream == NULL || ppMessagePart == NULL ) + { +#ifdef DEBUG + errorLog( "mime_messagePart_decode()", MIME_ERR_INVALIDPARAM ); +#endif + return MIME_ERR_INVALIDPARAM; + } + + p = mimeParser_new_internal(); + + if ( p != NULL ) + { + p->bDeleteMimeMessage = FALSE; + nRet = mimeParser_parseMimeMessage (p, pInput_stream, NULL, 0, MIME_CONTENT_MESSAGEPART, (void **) ppMessagePart); + + mimeParser_free( p ); + } + + return nRet; +} +*/ + + + +/* +* parameter : +* +* p : original messagePart +* +* returns : new instance of messagePart +*/ +mime_messagePart_t *mime_messagePart_clone (mime_messagePart_t * p) +{ + mime_messagePart_t *pNew = NULL; + + if (p == NULL) + { + return NULL; + } + + pNew = mime_messagePart_new(); + + if ( pNew != NULL ) + { + pNew->content_description = szStringClone( p->content_description ); + pNew->content_disposition = p->content_disposition; + pNew->content_disp_params = szStringClone( p->content_disp_params ); + pNew->content_type = p->content_type; + pNew->content_subtype = szStringClone( p->content_subtype ); + pNew->content_type_params = szStringClone( p->content_type_params ); + pNew->contentID = szStringClone( p->contentID ); + pNew->encoding_type = p->encoding_type; + pNew->extra_headers = mime_header_clone( p->extra_headers ); + pNew->extern_headers = mime_header_clone( p->extern_headers ); + pNew->pInternal = mime_messagePart_internal_clone( p->pInternal ); + } + + return pNew; +} + + + +/* +* carsonl, jan 8,98 +* test if messagePart have a part attached to itself +* +* parameter : +* +* pMessagePart : messagePart +* +* returns : return TRUE if have part, FALSE if no part +*/ +BOOLEAN mime_messagePart_isEmpty( mime_messagePart_t *pMessagePart ) +{ + mime_messagePart_internal_t *p; + + if ( pMessagePart == NULL ) + { + return TRUE; + } + + p = (mime_messagePart_internal_t *) pMessagePart->pInternal; + + if ( p != NULL && p->pTheMessage != NULL ) + { + return mime_message_isEmpty( p->pTheMessage ); + } + + return TRUE; +} + + + + +/* ----------------------------------- */ + + + + +/* +* parameter : none +* +* returns : new instance if successful, Return NULL if unsuccessful. +*/ +mime_messagePart_internal_t *mime_messagePart_internal_new() +{ + mime_messagePart_internal_t *p = (mime_messagePart_internal_t *) + malloc (sizeof (mime_messagePart_internal_t)); + + if (p == NULL) + { + return NULL; + } + else + memset (p, 0, sizeof (mime_messagePart_internal_t)); + + p->pTheMessage = NULL; + p->pUserObject = NULL; + + return p; +} + + + + +/* +* parameter : +* +* p : messagePart_internal +* +* returns : MIME_OK if successful +*/ +int mime_messagePart_internal_free (mime_messagePart_internal_t * p) +{ + if (p == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (p->pTheMessage != NULL) + { + mime_message_free (p->pTheMessage); + p->pTheMessage = NULL; + } + + free (p); + + return MIME_OK; +} + + + + +/* +* parameter : +* +* p : original messagePart_internal +* +* returns : new instance of messagePart_internal +*/ +mime_messagePart_internal_t * mime_messagePart_internal_clone (mime_messagePart_internal_t * p) +{ + mime_messagePart_internal_t *pNew = NULL; + + if (p == NULL) + { + return NULL; + } + + pNew = mime_messagePart_internal_new(); + + if (pNew == NULL) + { + return NULL; + } + + if (p->pTheMessage != NULL) + { + pNew->pTheMessage = mime_message_clone (p->pTheMessage); + pNew->pUserObject = p->pUserObject; + } + + return pNew; +} + + + + +/* ----------------------------------- */ + + + +/* +* constructor +* +* parameter : +* +* returns : new instance, NULL if unsuccessful +*/ +mime_multiPart_t *mime_multiPart_new() +{ + mime_multiPart_t *p = (mime_multiPart_t *) malloc( sizeof( mime_multiPart_t ) ); + mime_multiPart_internal_t * pInternal; + + if ( p == NULL ) + { + return NULL; + } + else + memset (p, 0, sizeof (mime_multiPart_t)); + + p->content_description = NULL; + p->content_disposition = MIME_DISPOSITION_UNINITIALIZED; + p->content_disp_params = NULL; + p->content_type = MIME_MULTIPART; + p->content_subtype = NULL; + p->content_type_params = NULL; + p->contentID = NULL; + p->encoding_type = MIME_ENCODING_UNINITIALIZED; + p->preamble = NULL; + p->extra_headers = NULL; + p->pInternal = (void *) mime_multiPart_internal_new(); + pInternal = (mime_multiPart_internal_t *) p->pInternal; + pInternal->fParsedPart = FALSE; + + return p; +} + + + +/* +* destructor +* +* parameter : +* +* p : multiPart +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_free( mime_multiPart_t *p ) +{ + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( p->content_description != NULL ) + { + free( p->content_description ); + p->content_description = NULL; + } + + if ( p->content_disp_params != NULL ) + { + free( p->content_disp_params ); + p->content_disp_params = NULL; + } + + if ( p->content_subtype != NULL ) + { + free( p->content_subtype ); + p->content_subtype = NULL; + } + + if ( p->content_type_params != NULL ) + { + free( p->content_type_params ); + p->content_type_params = NULL; + } + + if ( p->contentID != NULL ) + { + free( p->contentID ); + p->contentID = NULL; + } + + if (p->preamble != NULL); + { + free(p->preamble); + p->preamble = NULL; + } + + if ( p->extra_headers != NULL ) + { + mime_header_freeAll( p->extra_headers ); + p->extra_headers = NULL; + } + + if ( p->pInternal != NULL ) + { + mime_multiPart_internal_free( (mime_multiPart_internal_t *) p->pInternal ); + p->pInternal = NULL; + } + + free( p ); + + return MIME_OK; +} + + + + +/* +* carsonl, jan 8,98 +* read from inputstream into a multipart +* +* parameter : +* +* pInput_stream : input stream +* ppMultiPart : (output) new instance of multipart, populated with data from inputstream +* +* returns : MIME_OK if successful +*/ +/* +int mime_multiPart_decode( nsmail_inputstream_t *pInput_stream, mime_multiPart_t ** ppMultiPart) +{ + mimeParser_t *p; + int nRet; + + if ( pInput_stream == NULL || ppMultiPart == NULL ) + { +#ifdef DEBUG + errorLog( "mime_multiPart_decode()", MIME_ERR_INVALIDPARAM ); +#endif + return MIME_ERR_INVALIDPARAM; + } + + p = mimeParser_new_internal(); + + if ( p != NULL ) + { + p->bDeleteMimeMessage = FALSE; + nRet = mimeParser_parseMimeMessage (p, pInput_stream, NULL, 0, MIME_CONTENT_MULTIPART, (void **) ppMultiPart); + + mimeParser_free (p); + return nRet; + } + + return MIME_ERR_OUTOFMEMORY; +} +*/ + + + +/* +* create new instance and clone +* +* parameter : +* +* p : multiPart +* +* returns : MIME_OK new instance of multipart +*/ +mime_multiPart_t *mime_multiPart_clone( mime_multiPart_t *p ) +{ + mime_multiPart_t *pNew = NULL; + + if ( p == NULL ) + { + return NULL; + } + + pNew = mime_multiPart_new(); + + if ( pNew != NULL ) + { + pNew->content_description = szStringClone( p->content_description ); + pNew->content_disposition = p->content_disposition; + pNew->content_disp_params = szStringClone( p->content_disp_params ); + pNew->content_type = p->content_type; + pNew->content_subtype = szStringClone( p->content_subtype ); + pNew->content_type_params = szStringClone( p->content_type_params ); + pNew->contentID = szStringClone( p->contentID ); + pNew->preamble = szStringClone( p->preamble ); + pNew->encoding_type = p->encoding_type; + pNew->extra_headers = mime_header_clone( p->extra_headers ); + pNew->pInternal = mime_multiPart_internal_clone( p->pInternal ); + } + + return pNew; +} + + + +/* +* Prasad, jan 8,98 +* Add a part to multipart +* Uses new mime_mp_partInfo_t of mime_multiPart_internal_t +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_addPart (mime_multiPart_t *pMultiPart, + void * pMessage, + mime_content_type nContentType, + int * pIndex_assigned ) +{ + return mime_multiPart_addPart_clonable (pMultiPart, pMessage, + nContentType, TRUE, pIndex_assigned); +} + + + +/* +* Prasad, jan 8,98 +* Add a part to multipart +* Uses new mime_mp_partInfo_t of mime_multiPart_internal_t +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_addPart_clonable (mime_multiPart_t *pMultiPart, + void * pMessage, + mime_content_type nContentType, + BOOLEAN clone, + int * pIndex_assigned) +{ + mime_multiPart_internal_t *pMultiPartInternal; + mime_mp_partInfo_t * pPartInfo; + + mime_basicPart_t * pBasicPart2; + mime_multiPart_t * pMultiPart2; + mime_messagePart_t * pMessagePart2; + + if ( pMultiPart == NULL || pMessage == NULL || pIndex_assigned == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pMultiPart->pInternal == NULL) + { + /* Allocate a new one */ + pMultiPart->pInternal = mime_multiPart_internal_new(); + } + + pMultiPartInternal = (mime_multiPart_internal_t *) pMultiPart->pInternal; + *pIndex_assigned = ++(pMultiPartInternal->nPartCount); + + pPartInfo = &pMultiPartInternal->partInfo [*pIndex_assigned]; + pPartInfo->nContentType = nContentType; + pPartInfo->pThePart = clone ? mime_clone_any_part (pMessage, nContentType) : pMessage; + + if ( bIsBasicPart( nContentType ) ) + { + pBasicPart2 = (mime_basicPart_t *) pMessage; + + if (pBasicPart2->contentID != NULL) + pPartInfo->contentID = strdup (pBasicPart2->contentID); + else + pPartInfo->contentID = NULL; + } + + else if ( nContentType == MIME_CONTENT_MULTIPART ) + { + pMultiPart2 = (mime_multiPart_t *) pMessage; + + if (pMultiPart2->contentID != NULL) + pPartInfo->contentID = strdup (pMultiPart2->contentID); + else + pPartInfo->contentID = NULL; + } + + else if ( nContentType == MIME_CONTENT_MESSAGEPART ) + { + pMessagePart2 = (mime_messagePart_t *) pMessage; + + if (pMessagePart2->contentID != NULL) + pPartInfo->contentID = strdup (pMessagePart2->contentID); + else + pPartInfo->contentID = NULL; + } + + return MIME_OK; +} + + + + +/* +* Helper function to get part of a multipart message +* +* Will use contentID if index < 0 +* else use index if contentID == NULL +* +* parameter : +* +* pMultiPart : multiPart +* index : which part ( offset of zero ) do you want to retrieve +* contentID : (output) content ID of part +* pContentType : (output) content type of part +* ppTheBodyPart : (output) the part itself +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_getPart2 (mime_multiPart_t *pMultiPart, + int index, + char *contentID, + mime_content_type *pContentType, + void **ppTheBodyPart) +{ + mime_content_type nContentType; + mime_mp_partInfo_t * pPartInfo; + mime_multiPart_internal_t * pMultiPartInternal; + + int nIndex; + BOOLEAN bTestForIndex; + BOOLEAN bTestForContentID; + + if (pMultiPart == NULL || pContentType == NULL || ppTheBodyPart == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + bTestForIndex = index > 0 ? TRUE : FALSE; + bTestForContentID = !bTestForIndex && contentID != NULL ? TRUE : FALSE; + + if (bTestForIndex == FALSE && bTestForContentID == FALSE) + { + return MIME_ERR_INVALIDPARAM; + } + + pMultiPartInternal = (mime_multiPart_internal_t *) pMultiPart->pInternal; + + if (pMultiPartInternal == NULL) + { + return MIME_ERR_UNINITIALIZED; + } + + /* make sure index is not out of range */ + if (bTestForIndex == TRUE && pMultiPartInternal->nPartCount < index) + { + return MIME_ERR_INVALID_INDEX; + } + + if (bTestForIndex) /* return based on Index */ + { + pPartInfo = &pMultiPartInternal->partInfo [index]; + nContentType = pPartInfo->nContentType; + *pContentType = nContentType; + + if ( bIsBasicPart( nContentType ) ) + { + *ppTheBodyPart = mime_basicPart_clone ((mime_basicPart_t *) pPartInfo->pThePart); + return MIME_OK; + } + + else if ( nContentType == MIME_CONTENT_MULTIPART ) + { + *ppTheBodyPart = mime_multiPart_clone ((mime_multiPart_t *) pPartInfo->pThePart); + return MIME_OK; + } + + else if ( nContentType == MIME_CONTENT_MESSAGEPART ) + { + *ppTheBodyPart = mime_messagePart_clone( (mime_messagePart_t *) pPartInfo->pThePart ); + return MIME_OK; + } + + else + { + return MIME_ERR_NOT_FOUND; + } + + } /* bTestForIndex */ + + /* match based on contentID and return */ + + for (nIndex = 1; nIndex <= pMultiPartInternal->nPartCount; nIndex++) + { + pPartInfo = &pMultiPartInternal->partInfo [nIndex]; + + if (bStringEquals (pPartInfo->contentID, contentID)) + { + *pContentType = pPartInfo->nContentType; + + if ( bIsBasicPart( pPartInfo->nContentType ) ) + { + *ppTheBodyPart = mime_basicPart_clone (pPartInfo->pThePart); + return MIME_OK; + } + + else if ( pPartInfo->nContentType == MIME_CONTENT_MULTIPART ) + { + *ppTheBodyPart = mime_multiPart_clone (pPartInfo->pThePart); + return MIME_OK; + } + + else if ( pPartInfo->nContentType == MIME_CONTENT_MESSAGEPART ) + { + *ppTheBodyPart = mime_messagePart_clone (pPartInfo->pThePart); + return MIME_OK; + } + + else + { + return MIME_ERR_UNEXPECTED; + } + + } /* if */ + } + + return MIME_ERR_NOT_FOUND; +} + + + +/* ----------------------------------- */ + + + + +/* +* Constructor +* +* parameter : none +* +* returns : new instance of multiPart_internal, NULL if unsuccessful. +*/ +mime_multiPart_internal_t *mime_multiPart_internal_new() +{ + mime_multiPart_internal_t * p = (mime_multiPart_internal_t *) + malloc (sizeof (mime_multiPart_internal_t)); + + if ( p == NULL ) + { + return NULL; + } + else + memset (p, 0, sizeof (mime_multiPart_internal_t)); + + p->nPartCount = 0; + p->szBoundary = NULL; + p->pUserObject = NULL; + + return p; +} + + + +/* +* destructor +* +* parameter : +* +* p : multiPart_internal +* +* returns : MIME_OK if successful +*/ +int mime_multiPart_internal_free (mime_multiPart_internal_t * p) +{ + int nIndex; + mime_mp_partInfo_t * pPartInfo; + + if (p == NULL) + { + return MIME_OK; + } + + if (p->nPartCount > 0) + { + for (nIndex = 1; nIndex <= p->nPartCount; nIndex++) + { + pPartInfo = &p->partInfo [nIndex]; + + if (pPartInfo->contentID != NULL) + { + free (pPartInfo->contentID); + pPartInfo->contentID = NULL; + } + + if ( bIsBasicPart( pPartInfo->nContentType ) ) + mime_basicPart_free ((mime_basicPart_t *) pPartInfo->pThePart); + + else if ( pPartInfo->nContentType == MIME_CONTENT_MULTIPART ) + mime_multiPart_free ((mime_multiPart_t *) pPartInfo->pThePart); + + else if ( pPartInfo->nContentType == MIME_CONTENT_MESSAGEPART ) + mime_messagePart_free ((mime_messagePart_t *) pPartInfo->pThePart); + + else + { + return MIME_ERR_UNEXPECTED; + } + + pPartInfo->pThePart = NULL; + + } /* for */ + } /* if */ + + if ( p->szBoundary != NULL ) + free( p->szBoundary ); + + free (p); + + return MIME_OK; +} + + + + +/* +* Clone a new instance of multiPart_internal +* +* parameter : +* +* p : original multiPart_internal +* +* returns : new instance of multiPart_internal +*/ +mime_multiPart_internal_t * mime_multiPart_internal_clone (mime_multiPart_internal_t * p) +{ + int nIndex; + mime_mp_partInfo_t * pPartInfo; + mime_mp_partInfo_t * pPartInfoNew; + mime_multiPart_internal_t *pNew = NULL; + + if (p == NULL) + { + return NULL; + } + + pNew = mime_multiPart_internal_new(); + + if (pNew == NULL) + return NULL; + + pNew->nPartCount = p->nPartCount; + pNew->szBoundary = szStringClone( p->szBoundary ); + pNew->pUserObject = p->pUserObject; + + if (p->nPartCount > 0) + { + for (nIndex = 1; nIndex <= p->nPartCount; nIndex++) + { + pPartInfo = &p->partInfo [nIndex]; + pPartInfoNew = &pNew->partInfo [nIndex]; + + pPartInfoNew->nContentType = pPartInfo->nContentType; + + if (pPartInfo->contentID != NULL) + { + pPartInfoNew->contentID = strdup (pPartInfo->contentID); + } + + if ( bIsBasicPart( pPartInfo->nContentType ) ) + pPartInfoNew->pThePart = (void *) mime_basicPart_clone ((mime_basicPart_t *) pPartInfo->pThePart); + + else if ( pPartInfo->nContentType == MIME_CONTENT_MULTIPART ) + pPartInfoNew->pThePart = (void *) mime_multiPart_clone ((mime_multiPart_t *) pPartInfo->pThePart); + + else if ( pPartInfo->nContentType == MIME_CONTENT_MESSAGEPART ) + pPartInfoNew->pThePart = (void *) mime_messagePart_clone ((mime_messagePart_t *) pPartInfo->pThePart); + + else + return pNew; + + } /* for */ + } /* if */ + + return pNew; +} + + + +/* ----------------------------------- */ + + + +/* ORIGINAL ONE */ +/* return NULL if unsuccessful + * mime_message_t *mime_message_new() + * { + * mime_message_t *pMimeMessage = (mime_message_t *) malloc( sizeof( mime_message_t ) ); + * + * if ( pMimeMessage != NULL ) + * { + * pMimeMessage->rfc822_headers = NULL; + * pMimeMessage->pInternal = (void *) mime_message_internal_new(); + * } + * + * return pMimeMessage; + * } + */ + + +/* New one! Moved to mime.c */ +/* return NULL if unsuccessful */ +/* + * mime_message_t *mime_message_new( mimeDataSink_t *pDataSink ) + * { + * mime_message_internal_t *pMimeMessageInternal = NULL; + * mime_message_t *pMimeMessage = (mime_message_t *) malloc( sizeof( mime_message_t ) ); + * + * if ( pMimeMessage != NULL ) + * { + * pMimeMessage->rfc822_headers = NULL; + * pMimeMessage->pInternal = (void *) mime_message_internal_new(); + * + * pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + * + * if ( pMimeMessageInternal != NULL ) + * pMimeMessageInternal->pDataSink = pDataSink; + * } + * + * return pMimeMessage; + * } + */ + + +/* +* destructor +* +* parameter : +* +* p : mime message +* +* returns : MIME_OK if successful +*/ +int mime_message_free( mime_message_t *p ) +{ + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( p->rfc822_headers != NULL ) + { + mime_header_freeAll( p->rfc822_headers ); + p->rfc822_headers = NULL; + } + + if ( p->pInternal != NULL ) + { + mime_message_internal_free( (mime_message_internal_t *) p->pInternal ); + p->pInternal = NULL; + } + + free( p ); + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* read from inputstream into a mime_message +* +* parameter : +* +* pInput_stream : input stream +* ppMessage : (output) new instance of mime message +* +* returns : MIME_OK if successful +*/ +/* +int mime_message_decode( nsmail_inputstream_t *pInput_stream, mime_message_t ** ppMessage) +{ + mimeParser_t *p; + int nRet = MIME_ERR_OUTOFMEMORY; + + if ( pInput_stream == NULL || ppMessage == NULL ) + { +#ifdef DEBUG + errorLog( "mime_message_decode()", MIME_ERR_INVALIDPARAM ); +#endif + return MIME_ERR_INVALIDPARAM; + } + + p = mimeParser_new_internal(); + + if ( p != NULL ) + { + p->bDeleteMimeMessage = FALSE; + nRet = mimeParser_parseMimeMessage (p, pInput_stream, NULL, 0, 0, (void **)ppMessage); + mimeParser_free( p ); + } + + return nRet; +} +*/ + + + +/* +* create new instance and clone +* +* parameter : +* +* p : original mime message +* +* returns : new instance of mime message +*/ +struct mime_message *mime_message_clone( struct mime_message *p ) +{ + mime_message_t *pNew = NULL; + + if ( p == NULL ) + { + return NULL; + } + + pNew = mime_message_new( NULL ); + + if ( pNew != NULL ) + { + pNew->rfc822_headers = mime_header_clone( p->rfc822_headers ); + pNew->pInternal = mime_message_internal_clone( p->pInternal ); + } + + return pNew; +} + + + +/* ----------------------------------- */ + + + +/* +* constructor +* +* parameter : +* +* returns : new instance, NULL if unsuccessful +*/ +mime_message_internal_t *mime_message_internal_new() +{ + mime_message_internal_t *p = (mime_message_internal_t *) malloc( sizeof( mime_message_internal_t ) ); + + if ( p == NULL ) + { + return NULL; + } + else + memset (p, 0, sizeof (mime_message_internal_t)); + + p->pMimeBasicPart = NULL; + p->pMimeMultiPart = NULL; + p->pMimeMessagePart = NULL; + p->pUserObject = NULL; + p->pDataSink = NULL; +/* p->pParser = NULL; */ + + return p; +} + + + +/* +* destructor +* +* parameter : +* +* p : mime message internal +* +* returns : MIME_OK if successful +*/ +int mime_message_internal_free( mime_message_internal_t *p ) +{ + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( p->pMimeBasicPart != NULL ) + { + mime_basicPart_free( p->pMimeBasicPart ); + p->pMimeBasicPart = NULL; + } + + if ( p->pMimeMultiPart != NULL ) + { + mime_multiPart_free( p->pMimeMultiPart ); + p->pMimeMultiPart = NULL; + } + + if ( p->pMimeMessagePart != NULL ) + { + mime_messagePart_free( p->pMimeMessagePart ); + p->pMimeMessagePart = NULL; + } +/* + if ( p->pParser != NULL ) + { + mimeParser_free( p->pParser ); + p->pParser = NULL; + } +*/ + free( p ); + + return MIME_OK; +} + + + +/* +* create new instance and clone +* +* parameter : +* +* p : original mime message internal +* +* returns : new instance of mime message internal +*/ +mime_message_internal_t *mime_message_internal_clone( mime_message_internal_t *p ) +{ + mime_message_internal_t *pNew = NULL; + + if ( p == NULL ) + { + return NULL; + } + + pNew = mime_message_internal_new(); + + if ( pNew != NULL ) + { + if ( p->pMimeBasicPart != NULL ) + pNew->pMimeBasicPart = mime_basicPart_clone( p->pMimeBasicPart ); + + else if ( p->pMimeMultiPart != NULL ) + pNew->pMimeMultiPart = mime_multiPart_clone( p->pMimeMultiPart ); + + else if ( p->pMimeMessagePart != NULL ) + pNew->pMimeMessagePart = mime_messagePart_clone( p->pMimeMessagePart ); + + pNew->pUserObject = p->pUserObject; + pNew->pDataSink = p->pDataSink; + } + + return pNew; +} + + +/* Prasad +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_message_addBasicPart_clonable( mime_message_t * pMessage, mime_basicPart_t * pBasicPart, BOOLEAN clone ) +{ + mime_message_internal_t * pInternal; + + outmsg("In mime_message_addBasicPart_clonable"); + + if (pMessage == NULL || pBasicPart == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pMessage->pInternal == NULL) + { + outmsg("pMessage->pInternal == NULL"); + + /* allocate a new one. Never had a body */ + pMessage->pInternal = (void *) mime_message_internal_new(); + + if (pMessage->pInternal == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if (pInternal->pMimeBasicPart != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + if (pInternal->pMimeMultiPart != NULL || pInternal->pMimeMessagePart != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + outmsg("Adding the basicPart to the message"); + + pInternal->pMimeBasicPart = clone ? mime_basicPart_clone (pBasicPart) : pBasicPart; + + if (pInternal->pMimeBasicPart == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + outmsg("returning from mime_message_addBasicPart_clonable"); + + return MIME_OK; +} + + +/* Prasad +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_message_addMessagePart_clonable( mime_message_t * pMessage, mime_messagePart_t * pMessagePart, BOOLEAN clone ) +{ + mime_message_internal_t * pInternal; + + if (pMessage == NULL || pMessagePart == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pMessage->pInternal == NULL) + { + /* allocate a new one. Never had a body */ + pMessage->pInternal = (void *) mime_message_internal_new(); + + if (pMessage->pInternal == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if (pInternal->pMimeBasicPart != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + if (pInternal->pMimeMultiPart != NULL || pInternal->pMimeMessagePart != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + pInternal->pMimeMessagePart = clone ? mime_messagePart_clone (pMessagePart) : pMessagePart ; + + if (pInternal->pMimeMessagePart == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + return MIME_OK; +} + + +/* Prasad +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_message_addMultiPart_clonable( mime_message_t * pMessage, mime_multiPart_t * pMultiPart, BOOLEAN clone ) +{ + mime_message_internal_t * pInternal; + + if (pMessage == NULL || pMultiPart == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if (pMessage->pInternal == NULL) + { + /* allocate a new one. Never had a body */ + pMessage->pInternal = (void *) mime_message_internal_new(); + + if (pMessage->pInternal == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if (pInternal->pMimeBasicPart != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + if (pInternal->pMimeMultiPart != NULL || pInternal->pMimeMessagePart != NULL) + { + return MIME_ERR_ALREADY_SET; + } + + pInternal->pMimeMultiPart = clone ? mime_multiPart_clone (pMultiPart) : pMultiPart; + + if (pInternal->pMimeMultiPart == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + return MIME_OK; +} + + + +/* test is there is any part inside this message +* return TRUE if have parts +* return FALSE if empty or no parts +*/ +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +BOOLEAN mime_message_isEmpty( mime_message_t *pMessage ) +{ + mime_message_internal_t * pInternal; + + if ( pMessage == NULL ) + { + return TRUE; + } + + pInternal = (mime_message_internal_t *) pMessage->pInternal; + + if ( pInternal == NULL && + ( pInternal->pMimeBasicPart != NULL || + pInternal->pMimeMultiPart != NULL || + pInternal->pMimeMessagePart != NULL ) ) + + { + return FALSE; + } + + return TRUE; +} + + + + +/**********************************************************************************/ + + + + +/* translate encoding type to an integer */ +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_translateMimeEncodingType( char *s ) +{ + if ( s == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( bStringEquals( s, "base64" ) ) + return MIME_ENCODING_BASE64; + + else if ( bStringEquals( s, "qp" ) || bStringEquals( s, "quoted-printable" ) ) + return MIME_ENCODING_QP; + + else if ( bStringEquals( s, "7bit" ) ) + return MIME_ENCODING_7BIT; + + else if ( bStringEquals( s, "8bit" ) ) + return MIME_ENCODING_8BIT; + + else if ( bStringEquals( s, "binary" ) ) + return MIME_ENCODING_BINARY; + + return MIME_ENCODING_7BIT; +} + + +/* translate disposition type to an integer */ +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mime_translateDispType( char *s, char **ppParam ) +{ + if ( s == NULL || ppParam == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( bStringEquals( s, "inline" ) ) + { + *ppParam = strlen( s ) >= 8 ? &s[7] : NULL; + return MIME_DISPOSITION_INLINE; + } + + else if ( bStringEquals( s, "attachment" ) ) + { + *ppParam = strlen( s ) >= 12 ? &s[11] : NULL; + return MIME_DISPOSITION_ATTACHMENT; + } + + *ppParam = strlen( s ) >= 8 ? &s[7] : NULL; + + return MIME_DISPOSITION_INLINE; +} + + + +/* -------------------------------------------------- */ + + + +/* used by parser */ +/* constructor */ +/* return NULL if failed */ +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +mimeInfo_t *mimeInfo_new() +{ + mimeInfo_t *p = (mimeInfo_t *) malloc( sizeof( mimeInfo_t ) ); + + if ( p != NULL ) + { + p->nType = 0; + p->szName = NULL; + p->szValue = NULL; + p->pVectorParam = NULL; + } + else + memset (p, 0, sizeof (mimeInfo_t)); + + return p; +} + + + +/* destructor */ +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mimeInfo_free( mimeInfo_t *p ) +{ + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( p->szName != NULL ) + { + free( p->szName ); + p->szName = NULL; + } + + if ( p->szValue != NULL ) + { + free( p->szValue ); + p->szValue = NULL; + } + + if ( p->pVectorParam != NULL ) + { + Vector_free( p->pVectorParam ); + p->pVectorParam = NULL; + } + + if ( p != NULL ) + free( p ); + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mimeInfo_init( mimeInfo_t *p, int nType1, char *szName1 ) +{ + if ( p == NULL || szName1 == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + p->nType = nType1; + p->szName = szStringClone( szName1 ); + p->pVectorParam = NULL; + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +int mimeInfo_init2( mimeInfo_t *p, int nType1, char *szName1, char *szValue1 ) +{ + if ( p == NULL || szName1 == NULL || szValue1 == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + p->nType = nType1; + p->szName = szStringClone( szName1 ); + p->szValue = szStringClone( szValue1 ); + p->pVectorParam = NULL; + + return MIME_OK; +} + + +/* create new instance and clone */ +/* +* carsonl, jan 8,98 +* +* parameter : +* +* returns : MIME_OK if successful +*/ +mimeInfo_t *mimeInfo_clone( mimeInfo_t *p ) +{ + mimeInfo_t *m = (mimeInfo_t *) malloc( sizeof( mimeInfo_t ) ); + + if ( p == NULL ) + { + free( m ); + + return NULL; + } + + if ( m == NULL ) + { + return NULL; + } + else + memset (m, 0, sizeof (mimeInfo_t)); + + m->nType = p->nType; + + if ( p->szName != NULL && strlen( p->szName ) > 0 ) + m->szName = szStringClone( p->szName ); + else + m->szName = NULL; + + if ( p->szValue != NULL && strlen( p->szValue ) > 0 ) + m->szValue = szStringClone( p->szValue ); + else + m->szValue = NULL; + + m->pVectorParam = p->pVectorParam != NULL ? Vector_clone( p->pVectorParam ) : NULL; + + return m; +} + + +/* + * Prasad + * Utility routine to Clone and returns a body-part of any-type +* +* parameter : +* +* returns : MIME_OK if successful +*/ +void * mime_clone_any_part (void * pThePart, mime_content_type nContentType) +{ + if (pThePart == NULL) + { + return (void *) NULL; + } + + if ( bIsBasicPart( nContentType ) ) + return (void *) mime_basicPart_clone ((mime_basicPart_t * ) pThePart); + + else if ( nContentType == MIME_CONTENT_MULTIPART ) + return (void *) mime_multiPart_clone ((mime_multiPart_t * ) pThePart); + + else if ( nContentType == MIME_CONTENT_MESSAGEPART ) + return (void *) mime_messagePart_clone ((mime_messagePart_t * ) pThePart); + + else + return (void *) NULL; + +} /* mime_clone_any_part() */ + +/* +* carsonl, jan 8,98 +* callback constructor +* +* parameter : +* +* pDataSink : the user's datasink, NULL if don't want to use callbacks +* +* returns : new mimeMessage +*/ +mime_message_t *mime_message_new( mimeDataSink_t *pDataSink ) +{ + mime_message_internal_t *pMimeMessageInternal = NULL; + mime_message_t *pMimeMessage = (mime_message_t *) malloc( sizeof( mime_message_t ) ); + + if ( pMimeMessage != NULL ) + { + pMimeMessage->rfc822_headers = NULL; + pMimeMessage->pInternal = (void *) mime_message_internal_new(); + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessageInternal != NULL ) + pMimeMessageInternal->pDataSink = pDataSink; + } + else + memset (pMimeMessage, 0, sizeof (mime_message_t)); + + return pMimeMessage; +} + diff --git a/msgsdk/C/protocol/MIME/src/mimeparser.c b/msgsdk/C/protocol/MIME/src/mimeparser.c new file mode 100644 index 000000000000..fbda1cef1172 --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/mimeparser.c @@ -0,0 +1,3642 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +/* +* mimeparser.c +* mimeParser is line based parser. It breaks the inputstream into lines and parse line by line. +* +* carsonl, jan 8,97 +* +*/ + +#include +#include +#include + +#include "nsmail.h" +#include "vector.h" +#include "util.h" +#include "mime.h" +#include "mime_internal.h" +#include "mimeparser.h" +#include "mimeparser_internal.h" + +static BOOLEAN m_needEndMultiPart = FALSE; + + +/* --------------------------------- public functions -------------------------------- */ + +/* +* carsonl, jan 8,98 +* default constructor for both callback and regular version +* +* parameter : +* +* mimeDataSink_t *pDataSink : NULL if not using callbacks ( dynamic parsing ) +* pointer to user's datasink if using callbacks +* +* returns +* +* NULL not enough memory +* mimeParser_t * new instance of mimeParser +*/ +/*int mimeDynamicParser_new( mimeDataSink_t *pDataSink, mimeParser_t **pp, BOOLEAN bDecodeData, BOOLEAN bLocalStorage )*/ +int mimeDynamicParser_new( mimeDataSink_t *pDataSink, mimeParser_t **pp) +{ + mimeParser_t *p; + + if ( pDataSink == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + p = mimeParser_new_internal2( NULL ); + + if ( p != NULL ) + { + p->pDataSink = pDataSink; + p->bParseEntireFile = FALSE; + p->bDecodeData = FALSE; + p->bLocalStorage = FALSE; + /*p->bDecodeData = bDecodeData;*/ + /*p->bLocalStorage = bLocalStorage;*/ + + *pp = p; + return MIME_OK; + } + + *pp = NULL; + + return MIME_ERR_OUTOFMEMORY; +} + + + + +/* +* carsonl, jan 8,98 +* ONLY FOR DYNAMIC PARSING +* signal the begin of a parse +* +* parameter : +* +* mimeDataSink_t *pDataSink : NULL if not using callbacks ( dynamic parsing ) +* pointer to user's datasink if using callbacks +* +* returns : error code +*/ +int beginDynamicParse( mimeParser_t *p ) +{ + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* only for callbacks */ + if ( p->pDataSink == null ) + return MIME_ERR_EMPTY_DATASINK; + + p->nLeftoverBytes = 0; + p->out_byte = 0; + p->out_bits = 0; + p->QPNoOfLeftOverBytes = 0; + + if ( p->pDataSink != null ) + { + /* if (IsLocalStorage (p) && p->pDataSink->startMessageLocalStorage != null) */ + /* setUserObject (p->pMimeMessage, MIME_MESSAGE, (p->pDataSink->startMessageLocalStorage)(p->pDataSink, p->pMimeMessage)); */ + /* else */ + if ( p->pDataSink->startMessage != NULL ) + setUserObject( p->pMimeMessage, MIME_MESSAGE, (p->pDataSink->startMessage)(p->pDataSink) ); + } + + return MIME_OK; +} + + + + +/* +* carsonl, jan 8,98 +* ONLY FOR DYNAMIC PARSING +* parse inputstream +* +* parameter : +* +* mimeParser_t *p : pointer to mimeParser +* nsmail_inputstream_t *pInStream :inputstream, user must implement this +* +* returns : error code +* NOTE : all data will be sent to the user via callbacks defined within the datasink +*/ +int dynamicParseInputstream( mimeParser_t *p, nsmail_inputstream_t *pInStream ) +{ + int len, ret; + char buffer[BUFFER_SIZE]; + + + if ( p == NULL || pInStream == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* only for callbacks */ + if ( p->pDataSink == null ) + { + return MIME_ERR_EMPTY_DATASINK; + } + + for (len = pInStream->read (pInStream->rock, buffer, BUFFER_SIZE); + len > 0; + len = pInStream->read (pInStream->rock, buffer, BUFFER_SIZE)) + { + ret = dynamicParse (p, buffer, len); + if (ret != MIME_OK) + return ret; + } + + return MIME_OK; + + /*return mimeParser_parseMimeMessage( p, pInStream, NULL, 0, MIME_PARSE_ALL, NULL );*/ +} + + + + +/* +* carsonl, jan 8,98 +* ONLY FOR DYNAMIC PARSING +* parse data buffer +* +* parameter : +* +* mimeParser_t *p : pointer to mimeParser +* char *pData : data buffer +* int nLen : size of data buffer +* +* returns : nothing +* NOTE : all data will be sent to the user via callbacks defined within the datasink +*/ +int dynamicParse( mimeParser_t *p, char *pData, int nLen ) +{ + int ret; + + if ( p == NULL || pData == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* only for callbacks */ + if ( p->pDataSink == null ) + { + return MIME_ERR_EMPTY_DATASINK; + } + + ret = mimeParser_parseMimeMessage( p, NULL, pData, nLen, MIME_PARSE_ALL, NULL ); + return ret; +} + + + +/* +* carsonl, jan 8,98 +* signal end of parse +* +* parameter : +* +* mimeParser_t *p : pointer to mimeParser +* +* returns : nothing +*/ +int endDynamicParse( mimeParser_t *p ) +{ + mime_message_t *pTmpMsg; + mime_message_internal_t *pTmpMsg_internal; + mime_message_internal_t *pMimeMessage_internal; + mime_basicPart_t *pMimeBasicPart; + mime_multiPart_t *pMimeMultiPart; + mime_messagePart_t *pMimeMessagePart; + mime_basicPart_internal_t *pMimeBasicPart_internal; + mime_multiPart_internal_t *pMimeMultiPart_internal; + mime_messagePart_internal_t *pMimeMessagePart_internal; + char *szBuffer; + int len, i; + + if ( p == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* only for callbacks */ + if ( p->pDataSink == null ) + return MIME_ERR_EMPTY_DATASINK; + + decodeDataBuffer( p ); + + if ( p->pDataSink != NULL ) + { + /* take care of leftover bytes */ + if ((p->nCurrentMessageType == MIME_BASICPART) || (bIsBasicPart(p->nCurrentMessageType))) + { + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart_internal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + /* base64 */ + if ( pMimeBasicPart_internal != NULL ) + { + if ( pMimeBasicPart->encoding_type == MIME_ENCODING_BASE64 && p->out_bits > 0 ) + { + szBuffer = decodeBase64LeftOverBytes( p->out_bits, p->out_byte, &len ); + + if ( szBuffer != NULL ) + { + saveBodyData( p, szBuffer, len, pMimeBasicPart ); + + if ( p->pDataSink != NULL && p->pDataSink->bodyData != NULL ) + (p->pDataSink->bodyData)(p->pDataSink, pMimeBasicPart_internal->pUserObject, szBuffer, len ); + } + } + + /* quoted printable */ + else if ( pMimeBasicPart->encoding_type == MIME_ENCODING_QP && p->out_bits > 0 ) + { + /* will never happen */ + } + + if ( p->pDataSink->bodyData != NULL ) + (p->pDataSink->endBasicPart)(p->pDataSink, pMimeBasicPart_internal->pUserObject ); + } + } + + else if ( p->nCurrentMessageType == MIME_MULTIPART ) + { + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + pMimeMultiPart_internal = (mime_multiPart_internal_t *) pMimeMultiPart->pInternal; + + if ( pMimeMultiPart_internal != NULL && p->pDataSink->endMultiPart != NULL ) + (p->pDataSink->endMultiPart)(p->pDataSink, pMimeMultiPart_internal->pUserObject ); + } + + if ( p->nCurrentMessageType == MIME_MESSAGEPART ) + { + pMimeMessagePart = (mime_messagePart_t *) p->pCurrentMessage; + pMimeMessagePart_internal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + if ( pMimeMessagePart_internal != NULL ) + { + (p->pDataSink->endMessagePart)(p->pDataSink, pMimeMessagePart_internal->pUserObject ); + } + } + + + /* make end*() callback on all pending parents */ + if (p->nCurrentParent > 0) + /*for (i = p->nCurrentParent - 1; i >= 0; i--)*/ + for (i = p->nCurrentParent+1; i >= 0; i--) + { + /* MultiPart handled at END_BOUNDARY. Handle MESSAGEPART & MESSAGE only */ + if ( p->aCurrentParent[i].p != NULL && p->aCurrentParent[i].type == MIME_MESSAGEPART) + { + pMimeMessagePart = (mime_messagePart_t *) p->aCurrentParent[i].p; + + if (pMimeMessagePart_internal != NULL) + { + pMimeMessagePart_internal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + /* if it is rfc822 part call endMessage() also */ + if (pMimeMessagePart->content_subtype != NULL && + bStringEquals (pMimeMessagePart->content_subtype, "rfc822") && + pMimeMessagePart_internal != NULL) + { + pTmpMsg = pMimeMessagePart_internal->pTheMessage; + + if (pTmpMsg != NULL) + { + pTmpMsg_internal = (mime_message_internal_t *)pTmpMsg->pInternal; + if (pTmpMsg_internal != NULL) + (p->pDataSink->endMessage)(p->pDataSink, pTmpMsg_internal->pUserObject); + } + } + } + + if (pMimeMessagePart_internal != NULL) + { + (p->pDataSink->endMessagePart) (p->pDataSink, pMimeMessagePart_internal->pUserObject); + } + } + } + + pMimeMessage_internal = (mime_message_internal_t *) p->pMimeMessage->pInternal; + + if ( pMimeMessage_internal != NULL ) + (p->pDataSink->endMessage)(p->pDataSink, pMimeMessage_internal->pUserObject ); + } + +/* + * if ( p->bLocalStorage && p->pDataSink == null ) + * checkForEmptyMessages( p, p->pMimeMessage, MIME_MESSAGE ); + */ + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* parse entire message +* +* parameter : +* +* nsmail_inputstream_t *pInput : inputstream +* +* returns +* +* mime_message_t * : mime Message Structure populated with data from inputstream +* NULL : bad parameter or out of memory +* +* NOTE: no need to create an instance of the parser, just call this one method to parse a message +*/ +int parseEntireMessageInputstream( nsmail_inputstream_t *pInput, mime_message_t **ppMimeMessage ) +{ + mimeParser_t *p; + int nRet; + + if ( pInput == NULL ) + { + *ppMimeMessage = NULL; + + return MIME_ERR_INVALIDPARAM; + } + + p = mimeParser_new_internal2( NULL ); + + if ( p == NULL ) + { + *ppMimeMessage = NULL; + + return MIME_ERR_OUTOFMEMORY; + } + + nRet = mimeParser_parseMimeMessage( p, pInput, NULL, 0, MIME_PARSE_ALL, (void **)ppMimeMessage ); + mimeDynamicParser_free( &p ); + + return nRet; +} + + + +/* +* carsonl, jan 8,98 +* parse entire message +* +* parameter : +* +* char *pData : data buffer +* int nLen : size of buffer +* +* returns +* +* mime_message_t * : mime Message Structure populated with data from inputstream +* NULL : bad parameter or out of memory +* +* NOTE: no need to create an instance of the parser, just call this one method to parse a message +*/ +int parseEntireMessage( char *pData, int nLen, mime_message_t **ppMimeMessage ) +{ + mimeParser_t *p; + int nRet; + + if ( pData == NULL ) + { + *ppMimeMessage = NULL; + + return MIME_ERR_INVALIDPARAM; + } + + p = mimeParser_new_internal2( NULL ); + + if ( p == NULL ) + { + *ppMimeMessage = NULL; + + return MIME_ERR_OUTOFMEMORY; + } + + nRet = mimeParser_parseMimeMessage( p, NULL, pData, nLen, MIME_PARSE_ALL, (void**)ppMimeMessage ); + mimeDynamicParser_free( &p ); + + return nRet; +} + + + + +/* +* carsonl, jan 8,98 +* mimeParser destructor +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* +* returns : nothing +* +* NULL not enought buffer space, should never happen +* char * decoded buffer, null terminated +* pLen length of data +* +* NOTE: the user should set the bDecodeData field within their datasinks prior to giving it to the parser +* NOTE: if using callbacks with local storage enabled, all data structures are not released, it's up to the user +* to call mimeMessage_free( pMimeMessage ) to release the memory used +*/ +void mimeDynamicParser_free( mimeParser_t **pp ) +{ + if ( pp == NULL ) + { + return; + } + + if ( *pp == NULL ) + return; + + if ( (*pp)->pVectorMimeInfo != NULL ) + Vector_free( (*pp)->pVectorMimeInfo ); + + if ( (*pp)->pVectorMessageData != NULL ) + Vector_free( (*pp)->pVectorMessageData ); + + if ( (*pp)->pMimeMessage != NULL && (*pp)->bDeleteMimeMessage && ( (*pp)->pDataSink != NULL && !IsLocalStorage( *pp ) ) ) + { + mime_message_free( (*pp)->pMimeMessage ); + (*pp)->pMimeMessage = NULL; + } + + if ( (*pp)->pLeftoverBuffer != NULL ) + free( (*pp)->pLeftoverBuffer ); + + if ( (*pp)->pInputBuffer != NULL ) + free( (*pp)->pInputBuffer ); + + if ( (*pp)->pMimeInfoQueue != NULL ) + Vector_free( (*pp)->pMimeInfoQueue ); + + if ( (*pp)->pHeaderQueue != NULL ) + Vector_free( (*pp)->pHeaderQueue ); + + free( *pp ); + *pp = NULL; +} + + + + + +/* -------------------------- internal routines ------------------------------- */ + + + + +/* +* carsonl, jan 8,98 +* constructor +* +* parameter : none +* +* returns +* +* new instance of mimeParser +* +* NOTE : this is the non dynamic parsing version +*/ +mimeParser_t *mimeParser_new_internal() +{ + return mimeParser_new_internal2( NULL ); +} + + + + +/* +* carsonl, jan 8,98 +* constructor +* +* parameter : +* +* mime_message_t * pMimeMessage : pointer to user's mimeMessage object +* +* returns +* +* new instance of mimeParser +* +* NOTE : this is the non dynamic parsing version +*/ +mimeParser_t *mimeParser_new_internal2( mime_message_t * pMimeMessage ) +{ + mime_message_internal_t *pMimeMessageInternal = NULL; + mimeParser_t *p = (mimeParser_t *) malloc( sizeof( mimeParser_t ) ); + + if ( p == NULL ) + { + return NULL; + } + + p->pVectorMimeInfo = Vector_new( VECTOR_TYPE_MIMEINFO ); + + if ( p->pVectorMimeInfo == NULL ) + { + mimeDynamicParser_free ( &p ); + + return NULL; + } + + p->pVectorMessageData = Vector_new( VECTOR_TYPE_STRING ); + + if ( p->pVectorMessageData == NULL ) + { + mimeDynamicParser_free( &p ); + + return NULL; + } + + if ( pMimeMessage != NULL ) + { + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessageInternal != NULL ) + p->pDataSink = pMimeMessageInternal->pDataSink; + + /* two way link */ + p->pMimeMessage = pMimeMessage; + } + + else + { + p->pMimeMessage = mime_message_new( NULL ); + + if ( p->pMimeMessage == NULL ) + { + mimeDynamicParser_free( &p ); + + return NULL; + } + } + + p->bStartData = FALSE; + p->nMessageType = MIME_CONTENT_UNINITIALIZED; + p->nCurrentMessageType = MIME_CONTENT_UNINITIALIZED; + p->pCurrentMessage = NULL; + p->bDeleteMimeMessage = TRUE; /* set to false to use it outside the parser, free it yourself */ + + /* callback support */ + p->pDataSink = NULL; + + p->pLeftoverBuffer = (char *) malloc( BUFFER_SIZE + 1 ); + p->pInputBuffer = (char *) malloc( BUFFER_SIZE + 1 ); + + if ( p->pLeftoverBuffer == NULL || p->pInputBuffer == NULL ) + { + mimeDynamicParser_free( &p ); + + return NULL; + } + + p->nLeftoverBytes = 0; + p->out_byte = 0; + p->out_bits = 0; + p->bParseEntireFile = TRUE; + p->nLineType = MIME_HEADER; + p->fSeenBoundary = FALSE; + p->fEndMessageHeader = FALSE; + p->QPNoOfLeftOverBytes = 0; + p->pCurrentMimeMessage = p->pMimeMessage; + + p->nCurrentParent = 0; + p->aCurrentParent[0].type = MIME_MESSAGE; + p->aCurrentParent[0].p = p->pMimeMessage; + p->bDecodeData = TRUE; + p->bLocalStorage = TRUE; + + p->pNextMimeMessage = p->pMimeMessage; + p->nLastBoundry = START_BOUNDARY; + p->bQPEncoding = FALSE; + p->bReadCR = FALSE; + p->szPreviousHeaderName = NULL; + p->nMessagePartSubType = SUBTYPE_RFC822; + + p->tHeaderParent.type = MIME_MESSAGE; + p->tHeaderParent.p = p->pMimeMessage; + + p->tNextHeaderParent.type = UNINITIALIZED; + p->tNextHeaderParent.p = NULL; + + p->pMimeInfoQueue = Vector_new( VECTOR_TYPE_MIMEINFO ); + + if ( p->pMimeInfoQueue == NULL ) + { + mimeDynamicParser_free ( &p ); + + return NULL; + } + + p->pHeaderQueue = Vector_new( VECTOR_TYPE_STRING ); + + if ( p->pHeaderQueue == NULL ) + { + mimeDynamicParser_free( &p ); + + return NULL; + } + + return p; +} + + + + +/* +* carsonl, jan 8,98 +* create new message structure based on content type +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* char *s : content type input line +* +* returns : MIME_OK or MIME_INVALIDPARAM +*/ +static int nNewMessageStructure( mimeParser_t *p, char *s ) +{ + mime_message_internal_t *pInternal; + mime_content_type nContentType; + mime_messagePart_t *pMimeMessagePart; + mime_basicPart_t *pMimeBasicPart; + mime_multiPart_t *pMimeMultiPart; + mime_multiPart_internal_t *pMimeMultiPart_internal; + mime_messagePart_internal_t *pMimeMessagePart_internal; + char achContentSubtype[64]; + char *szParam; + void *pMessage = NULL; + char *szContentSubType; + char *szContentParams; + void *pUserObject; + + if ( p == NULL || s == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + nContentType = mimeParser_nGetContentType( s, achContentSubtype, &szParam ); + + if (((int)nContentType) < 0) + return nContentType; /* Its the error code */ + + pInternal = (mime_message_internal_t *) p->pMimeMessage->pInternal; + + switch ( nContentType ) + { + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + case MIME_BASICPART: + pMessage = mime_basicPart_new(); + nAddMessage( p, pMessage, nContentType); + + if ( p->pDataSink != NULL ) + { + /* if (IsLocalStorage( p ) && p->pDataSink->startBasicPartLocalStorage != NULL) */ + /* setUserObject(pMessage, MIME_BASICPART, (p->pDataSink->startBasicPartLocalStorage)(p->pDataSink, pMessage)); */ + /* else */ + if (p->pDataSink->startBasicPart != NULL) + { + setUserObject( pMessage, MIME_BASICPART, (p->pDataSink->startBasicPart)(p->pDataSink) ); + } + } + + break; + + case MIME_CONTENT_MULTIPART: + pMessage = mime_multiPart_new(); + nAddMessage( p, pMessage, MIME_CONTENT_MULTIPART ); + + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + pMimeMultiPart_internal = (mime_multiPart_internal_t *) pMimeMultiPart->pInternal; + pMimeMultiPart_internal->fParsedPart = TRUE; + + if ( p->pDataSink != NULL ) + { + /* if (IsLocalStorage( p ) && p->pDataSink->startMultiPartLocalStorage != NULL)*/ + /* setUserObject(pMessage, MIME_MULTIPART, (p->pDataSink->startMultiPartLocalStorage)(p->pDataSink, pMessage));*/ + /* else */ + if (p->pDataSink->startMultiPart != NULL) + setUserObject (pMessage, MIME_MULTIPART, (p->pDataSink->startMultiPart)(p->pDataSink)); + } + + /* save boundary */ + if ( pMimeMultiPart_internal != NULL ) + { + pMimeMultiPart_internal->szBoundary = mimeParser_parseForBoundary( s ); + + } + + break; + + case MIME_CONTENT_MESSAGEPART: + /* add code here */ + pMimeMessagePart = mime_messagePart_new(); + pMimeMessagePart_internal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + nAddMessage( p, (void *) pMimeMessagePart, MIME_CONTENT_MESSAGEPART ); + + if ( p->pDataSink != NULL ) + { + /* if ( IsLocalStorage( p ) && p->pDataSink->startMessagePartLocalStorage != NULL ) */ + /* { */ + /* pUserObject = (p->pDataSink->startMessagePartLocalStorage)(p->pDataSink, pMimeMessagePart); */ + /* setUserObject (pMimeMessagePart, MIME_MESSAGEPART, pUserObject); */ + /* } */ + /* else */ + if ( p->pDataSink->startMessagePart != NULL ) + { + pUserObject = (p->pDataSink->startMessagePart)(p->pDataSink); + setUserObject( pMimeMessagePart, MIME_MESSAGEPART, pUserObject ); + } + } + + if ( bStringEquals( achContentSubtype, "external-body" ) ) + p->nMessagePartSubType = SUBTYPE_EXTERNAL_BODY; + + /* unsupported partial subtype */ + else if ( bStringEquals( achContentSubtype, "partial" ) ) + { + return MIME_ERR_UNSUPPORTED_PARTIAL_SUBTYPE; + } + + /* determine subtype */ + else if ( bStringEquals( achContentSubtype, "rfc822" ) ) + { + pMimeMessagePart_internal->pTheMessage = mime_message_new (NULL); + + if (p->pDataSink != NULL) + { + /* if (IsLocalStorage(p) && p->pDataSink->startMessagePartLocalStorage != NULL)*/ + /* { */ + /* pUserObject = (p->pDataSink->startMessageLocalStorage)(p->pDataSink,*/ + /* pMimeMessagePart_internal->pTheMessage); */ + /* } */ + /* else */ + if (p->pDataSink->startMessage != NULL) + { + pUserObject = (p->pDataSink->startMessage)(p->pDataSink); + } + + setUserObject (pMimeMessagePart_internal->pTheMessage, MIME_MESSAGE, pUserObject); + } + + p->nMessagePartSubType = SUBTYPE_RFC822; + p->tNextHeaderParent.p = pMimeMessagePart_internal->pTheMessage; + p->tNextHeaderParent.type = MIME_MESSAGE; + + /* defered assignment till received first blank line */ + p->pNextMimeMessage = pMimeMessagePart_internal->pTheMessage; + } + break; + } + + szContentSubType = szStringClone( achContentSubtype ); + szContentParams = szStringClone( szLTrim( szParam ) ); + + /* set content type */ + switch ( p->nCurrentMessageType ) + { + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + case MIME_BASICPART: + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart->content_type = nContentType; + pMimeBasicPart->content_subtype = szContentSubType; + pMimeBasicPart->content_type_params = szContentParams; + break; + + case MIME_CONTENT_MULTIPART: + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + pMimeMultiPart->content_type = nContentType; + pMimeMultiPart->content_subtype = szContentSubType; + if (!bStringEquals (szContentParams, "boundary")) + pMimeMultiPart->content_type_params = szContentParams; + break; + + case MIME_CONTENT_MESSAGEPART: + pMimeMessagePart = (mime_messagePart_t *) p->pCurrentMessage; + pMimeMessagePart->content_type = nContentType; + pMimeMessagePart->content_subtype = szContentSubType; + pMimeMessagePart->content_type_params = szContentParams; + break; + } + + if ( p->pDataSink != NULL ) + { + if ( p->pDataSink->contentType != NULL ) + (p->pDataSink->contentType)(p->pDataSink, getUserObject2 (p->pCurrentMessage, p->nCurrentMessageType), nContentType ); + + if ( p->pDataSink->contentSubType ) + (p->pDataSink->contentSubType)(p->pDataSink, getUserObject2 (p->pCurrentMessage, p->nCurrentMessageType), szContentSubType ); + + if (p->pDataSink->contentTypeParams && szContentParams != NULL && !bStringEquals (szContentParams, "boundary")) + { + + (p->pDataSink->contentTypeParams)(p->pDataSink, getUserObject2 (p->pCurrentMessage, p->nCurrentMessageType), szContentParams ); + } + } + + return MIME_OK; +} + + + + + +/* +* carsonl, jan 8,98 +* populate message structure based on info inside pMimeInfo +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* mimeInfo_t *pMimeInfo : mimeInfo object +* +* returns : MIME_OK, MIME_INVALIDPARAM +*/ +int mimeParser_setData( mimeParser_t *p, mimeInfo_t *pMimeInfo ) +{ + mime_messagePart_t *pMimeMessagePart; + mime_messagePart_internal_t *pMimeMessagePartInternal; + mime_basicPart_t *pMimeBasicPart; + mime_multiPart_t *pMimeMultiPart; + char *szParam; + int nContentDisposition; + char *szContentDispParams; + int i, nSize, ret; + + if ( p == NULL || pMimeInfo == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + +/* externalheaders ----------------------------------------------- + + if ( p->nMessagePartSubType == SUBTYPE_EXTERNAL_BODY && + p->nCurrentMessageType == MIME_MESSAGEPART ) + { + pMimeMessagePart = (mime_messagePart_t *) p->pCurrentMessage; + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + if ( pMimeMessagePart->extra_headers == NULL ) + pMimeMessagePart->extra_headers = mime_header_new( pMimeInfo->szName, pMimeInfo->szValue ); + else + mime_header_add( pMimeMessagePart->extra_headers, pMimeInfo->szName, pMimeInfo->szValue ); + + if ( p->pDataSink != NULL && pMimeMessagePartInternal != NULL && p->pDataSink->header != NULL ) + (p->pDataSink->header)(p->pDataSink, pMimeMessagePartInternal->pUserObject, pMimeInfo->szName, pMimeInfo->szValue ); + + p->szPreviousHeaderName = pMimeInfo->szName; + } +------------------------------------------------------------ */ + + /* externalheaders */ + if ( p->nMessagePartSubType == SUBTYPE_EXTERNAL_BODY && + p->nCurrentMessageType == MIME_MESSAGEPART ) +/* p->nEmptyLineNo > 0 ) */ + { + /* add as external body headers */ + pMimeMessagePart = (mime_messagePart_t *) p->pCurrentMessage; + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + if ( pMimeMessagePart->extern_headers == NULL ) + pMimeMessagePart->extern_headers = mime_header_new( pMimeInfo->szName, pMimeInfo->szValue ); + else + mime_header_add( pMimeMessagePart->extern_headers, pMimeInfo->szName, pMimeInfo->szValue ); + + if ( p->pDataSink != NULL && pMimeMessagePartInternal != NULL && p->pDataSink->header != NULL ) + (p->pDataSink->header)(p->pDataSink, pMimeMessagePartInternal->pUserObject, pMimeInfo->szName, pMimeInfo->szValue ); + + p->szPreviousHeaderName = pMimeInfo->szName; + } + + /* create message structure */ + else if ( bStringEquals( pMimeInfo->szName, "content-type" ) ) + { + if ((ret = nNewMessageStructure (p, pMimeInfo->szValue)) != MIME_OK) + return ret; + + nSize = Vector_size( p->pMimeInfoQueue ); + + /* add from queue */ + if ( nSize > 0 && p->nMessagePartSubType != SUBTYPE_EXTERNAL_BODY ) + { + for ( i = 0; i < nSize; i++ ) + { + ret = mimeParser_setData( p, (mimeInfo_t*) Vector_elementAt( p->pMimeInfoQueue, i ) ); + if (ret != MIME_OK) + return ret; + } + + Vector_deleteAll( p->pMimeInfoQueue ); + } + } + + /* no message structure */ + else if ( p->pCurrentMessage == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + else if ( bStringEquals( pMimeInfo->szName, "content-description" ) ) + { + if ( p->nCurrentMessageType == UNINITIALIZED ) + { + Vector_addElement( p->pMimeInfoQueue, pMimeInfo, sizeof( mimeInfo_t ) ); + } + + else + { + switch ( p->nCurrentMessageType ) + { + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + case MIME_BASICPART: + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart->content_description = szStringClone( pMimeInfo->szValue ); + break; + + case MIME_CONTENT_MULTIPART: + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + pMimeMultiPart->content_description = szStringClone( pMimeInfo->szValue ); + break; + + case MIME_CONTENT_MESSAGEPART: + pMimeMessagePart = (mime_messagePart_t *) p->pCurrentMessage; + pMimeMessagePart->content_description = szStringClone( pMimeInfo->szValue ); + break; + } + + if ( p->pDataSink != null && p->pDataSink->contentDescription != NULL ) + (p->pDataSink->contentDescription)(p->pDataSink, getUserObject2 (p->pCurrentMessage, p->nCurrentMessageType), pMimeInfo->szValue ); + } + } + + else if ( bStringEquals( pMimeInfo->szName, "content-disposition" ) ) + { + if ( p->nCurrentMessageType == UNINITIALIZED ) + { + Vector_addElement( p->pMimeInfoQueue, pMimeInfo, sizeof( mimeInfo_t ) ); + } + + else + { + nContentDisposition = mime_translateDispType( pMimeInfo->szValue, &szParam ); + szContentDispParams = szStringClone( szLTrim( szParam ) ); + + switch ( p->nCurrentMessageType ) + { + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + case MIME_BASICPART: + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart->content_disposition = nContentDisposition; + pMimeBasicPart->content_disp_params = szContentDispParams; + break; + + case MIME_CONTENT_MULTIPART: + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + pMimeMultiPart->content_disposition = nContentDisposition; + pMimeMultiPart->content_disp_params = szContentDispParams; + break; + + case MIME_CONTENT_MESSAGEPART: + pMimeMessagePart = (mime_messagePart_t *) p->pCurrentMessage; + pMimeMessagePart->content_disposition = nContentDisposition; + pMimeMessagePart->content_disp_params = szContentDispParams; + break; + } + + if ( p->pDataSink != null && p->pDataSink->contentDisposition != NULL ) + { + (p->pDataSink->contentDisposition)(p->pDataSink, getUserObject2 (p->pCurrentMessage, p->nCurrentMessageType), nContentDisposition ); + + if ( szParam != null && p->pDataSink->contentDispParams != NULL ) + (p->pDataSink->contentDispParams)(p->pDataSink, getUserObject2 (p->pCurrentMessage, p->nCurrentMessageType), szContentDispParams ); + } + } + } + + else if ( bStringEquals( pMimeInfo->szName, "content-id" ) ) + { + if ( p->nCurrentMessageType == UNINITIALIZED ) + { + Vector_addElement( p->pMimeInfoQueue, pMimeInfo, sizeof( mimeInfo_t ) ); + } + + else + { + switch ( p->nCurrentMessageType ) + { + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + case MIME_BASICPART: + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart->contentID = szStringClone( pMimeInfo->szValue ); + break; + + case MIME_CONTENT_MULTIPART: + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + pMimeMultiPart->contentID = szStringClone( pMimeInfo->szValue ); + break; + + case MIME_CONTENT_MESSAGEPART: + pMimeMessagePart = (mime_messagePart_t *) p->pCurrentMessage; + pMimeMessagePart->contentID = szStringClone( pMimeInfo->szValue ); + break; + } + + if ( p->pDataSink != null && p->pDataSink->contentID != NULL ) + (p->pDataSink->contentID)(p->pDataSink, getUserObject2 (p->pCurrentMessage, p->nCurrentMessageType), pMimeInfo->szValue ); + } + } + + else if ( bStringEquals( pMimeInfo->szName, "content-md5" ) ) + { + if ( p->nCurrentMessageType == UNINITIALIZED ) + { + Vector_addElement( p->pMimeInfoQueue, pMimeInfo, sizeof( mimeInfo_t ) ); + } + + else if ( bIsBasicPart( p->nCurrentMessageType ) ) + { + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart->contentMD5 = szStringClone( pMimeInfo->szValue ); + + if ( p->pDataSink != null && p->pDataSink->contentMD5 != NULL ) + (p->pDataSink->contentMD5)(p->pDataSink, getUserObject2 (p->pCurrentMessage, p->nCurrentMessageType), pMimeInfo->szValue ); + } + } + + else if ( bStringEquals( pMimeInfo->szName, "content-transfer-encoding" ) ) + { + if ( p->nCurrentMessageType == UNINITIALIZED ) + { + Vector_addElement( p->pMimeInfoQueue, pMimeInfo, sizeof( mimeInfo_t ) ); + } + + else if ( bIsBasicPart( p->nCurrentMessageType ) ) + { + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart->encoding_type = mime_translateMimeEncodingType( pMimeInfo->szValue ); + + if ( pMimeBasicPart->encoding_type == MIME_ENCODING_QP ) + p->bQPEncoding = TRUE; + + if ( p->pDataSink != null && p->pDataSink->contentEncoding != NULL ) + (p->pDataSink->contentEncoding)(p->pDataSink, getUserObject( pMimeBasicPart, MIME_BASICPART ), pMimeBasicPart->encoding_type ); + } + + else if ( p->nCurrentMessageType == MIME_MESSAGEPART ) + { + pMimeMessagePart = (mime_messagePart_t *) p->pCurrentMessage; + pMimeMessagePart->encoding_type = mime_translateMimeEncodingType( pMimeInfo->szValue ); + + if ( p->pDataSink != null && p->pDataSink->contentEncoding != NULL ) + (p->pDataSink->contentEncoding)(p->pDataSink, getUserObject( pMimeMessagePart, MIME_MESSAGEPART ), pMimeMessagePart->encoding_type ); + } + else if ( p->nCurrentMessageType == MIME_MULTIPART ) + { + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + + pMimeMultiPart->encoding_type = mime_translateMimeEncodingType (pMimeInfo->szValue); + + if (pMimeMultiPart->encoding_type == MIME_ENCODING_7BIT || + pMimeMultiPart->encoding_type == MIME_ENCODING_8BIT || + pMimeMultiPart->encoding_type == MIME_ENCODING_8BIT) + { + if (p->pDataSink != null && p->pDataSink->contentEncoding != NULL) + (p->pDataSink->contentEncoding)(p->pDataSink, getUserObject (pMimeMultiPart, MIME_MULTIPART), + pMimeMultiPart->encoding_type); + } + else + pMimeMultiPart->encoding_type == MIME_ENCODING_UNINITIALIZED; + } + } + else if ( bStringEquals( pMimeInfo->szName, "content-name" ) ) + { + addHeader (p, pMimeInfo->szName, pMimeInfo->szValue, TRUE); + } + + return MIME_OK; +} + + + + + +/* +* carsonl, jan 8,98 +* parse the contents of mimeInfo +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* mimeInfo_t *pMimeInfo : mimeInfo object +* +* returns : MIME_OK, MIME_INVALIDPARAM +*/ +int mimeParser_parseMimeInfo( mimeParser_t *p, mimeInfo_t *pMimeInfo ) +{ + char *paramName; + char *value; + int offset; + int len; + BOOLEAN beginQuote; + char ch; + int i; + int valueLen; + mimeInfo_t *pMimeInfo2; + + if ( p == NULL || pMimeInfo == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + beginQuote = FALSE; + paramName = ""; + value = ""; + offset = 0; + len = 0; + beginQuote = FALSE; + valueLen = strlen( pMimeInfo->szValue ); + + /* go through entire line */ + for ( i=0; i < valueLen; i++ ) + { + ch = pMimeInfo->szValue[i]; + + /* handle quotes */ + if ( ch == '"' ) + beginQuote = beginQuote ? FALSE : TRUE; + + if ( beginQuote ) + { + len++; + continue; + } + + /* parse and fill in fields */ + switch ( ch ) + { + case ';': + pMimeInfo->szValue[offset+len] = 0; + value = szTrim( &pMimeInfo->szValue[offset] ); + offset = i + 1; + + if ( pMimeInfo->pVectorParam == NULL ) + { + pMimeInfo->pVectorParam = Vector_new( VECTOR_TYPE_MIMEINFO ); + + if ( pMimeInfo->pVectorParam == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + } + + pMimeInfo2 = mimeInfo_new(); + + if ( pMimeInfo2 == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + + mimeInfo_init2( pMimeInfo2, MIME_INFO, paramName, value ); + Vector_addElement( pMimeInfo->pVectorParam, pMimeInfo2, sizeof( mimeInfo_t ) ); + + value = ""; + paramName = ""; + + len = 0; + mimeInfo_free( pMimeInfo2 ); + pMimeInfo2 = NULL; + + break; + + case '=': + pMimeInfo->szValue[ offset + len ] = 0; + paramName = szTrim( &pMimeInfo->szValue[ offset ] ); + + offset = i + 1; + len = 0; + break; + + default: + len++; + } + } + + /* add it to internal buffer */ + if ( len > 0 ) + { + pMimeInfo->szValue[offset+len] = 0; + value = szTrim( &pMimeInfo->szValue[offset] ); + + if ( pMimeInfo->pVectorParam == NULL ) + { + pMimeInfo->pVectorParam = Vector_new( VECTOR_TYPE_MIMEINFO ); + + if ( pMimeInfo->pVectorParam == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + } + + pMimeInfo2 = mimeInfo_new(); + + if ( pMimeInfo2== NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + + mimeInfo_init2( pMimeInfo2, MIME_INFO, paramName, value ); + Vector_addElement( pMimeInfo->pVectorParam, pMimeInfo2, sizeof( mimeInfo_t ) ); + mimeInfo_free( pMimeInfo2 ); + pMimeInfo2 = NULL; + } + + return MIME_OK; +} + + +/* prototype */ +void appToLastHdrOnQueue (mimeParser_t *p, char *value); + +/* +* carsonl, jan 8,98 +* parse and extract data from input string +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* char *s : input string +* BOOLEAN bLastLine : TRUE if this is the last line +* +* returns : MIME_OK, MIME_ERR_INVALIDPARAM +*/ +int mimeParser_parseLine( mimeParser_t *p, char *s, int len, BOOLEAN bLastLine ) +{ + int i; + int nIndex, ret; + BOOLEAN finished = FALSE; + mimeInfo_t *mi, *mi2; + mime_basicPart_t *pMimeBasicPart; + mime_basicPart_internal_t *pMimeBasicPart_internal; + mime_multiPart_t *pMimeMultiPart; + mime_multiPart_internal_t *pMimeMultiPart_internal; + mime_messagePart_t *pMimeMessagePart; + mime_messagePart_internal_t *pMimeMessagePart_internal; + mime_message_t *pMimeMessage; + mime_message_internal_t *pMimeMessage_internal; + char achTemp[256], *pTmp; + int nSize; + + if ( p == NULL || s == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + mi = NULL; + mi2 = NULL; + pMimeBasicPart = NULL; + pMimeBasicPart_internal = NULL; + pMimeMultiPart = NULL; + pMimeMultiPart_internal = NULL; + pMimeMessagePart = NULL; + pMimeMessagePart_internal = NULL; + pMimeMessage_internal = NULL; + + + /* debug + sprintf(achTemp, "%s\n", s ); + fprintf (stderr, achTemp); + + if (strncmp (s, "-----------------------------2082357617733318156662372089--", 59) == 0) + { + nSize = nSize; + } + + if (strncmp (s, "Content-Type: multipart", 23) == 0) + { + nSize = nSize; + } + + */ + + + /* ignore additional header info */ + if ((p->nLineType == MIME_XHEADER || p->nLineType == MIME_HEADER) && (len > 0 && (s[0] == '\t' || s[0] == ' '))) + { + /*if (!(p->nCurrentMessageType == MIME_BASICPART && p->bStartData == TRUE))*/ + if (!(bIsBasicPart(p->nCurrentMessageType) && p->bStartData == TRUE)) + { + sprintf( achTemp, "\n%s", s ); + + /* continuation headers */ + if (p->tHeaderParent.type == MIME_BASICPART || bIsBasicPart(p->tHeaderParent.type)) + { + pMimeBasicPart = (mime_basicPart_t *) p->tHeaderParent.p; + pMimeBasicPart_internal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + if ( pMimeBasicPart->extra_headers == NULL ) + pMimeBasicPart->extra_headers = mime_header_new( p->szPreviousHeaderName, achTemp ); + else + { + mime_header_apend( pMimeBasicPart->extra_headers, p->szPreviousHeaderName, achTemp ); + } + + if ( p->pDataSink != NULL && pMimeBasicPart_internal != NULL && p->pDataSink->header != NULL ) + (p->pDataSink->header)(p->pDataSink, pMimeBasicPart_internal->pUserObject, + p->szPreviousHeaderName, achTemp ); + } + /*else if ( p->tHeaderParent.type == MIME_MESSAGEPART ) */ + else + { + if (p->szPreviousHeaderName == NULL) + { + appToLastHdrOnQueue (p, achTemp); + } + else + { + pMimeMessage = (mime_message_t*) p->tHeaderParent.p; + pMimeMessage_internal = (mime_message_internal_t *) p->pCurrentMimeMessage->pInternal; + + if ( pMimeMessage->rfc822_headers == NULL ) + pMimeMessage->rfc822_headers = mime_header_new( p->szPreviousHeaderName, achTemp ); + else + mime_header_apend( pMimeMessage->rfc822_headers, p->szPreviousHeaderName, achTemp ); + + if (p->pDataSink != NULL && pMimeMessage_internal != NULL && p->pDataSink->addHeader != NULL) + { + (p->pDataSink->addHeader)(p->pDataSink, pMimeMessage_internal->pUserObject, + p->szPreviousHeaderName, achTemp); + } + } + } + + return MIME_OK; + } + } + + if (len == 0) + { + p->nEmptyLineNo++; + + if (p->nEmptyLineNo == 1 && p->fEndMessageHeader == FALSE) + { + p->fEndMessageHeader = TRUE; + + if (p->pDataSink != NULL && p->pDataSink->endMessageHeader != NULL) + { + (p->pDataSink->endMessageHeader) (p->pDataSink, getUserObject( p->pMimeMessage, MIME_MESSAGE)); + } + } + } + + /* for messagePart, special case */ + if ( len == 0 && !p->bStartData ) + { + if ( p->bQPEncoding && p->nEmptyLineNo == 1 ) + p->bReadCR = TRUE; + + if (p->nEmptyLineNo > 1 && p->nCurrentMessageType == MIME_CONTENT_UNINITIALIZED && + (nGetCurrentParentType(p) == MIME_MESSAGEPART)) + { + p->nLineType = MIME_CRLF; + return MIME_OK; + } + + if (p->nEmptyLineNo == 2 && !(p->nCurrentMessageType == MIME_MULTIPART && p->fSeenBoundary ==FALSE)) + p->bStartData = TRUE; + else if (p->nEmptyLineNo == 1 && (nGetCurrentParentType(p) == MIME_MULTIPART) && p->fSeenBoundary == TRUE) + { + if (p->nCurrentMessageType == UNINITIALIZED) + p->bStartData = TRUE; + } + else if (p->nEmptyLineNo > 1 && p->nCurrentMessageType == MIME_MULTIPART) + { + if (p->fSeenBoundary == TRUE) + p->bStartData = TRUE; + else /* goes in preamble */ + { + /* Add the preamble */ + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + s[0] = '\r'; + s[1] = '\n'; + if (pMimeMultiPart->preamble == NULL) + { + pMimeMultiPart->preamble = (char *) malloc (3); + memset (pMimeMultiPart->preamble, 0, 3); + strncpy (pMimeMultiPart->preamble, s, 2); + } + else + { + /*append string*/ + pTmp = (char *) malloc (strlen (pMimeMultiPart->preamble) + 3); + memset (pTmp, 0, strlen (pMimeMultiPart->preamble) + 3); + strcpy (pTmp, pMimeMultiPart->preamble); + free (pMimeMultiPart->preamble); + pMimeMultiPart->preamble = strncat (pTmp, s, 2); + } + + p->nLineType = MIME_CRLF; + return MIME_OK; + } + } + else if ( p->nEmptyLineNo == 1 ) + { + /* change mimeMessage parent */ + if ( p->pNextMimeMessage != null ) + { + /* change parent only after first blank line */ + p->pCurrentMimeMessage = p->pNextMimeMessage; + p->pNextMimeMessage = NULL; + } + + /* insert headers from queue */ + nSize = Vector_size( p->pHeaderQueue ); + + if ( p->nCurrentMessageType != UNINITIALIZED && nSize > 0 ) + { + for ( i = 0; i < nSize; i++ ) + { + mi = (mimeInfo_t *) Vector_elementAt( p->pHeaderQueue, i ); + addHeader( p, mi->szName, mi->szValue, FALSE ); + } + + Vector_deleteAll( p->pHeaderQueue ); + } + + /* change header parent */ + if ( p->tNextHeaderParent.p != NULL && p->tNextHeaderParent.type != MIME_MULTIPART ) + { + p->tHeaderParent.p = p->tNextHeaderParent.p; + p->tHeaderParent.type = p->tNextHeaderParent.type; + p->tNextHeaderParent.p = NULL; + } + } + } + + /* for messagePart, special case */ +/* carsonl +/* if ( len == 0 ) + p->nEmptyLineNo++; +*/ + + if ( bStringEquals( s, "content-type" ) ) + p->nEmptyLineNo = 0; + + /* boundary */ + if ( ( p->nLineType == MIME_INFO || p->nLineType == MIME_HEADER || p->nLineType == MIME_XHEADER ) && len == 0 && + p->nCurrentMessageType != UNINITIALIZED && p->nMessagePartSubType != SUBTYPE_EXTERNAL_BODY ) + { + if ( p->nCurrentMessageType == MIME_CONTENT_MESSAGEPART ) + { + if ( p->nEmptyLineNo == 1 || p->nEmptyLineNo == 2 ) + p->nLineType = MIME_HEADER; + else + { + mi = mimeInfo_new(); + + if ( mi == NULL ) + return MIME_ERR_OUTOFMEMORY; + + /* content type */ + mi->nType = MIME_INFO; + mi->szName = "content-type"; + mi->szValue = "text/plain"; + ret = mimeParser_setData( p, mi ); + if (ret != MIME_OK) + return ret; + mimeParser_parseMimeInfo( p, mi ); + Vector_addElement( p->pVectorMimeInfo, mi, sizeof( mimeInfo_t ) ); + + /* encoding type */ + mi->nType = MIME_INFO; + mi->szName = "content-transfer-encoding"; + mi->szValue = "7bit"; + ret = mimeParser_setData( p, mi ); + if (ret != MIME_OK) + return ret; + mimeParser_parseMimeInfo( p, mi ); + Vector_addElement( p->pVectorMimeInfo, mi, sizeof( mimeInfo_t ) ); + + mi->szName = NULL; + mi->szValue = NULL; + mimeInfo_free( mi ); + mi = NULL; + + p->bStartData = TRUE; + p->fSeenBoundary = FALSE; + } + } + + /* start data only if it's a simple message with no boundary */ + else if ( bIsBasicPart( p->nCurrentMessageType ) ) + { + p->bStartData = TRUE; + p->fSeenBoundary = FALSE; + } + + if (p->nEmptyLineNo == 1) + return MIME_OK; + } + + /* empty line, don't process anymore */ + if ( !p->bStartData && len == 0 ) + { + if (p->nCurrentMessageType == MIME_MULTIPART) + { + p->nEmptyLineNo = 0; + + /* Add the preamble */ + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + s[0] = '\r'; + s[1] = '\n'; + if (pMimeMultiPart->preamble == NULL) + { + pMimeMultiPart->preamble = (char *) malloc (3); + memset (pMimeMultiPart->preamble, 0, 3); + strncpy (pMimeMultiPart->preamble, s, 2); + } + else + { + /*append string*/ + pTmp = (char *) malloc (strlen (pMimeMultiPart->preamble) + 3); + memset (pTmp, 0, strlen (pMimeMultiPart->preamble) + 3); + strcpy (pTmp, pMimeMultiPart->preamble); + free (pMimeMultiPart->preamble); + pMimeMultiPart->preamble = strncat (pTmp, s, 2); + } + } + + p->nLineType = MIME_CRLF; + return MIME_OK; + } + + /* identify line */ + mi = mimeInfo_new(); + + if ( mi == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + + /* -------------------------- identify line ----------------------- */ + mi->nType = mimeParser_checkForLineType( p, s, len ); + + if (mi->nType == START_BOUNDARY) + { + p->fSeenBoundary = TRUE; + p->nEmptyLineNo = 0; + if (p->nCurrentMessageType == MIME_CONTENT_MESSAGEPART && + p->nMessagePartSubType == SUBTYPE_EXTERNAL_BODY) + p->bStartData = FALSE; + + if (p->pDataSink != NULL && p->pDataSink->boundary != NULL) + { + if (p->nCurrentMessageType == MIME_MULTIPART) + { + (p->pDataSink->boundary) (p->pDataSink, + getUserObject(p->pCurrentMessage, MIME_MULTIPART), + mimeParser_getCurrentBoundary (p)); + } + else if (nGetCurrentParentType(p) == MIME_MULTIPART) + { + (p->pDataSink->boundary) (p->pDataSink, + getUserObject(pGetCurrentParent(p), MIME_MULTIPART), + mimeParser_getCurrentBoundary (p)); + } + } + } + + /* start of simple basicpart message */ + if (p->nLineType == MIME_CRLF && + p->nCurrentMessageType == UNINITIALIZED && + p->nLastBoundry == START_BOUNDARY && + mi->nType == MIME_MESSAGE_DATA && + ( p->nEmptyLineNo == 1 || p->nEmptyLineNo == 2 ) && + p->nMessagePartSubType != SUBTYPE_EXTERNAL_BODY ) + { + mi2 = mimeInfo_new(); + + /* content type */ + mi2->nType = MIME_INFO; + mi2->szName = "content-type"; + mi2->szValue = "text/plain"; + ret = mimeParser_setData( p, mi2 ); + + if (ret != MIME_OK) + return ret; + + mimeParser_parseMimeInfo( p, mi2 ); + Vector_addElement( p->pVectorMimeInfo, mi2, sizeof( mimeInfo_t ) ); + + /* encoding type */ + mi2->nType = MIME_INFO; + mi2->szName = "content-transfer-encoding"; + mi2->szValue = "7bit"; + ret = mimeParser_setData( p, mi2 ); + + if (ret != MIME_OK) + return ret; + + mimeParser_parseMimeInfo( p, mi2 ); + Vector_addElement( p->pVectorMimeInfo, mi2, sizeof( mimeInfo_t ) ); + + mi2->szName = NULL; + mi2->szValue = NULL; + mimeInfo_free( mi2 ); + mi2 = NULL; + p->bStartData = TRUE; + + if ( p->nEmptyLineNo == 1 || p->nEmptyLineNo == 2 ) + { + nSize = Vector_size( p->pHeaderQueue ); + + /* insert headers from queue */ + if ( nSize > 0 ) + { + /* change header parent */ + if ( p->tNextHeaderParent.p != null ) + { + p->tHeaderParent.p = p->tNextHeaderParent.p; + p->tHeaderParent.type = p->tNextHeaderParent.type; + p->tNextHeaderParent.p = NULL; + } + + for ( i = 0; i < nSize; i++ ) + { + mi2 = (mimeInfo_t *) Vector_elementAt( p->pHeaderQueue, i ); + addHeader( p, mi2->szName, mi2->szValue, FALSE ); + } + + Vector_deleteAll( p->pHeaderQueue ); + } + + /* change header parent */ + if ( p->tNextHeaderParent.p != null ) + { + p->tHeaderParent.p = p->tNextHeaderParent.p; + p->tHeaderParent.type = p->tNextHeaderParent.type; + p->tNextHeaderParent.p = NULL; + } + + /* should add from mimeinfo queue */ + + p->nEmptyLineNo = 0; /* reset for headers */ + } + } + + /* start boundary */ + if ( !p->bStartData && mi->nType == START_BOUNDARY ) + { +/* mimeInfo_free( mi ); + mi = NULL; +*/ + p->nLineType = MIME_INFO; + + p->nLeftoverBytes = 0; + p->out_byte = 0; + p->out_bits = 0; + p->QPNoOfLeftOverBytes = 0; + p->nMessagePartSubType = SUBTYPE_RFC822; + p->bReadCR = FALSE; + p->bQPEncoding = FALSE; + p->nEmptyLineNo = 0; + p->nCurrentMessageType = MIME_CONTENT_UNINITIALIZED; + p->nLastBoundry = START_BOUNDARY; + p->fSeenBoundary = TRUE; + + /* adjust to current parent */ + mimeParser_unwindCurrentBoundary( p, s, FALSE ); + + /*return MIME_INFO;*/ + } + /* end boundary */ + else if ( mi->nType == END_BOUNDARY || mi->nType == START_BOUNDARY ) + { + decodeDataBuffer(p); + + if ( p->pDataSink != null ) + { + switch( p->nCurrentMessageType ) + { + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + case MIME_BASICPART: + if ( p->pDataSink->endBasicPart != NULL ) + (p->pDataSink->endBasicPart)(p->pDataSink, getUserObject( p->pCurrentMessage, MIME_BASICPART ) ); + break; + + case MIME_MULTIPART: + if (mi->nType == END_BOUNDARY && p->pDataSink->endMultiPart != NULL) + (p->pDataSink->endMultiPart)(p->pDataSink, getUserObject( p->pCurrentMessage, MIME_MULTIPART ) ); + break; + + case MIME_MESSAGEPART: + if ( p->pDataSink->endMessagePart != NULL ) + (p->pDataSink->endMessagePart)(p->pDataSink, getUserObject( p->pCurrentMessage, MIME_MESSAGEPART ) ); + break; + } + + /* 4/24 */ + if ( mi->nType == END_BOUNDARY ) + { + if (nGetCurrentParentType(p) == MIME_MULTIPART) + { + (p->pDataSink->endMultiPart)(p->pDataSink, getUserObject(pGetCurrentParent(p), MIME_MULTIPART)); + m_needEndMultiPart = FALSE; + } + else + m_needEndMultiPart = TRUE; + } + + } + + if ( mi->nType == END_BOUNDARY ) + { + mimeParser_unwindCurrentBoundary( p, s, TRUE ); + p->nCurrentMessageType = MIME_CONTENT_UNINITIALIZED; + p->fSeenBoundary = FALSE; + } + + p->bStartData = FALSE; + p->nLineType = MIME_BOUNDARY; + p->nMessagePartSubType = SUBTYPE_RFC822; + p->bReadCR = FALSE; + p->bQPEncoding = FALSE; + p->nEmptyLineNo = 0; + p->nCurrentMessageType = MIME_CONTENT_UNINITIALIZED; + p->nLastBoundry = START_BOUNDARY; + + mimeInfo_free( mi ); + mi = NULL; + + return MIME_OK; + } + + /* message data */ + else if ( p->bStartData ) + { + nIndex = Vector_addElement( p->pVectorMessageData, s, len ); + mimeInfo_free( mi ); + mi = NULL; + + if (p->nCurrentMessageType == UNINITIALIZED) + { + if (nGetCurrentParentType(p) == MIME_MULTIPART) + { + mi = mimeInfo_new(); + mi->nType = MIME_INFO; + mi->szName = "content-type"; + mi->szValue = "text/plain"; + mimeParser_setData (p, mi); + mimeParser_parseMimeInfo (p, mi); + Vector_addElement (p->pVectorMimeInfo, mi, sizeof(mimeInfo_t)); + + /* free */ + mi->szName = NULL; + mi->szValue = NULL; + mimeInfo_free (mi); + + mi = NULL; + } + } + + if ( bIsBasicPart( p->nCurrentMessageType ) ) + { + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart_internal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + if ( pMimeBasicPart_internal->nStartMessageDataIndex == UNINITIALIZED ) + pMimeBasicPart_internal->nStartMessageDataIndex = nIndex; + + pMimeBasicPart_internal->nEndMessageDataIndex = nIndex; + pMimeBasicPart_internal->nRawMessageSize += len; + + if ( bLastLine ) + { + decodeDataBuffer(p); + + if ( p->pDataSink != null ) + { + switch( p->nCurrentMessageType ) + { + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + case MIME_BASICPART: + if ( p->pDataSink->endBasicPart != NULL ) + (p->pDataSink->endBasicPart)(p->pDataSink, getUserObject( p->pCurrentMessage, MIME_BASICPART ) ); + break; + + case MIME_MULTIPART: + if ( p->pDataSink->endMultiPart != NULL ) + (p->pDataSink->endMultiPart)(p->pDataSink, getUserObject( p->pCurrentMessage, MIME_MULTIPART ) ); + break; + + case MIME_MESSAGEPART: + if ( p->pDataSink->endMessagePart != NULL ) + (p->pDataSink->endMessagePart)(p->pDataSink, getUserObject( p->pCurrentMessage, MIME_MESSAGEPART ) ); + break; + } + } + } + } + + p->nLineType = MIME_MESSAGE_DATA; + + return MIME_OK; + } + + /* check and add preamble */ + if (p->nCurrentMessageType == MIME_MULTIPART && p->nEmptyLineNo > 0 && p->fSeenBoundary == FALSE) + { + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + s[len] = '\n'; + if (pMimeMultiPart->preamble == NULL) + { + pMimeMultiPart->preamble = (char *) malloc (len + 2); + memset (pMimeMultiPart->preamble, 0, len + 2); + strncpy (pMimeMultiPart->preamble, s, len+1); + } + else + { + /*append string*/ + pTmp = (char *) malloc (strlen (pMimeMultiPart->preamble) + len + 2); + memset (pTmp, 0, strlen (pMimeMultiPart->preamble) + len + 2); + strcpy (pTmp, pMimeMultiPart->preamble); + free (pMimeMultiPart->preamble); + pMimeMultiPart->preamble = strncat (pTmp, s, len+1); + } + + p->nLineType = mi->nType; + return MIME_OK; + } + + for ( len = strlen(s), i = 0; i < len && !finished; i++ ) + { + switch ( s[i] ) + { + case ':': + s[i] = 0; + mi->szName = s; + + /* remove junk spaces */ + for ( ++i; s[i] != 0 && isspace( s[i] ); i++ ) + ; + + mi->szValue = &s[i]; + + if ( mi->nType == MIME_INFO ) + { + ret = mimeParser_setData( p, mi ); + if (ret != MIME_OK) + return ret; + + if ( p->nMessagePartSubType != SUBTYPE_EXTERNAL_BODY ) + { + mimeParser_parseMimeInfo( p, mi ); + Vector_addElement( p->pVectorMimeInfo, mi, sizeof( mimeInfo_t ) ); + } + } + + else if ( ( mi->nType == MIME_HEADER || mi->nType == MIME_XHEADER ) && p->tHeaderParent.p != NULL ) + { + addHeader( p, mi->szName, mi->szValue, TRUE ); + p->nEmptyLineNo = 0; + } + + finished = TRUE; + break; + } + } + + /* add preamble */ + if (!finished && p->nCurrentMessageType == MIME_MULTIPART) + { + pMimeMultiPart = (mime_multiPart_t *) p->pCurrentMessage; + s[len] = '\n'; + if (pMimeMultiPart->preamble == NULL) + { + pMimeMultiPart->preamble = (char *) malloc (len + 2); + memset (pMimeMultiPart->preamble, 0, len + 2); + strncpy (pMimeMultiPart->preamble, s, len+1); + } + else + { + /*append string*/ + pTmp = (char *) malloc (strlen (pMimeMultiPart->preamble) + len + 2); + memset (pTmp, 0, strlen (pMimeMultiPart->preamble) + len + 2); + strcpy (pTmp, pMimeMultiPart->preamble); + free (pMimeMultiPart->preamble); + pMimeMultiPart->preamble = strncat (pTmp, s, len+1); + } + + p->nEmptyLineNo = 0; /* reset for preamble */ + } + + p->nLineType = mi->nType; + + /* note, don't free this stuff, wasn't allocated with malloc */ + mi->szName = NULL; + mi->szValue = NULL; + mimeInfo_free( mi ); + mi = NULL; + + if ( bLastLine ) + decodeDataBuffer(p); + + return MIME_OK; +} + + + + + + +/* +* carsonl, jan 8,98 +* decode message data +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* +* returns : nothing +*/ +static void decodeDataBuffer( mimeParser_t *p ) +{ + int offset = 0; + int i; + int len; + mime_basicPart_t *pMimeBasicPart; + mime_basicPart_internal_t *pMimeBasicPart_internal; + char *szNewBuffer; + char *szDecodedBuffer; + char *szLine; + BOOLEAN bDecoded = FALSE; + char achTemp[512]; + + /* decode message */ + if ( p == NULL ) + { + return; + } + + if ( !bIsBasicPart( p->nCurrentMessageType ) || p->pCurrentMessage == NULL ) + { + return; + } + + pMimeBasicPart = (mime_basicPart_t *) p->pCurrentMessage; + pMimeBasicPart_internal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + /* already decoded */ + if ( pMimeBasicPart_internal == NULL || + pMimeBasicPart_internal->bDecodedData || + pMimeBasicPart_internal->nRawMessageSize == 0 || + pMimeBasicPart_internal->nStartMessageDataIndex == UNINITIALIZED ) + { + return; + } + + /* base64 */ + if ( pMimeBasicPart->encoding_type == MIME_ENCODING_BASE64 && IsDecodeData(p) ) + { + len = decodeBase64Vector( pMimeBasicPart_internal->nStartMessageDataIndex, + pMimeBasicPart_internal->nEndMessageDataIndex, + p->pVectorMessageData, + &szDecodedBuffer, + pMimeBasicPart_internal->nRawMessageSize, + p->pDataSink != NULL ? &p->out_byte : NULL, + p->pDataSink != NULL ? &p->out_bits : NULL ); + + if ( len > 0 ) + { + saveBodyData( p, szDecodedBuffer, len, pMimeBasicPart ); + bDecoded = TRUE; + + if ( p->pDataSink != NULL && !IsLocalStorage(p) ) + { + free( szDecodedBuffer ); + } + } + } + + /* quoted printable */ + else if ( pMimeBasicPart->encoding_type == MIME_ENCODING_QP && IsDecodeData(p) ) + { + len = decodeQPVector (pMimeBasicPart_internal->nStartMessageDataIndex, + pMimeBasicPart_internal->nEndMessageDataIndex, + p->pVectorMessageData, + &szDecodedBuffer, + pMimeBasicPart_internal->nRawMessageSize, + p->achQPLeftOverBytes, + &p->QPNoOfLeftOverBytes); + + if ( len > 0 ) + { + saveBodyData( p, szDecodedBuffer, len, pMimeBasicPart ); + bDecoded = TRUE; + + if ( p->pDataSink != NULL && !IsLocalStorage(p) ) + { + free( szDecodedBuffer ); + } + } + } + /* plain buffer creation */ + else + { + i = pMimeBasicPart_internal->nEndMessageDataIndex - pMimeBasicPart_internal->nStartMessageDataIndex + 1; + + /* build buffer */ + szNewBuffer = (char *) malloc( pMimeBasicPart_internal->nRawMessageSize + 2 + ( i * 2) ); + + if ( szNewBuffer != NULL ) + { + for ( i = pMimeBasicPart_internal->nStartMessageDataIndex, offset = 0; + i <= pMimeBasicPart_internal->nEndMessageDataIndex; + i++ ) + { + szLine = (char *) Vector_elementAt( p->pVectorMessageData, i ); + sprintf( achTemp, "%s\r\n", szLine ); + + if ( szLine != NULL ) + { + len = strlen( achTemp ); + strncpy( &szNewBuffer[ offset ], achTemp, len ); + offset += len; + } + } + + /* pMimeBasicPart_internal->nMessageSize = pMimeBasicPart_internal->nRawMessageSize; */ + pMimeBasicPart_internal->nMessageSize = offset; + szNewBuffer[offset] = NULL; + } + + saveBodyData( p, szNewBuffer, offset, pMimeBasicPart ); + bDecoded = TRUE; + + if ( p->pDataSink != NULL && !IsLocalStorage(p) ) + { + free( szNewBuffer ); + } + } + + Vector_deleteAll( p->pVectorMessageData ); + + if ( bDecoded ) + { + if ( p->pDataSink == NULL ) + { + pMimeBasicPart_internal->bDecodedData = TRUE; + p->bStartData = FALSE; + } + else + { + pMimeBasicPart_internal->nStartMessageDataIndex = UNINITIALIZED; + pMimeBasicPart_internal->nEndMessageDataIndex = UNINITIALIZED; + } + } + + return; +} + + + + +/* +* carsonl, jan 8,98 +* parse data from either an inputstream or data buffer, if pInput != NULL, then it read data off the inputstream +* else if pData != NULL, then it reads data from the data buffer +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* nsmail_inputstream_t *pInput : inputstream +* char *pData : data buffer +* int nLen : size of data buffer +* int nContentType : +* use nContentType = 0 if you want it to parse the entire message +* nContentType >= MIME_CONTENT_TEXT && <= MIME_CONTENT_APPLICATION for basicPart +* nContentType = MIME_CONTENT_MULTIPART for multiPart +* nContentType = MIME_CONTENT_MESSAGEPART for messagePart +* +* void **ppReturn : (output) fully populated message structure +* if nContentType = 0 or MIME_PARSE_ALL mimeMessage +* nContentType == MIME_BASICPART mimeBasicPart +* nContentType = MIME_MULTIPART mimeMultiPart +* nContentType = MIME_MESSAGEPART mimeMessagePart +* +* returns : MIME_OK, MIME_INVALIDPARAM +*/ +int mimeParser_parseMimeMessage (mimeParser_t *p, nsmail_inputstream_t *pInput, + char *pData, int nLen, int nContentType, void **ppReturn ) +{ + int offset; + int ch; + int nNoOfBytes; + char *s; + int i, ret; + mime_message_t *pMimeMessage; + mime_message_internal_t *pMimeMessageInternal; + BOOLEAN bLastLine = FALSE; + BOOLEAN bBufferFull = TRUE; + + if ( p == NULL || ( pInput == NULL && pData == NULL ) ) + { + return MIME_ERR_INVALIDPARAM; + } + + offset = p->nLeftoverBytes; + + /* inputstream version */ + if ( pInput != NULL ) + { + for ( nNoOfBytes = (pInput->read)( pInput->rock, (char *) p->pInputBuffer, BUFFER_SIZE ); + nNoOfBytes > 0; + nNoOfBytes = (pInput->read)( pInput->rock, (char *) p->pInputBuffer, BUFFER_SIZE ) ) + { + if ( nNoOfBytes < BUFFER_SIZE ) + bBufferFull = FALSE; + + for ( i = 0, ch = p->pInputBuffer[i]; i < nNoOfBytes; ch = p->pInputBuffer[ ++i ] ) + { + /* eat it */ + if ( !p->bReadCR && ch == '\r' ) + continue; + + else if ( ch == '\n' ) + { + p->pLeftoverBuffer[offset] = 0; + s = szTrim( p->pLeftoverBuffer ); + + if ( !bBufferFull && i == nNoOfBytes - 1 ) + bLastLine = TRUE; + + /* look for continuation */ + if ( bStringEquals( s, "content-" ) ) + { + /*fprintf (stderr, "strlen(s)=%d offset=%d\n", strlen(s),offset);*/ + if (offset > strlen(s)) + offset = strlen(s); + if ( p->pInputBuffer[i+1] == ' ' || p->pInputBuffer[i+1] == '\t' ) + { + p->pLeftoverBuffer[offset++] = ch; + p->pLeftoverBuffer[offset] = 0; + continue; + } + } + + if ( p->bReadCR ) + { + p->pLeftoverBuffer[offset++] = ch; + p->pLeftoverBuffer[offset] = 0; + } + + ret = mimeParser_parseLine( p, p->pLeftoverBuffer, offset, bLastLine ); + if (ret != MIME_OK) + return ret; + offset = 0; + + continue; + } + + p->pLeftoverBuffer[ offset++ ] = ch; + } + } + + /* handle lastline */ + if ( p->pDataSink == NULL && offset != 0 ) + { + ret = mimeParser_parseLine( p, p->pLeftoverBuffer, offset, bLastLine ); + if (ret != MIME_OK) + return ret; + } + + p->nLeftoverBytes = offset; + } + + /* buffer version */ + else if ( pData != NULL ) + { + for ( i = 0, ch = pData[i]; i < nLen; ch = pData[ ++i ] ) + { + /* eat it */ + if ( !p->bReadCR && ch == '\r' ) + continue; + + else if ( ch == '\n' ) + { + p->pLeftoverBuffer[offset] = 0; + s = szTrim( p->pLeftoverBuffer ); + + /* look for continuation */ + /*if ( bStringEquals( s, "content-" ) && p->pLeftoverBuffer[ offset - 1 ] == ';' )*/ + if (bStringEquals(s, "content-")) + { + if (offset > strlen(s)) + offset = strlen(s); + if ( pData[i+1] == ' ' || pData[i+1] == '\t' ) + { + p->pLeftoverBuffer[offset++] = ch; + p->pLeftoverBuffer[offset] = 0; + continue; + } + } + + if ( p->bReadCR ) + { + p->pLeftoverBuffer[offset++] = ch; + p->pLeftoverBuffer[offset] = 0; + } + + ret = mimeParser_parseLine( p, p->pLeftoverBuffer, offset, bLastLine ); + if (ret != MIME_OK) + return ret; + offset = 0; + + continue; + } + + p->pLeftoverBuffer[ offset++ ] = ch; + } + + /* handle lastline */ + if ( p->pDataSink == NULL && offset != 0 ) + { + ret = mimeParser_parseLine( p, p->pLeftoverBuffer, offset, bLastLine ); + if (ret != MIME_OK) + return ret; + } + + p->nLeftoverBytes = offset; + } + + /* for simple messages with no boundary */ + if ( ( p->pMimeMessage != NULL && p->pDataSink == null ) || + ( p->bLocalStorage && p->pDataSink != null ) ) + { + decodeDataBuffer(p); + } + + pMimeMessage = p->pMimeMessage; + pMimeMessageInternal = (mime_message_internal_t *) p->pMimeMessage->pInternal; + + if ( ppReturn != NULL ) + { + switch ( nContentType ) + { + case MIME_PARSE_ALL: + *ppReturn = (void *) p->pMimeMessage; + p->pMimeMessage = NULL; /* user is responsible for freeing the memory */ + break; + + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + case MIME_BASICPART: + *ppReturn = (void *) pMimeMessageInternal->pMimeBasicPart; + pMimeMessageInternal->pMimeBasicPart = NULL; /* user is responsible for freeing the memory */ + break; + + case MIME_CONTENT_MULTIPART: + *ppReturn = (void *) pMimeMessageInternal->pMimeMultiPart; + pMimeMessageInternal->pMimeMultiPart = NULL; /* user is responsible for freeing the memory */ + break; + + case MIME_CONTENT_MESSAGEPART: + *ppReturn = (void *) pMimeMessageInternal->pMimeMessagePart; + pMimeMessageInternal->pMimeMessagePart = NULL; /* user is responsible for freeing the memory */ + break; + } + } + +/* + if ( pMimeMessage != NULL && ) + checkForEmptyMessages( p, pMimeMessage, MIME_MESSAGE ); +*/ + + return MIME_OK; +} + + + + + +/* +* carsonl, jan 8,98 +* save message data +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* char *pBuffer : input buffer +* int nLen : size of buffer +* mime_basicPart_t *pMimeBasicPart : the corresponding basicPart that is linked with this data +* +* returns : nothing +*/ +static void saveBodyData( mimeParser_t *p, char *pBuffer, int nLen, mime_basicPart_t *pMimeBasicPart ) +{ + mime_basicPart_internal_t *pMimeBasicPart_internal; + int nSize; + char *szBuffer; + + if ( p == NULL || pBuffer == NULL || pMimeBasicPart == NULL ) + { + return; + } + + if ( nLen <= 0 ) + return; + + pMimeBasicPart_internal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + if ( pMimeBasicPart_internal == NULL ) + return; + + if ( IsLocalStorage(p) ) + { + if ( p->bParseEntireFile ) + { + pMimeBasicPart_internal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + if ( pMimeBasicPart_internal != NULL ) + { + pMimeBasicPart_internal->szMessageBody = pBuffer; + pMimeBasicPart_internal->nMessageSize = nLen; + } + } + else + { + if ( pMimeBasicPart_internal->szMessageBody == NULL ) + { + pMimeBasicPart_internal->szMessageBody = pBuffer; + pMimeBasicPart_internal->nMessageSize = nLen; + pMimeBasicPart_internal->nDynamicBufferSize = nLen; + } + + /* append to existing buffer */ + else + { + /* still fits */ + if ( pMimeBasicPart_internal->nDynamicBufferSize - pMimeBasicPart_internal->nMessageSize > nLen ) + { + memcpy( &pMimeBasicPart_internal->szMessageBody[ pMimeBasicPart_internal->nMessageSize ], pBuffer, nLen ); + pMimeBasicPart_internal->nMessageSize += nLen; + } + + /* doesn't fit */ + else + { + nSize = ( nLen * 2 ) > BUFFER_INCREMENT ? nLen * 2 : BUFFER_INCREMENT; + nSize += pMimeBasicPart_internal->nMessageSize; + + szBuffer = (char*) malloc( nSize + 1 ); + + if ( szBuffer != NULL ) + { + memcpy( szBuffer, pMimeBasicPart_internal->szMessageBody, pMimeBasicPart_internal->nMessageSize ); + memcpy( &szBuffer[ pMimeBasicPart_internal->nMessageSize ], pBuffer, nLen ); + + if ( pMimeBasicPart_internal->szMessageBody != NULL ) + { + free( pMimeBasicPart_internal->szMessageBody ); + pMimeBasicPart_internal->szMessageBody = NULL; + } + + pMimeBasicPart_internal->szMessageBody = szBuffer; + pMimeBasicPart_internal->nMessageSize += nLen; + pMimeBasicPart_internal->nDynamicBufferSize = nSize; + } + else + { + } + } + + free( pBuffer ); + } + } + } + + if ( p->pDataSink != null && p->pDataSink->bodyData != NULL ) + (p->pDataSink->bodyData)(p->pDataSink, pMimeBasicPart_internal->pUserObject, pBuffer, nLen ); + else + pMimeBasicPart_internal->bDecodedData = TRUE; +} + + + + +static int nAddMessage( mimeParser_t *p, void *pMessage, mime_content_type nContentType ) +{ + mime_message_t *pMimeMessage; + mime_message_internal_t *pMimeMessageInternal; + mime_multiPart_t *pMimeMultiPart; + mime_messagePart_t *pMimeMessagePart; + mime_messagePart_internal_t *pMimeMessagePartInternal; + int index; + + if ( p == NULL || pMessage == NULL ) + { +#ifdef ERRORLOG + errorLog( "nAddMessage()", MIME_ERR_INVALIDPARAM ); +#endif + + return MIME_ERR_INVALIDPARAM; + } + + pMimeMessageInternal = (mime_message_internal_t *) p->pMimeMessage->pInternal; + + if ( p->nMessageType == MIME_CONTENT_UNINITIALIZED && pMimeMessageInternal != NULL ) + { + if ( bIsBasicPart( nContentType ) ) + { + mime_message_addBasicPart_clonable( p->pMimeMessage, (mime_basicPart_t *) pMessage, FALSE ); + p->nMessageType = MIME_BASICPART; + } + + else if ( nContentType == MIME_CONTENT_MULTIPART ) + { + mime_message_addMultiPart_clonable( p->pMimeMessage, (mime_multiPart_t *) pMessage, FALSE ); + p->nMessageType = MIME_CONTENT_MULTIPART; + vAddCurrentParent( p, MIME_MULTIPART, pMessage ); + p->fSeenBoundary = FALSE; + } + + else if ( nContentType == MIME_CONTENT_MESSAGEPART ) + { + mime_message_addMessagePart_clonable( p->pMimeMessage, (mime_messagePart_t *) pMessage, FALSE ); + p->nMessageType = MIME_CONTENT_MESSAGEPART; + + vAddCurrentParent( p, MIME_MESSAGEPART, pMessage ); + } + } + + /* add to mimemessage */ + else if ( nGetCurrentParentType(p) == MIME_MESSAGE ) + { + pMimeMessage = pGetCurrentParent(p); + + if ( pMimeMessage != NULL && pMimeMessage->pInternal != NULL ) + { + if ( bIsBasicPart( nContentType ) ) + { + mime_message_addBasicPart( pMimeMessage, (mime_basicPart_t *) pMessage, FALSE ); + } + + else if ( nContentType == MIME_CONTENT_MULTIPART ) + { + mime_message_addMultiPart( pMimeMessage, (mime_multiPart_t *) pMessage, FALSE ); + + /* reset current parent */ + vAddCurrentParent( p, MIME_MULTIPART, pMessage ); + } + + else if ( nContentType == MIME_CONTENT_MESSAGEPART ) + { + mime_message_addMessagePart( pMimeMessage, (mime_messagePart_t *) pMessage, FALSE ); + + /* reset current parent */ + pMimeMessagePart = (mime_messagePart_t *) pMessage; + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessagePartInternal != NULL ) + { + vAddCurrentParent( p, MIME_MESSAGEPART, pMessage ); + + /* reset current mimeMessage */ + p->pCurrentMimeMessage = pMimeMessagePartInternal->pTheMessage; + } + } + } + } + + else if ( nGetCurrentParentType(p) == MIME_MULTIPART ) + { + pMimeMultiPart = pGetCurrentParent(p); + + if ( bIsBasicPart( nContentType ) ) + { + mime_multiPart_addBasicPart( pMimeMultiPart, (mime_basicPart_t *) pMessage, FALSE, &index ); + } + + else if ( nContentType == MIME_CONTENT_MULTIPART ) + { + mime_multiPart_addMultiPart( pMimeMultiPart, (mime_multiPart_t *) pMessage, FALSE, &index ); + + /* reset current parent */ + vAddCurrentParent( p, MIME_MULTIPART, pMessage ); + } + + else if ( nContentType == MIME_CONTENT_MESSAGEPART ) + { + mime_multiPart_addMessagePart( pMimeMultiPart, (mime_messagePart_t *) pMessage, FALSE, &index ); + + /* reset current parent */ + vAddCurrentParent( p, MIME_MESSAGEPART, pMessage ); + } + } + + else if ( nGetCurrentParentType(p) == MIME_MESSAGEPART ) + { + pMimeMessagePart = pGetCurrentParent(p); + + if ( pMimeMessagePart != NULL && pMimeMessagePart->pInternal != NULL ) + { + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + pMimeMessage = pMimeMessagePartInternal->pTheMessage; + + if ( pMimeMessage != NULL ) + { + if ( bIsBasicPart( nContentType ) ) + { + mime_message_addBasicPart( pMimeMessage, (mime_basicPart_t *) pMessage, FALSE ); + } + + else if ( nContentType == MIME_CONTENT_MULTIPART ) + { + mime_message_addMultiPart( pMimeMessage, (mime_multiPart_t *) pMessage, FALSE ); + + /* reset current parent */ + vAddCurrentParent( p, MIME_MULTIPART, pMessage ); + } + + else if ( nContentType == MIME_CONTENT_MESSAGEPART ) + { + mime_message_addMessagePart( pMimeMessage, (mime_messagePart_t *) pMessage, FALSE ); + + /* reset current parent */ + pMimeMessagePart = (mime_messagePart_t *) pMessage; + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessagePartInternal != NULL ) + { + vAddCurrentParent( p, MIME_MESSAGEPART, pMessage ); + + /* reset current mimeMessage */ + p->pCurrentMimeMessage = pMimeMessagePartInternal->pTheMessage; + } + } + } + } + } + + setCurrentMessage( p, pMessage, nContentType ); + + return MIME_OK; +} + + + +/* --------------------------------- helper routines -------------------------------- */ + + + +/* +* carsonl, jan 8,98 +* get content type +* +* parameter : +* +* char *s : input buffer +* char *szSubtype : (output) subtype returned +* char **ppParam : (output) extra parameters +* +* out_bits : number of bits remaining, used internally by mimeParser +* out_byte : output byte, used internally by mimeParser +* int *pLen : number of bytes in buffer +* +* returns : content type +*/ +mime_content_type mimeParser_nGetContentType( char *s, char *szSubtype, char **ppParam ) +{ + int i, nStart, nSubtypeStart; + char achContentType[64]; + mime_content_type nContentType = MIME_CONTENT_UNINITIALIZED; + + if ( s == NULL || szSubtype == NULL || ppParam == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + achContentType[0] = 0; + szSubtype[0] = 0; + + /* skip spaces and colons */ + for ( i=0; s[i] != 0 && ( isspace( s[i] ) || s[i] == ':' ); i++ ) + ; + + /* skip to subtype */ + for ( nStart = i; s[i] != 0 && s[i] != '/' && s[i] != ';'; i++ ) + ; + + /* content type */ + strncpy( achContentType, &s[nStart], i - nStart ); + achContentType[ i - nStart ] = 0; + + /* content subtype */ + if ( s[i] == '/' ) + { + for ( nSubtypeStart = ++i; s[i] != 0 && s[i] != ';' && s[i] != ','; i++ ) + ; + + /* content subtype */ + strncpy( szSubtype, &s[nSubtypeStart], i - nSubtypeStart ); + szSubtype[ i - nSubtypeStart ] = 0; + } + + for ( ; i < s[i] != 0 && ( s[i] == ' ' || s[i] == ';' || s[i] == ',' ); i++ ) + ; + + *ppParam = i > (int) strlen(s) - 1 ? NULL : &s[i]; + + /* determine content type */ + if ( bStringEquals( achContentType, "text" ) ) + nContentType = MIME_CONTENT_TEXT; + + else if ( bStringEquals( achContentType, "audio" ) ) + nContentType = MIME_CONTENT_AUDIO; + + else if ( bStringEquals( achContentType, "image" ) ) + nContentType = MIME_CONTENT_IMAGE; + + else if ( bStringEquals( achContentType, "video" ) ) + nContentType = MIME_CONTENT_VIDEO; + + else if ( bStringEquals( achContentType, "application" ) ) + nContentType = MIME_CONTENT_APPLICATION; + + else if ( bStringEquals( achContentType, "multipart" ) ) + nContentType = MIME_CONTENT_MULTIPART; + + else if ( bStringEquals( achContentType, "message" ) ) + nContentType = MIME_CONTENT_MESSAGEPART; + + else + { + /*nContentType = MIME_CONTENT_TEXT;*/ + return MIME_ERR_INVALID_CONTENTTYPE; + } + + return nContentType; +} + + + +/* return boundary string, default to "-----" if none is found */ +/* +* carsonl, jan 8,98 +* parse for boundary +* +* parameter : +* +* char *s : input buffer +* +* returns : boundary string +* returns : default to "-----" if none is found +*/ +char *mimeParser_parseForBoundary( char *s ) +{ + char achBuffer[64]; + char *szStart; + char *szStart2; + int nLen; + BOOLEAN bQuotes = FALSE; + + if ( s == NULL ) + { + return NULL; + } + + szStart = strstr( s, "boundary" ); + + if ( szStart == NULL ) + strcpy( achBuffer, "-----" ); + + else + { + /* skip spaces and colons */ + for ( szStart += 9; *szStart != 0 && ( isspace( *szStart ) || *szStart == '=' ); szStart++ ) + ; + + if ( *szStart == '"' ) + { + bQuotes = TRUE; + szStart++; + } + + szStart2 = szStart; + + for ( nLen = 0; *szStart != 0 && *szStart != ';'; nLen++, szStart++ ) + { + if ( bQuotes && *szStart == '"' ) + break; + } + + if ( nLen < 61 ) + { + strncpy( achBuffer, szStart2, nLen ); + achBuffer[nLen] = 0; + } + } + + return szStringClone( achBuffer ); +} + + + + +/* +* carsonl, jan 8,98 +* check what kind of line this is +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* char *s : input line +* +* returns : line type +* +* MIME_ERR_INVALIDPARAM; +* MIME_INFO; +* MIME_XHEADER; +* MIME_CRLF; +* MIME_HEADER; +* NOT_A_BOUNDARY; +* END_BOUNDARY; +* START_BOUNDARY; +*/ +int mimeParser_checkForLineType( mimeParser_t *p, char *s, int len ) +{ + int nContentType; + int i; + + if ( p == NULL || s == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( p->bStartData ) + { + nContentType = mimeParser_nBoundaryCheck( p, s, len ); + + if ( nContentType != NOT_A_BOUNDARY ) + return nContentType; + } + + else if ( bStringEquals( s, "content-" ) ) + return MIME_INFO; + + else if ( bStringEquals( s, "x-" ) ) + return MIME_XHEADER; + + else if ( strlen( s ) == 0 ) + return MIME_CRLF; + + else + { + nContentType = mimeParser_nBoundaryCheck( p, s, len ); + + if ( nContentType != NOT_A_BOUNDARY ) + return nContentType; + else + { + for ( i = 0; i < len; i++ ) + { + if ( s[i] == ':' ) + return MIME_HEADER; + } + } + } + + return MIME_MESSAGE_DATA; +} + + + + +/* +* carsonl, jan 8,98 +* determine if line is a boundary +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* char *s : input string +* +* returns : boundary type +* +* START_BOUNDARY if it's a start boundary +* END_BOUNDARY if it's a end boundary +* NOT_A_BOUNDARY if it's not a boundary +*/ +int mimeParser_nBoundaryCheck( mimeParser_t *p, char *s, int len ) +{ + int boundaryLen; + char * currentBoundary; + + if ( p == NULL || s == NULL ) + { + return NOT_A_BOUNDARY; + } + + currentBoundary = mimeParser_getCurrentBoundary (p); + + if (currentBoundary == NULL) + return NOT_A_BOUNDARY; + + boundaryLen = strlen (currentBoundary); + + if ((len >= boundaryLen + 4) && s [0] == '-' && s [1] == '-' && + s [boundaryLen + 2] == '-' && s [boundaryLen + 3] == '-' && + bStringEquals (&s[2], mimeParser_getCurrentBoundary (p)) ) + return END_BOUNDARY; + else if ((len >= boundaryLen + 2) && s [0] == '-' && s [1] == '-' && + bStringEquals (&s[2], mimeParser_getCurrentBoundary (p)) ) + return START_BOUNDARY; + + +/* if ( s[len - 1] == '-' && s[len - 2] == '-' && bStringEquals( &s[2], mimeParser_getCurrentBoundary( p ) ) ) + * return END_BOUNDARY; + * + * else if ( s[0] == '-' && s[1] == '-' && bStringEquals( &s[2], mimeParser_getCurrentBoundary( p ) ) ) + * return START_BOUNDARY; + */ + + return NOT_A_BOUNDARY; +} + + +static void * getUserObject2 (void *pMessage, int contType) +{ + if (contType >= 0) + switch (contType) + { + case MIME_CONTENT_TEXT: + case MIME_CONTENT_AUDIO: + case MIME_CONTENT_IMAGE: + case MIME_CONTENT_VIDEO: + case MIME_CONTENT_APPLICATION: + return getUserObject (pMessage, MIME_BASICPART); + case MIME_CONTENT_MULTIPART: + return getUserObject (pMessage, MIME_MULTIPART); + case MIME_CONTENT_MESSAGEPART: + return getUserObject (pMessage, MIME_MESSAGEPART); + } + + return null; +} + + +/* +* carsonl, jan 8,98 +* get user object, for dynamic parsing only +* +* parameter : +* +* void *pMessage : input message +* int nType : message/part type +* +* returns : return user object for that part +*/ +static void *getUserObject( void *pMessage, int nType ) +{ + mime_message_t *pMimeMessage; + mime_message_internal_t *pMimeMessageInternal; + mime_basicPart_t *pMimeBasicPart; + mime_multiPart_t *pMimeMultiPart; + mime_messagePart_t *pMimeMessagePart; + mime_basicPart_internal_t *pMimeBasicPartInternal; + mime_multiPart_internal_t *pMimeMultiPartInternal; + mime_messagePart_internal_t *pMimeMessagePartInternal; + + if ( pMessage == NULL ) + { + return NULL; + } + + switch ( nType ) + { + case MIME_MESSAGE: + + pMimeMessage = (mime_message_t *) pMessage; + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessageInternal != NULL ) + return pMimeMessageInternal->pUserObject; + break; + + case MIME_BASICPART: + + pMimeBasicPart = (mime_basicPart_t *) pMessage; + pMimeBasicPartInternal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + if ( pMimeBasicPartInternal != NULL ) + return pMimeBasicPartInternal->pUserObject; + break; + + case MIME_MULTIPART: + + pMimeMultiPart = (mime_multiPart_t *) pMessage; + pMimeMultiPartInternal = (mime_multiPart_internal_t *) pMimeMultiPart->pInternal; + + if ( pMimeMultiPartInternal != NULL ) + return pMimeMultiPartInternal->pUserObject; + break; + + case MIME_MESSAGEPART: + + pMimeMessagePart = (mime_messagePart_t *) pMessage; + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + if ( pMimeMessagePartInternal != NULL ) + return pMimeMessagePartInternal->pUserObject; + break; + } +} + + + + +/* +* carsonl, jan 8,98 +* set user object, only for dynamic parsing +* +* parameter : +* +* void *pMessage : input message +* int nType : message/part type +* void *pUserObject : user object +* +* returns : nothing +*/ +static void setUserObject( void *pMessage, int nType, void *pUserObject ) +{ + mime_message_t *pMimeMessage; + mime_message_internal_t *pMimeMessageInternal; + mime_basicPart_t *pMimeBasicPart; + mime_multiPart_t *pMimeMultiPart; + mime_messagePart_t *pMimeMessagePart; + mime_basicPart_internal_t *pMimeBasicPartInternal; + mime_multiPart_internal_t *pMimeMultiPartInternal; + mime_messagePart_internal_t *pMimeMessagePartInternal; + + if ( pMessage == NULL ) + { + return; + } + + switch ( nType ) + { + case MIME_MESSAGE: + + pMimeMessage = (mime_message_t *) pMessage; + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessageInternal != NULL ) + pMimeMessageInternal->pUserObject = pUserObject; + break; + + case MIME_BASICPART: + + pMimeBasicPart = (mime_basicPart_t *) pMessage; + pMimeBasicPartInternal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + if ( pMimeBasicPartInternal != NULL ) + pMimeBasicPartInternal->pUserObject = pUserObject; + break; + + case MIME_MULTIPART: + + pMimeMultiPart = (mime_multiPart_t *) pMessage; + pMimeMultiPartInternal = (mime_multiPart_internal_t *) pMimeMultiPart->pInternal; + + if ( pMimeMultiPartInternal != NULL ) + pMimeMultiPartInternal->pUserObject = pUserObject; + break; + + case MIME_MESSAGEPART: + + pMimeMessagePart = (mime_messagePart_t *) pMessage; + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + if ( pMimeMessagePartInternal != NULL ) + pMimeMessagePartInternal->pUserObject = pUserObject; + break; + } +} + + + +/* +* carsonl, jan 8,98 +* decode remaining bytes for dynamic parsing +* +* parameter : +* +* out_bits : number of bits remaining, used internally by mimeParser +* out_byte : output byte, used internally by mimeParser +* int *pLen : number of bytes in buffer +* +* returns +* +* NULL not enought buffer space, should never happen +* char * decoded buffer, null terminated +* pLen length of data +* +* NOTE: the user should set the bDecodeData field within their datasinks prior to giving it to the parser +*/ +static char *decodeBase64LeftOverBytes( int out_bits, int out_byte, int *pLen ) +{ + int mask; + static char szOutput[5]; + int byte_pos = 0; + + if ( pLen == NULL ) + { + return NULL; + } + + /* Handle any bits still in the queue */ + while (out_bits >= 8) + { + if ( byte_pos >= 4 ) + { + return NULL; + } + + if (out_bits == 8) + { + szOutput[byte_pos++] = out_byte; + out_byte = 0; + } + + else + { + mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8)); + szOutput[byte_pos++] = (out_byte & mask) >> (out_bits - 8); + out_byte &= ~mask; + } + + out_bits -= 8; + } + + szOutput[ byte_pos ] = 0; + *pLen = byte_pos; + + return szOutput; +} + + + + +/* +* carsonl, jan 8,98 +* test if data should be stored locally +* +* parameter : +* +* mimeParser_t *p pointer to mimeParser +* +* return : +* +* TRUE if not using dynamic parsing or data should be stored locally +* FALSE if using dynamic parsing with no local storage +* +* NOTE: the user should set the bLocalStorage field within their datasinks prior to giving it to the parser +*/ +/*BOOLEAN IsLocalStorage( mimeParser_t *p ) { return p->pDataSink == NULL ? TRUE : p->pDataSink->bLocalStorage; } */ +BOOLEAN IsLocalStorage( mimeParser_t *p ) { return p->bLocalStorage; } + + + +/* +* carsonl, jan 8,98 +* test if data should be decoded +* +* parameter : +* +* mimeParser_t *p pointer to mimeParser +* +* return : +* +* TRUE decode data +* FALSE don't decode data, just parse +* +* NOTE: the user should set the bDecodeData field within their datasinks prior to giving it to the parser +*/ +/*BOOLEAN IsDecodeData( mimeParser_t *p ) { return p->pDataSink == NULL ? TRUE : p->pDataSink->bDecodeData; } */ +BOOLEAN IsDecodeData( mimeParser_t *p ) { return p->bDecodeData; } + + + + +/* +* carsonl, jan 8,98 +* get the boundary corresponding to the current multiPart message +* +* parameter : +* +* mimeParser_t *p : instance of mimeParser +* +* returns : current boundary as a null terminated string +*/ +char *mimeParser_getCurrentBoundary( mimeParser_t *p ) +{ + mime_multiPart_t *pMimeMultiPart; + mime_multiPart_internal_t *pMimeMultiPartInternal; + int i; + + if ( p == NULL ) + { +#ifdef ERRORLOG + errorLog( "mimeParser_getCurrentBoundary()", MIME_ERR_INVALIDPARAM ); +#endif + + return NULL; + } + + for ( i = p->nCurrentParent - 1; i >= 0; i-- ) + { + if ( p->aCurrentParent[i].p != NULL && p->aCurrentParent[i].type == MIME_MULTIPART ) + { + pMimeMultiPart = (mime_multiPart_t *) p->aCurrentParent[i].p; + pMimeMultiPartInternal = (mime_multiPart_internal_t *) pMimeMultiPart->pInternal; + + if ( pMimeMultiPartInternal != NULL ) + return pMimeMultiPartInternal->szBoundary; + } + } + + return NULL; +} + + + +int nGetCurrentParentType( mimeParser_t *p ) +{ + return p->aCurrentParent[ p->nCurrentParent - 1 ].type; +} + + + +void *pGetCurrentParent( mimeParser_t *p ) +{ + return p->aCurrentParent[ p->nCurrentParent - 1 ].p; +} + + + +void vAddCurrentParent( mimeParser_t *p, int nType, void *pParent ) +{ + if ( p->nCurrentParent < MAX_MULTIPART ) + { + p->aCurrentParent[ p->nCurrentParent ].type = nType; + p->aCurrentParent[ p->nCurrentParent++ ].p = pParent; + } + + else + { +#ifdef ERRORLOG + errorLog( "mimeParser_vAddCurrentParent()", MIME_ERR_MAX_NESTED_PARTS_REACHED ); +#endif + } +} + + + +void mimeParser_unwindCurrentBoundary( mimeParser_t *p, char *s, BOOLEAN bDelete ) +{ + mime_multiPart_t *pMimeMultiPart; + mime_multiPart_internal_t *pMimeMultiPartInternal; + int i; + char *szBoundary = NULL; + + if ( p == NULL ) + { +#ifdef ERRORLOG + errorLog( "mimeParser_getCurrentBoundary()", MIME_ERR_INVALIDPARAM ); +#endif + } + + for ( i = p->nCurrentParent - 1; i >= 0; i-- ) + { + if ( p->aCurrentParent[i].p != NULL && p->aCurrentParent[i].type == MIME_MULTIPART ) + { + pMimeMultiPart = (mime_multiPart_t *) p->aCurrentParent[i].p; + pMimeMultiPartInternal = (mime_multiPart_internal_t *) pMimeMultiPart->pInternal; + + if ( pMimeMultiPartInternal != NULL ) + szBoundary = pMimeMultiPartInternal->szBoundary; + + if ( szBoundary != NULL && bStringEquals( &s[2], szBoundary ) ) + { + if (p->pDataSink != null && m_needEndMultiPart == TRUE) + { + (p->pDataSink->endMultiPart)(p->pDataSink, getUserObject(p->aCurrentParent[i].p, MIME_MULTIPART)); + m_needEndMultiPart = FALSE; + } + + if ( bDelete ) + p->nCurrentParent--; + + break; + } + } + + p->nCurrentParent--; + } +} + + +void appToLastHdrOnQueue (mimeParser_t *p, char *value) +{ + mimeInfo_t * mi; + int valueLen; + char * newValue; + + mi = (mimeInfo_t *) Vector_popLastElement (p->pHeaderQueue); + valueLen = strlen (mi->szValue) + strlen (value); + + /*newValue = (char *) malloc(valueLen+3); + *memset (newValue, 0, valueLen+3); + *strncat (newValue, "\r\n", 2); + *strcat (newValue, value); + */ + + newValue = (char *) malloc(valueLen+1); + memset (newValue, 0, valueLen+1); + strcpy (newValue, mi->szValue); + strcat (newValue, value); + /* free (mi->szValue) */ + mi->szValue = newValue; + + Vector_addElement (p->pHeaderQueue, mi, sizeof(mimeInfo_t)); +} + +/** +* add header +* +* @author Carson Lee +* @version %I%, %G% +* +* @param mi.name header name +* @param mi.value header value +* @return none +* @exception MIMEException +*/ +static void addHeader( mimeParser_t *p, char *name, char *value, BOOLEAN addToQueue ) +{ + mime_message_t *pMimeMessage; + mime_message_internal_t *pMimeMessageInternal; + mime_basicPart_t *pMimeBasicPart; + mime_basicPart_internal_t *pMimeBasicPartInternal; + mime_messagePart_t *pMimeMessagePart; + mime_messagePart_internal_t *pMimeMessagePartInternal; + mimeInfo_t *mi; + char *szName; + char *szValue; + int i, nSize; + + if ( name == NULL || value == NULL ) + { +#ifdef ERRORLOG + errorLog( "addHeader()", MIME_ERR_INVALIDPARAM ); +#endif + return; + } + + if (p->nCurrentMessageType == UNINITIALIZED && p->tHeaderParent.type == MIME_MESSAGE && + p->tHeaderParent.p == p->pMimeMessage) + { + szName = szStringClone( name ); + szValue = szStringClone( value ); + + pMimeMessage = p->pMimeMessage; + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessage->rfc822_headers == NULL ) + pMimeMessage->rfc822_headers = mime_header_new( szName, szValue ); + else + mime_header_add( pMimeMessage->rfc822_headers, szName, szValue ); + + if (p->pDataSink != NULL && pMimeMessageInternal != NULL && p->pDataSink->header != NULL) + (p->pDataSink->header)(p->pDataSink, pMimeMessageInternal->pUserObject, szName, szValue ); + + p->szPreviousHeaderName = szName; + + return; + } + + /* insert headers from queue */ + if ( addToQueue ) + { + nSize = Vector_size( p->pHeaderQueue ); + + if ( p->nCurrentMessageType != UNINITIALIZED && nSize > 0 ) + { + for ( i = 0; i < nSize; i++ ) + { + mi = (mimeInfo_t *) Vector_elementAt( p->pHeaderQueue, i ); + addHeader( p, mi->szName, mi->szValue, FALSE ); + } + + Vector_deleteAll( p->pHeaderQueue ); + } + } + + /* add to header queue */ + if ( p->nCurrentMessageType == UNINITIALIZED && addToQueue ) + { + mi = mimeInfo_new(); + + if ( mi == NULL ) + { + return; + } + + szName = szStringClone( name ); + szValue = szStringClone( value ); + + mi->szName = szName; + mi->szValue = szValue; + + Vector_addElement( p->pHeaderQueue, mi, sizeof( mimeInfo_t ) ); + } + + else if ( p->tHeaderParent.type == MIME_MESSAGE ) + { + szName = szStringClone( name ); + szValue = szStringClone( value ); + + pMimeMessage = (mime_message_t *) p->tHeaderParent.p; + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessage->rfc822_headers == NULL ) + pMimeMessage->rfc822_headers = mime_header_new( szName, szValue ); + else + mime_header_add( pMimeMessage->rfc822_headers, szName, szValue ); + + if ( p->pDataSink != NULL && pMimeMessageInternal != NULL && p->pDataSink->header != NULL ) + (p->pDataSink->header)(p->pDataSink, pMimeMessageInternal->pUserObject, szName, szValue ); + + p->szPreviousHeaderName = szName; + } + + else + { + if ((p->tHeaderParent.type == MIME_BASICPART) || (bIsBasicPart(p->tHeaderParent.type))) + { + szName = szStringClone( name ); + szValue = szStringClone( value ); + + pMimeBasicPart = (mime_basicPart_t *) p->tHeaderParent.p; + pMimeBasicPartInternal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + if ( pMimeBasicPart->extra_headers == NULL ) + pMimeBasicPart->extra_headers = mime_header_new( szName, szValue ); + else + mime_header_add( pMimeBasicPart->extra_headers, szName, szValue ); + + if ( p->pDataSink != NULL && pMimeBasicPartInternal != NULL && p->pDataSink->header != NULL ) + (p->pDataSink->header)(p->pDataSink, pMimeBasicPartInternal->pUserObject, szName, szValue ); + + p->szPreviousHeaderName = szName; + } + + else if ( p->tHeaderParent.type == MIME_MULTIPART || p->tHeaderParent.type == MIME_MESSAGEPART ) + { + szName = szStringClone( name ); + szValue = szStringClone( value ); + + pMimeMessagePart = (mime_messagePart_t *) p->tHeaderParent.p; + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + if ( pMimeMessagePart->extra_headers == NULL ) + pMimeMessagePart->extra_headers = mime_header_new( szName, szValue ); + else + mime_header_add( pMimeMessagePart->extra_headers, szName, szValue ); + + if ( p->pDataSink != NULL && pMimeMessagePartInternal != NULL && p->pDataSink->header != NULL ) + (p->pDataSink->header)(p->pDataSink, pMimeMessagePartInternal->pUserObject, szName, szValue ); + + p->szPreviousHeaderName = szName; + } + } +} + + + +/** +* check for empty messages in all basicparts +* +* @author Carson Lee +* @version %I%, %G% +* +* @param +* +* o : any mime message structure, usually MIMEMessage +* +* @return none +* @exception MIMEException +*/ +static BOOLEAN checkForEmptyMessages( mimeParser_t *p, void *pMessage, int type ) +{ + mime_message_t *pMimeMessage; + mime_message_internal_t *pMimeMessageInternal; + mime_basicPart_t *pMimeBasicPart; + mime_basicPart_internal_t *pMimeBasicPartInternal; + mime_multiPart_t *pMimeMultiPart; + mime_multiPart_internal_t *pMimeMultiPartInternal; + mime_messagePart_t *pMimeMessagePart; + mime_messagePart_internal_t *pMimeMessagePartInternal; + int i; + mime_mp_partInfo_t *pPartInfo; + BOOLEAN bEmpty = FALSE; + + if ( p == NULL || pMessage == NULL ) + { +#ifdef ERRORLOG + errorLog( "checkForEmptyMessages()", MIME_ERR_INVALIDPARAM ); +#endif + return TRUE; + } + + else if ( type == MIME_MESSAGE ) + { + pMimeMessage = (mime_message_t *) pMessage; + pMimeMessageInternal = (mime_message_internal_t *) pMimeMessage->pInternal; + + if ( pMimeMessageInternal != NULL ) + { + if ( pMimeMessageInternal->pMimeBasicPart != NULL ) + bEmpty = checkForEmptyMessages( p, pMimeMessageInternal->pMimeBasicPart, MIME_BASICPART ); + + else if ( pMimeMessageInternal->pMimeMultiPart != NULL ) + bEmpty = checkForEmptyMessages( p, pMimeMessageInternal->pMimeBasicPart, MIME_MULTIPART ); + + else if ( pMimeMessageInternal->pMimeMessagePart != NULL ) + bEmpty = checkForEmptyMessages( p, pMimeMessageInternal->pMimeBasicPart, MIME_MESSAGEPART ); + } + } + + else if (type == MIME_BASICPART || bIsBasicPart(type)) + { + pMimeBasicPart = (mime_basicPart_t *) pMessage; + pMimeBasicPartInternal = (mime_basicPart_internal_t *) pMimeBasicPart->pInternal; + + if ( pMimeBasicPartInternal != NULL && pMimeBasicPartInternal->nMessageSize == 0 ) + { + bEmpty = TRUE; + +#ifdef ERRORLOG + errorLog( "checkForEmptyMessages()", MIME_ERR_EMPTY_BODY ); +#endif + } + } + + else if ( type == MIME_MULTIPART ) + { + pMimeMultiPart = (mime_multiPart_t *) pMessage; + pMimeMultiPartInternal = (mime_multiPart_internal_t *) pMimeMultiPart->pInternal; + + if ( pMimeMultiPartInternal != NULL ) + { + if ( pMimeMultiPartInternal->nPartCount == 0 ) + { + bEmpty = TRUE; + +#ifdef ERRORLOG + errorLog( "checkForEmptyMessages()", MIME_ERR_EMPTY_BODY ); +#endif + } + else + { + for ( i = 0; !bEmpty && i < pMimeMultiPartInternal->nPartCount; i++ ) + { + pPartInfo = &pMimeMultiPartInternal->partInfo[i]; + + if ( pPartInfo != NULL && pPartInfo->pThePart != NULL ) + bEmpty = checkForEmptyMessages( p, pPartInfo->pThePart, pPartInfo->nContentType ); + } + } + } + } + + else if ( type == MIME_MESSAGEPART ) + { + pMimeMessagePart = (mime_messagePart_t *) pMessage; + pMimeMessagePartInternal = (mime_messagePart_internal_t *) pMimeMessagePart->pInternal; + + if ( pMimeMessagePartInternal != NULL && pMimeMessagePartInternal->pTheMessage != NULL ) + bEmpty = checkForEmptyMessages( p, pMimeMessagePartInternal->pTheMessage, MIME_MESSAGE ); + } + + return bEmpty; +} + + + + +/** +* Set current mesage +* +* @author Carson Lee +* @version %I%, %G% +* +* @param message input message +* @param nMessageType message type +* @return MIME_OK if successful, an error code otherwise +* @exception none +*/ +static int setCurrentMessage( mimeParser_t *p, void *pMessage, int nMessageType ) +{ + + if ( pMessage == null ) + { +#ifdef ERRORLOG + errorLog( "setCurrentMessage()", MIME_ERR_INVALIDPARAM ); +#endif + + return NSMAIL_ERR_INVALIDPARAM; + } + + p->pCurrentMessage = pMessage; + p->nCurrentMessageType = nMessageType; + p->tNextHeaderParent.p = pMessage; + p->tNextHeaderParent.type = nMessageType; + + /* folowing lines duplicated from java side */ + /*if (nMessageType == MIME_BASICPART)*/ + if (bIsBasicPart(nMessageType)) + { + if ((nGetCurrentParentType(p) == MIME_MULTIPART) && p->fSeenBoundary == TRUE) + { + /* start adding following headers to this part itself */ + /* I.e. change header parent */ + p->tHeaderParent.p = pMessage; + p->tHeaderParent.type = nMessageType; + p->tNextHeaderParent.p = pMessage; + p->tNextHeaderParent.type = nMessageType; + } + } + + return NSMAIL_OK; +} + + diff --git a/msgsdk/C/protocol/MIME/src/nsmail_inputstream.c b/msgsdk/C/protocol/MIME/src/nsmail_inputstream.c new file mode 100644 index 000000000000..73c466db662b --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/nsmail_inputstream.c @@ -0,0 +1,283 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +/* +* nsmail_inputstream.c +* carsonl, jan 8,98 +* +* simple routines for a file inputstream implementation +*/ + + +#include +#include +#include + +#include "nsmail.h" +#include "vector.h" +#include "util.h" +#include "mime.h" +#include "mime_internal.h" +#include "mimeparser.h" +#include "mimeparser_internal.h" +#include + + + +/* +* carsonl, jan 8,98 +* constructor +* +* parameter : filename +* +* returns : new rock +*/ +int fileRock_new( char *filename, fileRock_t **ppRock ) +{ + if ( filename == NULL || ppRock == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + *ppRock = (fileRock_t *) malloc( sizeof( fileRock_t ) ); + + if ( *ppRock == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + + (*ppRock)->filename = filename; + (*ppRock)->offset = 0; + + (*ppRock)->buffer = (char *) malloc( BUFFER_SIZE ); + + if ( (*ppRock)->buffer == NULL ) + { + free( *ppRock ); + *ppRock = NULL; + + return MIME_ERR_OUTOFMEMORY; + } + + (*ppRock)->f = fopen( filename, "r" ); + + if ( (*ppRock)->f == NULL ) + { + free( (*ppRock)->buffer ); + free( *ppRock ); + *ppRock = NULL; + + return MIME_ERR_CANTOPENFILE; + } + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* free rock +* +* parameter : rock +* +* returns : nothing +*/ +void fileRock_free( fileRock_t **ppRock ) +{ + if ( ppRock == NULL ) + { + return; + } + + if ( *ppRock == NULL ) + return; + + if ( (*ppRock)->f != NULL ) + fclose( (*ppRock)->f ); + + if ( (*ppRock)->buffer != NULL ) + free( (*ppRock)->buffer ); + + free( *ppRock ); + *ppRock = NULL; +} + + + +/* +* carsonl, jan 8,98 +* read +* +* parameter : rock, input buffer, size of buffer +* +* returns : number of bytes read +*/ +int fileRock_read( void *rock, char *buf, unsigned size ) +{ + fileRock_t *pRock; + + if ( rock == NULL || buf == NULL ) + { + return 0; + } + + pRock = (fileRock_t *) rock; + + if ( pRock->f == NULL ) + return 0; + + return fread( buf, sizeof(char), size, pRock->f ); +} + + + +/* +* carsonl, jan 8,98 +* rewind +* +* parameter : rock +* +* returns : nothing +*/ +void fileRock_rewind( void *rock ) +{ + fileRock_t *pRock; + + if ( rock == NULL ) + { + return; + } + + pRock = (fileRock_t *) rock; + + if ( pRock->f != NULL ) + { + fseek( pRock->f, 0, SEEK_END ); + } + + return; +} + + + +/* +* carsonl, jan 8,98 +* close +* +* parameter : rock +* +* returns : nothing +*/ +void fileRock_close( void *rock ) +{ + fileRock_t *pRock; + + if ( rock == NULL ) + { + return; + } + + pRock = (fileRock_t *) rock; + + if ( pRock->f != NULL ) + { + fclose( pRock->f ); + pRock->f = NULL; + } + + return; +} + + + +/* +* carsonl, jan 8,98 +* constructor +* +* parameter : +* +* char *filename : filename +* +* returns : new inputstream or NULL if failed +*/ +int nsmail_inputstream_new( char *filename, nsmail_inputstream_t **ppInput ) +{ + int nRet; + + if ( filename == NULL || ppInput == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + *ppInput = (nsmail_inputstream_t *) malloc( sizeof( nsmail_inputstream_t ) ); + + if ( *ppInput == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + + nRet = fileRock_new( filename, (fileRock_t **) &(*ppInput)->rock ); + + if ( nRet == MIME_OK ) + { + (*ppInput)->read = &fileRock_read; + (*ppInput)->rewind = &fileRock_rewind; + (*ppInput)->close = &fileRock_close; + } + + return nRet; +} + + + +/* +* carsonl, jan 8,98 +* destructor +* +* parameter : +* +* nsmail_inputstream_t *in : inputstream +* +* returns : NSMAIL_OK, NSMAIL_ERR_INVALIDPARAM +*/ +void nsmail_inputstream_free( nsmail_inputstream_t **ppInput ) +{ + if ( ppInput == NULL ) + { + return; + } + + if ( *ppInput == NULL ) + return; + + if ( (*ppInput)->rock != NULL ) + fileRock_free( (fileRock_t **) &(*ppInput)->rock ); + + free( *ppInput ); + *ppInput = NULL; +} + diff --git a/msgsdk/C/protocol/MIME/src/util.c b/msgsdk/C/protocol/MIME/src/util.c new file mode 100644 index 000000000000..60a207e5b820 --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/util.c @@ -0,0 +1,2043 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +/* +* util.c +* +* Prasad, Nov 1997 +* clee, Oct 1997 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "vector.h" +#include "util.h" + +#include "mime.h" +#include "mime_internal.h" +#include "mimeparser.h" + + +static errorLog_t *g_pLog; /* default error log file */ + +#define CR '\r' +#define LF '\n' + + +/* base64 translation table */ +struct +{ + unsigned char digits[66]; + unsigned char xlate[256]; + unsigned char xlate_table_made; +} base64 = +{ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + "", + 0 +}; + + + + +/* ------------------- utility functions ------------------ */ +#ifdef HPUX +#define GETTIMEOFDAY(x) gettimeofday(x,(void *)NULL) +#elif defined(AIX) +#define GETTIMEOFDAY(x) gettimeofday(x,(void *)NULL) +#else +#define GETTIMEOFDAY(x) gettimeofday(x) +#endif + + + +/* +* carsonl, jan 8,98 +* determine if both strings are the same based on the length of the second string +* case insensitive +* +* parameter : +* +* s1 : first string +* s2 : second string +* +* returns : TRUE if equals +*/ +int bStringEquals( char *s1, char *s2 ) +{ + static char achBuffer[64]; + int len; + + if ( s1 != NULL && s2 != NULL ) + { + len = strlen( s2 ); + strncpy( achBuffer, s1, len ); + achBuffer[len] = 0; + +#ifdef XP_UNIX + if (strcasecmp (achBuffer, s2) == 0) + return TRUE; +#else + if ( stricmp( achBuffer, s2 ) == 0 ) + return TRUE; +#endif + } + + return FALSE; +} + +/* If s1 equals s2, returns TRUE, FALSE otherwise. */ +BOOLEAN equalsIgnoreCase (char * s1, char * s2) +{ +#ifdef XP_UNIX + if (strcasecmp (s1, s2) == 0) + return TRUE; + else + return FALSE; +#else + if (stricmp (s1, s2 ) == 0) + return TRUE; + else + return FALSE; +#endif + +} + + +/* +* carsonl, jan 8,98 +* right trim +* +* parameter : +* +* s : string to be trimmed +* +* returns : string +*/ +char *szRTrim( char *s ) +{ + int i; + + if ( s != NULL ) + { + for ( i = strlen(s); i > 0; i-- ) + { + if ( isspace( s[i-1] ) ) + s[i-1] = 0; + else + return s; + } + } + + return s; +} + + + +/* +* carsonl, jan 8,98 +* left trim +* +* parameter : +* +* s : string to be trimmed +* +* returns : string +*/ +char *szLTrim( char *s ) +{ + char *ss = NULL; + int i; + int len; + + if ( s != NULL ) + { + ss = s; + len = strlen( s ); + + for ( i = 0; i < len; i++, ss++ ) + { + if ( !isspace( s[i] ) ) + return ss; + } + } + + return ss; +} + + + + +/* +* carsonl, jan 8,98 +* trim both sides of the string +* +* parameter : +* +* s : string to be trimmed +* +* returns : string +*/ +char *szTrim( char *s ) { return szLTrim( szRTrim( s ) ); } + + + + +/* +* carsonl, jan 8,98 +* return a new copy of a string passed in +* +* parameter : +* +* s : string to be cloned +* +* returns : cloned string +*/ +char *szStringClone( char *s ) +{ + char *s2 = NULL; + int len; + + if ( s != NULL ) + { + len = strlen( s ); + + if ( len > 0 ) + { + s2 = (char *) malloc( len + 1 ); + + if ( s2 != NULL ) + strcpy( s2, s ); + } + } + + return s2; +} + + + +/* +* carsonl, jan 8,98 +* determine if content type is a basicpart +* +* parameter : +* +* int nType : content type +* +* returns : TRUE if basicpart +*/ +BOOLEAN bIsBasicPart( int nType ) +{ + if (nType == MIME_CONTENT_TEXT || + nType == MIME_CONTENT_AUDIO || + nType == MIME_CONTENT_IMAGE || + nType == MIME_CONTENT_VIDEO || + nType == MIME_CONTENT_APPLICATION ) + return TRUE; + + return FALSE; +} + + + +/* --------------------------------------------- */ + + + +/* +* carsonl, jan 8,98 +* Decodes a string encoded in RFC2047 format. If the string is not encoded +* returns the original string. Can be used on the header value returned by +* getHeader() and getAllHeaders() methods in MIMEMessage class. +* +* parameter : +* +* szInputString : string to be trimmed +* +* return : The decoded header string. +*/ +char *decodeHeader( char *szInputString ) +{ + int len, retLen = 0; + int i, j, outBytes, outBits; + int nStart = 0; + int nEnd = 0; + char *szEncodedText = NULL; + char *szDecodedText = NULL; + char *plainPart = NULL, *retBuf=NULL; + char *leftOverBuf=NULL, *leftOverDecodedBuf=NULL; + int plainTextLen = 0, leftOverLen=0; + char achCharset[16]; + BOOLEAN bEncodeBase64 = FALSE; + BOOLEAN bEncodeQP = FALSE; + BOOLEAN bEncodeString = FALSE; + + if ( szInputString == NULL ) + return NULL; + + len = strlen( szInputString ); + + /* find start of encoding text */ + for ( i = 0; i < len && szInputString[i] != 0 ; i++ ) + { + if ( szInputString[i] == '=' && szInputString[i+1] == '?' ) + { + bEncodeString = TRUE; + break; + } + } + + if (bEncodeString == FALSE) + return (strdup (szInputString)); + + if (i > 0) + { + plainTextLen = (i); + plainPart = malloc (i+1); + strncpy (plainPart, szInputString, plainTextLen); + plainPart [i] = 0; + } + + /* get charset */ + for ( i += 2, j = 0; i < len && szInputString[i] != '?' && j < 15; i++, j++ ) + { + achCharset[j] = szInputString[i]; + } + + achCharset[j] = 0; + i++; /* skip ? */ + + /* get encoding type */ + if ( szInputString[i] == 'Q' || szInputString[i] == 'q' ) + bEncodeQP = TRUE; + + else if ( szInputString[i] == 'B' || szInputString[i] == 'b' ) + bEncodeBase64 = TRUE; + + if (szInputString[i] == '?' ) + i++; /* skip ? */ + nStart = ++i; + + /* look for end of encoded text */ + for ( j = 0; i < len && szInputString[i] != 0; i++, j++ ) + { + if ( szInputString[i] == '?' && (i+1) < len && szInputString[i+1] == '=' ) + { + nEnd = i; + break; + } + } + + if ( nEnd > 0 ) + { + /* extract encoded text */ + szEncodedText = (char *) malloc( j + 1 ); + szDecodedText = (char *) malloc( j + 1 ); + + if ( szEncodedText != NULL && szDecodedText != NULL ) + { + strncpy( szEncodedText, &szInputString[nStart], j ); + + if ( bEncodeQP ) + decodeQP( szEncodedText, szDecodedText, j ); + + else if ( bEncodeBase64 ) + decodeBase64( szEncodedText, szDecodedText, j, j, &outBytes, &outBits ); + + free( szEncodedText ); + } + } + + if (nEnd+2 < len-1) + { + leftOverLen = len - (nEnd+2); + leftOverBuf = malloc (leftOverLen + 1); + strncpy (leftOverBuf, &szInputString[nEnd+2], leftOverLen); + leftOverBuf [leftOverLen] = 0; + leftOverDecodedBuf = decodeHeader (leftOverBuf); + } + + retLen = plainTextLen + strlen (szDecodedText) + strlen (leftOverDecodedBuf); + retBuf = malloc (retLen +1); + + if (plainPart != NULL && szDecodedText != NULL && leftOverDecodedBuf != NULL) + { + sprintf (retBuf, "%s%s%s", plainPart, szDecodedText, leftOverDecodedBuf); + free (plainPart); + free (szDecodedText); + free (leftOverBuf); + free (leftOverDecodedBuf); + } + else if (plainPart != NULL && szDecodedText != NULL) + { + sprintf (retBuf, "%s%s", plainPart, szDecodedText); + free (plainPart); + free (szDecodedText); + } + else if (szDecodedText != NULL && leftOverDecodedBuf != NULL) + { + sprintf (retBuf, "%s%s", szDecodedText, leftOverDecodedBuf); + free (szDecodedText); + free (leftOverBuf); + free (leftOverDecodedBuf); + } + else if (szDecodedText != NULL) + { + free (retBuf); + return szDecodedText; + } + else + { + free (retBuf); + return null; + } + + return retBuf; + +} + + + + +/* +* Prasad +* Generates and returns a boundary string that can be used in multi-parts etc. +* +* @return The boundary string. +*/ +char * generateBoundary() +{ + int randval1, randval2; + struct timeval tv; + char ca[100]; + char * pca; + int ct; + static int prev_randval1=0, prev_randval2=0, counter = 0; + + +#ifdef WIN32 + time_t ltime; + struct tm *ptm; + time( <ime ); + ptm = localtime( <ime ); + ct = ptm->tm_sec; +#else + /*gettimeofday (&tv);*/ + GETTIMEOFDAY(&tv); + ct = tv.tv_sec; +#endif + + /*srand ((unsigned int)ct);*/ + srand ((unsigned int)clock()); + randval1 = rand(); + randval2 = rand(); + /*if (randval1 == prev_randval1 || randval2 == prev_randval2)*/ + { + counter++; + randval1 += counter * 200; + randval2 += counter * 200; + } + + prev_randval1 = randval1; + prev_randval2 = randval2; + + pca = ca; + sprintf (pca, "-------"); + pca += 7; + sprintf (pca, "%x%x%x%x", randval1, randval2, randval1, randval2); + + return (strdup (ca)); +} + + + + +/* +* carsonl, jan 8,98 +* hex to decimal +* +* parameter : +* +* int nFirstByte : first hex byte +* int nSecondByte : second hex byte +* +* returns : decimal +*/ +int nConvertHexToDec( int nFirstByte, int nSecondByte ) +{ + int nValue = 0; + + switch ( nFirstByte ) + { + case ' ': + case '0': nValue += 0; break; + case '1': nValue += 16; break; + case '2': nValue += 32; break; + case '3': nValue += 48; break; + case '4': nValue += 64; break; + case '5': nValue += 80; break; + case '6': nValue += 96; break; + case '7': nValue += 112; break; + case '8': nValue += 128; break; + case '9': nValue += 144; break; + case 'A': + case 'a': nValue += 160; break; + case 'B': + case 'b': nValue += 176; break; + case 'C': + case 'c': nValue += 192; break; + case 'D': + case 'd': nValue += 208; break; + case 'E': + case 'e': nValue += 224; break; + case 'F': + case 'f': nValue += 240; break; + } + + switch ( nSecondByte ) + { + case ' ': + case '0': nValue += 0; break; + case '1': nValue += 1; break; + case '2': nValue += 2; break; + case '3': nValue += 3; break; + case '4': nValue += 4; break; + case '5': nValue += 5; break; + case '6': nValue += 6; break; + case '7': nValue += 7; break; + case '8': nValue += 8; break; + case '9': nValue += 9; break; + case 'A': + case 'a': nValue += 10; break; + case 'B': + case 'b': nValue += 11; break; + case 'C': + case 'c': nValue += 12; break; + case 'D': + case 'd': nValue += 13; break; + case 'E': + case 'e': nValue += 14; break; + case 'F': + case 'f': nValue += 15; break; + } + + return nValue; +} + + + + +/* ========================= STREAM UTILITIES =============================*/ + + + +/* +* Prasad, jan 8,98 +* Reader function for a buffer based mime_inputstream +* Note buf space is allocated/freed by the caller. +* +* parameter : +* +* return : +*/ +int buf_instream_read (void * rock, char *buf, int size) +{ + buf_instream_tracker_t * pStream; + int bytes_to_read = 0, bytes_left; + + if (rock == NULL || buf == NULL || size <= 0) + { + return MIME_ERR_INVALIDPARAM; + } + + pStream = (buf_instream_tracker_t *) rock; + + if (pStream->pDataBuf == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + bytes_left = pStream->total_size - pStream->bytes_read; + + if (bytes_left <= 0) + { + return MIME_ERR_EOF; + } + + if (bytes_left >= size) + bytes_to_read = size; + else + bytes_to_read = bytes_left; + + memcpy( buf, pStream->pNext, bytes_to_read ); + + buf [bytes_to_read] = NULL; /* NULL terminate it */ + + if (bytes_to_read == size) + { + /* we still have data to read on the stream */ + pStream->bytes_read += bytes_to_read; + + if (pStream->bytes_read < pStream->total_size) + pStream->pNext += bytes_to_read; + else + pStream->pNext = pStream->pDataBuf + pStream->total_size -1; /* on last byte */ + } + else + { + /* We returned less than what was asked. So we are at EOF */ + pStream->bytes_read = pStream->total_size; + pStream->pNext = pStream->pDataBuf + pStream->total_size -1; /* on last byte */ + } + + return bytes_to_read; +} + + + +/* +* Prasad, jan 8,98 +* Rewind function for a buffer based mime_inputstream +* +* parameter : rock +* +* return : nothing +*/ +void buf_instream_rewind (void * rock) +{ + buf_instream_tracker_t * pStream; + + if (rock == NULL) + return; + + pStream = (buf_instream_tracker_t *) rock; + pStream->bytes_read = 0; + pStream->pNext = pStream->pDataBuf; +} + + + +/* +* Prasad, jan 8,98 +* Close function for a buffer based mime_inputstream +* The client must free the stream after return from close. +* +* parameter : rock +* +* return : nothing +*/ +void buf_instream_close (void * rock) +{ + buf_instream_tracker_t * pStream; + + if (rock == NULL) + { + return; + } + + pStream = (buf_instream_tracker_t *) rock; + free (pStream->pDataBuf); + pStream->pDataBuf = NULL; + pStream->pNext = NULL; + pStream->total_size = 0; + pStream->bytes_read = 0; + + free (rock); + /* rock = NULL; */ +} + + + +/* +* Prasad, jan 8,98 +* Makes and returns an input stream out of the databuffer Passed. +* Uses the passed buffer as is. That is, data is not copied. +* data_size must be identical to actual size of data in pDataBuf. +* +* parameter : +* +* return : +*/ +int buf_instream_create (char * pDataBuf, long data_size, nsmail_inputstream_t ** ppRetInputStream) +{ + nsmail_inputstream_t * pNewStream; + buf_instream_tracker_t * pTracker; + + if (pDataBuf == NULL || data_size <= 0) + { + return MIME_ERR_INVALIDPARAM; + } + + pNewStream = (nsmail_inputstream_t *) malloc (sizeof (nsmail_inputstream_t)); + + if (pNewStream == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + pTracker = (buf_instream_tracker_t *) malloc (sizeof (buf_instream_tracker_t)); + + if (pTracker == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + pTracker->pDataBuf = pDataBuf; + pTracker->pNext = pDataBuf; + pTracker->total_size = data_size; + pTracker->bytes_read = 0; + + pNewStream->rock = (void *) pTracker; + + pNewStream->read = buf_instream_read; + pNewStream->rewind = buf_instream_rewind; + pNewStream->close = buf_instream_close; + + *ppRetInputStream = pNewStream; + + return MIME_OK; +} + + + +/* +* Prasad, jan 8,98 +* Appends src to dest and return the length of src string. +* Assumes there is enough room in dest. +* +* parameter : +* +* return : +*/ +int append_str (char * dest, char * src) +{ + int len; + + len = strlen (src); + + if (len > 0) + strncpy (dest, src, len); + + return len; +} + + + +/* +* Prasad, jan 8,98 +* Reader function for a file based mime_inputstream +* Note: buf space is allocated/freed by the caller. +* +* parameter : +* +* return : +*/ +int file_instream_read (void * rock, char *buf, int size) +{ + file_instream_tracker_t * pStream; + int read_len = 0; + + if (rock == NULL) + { + return -1; + } + + pStream = (file_instream_tracker_t *) rock; + + if (pStream->fp == NULL) + { + return -1; + } + + read_len = fread (buf, sizeof (char), size, pStream->fp); + buf [read_len] = NULL; /* NULL terminate it */ + + if (read_len > 0) + (pStream->bytes_read += read_len); + else + read_len = -1; + + return read_len; +} + + + +/* +* Prasad, jan 8,98 +* Rewind function for a file based mime_inputstream +* +* parameter : rock +* +* return : nothing +*/ +void file_instream_rewind (void * rock) +{ + file_instream_tracker_t * pStream; + + if (rock == NULL) + { + return; + } + + pStream = (file_instream_tracker_t *) rock; + + if (pStream->fp == NULL) + { + return; + } + + rewind (pStream->fp); + + pStream->bytes_read = 0; +} + + + +/* +* Prasad, jan 8,98 +* Close function for a file based mime_inputstream +* The client must free the stream after return from close. +* +* parameter : rock +* +* return : nothing +*/ +void file_instream_close (void * rock) +{ + file_instream_tracker_t * pStream; + + if (rock == NULL) + { + return; + } + + pStream = (file_instream_tracker_t *) rock; + + if (pStream->fp == NULL) + { + free (rock); + return; + } + + fclose (pStream->fp); + + free (pStream->file_name); + free (rock); +} + + + +/* +* Prasad, jan 8,98 +* Makes and returns an input stream out of the fileName Passed. +* NOTE: fileName must be that of an existing file since this is an inputStream. +* +* parameter : +* +* return : +*/ +int file_instream_create (char * fileName, nsmail_inputstream_t ** ppRetInputStream) +{ + FILE * fp; + nsmail_inputstream_t * pNewStream; + file_instream_tracker_t * pTracker; + + if (fileName == NULL || ppRetInputStream == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if ((fp = fopen(fileName, "rb")) == (FILE *) NULL) + { + return MIME_ERR_CANTOPENFILE; + } + + pNewStream = (nsmail_inputstream_t *) malloc (sizeof (nsmail_inputstream_t)); + + if (pNewStream == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + pTracker = (file_instream_tracker_t *) malloc (sizeof (file_instream_tracker_t)); + + if (pTracker == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + pTracker->file_name = (char *) strdup (fileName); + pTracker->fp = fp; + pTracker->bytes_read = 0; + + pNewStream->rock = (void *) pTracker; + pNewStream->read = file_instream_read; + pNewStream->rewind = file_instream_rewind; + pNewStream->close = file_instream_close; + + *ppRetInputStream = pNewStream; + + return 0; +} + + + +/* +* Prasad, jan 8,98 +* Returns the size of data that is available on the inputstream. -1 on an error. +* +* parameter : +* +* return : +*/ +long get_inputstream_size (nsmail_inputstream_t * pTheStream) +{ + static char * pLocalBuf; /* allocated only once */ + long stream_size = 0; + long read_size = 0; + + if (pLocalBuf == NULL) + pLocalBuf = (char *) malloc (MIME_BUFSIZE+1); /* allocated only once */ + + if (pLocalBuf == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + while (TRUE) + { + read_size = pTheStream->read (pTheStream->rock, pLocalBuf, MIME_BUFSIZE); + + if (read_size > 0) + { + stream_size += read_size; + read_size = 0; + } + else + break; + } /* while */ + + if (stream_size > 0) + { + pTheStream->rewind (pTheStream->rock); + return (stream_size); + } + else + return (-1); +} /* get_inputstream_size */ + +char * getFileShortName (char * fileName) +{ + char * pCh; + int i, len; + +#ifdef XP_UNIX +#define SEPCHAR '/' +#else +#define SEPCHAR '\\' +#endif + + if (fileName != NULL) + { + len = strlen (fileName); + + if (len <= 2) + return NULL; + + pCh = fileName + len; + + for (i = len -1; i >= 0; i--) + { + if (fileName [i] == SEPCHAR) + { + return strdup (pCh); + } + + pCh--; + } + + return strdup (fileName); + + } + + return NULL; +} + +char * getFileExtn (char * fileName) +{ + char * pCh; + int i, len; + + if (fileName != NULL) + { + len = strlen (fileName); + + if (len <= 2) + return NULL; + + pCh = fileName + len; + + for (i = len -1; i > (len - 6); i--) + { + if (fileName [i] == '.') + { + return strdup (pCh); + } + + pCh--; + } + + } + + return NULL; +} + +void file_outstream_write (void * rock, const char *buf, int size) +{ + file_outstream_tracker_t * pStream; + int write_len = 0; + + if (rock == NULL) + { + return; + } + + pStream = (file_outstream_tracker_t *) rock; + + if (pStream->fp == NULL) + { + return; + } + +#ifdef DEBUG + fprintf (stderr, "%s:%d> size=%d; %s\n", __FILE__, __LINE__, size, buf); +#endif + + write_len = fwrite (buf, sizeof (char), size, pStream->fp); + + if (write_len > 0) + (pStream->bytes_written += write_len); + + return; +} + + + + + +int file_outstream_create (char * fileName, nsmail_outputstream_t ** ppRetOutputStream) +{ + FILE * fp; + nsmail_outputstream_t * pNewStream; + file_outstream_tracker_t * pTracker; + + if (fileName == NULL || ppRetOutputStream == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + if ((fp = fopen(fileName, "wb")) == (FILE *) NULL) + { + return MIME_ERR_CANTOPENFILE; + } + + pNewStream = (nsmail_outputstream_t *) malloc (sizeof (nsmail_outputstream_t)); + + if (pNewStream == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + pTracker = (file_outstream_tracker_t *) malloc (sizeof (file_outstream_tracker_t)); + + if (pTracker == NULL) + { + return MIME_ERR_OUTOFMEMORY; + } + + pTracker->file_name = (char *) strdup (fileName); + pTracker->fp = fp; + pTracker->bytes_written = 0; + + pNewStream->rock = (void *) pTracker; + pNewStream->write = file_outstream_write; + /* pNewStream->rewind = file_instream_rewind; */ + pNewStream->close = file_outstream_close; + + *ppRetOutputStream = pNewStream; + + return 0; +} + +void file_outstream_close (void * rock) +{ + file_outstream_tracker_t * pStream; + + if (rock == NULL) + { + return; + } + + pStream = (file_outstream_tracker_t *) rock; + + if (pStream->fp == NULL) + { + free (rock); + return; + } + + fclose (pStream->fp); + + free (pStream->file_name); + free (rock); + /* rock = NULL; */ +} +/* ------------------------------- decoding ---------------------------- */ + + + +/* +* carson, Jan 8,98 +* +* Base64 Decodes data from input buffer and writes to Output buffer +* +* params : +* +* char *szInput : input buffer +* char *szOutput : output buffer +* int nInputBufferSize : input buffer size +* BOOLEAN bFirstBuffer : TRUE if first buffer +* BOOLEAN bLastBuffer : TRUE if last buffer +* +* return : number of decoded bytes +*/ +int base64Decoder( char *szInput, char *szOutput, int nInputBufferSize, BOOLEAN bFirstBuffer, BOOLEAN bLastBuffer ) +{ + int add_bits; + int mask; + int out_byte = 0; + int out_bits = 0; + int i; + int byte_pos = 0; + + if ( szInput == NULL || szOutput == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* Make translation table if it doesn't exist already */ + if ( !( base64.xlate_table_made ) ) + { + for ( i = 0; i < 256; i++ ) + base64.xlate[i] = 127; + + for (i = 0; base64.digits[i]; i++) + { + base64.xlate[base64.digits[i]] = i; + } + + base64.xlate_table_made = 1; + } + + /* Queue up relevant bits */ + for (i = 0; szInput[i] && i < nInputBufferSize; i++ ) + { + /* too small for us to decode */ + if ( i + 4 > nInputBufferSize ) + break; + + add_bits = base64.xlate[(unsigned char) szInput[i]]; + + if (add_bits >= 64) + continue; + + out_byte = (out_byte << 6) + add_bits; + out_bits += 6; + + /* If the queue has gotten big enough, put into the buffer */ + if (out_bits == 24) + { + szOutput[byte_pos++] = (out_byte & 0xFF0000) >> 16; + szOutput[byte_pos++] = (out_byte & 0x00FF00) >> 8; + szOutput[byte_pos++] = (out_byte & 0x0000FF); + out_bits = 0; + out_byte = 0; + } + } + + /* Handle any bits still in the queue */ + while (out_bits >= 8) + { + if (out_bits == 8) + { + szOutput[byte_pos++] = out_byte; + out_byte = 0; + } + + else + { + mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8)); + szOutput[byte_pos++] = (out_byte & mask) >> (out_bits - 8); + out_byte &= ~mask; + } + + out_bits -= 8; + } + + /* Ignore any remaining bits */ + return out_byte ? BASE64_SOMELEFT : byte_pos; +} + + + +/* +* carson, Jan 8,98 +* +* Base64 Decodes data from input buffer and writes to Output buffer +* +* params : +* +* char *szInput : input buffer +* char *szOutput : output buffer +* int nInputBufferSize : input buffer size +* int nMaxBufferSize : max output buffer size +* int *pOut_byte : leftover byte +* int *pOut_bits : leftover bits +* +* return : number of decoded bytes +*/ +int decodeBase64( char *szInput, char *szOutput, int nInputBufferSize, int nMaxBufferSize, int *pOut_byte, int *pOut_bits ) +{ + int add_bits; + int mask; + int out_byte = 0; + int out_bits = 0; + int i; + int byte_pos = 0; + + if ( szInput == NULL || szOutput == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* dynamic parsing */ + if ( pOut_byte != NULL && pOut_bits != NULL ) + { + out_byte = *pOut_byte; + out_bits = *pOut_bits; + } + + /* Make translation table if it doesn't exist already */ + if (!(base64.xlate_table_made)) + { + for ( i = 0; i < 256; i++ ) + base64.xlate[i] = 127; + + for (i = 0; base64.digits[i]; i++) + { + base64.xlate[base64.digits[i]] = i; + } + + base64.xlate_table_made = 1; + } + + /* Queue up relevant bits */ + for (i = 0; szInput[i] && i < nInputBufferSize; i++) + { + add_bits = base64.xlate[(unsigned char) szInput[i]]; + + if (add_bits >= 64) + continue; + + out_byte = (out_byte << 6) + add_bits; + out_bits += 6; + + /* If the queue has gotten big enough, put into the buffer */ + if (out_bits == 24) + { + if (byte_pos + 2 >= nMaxBufferSize ) + return BASE64_NOFIT; + + szOutput[byte_pos++] = (out_byte & 0xFF0000) >> 16; + szOutput[byte_pos++] = (out_byte & 0x00FF00) >> 8; + szOutput[byte_pos++] = (out_byte & 0x0000FF); + out_bits = 0; + out_byte = 0; + } + } + + /* Handle any bits still in the queue */ + if ( pOut_byte == NULL || pOut_bits == NULL ) + { + while (out_bits >= 8) + { + if (byte_pos >= nMaxBufferSize ) + return BASE64_NOFIT; + + if (out_bits == 8) + { + szOutput[byte_pos++] = out_byte; + out_byte = 0; + } + + else + { + mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8)); + szOutput[byte_pos++] = (out_byte & mask) >> (out_bits - 8); + out_byte &= ~mask; + } + + out_bits -= 8; + } + + /* Ignore any remaining bits */ + return out_byte ? BASE64_SOMELEFT : byte_pos; + } + + /* dynamic parsing */ + else + { + *pOut_byte = out_byte; + *pOut_bits = out_bits; + + return byte_pos; + } +} + + + +/* +* carson, Jan 8,98 +* +* Base64 Decodes data from vector and writes to Output buffer +* +* params : +* +* int nStart : start element in vector +* int nEnd : end element in vector +* Vector *v : input vector +* char *szOutput : output buffer +* int nMaxBufferSize : max output buffer size +* int *pOut_byte : leftover byte +* int *pOut_bits : leftover bits +* +* return : number of decoded bytes +*/ +int decodeBase64Vector( int nStart, int nEnd, Vector *v, char **szDecodedBuffer, int nRawMessageSize, int *pOut_byte, int *pOut_bits ) +{ + int add_bits; + int mask; + int out_byte = 0; + int out_bits = 0; + int byte_pos = 0; + int i, j, nLen; + char *szLine; + char *szOutput; + + if ( v == NULL || szDecodedBuffer == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* dynamic parsing */ + if ( pOut_byte != NULL && pOut_bits != NULL ) + { + out_byte = *pOut_byte; + out_bits = *pOut_bits; + } + + /* Make translation table if it doesn't exist already */ + if (!(base64.xlate_table_made)) + { + for (i = 0; i < 256; i++) + base64.xlate[i] = 127; + + for (i = 0; base64.digits[i]; i++) + { + base64.xlate[base64.digits[i]] = i; + } + + base64.xlate_table_made = 1; + } + + szOutput = (char *) malloc( nRawMessageSize + 1 ); + + if ( szOutput == NULL ) + { +#ifdef ERRORLOG + errorLog( "baseBase64Vector()", MIME_ERR_OUTOFMEMORY ); +#endif + + return 0; + } + + *szDecodedBuffer = szOutput; + + for ( j = nStart; j <= nEnd; j++ ) + { + szLine = (char *) Vector_elementAt( v, j ); + nLen = strlen( szLine ); + + /* Queue up relevant bits */ + for (i = 0; szLine[i] && i < nLen; i++) + { + add_bits = base64.xlate[(unsigned char) szLine[i]]; + + if (add_bits >= 64) + continue; + + out_byte = (out_byte << 6) + add_bits; + out_bits += 6; + + /* If the queue has gotten big enough, put into the buffer */ + if (out_bits == 24) + { + if (byte_pos + 2 >= nRawMessageSize ) + return BASE64_NOFIT; + + szOutput[byte_pos++] = (out_byte & 0xFF0000) >> 16; + szOutput[byte_pos++] = (out_byte & 0x00FF00) >> 8; + szOutput[byte_pos++] = (out_byte & 0x0000FF); + out_bits = 0; + out_byte = 0; + } + } + } + + /* Handle any bits still in the queue */ + if ( pOut_byte == NULL || pOut_bits == NULL ) + { + while (out_bits >= 8) + { + if (byte_pos >= nRawMessageSize ) + return BASE64_NOFIT; + + if (out_bits == 8) + { + szOutput[byte_pos++] = out_byte; + out_byte = 0; + } + + else + { + mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8)); + szOutput[byte_pos++] = (out_byte & mask) >> (out_bits - 8); + out_byte &= ~mask; + } + + out_bits -= 8; + } + + /* Ignore any remaining bits */ + return out_byte ? BASE64_SOMELEFT : byte_pos; + } + + /* dynamic parsing */ + else + { + *pOut_byte = out_byte; + *pOut_bits = out_bits; + + return byte_pos; + } +} + + + +/* +* carson, Jan 8,98 +* decode quoted printable +* +* param : +* +* char *szInput : input buffer +* char *szOutput : output buffer +* int MaxBufferSize : max buffer size +* +* return : number of decoded bytes +*/ +int decodeQP( char *szInput, char *szOutput, int nMaxBufferSize ) +{ + char ch; + int i = 0; + int j = 0; + + if ( szInput == NULL || szOutput == NULL ) + return MIME_ERR_INVALIDPARAM; + + for ( ch = szInput[i]; ch != 0 && j < nMaxBufferSize; i++ ) + { + if ( ( ch >= 33 && ch <= 60 ) || ( ch >= 62 && ch <= 126 ) || ( ch == 9 || ch == 32 ) ) + { + szOutput[j++] = ch; + } + + else if ( ch == '=' ) + { + szOutput[j++] = nConvertHexToDec( szInput[++i], szInput[++i] ); + } + } + + szOutput[j] = 0; + + return j; +} + + + +/* New routine prasad 3/31/98 */ +int decodeQPVector (int nStart, int nEnd, Vector *v, char **ppDecodedBuffer, + int nRawMessageSize, char *pLeftOverBytes, int *nNoOfLeftOverBytes) +{ + char token[3], ch; + char *pLine, *pOutput, *pInput; + int i = 0, j, ii=0, nLen = 0, written=0; + + if (v == NULL || pLeftOverBytes == NULL || nNoOfLeftOverBytes == NULL || ppDecodedBuffer == NULL) + { + return MIME_ERR_INVALIDPARAM; + } + + pOutput = (char *) malloc (nRawMessageSize + 1); + if (pOutput == NULL) + return MIME_ERR_OUTOFMEMORY; + memset (pOutput, 0, (nRawMessageSize + 1)); + + *ppDecodedBuffer = pOutput; + + /* get each line */ + for (ii = nStart; ii <= nEnd; ii++) + { + pLine = (char *) Vector_elementAt( v, ii ); + nLen += strlen (pLine); + if (ii == nStart) + { + if (*nNoOfLeftOverBytes > 0) + { + strncpy (pOutput, pLeftOverBytes, *nNoOfLeftOverBytes); + nLen += *nNoOfLeftOverBytes; + } + strcat (pOutput, pLine); + /* see if this helps! */ + strcat (pOutput, "\r\n"); + nLen += 2; + } + else + { + strcat (pOutput, pLine); + /* see if this helps! */ + strcat (pOutput, "\r\n"); + nLen += 2; + } + /* Don't free() pLine. It is freed by caller as part of freeing the vector */ + } + + pInput = pOutput; + written=0; + i=0; + + /* first time do it outside the loop */ + while (i < 3 && nLen > 0) + { + token [i++] = *pInput; + pInput++; + nLen--; + } + + while (nLen > 0 || i != 0) + { + while (i < 3 && nLen > 0) + { + token [i++] = *pInput; + pInput++; + nLen--; + } + + if (i < 3) /* did not get enough for a token */ + { + if (i == 2 && token [0] == CR && token [1] == LF) + { + *pOutput++ = token[0]; written++; + *pOutput++ = token[1]; written++; + *nNoOfLeftOverBytes = 0; + } + else + { + for (j=0; j < i; j++) + pLeftOverBytes [j] = token [j];; + *nNoOfLeftOverBytes = i; + } + + if (written > 0) + *pOutput++ = 0; /* null terminate it */ + + return (written); + } + + i = 0; + + if (token [0] == '=') + { + unsigned char c = 0; + if (token[1] >= '0' && token[1] <= '9') + c = token[1] - '0'; + else if (token[1] >= 'A' && token[1] <= 'F') + c = token[1] - ('A' - 10); + else if (token[1] >= 'a' && token[1] <= 'f') + c = token[1] - ('a' - 10); + /*else if (token[1] == CR || token[1] == LF)*/ + else if (token[1] == CR || token[1] == LF) + { + /* =\n means ignore the newline. */ + if (token[1] == CR && token[2] == LF) + ; /* swallow all three chars */ + else + { + pInput--; /* put the third char back */ + nLen++; + } + continue; + } + else + { + /* = followed by something other than hex or newline - + pass it through unaltered, I guess. + */ + if (pInput > pOutput) { *pOutput++ = token[0]; written++; } + if (pInput > pOutput) { *pOutput++ = token[1]; written++; } + if (pInput > pOutput) { *pOutput++ = token[2]; written++; } + continue; + } + + /* Second hex digit */ + c = (c << 4); + if (token[2] >= '0' && token[2] <= '9') + c += token[2] - '0'; + else if (token[2] >= 'A' && token[2] <= 'F') + c += token[2] - ('A' - 10); + else if (token[2] >= 'a' && token[2] <= 'f') + c += token[2] - ('a' - 10); + else + { + /* We got =xy where "x" was hex and "y" was not, so + treat that as a literal "=", x, and y. */ + if (pInput > pOutput) { *pOutput++ = token[0]; written++; } + if (pInput > pOutput) { *pOutput++ = token[1]; written++; } + if (pInput > pOutput) { *pOutput++ = token[2]; written++; } + continue; + } + + *pOutput++ = (char) c; + written++; + } + else + { + *pOutput++ = token[0]; + written++; + + token[0] = token[1]; + token[1] = token[2]; + i = 2; + } + } + + if (written > 0) + *pOutput++ = 0; /* null terminate it */ + return written; +} + + + +/* +* carson, Jan 8,98 +* QuotedPrintable Decodes data from vector, write decoded data to szOutput +* +* params : +* +* int nStart : starting element in vector +* int nEndt : ending element in vector +* Vector *v : vector +* char *szOutput : output buffer +* int MaxBufferSize : max buffer size +* +* return : number of decoded bytes +*/ +int decodeQPVectorOrig( int nStart, int nEnd, Vector *v, char **szDecodedBuffer, int nRawMessageSize, char *szLeftOverBytes, int *nNoOfLeftOverBytes ) +{ + char ch; + int i = 0; + int j = 0; + int ii, nLen; + char *szLine; + char achBuffer[96]; + boolean bAppendLeftOverBytes = FALSE; + char *szOutput; + + if ( v == NULL || szLeftOverBytes == NULL || nNoOfLeftOverBytes == NULL || szDecodedBuffer == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + szOutput = (char *) malloc( nRawMessageSize + 1 ); + + if ( szOutput == NULL ) + { +#ifdef ERRORLOG + errorLog( "baseQPVector()", MIME_ERR_OUTOFMEMORY ); +#endif + + return MIME_ERR_OUTOFMEMORY; + } + + *szDecodedBuffer = szOutput; + + /* get each line */ + for ( ii = nStart; ii <= nEnd; ii++ ) + { + szLine = (char *) Vector_elementAt( v, ii ); + nLen = strlen( szLine ); + + if ( !bAppendLeftOverBytes ) + { + if ( *nNoOfLeftOverBytes > 0 ) + { + strncpy( achBuffer, szLeftOverBytes, *nNoOfLeftOverBytes ); + achBuffer[ *nNoOfLeftOverBytes ] = 0; + + strcat( achBuffer, szLine ); + nLen = nLen + *nNoOfLeftOverBytes; + szLine = achBuffer; + } + + bAppendLeftOverBytes = TRUE; + } + + /* enumerate through each char */ + for ( i = 0, ch = szLine[i]; ch != 0 && i < nLen && j < nRawMessageSize; ch = szLine[++i] ) + { + if ( ( ch >= 33 && ch <= 60 ) || ( ch >= 62 && ch <= 126 ) || ( ch == 9 || ch == 32 ) ) + { + szOutput[j++] = ch; + } + + else if ( ch == '=' ) + { + if ( i + 2 < nLen ) + { + szOutput[j++] = nConvertHexToDec( szLine[++i], szLine[++i] ); + } + + /* get more data */ + else if ( ii <= nEnd ) + { + strcpy( achBuffer, &szLine[i+1] ); + szLine = (char *) Vector_elementAt( v, ++ii ); + strcat( achBuffer, szLine ); + nLen = strlen( achBuffer ); + szLine = achBuffer; + i = -1; + } + + /* save it for next time */ + else + { + szLeftOverBytes[0] = ch; *nNoOfLeftOverBytes = 1; + + if ( i+1 < nLen ) + szLeftOverBytes[1] = ch; *nNoOfLeftOverBytes = 2; + } + } + } + } + + szOutput[j] = 0; + + return j; +} + + + + +/* ---------------------------------- log support ------------------------------------- */ + + + +/* +* carsonl, jan 8,98 +* create new log +* +* parameter : +* +* char *szFilename : name of log file +* +* return : instance of log object +*/ +errorLog_t *errorLog_new( char *szFilename ) +{ + errorLog_t *pLog; + + if ( szFilename == NULL ) + return NULL; + + pLog = (errorLog_t*) malloc( sizeof( errorLog_t ) ); + + /* initialize log file */ + if ( pLog != NULL ) + { + pLog->m_pFile = fopen( szFilename, "a" ); + + if ( pLog->m_pFile == NULL ) + { + free( pLog ); + pLog = NULL; + } + else + { + strcpy( pLog->m_achFilename, szFilename ); + pLog->m_bActive = TRUE; + } + } + + return pLog; +} + + + +/* +* carsonl, jan 8,98 +* error logger +* +* parameter : +* +* char *pOwner : caller +* int nError : error No +* +* return : nothing +* NOTE : will only write to log file if m_bActive flag is set to TRUE ( default ) +*/ +void errorLog2( errorLog_t *pLog, char *szOwner, int nError ) +{ + static char buffer[128]; + char *szError; + + if ( pLog == NULL || pLog->m_pFile == NULL || szOwner == NULL ) + return; + + if ( !pLog->m_bActive ) + return; + + switch( nError ) + { + case MIME_ERR_EOF: szError = "End of file"; break; + case MIME_ERR_INVALIDPARAM: szError = "Invalid parameter"; break; + case MIME_ERR_ENCODE: szError = "encoding"; break; + case MIME_ERR_UNEXPECTED: szError = "unexpected"; break; + case MIME_ERR_OUTOFMEMORY: szError = "out of memory"; break; + case MIME_ERR_IO: szError = "I/O"; break; + case MIME_ERR_IO_READ: szError = "I/O read"; break; + case MIME_ERR_IO_WRITE: szError = "I/O write"; break; + case MIME_ERR_PARSE: szError = "parse"; break; + case MIME_ERR_INVALID_INDEX: szError = "invalid index"; break; + case MIME_ERR_UNINITIALIZED: szError = "unintialized"; break; + case MIME_ERR_CANTOPENFILE: szError = "can't open file"; break; + case MIME_ERR_CANT_SET: szError = "can't set"; break; + case MIME_ERR_ALREADY_SET: szError = "already set"; break; + case MIME_ERR_CANT_DELETE: szError = "can't delete"; break; + case MIME_ERR_CANT_ADD: szError = "can't add"; break; + case MIME_ERR_NO_HEADERS: szError = "no headers"; break; + case MIME_ERR_NOT_SET: szError = "not set"; break; + case MIME_ERR_NO_BODY: szError = "no body"; break; + case MIME_ERR_NOT_FOUND: szError = "not found"; break; + case MIME_ERR_NO_CONTENT_SUBTYPE: szError = "no content subtype"; break; + case MIME_ERR_INVALID_ENCODING: szError = "invalid encoding"; break; + case MIME_ERR_INVALID_BASICPART: szError = "invalid basicpart"; break; + case MIME_ERR_INVALID_MULTIPART: szError = "invalid multipart"; break; + case MIME_ERR_INVALID_MESSAGEPART: szError = "invalid messagepart"; break; + case MIME_ERR_INVALID_MESSAGE: szError = "invalid message"; break; + case MIME_ERR_INVALID_CONTENTTYPE: szError = "invalid content type"; break; + case MIME_ERR_INVALID_CONTENTID: szError = "invalid content ID"; break; + case MIME_ERR_NO_DATA: szError = "no data"; break; + case MIME_ERR_NOTIMPL: szError = "not implemented"; break; + case MIME_ERR_EMPTY_BODY: szError = "empty body"; break; + case MIME_ERR_UNSUPPORTED_PARTIAL_SUBTYPE: szError = "partial subtype not supported"; + case MIME_ERR_MAX_NESTED_PARTS_REACHED : szError = "maximum number of nested parts reached."; + default: szError = "Undefined error"; break; + } + + sprintf( buffer, "ERROR : %s error called from %s\n", szError, szOwner ); + fwrite( buffer, sizeof(char), strlen( buffer ), pLog->m_pFile ); +} + + +/* +* carsonl, jan 8,98 +* error logger +* +* parameter : +* +* char *pOwner : caller +* int nError : error No +* +* return : nothing +* NOTE : will only write to log file if m_bActive flag is set to TRUE ( default ) +*/ +void errorLogMsg2( errorLog_t *pLog, char *szMsg ) +{ + static char buffer[128]; + + if ( pLog == NULL || pLog->m_pFile == NULL || szMsg == NULL ) + return; + + if ( !pLog->m_bActive ) + return; + + sprintf( buffer, "ERROR : %s\n", szMsg ); + fwrite( buffer, sizeof(char), strlen( buffer ), pLog->m_pFile ); +} + + + +/* +* carsonl, jan 8,98 +* free log object +* +* parameter : +* +* char *pLog : log object to free +* int nError : error No +* +* return : nothing +*/ +void errorLog_free( errorLog_t *pLog ) +{ + if ( pLog != NULL ) + { + if ( pLog->m_pFile != NULL ) + fclose( pLog->m_pFile ); + + free( pLog ); + } +} + + + +/* +* carsonl, jan 8,98 +* init log +* +* parameter : +* +* char *szFilename : log filename +* +* return : nothing +*/ +void initErrorLog( char *szFilename ) { g_pLog = errorLog_new( szFilename ); } + + + + +/* +* carsonl, jan 8,98 +* close log file +* +* parameter : none +* +* return : nothing +*/ +void closeErrorLog() { if ( g_pLog != NULL ) errorLog_free( g_pLog ); } + + + +/* +* carsonl, jan 8,98 +* log error +* +* parameter : +* +* char *pOwner : caller +* int nError : error No +* +* return : nothing +*/ +void errorLog( char *szOwner, int nError ) +{ + if ( g_pLog == NULL ) + g_pLog = errorLog_new( LOG_FILE ); + + errorLog2( g_pLog, szOwner, nError ); +} + + + + +/* +* carsonl, jan 8,98 +* log error +* +* parameter : +* +* char *pOwner : caller +* int nError : error No +* +* return : nothing +*/ +void errorLogMsg( char *szMsg ) +{ + if ( g_pLog == NULL ) + g_pLog = errorLog_new( LOG_FILE ); + + errorLogMsg2( g_pLog, szMsg ); +} + + +/* +* carsonl, jan 8,98 +* turn error log on +* +* parameter : none +* +* return : nothing +*/ +void errorLogOn() { if ( g_pLog == NULL ) g_pLog->m_bActive = TRUE; } + + + +/* +* carsonl, jan 8,98 +* turn error log off +* +* parameter : none +* +* return : nothing +*/ +void errorLogOff() { if ( g_pLog == NULL ) g_pLog->m_bActive = FALSE; } + + diff --git a/msgsdk/C/protocol/MIME/src/vector.c b/msgsdk/C/protocol/MIME/src/vector.c new file mode 100644 index 000000000000..755f9320e687 --- /dev/null +++ b/msgsdk/C/protocol/MIME/src/vector.c @@ -0,0 +1,398 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + + +/* vector.c +* +* simple vector class +* carsonl, oct 1,97 +*/ + +#include +#include +#include + +#include "nsmail.h" +#include "vector.h" +#include "util.h" +#include "mime.h" +#include "mime_internal.h" +#include "mimeparser.h" + + + +/* +* carsonl, jan 8,98 +* constructor +* +* parameter : +* +* int type1 : content type +* +* returns : new instance of vector +*/ +Vector *Vector_new( int nType ) +{ + Vector *v = (Vector *) malloc( sizeof( Vector ) ); + + if ( v == NULL ) + { + return NULL; + } + + v->nSize = 0; + v->nMaxSize = INITIAL_SIZE; + v->nType = nType; + + v->pt = (void **) malloc( INITIAL_SIZE * sizeof( void * ) ); + + if ( v->pt == NULL ) + { + free( v ); + + return NULL; + } + + return v; +} + + + +/* +* carsonl, jan 8,98 +* clone +* +* parameter : +* +* Vector *v : original vector +* +* returns : new instance of vector, or NULL if incorrect parameters or out of memory +*/ +Vector *Vector_clone( Vector *v ) +{ + int i, len; + Vector *v2; + + if ( v == NULL ) + { + return NULL; + } + + v2 = (Vector *) malloc( sizeof( Vector ) ); + + if ( v2 == NULL ) + { + return NULL; + } + + v2->nMaxSize = v->nMaxSize; + v2->nSize = v->nSize; + v2->nType = v->nType; + + /* clone pointer array */ + v2->pt = (void **) malloc( v->nMaxSize * sizeof( void* ) ); + + if ( v2->pt == NULL ) + { + free( v2 ); + + return NULL; + } + + memcpy( v2->pt, v->pt, v->nSize * sizeof( void* ) ); + + /* clone each element */ + for ( i=0; i < v->nSize; i++ ) + { + if ( v->pt[i] != NULL ) + { + switch ( v->nType ) + { + case VECTOR_TYPE_STRING: + len = strlen( (char *) v->pt[i] ) + 1; + v2->pt[i] = (char *) malloc( len ); + + if ( v2->pt[i] != NULL ) + { + memcpy( v2->pt[i], v->pt[i], len ); + } + break; + + case VECTOR_TYPE_MIMEINFO: + v2->pt[i] = (void *) mimeInfo_clone( (mimeInfo_t *) v->pt[i] ); + break; + } + } + } + + return v2; +} + + + +/* +* carsonl, jan 8,98 +* destructor +* +* parameter : +* +* Vector *v : vector +* +* returns : MIME_OK if successful +*/ +int Vector_free( Vector *v ) +{ + int i; + + if ( v == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( v->pt != NULL ) + { + for ( i=0; i < v->nSize; i++ ) + { + if ( v->pt[i] != NULL ) + { + switch ( v->nType ) + { + case VECTOR_TYPE_STRING: + free( v->pt[i] ); + break; + + case VECTOR_TYPE_MIMEINFO: + mimeInfo_free( v->pt[i] ); + break; + + default: + free( v->pt[i] ); + } + } + } + + free( v->pt ); + } + + free( v ); + + return MIME_OK; +} + + + + +/* +* carsonl, jan 8,98 +* delete all elements +* +* parameter : +* +* Vector *v : original vector +* +* returns : MIME_OK if successful +*/ +int Vector_deleteAll( Vector *v ) +{ + int i; + + if ( v == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + if ( v->pt != NULL ) + { + for ( i=0; i < v->nSize; i++ ) + { + if ( v->pt[i] != NULL ) + { + switch ( v->nType ) + { + case VECTOR_TYPE_STRING: + free( v->pt[i] ); + break; + + case VECTOR_TYPE_MIMEINFO: + mimeInfo_free( v->pt[i] ); + break; + + default: + free( v->pt[i] ); + } + + v->pt[i] = NULL; + } + } + + v->nSize = 0; + } + + return MIME_OK; +} + + + +/* +* carsonl, jan 8,98 +* add a new element +* +* parameter : +* +* Vector *v : original vector +* void *pObject : user's object +* int nObjectSize : object size +* +* returns : return a negative error code if failed, return the vector index if successful +*/ +int Vector_addElement( Vector *v, void *pObject, int nObjectSize ) +{ + if ( v == NULL || pObject == NULL || v->pt == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + /* reallocate more space */ + if ( v->nSize >= v->nMaxSize ) + { + void *ptOld = v->pt; + v->nMaxSize += INITIAL_SIZE; + + v->pt = (void **) malloc( v->nMaxSize * sizeof( void* ) ); + + if ( v->pt == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + + memcpy( v->pt, ptOld, v->nSize * sizeof( void* ) ); + + if ( ptOld != NULL ) + free( ptOld ); + } + + /* copy content */ + switch ( v->nType ) + { + case VECTOR_TYPE_MIMEINFO: + v->pt[ v->nSize ] = (void **) mimeInfo_clone( (mimeInfo_t *) pObject ); + break; + + default: + /* store object */ + v->pt[ v->nSize ] = (void **) malloc( nObjectSize + 1 ); + + /* out of memory */ + if ( v->pt[ v->nSize ] == NULL ) + { + return MIME_ERR_OUTOFMEMORY; + } + + memcpy( v->pt[v->nSize], pObject, nObjectSize + 1 ); + break; + } + + /* add element */ + v->nSize++; + + return v->nSize - 1; +} + + + +/* +* carsonl, jan 8,98 +* return the vector at nIndex +* +* parameter : +* +* Vector *v : original vector +* int nIndex : element index +* +* returns : object at index +*/ +void *Vector_elementAt( Vector *v, int nIndex ) +{ + if ( v != NULL && nIndex < v->nSize ) + return v->pt[ nIndex ]; + + return NULL; +} + + +void *Vector_deleteLastElement (Vector *v) +{ + int i; + + if (v != NULL && v->nSize > 0) + { + i = v->nSize; + free(v->pt[i-1] ); + v->pt[i-1] = NULL; + v->nSize--; + } + + return NULL; +} + + +void *Vector_popLastElement (Vector *v) +{ + int i; + void * p; + + if (v != NULL && v->nSize > 0) + { + i = v->nSize; + p = v->pt[i-1]; + v->pt[i-1] = NULL; + v->nSize--; + return p; + } + + return NULL; +} + +/* +* carsonl, jan 8,98 +* return # of elements in the vector class +* +* parameter : +* +* Vector *v : original vector +* +* returns : size of vector +*/ +int Vector_size( Vector *v ) +{ + if ( v == NULL ) + { + return MIME_ERR_INVALIDPARAM; + } + + return v->nSize; +} + + diff --git a/msgsdk/C/protocol/MIME/test/dynamic/testdynamic.c b/msgsdk/C/protocol/MIME/test/dynamic/testdynamic.c new file mode 100644 index 000000000000..993ec94639fb --- /dev/null +++ b/msgsdk/C/protocol/MIME/test/dynamic/testdynamic.c @@ -0,0 +1,346 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* * Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + +/* + * Example program to demonstrate the use of the MIME dynamic parser + * + */ + + +#include "stdio.h" +#include "nsmail.h" +#include "mime.h" +#include "mimeparser.h" +#include "nsStream.h" +#include "testdynamic.h" + + +char achTemp[512]; +int messageNo = 0; +int basicPartNo = 0; +int multiPartNo = 0; +int messagePartNo = 0; +nsmail_outputstream_t *pBodyDataStream; + +#define outmsg(x) (fprintf(stderr,"%s:%d>%s\n",__FILE__,__LINE__,x)) +#define outmsg2(x, y) (fprintf(stderr,"%s:%d>%s%s\n",__FILE__,__LINE__,x,y)) + +#ifdef XP_UNIX +#define BASICPART_FILE "/tmp/bodypart.out" +#define BODYDATA_FILE "/tmp/boddata.out" +#define BASICPART_BYTESTREAM "/tmp/basicpart.bstream" +#else +#define BASICPART_FILE "C:\\temp\\bodypart.out" +#define BODYDATA_FILE "C:\\temp\\boddata.out" +#define BASICPART_BYTESTREAM "C:\\temp\\basicpart.bstream" +#endif + +/* allocate and return the callback object */ +char * getCBObject (char * s, int num) +{ + char * CBObj = (char *) mime_malloc (20); + + memset (CBObj, 0, 20); + + sprintf (CBObj, "%s%d", s, num); + return CBObj; +} + +void freeCBObject (void * pCBObj) +{ + mime_memfree (pCBObj); +} + + +/************************************************************************************/ +/* ------ datasink methods ---------- */ +/************************************************************************************/ + + +void mimeDataSink2_header (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *name, char *value) +{ + if (name != NULL && value != NULL) + sprintf( achTemp, "> header() name = [%s] value = [%s]\n", name, value); + else if (name != NULL && value == NULL) + sprintf( achTemp, "> header() name = [%s] value = [%s]\n", name, "null"); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_addHeader (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *name, char *value) +{ + sprintf( achTemp, "> addHeader() name = [%s] value = [%s]\n", name, value); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_endMessageHeader (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + sprintf( achTemp, "> endMessageHeader()"); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentType (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentType) +{ + sprintf( achTemp, "> contentType() = [%d]\n", nContentType); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentSubType (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentSubType) +{ + sprintf( achTemp, "> contentSubType() = [%s]\n", contentSubType); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentTypeParams (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentTypeParams) +{ + sprintf( achTemp, "> contentTypeParams() = [%s]\n", contentTypeParams); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentID (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *contentID) +{ + sprintf( achTemp, "> contentID() = [%s]\n", contentID); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentMD5 (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentMD5) +{ + sprintf( achTemp, "> contentMD5() = [%s]\n", contentMD5); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentDisposition (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentDisposition) +{ + sprintf( achTemp, "> contentDisposition() = [%d]\n", nContentDisposition); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentDispParams (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentDispParams) +{ + sprintf( achTemp, "> contentDispParams() = [%s]\n", contentDispParams); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentDescription (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *contentDescription) +{ + sprintf( achTemp, "> contentDescription() = [%s]\n", contentDescription); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentEncoding (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentEncoding) +{ + sprintf( achTemp, "> contentEncoding() = [%d]\n", nContentEncoding); + outmsg2((char *)pCallbackObject, achTemp); +} + + +void *mimeDataSink2_startMessage (mimeDataSinkPtr_t pSink) +{ + char * msgCB = getCBObject ("Message", ++messageNo); + outmsg2("startMessage() ", msgCB); + return msgCB; +} + +void mimeDataSink2_endMessage (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + outmsg2((char*)pCallbackObject, "> endMessage()"); + /*outmsg( "endMessage()\n");*/ +} + + +void *mimeDataSink2_startBasicPart (mimeDataSinkPtr_t pSink) +{ + char * basicCB = getCBObject ("BasicPart", ++basicPartNo); + outmsg2("startBasicPart() ", basicCB); + return basicCB; +} + +void mimeDataSink2_bodyData (mimeDataSinkPtr_t pSink, void *pCallbackObject, char bodyData[], int len) +{ + outmsg((char *)pCallbackObject); + outmsg( "bodyData() = ["); + outmsg( "]\n"); + if (pBodyDataStream != NULL) + { + pBodyDataStream->write (pBodyDataStream->rock, bodyData, len); + } +} + +void mimeDataSink2_endBasicPart (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + outmsg2((char*)pCallbackObject, "> endBasicPart()"); +} + +void *mimeDataSink2_startMultiPart (mimeDataSinkPtr_t pSink) +{ + char * mpCB = getCBObject ("MultiPart", ++multiPartNo); + outmsg2("startMultiPart() ", mpCB); + return mpCB; +} + +void mimeDataSink2_boundary (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * boundary) +{ + sprintf( achTemp, "> boundary() = [%s]\n", boundary); + outmsg2((char*)pCallbackObject, achTemp); +} + +void mimeDataSink2_endMultiPart (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + outmsg2((char*)pCallbackObject, "> endMultiPart()"); +} + +void *mimeDataSink2_startMessagePart (mimeDataSinkPtr_t pSink) +{ + char * msgpCB = getCBObject ("MessagePart", ++messagePartNo); + outmsg2("startMessagePart() ", msgpCB); + return msgpCB; +} + +void mimeDataSink2_endMessagePart (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + outmsg2((char*)pCallbackObject, "> endMessagePart()"); +} + + + +void dynamicParseEntireFile (char *szFilename) +{ + int len, ret; + char buffer[BUFFER_SIZE2]; + struct mimeParser *p; + mimeDataSink_t *pDataSink; + nsmail_inputstream_t *pInStream; + + /* Create a new data-sink */ + ret = mimeDataSink_new (&pDataSink); + + if (ret != MIME_OK) + { + fprintf (stderr, "mimeDataSink_new failed! ret = %d\n", ret); + exit (1); + } + + /* initialize the data-sink */ + pDataSink->header = &mimeDataSink2_header; + pDataSink->addHeader = &mimeDataSink2_addHeader; + pDataSink->endMessageHeader = &mimeDataSink2_endMessageHeader; + pDataSink->contentType = &mimeDataSink2_contentType; + pDataSink->contentSubType = &mimeDataSink2_contentSubType; + pDataSink->contentTypeParams = &mimeDataSink2_contentTypeParams; + pDataSink->contentID = &mimeDataSink2_contentID; + pDataSink->contentMD5 = &mimeDataSink2_contentMD5; + pDataSink->contentDisposition = &mimeDataSink2_contentDisposition; + pDataSink->contentDispParams = &mimeDataSink2_contentDispParams; + pDataSink->contentDescription = &mimeDataSink2_contentDescription; + pDataSink->contentEncoding = &mimeDataSink2_contentEncoding; + + pDataSink->startMessage = &mimeDataSink2_startMessage; + pDataSink->endMessage = &mimeDataSink2_endMessage; + + pDataSink->startBasicPart = &mimeDataSink2_startBasicPart; + pDataSink->bodyData = &mimeDataSink2_bodyData; + pDataSink->endBasicPart = &mimeDataSink2_endBasicPart; + + pDataSink->startMultiPart = &mimeDataSink2_startMultiPart; + pDataSink->boundary = &mimeDataSink2_boundary; + pDataSink->endMultiPart = &mimeDataSink2_endMultiPart; + + pDataSink->startMessagePart = &mimeDataSink2_startMessagePart; + pDataSink->endMessagePart = &mimeDataSink2_endMessagePart; + + /* create a new parser instance */ + ret = mimeDynamicParser_new (pDataSink, &p); + + if (ret != MIME_OK) + { + mimeDataSink_free( &pDataSink); + fprintf (stderr, "mimeDynamicParser_new failed! ret = %d\n", ret); + exit (1); + } + + /* open an input-stream to the file with MIME message to parse */ + ret = file_inputStream_create (szFilename, &pInStream); + + if (ret != MIME_OK) + { + fprintf (stderr, "file_inputStream_create failed! ret = %d\n", ret); + exit (1); + } + + ret = file_outputStream_create (BODYDATA_FILE, &pBodyDataStream); + + if (ret != MIME_OK) + { + fprintf (stderr, "file_outputStream_create on %s failed! ret = %d\n", BODYDATA_FILE, ret); + pBodyDataStream = NULL; + } + + beginDynamicParse (p); + + /* You can also pass the entire stream to the parser */ + /* ret = dynamicParseInputstream (p, pInStream); */ + + for (len = pInStream->read (pInStream->rock, buffer, BUFFER_SIZE2); + len > 0; + len = pInStream->read (pInStream->rock, buffer, BUFFER_SIZE2)) + { + if (dynamicParse (p, buffer, len) != MIME_OK) + break; + } + + ret = endDynamicParse (p); + + if (ret != MIME_OK) + { + fprintf (stderr, "file_inputStream_create failed! ret = %d\n", ret); + exit (1); + } + + /* close and free the inputStream created */ + pInStream->close (pInStream->rock); + nsStream_free (pInStream); + + /* free the parser and data-sink */ + mimeDynamicParser_free (&p); + mimeDataSink_free (&pDataSink); +} + + + +int main (int argc, char *argv[]) +{ + if (argc != 2) + { + fprintf (stderr, "Usage: %s \n", argv[0]); +#ifdef XP_UNIX + fprintf (stderr, "example: %s /tmp/TestCases_MIME/Messages/mime1.txt\n", argv[0]); +#else + fprintf (stderr, "example: %s e:\\share\\MIME_Test\\Messages\\mime1.txt\n", argv[0]); +#endif + exit (1); + } + + dynamicParseEntireFile (argv[1]); + + return 0; +} diff --git a/msgsdk/C/protocol/MIME/test/dynamic/testdynamic.h b/msgsdk/C/protocol/MIME/test/dynamic/testdynamic.h new file mode 100644 index 000000000000..e474d9736b60 --- /dev/null +++ b/msgsdk/C/protocol/MIME/test/dynamic/testdynamic.h @@ -0,0 +1,75 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* +* Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + +/* +* Example dynamic parsing program +*/ + +#ifndef TESTAPP_H +#define TESTAPP_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define BUFFER_SIZE2 256 + + +void dynamicParseEntireFile (char *szFilename); + +void mimeDataSink2_header (mimeDataSinkPtr_t pSink,void *pCallbackObject, char *name, char *value); +void mimeDataSink2_addHeader (mimeDataSinkPtr_t pSink,void *pCallbackObject, char *name, char *value); +void mimeDataSink2_contentType (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentType); +void mimeDataSink2_contentSubType (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentSubType); +void mimeDataSink2_contentTypeParams (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentTypeParams); +void mimeDataSink2_contentID (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *contentID); +void mimeDataSink2_contentMD5 (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentMD5); +void mimeDataSink2_contentDisposition (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentDisposition); +void mimeDataSink2_contentDispParams (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentDispParams); +void mimeDataSink2_contentDescription (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *contentDescription); +void mimeDataSink2_contentEncoding (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentEncoding); +void *mimeDataSink2_startMessageLocalStorage (mimeDataSinkPtr_t pSink, mime_message_t *m); +void *mimeDataSink2_startMessage (mimeDataSinkPtr_t pSink); +void mimeDataSink2_endMessage (mimeDataSinkPtr_t pSink, void *pCallbackObject); +void *mimeDataSink2_startBasicPartLocalStorage (mimeDataSinkPtr_t pSink, mime_basicPart_t *m); +void *mimeDataSink2_startBasicPart (mimeDataSinkPtr_t pSink); +void mimeDataSink2_bodyData (mimeDataSinkPtr_t pSink, void *pCallbackObject, char bodyData[], int len); +void mimeDataSink2_endBasicPart (mimeDataSinkPtr_t pSink, void *pCallbackObject); +void *mimeDataSink2_startMultiPartLocalStorage (mimeDataSinkPtr_t pSink, mime_multiPart_t *m); +void *mimeDataSink2_startMultiPart (mimeDataSinkPtr_t pSink); +void mimeDataSink2_boundary (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * boundary); +void mimeDataSink2_endMultiPart (mimeDataSinkPtr_t pSink, void *pCallbackObject); +void *mimeDataSink2_startMessagePartLocalStorage (mimeDataSinkPtr_t pSink, mime_messagePart_t *m); +void *mimeDataSink2_startMessagePart (mimeDataSinkPtr_t pSink); +void mimeDataSink2_endMessagePart (mimeDataSinkPtr_t pSink, void *pCallbackObject); + + +#ifdef __cplusplus +} +#endif + + +#endif /* TESTAPP_H */ diff --git a/msgsdk/C/protocol/MIME/test/dynamic/testdynamicStream.c b/msgsdk/C/protocol/MIME/test/dynamic/testdynamicStream.c new file mode 100644 index 000000000000..a8be11ffe472 --- /dev/null +++ b/msgsdk/C/protocol/MIME/test/dynamic/testdynamicStream.c @@ -0,0 +1,355 @@ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, + * released on or about June 15, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape + * Communications Corporation. All Rights Reserved. + * + * Contributor(s): ______________________________________. +*/ + +/* * Copyright (c) 1997 and 1998 Netscape Communications Corporation +* (http://home.netscape.com/misc/trademarks.html) +*/ + +/* + * Example program to demonstrate the use of the MIME dynamic parser + * + */ + + +#include "stdio.h" +#include "nsmail.h" +#include "mime.h" +#include "mimeparser.h" +#include "nsStream.h" +#include "testdynamic.h" + + +char achTemp[512]; +int messageNo = 0; +int basicPartNo = 0; +int multiPartNo = 0; +int messagePartNo = 0; +nsmail_outputstream_t *pBodyDataStream; + +#define outmsg(x) (fprintf(stderr,"%s:%d>%s\n",__FILE__,__LINE__,x)) +#define outmsg2(x, y) (fprintf(stderr,"%s:%d>%s%s\n",__FILE__,__LINE__,x,y)) + +#ifdef XP_UNIX +#define BASICPART_FILE "/tmp/bodypart.out" +#define BODYDATA_FILE "/tmp/boddata.out" +#define BASICPART_BYTESTREAM "/tmp/basicpart.bstream" +#else +#define BASICPART_FILE "C:\\temp\\bodypart.out" +#define BODYDATA_FILE "C:\\temp\\boddata.out" +#define BASICPART_BYTESTREAM "C:\\temp\\basicpart.bstream" +#endif + +/* allocate and return the callback object */ +char * getCBObject (char * s, int num) +{ + char * CBObj = (char *) mime_malloc (20); + + memset (CBObj, 0, 20); + + sprintf (CBObj, "%s%d", s, num); + return CBObj; +} + +void freeCBObject (void * pCBObj) +{ + mime_memfree (pCBObj); +} + +/************************************************************************************/ +/* ------ datasink methods ---------- */ +/************************************************************************************/ + + +void mimeDataSink2_header (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *name, char *value) +{ + if (name != NULL && value != NULL) + sprintf( achTemp, "> header() name = [%s] value = [%s]\n", name, value); + else if (name != NULL && value == NULL) + sprintf( achTemp, "> header() name = [%s] value = [%s]\n", name, "null"); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_addHeader (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *name, char *value) +{ + sprintf( achTemp, "> addHeader() name = [%s] value = [%s]\n", name, value); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_endMessageHeader (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + sprintf( achTemp, "> endMessageHeader()"); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentType (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentType) +{ + sprintf( achTemp, "> contentType() = [%d]\n", nContentType); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentSubType (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentSubType) +{ + sprintf( achTemp, "> contentSubType() = [%s]\n", contentSubType); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentTypeParams (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentTypeParams) +{ + sprintf( achTemp, "> contentTypeParams() = [%s]\n", contentTypeParams); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentID (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *contentID) +{ + sprintf( achTemp, "> contentID() = [%s]\n", contentID); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentMD5 (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentMD5) +{ + sprintf( achTemp, "> contentMD5() = [%s]\n", contentMD5); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentDisposition (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentDisposition) +{ + sprintf( achTemp, "> contentDisposition() = [%d]\n", nContentDisposition); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentDispParams (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * contentDispParams) +{ + sprintf( achTemp, "> contentDispParams() = [%s]\n", contentDispParams); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentDescription (mimeDataSinkPtr_t pSink, void *pCallbackObject, char *contentDescription) +{ + sprintf( achTemp, "> contentDescription() = [%s]\n", contentDescription); + outmsg2((char *)pCallbackObject, achTemp); +} + +void mimeDataSink2_contentEncoding (mimeDataSinkPtr_t pSink, void *pCallbackObject, int nContentEncoding) +{ + sprintf( achTemp, "> contentEncoding() = [%d]\n", nContentEncoding); + outmsg2((char *)pCallbackObject, achTemp); +} + +void *mimeDataSink2_startMessage (mimeDataSinkPtr_t pSink) +{ + char * msgCB = getCBObject ("Message", ++messageNo); + outmsg2("startMessage() ", msgCB); + return msgCB; +} + +void mimeDataSink2_endMessage (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + outmsg2((char*)pCallbackObject, "> endMessage()"); + /*outmsg( "endMessage()\n");*/ +} + + +void *mimeDataSink2_startBasicPart (mimeDataSinkPtr_t pSink) +{ + char * basicCB = getCBObject ("BasicPart", ++basicPartNo); + outmsg2("startBasicPart() ", basicCB); + return basicCB; +} + +void mimeDataSink2_bodyData (mimeDataSinkPtr_t pSink, void *pCallbackObject, char bodyData[], int len) +{ + outmsg((char *)pCallbackObject); + outmsg( "bodyData() = ["); + outmsg( "]\n"); + + if (pBodyDataStream != NULL) + { + pBodyDataStream->write (pBodyDataStream->rock, bodyData, len); + } +/* + outmsg( "bodyData() = ["); + outmsg( bodyData); + outmsg( "]\n"); +*/ +} + +void mimeDataSink2_endBasicPart (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + outmsg2((char*)pCallbackObject, "> endBasicPart()"); +} + + +void *mimeDataSink2_startMultiPart (mimeDataSinkPtr_t pSink) +{ + char * mpCB = getCBObject ("MultiPart", ++multiPartNo); + outmsg2("startMultiPart() ", mpCB); + return mpCB; +} + +void mimeDataSink2_boundary (mimeDataSinkPtr_t pSink, void *pCallbackObject, char * boundary) +{ + sprintf( achTemp, "> boundary() = [%s]\n", boundary); + outmsg2((char*)pCallbackObject, achTemp); +} + +void mimeDataSink2_endMultiPart (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + outmsg2((char*)pCallbackObject, "> endMultiPart()"); +} + +void *mimeDataSink2_startMessagePart (mimeDataSinkPtr_t pSink) +{ + char * msgpCB = getCBObject ("MessagePart", ++messagePartNo); + outmsg2("startMessagePart() ", msgpCB); + return msgpCB; +} + +void mimeDataSink2_endMessagePart (mimeDataSinkPtr_t pSink, void *pCallbackObject) +{ + outmsg2((char*)pCallbackObject, "> endMessagePart()"); +} + + + +void dynamicParseEntireFile (char *szFilename) +{ + int len, ret; + char buffer[BUFFER_SIZE2]; + struct mimeParser *p; + mimeDataSink_t *pDataSink; + nsmail_inputstream_t *pInStream; + + /* Create a new data-sink */ + ret = mimeDataSink_new (&pDataSink); + + if (ret != MIME_OK) + { + fprintf (stderr, "mimeDataSink_new failed! ret = %d\n", ret); + exit (1); + } + + /* initialize the data-sink */ + pDataSink->header = &mimeDataSink2_header; + pDataSink->addHeader = &mimeDataSink2_addHeader; + pDataSink->endMessageHeader = &mimeDataSink2_endMessageHeader; + pDataSink->contentType = &mimeDataSink2_contentType; + pDataSink->contentSubType = &mimeDataSink2_contentSubType; + pDataSink->contentTypeParams = &mimeDataSink2_contentTypeParams; + pDataSink->contentID = &mimeDataSink2_contentID; + pDataSink->contentMD5 = &mimeDataSink2_contentMD5; + pDataSink->contentDisposition = &mimeDataSink2_contentDisposition; + pDataSink->contentDispParams = &mimeDataSink2_contentDispParams; + pDataSink->contentDescription = &mimeDataSink2_contentDescription; + pDataSink->contentEncoding = &mimeDataSink2_contentEncoding; + + pDataSink->startMessage = &mimeDataSink2_startMessage; + pDataSink->endMessage = &mimeDataSink2_endMessage; + + pDataSink->startBasicPart = &mimeDataSink2_startBasicPart; + pDataSink->bodyData = &mimeDataSink2_bodyData; + pDataSink->endBasicPart = &mimeDataSink2_endBasicPart; + + pDataSink->startMultiPart = &mimeDataSink2_startMultiPart; + pDataSink->boundary = &mimeDataSink2_boundary; + pDataSink->endMultiPart = &mimeDataSink2_endMultiPart; + + pDataSink->startMessagePart = &mimeDataSink2_startMessagePart; + pDataSink->endMessagePart = &mimeDataSink2_endMessagePart; + + /* create a new parser instance */ + ret = mimeDynamicParser_new (pDataSink, &p); + + if (ret != MIME_OK) + { + mimeDataSink_free( &pDataSink); + fprintf (stderr, "mimeDynamicParser_new failed! ret = %d\n", ret); + exit (1); + } + + /* open an input-stream to the file with MIME message to parse */ + ret = file_inputStream_create (szFilename, &pInStream); + + if (ret != MIME_OK) + { + fprintf (stderr, "file_inputStream_create failed! ret = %d\n", ret); + exit (1); + } + + ret = file_outputStream_create (BODYDATA_FILE, &pBodyDataStream); + if (ret != MIME_OK) + { + fprintf (stderr, "file_outputStream_create on %s failed! ret = %d\n", BODYDATA_FILE, ret); + pBodyDataStream = NULL; + } + + beginDynamicParse (p); + + ret = dynamicParseInputstream (p, pInStream); + + if (ret != MIME_OK) + { + fprintf (stderr, "dynamicParseInputstream failed! ret = %d\n", ret); + } +#if (0) + for (len = pInStream->read (pInStream->rock, buffer, BUFFER_SIZE2); + len > 0; + len = pInStream->read (pInStream->rock, buffer, BUFFER_SIZE2)) + { + if (dynamicParse (p, buffer, len) != MIME_OK) + break; + } +#endif + + ret = endDynamicParse (p); + + if (ret != MIME_OK) + { + fprintf (stderr, "endDynamicParse failed! ret = %d\n", ret); + exit (1); + } + + /* close and free the inputStream created */ + pInStream->close (pInStream->rock); + nsStream_free (pInStream); + + /* free the parser and data-sink */ + mimeDynamicParser_free (&p); + mimeDataSink_free (&pDataSink); +} + + + +int main (int argc, char *argv[]) +{ + if (argc != 2) + { + fprintf (stderr, "Usage: %s \n", argv[0]); +#ifdef XP_UNIX + fprintf (stderr, "example: %s /tmp/TestCases_MIME/Messages/mime1.txt\n", argv[0]); +#else + fprintf (stderr, "example: %s e:\\share\\MIME_Test\\Messages\\mime1.txt\n", argv[0]); +#endif + exit (1); + } + + dynamicParseEntireFile (argv[1]); + + return 0; +}