aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/rfc822/MCMessageBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/rfc822/MCMessageBuilder.cpp')
-rw-r--r--src/core/rfc822/MCMessageBuilder.cpp959
1 files changed, 959 insertions, 0 deletions
diff --git a/src/core/rfc822/MCMessageBuilder.cpp b/src/core/rfc822/MCMessageBuilder.cpp
new file mode 100644
index 00000000..a98cefd1
--- /dev/null
+++ b/src/core/rfc822/MCMessageBuilder.cpp
@@ -0,0 +1,959 @@
+#include "MCWin32.h" // Should be included first.
+
+#include "MCMessageBuilder.h"
+
+#include "MCMessageHeader.h"
+#include "MCAttachment.h"
+#include "MCMessageParser.h"
+
+#include <stdlib.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <libetpan/libetpan.h>
+
+using namespace mailcore;
+
+static char * generate_boundary(const char * boundary_prefix);
+struct mailmime * part_multiple_new(MessageBuilder * builder, const char * type, const char * boundary_prefix);
+static struct mailmime *
+part_new_empty(MessageBuilder * builder, struct mailmime_content * content,
+ struct mailmime_fields * mime_fields,
+ const char * boundary_prefix,
+ int force_single);
+
+static struct mailmime * get_multipart_alternative(MessageBuilder * builder, const char * boundary_prefix)
+{
+ struct mailmime * mime;
+
+ mime = part_multiple_new(builder, "multipart/alternative", boundary_prefix);
+
+ return mime;
+}
+
+static struct mailmime * get_multipart_related(MessageBuilder * builder, const char * boundary_prefix)
+{
+ struct mailmime * mime;
+
+ mime = part_multiple_new(builder, "multipart/related", boundary_prefix);
+
+ return mime;
+}
+
+static struct mailmime * get_multipart_signed_pgp(MessageBuilder * builder, const char * boundary_prefix)
+{
+ struct mailmime * mime;
+
+ mime = part_multiple_new(builder, "multipart/signed", boundary_prefix);
+ struct mailmime_parameter * param = mailmime_param_new_with_data((char *) "protocol", (char *) "application/pgp-signature");
+ clist_append(mime->mm_content_type->ct_parameters, param);
+
+ return mime;
+}
+
+static struct mailmime * get_multipart_encrypted_pgp(MessageBuilder * builder, const char * boundary_prefix)
+{
+ struct mailmime * mime;
+
+ mime = part_multiple_new(builder, "multipart/encrypted", boundary_prefix);
+ struct mailmime_parameter * param = mailmime_param_new_with_data((char *) "protocol", (char *) "application/pgp-encrypted");
+ clist_append(mime->mm_content_type->ct_parameters, param);
+
+ return mime;
+}
+
+static int add_attachment(MessageBuilder * builder, struct mailmime * mime,
+ struct mailmime * mime_sub,
+ const char * boundary_prefix)
+{
+ struct mailmime * saved_sub;
+ struct mailmime * mp;
+ int res;
+ int r;
+
+ switch (mime->mm_type) {
+ case MAILMIME_SINGLE:
+ res = MAILIMF_ERROR_INVAL;
+ goto err;
+
+ case MAILMIME_MULTIPLE:
+ r = mailmime_add_part(mime, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ return MAILIMF_NO_ERROR;
+ }
+
+ /* MAILMIME_MESSAGE */
+
+ if (mime->mm_data.mm_message.mm_msg_mime == NULL) {
+ /* there is no subpart, we can simply attach it */
+
+ r = mailmime_add_part(mime, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ return MAILIMF_NO_ERROR;
+ }
+
+ if (mime->mm_data.mm_message.mm_msg_mime->mm_type == MAILMIME_MULTIPLE &&
+ strcasecmp(mime->mm_data.mm_message.mm_msg_mime->mm_content_type->ct_subtype, "alternative") != 0) {
+ /* in case the subpart is multipart, simply attach it to the subpart */
+
+ return mailmime_add_part(mime->mm_data.mm_message.mm_msg_mime, mime_sub);
+ }
+
+ /* we save the current subpart, ... */
+
+ saved_sub = mime->mm_data.mm_message.mm_msg_mime;
+
+ /* create a multipart */
+
+ mp = part_multiple_new(builder, "multipart/mixed", boundary_prefix);
+ if (mp == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ /* detach the saved subpart from the parent */
+
+ mailmime_remove_part(saved_sub);
+
+ /* the created multipart is the new child of the parent */
+
+ r = mailmime_add_part(mime, mp);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mp;
+ }
+
+ /* then, attach the saved subpart and ... */
+
+ r = mailmime_add_part(mp, saved_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_saved_sub;
+ }
+
+ /* the given part to the parent */
+
+ r = mailmime_add_part(mp, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_saved_sub;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+free_mp:
+ mailmime_free(mp);
+free_saved_sub:
+ mailmime_free(saved_sub);
+err:
+ return res;
+}
+
+static struct mailmime * get_text_part(MessageBuilder * builder,
+ const char * mime_type, const char * charset, const char * content_id,
+ const char * description,
+ const char * text, size_t length, int encoding_type, clist * contentTypeParameters)
+{
+ struct mailmime_fields * mime_fields;
+ struct mailmime * mime;
+ struct mailmime_content * content;
+ struct mailmime_parameter * param;
+ struct mailmime_disposition * disposition;
+ struct mailmime_mechanism * encoding;
+ char * dup_content_id;
+ char * dup_description;
+
+ encoding = mailmime_mechanism_new(encoding_type, NULL);
+ disposition = mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
+ NULL, NULL, NULL, NULL, (size_t) -1);
+ dup_content_id = NULL;
+ if (content_id != NULL)
+ dup_content_id = strdup(content_id);
+ dup_description = NULL;
+ if (dup_description != NULL)
+ dup_description = strdup(description);
+ mime_fields = mailmime_fields_new_with_data(encoding,
+ dup_content_id, dup_description, disposition, NULL);
+
+ content = mailmime_content_new_with_str(mime_type);
+ if (charset == NULL) {
+ param = mailmime_param_new_with_data((char *) "charset", (char *) "utf-8");
+ }
+ else {
+ param = mailmime_param_new_with_data((char *) "charset", (char *) charset);
+ }
+ clist_append(content->ct_parameters, param);
+ if (contentTypeParameters != NULL) {
+ clist_concat(content->ct_parameters, contentTypeParameters);
+ }
+
+ mime = part_new_empty(builder, content, mime_fields, NULL, 1);
+ mailmime_set_body_text(mime, (char *) text, length);
+
+ return mime;
+}
+
+static struct mailmime * get_plain_text_part(MessageBuilder * builder,
+ const char * mime_type, const char * charset, const char * content_id,
+ const char * description,
+ const char * text, size_t length, clist * contentTypeParameters, bool forEncryption)
+{
+ bool needsQuotedPrintable;
+ int mechanism;
+
+ needsQuotedPrintable = false;
+ if (forEncryption) {
+ needsQuotedPrintable = true;
+ }
+ if (!needsQuotedPrintable) {
+ for(size_t i = 0 ; i < length ; i ++) {
+ if ((text[i] & (1 << 7)) != 0) {
+ needsQuotedPrintable = true;
+ break;
+ }
+ }
+ }
+
+ mechanism = MAILMIME_MECHANISM_7BIT;
+ if (needsQuotedPrintable) {
+ mechanism = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
+ }
+ return get_text_part(builder, mime_type, charset, content_id, description, text, length, mechanism, contentTypeParameters);
+}
+
+static struct mailmime * get_other_text_part(MessageBuilder * builder,
+ const char * mime_type, const char * charset, const char * content_id,
+ const char * description,
+ const char * text, size_t length, clist * contentTypeParameters)
+{
+ return get_text_part(builder, mime_type, charset, content_id, description, text, length, MAILMIME_MECHANISM_QUOTED_PRINTABLE, contentTypeParameters);
+}
+
+static struct mailmime * get_file_part(MessageBuilder * builder,
+ const char * filename, const char * mime_type, int is_inline,
+ const char * content_id,
+ const char * content_description,
+ const char * text, size_t length, clist * contentTypeParameters)
+{
+ char * disposition_name;
+ int encoding_type;
+ struct mailmime_disposition * disposition;
+ struct mailmime_mechanism * encoding;
+ struct mailmime_content * content;
+ struct mailmime * mime;
+ struct mailmime_fields * mime_fields;
+ char * dup_content_id;
+ char * dup_content_description;
+
+ disposition_name = NULL;
+ if (filename != NULL) {
+ disposition_name = strdup(filename);
+ }
+ if (is_inline) {
+ disposition = mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
+ disposition_name, NULL, NULL, NULL, (size_t) -1);
+ }
+ else {
+ disposition = mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
+ disposition_name, NULL, NULL, NULL, (size_t) -1);
+ }
+ content = mailmime_content_new_with_str(mime_type);
+
+ encoding_type = MAILMIME_MECHANISM_BASE64;
+ encoding = mailmime_mechanism_new(encoding_type, NULL);
+ dup_content_id = NULL;
+ if (content_id != NULL)
+ dup_content_id = strdup(content_id);
+ dup_content_description = NULL;
+ if (content_description != NULL)
+ dup_content_description = strdup(content_description);
+ mime_fields = mailmime_fields_new_with_data(encoding,
+ dup_content_id, dup_content_description, disposition, NULL);
+
+ if (contentTypeParameters != NULL) {
+ clist_concat(content->ct_parameters, contentTypeParameters);
+ }
+
+ mime = part_new_empty(builder, content, mime_fields, NULL, 1);
+ mailmime_set_body_text(mime, (char *) text, length);
+
+ return mime;
+}
+
+#define MIME_ENCODED_STR(str) (str != NULL ? str->encodedMIMEHeaderValue()->bytes() : NULL)
+
+static clist * content_type_parameters_from_attachment(Attachment * att)
+{
+ clist * contentTypeParameters = NULL;
+ struct mailmime_parameter * param;
+
+ mc_foreacharray(String, name, att->allContentTypeParametersNames()) {
+ if (contentTypeParameters == NULL) {
+ contentTypeParameters = clist_new();
+ }
+ String * value = att->contentTypeParameterValueForName(name);
+ param = mailmime_param_new_with_data((char *)name->UTF8Characters(), (char *)value->UTF8Characters());
+ clist_append(contentTypeParameters, param);
+ }
+
+ return contentTypeParameters;
+}
+
+static struct mailmime * mime_from_attachment(MessageBuilder * builder, Attachment * att, bool forEncryption)
+{
+ struct mailmime * mime;
+ Data * data;
+ int r;
+
+ data = att->data();
+ if (data == NULL) {
+ data = Data::data();
+ }
+ if (att->mimeType()->lowercaseString()->isEqual(MCSTR("message/rfc822"))) {
+ size_t indx = 0;
+ r = mailmime_parse(data->bytes(), data->length(), &indx, &mime);
+ if (r != MAILIMF_NO_ERROR)
+ return NULL;
+ }
+ else {
+ clist * contentTypeParameters = content_type_parameters_from_attachment(att);
+ if (att->isInlineAttachment() && att->mimeType()->lowercaseString()->isEqual(MCSTR("text/plain"))) {
+ mime = get_plain_text_part(builder, MCUTF8(att->mimeType()), MCUTF8(att->charset()),
+ MCUTF8(att->contentID()),
+ MIME_ENCODED_STR(att->contentDescription()),
+ data->bytes(), data->length(),
+ contentTypeParameters,
+ forEncryption);
+ }
+ else if (att->isInlineAttachment() && att->mimeType()->lowercaseString()->hasPrefix(MCSTR("text/"))) {
+ mime = get_other_text_part(builder, MCUTF8(att->mimeType()), MCUTF8(att->charset()),
+ MCUTF8(att->contentID()),
+ MIME_ENCODED_STR(att->contentDescription()),
+ data->bytes(), data->length(),
+ contentTypeParameters);
+ }
+ else {
+ mime = get_file_part(builder, MIME_ENCODED_STR(att->filename()),
+ MCUTF8(att->mimeType()), att->isInlineAttachment(),
+ MCUTF8(att->contentID()),
+ MIME_ENCODED_STR(att->contentDescription()),
+ data->bytes(), data->length(),
+ contentTypeParameters);
+ }
+ if (contentTypeParameters != NULL) {
+ clist_free(contentTypeParameters);
+ }
+ }
+ return mime;
+}
+
+static struct mailmime * multipart_related_from_attachments(MessageBuilder * builder,
+ Attachment * htmlAttachment,
+ Array * attachments, const char * boundary_prefix, bool forEncryption)
+{
+ if ((attachments != NULL) && (attachments->count() > 0)) {
+ struct mailmime * submime;
+ struct mailmime * mime;
+
+ mime = get_multipart_related(builder, boundary_prefix);
+
+ submime = mime_from_attachment(builder, htmlAttachment, forEncryption);
+ add_attachment(builder, mime, submime, boundary_prefix);
+
+ for(unsigned int i = 0 ; i < attachments->count() ; i ++) {
+ Attachment * attachment;
+
+ attachment = (Attachment *) attachments->objectAtIndex(i);
+ submime = mime_from_attachment(builder, attachment, forEncryption);
+ add_attachment(builder, mime, submime, boundary_prefix);
+ }
+
+ return mime;
+ }
+ else {
+ struct mailmime * mime;
+
+ mime = mime_from_attachment(builder, htmlAttachment, forEncryption);
+
+ return mime;
+ }
+}
+
+static struct mailmime *
+part_new_empty(MessageBuilder * builder, struct mailmime_content * content,
+ struct mailmime_fields * mime_fields,
+ const char * boundary_prefix,
+ int force_single)
+{
+ struct mailmime * build_info;
+ clist * list;
+ int r;
+ int mime_type;
+
+ list = NULL;
+
+ if (force_single) {
+ mime_type = MAILMIME_SINGLE;
+ }
+ else {
+ switch (content->ct_type->tp_type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ mime_type = MAILMIME_SINGLE;
+ break;
+
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ mime_type = MAILMIME_MULTIPLE;
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+ if (strcasecmp(content->ct_subtype, "rfc822") == 0)
+ mime_type = MAILMIME_MESSAGE;
+ else
+ mime_type = MAILMIME_SINGLE;
+ break;
+
+ default:
+ goto err;
+ }
+ break;
+
+ default:
+ goto err;
+ }
+ }
+
+ if (mime_type == MAILMIME_MULTIPLE) {
+ char * attr_name;
+ char * attr_value;
+ struct mailmime_parameter * param;
+ clist * parameters;
+ char * boundary;
+
+ list = clist_new();
+ if (list == NULL)
+ goto err;
+
+ attr_name = strdup("boundary");
+ if (attr_name == NULL)
+ goto free_list;
+
+ if (builder != NULL) {
+ String * boundaryString = builder->nextBoundary();
+ boundary = strdup(boundaryString->UTF8Characters());
+ }
+ else {
+ boundary = generate_boundary(boundary_prefix);
+ }
+ attr_value = boundary;
+ if (attr_name == NULL) {
+ free(attr_name);
+ goto free_list;
+ }
+
+ param = mailmime_parameter_new(attr_name, attr_value);
+ if (param == NULL) {
+ free(attr_value);
+ free(attr_name);
+ goto free_list;
+ }
+
+ if (content->ct_parameters == NULL) {
+ parameters = clist_new();
+ if (parameters == NULL) {
+ mailmime_parameter_free(param);
+ goto free_list;
+ }
+ }
+ else
+ parameters = content->ct_parameters;
+
+ r = clist_append(parameters, param);
+ if (r != 0) {
+ clist_free(parameters);
+ mailmime_parameter_free(param);
+ goto free_list;
+ }
+
+ if (content->ct_parameters == NULL)
+ content->ct_parameters = parameters;
+ }
+
+ build_info = mailmime_new(mime_type,
+ NULL, 0, mime_fields, content,
+ NULL, NULL, NULL, list,
+ NULL, NULL);
+ if (build_info == NULL) {
+ clist_free(list);
+ return NULL;
+ }
+
+ return build_info;
+
+free_list:
+ clist_free(list);
+err:
+ return NULL;
+}
+
+struct mailmime * part_multiple_new(MessageBuilder * builder, const char * type, const char * boundary_prefix)
+{
+ struct mailmime_fields * mime_fields;
+ struct mailmime_content * content;
+ struct mailmime * mp;
+
+ mime_fields = mailmime_fields_new_empty();
+ if (mime_fields == NULL)
+ goto err;
+
+ content = mailmime_content_new_with_str(type);
+ if (content == NULL)
+ goto free_fields;
+
+ mp = part_new_empty(builder, content, mime_fields, boundary_prefix, 0);
+ if (mp == NULL)
+ goto free_content;
+
+ return mp;
+
+free_content:
+ mailmime_content_free(content);
+free_fields:
+ mailmime_fields_free(mime_fields);
+err:
+ return NULL;
+}
+
+#define MAX_MESSAGE_ID 512
+
+static char * generate_boundary(const char * boundary_prefix)
+{
+ char id[MAX_MESSAGE_ID];
+ time_t now;
+ char name[MAX_MESSAGE_ID];
+ long value;
+
+ now = time(NULL);
+ value = random();
+
+ gethostname(name, MAX_MESSAGE_ID);
+
+ if (boundary_prefix == NULL)
+ boundary_prefix = "";
+
+ snprintf(id, MAX_MESSAGE_ID, "%s%lx_%lx_%x", boundary_prefix, now, value, getpid());
+
+ return strdup(id);
+}
+
+void MessageBuilder::init()
+{
+ mHTMLBody = NULL;
+ mTextBody = NULL;
+ mAttachments = NULL;
+ mRelatedAttachments = NULL;
+ mBoundaryPrefix = NULL;
+ mBoundaries = new Array();
+ mCurrentBoundaryIndex = 0;
+}
+
+MessageBuilder::MessageBuilder()
+{
+ init();
+}
+
+MessageBuilder::MessageBuilder(MessageBuilder * other) : AbstractMessage(other)
+{
+ init();
+ setHTMLBody(other->mHTMLBody);
+ setTextBody(other->mTextBody);
+ setAttachments(other->mAttachments);
+ setRelatedAttachments(other->mRelatedAttachments);
+ MC_SAFE_REPLACE_COPY(String, mBoundaryPrefix, other->mBoundaryPrefix);
+}
+
+MessageBuilder::~MessageBuilder()
+{
+ MC_SAFE_RELEASE(mHTMLBody);
+ MC_SAFE_RELEASE(mTextBody);
+ MC_SAFE_RELEASE(mAttachments);
+ MC_SAFE_RELEASE(mRelatedAttachments);
+ MC_SAFE_RELEASE(mBoundaryPrefix);
+ MC_SAFE_RELEASE(mBoundaries);
+}
+
+String * MessageBuilder::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this);
+ if (header() != NULL) {
+ result->appendString(header()->description());
+ result->appendUTF8Characters("\n");
+ }
+ if (mHTMLBody != NULL) {
+ result->appendUTF8Characters("-- html body --\n");
+ result->appendString(mHTMLBody);
+ result->appendUTF8Characters("\n");
+ }
+ if (mTextBody != NULL) {
+ result->appendUTF8Characters("-- text body --\n");
+ result->appendString(mTextBody);
+ result->appendUTF8Characters("\n");
+ }
+ if (mAttachments != NULL) {
+ result->appendUTF8Characters("-- attachments --\n");
+ result->appendString(mAttachments->description());
+ result->appendUTF8Characters("\n");
+ }
+ if (mRelatedAttachments != NULL) {
+ result->appendUTF8Characters("-- related attachments --\n");
+ result->appendString(mRelatedAttachments->description());
+ result->appendUTF8Characters("\n");
+ }
+ result->appendUTF8Characters(">");
+
+ return result;
+}
+
+Object * MessageBuilder::copy()
+{
+ return new MessageBuilder(this);
+}
+
+void MessageBuilder::setHTMLBody(String * htmlBody)
+{
+ MC_SAFE_REPLACE_COPY(String, mHTMLBody, htmlBody);
+}
+
+String * MessageBuilder::htmlBody()
+{
+ return mHTMLBody;
+}
+
+void MessageBuilder::setTextBody(String * textBody)
+{
+ MC_SAFE_REPLACE_COPY(String, mTextBody, textBody);
+}
+
+String * MessageBuilder::textBody()
+{
+ return mTextBody;
+}
+
+void MessageBuilder::setAttachments(Array * attachments)
+{
+ MC_SAFE_REPLACE_COPY(Array, mAttachments, attachments);
+}
+
+Array * MessageBuilder::attachments()
+{
+ return mAttachments;
+}
+
+void MessageBuilder::addAttachment(Attachment * attachment)
+{
+ if (attachment == NULL) {
+ return;
+ }
+ if (mAttachments == NULL) {
+ mAttachments = new Array();
+ }
+ mAttachments->addObject(attachment);
+}
+
+void MessageBuilder::setRelatedAttachments(Array * attachments)
+{
+ MC_SAFE_REPLACE_COPY(Array, mRelatedAttachments, attachments);
+}
+
+Array * MessageBuilder::relatedAttachments()
+{
+ return mRelatedAttachments;
+}
+
+void MessageBuilder::addRelatedAttachment(Attachment * attachment)
+{
+ if (attachment == NULL) {
+ return;
+ }
+ if (mRelatedAttachments == NULL) {
+ mRelatedAttachments = new Array();
+ }
+ mRelatedAttachments->addObject(attachment);
+}
+
+void MessageBuilder::setBoundaryPrefix(String * boundaryPrefix)
+{
+ MC_SAFE_REPLACE_COPY(String, mBoundaryPrefix, boundaryPrefix);
+}
+
+String * MessageBuilder::boundaryPrefix()
+{
+ return mBoundaryPrefix;
+}
+
+struct mailmime * MessageBuilder::mimeAndFilterBccAndForEncryption(bool filterBcc, bool forEncryption)
+{
+ struct mailmime * htmlPart;
+ struct mailmime * textPart;
+ struct mailmime * altPart;
+ struct mailmime * mainPart;
+
+ mCurrentBoundaryIndex = 0;
+ htmlPart = NULL;
+ textPart = NULL;
+ altPart = NULL;
+ mainPart = NULL;
+
+ if (htmlBody() != NULL) {
+ Attachment * htmlAttachment;
+
+ htmlAttachment = Attachment::attachmentWithHTMLString(htmlBody());
+ htmlPart = multipart_related_from_attachments(this, htmlAttachment, mRelatedAttachments,
+ MCUTF8(mBoundaryPrefix), forEncryption);
+ }
+
+ if (textBody() != NULL) {
+ Attachment * textAttachment;
+
+ textAttachment = Attachment::attachmentWithText(textBody());
+ textPart = mime_from_attachment(this, textAttachment, forEncryption);
+ }
+ else if (htmlBody() != NULL) {
+ Attachment * textAttachment;
+
+ textAttachment = Attachment::attachmentWithText(htmlBody()->flattenHTML());
+ textPart = mime_from_attachment(this, textAttachment, forEncryption);
+ }
+
+ if ((textPart != NULL) && (htmlPart != NULL)) {
+ altPart = get_multipart_alternative(this, MCUTF8(mBoundaryPrefix));
+ mailmime_smart_add_part(altPart, textPart);
+ mailmime_smart_add_part(altPart, htmlPart);
+ mainPart = altPart;
+ }
+ else if (textPart != NULL) {
+ mainPart = textPart;
+ }
+ else if (htmlPart != NULL) {
+ mainPart = htmlPart;
+ }
+
+ struct mailimf_fields * fields;
+ unsigned int i;
+ struct mailmime * mime;
+
+ fields = header()->createIMFFieldsAndFilterBcc(filterBcc);
+
+ mime = mailmime_new_message_data(NULL);
+ mailmime_set_imf_fields(mime, fields);
+
+ if (mainPart != NULL) {
+ add_attachment(this, mime, mainPart, MCUTF8(mBoundaryPrefix));
+ }
+
+ if (attachments() != NULL) {
+ for(i = 0 ; i < attachments()->count() ; i ++) {
+ Attachment * attachment;
+ struct mailmime * submime;
+
+ attachment = (Attachment *) attachments()->objectAtIndex(i);
+ submime = mime_from_attachment(this, attachment, forEncryption);
+ add_attachment(this, mime, submime, MCUTF8(mBoundaryPrefix));
+ }
+ }
+
+ struct mailmime * result = mime;
+ if (forEncryption) {
+ result = mime->mm_data.mm_message.mm_msg_mime;
+ mime->mm_data.mm_message.mm_msg_mime = NULL;
+ mailmime_free(mime);
+ }
+
+ return result;
+}
+
+Data * MessageBuilder::dataAndFilterBccAndForEncryption(bool filterBcc, bool forEncryption)
+{
+ Data * data;
+ MMAPString * str;
+ int col;
+
+ str = mmap_string_new("");
+ col = 0;
+ struct mailmime * mime = mimeAndFilterBccAndForEncryption(filterBcc, forEncryption);
+ mailmime_write_mem(str, &col, mime);
+ data = Data::dataWithBytes(str->str, (unsigned int) str->len);
+ mmap_string_free(str);
+ mailmime_free(mime);
+
+ return data;
+}
+
+Data * MessageBuilder::data()
+{
+ return dataAndFilterBccAndForEncryption(false, false);
+}
+
+Data * MessageBuilder::dataForEncryption()
+{
+ return dataAndFilterBccAndForEncryption(false, true);
+}
+
+String * MessageBuilder::htmlRendering(HTMLRendererTemplateCallback * htmlCallback)
+{
+ MessageParser * message = MessageParser::messageParserWithData(data());
+ return message->htmlRendering(htmlCallback);
+}
+
+String * MessageBuilder::htmlBodyRendering()
+{
+ MessageParser * message = MessageParser::messageParserWithData(data());
+ return message->htmlBodyRendering();
+}
+
+String * MessageBuilder::plainTextRendering()
+{
+ MessageParser * message = MessageParser::messageParserWithData(data());
+ return message->plainTextRendering();
+}
+
+String * MessageBuilder::plainTextBodyRendering(bool stripWhitespace)
+{
+ MessageParser * message = MessageParser::messageParserWithData(data());
+ return message->plainTextBodyRendering(stripWhitespace);
+}
+
+struct mailmime * get_signature_part(Data * signature)
+{
+ struct mailmime * mime;
+ struct mailmime_content * content;
+
+ content = mailmime_content_new_with_str("application/pgp-signature");
+ struct mailmime_fields * mime_fields = mailmime_fields_new_empty();
+ mime = part_new_empty(NULL, content, mime_fields, NULL, 1);
+ mailmime_set_body_text(mime, signature->bytes(), signature->length());
+
+ return mime;
+}
+
+Data * MessageBuilder::openPGPSignedMessageDataWithSignatureData(Data * signature)
+{
+ struct mailimf_fields * fields;
+ struct mailmime * mime;
+
+ fields = header()->createIMFFieldsAndFilterBcc(false);
+
+ mime = mailmime_new_message_data(NULL);
+ mailmime_set_imf_fields(mime, fields);
+
+ struct mailmime * multipart = get_multipart_signed_pgp(NULL, MCUTF8(boundaryPrefix()));
+ add_attachment(NULL, mime, multipart, MCUTF8(boundaryPrefix()));
+ struct mailmime * part_to_sign = mimeAndFilterBccAndForEncryption(false, true);
+ add_attachment(NULL, multipart, part_to_sign, MCUTF8(boundaryPrefix()));
+ struct mailmime * signature_part = get_signature_part(signature);
+ add_attachment(NULL, multipart, signature_part, MCUTF8(boundaryPrefix()));
+
+ MMAPString * str = mmap_string_new("");
+ int col = 0;
+
+ mailmime_write_mem(str, &col, mime);
+ Data * data = Data::dataWithBytes(str->str, (unsigned int) str->len);
+ mmap_string_free(str);
+ mailmime_free(mime);
+
+ return data;
+}
+
+static struct mailmime * get_pgp_version_part(void)
+{
+ struct mailmime * mime;
+ struct mailmime_content * content;
+
+ content = mailmime_content_new_with_str("application/pgp-encrypted");
+ struct mailmime_fields * mime_fields = mailmime_fields_new_empty();
+ mime = part_new_empty(NULL, content, mime_fields, NULL, 1);
+ const char * version = "Version: 1\r\n";
+ mailmime_set_body_text(mime, (char *) version, strlen(version));
+
+ return mime;
+}
+
+static struct mailmime * get_encrypted_part(Data * encryptedData)
+{
+ struct mailmime * mime;
+ struct mailmime_content * content;
+
+ content = mailmime_content_new_with_str("application/octet-stream");
+ struct mailmime_fields * mime_fields = mailmime_fields_new_empty();
+ mime = part_new_empty(NULL, content, mime_fields, NULL, 1);
+ mailmime_set_body_text(mime, encryptedData->bytes(), encryptedData->length());
+
+ return mime;
+}
+
+Data * MessageBuilder::openPGPEncryptedMessageDataWithEncryptedData(Data * encryptedData)
+{
+ struct mailimf_fields * fields;
+ struct mailmime * mime;
+
+ fields = header()->createIMFFieldsAndFilterBcc(false);
+
+ mime = mailmime_new_message_data(NULL);
+ mailmime_set_imf_fields(mime, fields);
+
+ struct mailmime * multipart = get_multipart_encrypted_pgp(NULL, MCUTF8(boundaryPrefix()));
+ add_attachment(NULL, mime, multipart, MCUTF8(boundaryPrefix()));
+
+ struct mailmime * version_part = get_pgp_version_part();
+ add_attachment(NULL, multipart, version_part, MCUTF8(boundaryPrefix()));
+ struct mailmime * encrypted_part = get_encrypted_part(encryptedData);
+ add_attachment(NULL, multipart, encrypted_part, MCUTF8(boundaryPrefix()));
+
+ MMAPString * str = mmap_string_new("");
+ int col = 0;
+
+ mailmime_write_mem(str, &col, mime);
+ Data * data = Data::dataWithBytes(str->str, (unsigned int) str->len);
+ mmap_string_free(str);
+ mailmime_free(mime);
+
+ return data;
+}
+
+String * MessageBuilder::nextBoundary()
+{
+ unsigned int idx = mCurrentBoundaryIndex;
+ mCurrentBoundaryIndex ++;
+ if (idx < mBoundaries->count()) {
+ return (String *) mBoundaries->objectAtIndex(idx);
+ }
+
+ char * boundary = generate_boundary(MCUTF8(mBoundaryPrefix));
+ String * boundaryString = String::stringWithUTF8Characters(boundary);
+ mBoundaries->addObject(boundaryString);
+ free(boundary);
+
+ return boundaryString;
+}
+
+void MessageBuilder::resetBoundaries()
+{
+ mBoundaries->removeAllObjects();
+}
+
+void MessageBuilder::setBoundaries(Array * boundaries)
+{
+ resetBoundaries();
+ mBoundaries->addObjectsFromArray(boundaries);
+}