diff options
Diffstat (limited to 'src/core/abstract/MCMessageHeader.cpp')
-rw-r--r-- | src/core/abstract/MCMessageHeader.cpp | 1291 |
1 files changed, 1291 insertions, 0 deletions
diff --git a/src/core/abstract/MCMessageHeader.cpp b/src/core/abstract/MCMessageHeader.cpp new file mode 100644 index 00000000..bc141424 --- /dev/null +++ b/src/core/abstract/MCMessageHeader.cpp @@ -0,0 +1,1291 @@ +#include "MCWin32.h" // should be first include. + +#include "MCMessageHeader.h" + +#include "MCDefines.h" +#include "MCAddress.h" +#include "MCIterator.h" +#include "MCLibetpan.h" + +#include <string.h> +#ifndef _MSC_VER +#include <unistd.h> +#endif +#include <libetpan/libetpan.h> + +using namespace mailcore; + +static struct mailimf_address_list * lep_address_list_from_array(Array * addresses); +static struct mailimf_mailbox_list * lep_mailbox_list_from_array(Array * addresses); +static Array * lep_address_list_from_lep_addr(struct mailimf_address_list * addr_list); +static Array * lep_address_list_from_lep_mailbox(struct mailimf_mailbox_list * mb_list); + +static Array * msg_id_to_string_array(clist * msgids); +static clist * msg_id_from_string_array(Array * msgids); + +#define MAX_HOSTNAME 512 + +MessageHeader::MessageHeader() +{ + init(true, true); +} + +MessageHeader::MessageHeader(MessageHeader * other) +{ + init(false, other->mMessageID == NULL); + if (other->mMessageID != NULL) { + setMessageID(other->mMessageID); + mMessageIDAutoGenerated = other->isMessageIDAutoGenerated(); + } + setReferences(other->mReferences); + setInReplyTo(other->mInReplyTo); + setSender(other->mSender); + setFrom(other->mFrom); + setTo(other->mTo); + setCc(other->mCc); + setBcc(other->mBcc); + setReplyTo(other->mReplyTo); + setSubject(other->mSubject); + setDate(other->date()); + setReceivedDate(other->receivedDate()); + setExtraHeaders(other->mExtraHeaders); +} + +void MessageHeader::init(bool generateDate, bool generateMessageID) +{ + mMessageID = NULL; + mMessageIDAutoGenerated = false; + mReferences = NULL; + mInReplyTo = NULL; + mSender = NULL; + mFrom = NULL; + mTo = NULL; + mCc = NULL; + mBcc = NULL; + mReplyTo = NULL; + mSubject = NULL; + mDate = (time_t) -1; + mReceivedDate = (time_t) -1; + mExtraHeaders = NULL; + + if (generateDate) { + time_t date; + date = time(NULL); + setDate(date); + setReceivedDate(date); + } + if (generateMessageID) { + static String * hostname = NULL; + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + pthread_mutex_lock(&lock); + if (hostname == NULL) { + char name[MAX_HOSTNAME]; + int r; + + r = gethostname(name, MAX_HOSTNAME); + if (r < 0) { + hostname = NULL; + } + else { + hostname = new String(name); + } + if (hostname == NULL) { + hostname = new String("localhost"); + } + } + pthread_mutex_unlock(&lock); + + String * messageID = new String(); + messageID->appendString(String::uuidString()); + messageID->appendUTF8Characters("@"); + messageID->appendString(hostname); + setMessageID(messageID); + messageID->release(); + + mMessageIDAutoGenerated = true; + } +} + +MessageHeader::~MessageHeader() +{ + MC_SAFE_RELEASE(mMessageID); + MC_SAFE_RELEASE(mReferences); + MC_SAFE_RELEASE(mInReplyTo); + MC_SAFE_RELEASE(mSender); + MC_SAFE_RELEASE(mFrom); + MC_SAFE_RELEASE(mTo); + MC_SAFE_RELEASE(mCc); + MC_SAFE_RELEASE(mBcc); + MC_SAFE_RELEASE(mReplyTo); + MC_SAFE_RELEASE(mSubject); + MC_SAFE_RELEASE(mExtraHeaders); +} + +String * MessageHeader::description() +{ + String * result = String::string(); + result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this); + if (mMessageID != NULL) { + result->appendUTF8Format("Message-ID: %s\n", mMessageID->UTF8Characters()); + } + if (mReferences != NULL) { + result->appendUTF8Format("References: %s\n", mReferences->description()->UTF8Characters()); + } + if (mInReplyTo != NULL) { + result->appendUTF8Format("In-Reply-To: %s\n", mInReplyTo->description()->UTF8Characters()); + } + if (mSender != NULL) { + result->appendUTF8Format("Sender: %s\n", mSender->description()->UTF8Characters()); + } + if (mFrom != NULL) { + result->appendUTF8Format("From: %s\n", mFrom->description()->UTF8Characters()); + } + if (mTo != NULL) { + result->appendUTF8Format("To: %s\n", mTo->description()->UTF8Characters()); + } + if (mCc != NULL) { + result->appendUTF8Format("Cc: %s\n", mCc->description()->UTF8Characters()); + } + if (mBcc != NULL) { + result->appendUTF8Format("Bcc: %s\n", mBcc->description()->UTF8Characters()); + } + if (mReplyTo != NULL) { + result->appendUTF8Format("Reply-To: %s\n", mReplyTo->description()->UTF8Characters()); + } + if (mSubject != NULL) { + result->appendUTF8Format("Subject: %s\n", mSubject->UTF8Characters()); + } + if (mExtraHeaders != NULL) { + mc_foreachhashmapKeyAndValue(String, header, String, value, mExtraHeaders) { + result->appendUTF8Format("%s: %s\n", header->UTF8Characters(), value->UTF8Characters()); + } + } + result->appendUTF8Format(">"); + + return result; +} + +Object * MessageHeader::copy() +{ + return new MessageHeader(this); +} + +void MessageHeader::setMessageID(String * messageID) +{ + MC_SAFE_REPLACE_COPY(String, mMessageID, messageID); + mMessageIDAutoGenerated = false; +} + +String * MessageHeader::messageID() +{ + return mMessageID; +} + +bool MessageHeader::isMessageIDAutoGenerated() +{ + return mMessageIDAutoGenerated; +} + +void MessageHeader::setReferences(Array * references) +{ + MC_SAFE_REPLACE_COPY(Array, mReferences, references); +} + +Array * MessageHeader::references() +{ + return mReferences; +} + +void MessageHeader::setInReplyTo(Array * inReplyTo) +{ + MC_SAFE_REPLACE_COPY(Array, mInReplyTo, inReplyTo); +} + +Array * MessageHeader::inReplyTo() +{ + return mInReplyTo; +} + +void MessageHeader::setDate(time_t date) +{ + mDate = date; +} + +time_t MessageHeader::date() +{ + return mDate; +} + +void MessageHeader::setReceivedDate(time_t date) +{ + mReceivedDate = date; +} + +time_t MessageHeader::receivedDate() +{ + return mReceivedDate; +} + +void MessageHeader::setSender(Address * sender) +{ + MC_SAFE_REPLACE_RETAIN(Address, mSender, sender); +} + +Address * MessageHeader::sender() +{ + return mSender; +} + +void MessageHeader::setFrom(Address * from) +{ + MC_SAFE_REPLACE_RETAIN(Address, mFrom, from); +} + +Address * MessageHeader::from() +{ + return mFrom; +} + +void MessageHeader::setTo(Array * to) +{ + MC_SAFE_REPLACE_COPY(Array, mTo, to); +} + +Array * MessageHeader::to() +{ + return mTo; +} + +void MessageHeader::setCc(Array * cc) +{ + MC_SAFE_REPLACE_COPY(Array, mCc, cc); +} + +Array * MessageHeader::cc() +{ + return mCc; +} + +void MessageHeader::setBcc(Array * bcc) +{ + MC_SAFE_REPLACE_COPY(Array, mBcc, bcc); +} + +Array * MessageHeader::bcc() +{ + return mBcc; +} + +void MessageHeader::setReplyTo(Array * replyTo) +{ + MC_SAFE_REPLACE_COPY(Array, mReplyTo, replyTo); +} + +Array * MessageHeader::replyTo() +{ + return mReplyTo; +} + +void MessageHeader::setSubject(String * subject) +{ + MC_SAFE_REPLACE_COPY(String, mSubject, subject); +} + +String * MessageHeader::subject() +{ + return mSubject; +} + +void MessageHeader::setUserAgent(String * userAgent) +{ + setExtraHeader(MCSTR("X-Mailer"), userAgent); +} + +String * MessageHeader::userAgent() +{ + return extraHeaderValueForName(MCSTR("X-Mailer")); +} + +void MessageHeader::setExtraHeaders(HashMap * headers) +{ + MC_SAFE_REPLACE_COPY(HashMap, mExtraHeaders, headers); +} + +Array * MessageHeader::allExtraHeadersNames() +{ + if (mExtraHeaders == NULL) + return Array::array(); + return mExtraHeaders->allKeys(); +} + +void MessageHeader::setExtraHeader(String * name, String * object) +{ + if (mExtraHeaders == NULL) { + mExtraHeaders = new HashMap(); + } + removeExtraHeader(name); + mExtraHeaders->setObjectForKey(name, object); +} + +void MessageHeader::removeExtraHeader(String * name) +{ + if (mExtraHeaders == NULL) + return; + mc_foreachhashmapKey(String, key, mExtraHeaders) { + if (key->isEqualCaseInsensitive(name)) { + mExtraHeaders->removeObjectForKey(key); + break; + } + } +} + +String * MessageHeader::extraHeaderValueForName(String * name) +{ + String * result = NULL; + mc_foreachhashmapKey(String, key, mExtraHeaders) { + if (key->isEqualCaseInsensitive(name)) { + result = (String *) mExtraHeaders->objectForKey(key); + } + } + return result; +} + +String * MessageHeader::extractedSubject() +{ + if (subject() == NULL) + return NULL; + return subject()->extractedSubject(); +} + +String * MessageHeader::partialExtractedSubject() +{ + if (subject() == NULL) + return NULL; + return subject()->extractedSubjectAndKeepBracket(true); +} + +void MessageHeader::importHeadersData(Data * data) +{ + size_t cur_token; + struct mailimf_fields * fields; + int r; + + cur_token = 0; + r = mailimf_envelope_and_optional_fields_parse(data->bytes(), data->length(), &cur_token, &fields); + if (r != MAILIMF_NO_ERROR) { + return; + } + + importIMFFields(fields); + + mailimf_fields_free(fields); +} + +void MessageHeader::importIMFFields(struct mailimf_fields * fields) +{ + struct mailimf_single_fields single_fields; + + mailimf_single_fields_init(&single_fields, fields); + + /* date */ + + if (single_fields.fld_orig_date != NULL) { + time_t timestamp; + timestamp = timestampFromDate(single_fields.fld_orig_date->dt_date_time); + setDate(timestamp); + setReceivedDate(timestamp); + //MCLog("%lu %lu", (unsigned long) timestamp, date()); + } + + /* subject */ + if (single_fields.fld_subject != NULL) { + char * subject; + + subject = single_fields.fld_subject->sbj_value; + setSubject(String::stringByDecodingMIMEHeaderValue(subject)); + } + + /* sender */ + if (single_fields.fld_sender != NULL) { + struct mailimf_mailbox * mb; + Address * address; + + mb = single_fields.fld_sender->snd_mb; + if (mb != NULL) { + address = Address::addressWithIMFMailbox(mb); + setSender(address); + } + } + + /* from */ + if (single_fields.fld_from != NULL) { + struct mailimf_mailbox_list * mb_list; + Array * addresses; + + mb_list = single_fields.fld_from->frm_mb_list; + addresses = lep_address_list_from_lep_mailbox(mb_list); + if (addresses->count() > 0) { + setFrom((Address *) (addresses->objectAtIndex(0))); + } + } + + /* replyto */ + if (single_fields.fld_reply_to != NULL) { + struct mailimf_address_list * addr_list; + Array * addresses; + + addr_list = single_fields.fld_reply_to->rt_addr_list; + addresses = lep_address_list_from_lep_addr(addr_list); + setReplyTo(addresses); + } + + /* to */ + if (single_fields.fld_to != NULL) { + struct mailimf_address_list * addr_list; + Array * addresses; + + addr_list = single_fields.fld_to->to_addr_list; + addresses = lep_address_list_from_lep_addr(addr_list); + setTo(addresses); + } + + /* cc */ + if (single_fields.fld_cc != NULL) { + struct mailimf_address_list * addr_list; + Array * addresses; + + addr_list = single_fields.fld_cc->cc_addr_list; + addresses = lep_address_list_from_lep_addr(addr_list); + setCc(addresses); + } + + /* bcc */ + if (single_fields.fld_bcc != NULL) { + struct mailimf_address_list * addr_list; + Array * addresses; + + addr_list = single_fields.fld_bcc->bcc_addr_list; + addresses = lep_address_list_from_lep_addr(addr_list); + setBcc(addresses); + } + + /* msgid */ + if (single_fields.fld_message_id != NULL) { + char * msgid; + String * str; + + msgid = single_fields.fld_message_id->mid_value; + str = String::stringWithUTF8Characters(msgid); + setMessageID(str); + } + + /* references */ + if (single_fields.fld_references != NULL) { + clist * msg_id_list; + Array * msgids; + + msg_id_list = single_fields.fld_references->mid_list; + msgids = msg_id_to_string_array(msg_id_list); + setReferences(msgids); + } + + /* inreplyto */ + if (single_fields.fld_in_reply_to != NULL) { + clist * msg_id_list; + Array * msgids; + + msg_id_list = single_fields.fld_in_reply_to->mid_list; + msgids = msg_id_to_string_array(msg_id_list); + setInReplyTo(msgids); + } + + // Take care of other headers. + for(clistiter * cur = clist_begin(fields->fld_list) ; cur != NULL ; cur = clist_next(cur)) { + struct mailimf_field * field; + + field = (mailimf_field *)clist_content(cur); + + if (field->fld_type != MAILIMF_FIELD_OPTIONAL_FIELD) { + continue; + } + + char * fieldName; + String * fieldNameStr; + + fieldName = field->fld_data.fld_optional_field->fld_name; + fieldNameStr = String::stringWithUTF8Characters(fieldName); + // Set only if this optional-field is not set + if (extraHeaderValueForName(fieldNameStr) == NULL) { + char * fieldValue; + String * fieldValueStr; + + fieldValue = field->fld_data.fld_optional_field->fld_value; + fieldValueStr = String::stringByDecodingMIMEHeaderValue(fieldValue); + setExtraHeader(fieldNameStr, fieldValueStr); + } + } +} + +#pragma mark RFC 2822 mailbox conversion + +static Array * lep_address_list_from_lep_mailbox(struct mailimf_mailbox_list * mb_list) +{ + Array * result; + clistiter * cur; + + result = Array::array(); + for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ; cur = clist_next(cur)) { + struct mailimf_mailbox * mb; + Address * address; + + mb = (struct mailimf_mailbox *) clist_content(cur); + address = Address::addressWithIMFMailbox(mb); + result->addObject(address); + } + + return result; +} + +static Array * lep_address_list_from_lep_addr(struct mailimf_address_list * addr_list) +{ + Array * result; + clistiter * cur; + + result = Array::array(); + + if (addr_list == NULL) { + return result; + } + + if (addr_list->ad_list == NULL) { + return result; + } + + for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ; + cur = clist_next(cur)) { + struct mailimf_address * addr; + + addr = (struct mailimf_address *) clist_content(cur); + switch (addr->ad_type) { + case MAILIMF_ADDRESS_MAILBOX: + { + Address * address; + + address = Address::addressWithIMFMailbox(addr->ad_data.ad_mailbox); + result->addObject(address); + break; + } + + case MAILIMF_ADDRESS_GROUP: + { + if (addr->ad_data.ad_group->grp_mb_list != NULL) { + Array * subArray; + + subArray = lep_address_list_from_lep_mailbox(addr->ad_data.ad_group->grp_mb_list); + result->addObjectsFromArray(subArray); + } + break; + } + } + } + + return result; +} + +static struct mailimf_mailbox_list * lep_mailbox_list_from_array(Array * addresses) +{ + struct mailimf_mailbox_list * mb_list; + + if (addresses == NULL) + return NULL; + + if (addresses->count() == 0) + return NULL; + + mb_list = mailimf_mailbox_list_new_empty(); + + for(unsigned i = 0 ; i < addresses->count() ; i ++) { + Address * address = (Address *) addresses->objectAtIndex(i); + struct mailimf_mailbox * mailbox = address->createIMFMailbox(); + mailimf_mailbox_list_add(mb_list, mailbox); + } + + return mb_list; +} + +static struct mailimf_address_list * lep_address_list_from_array(Array * addresses) +{ + struct mailimf_address_list * addr_list; + + if (addresses == NULL) + return NULL; + + if (addresses->count() == 0) + return NULL; + + addr_list = mailimf_address_list_new_empty(); + + for(unsigned i = 0 ; i < addresses->count() ; i ++) { + Address * address = (Address *) addresses->objectAtIndex(i); + struct mailimf_address * addr = address->createIMFAddress(); + mailimf_address_list_add(addr_list, addr); + } + + return addr_list; +} + +#pragma mark Message-ID conversion + +static Array * msg_id_to_string_array(clist * msgids) +{ + clistiter * cur; + Array * result; + + result = Array::array(); + + for(cur = clist_begin(msgids) ; cur != NULL ; cur = clist_next(cur)) { + char * msgid; + String * str; + + msgid = (char *) clist_content(cur); + str = String::stringWithUTF8Characters(msgid); + result->addObject(str); + } + + return result; +} + +static clist * msg_id_from_string_array(Array * msgids) +{ + clist * result; + + if (msgids == NULL) + return NULL; + + if (msgids->count() == 0) + return NULL; + + result = clist_new(); + for(unsigned int i = 0 ; i < msgids->count() ; i ++) { + String * msgid = (String *) msgids->objectAtIndex(i); + clist_append(result, strdup(msgid->UTF8Characters())); + } + + return result; +} + +struct mailimf_fields * MessageHeader::createIMFFieldsAndFilterBcc(bool filterBcc) +{ + struct mailimf_date_time * imfDate; + char * imfMsgid; + char * imfSubject; + struct mailimf_mailbox_list * imfFrom; + struct mailimf_address_list * imfReplyTo; + struct mailimf_address_list * imfTo; + struct mailimf_address_list * imfCc; + struct mailimf_address_list * imfBcc; + clist * imfInReplyTo; + clist * imfReferences; + struct mailimf_fields * fields; + + imfDate = NULL; + if (date() != (time_t) -1) { + //MCLog("%lu", date()); + imfDate = dateFromTimestamp(date()); + } + imfFrom = NULL; + if (from() != NULL) { + imfFrom = lep_mailbox_list_from_array(Array::arrayWithObject(from())); + } + imfReplyTo = lep_address_list_from_array(replyTo()); + imfTo = lep_address_list_from_array(to()); + imfCc = lep_address_list_from_array(cc()); + imfBcc = NULL; + if (!filterBcc) { + imfBcc = lep_address_list_from_array(bcc()); + } + imfMsgid = NULL; + if (messageID() != NULL) { + imfMsgid = strdup(messageID()->UTF8Characters()); + } + imfInReplyTo = msg_id_from_string_array(inReplyTo()); + imfReferences = msg_id_from_string_array(references()); + imfSubject = NULL; + if ((subject() != NULL) && (subject()->length() > 0)) { + Data * data; + + data = subject()->encodedMIMEHeaderValueForSubject(); + if (data->bytes() != NULL) { + imfSubject = strdup(data->bytes()); + } + } + + if ((imfTo == NULL) && (imfCc == NULL) && (imfBcc == NULL)) { + imfTo = mailimf_address_list_new_empty(); + mailimf_address_list_add_parse(imfTo, (char *) "Undisclosed recipients:;"); + } + + fields = mailimf_fields_new_with_data_all(imfDate, + imfFrom, + NULL /* sender */, + imfReplyTo, + imfTo, + imfCc, + imfBcc, + imfMsgid, + imfInReplyTo, + imfReferences, + imfSubject); + + if (mExtraHeaders != NULL) { + mc_foreachhashmapKeyAndValue(String, header, String, value, mExtraHeaders) { + struct mailimf_field * field; + + field = mailimf_field_new_custom(strdup(header->UTF8Characters()), strdup(value->UTF8Characters())); + mailimf_fields_add(fields, field); + } + } + + return fields; +} + +extern "C" { + extern int mailimap_hack_date_time_parse(char * str, + struct mailimap_date_time ** result, + size_t progr_rate, + progress_function * progr_fun); +} + +#pragma mark IMAP mailbox conversion + +static Array * imap_mailbox_list_to_address_array(clist * imap_mailbox_list) +{ + clistiter * cur; + Array * result; + + result = Array::array(); + + for(cur = clist_begin(imap_mailbox_list) ; cur != NULL ; + cur = clist_next(cur)) { + struct mailimap_address * imap_addr; + Address * address; + + imap_addr = (struct mailimap_address *) clist_content(cur); + address = Address::addressWithIMAPAddress(imap_addr); + result->addObject(address); + } + + return result; +} + +void MessageHeader::importIMAPEnvelope(struct mailimap_envelope * env) +{ + if (env->env_date != NULL) { + size_t cur_token; + struct mailimf_date_time * date_time; + int r; + + cur_token = 0; + r = mailimf_date_time_parse(env->env_date, strlen(env->env_date), + &cur_token, &date_time); + if (r == MAILIMF_NO_ERROR) { + time_t timestamp; + + // date + timestamp = timestampFromDate(date_time); + setDate(timestamp); + setReceivedDate(timestamp); + mailimf_date_time_free(date_time); + } + else { + struct mailimap_date_time * imap_date; + + r = mailimap_hack_date_time_parse(env->env_date, &imap_date, 0, NULL); + if (r == MAILIMAP_NO_ERROR) { + time_t timestamp; + + timestamp = timestampFromIMAPDate(imap_date); + setDate(timestamp); + setReceivedDate(timestamp); + mailimap_date_time_free(imap_date); + } + } + } + + if (env->env_subject != NULL) { + char * subject; + + // subject + subject = env->env_subject; + setSubject(String::stringByDecodingMIMEHeaderValue(subject)); + } + + if (env->env_sender != NULL) { + if (env->env_sender->snd_list != NULL) { + Array * addresses; + + addresses = imap_mailbox_list_to_address_array(env->env_sender->snd_list); + if (addresses->count() > 0) { + setSender((Address *) addresses->objectAtIndex(0)); + } + } + } + + if (env->env_from != NULL) { + if (env->env_from->frm_list != NULL) { + Array * addresses; + + addresses = imap_mailbox_list_to_address_array(env->env_from->frm_list); + if (addresses->count() > 0) { + setFrom((Address *) addresses->objectAtIndex(0)); + } + } + } + + // skip Sender header + + if (env->env_reply_to != NULL) { + if (env->env_reply_to->rt_list != NULL) { + Array * addresses; + + addresses = imap_mailbox_list_to_address_array(env->env_reply_to->rt_list); + setReplyTo(addresses); + } + } + + if (env->env_to != NULL) { + if (env->env_to->to_list != NULL) { + Array * addresses; + + addresses = imap_mailbox_list_to_address_array(env->env_to->to_list); + setTo(addresses); + } + } + + if (env->env_cc != NULL) { + if (env->env_cc->cc_list != NULL) { + Array * addresses; + + addresses = imap_mailbox_list_to_address_array(env->env_cc->cc_list); + setCc(addresses); + } + } + + if (env->env_bcc != NULL) { + if (env->env_bcc->bcc_list != NULL) { + Array * addresses; + + addresses = imap_mailbox_list_to_address_array(env->env_bcc->bcc_list); + setBcc(addresses); + } + } + + if (env->env_in_reply_to != NULL) { + size_t cur_token; + clist * msg_id_list; + int r; + + cur_token = 0; + r = mailimf_msg_id_list_parse(env->env_in_reply_to, + strlen(env->env_in_reply_to), &cur_token, &msg_id_list); + if (r == MAILIMF_NO_ERROR) { + Array * msgids; + + msgids = msg_id_to_string_array(msg_id_list); + setInReplyTo(msgids); + // in-reply-to + clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL); + clist_free(msg_id_list); + } + } + + if (env->env_message_id != NULL) { + char * msgid; + size_t cur_token; + int r; + + cur_token = 0; + r = mailimf_msg_id_parse(env->env_message_id, strlen(env->env_message_id), + &cur_token, &msgid); + if (r == MAILIMF_NO_ERROR) { + // msg id + String * str; + + str = String::stringWithUTF8Characters(msgid); + setMessageID(str); + mailimf_msg_id_free(msgid); + } + } +} + +void MessageHeader::importIMAPReferences(Data * data) +{ + size_t cur_token; + struct mailimf_fields * fields; + int r; + struct mailimf_single_fields single_fields; + + cur_token = 0; + r = mailimf_fields_parse(data->bytes(), data->length(), &cur_token, &fields); + if (r != MAILIMF_NO_ERROR) { + return; + } + + mailimf_single_fields_init(&single_fields, fields); + if (single_fields.fld_references != NULL) { + Array * msgids; + + msgids = msg_id_to_string_array(single_fields.fld_references->mid_list); + setReferences(msgids); + } + if (single_fields.fld_subject != NULL) { + if (single_fields.fld_subject->sbj_value != NULL) { + bool broken; + char * value; + bool isASCII; + + broken = false; + value = single_fields.fld_subject->sbj_value; + + isASCII = true; + for(char * p = value ; * p != 0 ; p ++) { + if ((unsigned char) * p >= 128) { + isASCII = false; + } + } + if (strstr(value, "windows-1251") == NULL) { + if (isASCII) { + broken = true; + } + } + + //MCLog("charset: %s %s", value, MCUTF8(charset)); + + if (!broken) { + setSubject(String::stringByDecodingMIMEHeaderValue(single_fields.fld_subject->sbj_value)); + } + } + } + + mailimf_fields_free(fields); +} + +void MessageHeader::importIMAPInternalDate(struct mailimap_date_time * date) +{ + setReceivedDate(timestampFromIMAPDate(date)); +} + +Array * MessageHeader::recipientWithReplyAll(bool replyAll, bool includeTo, bool includeCc, Array * senderEmails) +{ + bool hasCc; + bool hasTo; + Set * addedAddresses; + Array * toField; + Array * ccField; + bool containsSender; + + toField = NULL; + ccField = NULL; + + hasTo = false; + hasCc = false; + addedAddresses = new Set(); + + containsSender = false; + if (senderEmails != NULL) { + if (from() != NULL) { + if (senderEmails->containsObject(from()->mailbox()->lowercaseString())) { + containsSender = true; + } + } + if (sender() != NULL) { + if (senderEmails->containsObject(sender()->mailbox()->lowercaseString())) { + containsSender = true; + } + } + } + + if (containsSender) { + Array * recipient; + + recipient = new Array(); + if (to() != NULL) { + for(unsigned int i = 0 ; i < to()->count() ; i ++) { + Address * address = (Address *) to()->objectAtIndex(i); + if (addedAddresses->containsObject(address->mailbox()->lowercaseString())) { + continue; + } + if ((from() != NULL) && address->mailbox()->isEqualCaseInsensitive(from()->mailbox())) { + recipient->addObjectsFromArray(replyTo()); + for(unsigned int j = 0 ; j < replyTo()->count() ; j ++) { + Address * rtAddress = (Address *) replyTo()->objectAtIndex(j); + if (addedAddresses->containsObject(rtAddress->mailbox()->lowercaseString())) { + continue; + } + addedAddresses->addObject(rtAddress->mailbox()->lowercaseString()); + } + } + else { + if (address->mailbox() != NULL) { + recipient->addObject(address); + addedAddresses->addObject(address->mailbox()->lowercaseString()); + } + } + hasTo = true; + } + } + toField = recipient; + toField->retain()->autorelease(); + recipient->release(); + + if (replyAll) { + recipient = new Array(); + if (cc() != NULL) { + for(unsigned int i = 0 ; i < cc()->count() ; i ++) { + Address * address = (Address *) cc()->objectAtIndex(i); + if (addedAddresses->containsObject(address->mailbox()->lowercaseString())) { + continue; + } + if (address->mailbox() == NULL) + continue; + recipient->addObject(address); + addedAddresses->addObject(address->mailbox()->lowercaseString()); + hasCc = true; + } + } + ccField = recipient; + ccField->retain()->autorelease(); + recipient->release(); + } + + if (!hasTo && !hasCc) { + hasTo = true; + toField = Array::arrayWithObject(from()); + } + } + else { + addedAddresses->addObjectsFromArray(senderEmails); + + if (replyTo() != NULL && replyTo()->count() > 0) { + hasTo = true; + toField = replyTo(); + for(unsigned int i = 0 ; i < replyTo()->count() ; i ++) { + Address * address = (Address *) replyTo()->objectAtIndex(i); + if (address->mailbox() == NULL) + continue; + addedAddresses->addObject(address->mailbox()->lowercaseString()); + } + } + else { + if (from() != NULL && from()->mailbox() != NULL) { + hasTo = true; + toField = Array::arrayWithObject(from()); + addedAddresses->addObject(from()->mailbox()->lowercaseString()); + } + } + + if (replyAll) { + Array * recipient; + + recipient = new Array(); + if (to() != NULL) { + for(unsigned int i = 0 ; i < to()->count() ; i ++) { + Address * address = (Address *) to()->objectAtIndex(i); + if (addedAddresses->containsObject(address->mailbox()->lowercaseString())) { + continue; + } + if (address->mailbox() == NULL) + continue; + recipient->addObject(address); + addedAddresses->addObject(address->mailbox()->lowercaseString()); + } + } + if (cc() != NULL) { + for(unsigned int i = 0 ; i < cc()->count() ; i ++) { + Address * address = (Address *) cc()->objectAtIndex(i); + if (addedAddresses->containsObject(address->mailbox()->lowercaseString())) { + continue; + } + if (address->mailbox() == NULL) + continue; + recipient->addObject(address); + addedAddresses->addObject(address->mailbox()->lowercaseString()); + } + } + if (recipient->count() > 0) { + hasCc = true; + } + ccField = recipient; + ccField->retain()->autorelease(); + recipient->release(); + } + } + + addedAddresses->release(); + + Array * result; + result = Array::array(); + if (hasTo && includeTo) + result->addObjectsFromArray(toField); + if (hasCc && includeCc) + result->addObjectsFromArray(ccField); + + return result; +} + +MessageHeader * MessageHeader::replyHeader(bool replyAll, Array * addressesExcludedFromRecipient) +{ + MessageHeader * result; + String * subjectValue; + Array * referencesValue; + Array * inReplyTo; + Array * toValue; + Array * ccValue; + + referencesValue = NULL; + inReplyTo = NULL; + + result = new MessageHeader(); + if (subject() == NULL) { + subjectValue = MCSTR("Re: "); + } + else { + subjectValue = MCSTR("Re: ")->stringByAppendingString(subject()); + } + if (references() != NULL) { + referencesValue = (Array *) (references()->copy()); + referencesValue->autorelease(); + if (messageID() != NULL ) { + referencesValue->addObject(messageID()); + } + } + if (messageID()) { + inReplyTo = Array::array(); + inReplyTo->addObject(messageID()); + } + toValue = recipientWithReplyAll(replyAll, true, false, addressesExcludedFromRecipient); + ccValue = recipientWithReplyAll(replyAll, false, true, addressesExcludedFromRecipient);; + + result->setSubject(subjectValue); + result->setReferences(referencesValue); + result->setInReplyTo(inReplyTo); + result->setTo(toValue); + result->setCc(ccValue); + + result->autorelease(); + return result; +} + +MessageHeader * MessageHeader::forwardHeader() +{ + MessageHeader * result; + String * subjectValue; + Array * referencesValue; + Array * inReplyTo; + + referencesValue = NULL; + inReplyTo = NULL; + + result = new MessageHeader(); + if (subject() == NULL) { + subjectValue = MCSTR("Fw: "); + } + else { + subjectValue = MCSTR("Fw: ")->stringByAppendingString(subject()); + } + if (references() != NULL) { + referencesValue = (Array *) (references()->copy()); + referencesValue->autorelease(); + if (messageID() != NULL ) { + referencesValue->addObject(messageID()); + } + } + if (messageID() != NULL) { + inReplyTo = Array::array(); + inReplyTo->addObject(messageID()); + } + result->setSubject(subjectValue); + result->setReferences(referencesValue); + result->setInReplyTo(inReplyTo); + + result->autorelease(); + return result; +} + +HashMap * MessageHeader::serializable() +{ + HashMap * result = Object::serializable(); + + if (messageID() != NULL) { + result->setObjectForKey(MCSTR("messageID"), messageID()); + } + if (mMessageIDAutoGenerated) { + result->setObjectForKey(MCSTR("messageIDAutoGenerated"), Value::valueWithBoolValue(true)); + } + if (references() != NULL) { + result->setObjectForKey(MCSTR("references"), references()); + } + if (inReplyTo() != NULL) { + result->setObjectForKey(MCSTR("inReplyTo"), inReplyTo()); + } + if (sender() != NULL) { + result->setObjectForKey(MCSTR("sender"), sender()->serializable()); + } + if (from() != NULL) { + result->setObjectForKey(MCSTR("from"), from()->serializable()); + } + if (to() != NULL) { + result->setObjectForKey(MCSTR("to"), to()->serializable()); + } + if (cc() != NULL) { + result->setObjectForKey(MCSTR("cc"), cc()->serializable()); + } + if (bcc() != NULL) { + result->setObjectForKey(MCSTR("bcc"), bcc()->serializable()); + } + if (replyTo() != NULL) { + result->setObjectForKey(MCSTR("replyTo"), replyTo()->serializable()); + } + if (subject() != NULL) { + result->setObjectForKey(MCSTR("subject"), subject()); + } + result->setObjectForKey(MCSTR("date"), String::stringWithUTF8Format("%lld", (unsigned long long) date())); + result->setObjectForKey(MCSTR("receivedDate"), String::stringWithUTF8Format("%lld", (unsigned long long) receivedDate())); + if (mExtraHeaders != NULL) { + result->setObjectForKey(MCSTR("extraHeaders"), mExtraHeaders); + } + + return result; +} + +void MessageHeader::importSerializable(HashMap * hashmap) +{ + setMessageID((String *) hashmap->objectForKey(MCSTR("messageID"))); + + Value * value = (Value *)hashmap->objectForKey(MCSTR("messageIDAutoGenerated")); + mMessageIDAutoGenerated = value != NULL && value->boolValue(); + + setReferences((Array *) hashmap->objectForKey(MCSTR("references"))); + setInReplyTo((Array *) hashmap->objectForKey(MCSTR("inReplyTo"))); + setSender((Address *) Object::objectWithSerializable((HashMap *) hashmap->objectForKey(MCSTR("sender")))); + setFrom((Address *) Object::objectWithSerializable((HashMap *) hashmap->objectForKey(MCSTR("from")))); + setTo((Array *) Object::objectWithSerializable((HashMap *) hashmap->objectForKey(MCSTR("to")))); + setCc((Array *)Object::objectWithSerializable((HashMap *) hashmap->objectForKey(MCSTR("cc")))); + setBcc((Array *)Object::objectWithSerializable((HashMap *) hashmap->objectForKey(MCSTR("bcc")))); + setReplyTo((Array *)Object::objectWithSerializable((HashMap *) hashmap->objectForKey(MCSTR("replyTo")))); + setSubject((String *) hashmap->objectForKey(MCSTR("subject"))); + setDate((time_t) ((String *) hashmap->objectForKey(MCSTR("date")))->unsignedLongLongValue()); + setReceivedDate((time_t) ((String *) hashmap->objectForKey(MCSTR("receivedDate")))->unsignedLongLongValue()); + setExtraHeaders((HashMap *) hashmap->objectForKey(MCSTR("extraHeaders"))); +} + +static void * createObject() +{ + return new MessageHeader(); +} + +INITIALIZE(MessageHeader) +{ + Object::registerObjectConstructor("mailcore::MessageHeader", &createObject); +} |