aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/rfc822/MCMessageBuilder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/rfc822/MCMessageBuilder.cc')
-rw-r--r--src/core/rfc822/MCMessageBuilder.cc312
1 files changed, 246 insertions, 66 deletions
diff --git a/src/core/rfc822/MCMessageBuilder.cc b/src/core/rfc822/MCMessageBuilder.cc
index 3e63ce4a..0ffe0819 100644
--- a/src/core/rfc822/MCMessageBuilder.cc
+++ b/src/core/rfc822/MCMessageBuilder.cc
@@ -12,32 +12,54 @@
using namespace mailcore;
static char * generate_boundary(const char * boundary_prefix);
-struct mailmime * part_multiple_new(const char * type, const char * boundary_prefix);
+struct mailmime * part_multiple_new(MessageBuilder * builder, const char * type, const char * boundary_prefix);
static struct mailmime *
-part_new_empty(struct mailmime_content * content,
+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(const char * boundary_prefix)
+static struct mailmime * get_multipart_alternative(MessageBuilder * builder, const char * boundary_prefix)
{
struct mailmime * mime;
- mime = part_multiple_new("multipart/alternative", boundary_prefix);
+ mime = part_multiple_new(builder, "multipart/alternative", boundary_prefix);
return mime;
}
-static struct mailmime * get_multipart_related(const char * boundary_prefix)
+static struct mailmime * get_multipart_related(MessageBuilder * builder, const char * boundary_prefix)
{
struct mailmime * mime;
- mime = part_multiple_new("multipart/related", boundary_prefix);
+ mime = part_multiple_new(builder, "multipart/related", boundary_prefix);
return mime;
}
-static int add_attachment(struct mailmime * 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)
{
@@ -88,7 +110,7 @@ static int add_attachment(struct mailmime * mime,
/* create a multipart */
- mp = part_multiple_new("multipart/mixed", boundary_prefix);
+ mp = part_multiple_new(builder, "multipart/mixed", boundary_prefix);
if (mp == NULL) {
res = MAILIMF_ERROR_MEMORY;
goto err;
@@ -132,7 +154,8 @@ err:
return res;
}
-static struct mailmime * get_text_part(const char * mime_type, const char * charset, const char * content_id,
+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)
{
@@ -169,23 +192,30 @@ static struct mailmime * get_text_part(const char * mime_type, const char * char
clist_concat(content->ct_parameters, contentTypeParameters);
}
- mime = part_new_empty(content, mime_fields, NULL, 1);
+ 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(const char * mime_type, const char * charset, const char * content_id,
+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)
+ const char * text, size_t length, clist * contentTypeParameters, bool forEncryption)
{
bool needsQuotedPrintable;
int mechanism;
needsQuotedPrintable = false;
- for(size_t i = 0 ; i < length ; i ++) {
- if ((text[i] & (1 << 7)) != 0) {
- needsQuotedPrintable = true;
+ if (forEncryption) {
+ needsQuotedPrintable = true;
+ }
+ if (!needsQuotedPrintable) {
+ for(size_t i = 0 ; i < length ; i ++) {
+ if ((text[i] & (1 << 7)) != 0) {
+ needsQuotedPrintable = true;
+ break;
+ }
}
}
@@ -193,17 +223,19 @@ static struct mailmime * get_plain_text_part(const char * mime_type, const char
if (needsQuotedPrintable) {
mechanism = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
}
- return get_text_part(mime_type, charset, content_id, description, text, length, mechanism, contentTypeParameters);
+ return get_text_part(builder, mime_type, charset, content_id, description, text, length, mechanism, contentTypeParameters);
}
-static struct mailmime * get_other_text_part(const char * mime_type, const char * charset, const char * content_id,
+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(mime_type, charset, content_id, description, text, length, MAILMIME_MECHANISM_QUOTED_PRINTABLE, 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(const char * filename, const char * mime_type, int is_inline,
+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)
@@ -247,7 +279,7 @@ static struct mailmime * get_file_part(const char * filename, const char * mime_
clist_concat(content->ct_parameters, contentTypeParameters);
}
- mime = part_new_empty(content, mime_fields, NULL, 1);
+ mime = part_new_empty(builder, content, mime_fields, NULL, 1);
mailmime_set_body_text(mime, (char *) text, length);
return mime;
@@ -272,7 +304,7 @@ static clist * content_type_parameters_from_attachment(Attachment * att)
return contentTypeParameters;
}
-static struct mailmime * mime_from_attachment(Attachment * att)
+static struct mailmime * mime_from_attachment(MessageBuilder * builder, Attachment * att, bool forEncryption)
{
struct mailmime * mime;
Data * data;
@@ -291,21 +323,22 @@ static struct mailmime * mime_from_attachment(Attachment * att)
else {
clist * contentTypeParameters = content_type_parameters_from_attachment(att);
if (att->isInlineAttachment() && att->mimeType()->lowercaseString()->isEqual(MCSTR("text/plain"))) {
- mime = get_plain_text_part(MCUTF8(att->mimeType()), MCUTF8(att->charset()),
+ 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);
+ contentTypeParameters,
+ forEncryption);
}
else if (att->isInlineAttachment() && att->mimeType()->lowercaseString()->hasPrefix(MCSTR("text/"))) {
- mime = get_other_text_part(MCUTF8(att->mimeType()), MCUTF8(att->charset()),
+ 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(MIME_ENCODED_STR(att->filename()),
+ mime = get_file_part(builder, MIME_ENCODED_STR(att->filename()),
MCUTF8(att->mimeType()), att->isInlineAttachment(),
MCUTF8(att->contentID()),
MIME_ENCODED_STR(att->contentDescription()),
@@ -319,24 +352,25 @@ static struct mailmime * mime_from_attachment(Attachment * att)
return mime;
}
-static struct mailmime * multipart_related_from_attachments(Attachment * htmlAttachment,
- Array * attachments, const char * boundary_prefix)
+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(boundary_prefix);
+ mime = get_multipart_related(builder, boundary_prefix);
- submime = mime_from_attachment(htmlAttachment);
- add_attachment(mime, submime, 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(attachment);
- add_attachment(mime, submime, boundary_prefix);
+ submime = mime_from_attachment(builder, attachment, forEncryption);
+ add_attachment(builder, mime, submime, boundary_prefix);
}
return mime;
@@ -344,14 +378,14 @@ static struct mailmime * multipart_related_from_attachments(Attachment * htmlAtt
else {
struct mailmime * mime;
- mime = mime_from_attachment(htmlAttachment);
+ mime = mime_from_attachment(builder, htmlAttachment, forEncryption);
return mime;
}
}
static struct mailmime *
-part_new_empty(struct mailmime_content * content,
+part_new_empty(MessageBuilder * builder, struct mailmime_content * content,
struct mailmime_fields * mime_fields,
const char * boundary_prefix,
int force_single)
@@ -410,7 +444,13 @@ part_new_empty(struct mailmime_content * content,
if (attr_name == NULL)
goto free_list;
- boundary = generate_boundary(boundary_prefix);
+ 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);
@@ -462,7 +502,7 @@ err:
return NULL;
}
-struct mailmime * part_multiple_new(const char * type, const char * boundary_prefix)
+struct mailmime * part_multiple_new(MessageBuilder * builder, const char * type, const char * boundary_prefix)
{
struct mailmime_fields * mime_fields;
struct mailmime_content * content;
@@ -476,7 +516,7 @@ struct mailmime * part_multiple_new(const char * type, const char * boundary_pre
if (content == NULL)
goto free_fields;
- mp = part_new_empty(content, mime_fields, boundary_prefix, 0);
+ mp = part_new_empty(builder, content, mime_fields, boundary_prefix, 0);
if (mp == NULL)
goto free_content;
@@ -519,8 +559,10 @@ void MessageBuilder::init()
mAttachments = NULL;
mRelatedAttachments = NULL;
mBoundaryPrefix = NULL;
+ mBoundaries = new Array();
+ mCurrentBoundaryIndex = 0;
}
-
+
MessageBuilder::MessageBuilder()
{
init();
@@ -543,6 +585,7 @@ MessageBuilder::~MessageBuilder()
MC_SAFE_RELEASE(mAttachments);
MC_SAFE_RELEASE(mRelatedAttachments);
MC_SAFE_RELEASE(mBoundaryPrefix);
+ MC_SAFE_RELEASE(mBoundaries);
}
String * MessageBuilder::description()
@@ -655,45 +698,42 @@ String * MessageBuilder::boundaryPrefix()
return mBoundaryPrefix;
}
-Data * MessageBuilder::dataAndFilterBcc(bool filterBcc)
+struct mailmime * MessageBuilder::mimeAndFilterBccAndForEncryption(bool filterBcc, bool forEncryption)
{
- Data * data;
- MMAPString * str;
- int col;
-
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(htmlAttachment, mRelatedAttachments,
- MCUTF8(mBoundaryPrefix));
+ htmlPart = multipart_related_from_attachments(this, htmlAttachment, mRelatedAttachments,
+ MCUTF8(mBoundaryPrefix), forEncryption);
}
-
+
if (textBody() != NULL) {
Attachment * textAttachment;
-
+
textAttachment = Attachment::attachmentWithText(textBody());
- textPart = mime_from_attachment(textAttachment);
+ textPart = mime_from_attachment(this, textAttachment, forEncryption);
}
else if (htmlBody() != NULL) {
Attachment * textAttachment;
-
+
textAttachment = Attachment::attachmentWithText(htmlBody()->flattenHTML());
- textPart = mime_from_attachment(textAttachment);
+ textPart = mime_from_attachment(this, textAttachment, forEncryption);
}
-
+
if ((textPart != NULL) && (htmlPart != NULL)) {
- altPart = get_multipart_alternative(MCUTF8(mBoundaryPrefix));
+ altPart = get_multipart_alternative(this, MCUTF8(mBoundaryPrefix));
mailmime_smart_add_part(altPart, textPart);
mailmime_smart_add_part(altPart, htmlPart);
mainPart = altPart;
@@ -704,44 +744,66 @@ Data * MessageBuilder::dataAndFilterBcc(bool filterBcc)
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(mime, mainPart, MCUTF8(mBoundaryPrefix));
+ 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(attachment);
- add_attachment(mime, submime, MCUTF8(mBoundaryPrefix));
+ 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 dataAndFilterBcc(false);
+ return dataAndFilterBccAndForEncryption(false, false);
+}
+
+Data * MessageBuilder::dataForEncryption()
+{
+ return dataAndFilterBccAndForEncryption(false, true);
}
String * MessageBuilder::htmlRendering(HTMLRendererTemplateCallback * htmlCallback)
@@ -768,3 +830,121 @@ String * MessageBuilder::plainTextBodyRendering(bool stripWhitespace)
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();
+}
+