diff options
Diffstat (limited to 'src/core/abstract')
-rw-r--r-- | src/core/abstract/.DS_Store | bin | 0 -> 6148 bytes | |||
-rw-r--r-- | src/core/abstract/MCAbstract.h | 13 | ||||
-rw-r--r-- | src/core/abstract/MCAbstractMessage.cc | 65 | ||||
-rw-r--r-- | src/core/abstract/MCAbstractMessage.h | 29 | ||||
-rw-r--r-- | src/core/abstract/MCAbstractMessagePart.cc | 88 | ||||
-rw-r--r-- | src/core/abstract/MCAbstractMessagePart.h | 39 | ||||
-rw-r--r-- | src/core/abstract/MCAbstractMultipart.cc | 95 | ||||
-rw-r--r-- | src/core/abstract/MCAbstractMultipart.h | 32 | ||||
-rw-r--r-- | src/core/abstract/MCAbstractPart.cc | 223 | ||||
-rw-r--r-- | src/core/abstract/MCAbstractPart.h | 63 | ||||
-rw-r--r-- | src/core/abstract/MCAddress.cc | 364 | ||||
-rw-r--r-- | src/core/abstract/MCAddress.h | 55 | ||||
-rw-r--r-- | src/core/abstract/MCMessageConstants.h | 208 | ||||
-rw-r--r-- | src/core/abstract/MCMessageHeader.cc | 1054 | ||||
-rw-r--r-- | src/core/abstract/MCMessageHeader.h | 90 |
15 files changed, 2418 insertions, 0 deletions
diff --git a/src/core/abstract/.DS_Store b/src/core/abstract/.DS_Store Binary files differnew file mode 100644 index 00000000..5008ddfc --- /dev/null +++ b/src/core/abstract/.DS_Store diff --git a/src/core/abstract/MCAbstract.h b/src/core/abstract/MCAbstract.h new file mode 100644 index 00000000..fd36af46 --- /dev/null +++ b/src/core/abstract/MCAbstract.h @@ -0,0 +1,13 @@ +#ifndef __MAILCORE_MCABSTRACT_H + +#define __MAILCORE_MCABSTRACT_H + +#include <mailcore/MCAbstractMessage.h> +#include <mailcore/MCAbstractMessagePart.h> +#include <mailcore/MCAbstractMultipart.h> +#include <mailcore/MCAbstractPart.h> +#include <mailcore/MCAddress.h> +#include <mailcore/MCMessageConstants.h> +#include <mailcore/MCMessageHeader.h> + +#endif diff --git a/src/core/abstract/MCAbstractMessage.cc b/src/core/abstract/MCAbstractMessage.cc new file mode 100644 index 00000000..00a4b9b9 --- /dev/null +++ b/src/core/abstract/MCAbstractMessage.cc @@ -0,0 +1,65 @@ +#include "MCAbstractMessage.h" + +#include "MCMessageHeader.h" + +using namespace mailcore; + +AbstractMessage::AbstractMessage() +{ + init(); +} + +AbstractMessage::AbstractMessage(AbstractMessage * other) +{ + init(); + mHeader = (MessageHeader *) MC_SAFE_COPY(other->mHeader); +} + +void AbstractMessage::init() +{ + mHeader = NULL; +} + +AbstractMessage::~AbstractMessage() +{ + MC_SAFE_RELEASE(mHeader); +} + +String * AbstractMessage::description() +{ + if (mHeader != NULL) { + String * result = String::string(); + result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this); + result->appendString(mHeader->description()); + result->appendUTF8Characters(">"); + return result; + } + else { + return Object::description(); + } +} + +#if 0 +String * AbstractMessage::className() +{ + return MCSTR("MessageHeader"); +} +#endif + +Object * AbstractMessage::copy() +{ + return new AbstractMessage(this); +} + +MessageHeader * AbstractMessage::header() +{ + if (mHeader == NULL) { + mHeader = new MessageHeader(); + } + return mHeader; +} + +void AbstractMessage::setHeader(MessageHeader * header) +{ + MC_SAFE_REPLACE_RETAIN(MessageHeader, mHeader, header); +} diff --git a/src/core/abstract/MCAbstractMessage.h b/src/core/abstract/MCAbstractMessage.h new file mode 100644 index 00000000..e5b62c8a --- /dev/null +++ b/src/core/abstract/MCAbstractMessage.h @@ -0,0 +1,29 @@ +#ifndef __MAILCORE_MCABSTRACTMESSAGE_H_ +#define __MAILCORE_MCABSTRACTMESSAGE_H_ + +#include <mailcore/MCBaseTypes.h> + +namespace mailcore { + + class MessageHeader; + + class AbstractMessage : public Object { + private: + MessageHeader * mHeader; + void init(); + + public: + AbstractMessage(); + AbstractMessage(AbstractMessage * other); + virtual ~AbstractMessage(); + + virtual String * description(); + //virtual String * className(); + virtual Object * copy(); + + virtual MessageHeader * header(); + virtual void setHeader(MessageHeader * header); + }; +} + +#endif diff --git a/src/core/abstract/MCAbstractMessagePart.cc b/src/core/abstract/MCAbstractMessagePart.cc new file mode 100644 index 00000000..6939d060 --- /dev/null +++ b/src/core/abstract/MCAbstractMessagePart.cc @@ -0,0 +1,88 @@ +#include "MCAbstractMessagePart.h" + +#include "MCMessageHeader.h" + +using namespace mailcore; + +void AbstractMessagePart::init() +{ + mMainPart = NULL; + mHeader = NULL; +} + +AbstractMessagePart::AbstractMessagePart() +{ +} + +AbstractMessagePart::AbstractMessagePart(AbstractMessagePart * other) +{ + if (other->mainPart() != NULL) { + setMainPart((AbstractPart *) other->mainPart()->copy()->autorelease()); + } + if (other->mHeader != NULL) { + setHeader((MessageHeader *) other->header()->copy()->autorelease()); + } +} + +AbstractMessagePart::~AbstractMessagePart() +{ + MC_SAFE_RELEASE(mMainPart); + MC_SAFE_RELEASE(mHeader); +} + +String * AbstractMessagePart::description() +{ + String * result = String::string(); + result->appendUTF8Format("<%s:%p %s>", className(), this, mMainPart->description()); + return result; +} + +#if 0 +String * AbstractMessagePart::className() +{ + return MCSTR("AbstractMessagePart"); +} +#endif + +Object * AbstractMessagePart::copy() +{ + return new AbstractMessagePart(this); +} + +MessageHeader * AbstractMessagePart::header() +{ + if (mHeader == NULL) { + mHeader = new MessageHeader(); + } + return mHeader; +} + +void AbstractMessagePart::setHeader(MessageHeader * header) +{ + MC_SAFE_REPLACE_RETAIN(MessageHeader, mHeader, header); +} + +AbstractPart * AbstractMessagePart::mainPart() +{ + return mMainPart; +} + +void AbstractMessagePart::setMainPart(AbstractPart * mainPart) +{ + MC_SAFE_REPLACE_RETAIN(AbstractPart, mMainPart, mainPart); + applyMessage(); +} + +void AbstractMessagePart::applyMessage() +{ + if (mMainPart == NULL) + return; + + mMainPart->setMessage(message()); +} + +void AbstractMessagePart::setMessage(AbstractMessage * message) +{ + AbstractPart::setMessage(message); + applyMessage(); +} diff --git a/src/core/abstract/MCAbstractMessagePart.h b/src/core/abstract/MCAbstractMessagePart.h new file mode 100644 index 00000000..a855202c --- /dev/null +++ b/src/core/abstract/MCAbstractMessagePart.h @@ -0,0 +1,39 @@ +#ifndef __MAILCORE_MCABSTRACTMESSAGEPART_H_ + +#define __MAILCORE_MCABSTRACTMESSAGEPART_H_ + +#include <mailcore/MCBaseTypes.h> +#include <mailcore/MCAbstractPart.h> + +namespace mailcore { + + class MessageHeader; + + class AbstractMessagePart : public AbstractPart { + private: + AbstractPart * mMainPart; + MessageHeader * mHeader; + void init(); + void applyMessage(); + + public: + AbstractMessagePart(); + AbstractMessagePart(AbstractMessagePart * other); + virtual ~AbstractMessagePart(); + + virtual String * description(); + //virtual String * className(); + virtual Object * copy(); + + virtual MessageHeader * header(); + virtual void setHeader(MessageHeader * header); + + virtual AbstractPart * mainPart(); + virtual void setMainPart(AbstractPart * mainPart); + + virtual void setMessage(AbstractMessage * message); + }; +} + + +#endif diff --git a/src/core/abstract/MCAbstractMultipart.cc b/src/core/abstract/MCAbstractMultipart.cc new file mode 100644 index 00000000..fa48d959 --- /dev/null +++ b/src/core/abstract/MCAbstractMultipart.cc @@ -0,0 +1,95 @@ +#include "MCAbstractMultipart.h" + +using namespace mailcore; + +AbstractMultipart::AbstractMultipart() +{ + init(); +} + +AbstractMultipart::AbstractMultipart(AbstractMultipart * other) : AbstractPart(other) +{ + init(); + + setPartType(other->partType()); + Array * parts = Array::array(); + for(unsigned int i = 0 ; i < other->parts()->count() ; i ++) { + AbstractPart * part = (AbstractPart *) other->parts()->objectAtIndex(i); + parts->addObject(part->copy()->autorelease()); + } + setParts(parts); +} + +void AbstractMultipart::init() +{ + mParts = NULL; + setPartType(PartTypeMultipartMixed); +} + +AbstractMultipart::~AbstractMultipart() +{ + MC_SAFE_RELEASE(mParts); +} + +Array * AbstractMultipart::parts() +{ + return mParts; +} + +void AbstractMultipart::setParts(Array * parts) +{ + MC_SAFE_REPLACE_COPY(Array, mParts, parts); + applyMessage(); +} + +String * AbstractMultipart::description() +{ + String * result = String::string(); + + const char * partTypeName = NULL; + switch (partType()) { + default: + case PartTypeMultipartMixed: + partTypeName = "mixed"; + break; + case PartTypeMultipartRelated: + partTypeName = "related"; + break; + case PartTypeMultipartAlternative: + partTypeName = "alernative"; + break; + } + + result->appendUTF8Format("<%s:%p %s %s>", + MCUTF8(className()), this, partTypeName, MCUTF8(mParts->description())); + return result; +} + +#if 0 +String * AbstractMultipart::className() +{ + return MCSTR("AbstractMultipart"); +} +#endif + +Object * AbstractMultipart::copy() +{ + return new AbstractMultipart(this); +} + +void AbstractMultipart::applyMessage() +{ + if (mParts == NULL) + return; + + for(unsigned int i = 0 ; i < mParts->count() ; i ++) { + AbstractPart * part = (AbstractPart *) mParts->objectAtIndex(i); + part->setMessage(message()); + } +} + +void AbstractMultipart::setMessage(AbstractMessage * message) +{ + AbstractPart::setMessage(message); + applyMessage(); +} diff --git a/src/core/abstract/MCAbstractMultipart.h b/src/core/abstract/MCAbstractMultipart.h new file mode 100644 index 00000000..c731ed7b --- /dev/null +++ b/src/core/abstract/MCAbstractMultipart.h @@ -0,0 +1,32 @@ +#ifndef __MAILCORE_MCABSTRACTMULTIPART_H + +#define __MAILCORE_MCABSTRACTMULTIPART_H + +#include <mailcore/MCBaseTypes.h> +#include <mailcore/MCAbstractPart.h> + +namespace mailcore { + + class AbstractMultipart : public AbstractPart { + private: + Array * mParts; + void init(); + void applyMessage(); + + public: + AbstractMultipart(); + AbstractMultipart(AbstractMultipart * other); + virtual ~AbstractMultipart(); + + virtual String * description(); + //virtual String * className(); + virtual Object * copy(); + + virtual Array * parts(); + virtual void setParts(Array * parts); + + virtual void setMessage(AbstractMessage * message); + }; +} + +#endif diff --git a/src/core/abstract/MCAbstractPart.cc b/src/core/abstract/MCAbstractPart.cc new file mode 100644 index 00000000..30c4c8f0 --- /dev/null +++ b/src/core/abstract/MCAbstractPart.cc @@ -0,0 +1,223 @@ +#include "MCAbstractPart.h" + +#include <string.h> +#include <stdlib.h> + +using namespace mailcore; + +AbstractPart::AbstractPart() +{ + init(); +} + +AbstractPart::AbstractPart(AbstractPart * other) +{ + init(); + setFilename(other->mFilename); + setMimeType(other->mMimeType); + setCharset(other->mCharset); + setContentID(other->mContentID); + setContentLocation(other->mContentLocation); + setInlineAttachment(other->mInlineAttachment); + setPartType(other->mPartType); +} + +void AbstractPart::init() +{ + mFilename = NULL; + mMimeType = NULL; + mCharset = NULL; + mContentID = NULL; + mContentLocation = NULL; + mInlineAttachment = false; + mPartType = PartTypeSingle; +} + +AbstractPart::~AbstractPart() +{ + MC_SAFE_RELEASE(mFilename); + MC_SAFE_RELEASE(mMimeType); + MC_SAFE_RELEASE(mCharset); + MC_SAFE_RELEASE(mContentID); + MC_SAFE_RELEASE(mContentLocation); +} + +String * AbstractPart::description() +{ + String * result = String::string(); + result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this); + if (mFilename != NULL) { + result->appendUTF8Format("filename: %s\n", mFilename->UTF8Characters()); + } + if (mMimeType != NULL) { + result->appendUTF8Format("mime type: %s\n", mMimeType->UTF8Characters()); + } + if (mCharset != NULL) { + result->appendUTF8Format("charset: %s\n", mCharset->UTF8Characters()); + } + if (mContentID != NULL) { + result->appendUTF8Format("content-ID: %s\n", mContentID->UTF8Characters()); + } + if (mContentLocation != NULL) { + result->appendUTF8Format("content-location: %s\n", mContentLocation->UTF8Characters()); + } + result->appendUTF8Format("inline: %i\n", mInlineAttachment); + result->appendUTF8Format(">"); + + return result; +} + +#if 0 +String * AbstractPart::className() +{ + return MCSTR("AbstractPart"); +} +#endif + +Object * AbstractPart::copy() +{ + return new AbstractPart(this); +} + +PartType AbstractPart::partType() +{ + return mPartType; +} + +void AbstractPart::setPartType(PartType type) +{ + mPartType = type; +} + +String * AbstractPart::filename() +{ + return mFilename; +} + +void AbstractPart::setFilename(String * filename) +{ + MC_SAFE_REPLACE_COPY(String, mFilename, filename); +} + +String * AbstractPart::mimeType() +{ + return mMimeType; +} + +void AbstractPart::setMimeType(String * mimeType) +{ + MC_SAFE_REPLACE_COPY(String, mMimeType, mimeType); +} + +String * AbstractPart::charset() +{ + return mCharset; +} + +void AbstractPart::setCharset(String * charset) +{ + MC_SAFE_REPLACE_COPY(String, mCharset, charset); +} + +String * AbstractPart::contentID() +{ + return mContentID; +} + +void AbstractPart::setContentID(String * contentID) +{ + MC_SAFE_REPLACE_COPY(String, mContentID, contentID); +} + +String * AbstractPart::contentLocation() +{ + return mContentLocation; +} + +void AbstractPart::setContentLocation(String * contentLocation) +{ + MC_SAFE_REPLACE_COPY(String, mContentLocation, contentLocation); +} + +bool AbstractPart::isInlineAttachment() +{ + return mInlineAttachment; +} + +void AbstractPart::setInlineAttachment(bool inlineAttachment) +{ + mInlineAttachment = inlineAttachment; +} + +AbstractMessage * AbstractPart::message() +{ + return mMessage; +} + +void AbstractPart::setMessage(AbstractMessage * message) +{ + mMessage = message; +} + +void AbstractPart::importIMAPFields(struct mailimap_body_fields * fields, + struct mailimap_body_ext_1part * extension) +{ + if (fields->bd_parameter != NULL) { + clistiter * cur; + + for(cur = clist_begin(fields->bd_parameter->pa_list) ; cur != NULL ; + cur = clist_next(cur)) { + struct mailimap_single_body_fld_param * imap_param; + + imap_param = (struct mailimap_single_body_fld_param *) clist_content(cur); + + if (strcasecmp(imap_param->pa_name, "name") == 0) { + setFilename(String::stringByDecodingMIMEHeaderValue(imap_param->pa_value)); + } + else if (strcasecmp(imap_param->pa_name, "charset") == 0) { + setCharset(String::stringByDecodingMIMEHeaderValue(imap_param->pa_value)); + } + } + } + if (fields->bd_id != NULL) { + char * contentid; + size_t cur_token; + int r; + + cur_token = 0; + r = mailimf_msg_id_parse(fields->bd_id, strlen(fields->bd_id), + &cur_token, &contentid); + if (r == MAILIMF_NO_ERROR) { + // msg id + setContentID(String::stringWithUTF8Characters(contentid)); + free(contentid); + } + } + + if (extension != NULL) { + if (extension->bd_disposition != NULL) { + if (strcasecmp(extension->bd_disposition->dsp_type, "inline") == 0) { + setInlineAttachment(true); + } + + if (extension->bd_disposition->dsp_attributes != NULL) { + clistiter * cur; + + for(cur = clist_begin(extension->bd_disposition->dsp_attributes->pa_list) ; cur != NULL ; + cur = clist_next(cur)) { + struct mailimap_single_body_fld_param * imap_param; + + imap_param = (struct mailimap_single_body_fld_param *) clist_content(cur); + + if (strcasecmp(imap_param->pa_name, "filename") == 0) { + setFilename(String::stringByDecodingMIMEHeaderValue(imap_param->pa_value)); + } + } + } + } + + if (extension->bd_loc != NULL) { + setContentLocation(String::stringWithUTF8Characters(extension->bd_loc)); + } + } +} diff --git a/src/core/abstract/MCAbstractPart.h b/src/core/abstract/MCAbstractPart.h new file mode 100644 index 00000000..356ed256 --- /dev/null +++ b/src/core/abstract/MCAbstractPart.h @@ -0,0 +1,63 @@ +#ifndef __MAILCORE_MCABSTRACTPART_H_ + +#define __MAILCORE_MCABSTRACTPART_H_ + +#include <mailcore/MCBaseTypes.h> +#include <mailcore/MCMessageConstants.h> + +namespace mailcore { + + class AbstractMessage; + + class AbstractPart : public Object { + private: + String * mFilename; + String * mMimeType; + String * mCharset; + String * mContentID; + String * mContentLocation; + bool mInlineAttachment; + PartType mPartType; + AbstractMessage * mMessage; // weak + void init(); + + public: + AbstractPart(); + AbstractPart(AbstractPart * other); + virtual ~AbstractPart(); + + virtual String * description(); + //virtual String * className(); + virtual Object * copy(); + + virtual PartType partType(); + virtual void setPartType(PartType type); + + virtual String * filename(); + virtual void setFilename(String * filename); + + virtual String * mimeType(); + virtual void setMimeType(String * mimeType); + + virtual String * charset(); + virtual void setCharset(String * charset); + + virtual String * contentID(); + virtual void setContentID(String * contentID); + + virtual String * contentLocation(); + virtual void setContentLocation(String * contentLocation); + + virtual bool isInlineAttachment(); + virtual void setInlineAttachment(bool inlineAttachment); + + virtual AbstractMessage * message(); + virtual void setMessage(AbstractMessage * message); + + virtual void importIMAPFields(struct mailimap_body_fields * fields, + struct mailimap_body_ext_1part * extension); + }; + +} + +#endif diff --git a/src/core/abstract/MCAddress.cc b/src/core/abstract/MCAddress.cc new file mode 100644 index 00000000..25bed974 --- /dev/null +++ b/src/core/abstract/MCAddress.cc @@ -0,0 +1,364 @@ +#include "MCAddress.h" + +#include <string.h> + +using namespace mailcore; + +Address::Address() +{ + init(); +} + +Address::Address(Address * other) +{ + init(); + setDisplayName(other->displayName()); + setMailbox(other->mailbox()); +} + +void Address::init() +{ + mDisplayName = NULL; + mMailbox = NULL; +} + +Address::~Address() +{ + MC_SAFE_RELEASE(mDisplayName); + MC_SAFE_RELEASE(mMailbox); +} + +Address * Address::addressWithDisplayName(String * displayName, String * mailbox) +{ + Address * result = new Address(); + result->setDisplayName(displayName); + result->setMailbox(mailbox); + return (Address *) result->autorelease(); +} + +Address * Address::addressWithMailbox(String * mailbox) +{ + return addressWithDisplayName(NULL, mailbox); +} + +Address * Address::addressWithIMFMailbox(struct mailimf_mailbox * mailbox) +{ + Address * address; + + address = new Address(); + if (mailbox->mb_display_name != NULL) { + address->setDisplayName(String::stringByDecodingMIMEHeaderValue(mailbox->mb_display_name)); + } + if (mailbox->mb_addr_spec != NULL) { + address->setMailbox(String::stringWithUTF8Characters(mailbox->mb_addr_spec)); + } + if (address->mailbox() == NULL) { + address->setMailbox(String::string()); + } + + return (Address *) address->autorelease(); +} + +Address * Address::addressWithIMAPAddress(struct mailimap_address * imap_addr) +{ + char * dsp_name; + Address * address; + String * mailbox; + + if (imap_addr->ad_personal_name == NULL) + dsp_name = NULL; + else { + dsp_name = imap_addr->ad_personal_name; + } + + if (imap_addr->ad_host_name == NULL) { + const char * addr; + + if (imap_addr->ad_mailbox_name == NULL) { + addr = ""; + } + else { + addr = imap_addr->ad_mailbox_name; + } + mailbox = String::stringWithUTF8Characters(addr); + if (mailbox == NULL) { + mailbox = MCSTR(""); + } + } + else if (imap_addr->ad_mailbox_name == NULL) { + // fix by Gabor Cselle, (http://gaborcselle.com/), reported 8/16/2009 + mailbox = String::stringWithUTF8Format("@%s", imap_addr->ad_host_name); + } + else { + mailbox = String::stringWithUTF8Format("%s@%s", imap_addr->ad_mailbox_name, imap_addr->ad_host_name); + } + + address = new Address(); + if (dsp_name != NULL) { + address->setDisplayName(String::stringByDecodingMIMEHeaderValue(dsp_name)); + } + address->setMailbox(mailbox); + + return (Address *) address->autorelease(); +} + +Address * Address::addressWithRFC822String(String * RFC822String) +{ + const char * utf8String; + size_t currentIndex; + struct mailimf_mailbox * mb; + int r; + Address * result; + + utf8String = RFC822String->UTF8Characters(); + currentIndex = 0; + r = mailimf_mailbox_parse(utf8String, strlen(utf8String), ¤tIndex, &mb); + if (r != MAILIMF_NO_ERROR) + return NULL; + + result = addressWithIMFMailbox(mb); + mailimf_mailbox_free(mb); + + return result; +} + +Address * Address::addressWithNonEncodedIMFMailbox(struct mailimf_mailbox * mailbox) +{ + Address * address; + + address = new Address(); + if (mailbox->mb_display_name != NULL) { + address->setDisplayName(String::stringWithUTF8Characters(mailbox->mb_display_name)); + } + if (mailbox->mb_addr_spec != NULL) { + address->setMailbox(String::stringWithUTF8Characters(mailbox->mb_addr_spec)); + } + if (address->mailbox() == NULL) { + address->setMailbox(String::string()); + } + + return (Address *) address->autorelease(); +} + +Address * Address::addressWithNonEncodedRFC822String(String * nonEncodedRFC822String) +{ + const char * utf8String; + size_t currentIndex; + struct mailimf_mailbox * mb; + int r; + Address * result; + + utf8String = nonEncodedRFC822String->UTF8Characters(); + currentIndex = 0; + r = mailimf_mailbox_parse(utf8String, strlen(utf8String), ¤tIndex, &mb); + if (r != MAILIMF_NO_ERROR) + return NULL; + + result = addressWithNonEncodedIMFMailbox(mb); + mailimf_mailbox_free(mb); + + return result; +} + +String * Address::description() +{ + String * result = String::string(); + result->appendString(className()); + result->appendUTF8Format(":%p ", this); + if (mDisplayName != NULL) { + result->appendString(mDisplayName); + } + result->appendUTF8Characters(" <"); + if (mMailbox != NULL) { + result->appendString(mMailbox); + } + result->appendUTF8Characters(">"); + + return result; +} + +#if 0 +String * Address::className() +{ + return MCSTR("Address"); +} +#endif + +bool Address::isEqual(Object * otherObject) +{ + Address * otherAddress = (Address *) otherObject; + + if (mDisplayName == NULL) { + if (otherAddress->displayName() != NULL) { + return false; + } + } + else if (mDisplayName != NULL) { + if (otherAddress->displayName() == NULL) { + return false; + } + else { + if (!mDisplayName->isEqual(otherAddress->displayName())) + return false; + } + } + + if (mMailbox == NULL) { + if (otherAddress->mailbox() != NULL) { + return false; + } + } + else if (mMailbox != NULL) { + if (otherAddress->mailbox() == NULL) { + return false; + } + else { + if (!mMailbox->isEqual(otherAddress->mailbox())) + return false; + } + } + + return true; +} + +unsigned int Address::hash() +{ + unsigned int value; + + value = 0; + if (mDisplayName != NULL) { + value += mDisplayName->hash(); + } + if (mMailbox != NULL) { + value += mMailbox->hash(); + } + + return value; +} + +Object * Address::copy() +{ + return new Address(this); +} + +void Address::setDisplayName(String * displayName) +{ + MC_SAFE_REPLACE_COPY(String, mDisplayName, displayName); +} + +String * Address::displayName() +{ + return mDisplayName; +} + +void Address::setMailbox(String * mailbox) +{ + MC_SAFE_REPLACE_COPY(String, mMailbox, mailbox); +} + +String * Address::mailbox() +{ + return mMailbox; +} + +struct mailimf_address * Address::createIMFAddress() +{ + struct mailimf_mailbox * mailbox; + struct mailimf_address * result; + + mailbox = createIMFMailbox(); + result = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mailbox, NULL); + + return result; +} + +struct mailimf_mailbox * Address::createIMFMailbox() +{ + struct mailimf_mailbox * result; + char * display_name; + char * addr_spec; + + display_name = NULL; + if (displayName() != NULL) { + if (displayName()->length() > 0) { + Data * data; + + data = displayName()->encodedAddressDisplayNameValue(); + if (data->bytes() != NULL) { + display_name = strdup(data->bytes()); + } + } + } + addr_spec = strdup(mailbox()->UTF8Characters()); + result = mailimf_mailbox_new(display_name, addr_spec); + + return result; +} + +String * Address::RFC822String() +{ + struct mailimf_mailbox * mb; + MMAPString * str; + int col; + struct mailimf_mailbox_list * mb_list; + clist * list; + String * result; + + mb = createIMFMailbox(); + + list = clist_new(); + clist_append(list, mb); + mb_list = mailimf_mailbox_list_new(list); + + str = mmap_string_new(""); + col = 0; + mailimf_mailbox_list_write_mem(str, &col, mb_list); + + result = String::stringWithUTF8Characters(str->str); + + mailimf_mailbox_list_free(mb_list); + mmap_string_free(str); + + return result; +} + +String * Address::nonEncodedRFC822String() +{ + struct mailimf_mailbox * mb; + MMAPString * str; + int col; + struct mailimf_mailbox_list * mb_list; + clist * list; + String * result; + char * display_name; + char * addr_spec; + + display_name = NULL; + if (displayName() != NULL) { + if (displayName()->length() > 0) { + display_name = strdup(displayName()->UTF8Characters()); + } + } + if ((mailbox() == NULL) || (mailbox()->length() == 0)) { + addr_spec = strdup("invalid"); + } + else { + addr_spec = strdup(mailbox()->UTF8Characters()); + } + mb = mailimf_mailbox_new(display_name, addr_spec); + + list = clist_new(); + clist_append(list, mb); + mb_list = mailimf_mailbox_list_new(list); + + str = mmap_string_new(""); + col = 0; + mailimf_mailbox_list_write_mem(str, &col, mb_list); + + result = String::stringWithUTF8Characters(str->str); + + mailimf_mailbox_list_free(mb_list); + mmap_string_free(str); + + return result; +} diff --git a/src/core/abstract/MCAddress.h b/src/core/abstract/MCAddress.h new file mode 100644 index 00000000..227c1136 --- /dev/null +++ b/src/core/abstract/MCAddress.h @@ -0,0 +1,55 @@ +#ifndef __MAILCORE_MCADDRESS_H_ + +#define __MAILCORE_MCADDRESS_H_ + +#include <libetpan/libetpan.h> +#include <mailcore/MCBaseTypes.h> + +namespace mailcore { + + class Address : public Object { + private: + String * mDisplayName; + String * mMailbox; + void init(); + + public: + Address(); + Address(Address * other); + virtual ~Address(); + + static Address * addressWithDisplayName(String * displayName, String * mailbox); + static Address * addressWithMailbox(String * mailbox); + static Address * addressWithRFC822String(String * RFC822String); + static Address * addressWithNonEncodedRFC822String(String * nonEncodedRFC822String); + + virtual String * description(); + //virtual String * className(); + + virtual bool isEqual(Object * otherObject); + virtual unsigned int hash(); + + virtual Object * copy(); + + virtual void setDisplayName(String * displayName); + virtual String * displayName(); + + virtual void setMailbox(String * address); + virtual String * mailbox(); + + virtual String * RFC822String(); + virtual String * nonEncodedRFC822String(); + + // Additions + static Address * addressWithIMFMailbox(struct mailimf_mailbox * mb); + static Address * addressWithNonEncodedIMFMailbox(struct mailimf_mailbox * mb); + static Address * addressWithIMAPAddress(struct mailimap_address * imap_addr); + + // Must be released + virtual struct mailimf_address * createIMFAddress(); + virtual struct mailimf_mailbox * createIMFMailbox(); + }; + +} + +#endif diff --git a/src/core/abstract/MCMessageConstants.h b/src/core/abstract/MCMessageConstants.h new file mode 100644 index 00000000..ab30b8c4 --- /dev/null +++ b/src/core/abstract/MCMessageConstants.h @@ -0,0 +1,208 @@ +#ifndef __MAILCORE_MCMESSAGECONSTANTS_H_ +#define __MAILCORE_MCMESSAGECONSTANTS_H_ + +namespace mailcore { + + enum ConnectionType { + ConnectionTypeClear = 1 << 0, + ConnectionTypeStartTLS = 1 << 1, + ConnectionTypeTLS = 1 << 2, + }; + + enum AuthType { + AuthTypeSASLNone = 0, + AuthTypeSASLCRAMMD5 = 1 << 0, + AuthTypeSASLPlain = 1 << 1, + AuthTypeSASLGSSAPI = 1 << 2, + AuthTypeSASLDIGESTMD5 = 1 << 3, + AuthTypeSASLLogin = 1 << 4, + AuthTypeSASLSRP = 1 << 5, + AuthTypeSASLNTLM = 1 << 6, + AuthTypeSASLKerberosV4 = 1 << 7, + }; + + enum IMAPFolderFlag { + IMAPFolderFlagNone = 0, + IMAPFolderFlagMarked = 1 << 0, + IMAPFolderFlagUnmarked = 1 << 1, + IMAPFolderFlagNoSelect = 1 << 2, + IMAPFolderFlagNoInferiors = 1 << 3, + IMAPFolderFlagInbox = 1 << 4, + IMAPFolderFlagSentMail = 1 << 5, + IMAPFolderFlagStarred = 1 << 6, + IMAPFolderFlagAllMail = 1 << 7, + IMAPFolderFlagTrash = 1 << 8, + IMAPFolderFlagDrafts = 1 << 9, + IMAPFolderFlagSpam = 1 << 10, + IMAPFolderFlagImportant = 1 << 11, + IMAPFolderFlagArchive = 1 << 12, + }; + + enum MessageFlag { + MessageFlagNone = 0, + MessageFlagSeen = 1 << 0, + MessageFlagAnswered = 1 << 1, + MessageFlagFlagged = 1 << 2, + MessageFlagDeleted = 1 << 3, + MessageFlagDraft = 1 << 4, + MessageFlagMDNSent = 1 << 5, + MessageFlagForwarded = 1 << 6, + MessageFlagSubmitPending = 1 << 7, + MessageFlagSubmitted = 1 << 8, + } ; + + enum IMAPMessagesRequestKind { + IMAPMessagesRequestKindUid = 0, // This is the default and it's always fetched + IMAPMessagesRequestKindFlags = 1 << 0, + IMAPMessagesRequestKindHeaders = 1 << 1, + IMAPMessagesRequestKindStructure = 1 << 2, + IMAPMessagesRequestKindInternalDate = 1 << 3, + IMAPMessagesRequestKindFullHeaders = 1 << 4, + IMAPMessagesRequestKindHeaderSubject = 1 << 5, + IMAPMessagesRequestKindGmailLabels = 1 << 6, + }; + + enum IMAPFetchRequestType { + IMAPFetchRequestTypeUID = 0, + IMAPFetchRequestTypeSequence = 1 + }; + + enum IMAPStoreFlagsRequestKind { + IMAPStoreFlagsRequestKindAdd, + IMAPStoreFlagsRequestKindRemove, + IMAPStoreFlagsRequestKindSet, + }; + + enum IMAPWorkaround { + IMAPWorkaroundGmail = 1 << 0, + IMAPWorkaroundYahoo = 1 << 1, + IMAPWorkaroundExchange2003 = 1 << 2, + }; + + enum IMAPCapability { + IMAPCapabilityACL, + IMAPCapabilityBinary, + IMAPCapabilityCatenate, + IMAPCapabilityChildren, + IMAPCapabilityCompressDeflate, + IMAPCapabilityCondstore, + IMAPCapabilityEnable, + IMAPCapabilityIdle, + IMAPCapabilityLiteralPlus, + IMAPCapabilityMultiAppend, + IMAPCapabilityNamespace, + IMAPCapabilityQResync, + IMAPCapabilityQuota, + IMAPCapabilitySort, + IMAPCapabilityStartTLS, + IMAPCapabilityThreadOrderedSubject, + IMAPCapabilityThreadReferences, + IMAPCapabilityUIDPlus, + IMAPCapabilityUnselect, + IMAPCapabilityXList, + IMAPCapabilityAuthAnonymous, + IMAPCapabilityAuthCRAMMD5, + MAPCapabilityAuthDigestMD5, + IMAPCapabilityAuthExternal, + IMAPCapabilityAuthGSSAPI, + IMAPCapabilityAuthKerberosV4, + IMAPCapabilityAuthLogin, + IMAPCapabilityAuthNTLM, + IMAPCapabilityAuthOTP, + IMAPCapabilityAuthPlain, + IMAPCapabilityAuthSKey, + IMAPCapabilityAuthSRP, + }; + + enum POPCapability { + POPCapabilityNone, + POPCapabilityStartTLS, + POPCapabilityTop, + POPCapabilityUser, + POPCapabilityRespCodes, + POPCapabilityPipelining, + POPCapabilityUIDL, + POPCapabilitySASL, + POPCapabilityAuthAnonymous, + POPCapabilityAuthCRAMMD5, + POPCapabilityAuthDigestMD5, + POPCapabilityAuthExternal, + POPCapabilityAuthGSSAPI, + POPCapabilityAuthKerberosV4, + POPCapabilityAuthLogin, + POPCapabilityAuthNTLM, + POPCapabilityAuthOTP, + POPCapabilityAuthPlain, + POPCapabilityAuthSKey, + POPCapabilityAuthSRP, + }; + + enum Encoding { + Encoding7Bit = 0, // should match MAILIMAP_BODY_FLD_ENC_7BIT + Encoding8Bit = 1, // should match MAILIMAP_BODY_FLD_ENC_8BIT + EncodingBinary = 2, // should match MAILIMAP_BODY_FLD_ENC_BINARY + EncodingBase64 = 3, // should match MAILIMAP_BODY_FLD_ENC_BASE64 + EncodingQuotedPrintable = 4, // should match MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE + EncodingOther = 5, // should match MAILIMAP_BODY_FLD_ENC_OTHER + // negative values should be used for other encoding + EncodingUUEncode = -1 + }; + + enum IMAPSearchKind { + IMAPSearchKindNone, + IMAPSearchKindFrom, + IMAPSearchKindRecipient, + IMAPSearchKindSubject, + IMAPSearchKindContent, + IMAPSearchKindHeader, + IMAPSearchKindOr, + IMAPSearchKindAnd, + }; + + enum ErrorCode { + ErrorNone, + ErrorConnection, + ErrorTLSNotAvailable, + ErrorTLSCertificate, + ErrorParse, + ErrorCertificate, + ErrorAuthentication, + ErrorGmailIMAPNotEnabled, + ErrorGmailExceededBandwidthLimit, + ErrorGmailTooManySimultaneousConnections, + ErrorMobileMeMoved, + ErrorYahooUnavailable, + ErrorNonExistantFolder, + ErrorRename, + ErrorDelete, + ErrorCreate, + ErrorSubscribe, + ErrorAppend, + ErrorCopy, + ErrorExpunge, + ErrorFetch, + ErrorIdle, + ErrorIdentity, + ErrorNamespace, + ErrorStore, + ErrorStartTLSNotAvailable, + ErrorSendMessageIllegalAttachment, + ErrorStorageLimit, + ErrorSendMessageNotAllowed, + ErrorNeedsConnectToWebmail, + ErrorSendMessage, + ErrorAuthenticationRequired, + ErrorFetchMessageList, + ErrorDeleteMessage, + }; + + enum PartType { + PartTypeSingle, + PartTypeMessage, + PartTypeMultipartMixed, + PartTypeMultipartRelated, + PartTypeMultipartAlternative, + }; +} + +#endif
\ No newline at end of file diff --git a/src/core/abstract/MCMessageHeader.cc b/src/core/abstract/MCMessageHeader.cc new file mode 100644 index 00000000..06ad386b --- /dev/null +++ b/src/core/abstract/MCMessageHeader.cc @@ -0,0 +1,1054 @@ +#include "MCMessageHeader.h" + +#include "MCAddress.h" + +#include <string.h> +#include <unistd.h> + +using namespace mailcore; + +static time_t timestamp_from_date(struct mailimf_date_time * date_time); +static struct mailimf_date_time * get_date_from_timestamp(time_t timeval); +static time_t timestamp_from_imap_date(struct mailimap_date_time * date_time); +static time_t mkgmtime(struct tm * tmp); +static int tmcomp(struct tm * atmp, struct tm * btmp); + +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); + setMessageID(other->mMessageID); + 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); + setUserAgent(other->mUserAgent); +} + +void MessageHeader::init(bool generateDate, bool generateMessageID) +{ + mMessageID = NULL; + 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; + mUserAgent = 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(); + } +} + +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(mUserAgent); +} + +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 (mUserAgent != NULL) { + result->appendUTF8Format("X-Mailer: %s\n", mUserAgent->UTF8Characters()); + } + result->appendUTF8Format(">"); + + return result; +} + +#if 0 +String * MessageHeader::className() +{ + return MCSTR("MessageHeader"); +} +#endif + +Object * MessageHeader::copy() +{ + return new MessageHeader(this); +} + +void MessageHeader::setMessageID(String * messageID) +{ + MC_SAFE_REPLACE_COPY(String, mMessageID, messageID); +} + +String * MessageHeader::messageID() +{ + return mMessageID; +} + +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) +{ + MC_SAFE_REPLACE_COPY(String, mUserAgent, userAgent); +} + +String * MessageHeader::userAgent() +{ + return mUserAgent; +} + +String * MessageHeader::extractedSubject() +{ + return subject()->extractedSubject(); +} + +String * MessageHeader::partialExtractedSubject() +{ + return subject()->extractedSubjectAndKeepBracket(true); +} + +void MessageHeader::importHeadersData(Data * data) +{ + size_t cur_token; + struct mailimf_fields * fields; + int r; + + cur_token = 0; + r = mailimf_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 = timestamp_from_date(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); + } +} + +static time_t timestamp_from_date(struct mailimf_date_time * date_time) +{ + struct tm tmval; + time_t timeval; + int zone_min; + int zone_hour; + + tmval.tm_sec = date_time->dt_sec; + tmval.tm_min = date_time->dt_min; + tmval.tm_hour = date_time->dt_hour; + tmval.tm_mday = date_time->dt_day; + tmval.tm_mon = date_time->dt_month - 1; + if (date_time->dt_year < 1000) { + // workaround when century is not given in year + tmval.tm_year = date_time->dt_year + 2000 - 1900; + } + else { + tmval.tm_year = date_time->dt_year - 1900; + } + + timeval = mkgmtime(&tmval); + + if (date_time->dt_zone >= 0) { + zone_hour = date_time->dt_zone / 100; + zone_min = date_time->dt_zone % 100; + } + else { + zone_hour = -((- date_time->dt_zone) / 100); + zone_min = -((- date_time->dt_zone) % 100); + } + timeval -= zone_hour * 3600 + zone_min * 60; + + return timeval; +} + +static struct mailimf_date_time * get_date_from_timestamp(time_t timeval) +{ + struct tm gmt; + struct tm lt; + int off; + struct mailimf_date_time * date_time; + int sign; + int hour; + int min; + + gmtime_r(&timeval, &gmt); + localtime_r(&timeval, <); + + off = (mkgmtime(<) - mkgmtime(&gmt)) / 60; + if (off < 0) { + sign = -1; + } + else { + sign = 1; + } + off = off * sign; + min = off % 60; + hour = off / 60; + off = hour * 100 + min; + off = off * sign; + + date_time = mailimf_date_time_new(lt.tm_mday, lt.tm_mon + 1, + lt.tm_year + 1900, + lt.tm_hour, lt.tm_min, lt.tm_sec, + off); + + return date_time; +} + +static time_t timestamp_from_imap_date(struct mailimap_date_time * date_time) +{ + struct tm tmval; + time_t timeval; + int zone_min; + int zone_hour; + + tmval.tm_sec = date_time->dt_sec; + tmval.tm_min = date_time->dt_min; + tmval.tm_hour = date_time->dt_hour; + tmval.tm_mday = date_time->dt_day; + tmval.tm_mon = date_time->dt_month - 1; + if (date_time->dt_year < 1000) { + // workaround when century is not given in year + tmval.tm_year = date_time->dt_year + 2000 - 1900; + } + else { + tmval.tm_year = date_time->dt_year - 1900; + } + + timeval = mkgmtime(&tmval); + + if (date_time->dt_zone >= 0) { + zone_hour = date_time->dt_zone / 100; + zone_min = date_time->dt_zone % 100; + } + else { + zone_hour = -((- date_time->dt_zone) / 100); + zone_min = -((- date_time->dt_zone) % 100); + } + timeval -= zone_hour * 3600 + zone_min * 60; + + return timeval; +} + +#define INVALID_TIMESTAMP (-1) + +static int tmcomp(struct tm * atmp, struct tm * btmp) +{ + register int result; + + if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && + (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && + (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && + (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && + (result = (atmp->tm_min - btmp->tm_min)) == 0) + result = atmp->tm_sec - btmp->tm_sec; + return result; +} + +static time_t mkgmtime(struct tm * tmp) +{ + register int dir; + register int bits; + register int saved_seconds; + time_t t; + struct tm yourtm, mytm; + + yourtm = *tmp; + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = 0; + /* + ** Calculate the number of magnitude bits in a time_t + ** (this works regardless of whether time_t is + ** signed or unsigned, though lint complains if unsigned). + */ + for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) + ; + /* + ** If time_t is signed, then 0 is the median value, + ** if time_t is unsigned, then 1 << bits is median. + */ + if(bits > 40) bits = 40; + t = (t < 0) ? 0 : ((time_t) 1 << bits); + for ( ; ; ) { + gmtime_r(&t, &mytm); + dir = tmcomp(&mytm, &yourtm); + if (dir != 0) { + if (bits-- < 0) { + return INVALID_TIMESTAMP; + } + if (bits < 0) + --t; + else if (dir > 0) + t -= (time_t) 1 << bits; + else t += (time_t) 1 << bits; + continue; + } + break; + } + t += saved_seconds; + return t; +} + +#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 = get_date_from_timestamp(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 (mUserAgent != NULL) { + struct mailimf_field * field; + + field = mailimf_field_new_custom(strdup("X-Mailer"), strdup(mUserAgent->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 = timestamp_from_date(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 = timestamp_from_imap_date(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(timestamp_from_imap_date(date)); +} + diff --git a/src/core/abstract/MCMessageHeader.h b/src/core/abstract/MCMessageHeader.h new file mode 100644 index 00000000..5a7483e2 --- /dev/null +++ b/src/core/abstract/MCMessageHeader.h @@ -0,0 +1,90 @@ +#ifndef __MAILCORE_MCMESSAGEHEADER_H_ + +#define __MAILCORE_MCMESSAGEHEADER_H_ + +#include <mailcore/MCBaseTypes.h> +#include <time.h> + +namespace mailcore { + + class Address; + + class MessageHeader : public Object { + private: + String * mMessageID; + Array * /* String */ mReferences; + Array * /* String */ mInReplyTo; + Address * mSender; + Address * mFrom; + Array * /* Address */ mTo; + Array * /* Address */ mCc; + Array * /* Address */ mBcc; + Array * /* Address */ mReplyTo; + String * mSubject; + time_t mDate; + time_t mReceivedDate; + String * mUserAgent; + void init(bool generateDate, bool generateMessageID); + + public: + MessageHeader(); + MessageHeader(MessageHeader * other); + virtual ~MessageHeader(); + + virtual String * description(); + //virtual String * className(); + virtual Object * copy(); + + virtual void setMessageID(String * messageID); + virtual String * messageID(); + + virtual void setReferences(Array * references); + virtual Array * references(); + + virtual void setInReplyTo(Array * inReplyTo); + virtual Array * inReplyTo(); + + virtual void setDate(time_t date); + virtual time_t date(); + + virtual void setReceivedDate(time_t date); + virtual time_t receivedDate(); + + virtual void setSender(Address * sender); + virtual Address * sender(); + + virtual void setFrom(Address * from); + virtual Address * from(); + + virtual void setTo(Array * to); + virtual Array * to(); + + virtual void setCc(Array * cc); + virtual Array * cc(); + + virtual void setBcc(Array * bcc); + virtual Array * bcc(); + + virtual void setReplyTo(Array * replyTo); + virtual Array * replyTo(); + + virtual void setSubject(String * subject); + virtual String * subject(); + + virtual void setUserAgent(String * userAgent); + virtual String * userAgent(); + + virtual String * extractedSubject(); + virtual String * partialExtractedSubject(); + virtual void importHeadersData(Data * data); + virtual void importIMAPEnvelope(struct mailimap_envelope * env); + virtual void importIMAPReferences(Data * data); + virtual void importIMAPInternalDate(struct mailimap_date_time * date); + + virtual struct mailimf_fields * createIMFFieldsAndFilterBcc(bool filterBcc); + virtual void importIMFFields(struct mailimf_fields * fields); + }; + +} + +#endif |