diff options
author | 2016-01-18 23:41:02 -0500 | |
---|---|---|
committer | 2016-01-18 23:41:02 -0500 | |
commit | 63e1f0471769d8a72edeafbd4e65b9d0c2763e9e (patch) | |
tree | bd602a8610c680548761a8fac3fd48025b3f9df5 /src/core | |
parent | e1fddae3b6edbbd33a22408f30a36704906cd30f (diff) | |
parent | ab62ae2cdddc2fda8ad667260db22617839b3593 (diff) |
Merge branch 'master' of https://github.com/MailCore/mailcore2
Diffstat (limited to 'src/core')
57 files changed, 1498 insertions, 133 deletions
diff --git a/src/core/abstract/MCAbstractPart.cpp b/src/core/abstract/MCAbstractPart.cpp index e88a5a36..0956368c 100644 --- a/src/core/abstract/MCAbstractPart.cpp +++ b/src/core/abstract/MCAbstractPart.cpp @@ -28,6 +28,7 @@ AbstractPart::AbstractPart(AbstractPart * other) setContentLocation(other->mContentLocation); setContentDescription(other->mContentDescription); setInlineAttachment(other->mInlineAttachment); + setAttachment(other->mAttachment); setPartType(other->mPartType); setContentTypeParameters(other->mContentTypeParameters); } @@ -42,6 +43,7 @@ void AbstractPart::init() mContentLocation = NULL; mContentDescription = NULL; mInlineAttachment = false; + mAttachment = false; mPartType = PartTypeSingle; mContentTypeParameters = NULL; } @@ -81,6 +83,7 @@ String * AbstractPart::description() result->appendUTF8Format("content-description: %s\n", mContentDescription->UTF8Characters()); } result->appendUTF8Format("inline: %i\n", mInlineAttachment); + result->appendUTF8Format("attachment: %i\n", mAttachment); if (mContentTypeParameters != NULL) { mc_foreachhashmapKeyAndValue(String, key, String, value, mContentTypeParameters) { result->appendUTF8Format("%s: %s\n", key->UTF8Characters(), value->UTF8Characters()); @@ -186,6 +189,16 @@ void AbstractPart::setInlineAttachment(bool inlineAttachment) mInlineAttachment = inlineAttachment; } +bool AbstractPart::isAttachment() +{ + return mAttachment; +} + +void AbstractPart::setAttachment(bool attachment) +{ + mAttachment = attachment; +} + void AbstractPart::importIMAPFields(struct mailimap_body_fields * fields, struct mailimap_body_ext_1part * extension) { @@ -233,7 +246,10 @@ void AbstractPart::importIMAPFields(struct mailimap_body_fields * fields, if (strcasecmp(extension->bd_disposition->dsp_type, "inline") == 0) { setInlineAttachment(true); } - + else if (strcasecmp(extension->bd_disposition->dsp_type, "attachment") == 0) { + setAttachment(true); + } + if (extension->bd_disposition->dsp_attributes != NULL) { clistiter * cur; @@ -345,6 +361,9 @@ HashMap * AbstractPart::serializable() if (mInlineAttachment) { result->setObjectForKey(MCSTR("inlineAttachment"), MCSTR("1")); } + if (mAttachment) { + result->setObjectForKey(MCSTR("attachment"), MCSTR("1")); + } String * partTypeStr; switch (mPartType) { default: @@ -387,6 +406,12 @@ void AbstractPart::importSerializable(HashMap * serializable) setInlineAttachment(true); } } + value = (String *) serializable->objectForKey(MCSTR("attachment")); + if (value != NULL) { + if (value->intValue()) { + setAttachment(true); + } + } value = (String *) serializable->objectForKey(MCSTR("partType")); if (value != NULL) { if (value->isEqual(MCSTR("single"))) { @@ -417,8 +442,9 @@ void AbstractPart::setContentTypeParameters(HashMap * parameters) Array * AbstractPart::allContentTypeParametersNames() { - if (mContentTypeParameters == NULL) + if (mContentTypeParameters == NULL) { return Array::array(); + } return mContentTypeParameters->allKeys(); } @@ -433,8 +459,9 @@ void AbstractPart::setContentTypeParameter(String * name, String * object) void AbstractPart::removeContentTypeParameter(String * name) { - if (mContentTypeParameters == NULL) + if (mContentTypeParameters == NULL) { return; + } mc_foreachhashmapKey(String, key, mContentTypeParameters) { if (key->isEqualCaseInsensitive(name)) { mContentTypeParameters->removeObjectForKey(key); diff --git a/src/core/abstract/MCAbstractPart.h b/src/core/abstract/MCAbstractPart.h index 7a743e1d..88b5b331 100644 --- a/src/core/abstract/MCAbstractPart.h +++ b/src/core/abstract/MCAbstractPart.h @@ -43,6 +43,9 @@ namespace mailcore { virtual bool isInlineAttachment(); virtual void setInlineAttachment(bool inlineAttachment); + virtual bool isAttachment(); + virtual void setAttachment(bool attachment); + virtual AbstractPart * partForContentID(String * contentID); virtual AbstractPart * partForUniqueID(String * uniqueID); @@ -75,6 +78,7 @@ namespace mailcore { String * mContentLocation; String * mContentDescription; bool mInlineAttachment; + bool mAttachment; PartType mPartType; HashMap * mContentTypeParameters; void init(); diff --git a/src/core/abstract/MCAddress.cpp b/src/core/abstract/MCAddress.cpp index 98b4d8ec..335bc68b 100644 --- a/src/core/abstract/MCAddress.cpp +++ b/src/core/abstract/MCAddress.cpp @@ -213,6 +213,9 @@ Array * Address::addressesWithNonEncodedRFC822String(String * string) String * Address::RFC822StringForAddresses(Array * addresses) { String * result = String::string(); + if (addresses == NULL) { + return result; + } for(unsigned int i = 0 ; i < addresses->count() ; i ++) { Address * address = (Address *) addresses->objectAtIndex(i); if (i != 0) { @@ -226,6 +229,9 @@ String * Address::RFC822StringForAddresses(Array * addresses) String * Address::nonEncodedRFC822StringForAddresses(Array * addresses) { String * result = String::string(); + if (addresses == NULL) { + return result; + } for(unsigned int i = 0 ; i < addresses->count() ; i ++) { Address * address = (Address *) addresses->objectAtIndex(i); if (i != 0) { diff --git a/src/core/abstract/MCErrorMessage.cpp b/src/core/abstract/MCErrorMessage.cpp index c7205d42..bbe65eb1 100644 --- a/src/core/abstract/MCErrorMessage.cpp +++ b/src/core/abstract/MCErrorMessage.cpp @@ -15,35 +15,37 @@ static const char * localizedDescriptionTable[] = { "MobileMe is no longer an active mail service.", /** MCOErrorMobileMeMoved */ "Yahoo!'s servers are currently unavailable.", /** MCOErrorYahooUnavailable */ "The requested folder does not exist. Folder selection failed", /** MCOErrorNonExistantFolder */ - "An error occured while renaming the requested folder.", /** MCOErrorRename */ - "An error occured while deleting the requested folder.", /** MCOErrorDelete */ - "An error occured while creating the requested folder.", /** MCOErrorCreate */ - "An error occured while (un)subscribing to the requested folder.", /** MCOErrorSubscribe */ - "An error occured while appending a message to the requested folder.", /** MCOErrorAppend */ - "An error occured while copying a message to the requested folder.", /** MCOErrorCopy */ - "An error occured while expunging a message in the requested folder.", /** MCOErrorExpunge */ - "An error occured while fetching messages in the requested folder.", /** MCOErrorFetch */ - "An error occured during an IDLE operation.", /** MCOErrorIdle */ - "An error occured while requesting the server's identity.", /** MCOErrorIdentity */ - "An error occured while requesting the server's namespace.", /** MCOErrorNamespace */ - "An error occured while storing flags.", /** MCOErrorStore */ - "An error occured while requesting the server's capabilities.", /** MCOErrorCapability */ + "An error occurred while renaming the requested folder.", /** MCOErrorRename */ + "An error occurred while deleting the requested folder.", /** MCOErrorDelete */ + "An error occurred while creating the requested folder.", /** MCOErrorCreate */ + "An error occurred while (un)subscribing to the requested folder.", /** MCOErrorSubscribe */ + "An error occurred while appending a message to the requested folder.", /** MCOErrorAppend */ + "An error occurred while copying a message to the requested folder.", /** MCOErrorCopy */ + "An error occurred while expunging a message in the requested folder.", /** MCOErrorExpunge */ + "An error occurred while fetching messages in the requested folder.", /** MCOErrorFetch */ + "An error occurred during an IDLE operation.", /** MCOErrorIdle */ + "An error occurred while requesting the server's identity.", /** MCOErrorIdentity */ + "An error occurred while requesting the server's namespace.", /** MCOErrorNamespace */ + "An error occurred while storing flags.", /** MCOErrorStore */ + "An error occurred while requesting the server's capabilities.", /** MCOErrorCapability */ "The server does not support STARTTLS connections.", /** MCOErrorStartTLSNotAvailable */ "Attempted to send a message with an illegal attachment.", /** MCOErrorSendMessageIllegalAttachment */ "The SMTP storage limit was hit while trying to send a large message.", /** MCOErrorStorageLimit */ "Sending messages is not allowed on this server.", /** MCOErrorSendMessageNotAllowed */ "The current HotMail account cannot connect to WebMail.", /** MCOErrorNeedsConnectToWebmail */ - "An error occured while sending the message.", /** MCOErrorSendMessage */ + "An error occurred while sending the message.", /** MCOErrorSendMessage */ "Authentication is required for this SMTP server.", /** MCOErrorAuthenticationRequired */ - "An error occured while fetching a message list on the POP server.", /** MCOErrorFetchMessageList */ - "An error occured while deleting a message on the POP server.", /** MCOErrorDeleteMessage */ + "An error occurred while fetching a message list on the POP server.", /** MCOErrorFetchMessageList */ + "An error occurred while deleting a message on the POP server.", /** MCOErrorDeleteMessage */ "Account check failed because the account is invalid.", /** MCOErrorInvalidAccount */ "File access error", /** MCOErrorFile */ "Compression is not available", /** MCOErrorCompression */ "A sender is required to send message", /** MCOErrorNoSender */ "A recipient is required to send message", /** MCOErrorNoRecipient */ - "An error occured while performing a No-Op operation.", /** MCOErrorNoop */ + "An error occurred while performing a No-Op operation.", /** MCOErrorNoop */ "An application specific password is required", /** MCOErrorGmailApplicationSpecificPasswordRequired */ + "An error when requesting date", /** MCOErrorServerDate */ + "No valid server found", /** MCOErrorNoValidServerFound */ }; String * mailcore::errorMessageWithErrorCode(ErrorCode errorCode) diff --git a/src/core/abstract/MCMessageConstants.h b/src/core/abstract/MCMessageConstants.h index 1c489583..7d7403da 100644 --- a/src/core/abstract/MCMessageConstants.h +++ b/src/core/abstract/MCMessageConstants.h @@ -180,6 +180,7 @@ namespace mailcore { IMAPSearchKindContent, IMAPSearchKindBody, IMAPSearchKindUIDs, + IMAPSearchKindNumbers, IMAPSearchKindHeader, IMAPSearchKindRead, IMAPSearchKindUnread, @@ -250,6 +251,8 @@ namespace mailcore { ErrorNoop, ErrorGmailApplicationSpecificPasswordRequired, // 40 ErrorServerDate, + ErrorNoValidServerFound, + ErrorCustomCommand, }; enum PartType { diff --git a/src/core/abstract/MCMessageHeader.cpp b/src/core/abstract/MCMessageHeader.cpp index e65695ca..63675be5 100644 --- a/src/core/abstract/MCMessageHeader.cpp +++ b/src/core/abstract/MCMessageHeader.cpp @@ -721,12 +721,7 @@ struct mailimf_fields * MessageHeader::createIMFFieldsAndFilterBcc(bool filterBc 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 */, @@ -985,6 +980,7 @@ Array * MessageHeader::recipientWithReplyAll(bool replyAll, bool includeTo, bool Array * toField; Array * ccField; bool containsSender; + Array * senderEmailsMailboxes; toField = NULL; ccField = NULL; @@ -992,19 +988,23 @@ Array * MessageHeader::recipientWithReplyAll(bool replyAll, bool includeTo, bool hasTo = false; hasCc = false; addedAddresses = new Set(); - + senderEmailsMailboxes = Array::array(); + containsSender = false; if (senderEmails != NULL) { - if (from() != NULL) { - if (senderEmails->containsObject(from()->mailbox()->lowercaseString())) { - containsSender = true; + mc_foreacharray(Address, address, senderEmails) { + senderEmailsMailboxes->addObject(address->mailbox()->lowercaseString()); } - } - if (sender() != NULL) { - if (senderEmails->containsObject(sender()->mailbox()->lowercaseString())) { - containsSender = true; + if (from() != NULL) { + if (senderEmailsMailboxes->containsObject(from()->mailbox()->lowercaseString())) { + containsSender = true; + } + } + if (sender() != NULL) { + if (senderEmailsMailboxes->containsObject(sender()->mailbox()->lowercaseString())) { + containsSender = true; + } } - } } if (containsSender) { @@ -1019,12 +1019,14 @@ Array * MessageHeader::recipientWithReplyAll(bool replyAll, bool includeTo, bool } 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; + if (replyTo() != NULL) { + 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()); } - addedAddresses->addObject(rtAddress->mailbox()->lowercaseString()); } } else { @@ -1066,7 +1068,7 @@ Array * MessageHeader::recipientWithReplyAll(bool replyAll, bool includeTo, bool } } else { - addedAddresses->addObjectsFromArray(senderEmails); + addedAddresses->addObjectsFromArray(senderEmailsMailboxes); if (replyTo() != NULL && replyTo()->count() > 0) { hasTo = true; @@ -1152,7 +1154,12 @@ MessageHeader * MessageHeader::replyHeader(bool replyAll, Array * addressesExclu subjectValue = MCSTR("Re: "); } else { - subjectValue = MCSTR("Re: ")->stringByAppendingString(subject()); + if (!subject()->lowercaseString()->hasPrefix(MCSTR("re:"))) { + subjectValue = MCSTR("Re: ")->stringByAppendingString(subject()); + } + else { + subjectValue = (String *) subject()->copy()->autorelease(); + } } if (references() != NULL) { referencesValue = (Array *) (references()->copy()); @@ -1193,7 +1200,7 @@ MessageHeader * MessageHeader::forwardHeader() subjectValue = MCSTR("Fw: "); } else { - subjectValue = MCSTR("Fw: ")->stringByAppendingString(subject()); + subjectValue = MCSTR("Fw: ")->stringByAppendingString(subject()->extractedSubjectAndKeepBracket(true)); } if (references() != NULL) { referencesValue = (Array *) (references()->copy()); diff --git a/src/core/basetypes/MCAssert.c b/src/core/basetypes/MCAssert.c index ce9b5703..564f1648 100644 --- a/src/core/basetypes/MCAssert.c +++ b/src/core/basetypes/MCAssert.c @@ -9,6 +9,6 @@ void MCAssertInternal(const char * filename, unsigned int line, int cond, const return; } - fprintf(stderr, "%s:%i: assert %s\n", filename, line, condString); + fprintf(stderr, "%s:%u: assert %s\n", filename, line, condString); abort(); } diff --git a/src/core/basetypes/MCBaseTypes.h b/src/core/basetypes/MCBaseTypes.h index ce3e1153..3088d4c2 100644 --- a/src/core/basetypes/MCBaseTypes.h +++ b/src/core/basetypes/MCBaseTypes.h @@ -26,5 +26,6 @@ #include <MailCore/MCICUTypes.h> #include <MailCore/MCIterator.h> #include <MailCore/MCConnectionLogger.h> +#include <MailCore/MCHTMLCleaner.h> #endif diff --git a/src/core/basetypes/MCData.cpp b/src/core/basetypes/MCData.cpp index 8b689036..079344da 100644 --- a/src/core/basetypes/MCData.cpp +++ b/src/core/basetypes/MCData.cpp @@ -718,6 +718,20 @@ void Data::importSerializable(HashMap * serializable) setData(((String *) (serializable->objectForKey(MCSTR("data"))))->decodedBase64Data()); } +ErrorCode Data::writeToFile(String * filename) +{ + FILE * f = fopen(filename->fileSystemRepresentation(), "wb"); + if (f == NULL) { + return ErrorFile; + } + size_t result = fwrite(bytes(), length(), 1, f); + fclose(f); + if (result == 0) { + return ErrorFile; + } + return ErrorNone; +} + #if __APPLE__ static CFStringEncoding encodingFromCString(const char * charset) { diff --git a/src/core/basetypes/MCData.h b/src/core/basetypes/MCData.h index bec75008..0bb1bc07 100644 --- a/src/core/basetypes/MCData.h +++ b/src/core/basetypes/MCData.h @@ -44,6 +44,8 @@ namespace mailcore { virtual Data * decodedDataUsingEncoding(Encoding encoding); virtual String * base64String(); + + virtual ErrorCode writeToFile(String * filename); public: // private virtual String * charsetWithFilteredHTML(bool filterHTML, String * hintCharset = NULL); diff --git a/src/core/basetypes/MCHTMLCleaner.h b/src/core/basetypes/MCHTMLCleaner.h index 33e65767..eccf88c9 100644 --- a/src/core/basetypes/MCHTMLCleaner.h +++ b/src/core/basetypes/MCHTMLCleaner.h @@ -13,6 +13,8 @@ #include <MailCore/MCString.h> #include <MailCore/MCUtils.h> +#ifdef __cplusplus + namespace mailcore { class MAILCORE_EXPORT HTMLCleaner { @@ -23,3 +25,5 @@ namespace mailcore { } #endif + +#endif diff --git a/src/core/basetypes/MCHashMap.cpp b/src/core/basetypes/MCHashMap.cpp index c56277fc..9958c502 100644 --- a/src/core/basetypes/MCHashMap.cpp +++ b/src/core/basetypes/MCHashMap.cpp @@ -169,6 +169,10 @@ void HashMap::removeObjectForKey(Object * key) { unsigned int func, indx; HashMapIter * iter, * old; + + if (key == NULL) { + return; + } func = key->hash();; indx = func % mAllocated; diff --git a/src/core/basetypes/MCIndexSet.cpp b/src/core/basetypes/MCIndexSet.cpp index 7f7e1db3..191a1588 100644 --- a/src/core/basetypes/MCIndexSet.cpp +++ b/src/core/basetypes/MCIndexSet.cpp @@ -398,6 +398,21 @@ void IndexSet::importSerializable(HashMap * serializable) } } +bool IndexSet::isEqual(Object * otherObject) +{ + IndexSet * otherIndexSet = (IndexSet *) otherObject; + if (mCount != otherIndexSet->mCount) { + return false; + } + for(unsigned int i = 0 ; i < mCount ; i ++) { + if ((mRanges[i].location != otherIndexSet->mRanges[i].location) || + (mRanges[i].length != otherIndexSet->mRanges[i].length)) { + return false; + } + } + return true; +} + void IndexSet::addIndexSet(IndexSet * indexSet) { for(unsigned int i = 0 ; i < indexSet->rangesCount() ; i ++) { @@ -435,3 +450,52 @@ INITIALIZE(IndexSet) { Object::registerObjectConstructor("mailcore::IndexSet", &createObject); } + +/* + +Unit test: + +String * uidsStr = MCSTR("129597-129662,129664,129667-129671,129673-129674,129678-129694,129696-129804"); +String * cachedUidsStr = MCSTR("129755-129804"); +IndexSet * uids = NULL; +IndexSet * cachedUids = NULL; + +{ + IndexSet * result = new IndexSet(); + Array * array = uidsStr->componentsSeparatedByString(MCSTR(",")); + mc_foreacharray(String, rangeStr, array) { + Array * rangeArray = rangeStr->componentsSeparatedByString(MCSTR("-")); + if (rangeArray->count() == 2) { + int left = ((String *) rangeArray->objectAtIndex(0))->intValue(); + int right = ((String *) rangeArray->objectAtIndex(1))->intValue(); + int length = right - left; + result->addRange(RangeMake(left, length)); + } + else { + result->addIndex(rangeStr->intValue()); + } + } + //fprintf(stderr, "%s\n", MCUTF8DESC(result)); + uids = result; +} +{ + IndexSet * result = new IndexSet(); + Array * array = cachedUidsStr->componentsSeparatedByString(MCSTR(",")); + mc_foreacharray(String, rangeStr, array) { + Array * rangeArray = rangeStr->componentsSeparatedByString(MCSTR("-")); + if (rangeArray->count() == 2) { + int left = ((String *) rangeArray->objectAtIndex(0))->intValue(); + int right = ((String *) rangeArray->objectAtIndex(1))->intValue(); + int length = right - left; + result->addRange(RangeMake(left, length)); + } + else { + result->addIndex(rangeStr->intValue()); + } + } + cachedUids = result; +} +fprintf(stderr, "|%s|\n", MCUTF8DESC(uids)); +uids->removeIndexSet(cachedUids); +fprintf(stderr, "|%s|\n", MCUTF8DESC(uids)); +*/ diff --git a/src/core/basetypes/MCIndexSet.h b/src/core/basetypes/MCIndexSet.h index 2e2f4892..2cf67b07 100644 --- a/src/core/basetypes/MCIndexSet.h +++ b/src/core/basetypes/MCIndexSet.h @@ -50,7 +50,8 @@ namespace mailcore { virtual Object * copy(); virtual HashMap * serializable(); virtual void importSerializable(HashMap * serializable); - + virtual bool isEqual(Object * otherObject); + private: Range * mRanges; unsigned int mCount; diff --git a/src/core/basetypes/MCJSONParser.cpp b/src/core/basetypes/MCJSONParser.cpp index d9f68204..cfddbf9e 100644 --- a/src/core/basetypes/MCJSONParser.cpp +++ b/src/core/basetypes/MCJSONParser.cpp @@ -587,7 +587,7 @@ bool JSONParser::parseFloat() } else { mPosition += endptr - str; - mResult = Value::valueWithDoubleValue(value); + mResult = Value::valueWithDoubleValue(value)->retain(); } pool->release(); @@ -617,7 +617,9 @@ Object * JSONParser::objectFromString(String * str) parser->setContent(str); parser->parse(); result = parser->result(); - result->retain()->autorelease(); + if (result != NULL) { + result->retain()->autorelease(); + } parser->release(); return result; diff --git a/src/core/basetypes/MCLog.cpp b/src/core/basetypes/MCLog.cpp index 952229ec..386ac422 100644 --- a/src/core/basetypes/MCLog.cpp +++ b/src/core/basetypes/MCLog.cpp @@ -53,9 +53,7 @@ static void logInternalv(FILE * file, return; while (1) { - const char * p = filename; - - p = strchr(filename, '/'); + const char * p = strchr(filename, '/'); if (p == NULL) { break; } @@ -80,7 +78,7 @@ static void logInternalv(FILE * file, #else if (0) { #endif - fprintf(file, "[%i:main] %s:%i: ", sPid, filename, line); + fprintf(file, "[%i:main] %s:%u: ", sPid, filename, line); } else { unsigned long threadValue; @@ -91,7 +89,7 @@ static void logInternalv(FILE * file, #else threadValue = (unsigned long) thread_id; #endif - fprintf(file, "[%i:%lx] %s:%i: ", sPid, threadValue, filename, line); + fprintf(file, "[%i:%lx] %s:%u: ", sPid, threadValue, filename, line); } vfprintf(file, format, argp); fprintf(file, "\n"); diff --git a/src/core/basetypes/MCObject.cpp b/src/core/basetypes/MCObject.cpp index bbcddb2f..6f776ef6 100644 --- a/src/core/basetypes/MCObject.cpp +++ b/src/core/basetypes/MCObject.cpp @@ -181,7 +181,7 @@ static void removeFromPerformHash(Object * obj, Object::Method method, void * co keyData.method = method; key.data = &keyData; key.len = sizeof(keyData); - + pthread_mutex_lock(&delayedPerformLock); chash_delete(delayedPerformHash, (chashdatum *) &key, NULL); pthread_mutex_unlock(&delayedPerformLock); @@ -360,7 +360,9 @@ void Object::performMethodOnDispatchQueueAfterDelay(Method method, void * contex } dupCancelableBlock(false); Block_release(dupCancelableBlock); - release(); + if (!cancelled) { + release(); + } }); } @@ -373,6 +375,7 @@ void Object::cancelDelayedPerformMethodOnDispatchQueue(Method method, void * con } removeFromPerformHash(this, method, context, targetDispatchQueue); dupCancelableBlock(true); + release(); } #endif diff --git a/src/core/basetypes/MCString.cpp b/src/core/basetypes/MCString.cpp index 213d5e5f..9c024067 100644 --- a/src/core/basetypes/MCString.cpp +++ b/src/core/basetypes/MCString.cpp @@ -823,7 +823,9 @@ String::String(const char * UTF8Characters) { mUnicodeChars = NULL; reset(); - allocate((unsigned int) strlen(UTF8Characters), true); + if (UTF8Characters != NULL) { + allocate((unsigned int) strlen(UTF8Characters), true); + } appendUTF8Characters(UTF8Characters); } @@ -890,7 +892,7 @@ void String::allocate(unsigned int length, bool force) String * String::string() { - return stringWithCharacters(NULL); + return stringWithCharacters(NULL, 0); } String * String::stringWithData(Data * data, const char * charset) @@ -926,12 +928,18 @@ String * String::stringWithVUTF8Format(const char * format, va_list ap) String * String::stringWithUTF8Characters(const char * UTF8Characters) { + if (UTF8Characters == NULL) { + return NULL; + } String * result = new String(UTF8Characters); return (String *) result->autorelease(); } String * String::stringWithCharacters(const UChar * characters) { + if (characters == NULL) { + return NULL; + } String * result = new String(characters); return (String *) result->autorelease(); } @@ -1194,6 +1202,9 @@ Data * String::encodedMIMEHeaderValueForSubject() int String::compareWithCaseSensitive(String * otherString, bool caseSensitive) { + if (otherString == NULL) { + return 1; + } if ((length() == 0) && (otherString->length() == 0)) { return 0; } @@ -1206,7 +1217,7 @@ int String::compareWithCaseSensitive(String * otherString, bool caseSensitive) } if (otherString->unicodeCharacters() == NULL) { - return -1; + return 1; } #if DISABLE_ICU @@ -2034,25 +2045,69 @@ String * String::flattenHTML() String * String::stripWhitespace() { - String *str = (String *)copy(); - - str->replaceOccurrencesOfString(MCSTR("\t"), MCSTR(" ")); - str->replaceOccurrencesOfString(MCSTR("\n"), MCSTR(" ")); - str->replaceOccurrencesOfString(MCSTR("\v"), MCSTR(" ")); - str->replaceOccurrencesOfString(MCSTR("\f"), MCSTR(" ")); - str->replaceOccurrencesOfString(MCSTR("\r"), MCSTR(" ")); - str->replaceOccurrencesOfString(s_unicode160, MCSTR(" ")); - str->replaceOccurrencesOfString(s_unicode133, MCSTR(" ")); - str->replaceOccurrencesOfString(s_unicode2028, MCSTR(" ")); + String * str = (String *)copy(); - while (str->replaceOccurrencesOfString(MCSTR(" "), MCSTR(" ")) > 0) { - /* do nothing */ + // replace space-like characters with space. + const UChar * source = str->unicodeCharacters(); + UChar * dest = str->mUnicodeChars; + while (* source != 0) { + if (* source == '\t') { + * dest = ' '; + } + else if (* source == '\n') { + * dest = ' '; + } + else if (* source == '\t') { + * dest = ' '; + } + else if (* source == '\f') { + * dest = ' '; + } + else if (* source == '\r') { + * dest = ' '; + } + else if (* source == 160) { + * dest = ' '; + } + else if (* source == 133) { + * dest = ' '; + } + else if (* source == 0x2028) { + * dest = ' '; + } + else { + * dest = * source; + } + dest ++; + source ++; } - while (str->hasPrefix(MCSTR(" "))) { - str->deleteCharactersInRange(RangeMake(0, 1)); + + // skip spaces at the beginning. + source = str->unicodeCharacters(); + dest = str->mUnicodeChars; + while (* source == ' ') { + source ++; } - while (str->hasSuffix(MCSTR(" "))) { - str->deleteCharactersInRange(RangeMake(str->length() - 1, 1)); + + // copy content + while (* source != 0) { + if ((* source == ' ') && (* (source + 1) == ' ')) { + source ++; + } + * dest = * source; + source ++; + dest ++; + } + * dest = 0; + str->mLength = (unsigned int) (dest - str->mUnicodeChars); + + // skip spaces at the end. + if (str->mLength > 0) { + while (* (dest - 1) == ' ') { + dest --; + } + * dest = 0; + str->mLength = (unsigned int) (dest - str->mUnicodeChars); } str->autorelease(); @@ -2241,10 +2296,29 @@ Array * String::componentsSeparatedByString(String * separator) p = mUnicodeChars; while (1) { UChar * location; +#if 0 location = u_strstr(p, separator->unicodeCharacters()); if (location == NULL) { break; } +#else + int remaining = length() - (int) (p - mUnicodeChars); + location = NULL; + while (location == NULL) { + location = (UChar *) memmem(p, remaining * sizeof(UChar), separator->unicodeCharacters(), separator->length() * sizeof(UChar)); + if (location == NULL) { + break; + } + // If it's odd, it's an invalid location. Keep looking for the pattern. + if (((char *) location - (char *) p) % sizeof(UChar) != 0) { + p = (UChar *) (((char *) location) + 1); + location = NULL; + } + } + if (location == NULL) { + break; + } +#endif unsigned int length = (unsigned int) (location - p); String * value = new String(p, length); @@ -2357,6 +2431,10 @@ String * String::uniquedStringWithUTF8Characters(const char * UTF8Characters) static pthread_once_t once = PTHREAD_ONCE_INIT; int r; + if (UTF8Characters == NULL) { + return NULL; + } + pthread_once(&once, initUniquedStringHash); key.data = (void *) UTF8Characters; key.len = (unsigned int) strlen(UTF8Characters); @@ -2512,6 +2590,102 @@ Data * String::decodedBase64Data() return result; } +static int hexValue(const char * code) { + int value = 0; + const char * pch = code; + for (;;) { + int digit = *pch++; + if (digit >= '0' && digit <= '9') { + value += digit - '0'; + } + else if (digit >= 'A' && digit <= 'F') { + value += digit - 'A' + 10; + } + else if (digit >= 'a' && digit <= 'f') { + value += digit - 'a' + 10; + } + else { + return -1; + } + if (pch == code + 2) { + return value; + } + value <<= 4; + } +} + +String * String::urlDecodedString() +{ + Data * sourceData = dataUsingEncoding(); + const char * source = sourceData->bytes(); + char * start = (char *) malloc(sourceData->length() + 1); + char * dest = start; + unsigned int i = 0; + while (i < sourceData->length()) { + switch (source[i]) { + case '%': + { + if (i + 2 < sourceData->length()) { + int value = hexValue(&source[i + 1]); + if (value >= 0) { + *(dest++) = value; + i += 3; + } + else { + *dest++ = '?'; + i ++; + } + } + else { + *dest++ = '?'; + i ++; + } + break; + } + default: + { + *dest++ = source[i]; + i ++; + break; + } + } + } + * dest = 0; + String * result = String::stringWithUTF8Characters(start); + free(start); + return result; +} + +static inline bool isValidUrlChar(char ch) { + return strchr("$&+,/:;=?@[]#!'()* ", ch) == NULL; +} + +String * String::urlEncodedString() +{ + const char * digits = "0123456789ABCDEF"; + Data * sourceData = dataUsingEncoding(); + const char * source = sourceData->bytes(); + char * start = (char *) malloc(sourceData->length() * 3 + 1); + char * dest = start; + unsigned int i = 0; + while (i < sourceData->length()) { + unsigned char ch = (unsigned char) source[i]; + if (isValidUrlChar(ch)) { + *dest++ = ch; + } else { + *dest++ = '%'; + *dest++ = digits[(ch >> 4) & 0x0F]; + *dest++ = digits[ ch & 0x0F]; + } + i ++; + } + *dest = 0; + String * result = String::stringWithUTF8Characters(dest); + free(start); + + return result; +} + HashMap * String::serializable() { HashMap * result = Object::serializable(); diff --git a/src/core/basetypes/MCString.h b/src/core/basetypes/MCString.h index cbe5538b..5ee2ad65 100644 --- a/src/core/basetypes/MCString.h +++ b/src/core/basetypes/MCString.h @@ -117,6 +117,9 @@ namespace mailcore { virtual Data * decodedBase64Data(); + virtual String * urlDecodedString(); + virtual String * urlEncodedString(); + public: // private static String * uniquedStringWithUTF8Characters(const char * UTF8Characters); diff --git a/src/core/basetypes/MCUtils.h b/src/core/basetypes/MCUtils.h index eb4ef290..ef8f3cd3 100644 --- a/src/core/basetypes/MCUtils.h +++ b/src/core/basetypes/MCUtils.h @@ -48,6 +48,20 @@ # define MAILCORE_EXPORT #endif +#ifdef __ANDROID_API__ +#if __ANDROID_API__ < 21 +#include <wchar.h> +extern int iswblank(wint_t); +extern int vfwscanf(FILE*, const wchar_t*, va_list); +extern int vswscanf(const wchar_t*, const wchar_t*, va_list); +extern int vwscanf(const wchar_t*, va_list); +extern float wcstof(const wchar_t*, wchar_t**); +extern long double wcstold(const wchar_t*, wchar_t**); +extern long long wcstoll(const wchar_t*, wchar_t**, int); +extern unsigned long long wcstoull(const wchar_t*, wchar_t**, int); +#endif +#endif + #ifdef __clang__ #if __has_feature(attribute_analyzer_noreturn) @@ -65,4 +79,8 @@ #endif +#ifndef DEPRECATED_ATTRIBUTE +#define DEPRECATED_ATTRIBUTE __attribute__((deprecated)) +#endif + #endif diff --git a/src/core/basetypes/icu-ucsdet/cstring.c b/src/core/basetypes/icu-ucsdet/cstring.c index 3af959eb..868ee5c0 100644 --- a/src/core/basetypes/icu-ucsdet/cstring.c +++ b/src/core/basetypes/icu-ucsdet/cstring.c @@ -225,7 +225,7 @@ U_CAPI int32_t U_EXPORT2 T_CString_stringToInteger(const char *integerString, int32_t radix) { char *end; - return uprv_strtoul(integerString, &end, radix); + return (int32_t)uprv_strtoul(integerString, &end, radix); } diff --git a/src/core/basetypes/icu-ucsdet/uinvchar.c b/src/core/basetypes/icu-ucsdet/uinvchar.c index f874edd9..81f73d80 100644 --- a/src/core/basetypes/icu-ucsdet/uinvchar.c +++ b/src/core/basetypes/icu-ucsdet/uinvchar.c @@ -569,7 +569,7 @@ uprv_aestrncpy(uint8_t *dst, const uint8_t *src, int32_t n) uint8_t *orig_dst = dst; if(n==-1) { - n = uprv_strlen((const char*)src)+1; /* copy NUL */ + n = (int32_t)uprv_strlen((const char*)src)+1; /* copy NUL */ } /* copy non-null */ while(*src && n>0) { @@ -590,7 +590,7 @@ uprv_eastrncpy(uint8_t *dst, const uint8_t *src, int32_t n) uint8_t *orig_dst = dst; if(n==-1) { - n = uprv_strlen((const char*)src)+1; /* copy NUL */ + n = (int32_t)uprv_strlen((const char*)src)+1; /* copy NUL */ } /* copy non-null */ while(*src && n>0) { diff --git a/src/core/basetypes/icu-ucsdet/ustring.cpp b/src/core/basetypes/icu-ucsdet/ustring.cpp index 40d23c06..d5d748fc 100644 --- a/src/core/basetypes/icu-ucsdet/ustring.cpp +++ b/src/core/basetypes/icu-ucsdet/ustring.cpp @@ -997,7 +997,7 @@ u_strlen(const UChar *s) while(*t != 0) { ++t; } - return t - s; + return (int32_t)(t - s); #endif } diff --git a/src/core/imap/MCIMAPMessage.cpp b/src/core/imap/MCIMAPMessage.cpp index 48139633..530d9075 100644 --- a/src/core/imap/MCIMAPMessage.cpp +++ b/src/core/imap/MCIMAPMessage.cpp @@ -26,6 +26,7 @@ void IMAPMessage::init() mModSeqValue = 0; mGmailThreadID = 0; mGmailMessageID = 0; + mSize = 0; } IMAPMessage::IMAPMessage() @@ -257,7 +258,7 @@ HashMap * IMAPMessage::serializable() HashMap * result = AbstractMessage::serializable(); result->setObjectForKey(MCSTR("modSeqValue"), String::stringWithUTF8Format("%llu", (long long unsigned) modSeqValue())); result->setObjectForKey(MCSTR("uid"), String::stringWithUTF8Format("%lu", (long unsigned) uid())); - result->setObjectForKey(MCSTR("size"), String::stringWithUTF8Format("%lu", (long unsigned) uid())); + result->setObjectForKey(MCSTR("size"), String::stringWithUTF8Format("%lu", (long unsigned) size())); result->setObjectForKey(MCSTR("flags"), String::stringWithUTF8Format("%u", (unsigned) flags())); result->setObjectForKey(MCSTR("originalFlags"), String::stringWithUTF8Format("%u", (unsigned) originalFlags())); if (customFlags() != NULL) { @@ -300,7 +301,7 @@ void IMAPMessage::importSerializable(HashMap * serializable) } String * originalFlags = (String *) serializable->objectForKey(MCSTR("originalFlags")); if (originalFlags != NULL) { - setFlags((MessageFlag) originalFlags->unsignedIntValue()); + setOriginalFlags((MessageFlag) originalFlags->unsignedIntValue()); } String * customFlags = (String *) serializable->objectForKey(MCSTR("customFlags")); if (customFlags != NULL) { diff --git a/src/core/imap/MCIMAPNamespace.cpp b/src/core/imap/MCIMAPNamespace.cpp index 09037877..d5c618a0 100644 --- a/src/core/imap/MCIMAPNamespace.cpp +++ b/src/core/imap/MCIMAPNamespace.cpp @@ -142,3 +142,16 @@ void IMAPNamespace::importIMAPNamespace(struct mailimap_namespace_item * item) item->release(); } } + +HashMap * IMAPNamespace::serializable() +{ + HashMap * result = Object::serializable(); + result->setObjectForKey(MCSTR("items"), mItems->serializable()); + return result; +} + +void IMAPNamespace::importSerializable(HashMap * serializable) +{ + Array * items = (Array *) Object::objectWithSerializable((HashMap *) serializable->objectForKey(MCSTR("items"))); + MC_SAFE_REPLACE_RETAIN(Array, mItems, items); +} diff --git a/src/core/imap/MCIMAPNamespace.h b/src/core/imap/MCIMAPNamespace.h index e57cecba..711fb7e5 100644 --- a/src/core/imap/MCIMAPNamespace.h +++ b/src/core/imap/MCIMAPNamespace.h @@ -33,7 +33,9 @@ namespace mailcore { IMAPNamespace(IMAPNamespace * other); virtual String * description(); virtual Object * copy(); - + virtual HashMap * serializable(); + virtual void importSerializable(HashMap * serializable); + private: Array * /* String */ mItems; void init(); diff --git a/src/core/imap/MCIMAPNamespaceItem.cpp b/src/core/imap/MCIMAPNamespaceItem.cpp index c985e915..c8561c50 100644 --- a/src/core/imap/MCIMAPNamespaceItem.cpp +++ b/src/core/imap/MCIMAPNamespaceItem.cpp @@ -150,3 +150,23 @@ static Array * decodedComponents(Array * components) return result; } + +HashMap * IMAPNamespaceItem::serializable() +{ + HashMap * result = Object::serializable(); + result->setObjectForKey(MCSTR("delimiter"), String::stringWithUTF8Format("%c", mDelimiter)); + if (mPrefix != NULL) { + result->setObjectForKey(MCSTR("prefix"), mPrefix); + } + return result; +} + +void IMAPNamespaceItem::importSerializable(HashMap * serializable) +{ + String * aPrefix = (String *) serializable->objectForKey(MCSTR("prefix")); + setPrefix(aPrefix); + String * delimiterString = (String *) serializable->objectForKey(MCSTR("delimiter")); + if ((delimiterString != NULL) && (delimiterString->length() > 0)) { + setDelimiter((char) delimiterString->characterAtIndex(0)); + } +} diff --git a/src/core/imap/MCIMAPNamespaceItem.h b/src/core/imap/MCIMAPNamespaceItem.h index 3ca8e485..0fffed98 100644 --- a/src/core/imap/MCIMAPNamespaceItem.h +++ b/src/core/imap/MCIMAPNamespaceItem.h @@ -28,7 +28,9 @@ namespace mailcore { IMAPNamespaceItem(IMAPNamespaceItem * other); virtual String * description(); virtual Object * copy(); - + virtual HashMap * serializable(); + virtual void importSerializable(HashMap * serializable); + private: char mDelimiter; String * mPrefix; diff --git a/src/core/imap/MCIMAPSearchExpression.cpp b/src/core/imap/MCIMAPSearchExpression.cpp index b3467e59..8d6b1f0b 100644 --- a/src/core/imap/MCIMAPSearchExpression.cpp +++ b/src/core/imap/MCIMAPSearchExpression.cpp @@ -9,6 +9,7 @@ void IMAPSearchExpression::init() mValue = NULL; mLongNumber = 0; mUids = NULL; + mNumbers = NULL; mLeftExpression = NULL; mRightExpression = NULL; } @@ -26,6 +27,7 @@ IMAPSearchExpression::IMAPSearchExpression(IMAPSearchExpression * other) MC_SAFE_REPLACE_COPY(String, mHeader, other->mHeader); MC_SAFE_REPLACE_COPY(String, mValue, other->mValue); MC_SAFE_REPLACE_COPY(IndexSet, mUids, other->mUids); + MC_SAFE_REPLACE_COPY(IndexSet, mNumbers, other->mNumbers); MC_SAFE_REPLACE_COPY(IMAPSearchExpression, mLeftExpression, other->mLeftExpression); MC_SAFE_REPLACE_COPY(IMAPSearchExpression, mRightExpression, other->mRightExpression); } @@ -35,6 +37,7 @@ IMAPSearchExpression::~IMAPSearchExpression() MC_SAFE_RELEASE(mHeader); MC_SAFE_RELEASE(mValue); MC_SAFE_RELEASE(mUids); + MC_SAFE_RELEASE(mNumbers); MC_SAFE_RELEASE(mLeftExpression); MC_SAFE_RELEASE(mRightExpression); } @@ -68,6 +71,9 @@ String * IMAPSearchExpression::description() case IMAPSearchKindUIDs: return String::stringWithUTF8Format("<%s:%p UIDs %s>", MCUTF8(className()), this, MCUTF8(mUids->description())); + case IMAPSearchKindNumbers: + return String::stringWithUTF8Format("<%s:%p Numbers %s>", MCUTF8(className()), this, + MCUTF8(mNumbers->description())); case IMAPSearchKindContent: return String::stringWithUTF8Format("<%s:%p Content %s>", MCUTF8(className()), this, MCUTF8(mValue->description())); @@ -170,6 +176,13 @@ IMAPSearchExpression * IMAPSearchExpression::searchUIDs(IndexSet * uids) return (IMAPSearchExpression *) expr->autorelease(); } +IMAPSearchExpression * IMAPSearchExpression::searchNumbers(IndexSet * numbers) +{ + IMAPSearchExpression * expr = new IMAPSearchExpression(); + expr->mKind = IMAPSearchKindNumbers; + MC_SAFE_REPLACE_COPY(IndexSet, expr->mNumbers, numbers); + return (IMAPSearchExpression *) expr->autorelease(); +} IMAPSearchExpression * IMAPSearchExpression::searchHeader(String * header, String * value) { @@ -393,6 +406,11 @@ IndexSet * IMAPSearchExpression::uids() return mUids; } +IndexSet * IMAPSearchExpression::numbers() +{ + return mNumbers; +} + IMAPSearchExpression * IMAPSearchExpression::leftExpression() { return mLeftExpression; diff --git a/src/core/imap/MCIMAPSearchExpression.h b/src/core/imap/MCIMAPSearchExpression.h index 6f1f4ea0..182f3013 100644 --- a/src/core/imap/MCIMAPSearchExpression.h +++ b/src/core/imap/MCIMAPSearchExpression.h @@ -20,6 +20,7 @@ namespace mailcore { virtual uint64_t longNumber(); virtual time_t date(); virtual IndexSet * uids(); + virtual IndexSet * numbers(); virtual IMAPSearchExpression * leftExpression(); @@ -36,6 +37,7 @@ namespace mailcore { static IMAPSearchExpression * searchBody(String * value); static IMAPSearchExpression * searchHeader(String * header, String * value); static IMAPSearchExpression * searchUIDs(IndexSet * uids); + static IMAPSearchExpression * searchNumbers(IndexSet * numbers); static IMAPSearchExpression * searchRead(); static IMAPSearchExpression * searchUnread(); static IMAPSearchExpression * searchFlagged(); @@ -73,6 +75,7 @@ namespace mailcore { String * mValue; uint64_t mLongNumber; IndexSet * mUids; + IndexSet * mNumbers; IMAPSearchExpression * mLeftExpression; IMAPSearchExpression * mRightExpression; void init(); diff --git a/src/core/imap/MCIMAPSession.cpp b/src/core/imap/MCIMAPSession.cpp index 854bddec..93427d8d 100755 --- a/src/core/imap/MCIMAPSession.cpp +++ b/src/core/imap/MCIMAPSession.cpp @@ -627,6 +627,10 @@ void IMAPSession::connect(ErrorCode * pError) if (mImap->imap_response != NULL) { MC_SAFE_REPLACE_RETAIN(String, mWelcomeString, String::stringWithUTF8Characters(mImap->imap_response)); mYahooServer = (mWelcomeString->locationOfString(MCSTR("yahoo.com")) != -1); +#ifdef LIBETPAN_HAS_MAILIMAP_163_WORKAROUND + if(mWelcomeString->locationOfString(MCSTR("Coremail System IMap Server Ready")) != -1) + mailimap_set_163_workaround_enabled(mImap, 1); +#endif } mState = STATE_CONNECTED; @@ -789,7 +793,12 @@ void IMAPSession::login(ErrorCode * pError) case AuthTypeXOAuth2: case AuthTypeXOAuth2Outlook: - r = mailimap_oauth2_authenticate(mImap, utf8username, MCUTF8(mOAuth2Token)); + if (mOAuth2Token == NULL) { + r = MAILIMAP_ERROR_STREAM; + } + else { + r = mailimap_oauth2_authenticate(mImap, utf8username, MCUTF8(mOAuth2Token)); + } break; } if (r == MAILIMAP_ERROR_STREAM) { @@ -987,6 +996,33 @@ static uint64_t get_mod_sequence_value(mailimap * session) return mod_sequence_value; } +String * IMAPSession::customCommand(String * command, ErrorCode * pError) +{ + int r; + + loginIfNeeded(pError); + if (* pError != ErrorNone) + return NULL; + + r = mailimap_custom_command(mImap, MCUTF8(command)); + if (r == MAILIMAP_ERROR_STREAM) { + mShouldDisconnect = true; + * pError = ErrorConnection; + return NULL; + } + else if (r == MAILIMAP_ERROR_PARSE) { + * pError = ErrorParse; + return NULL; + } + else if (hasError(r)) { + * pError = ErrorCustomCommand; + return NULL; + } + + String *response = String::stringWithUTF8Characters(mImap->imap_response); + return response; +} + void IMAPSession::select(String * folder, ErrorCode * pError) { int r; @@ -1088,14 +1124,17 @@ IMAPFolderStatus * IMAPSession::folderStatus(String * folder, ErrorCode * pError mShouldDisconnect = true; * pError = ErrorConnection; MCLog("status error : %s %i", MCUTF8DESC(this), * pError); + mailimap_status_att_list_free(status_att_list); return fs; } else if (r == MAILIMAP_ERROR_PARSE) { * pError = ErrorParse; + mailimap_status_att_list_free(status_att_list); return fs; } else if (hasError(r)) { * pError = ErrorNonExistantFolder; + mailimap_status_att_list_free(status_att_list); return fs; } @@ -1141,7 +1180,7 @@ IMAPFolderStatus * IMAPSession::folderStatus(String * folder, ErrorCode * pError } mailimap_status_att_list_free(status_att_list); - + mailimap_mailbox_data_status_free(status); return fs; } @@ -1574,7 +1613,6 @@ void IMAPSession::appendMessageWithCustomFlagsAndDate(String * folder, Data * me mProgressCallback = progressCallback; bodyProgress(0, messageData->length()); - flag_list = NULL; flag_list = flags_to_lep(flags); if (customFlags != NULL) { for (unsigned int i = 0 ; i < customFlags->count() ; i ++) { @@ -2791,6 +2829,10 @@ static struct mailimap_search_key * searchKeyFromSearchExpression(IMAPSearchExpr { return mailimap_search_key_new_uid(setFromIndexSet(expression->uids())); } + case IMAPSearchKindNumbers: + { + return mailimap_search_key_new_set(setFromIndexSet(expression->numbers())); + } case IMAPSearchKindHeader: { return mailimap_search_key_new_header(strdup(expression->header()->UTF8Characters()), strdup(expression->value()->UTF8Characters())); diff --git a/src/core/imap/MCIMAPSession.h b/src/core/imap/MCIMAPSession.h index d0a310b7..5ee6bc1c 100755 --- a/src/core/imap/MCIMAPSession.h +++ b/src/core/imap/MCIMAPSession.h @@ -107,6 +107,7 @@ namespace mailcore { IndexSet * numbers, IMAPProgressCallback * progressCallback, Array * extraHeaders, ErrorCode * pError); + virtual String * customCommand(String * command, ErrorCode * pError); virtual Data * fetchMessageByUID(String * folder, uint32_t uid, IMAPProgressCallback * progressCallback, ErrorCode * pError); @@ -177,7 +178,7 @@ namespace mailcore { virtual bool isCompressionEnabled(); virtual bool allowsNewPermanentFlags(); - virtual String * gmailUserDisplayName(); + virtual String * gmailUserDisplayName() DEPRECATED_ATTRIBUTE; virtual void setConnectionLogger(ConnectionLogger * logger); virtual ConnectionLogger * connectionLogger(); diff --git a/src/core/nntp/MCNNTPGroupInfo.cpp b/src/core/nntp/MCNNTPGroupInfo.cpp index 787967f3..8ebe08bc 100644 --- a/src/core/nntp/MCNNTPGroupInfo.cpp +++ b/src/core/nntp/MCNNTPGroupInfo.cpp @@ -13,10 +13,12 @@ using namespace mailcore; void NNTPGroupInfo::init() { mMessageCount = 0; + mName = NULL; } NNTPGroupInfo::NNTPGroupInfo() { + MC_SAFE_RELEASE(mName); init(); } diff --git a/src/core/nntp/MCNNTPSession.cpp b/src/core/nntp/MCNNTPSession.cpp index f6427006..933f10f2 100644 --- a/src/core/nntp/MCNNTPSession.cpp +++ b/src/core/nntp/MCNNTPSession.cpp @@ -464,7 +464,7 @@ Data * NNTPSession::fetchArticle(String *groupName, unsigned int index, NNTPProg return result; } -Data * NNTPSession::fetchArticleByMessageID(String * groupName, String * messageID, ErrorCode * pError) +Data * NNTPSession::fetchArticleByMessageID(String * messageID, ErrorCode * pError) { int r; char * msgID; @@ -473,11 +473,6 @@ Data * NNTPSession::fetchArticleByMessageID(String * groupName, String * message MCLog("fetch article at message-id %s", messageID->UTF8Characters()); - selectGroup(groupName, pError); - if (* pError != ErrorNone) { - return NULL; - } - msgID = strdup(messageID->UTF8Characters()); r = newsnntp_article_by_message_id(mNNTP, msgID, &content, &content_len); diff --git a/src/core/nntp/MCNNTPSession.h b/src/core/nntp/MCNNTPSession.h index dc2316ff..ec0080ed 100644 --- a/src/core/nntp/MCNNTPSession.h +++ b/src/core/nntp/MCNNTPSession.h @@ -53,7 +53,7 @@ namespace mailcore { virtual IndexSet * fetchAllArticles(String * groupname, ErrorCode * pError); virtual Data * fetchArticle(String *groupName, unsigned int index, NNTPProgressCallback * callback, ErrorCode * pError); - virtual Data * fetchArticleByMessageID(String * groupname, String * messageID, ErrorCode * pError); + virtual Data * fetchArticleByMessageID(String * messageID, ErrorCode * pError); virtual time_t fetchServerDate(ErrorCode * pError); diff --git a/src/core/pop/MCPOPSession.cpp b/src/core/pop/MCPOPSession.cpp index 8415a081..ab8975a6 100644 --- a/src/core/pop/MCPOPSession.cpp +++ b/src/core/pop/MCPOPSession.cpp @@ -174,6 +174,7 @@ static void logger(mailpop3 * pop3, int log_type, const char * buffer, size_t si void POPSession::setup() { mPop = mailpop3_new(0, NULL); + mailpop3_set_timeout(mPop, timeout()); mailpop3_set_progress_callback(mPop, POPSession::body_progress, this); mailpop3_set_logger(mPop, logger, this); } diff --git a/src/core/provider/MCAccountValidator.cpp b/src/core/provider/MCAccountValidator.cpp new file mode 100644 index 00000000..59538c72 --- /dev/null +++ b/src/core/provider/MCAccountValidator.cpp @@ -0,0 +1,497 @@ +// +// MCAccountValidator.cpp +// mailcore2 +// +// Created by Christopher Hockley on 22/01/15. +// Copyright (c) 2015 MailCore. All rights reserved. +// + +#include "MCAccountValidator.h" +#include "MCMailProvider.h" +#include "MCMailProvidersManager.h" +#include "MCIMAPAsyncSession.h" +#include "MCPOPAsyncSession.h" +#include "MCSMTPAsyncSession.h" +#include "MCNetService.h" +#include "MCAddress.h" +#include "MCIMAPOperation.h" +#include "MCPOPOperation.h" +#include "MCSMTPOperation.h" +#include "MCMXRecordResolverOperation.h" + +using namespace mailcore; + +/* this is the service being tested */ + +enum { + SERVICE_IMAP, /* IMAP service */ + SERVICE_POP, /* POP service */ + SERVICE_SMTP, /* SMTP service */ +}; + +void AccountValidator::init() +{ + mEmail = NULL; + mUsername = NULL; + mPassword = NULL; + mOAuth2Token = NULL; + + mImapServices = new Array(); + mSmtpServices = new Array(); + mPopServices = new Array(); + + mIdentifier = NULL; + mImapServer = NULL; + mPopServer = NULL; + mSmtpServer = NULL; + mImapError = ErrorNone; + mPopError = ErrorNone; + mSmtpError = ErrorNone; + + mCurrentServiceIndex = 0; + mCurrentServiceTested = 0; + + mProvider = NULL; + + mOperation = NULL; + mQueue = NULL; + mResolveMX = NULL; + + mImapSession = NULL; + mPopSession = NULL; + mSmtpSession = NULL; + + mImapEnabled = false; + mPopEnabled = false; + mSmtpEnabled = false; +} + +AccountValidator::AccountValidator() +{ + init(); +} + +AccountValidator::~AccountValidator() +{ + MC_SAFE_RELEASE(mEmail); + MC_SAFE_RELEASE(mUsername); + MC_SAFE_RELEASE(mPassword); + MC_SAFE_RELEASE(mOAuth2Token); + MC_SAFE_RELEASE(mImapServices); + MC_SAFE_RELEASE(mSmtpServices); + MC_SAFE_RELEASE(mPopServices); + MC_SAFE_RELEASE(mIdentifier); + MC_SAFE_RELEASE(mProvider); + MC_SAFE_RELEASE(mOperation); + MC_SAFE_RELEASE(mQueue); + MC_SAFE_RELEASE(mResolveMX); + MC_SAFE_RELEASE(mImapSession); + MC_SAFE_RELEASE(mPopSession); + MC_SAFE_RELEASE(mSmtpSession); +} + +void AccountValidator::start() +{ + if (mEmail == NULL) { + if (mUsername == NULL) { + return; + } + else { + mEmail = mUsername; + MC_SAFE_RETAIN(mEmail); + } + } + else if (mUsername == NULL){ + mUsername = mEmail; + MC_SAFE_RETAIN(mUsername); + } + + MC_SAFE_RELEASE(mProvider); + mProvider = MailProvidersManager::sharedManager()->providerForEmail(mEmail); + if (mProvider != NULL) { + MC_SAFE_REPLACE_COPY(String, mIdentifier, mProvider->identifier()); + } + MC_SAFE_RETAIN(mProvider); + + if (mProvider == NULL) { + resolveMX(); + } + else{ + startCheckingHosts(); + } +} + +void AccountValidator::cancel() +{ + if(mOperation != NULL) + mOperation->cancel(); + + if(mResolveMX != NULL) + mResolveMX->cancel(); + + if (mQueue != NULL) + mQueue->cancelAllOperations(); + + MC_SAFE_RELEASE(mOperation); + MC_SAFE_RELEASE(mResolveMX); + MC_SAFE_RELEASE(mQueue); + MC_SAFE_RELEASE(mImapSession); + MC_SAFE_RELEASE(mPopSession); + MC_SAFE_RELEASE(mSmtpSession); + + Operation::cancel(); +} + +void AccountValidator::operationFinished(Operation * op) +{ + if (op == mResolveMX) { + resolveMXDone(); + } + else { + checkNextHostDone(); + } +} + +void AccountValidator::resolveMX() +{ + Array * components; + String * domain; + + components = mUsername->componentsSeparatedByString(MCSTR("@")); + if (components->count() >= 2) { + domain = (String *) components->lastObject(); + mResolveMX = new MXRecordResolverOperation(); + mResolveMX->setHostname(domain); + mResolveMX->setCallback((OperationCallback *)this); + + mQueue = new OperationQueue(); + mQueue->addOperation(mResolveMX); + } + else { + mImapError = ErrorNoValidServerFound; + mPopError = ErrorNoValidServerFound; + mSmtpError = ErrorNoValidServerFound; + + callback()->operationFinished(this); + } +} + +void AccountValidator::resolveMXDone() +{ + Array * mxRecords = mResolveMX->mxRecords(); + + mc_foreacharray(String, mxRecord, mxRecords) { + MailProvider * provider = MailProvidersManager::sharedManager()->providerForMX(mxRecord); + if (provider != NULL){ + MC_SAFE_REPLACE_RETAIN(MailProvider, mProvider, provider); + if (mProvider != NULL) { + MC_SAFE_REPLACE_COPY(String, mIdentifier, mProvider->identifier()); + } + break; + } + } + + startCheckingHosts(); +} + +void AccountValidator::setupServices() +{ + MC_SAFE_RELEASE(mImapServices); + mImapServices = mProvider->imapServices(); + MC_SAFE_RETAIN(mImapServices); + + MC_SAFE_RELEASE(mPopServices); + mPopServices = mProvider->popServices(); + MC_SAFE_RETAIN(mPopServices); + + MC_SAFE_RELEASE(mSmtpServices); + mSmtpServices = mProvider->smtpServices(); + MC_SAFE_RETAIN(mSmtpServices); +} + +void AccountValidator::startCheckingHosts() +{ + if (mProvider != NULL) { + setupServices(); + } + + if (mImapServices->count() == 0) + mImapError = ErrorNoValidServerFound; + + if (mPopServices->count() == 0) + mPopError = ErrorNoValidServerFound; + + if (mSmtpServices->count() == 0) + mSmtpError = ErrorNoValidServerFound; + + checkNextHost(); +} + +/** + Each service(IMAP/POP/SMTP) is tested one after the other. + For each service we test each server details (NetService), + Until either: + we find on that works and returns ErrorNone in checkNextHostDone(). + we have gone trough the Array of NetService for that service and checkNextHost() is then called for the next service. + */ +void AccountValidator::checkNextHost() +{ + if (mCurrentServiceTested == SERVICE_IMAP) { + if (mImapEnabled && (mCurrentServiceIndex < mImapServices->count())) { + mImapSession = new IMAPAsyncSession(); + mImapSession->setUsername(mUsername); + mImapSession->setPassword(mPassword); + if (mOAuth2Token != NULL) { + mImapSession->setOAuth2Token(mOAuth2Token); + mImapSession->setAuthType(AuthTypeXOAuth2); + } + + mImapServer = (NetService *) mImapServices->objectAtIndex(mCurrentServiceIndex); + mImapSession->setHostname(mImapServer->hostname()); + mImapSession->setPort(mImapServer->port()); + mImapSession->setConnectionType(mImapServer->connectionType()); + + mOperation = (IMAPOperation *)mImapSession->checkAccountOperation(); + mOperation->retain(); + mOperation->setCallback(this); + mOperation->start(); + } + else if (mImapEnabled && (mImapServices->count() > 0)) { + mImapServer = NULL; + callback()->operationFinished(this); + } + else { + mCurrentServiceTested ++; + mCurrentServiceIndex = 0; + checkNextHost(); + } + } + else if (mCurrentServiceTested == SERVICE_POP){ + if (mPopEnabled && (mCurrentServiceIndex < mPopServices->count())) { + mPopSession = new POPAsyncSession(); + mPopSession->setUsername(mUsername); + mPopSession->setPassword(mPassword); + + mPopServer = (NetService *) mPopServices->objectAtIndex(mCurrentServiceIndex); + mPopSession->setHostname(mPopServer->hostname()); + mPopSession->setPort(mPopServer->port()); + mPopSession->setConnectionType(mPopServer->connectionType()); + + mOperation = mPopSession->checkAccountOperation(); + mOperation->retain(); + mOperation->setCallback(this); + mOperation->start(); + } + else if (mPopEnabled && (mPopServices->count() > 0)) { + mPopServer = NULL; + callback()->operationFinished(this); + } + else { + mCurrentServiceTested ++; + mCurrentServiceIndex = 0; + checkNextHost(); + } + } + else if (mCurrentServiceTested == SERVICE_SMTP){ + if (mSmtpEnabled && (mCurrentServiceIndex < mSmtpServices->count())) { + mSmtpSession = new SMTPAsyncSession(); + mSmtpSession->setUsername(mUsername); + mSmtpSession->setPassword(mPassword); + if (mOAuth2Token != NULL) { + mSmtpSession->setOAuth2Token(mOAuth2Token); + mSmtpSession->setAuthType(AuthTypeXOAuth2); + } + + mSmtpServer = (NetService *) mSmtpServices->objectAtIndex(mCurrentServiceIndex); + mSmtpSession->setHostname(mSmtpServer->hostname()); + mSmtpSession->setPort(mSmtpServer->port()); + mSmtpSession->setConnectionType(mSmtpServer->connectionType()); + + mOperation = mSmtpSession->checkAccountOperation(Address::addressWithMailbox(mEmail)); + mOperation->retain(); + mOperation->setCallback(this); + mOperation->start(); + } + else if (mSmtpEnabled && (mSmtpServices->count() > 0)) { + mSmtpServer = NULL; + callback()->operationFinished(this); + } + else { + mCurrentServiceTested ++; + mCurrentServiceIndex = 0; + checkNextHost(); + } + } + else { + callback()->operationFinished(this); + } +} + +void AccountValidator::checkNextHostDone() +{ + ErrorCode error = ErrorNone; + + if (mCurrentServiceTested == SERVICE_IMAP) { + mImapError = ((IMAPOperation *)mOperation)->error(); + error = mImapError; + MC_SAFE_RELEASE(mImapSession); + } + else if (mCurrentServiceTested == SERVICE_POP) { + mPopError = ((POPOperation *)mOperation)->error(); + error = mPopError; + MC_SAFE_RELEASE(mPopSession); + } + else if (mCurrentServiceTested == SERVICE_SMTP) { + mSmtpError = ((SMTPOperation *)mOperation)->error(); + error = mSmtpError; + MC_SAFE_RELEASE(mSmtpSession); + } + + MC_SAFE_RELEASE(mOperation); + + if (error == ErrorNone) { + mCurrentServiceIndex = 0; + mCurrentServiceTested ++; + } + else { + mCurrentServiceIndex ++; + } + + checkNextHost(); +} + +void AccountValidator::setEmail(String * email) +{ + MC_SAFE_REPLACE_COPY(String, mEmail, email); +} + +String * AccountValidator::email() +{ + return mEmail; +} + +void AccountValidator::setUsername(String * username) +{ + MC_SAFE_REPLACE_COPY(String, mUsername, username); +} + +String * AccountValidator::username() +{ + return mUsername; +} + +void AccountValidator::setPassword(String * password) +{ + MC_SAFE_REPLACE_COPY(String, mPassword, password); +} + +String * AccountValidator::password() +{ + return mPassword; +} + +void AccountValidator::setOAuth2Token(String * OAuth2Token) +{ + MC_SAFE_REPLACE_COPY(String, mOAuth2Token, OAuth2Token); +} + +String * AccountValidator::OAuth2Token() +{ + return mOAuth2Token; +} + +void AccountValidator::setImapEnabled(bool enabled) +{ + mImapEnabled = enabled; +} + +bool AccountValidator::isImapEnabled() +{ + return mImapEnabled; +} + +void AccountValidator::setPopEnabled(bool enabled) +{ + mPopEnabled = enabled; +} + +bool AccountValidator::isPopEnabled() +{ + return mPopEnabled; +} + + +void AccountValidator::setSmtpEnabled(bool enabled) +{ + mSmtpEnabled = enabled; +} + +bool AccountValidator::isSmtpEnabled() +{ + return mSmtpEnabled; +} + +void AccountValidator::setImapServices(Array * imapServices) +{ + MC_SAFE_REPLACE_COPY(Array, mImapServices, imapServices); +} + +Array * AccountValidator::imapServices() +{ + return mImapServices; +} + +void AccountValidator::setSmtpServices(Array * smtpServices) +{ + MC_SAFE_REPLACE_COPY(Array, mSmtpServices, smtpServices); +} + +Array * AccountValidator::smtpServices() +{ + return mSmtpServices; +} + +void AccountValidator::setPopServices(Array * popServices) +{ + MC_SAFE_REPLACE_COPY(Array, mPopServices, popServices); +} + +Array * AccountValidator::popServices() +{ + return mPopServices; +} + +String * AccountValidator::identifier() +{ + return mIdentifier; +} + +NetService * AccountValidator::imapServer() +{ + return mImapServer; +} + +NetService * AccountValidator::smtpServer() +{ + return mSmtpServer; +} + +NetService * AccountValidator::popServer() +{ + return mPopServer; +} + +ErrorCode AccountValidator::imapError() +{ + return mImapError; +} + +ErrorCode AccountValidator::popError() +{ + return mPopError; +} + +ErrorCode AccountValidator::smtpError() +{ + return mSmtpError; +} diff --git a/src/core/provider/MCAccountValidator.h b/src/core/provider/MCAccountValidator.h new file mode 100644 index 00000000..436317cf --- /dev/null +++ b/src/core/provider/MCAccountValidator.h @@ -0,0 +1,119 @@ +// +// MCAccountValidator.h +// mailcore2 +// +// Created by Christopher Hockley on 22/01/15. +// Copyright (c) 2015 MailCore. All rights reserved. +// + +#ifndef MAILCORE_MCACCOUNTVALIDATOR_H + +#define MAILCORE_MCACCOUNTVALIDATOR_H + +#include <MailCore/MCBaseTypes.h> + +#ifdef __cplusplus + +namespace mailcore { + + class NetService; + class MailProvider; + class MXRecordResolverOperation; + class IMAPAsyncSession; + class POPAsyncSession; + class SMTPAsyncSession; + + class MAILCORE_EXPORT AccountValidator : public Operation, public OperationCallback { + public: + AccountValidator(); + virtual ~AccountValidator(); + + virtual void setEmail(String * email); + virtual String * email(); /* for SMTP */ + virtual void setUsername(String * username); + virtual String * username(); + virtual void setPassword(String * password); + virtual String * password(); + virtual void setOAuth2Token(String * OAuth2Token); + virtual String * OAuth2Token(); + + virtual void setImapEnabled(bool enabled); + virtual bool isImapEnabled(); + + virtual void setPopEnabled(bool enabled); + virtual bool isPopEnabled(); + + virtual void setSmtpEnabled(bool enabled); + virtual bool isSmtpEnabled(); + + virtual void setImapServices(Array * imapServices); + virtual Array * /* NetService */ imapServices(); + virtual void setSmtpServices(Array * smtpServices); + virtual Array * /* NetService */ smtpServices(); + virtual void setPopServices(Array * popServices); + virtual Array * /* NetService */ popServices(); + + // result + virtual String * identifier(); + virtual NetService * imapServer(); + virtual NetService * popServer(); + virtual NetService * smtpServer(); + virtual ErrorCode imapError(); + virtual ErrorCode popError(); + virtual ErrorCode smtpError(); + + virtual void start(); + virtual void cancel(); + + private: + String * mEmail; /* for SMTP */ + String * mUsername; + String * mPassword; + String * mOAuth2Token; + + Array * /* NetService */ mImapServices; + Array * /* NetService */ mSmtpServices; + Array * /* NetService */ mPopServices; + + // result + String * mIdentifier; + NetService * mImapServer; + NetService * mPopServer; + NetService * mSmtpServer; + ErrorCode mImapError; + ErrorCode mPopError; + ErrorCode mSmtpError; + + MailProvider * mProvider; + + //indexs for services being tested + int mCurrentServiceIndex; + int mCurrentServiceTested; + + Operation * mOperation; + virtual void operationFinished(Operation * op); + + OperationQueue * mQueue; + MXRecordResolverOperation * mResolveMX; + + IMAPAsyncSession * mImapSession; + POPAsyncSession * mPopSession; + SMTPAsyncSession * mSmtpSession; + + bool mImapEnabled; + bool mPopEnabled; + bool mSmtpEnabled; + + void init(); + void setupServices(); + void resolveMX(); + void resolveMXDone(); + void startCheckingHosts(); + void checkNextHost(); + void checkNextHostDone(); + }; +} + +#endif + +#endif diff --git a/src/core/provider/MCMXRecordResolverOperation.cpp b/src/core/provider/MCMXRecordResolverOperation.cpp new file mode 100644 index 00000000..ac6c8219 --- /dev/null +++ b/src/core/provider/MCMXRecordResolverOperation.cpp @@ -0,0 +1,75 @@ +// +// MCFetchAsyncMXRecord.cpp +// mailcore2 +// +// Created by Christopher Hockley on 29/01/15. +// Copyright (c) 2015 MailCore. All rights reserved. +// + +#include "MCMXRecordResolverOperation.h" + +#if !defined(ANDROID) && !defined(__ANDROID__) +#include <arpa/inet.h> +#include <resolv.h> +#endif + +using namespace mailcore; + +MXRecordResolverOperation::MXRecordResolverOperation() +{ + mHostname = NULL; + mMXRecords = NULL; +} + +MXRecordResolverOperation::~MXRecordResolverOperation() +{ + MC_SAFE_RELEASE(mMXRecords); + MC_SAFE_RELEASE(mHostname); +} + +void MXRecordResolverOperation::setHostname(String * hostname) +{ + MC_SAFE_REPLACE_COPY(String, mHostname, hostname); +} + +String * MXRecordResolverOperation::hostname() +{ + return mHostname; +} + +Array * MXRecordResolverOperation::mxRecords() +{ + return mMXRecords; +} + +void MXRecordResolverOperation::main() +{ + mMXRecords = new Array(); +#if !defined(ANDROID) && !defined(__ANDROID__) + unsigned char response[NS_PACKETSZ]; + ns_msg handle; + ns_rr rr; + int len; + char dispbuf[4096]; + + if (((len = res_search(MCUTF8(mHostname), ns_c_in, ns_t_mx, response, sizeof(response))) >= 0) and + (ns_initparse(response, len, &handle) >= 0) and + (ns_msg_count(handle, ns_s_an) >= 0)) { + + for (int ns_index = 0; ns_index < len; ns_index++) { + if (ns_parserr(&handle, ns_s_an, ns_index, &rr)) { + /* WARN: ns_parserr failed */ + continue; + } + ns_sprintrr (&handle, &rr, NULL, NULL, dispbuf, sizeof (dispbuf)); + if (ns_rr_class(rr) == ns_c_in and ns_rr_type(rr) == ns_t_mx) { + char mxname[4096]; + dn_expand(ns_msg_base(handle), ns_msg_base(handle) + ns_msg_size(handle), ns_rr_rdata(rr) + NS_INT16SZ, mxname, sizeof(mxname)); + String * str = String::stringWithUTF8Characters(mxname); + mMXRecords->addObject(str); + } + } + } +#endif +} + diff --git a/src/core/provider/MCMXRecordResolverOperation.h b/src/core/provider/MCMXRecordResolverOperation.h new file mode 100644 index 00000000..7d8a6fc8 --- /dev/null +++ b/src/core/provider/MCMXRecordResolverOperation.h @@ -0,0 +1,41 @@ +// +// ResolveProviderUsingMXRecordAsync.h +// mailcore2 +// +// Created by Christopher Hockley on 29/01/15. +// Copyright (c) 2015 MailCore. All rights reserved. +// + +#ifndef MAILCORE_MCFETCHASYNCMXRECORD_H + +#define MAILCORE_MCFETCHASYNCMXRECORD_H + +#include <MailCore/MCBaseTypes.h> +#include <MailCore/MCMessageConstants.h> + +#ifdef __cplusplus + +namespace mailcore { + + class MAILCORE_EXPORT MXRecordResolverOperation : public Operation { + public: + MXRecordResolverOperation(); + virtual ~MXRecordResolverOperation(); + + virtual void setHostname(String * hostname); + virtual String * hostname(); + + virtual Array * mxRecords(); + + public: // subclass behavior + virtual void main(); + + private: + Array * mMXRecords; + String * mHostname; + }; +} + +#endif + +#endif diff --git a/src/core/provider/MCMailProvider.cpp b/src/core/provider/MCMailProvider.cpp index 1055d4fa..99fc4deb 100644 --- a/src/core/provider/MCMailProvider.cpp +++ b/src/core/provider/MCMailProvider.cpp @@ -161,30 +161,42 @@ bool MailProvider::matchEmail(String * email) domain = (String *) components->lastObject(); + bool matchExcludeDomain = false; mc_foreacharray(String, exclude, mDomainExclude) { if (matchDomain(exclude, domain)){ - return false; + matchExcludeDomain = true;; + break; } } - + if (matchExcludeDomain) { + return false; + } + + bool matchValidDomain = false; mc_foreacharray(String, match, mDomainMatch) { if (matchDomain(match, domain)){ - return true; + matchValidDomain = true; + break; } } - + if (matchValidDomain) { + return true; + } + return false; } bool MailProvider::matchMX(String * hostname) { + bool result = false; mc_foreacharray(String, match, mMxMatch) { if (matchDomain(match, hostname)){ - return true; + result = true; + break; } } - - return false; + + return result; } bool MailProvider::matchDomain(String * match, String * domain) @@ -272,6 +284,7 @@ String * MailProvider::importantFolderPath() bool MailProvider::isMainFolder(String * folderPath, String * prefix) { + bool result = false; mc_foreachhashmapValue(String, path, mMailboxPaths) { String * fullPath; @@ -282,11 +295,13 @@ bool MailProvider::isMainFolder(String * folderPath, String * prefix) fullPath = path; } - if (fullPath->isEqual(folderPath)) - return true; + if (fullPath->isEqual(folderPath)) { + result = true; + break; + } } - return false; + return result; } String * MailProvider::description() diff --git a/src/core/provider/MCMailProvidersManager.cpp b/src/core/provider/MCMailProvidersManager.cpp index 0d7938e4..a5f7891a 100644 --- a/src/core/provider/MCMailProvidersManager.cpp +++ b/src/core/provider/MCMailProvidersManager.cpp @@ -30,22 +30,28 @@ MailProvidersManager * MailProvidersManager::sharedManager() MailProvider * MailProvidersManager::providerForEmail(String * email) { + MailProvider * result = NULL; mc_foreachhashmapValue(MailProvider, provider, mProviders) { - if (provider->matchEmail(email)) - return provider; + if (provider->matchEmail(email)) { + result = provider; + break; + } } - return NULL; + return result; } MailProvider * MailProvidersManager::providerForMX(String * hostname) { + MailProvider * result = NULL; mc_foreachhashmapValue(MailProvider, provider, mProviders) { - if (provider->matchMX(hostname)) - return provider; + if (provider->matchMX(hostname)) { + result = provider; + break; + } } - - return NULL; + + return result; } MailProvider * MailProvidersManager::providerForIdentifier(String * identifier) diff --git a/src/core/provider/MCMailProvidersManager.h b/src/core/provider/MCMailProvidersManager.h index 42d1d3bc..774c2d30 100644 --- a/src/core/provider/MCMailProvidersManager.h +++ b/src/core/provider/MCMailProvidersManager.h @@ -40,4 +40,4 @@ namespace mailcore { #endif -#endif
\ No newline at end of file +#endif diff --git a/src/core/provider/MCNetService.h b/src/core/provider/MCNetService.h index bc1edf81..00a618ad 100644 --- a/src/core/provider/MCNetService.h +++ b/src/core/provider/MCNetService.h @@ -56,4 +56,4 @@ namespace mailcore { #endif -#endif
\ No newline at end of file +#endif diff --git a/src/core/provider/MCProvider.h b/src/core/provider/MCProvider.h index b13bb263..ad8189b2 100644 --- a/src/core/provider/MCProvider.h +++ b/src/core/provider/MCProvider.h @@ -13,5 +13,6 @@ #include <MailCore/MCMailProvidersManager.h> #include <MailCore/MCMailProvider.h> #include <MailCore/MCNetService.h> +#include <MailCore/MCAccountValidator.h> #endif diff --git a/src/core/renderer/MCHTMLRenderer.cpp b/src/core/renderer/MCHTMLRenderer.cpp index 568c939e..c42bcb45 100644 --- a/src/core/renderer/MCHTMLRenderer.cpp +++ b/src/core/renderer/MCHTMLRenderer.cpp @@ -92,7 +92,7 @@ static bool isTextPart(AbstractPart * part, htmlRendererContext * context) MCAssert(mimeType != NULL); if (!part->isInlineAttachment()) { - if ((part->filename() != NULL) && context->firstRendered) { + if (part->isAttachment() || ((part->filename() != NULL) && context->firstRendered)) { return false; } } @@ -218,6 +218,9 @@ static String * htmlForAbstractMessage(String * folder, AbstractMessage * messag context.pass = 1; context.firstAttachment = false; context.hasTextPart = false; + + htmlCallback->setMixedTextAndAttachmentsModeEnabled(context.hasMixedTextAndAttachments); + String * content = htmlForAbstractPart(mainPart, &context); if (content == NULL) return NULL; @@ -274,6 +277,28 @@ static String * htmlForAbstractSinglePart(AbstractPart * part, htmlRendererConte if (isTextPart(part, context)) { if (context->pass == 0) { if (context->state == RENDER_STATE_HAD_ATTACHMENT) { +#if 0 + if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) { + if (mimeType->isEqual(MCSTR("text/plain"))) { + Data * data = context->dataCallback->dataForIMAPPart(context->folder, (IMAPPart *) part); + if (data != NULL) { + if (data->length() == 0) { + return NULL; + } + else if (data->length() == 2) { + if (strncmp(data->bytes(), "\r\n", 2) == 0) { + return NULL; + } + } + else if (data->length() == 1) { + if (strncmp(data->bytes(), "\n", 1) == 0) { + return NULL; + } + } + } + } + } +#endif context->state = RENDER_STATE_HAD_ATTACHMENT_THEN_TEXT; } return NULL; @@ -296,6 +321,7 @@ static String * htmlForAbstractSinglePart(AbstractPart * part, htmlRendererConte String * str = data->stringWithDetectedCharset(charset, false); str = str->htmlMessageContent(); + str = context->htmlCallback->filterHTMLForPart(str); context->firstRendered = true; return str; } @@ -307,7 +333,8 @@ static String * htmlForAbstractSinglePart(AbstractPart * part, htmlRendererConte } else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) { data = ((Attachment *) part)->data(); - MCAssert(data != NULL); + // It may be NULL when mailcore::MessageParser::attachments() is invoked when + // when mailcore::MessageParser has been serialized/unserialized. } if (data == NULL) return NULL; diff --git a/src/core/renderer/MCHTMLRendererCallback.cpp b/src/core/renderer/MCHTMLRendererCallback.cpp index fb492c9e..a3b14341 100644 --- a/src/core/renderer/MCHTMLRendererCallback.cpp +++ b/src/core/renderer/MCHTMLRendererCallback.cpp @@ -289,3 +289,7 @@ bool HTMLRendererTemplateCallback::shouldShowPart(AbstractPart * part) { return true; } + +void HTMLRendererTemplateCallback::setMixedTextAndAttachmentsModeEnabled(bool enabled) +{ +} diff --git a/src/core/renderer/MCHTMLRendererCallback.h b/src/core/renderer/MCHTMLRendererCallback.h index a12a3e45..4a4fc40f 100644 --- a/src/core/renderer/MCHTMLRendererCallback.h +++ b/src/core/renderer/MCHTMLRendererCallback.h @@ -35,6 +35,8 @@ namespace mailcore { HTMLRendererTemplateCallback(); virtual ~HTMLRendererTemplateCallback(); + virtual void setMixedTextAndAttachmentsModeEnabled(bool enabled); + virtual bool canPreviewPart(AbstractPart * part); virtual bool shouldShowPart(AbstractPart * part); diff --git a/src/core/rfc822/MCAttachment.cpp b/src/core/rfc822/MCAttachment.cpp index 99f3caa0..cdee201b 100644 --- a/src/core/rfc822/MCAttachment.cpp +++ b/src/core/rfc822/MCAttachment.cpp @@ -2,6 +2,7 @@ #include "MCAttachment.h" +#include "MCDefines.h" #include "MCMultipart.h" #include "MCMessagePart.h" #include "MCMessageHeader.h" @@ -111,10 +112,7 @@ String * Attachment::mimeTypeForFilename(String * filename) if (result != NULL) return result; - if (ext->isEqual(MCSTR("jpg"))) { - return MCSTR("image/jpeg"); - } - else if (ext->isEqual(MCSTR("jpeg"))) { + if (ext->isEqual(MCSTR("jpeg")) || ext->isEqual(MCSTR("jpg"))) { return MCSTR("image/jpeg"); } else if (ext->isEqual(MCSTR("png"))) { @@ -129,6 +127,9 @@ String * Attachment::mimeTypeForFilename(String * filename) else if (ext->isEqual(MCSTR("txt"))) { return MCSTR("text/plain"); } + else if (ext->isEqual(MCSTR("tiff")) || ext->isEqual(MCSTR("tif"))) { + return MCSTR("image/tiff"); + } return NULL; } @@ -589,6 +590,9 @@ Attachment * Attachment::attachmentWithSingleMIME(struct mailmime * mime) if (single_fields.fld_disposition->dsp_type->dsp_type == MAILMIME_DISPOSITION_TYPE_INLINE) { result->setInlineAttachment(true); } + else if (single_fields.fld_disposition->dsp_type->dsp_type == MAILMIME_DISPOSITION_TYPE_ATTACHMENT) { + result->setAttachment(true); + } } } @@ -607,3 +611,13 @@ MessagePart * Attachment::attachmentWithMessageMIME(struct mailmime * mime) return (MessagePart *) attachment->autorelease(); } + +static void * createObject() +{ + return new Attachment(); +} + +INITIALIZE(Attachment) +{ + Object::registerObjectConstructor("mailcore::Attachment", &createObject); +} diff --git a/src/core/rfc822/MCMessageParser.cpp b/src/core/rfc822/MCMessageParser.cpp index 71071c02..beddeebc 100644 --- a/src/core/rfc822/MCMessageParser.cpp +++ b/src/core/rfc822/MCMessageParser.cpp @@ -5,6 +5,7 @@ #include <CoreFoundation/CoreFoundation.h> #endif +#include "MCDefines.h" #include "MCAttachment.h" #include "MCMessageHeader.h" #include "MCHTMLRenderer.h" @@ -140,6 +141,15 @@ HashMap * MessageParser::serializable() return result; } +void MessageParser::importSerializable(HashMap * serializable) +{ + AbstractMessage::importSerializable(serializable); + MC_SAFE_REPLACE_RETAIN(AbstractPart, mMainPart, Object::objectWithSerializable((HashMap *) serializable->objectForKey(MCSTR("mainPart")))); + if (mMainPart != NULL) { + mMainPart->applyUniquePartID(); + } +} + Object * MessageParser::copy() { return new MessageParser(this); @@ -190,3 +200,13 @@ String * MessageParser::plainTextBodyRendering(bool stripWhitespace) } return plainTextBodyString; } + +static void * createObject() +{ + return new MessageParser(); +} + +INITIALIZE(MessageParser) +{ + Object::registerObjectConstructor("mailcore::MessageParser", &createObject); +} diff --git a/src/core/rfc822/MCMessageParser.h b/src/core/rfc822/MCMessageParser.h index 048cee60..9682bfce 100644 --- a/src/core/rfc822/MCMessageParser.h +++ b/src/core/rfc822/MCMessageParser.h @@ -42,7 +42,8 @@ namespace mailcore { virtual AbstractPart * partForUniqueID(String * uniqueID); virtual HashMap * serializable(); - + virtual void importSerializable(HashMap * serializable); + #ifdef __APPLE__ public: static MessageParser * messageParserWithData(CFDataRef data); diff --git a/src/core/rfc822/MCMessagePart.cpp b/src/core/rfc822/MCMessagePart.cpp index 21d61181..abd98ac2 100644 --- a/src/core/rfc822/MCMessagePart.cpp +++ b/src/core/rfc822/MCMessagePart.cpp @@ -1,5 +1,7 @@ #include "MCMessagePart.h" +#include "MCDefines.h" + using namespace mailcore; MessagePart::MessagePart() @@ -18,3 +20,13 @@ Object * MessagePart::copy() { return new MessagePart(this); } + +static void * createObject() +{ + return new MessagePart(); +} + +INITIALIZE(MessagePart) +{ + Object::registerObjectConstructor("mailcore::MessagePart", &createObject); +} diff --git a/src/core/rfc822/MCMultipart.cpp b/src/core/rfc822/MCMultipart.cpp index e048669e..0be76430 100644 --- a/src/core/rfc822/MCMultipart.cpp +++ b/src/core/rfc822/MCMultipart.cpp @@ -1,5 +1,7 @@ #include "MCMultipart.h" +#include "MCDefines.h" + using namespace mailcore; Multipart::Multipart() @@ -19,3 +21,12 @@ Object * Multipart::copy() return new Multipart(this); } +static void * createObject() +{ + return new Multipart(); +} + +INITIALIZE(Multipart) +{ + Object::registerObjectConstructor("mailcore::Multipart", &createObject); +} diff --git a/src/core/smtp/MCSMTPSession.cpp b/src/core/smtp/MCSMTPSession.cpp index eab05730..0c2016fd 100644 --- a/src/core/smtp/MCSMTPSession.cpp +++ b/src/core/smtp/MCSMTPSession.cpp @@ -189,6 +189,10 @@ static void logger(mailsmtp * smtp, int log_type, const char * buffer, size_t si return; ConnectionLogType type = getConnectionType(log_type); + if ((int) type == -1) { + // in case of MAILSTREAM_LOG_TYPE_INFO_RECEIVED or MAILSTREAM_LOG_TYPE_INFO_SENT. + return; + } bool isBuffer = isBufferFromLogType(log_type); if (isBuffer) { @@ -626,6 +630,7 @@ void SMTPSession::sendMessage(Address * from, Array * recipients, Data * message r = mailesmtp_send_quit(mSmtp, MCUTF8(from->mailbox()), 0, NULL, address_list, messageData->bytes(), messageData->length()); + mShouldDisconnect = true; } else { r = mailesmtp_send(mSmtp, MCUTF8(from->mailbox()), 0, NULL, @@ -667,17 +672,22 @@ void SMTPSession::sendMessage(Address * from, Array * recipients, Data * message goto err; } else if (r != MAILSMTP_NO_ERROR) { - if ((responseCode == 550) && (response != NULL) && (response->hasPrefix(MCSTR("5.3.4")))) { - * pError = ErrorNeedsConnectToWebmail; - goto err; - } - else { - * pError = ErrorSendMessage; - MC_SAFE_REPLACE_COPY(String, mLastSMTPResponse, response); - mLastLibetpanError = r; - mLastSMTPResponseCode = responseCode; - goto err; + if ((responseCode == 550) && (response != NULL)) { + if (response->hasPrefix(MCSTR("5.3.4 "))) { + * pError = ErrorNeedsConnectToWebmail; + goto err; + } + else if (response->hasPrefix(MCSTR("5.7.1 "))) { + * pError = ErrorSendMessageNotAllowed; + goto err; + } } + + * pError = ErrorSendMessage; + MC_SAFE_REPLACE_COPY(String, mLastSMTPResponse, response); + mLastLibetpanError = r; + mLastSMTPResponseCode = responseCode; + goto err; } bodyProgress(messageData->length(), messageData->length()); @@ -702,7 +712,8 @@ Data * SMTPSession::dataWithFilteredBcc(Data * data) struct mailimf_fields * fields = msg->msg_fields; int col = 0; - + + int hasRecipient = 0; str = mmap_string_new(""); for(clistiter * cur = clist_begin(fields->fld_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimf_field * field = (struct mailimf_field *) clist_content(cur); @@ -711,6 +722,17 @@ Data * SMTPSession::dataWithFilteredBcc(Data * data) clist_delete(fields->fld_list, cur); break; } + else if ((field->fld_type == MAILIMF_FIELD_TO) || (field->fld_type == MAILIMF_FIELD_CC) || (field->fld_type == MAILIMF_FIELD_BCC)) { + hasRecipient = 1; + } + } + if (!hasRecipient) { + struct mailimf_address_list * imfTo; + imfTo = mailimf_address_list_new_empty(); + mailimf_address_list_add_parse(imfTo, (char *) "Undisclosed recipients:;"); + struct mailimf_to * toField = mailimf_to_new(imfTo); + struct mailimf_field * field = mailimf_field_new(MAILIMF_FIELD_TO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, toField, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + mailimf_fields_add(fields, field); } mailimf_fields_write_mem(str, &col, fields); mmap_string_append(str, "\n"); diff --git a/src/core/zip/MCZip.cpp b/src/core/zip/MCZip.cpp index a9879c9f..69e7fc6e 100644 --- a/src/core/zip/MCZip.cpp +++ b/src/core/zip/MCZip.cpp @@ -1,6 +1,7 @@ #include "MCWin32.h" // Should be included first. #include "MCZip.h" +#include "MCZipPrivate.h" #include "zip.h" #include "unzip.h" @@ -166,23 +167,33 @@ static ErrorCode addFile(zipFile file, String * path) return ErrorNone; } -String * mailcore::CreateTemporaryZipFileFromFolder(String * folder) +#ifndef __APPLE__ +String * mailcore::TemporaryDirectoryForZip() { char tempdir[] = "/tmp/mailcore2-XXXXXX"; char * result = mkdtemp(tempdir); if (result == NULL) { return NULL; } + return String::stringWithFileSystemRepresentation(tempdir); +} +#endif + +String * mailcore::CreateTemporaryZipFileFromFolder(String * folder) +{ + String * tempDirectoryString = TemporaryDirectoryForZip(); + + if (tempDirectoryString == NULL) { + return NULL; + } - String * tempDirectoryString = String::stringWithFileSystemRepresentation(tempdir); String * path = tempDirectoryString->stringByAppendingPathComponent(folder->lastPathComponent())->stringByAppendingUTF8Format(".zip"); ErrorCode err = CreateZipFileFromFolder(path, folder); if (err != ErrorNone) { - unlink(path->fileSystemRepresentation()); - unlink(tempdir); return NULL; } + unlink(tempDirectoryString->fileSystemRepresentation()); return path; } diff --git a/src/core/zip/MCZipMac.mm b/src/core/zip/MCZipMac.mm new file mode 100644 index 00000000..94a8a807 --- /dev/null +++ b/src/core/zip/MCZipMac.mm @@ -0,0 +1,30 @@ +// +// MCZipMac.mm +// mailcore2 +// +// Created by juliangsp on 7/7/15. +// Copyright (c) 2015 MailCore. All rights reserved. +// + +#include "MCZipPrivate.h" + +#import "NSObject+MCO.h" +#import <Foundation/Foundation.h> + +using namespace mailcore; + +String * mailcore::TemporaryDirectoryForZip() +{ + NSError * error; + NSString * directoryString; + + error = nil; + directoryString = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]; + directoryString = [directoryString stringByAppendingString:[[NSUUID UUID] UUIDString]]; + + if (![[NSFileManager defaultManager] createDirectoryAtPath:directoryString withIntermediateDirectories:YES attributes:nil error:NULL]) { + return nil; + } + + return MCO_FROM_OBJC(String, directoryString); +} diff --git a/src/core/zip/MCZipPrivate.h b/src/core/zip/MCZipPrivate.h new file mode 100644 index 00000000..070946f6 --- /dev/null +++ b/src/core/zip/MCZipPrivate.h @@ -0,0 +1,20 @@ +// +// MCZipMac.h +// mailcore2 +// +// Created by juliangsp on 7/7/15. +// Copyright (c) 2015 MailCore. All rights reserved. +// + +#ifndef mailcore2_MCZipMac_h +#define mailcore2_MCZipMac_h + +#include <MailCore/MCBaseTypes.h> + +namespace mailcore { + + String * TemporaryDirectoryForZip(); + +}; + +#endif |