diff options
author | Brian Smith <brian@dbsoft.org> | 2022-04-26 10:13:11 -0500 |
---|---|---|
committer | Brian Smith <brian@dbsoft.org> | 2022-04-26 10:19:04 -0500 |
commit | 3daf711085889bad1bd68651bc4e8790412ae105 (patch) | |
tree | f5b0e4c1befb320cdf158e1839ac5e273373087f /mailnews | |
parent | 7fe702603066e7f122d5dd66a3a1892ac7e06215 (diff) | |
download | uxp-3daf711085889bad1bd68651bc4e8790412ae105.tar.gz |
Issue #1829 - Revert “Issue #1751 -- Remove XP_MACOSX conditionals from the rest of the tree.”
This also removes some PP abuse and takes file entries out of PP when no longer
needed without XP_MACOSX conditionals.
This reverts commit 6f707bde95dab6998ac204f9ee6c925ee230c740.
Diffstat (limited to 'mailnews')
25 files changed, 1662 insertions, 9 deletions
diff --git a/mailnews/addrbook/public/nsAbBaseCID.h b/mailnews/addrbook/public/nsAbBaseCID.h index 611300d0ab..0dcc630c50 100644 --- a/mailnews/addrbook/public/nsAbBaseCID.h +++ b/mailnews/addrbook/public/nsAbBaseCID.h @@ -387,6 +387,47 @@ #define NS_ABVIEW_CONTRACTID \ "@mozilla.org/addressbook/abview;1" +#ifdef XP_MACOSX +// +// nsAbOSXDirectory +// +#define NS_ABOSXDIRECTORY_PREFIX "moz-abosxdirectory" +#define NS_ABOSXCARD_PREFIX "moz-abosxcard" + +#define NS_ABOSXDIRECTORY_CONTRACTID \ + NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABOSXDIRECTORY_PREFIX + +#define NS_ABOSXDIRECTORY_CID \ +{ /* {83781cc6-c682-11d6-bdeb-0005024967b8}*/ \ + 0x83781cc6, 0xc682, 0x11d6, \ + {0xbd, 0xeb, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \ +} + +// +// nsAbOSXCard +// +#define NS_ABOSXCARD_CONTRACTID \ + NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABOSXCARD_PREFIX + +#define NS_ABOSXCARD_CID \ +{ /* {89bbf582-c682-11d6-bc9d-0005024967b8}*/ \ + 0x89bbf582, 0xc682, 0x11d6, \ + {0xbc, 0x9d, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \ +} + +// +// OS X directory factory +// +#define NS_ABOSXDIRFACTORY_CONTRACTID \ + NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX NS_ABOSXDIRECTORY_PREFIX + +#define NS_ABOSXDIRFACTORY_CID \ +{ /* {90efe2fe-c682-11d6-9c83-0005024967b8}*/ \ + 0x90efe2fe, 0xc682, 0x11d6, \ + {0x9c, 0x83, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \ +} +#endif + #define NS_MSGVCARDSERVICE_CID \ { 0x3c4ac0da, 0x2cda, 0x4018, \ { 0x95, 0x51, 0xe1, 0x58, 0xb2, 0xe1, 0x22, 0xd3 }} diff --git a/mailnews/base/prefs/content/AccountWizard.xul b/mailnews/base/prefs/content/AccountWizard.xul index 9d825084b2..2aee2e3a5d 100644 --- a/mailnews/base/prefs/content/AccountWizard.xul +++ b/mailnews/base/prefs/content/AccountWizard.xul @@ -343,7 +343,11 @@ checked="true"/> </hbox> <spacer flex="1"/> +#ifndef XP_MACOSX <description>&clickFinish.label;</description> +#else + <description>&clickFinish.labelMac;</description> +#endif </vbox> </wizardpage> diff --git a/mailnews/base/search/src/nsMsgFilter.cpp b/mailnews/base/search/src/nsMsgFilter.cpp index d7e9ac9408..e94240f299 100644 --- a/mailnews/base/search/src/nsMsgFilter.cpp +++ b/mailnews/base/search/src/nsMsgFilter.cpp @@ -822,6 +822,11 @@ nsresult nsMsgFilter::ConvertMoveOrCopyToFolderValue(nsIMsgRuleAction *filterAct if (offset != -1) moveValue.Cut(offset, 4); +#ifdef XP_MACOSX + nsCString unescapedMoveValue; + MsgUnescapeString(moveValue, 0, unescapedMoveValue); + moveValue = unescapedMoveValue; +#endif destFolderUri.Append('/'); if (filterVersion == k45Version) { diff --git a/mailnews/base/src/nsMessenger.cpp b/mailnews/base/src/nsMessenger.cpp index 8719530f79..953b462b6a 100644 --- a/mailnews/base/src/nsMessenger.cpp +++ b/mailnews/base/src/nsMessenger.cpp @@ -698,6 +698,7 @@ nsresult nsMessenger::SaveAttachment(nsIFile *aFile, saveListener->QueryInterface(NS_GET_IID(nsIStreamListener), getter_AddRefs(convertedListener)); +#ifndef XP_MACOSX // if the content type is bin hex we are going to do a hokey hack and make sure we decode the bin hex // when saving an attachment to disk.. if (MsgLowerCaseEqualsLiteral(aContentType, APPLICATION_BINHEX)) @@ -712,6 +713,7 @@ nsresult nsMessenger::SaveAttachment(nsIFile *aFile, channelSupport, getter_AddRefs(convertedListener)); } +#endif nsCOMPtr<nsIURI> dummyNull; if (fetchService) rv = fetchService->FetchMimePart(URL, fullMessageUri.get(), @@ -769,6 +771,10 @@ nsMessenger::SaveAttachmentToFolder(const nsACString& contentType, const nsACStr ConvertAndSanitizeFileName(PromiseFlatCString(displayName).get(), unescapedFileName); rv = attachmentDestination->Append(unescapedFileName); NS_ENSURE_SUCCESS(rv, rv); +#ifdef XP_MACOSX + rv = attachmentDestination->CreateUnique(nsIFile::NORMAL_FILE_TYPE, ATTACHMENT_PERMISSION); + NS_ENSURE_SUCCESS(rv, rv); +#endif rv = SaveAttachment(attachmentDestination, url, messageUri, contentType, nullptr, nullptr); attachmentDestination.swap(*aOutFile); diff --git a/mailnews/base/src/nsMsgMailSession.cpp b/mailnews/base/src/nsMsgMailSession.cpp index 20d6f045c3..f9e396988c 100644 --- a/mailnews/base/src/nsMsgMailSession.cpp +++ b/mailnews/base/src/nsMsgMailSession.cpp @@ -353,9 +353,11 @@ NS_IMETHODIMP nsMsgMailSession::AddMsgWindow(nsIMsgWindow *msgWindow) NS_IMETHODIMP nsMsgMailSession::RemoveMsgWindow(nsIMsgWindow *msgWindow) { mWindows.RemoveObject(msgWindow); - // For suite, we don't want to disable mailnews when the last mail window - // is closed (other component windows may still be open). -#if !defined(MOZ_SUITE) + // Mac keeps a hidden window open so the app doesn't shut down when + // the last window is closed. So don't shutdown the account manager in that + // case. Similarly, for suite, we don't want to disable mailnews when the + // last mail window is closed. +#if !defined(XP_MACOSX) && !defined(MOZ_SUITE) if (!mWindows.Count()) { nsresult rv; diff --git a/mailnews/base/src/nsStatusBarBiffManager.cpp b/mailnews/base/src/nsStatusBarBiffManager.cpp index 08dfb7b76e..27f393986d 100644 --- a/mailnews/base/src/nsStatusBarBiffManager.cpp +++ b/mailnews/base/src/nsStatusBarBiffManager.cpp @@ -136,11 +136,13 @@ nsresult nsStatusBarBiffManager::PlayBiffSound(const char *aPrefBranch) } } } +#ifndef XP_MACOSX // if nothing played, play the default system sound if (!customSoundPlayed) { rv = mSound->PlayEventSound(nsISound::EVENT_NEW_MAIL_RECEIVED); NS_ENSURE_SUCCESS(rv, rv); } +#endif return rv; } diff --git a/mailnews/base/util/nsMsgUtils.cpp b/mailnews/base/util/nsMsgUtils.cpp index 6fc884d510..44609bea00 100644 --- a/mailnews/base/util/nsMsgUtils.cpp +++ b/mailnews/base/util/nsMsgUtils.cpp @@ -611,7 +611,7 @@ nsresult NS_MsgCreatePathStringFromFolderURI(const char *aFolderURI, ? oldPath.FindChar('/', startSlashPos + 1) - 1 : oldPath.Length() - 1; if (endSlashPos < 0) endSlashPos = oldPath.Length(); -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) bool isLocalUri = aScheme.EqualsLiteral("none") || aScheme.EqualsLiteral("pop3") || aScheme.EqualsLiteral("rss"); @@ -636,7 +636,7 @@ nsresult NS_MsgCreatePathStringFromFolderURI(const char *aFolderURI, CopyUTF16toMUTF7(pathPiece, tmp); CopyASCIItoUTF16(tmp, pathPiece); } -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) // Don't hash path pieces because local mail folder uri's have already // been hashed. We're only doing this on the mac to limit potential // regressions. diff --git a/mailnews/build/nsMailModule.cpp b/mailnews/build/nsMailModule.cpp index dea26047a0..5b86b4c3ef 100644 --- a/mailnews/build/nsMailModule.cpp +++ b/mailnews/build/nsMailModule.cpp @@ -102,6 +102,9 @@ #ifdef XP_WIN #include "nsMessengerWinIntegration.h" #endif +#ifdef XP_MACOSX +#include "nsMessengerOSXIntegration.h" +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) #include "nsMessengerUnixIntegration.h" #endif @@ -154,6 +157,12 @@ #include "nsAbOutlookDirectory.h" #endif +#ifdef XP_MACOSX +#include "nsAbOSXDirectory.h" +#include "nsAbOSXCard.h" +#include "nsAbOSXDirFactory.h" +#endif + //////////////////////////////////////////////////////////////////////////////// // bayesian spam filter includes //////////////////////////////////////////////////////////////////////////////// @@ -370,6 +379,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgShutdownService) #ifdef XP_WIN NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerWinIntegration, Init) #endif +#ifdef XP_MACOSX +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerOSXIntegration, Init) +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerUnixIntegration, Init) #endif @@ -427,6 +439,9 @@ NS_DEFINE_NAMED_CID(NS_MSGNOTIFICATIONSERVICE_CID); #ifdef XP_WIN NS_DEFINE_NAMED_CID(NS_MESSENGERWININTEGRATION_CID); #endif +#ifdef XP_MACOSX +NS_DEFINE_NAMED_CID(NS_MESSENGEROSXINTEGRATION_CID); +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) NS_DEFINE_NAMED_CID(NS_MESSENGERUNIXINTEGRATION_CID); #endif @@ -484,6 +499,12 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbView) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgVCardService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDIFService) +#ifdef XP_MACOSX +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXDirectory) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXCard) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXDirFactory) +#endif + NS_DEFINE_NAMED_CID(NS_ABMANAGER_CID); NS_DEFINE_NAMED_CID(NS_ABDIRECTORY_CID); NS_DEFINE_NAMED_CID(NS_ABMDBDIRECTORY_CID); @@ -515,6 +536,11 @@ NS_DEFINE_NAMED_CID(NS_ABLDAP_REPLICATIONQUERY_CID); NS_DEFINE_NAMED_CID(NS_ABLDAP_PROCESSREPLICATIONDATA_CID); #endif NS_DEFINE_NAMED_CID(NS_ABDIRECTORYQUERYPROXY_CID); +#ifdef XP_MACOSX +NS_DEFINE_NAMED_CID(NS_ABOSXDIRECTORY_CID); +NS_DEFINE_NAMED_CID(NS_ABOSXCARD_CID); +NS_DEFINE_NAMED_CID(NS_ABOSXDIRFACTORY_CID); +#endif NS_DEFINE_NAMED_CID(NS_ABVIEW_CID); NS_DEFINE_NAMED_CID(NS_MSGVCARDSERVICE_CID); NS_DEFINE_NAMED_CID(NS_ABLDIFSERVICE_CID); @@ -897,6 +923,9 @@ const mozilla::Module::CIDEntry kMailNewsCIDs[] = { #ifdef XP_WIN { &kNS_MESSENGERWININTEGRATION_CID, false, NULL, nsMessengerWinIntegrationConstructor}, #endif +#ifdef XP_MACOSX + { &kNS_MESSENGEROSXINTEGRATION_CID, false, NULL, nsMessengerOSXIntegrationConstructor}, +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) { &kNS_MESSENGERUNIXINTEGRATION_CID, false, NULL, nsMessengerUnixIntegrationConstructor}, #endif @@ -939,6 +968,11 @@ const mozilla::Module::CIDEntry kMailNewsCIDs[] = { { &kNS_ABLDAPDIRFACTORY_CID, false, NULL, nsAbLDAPDirFactoryConstructor }, #endif { &kNS_ABDIRECTORYQUERYPROXY_CID, false, NULL, nsAbDirectoryQueryProxyConstructor }, +#ifdef XP_MACOSX + { &kNS_ABOSXDIRECTORY_CID, false, NULL, nsAbOSXDirectoryConstructor }, + { &kNS_ABOSXCARD_CID, false, NULL, nsAbOSXCardConstructor }, + { &kNS_ABOSXDIRFACTORY_CID, false, NULL, nsAbOSXDirFactoryConstructor }, +#endif { &kNS_ABVIEW_CID, false, NULL, nsAbViewConstructor }, { &kNS_MSGVCARDSERVICE_CID, false, NULL, nsMsgVCardServiceConstructor }, { &kNS_ABLDIFSERVICE_CID, false, NULL, nsAbLDIFServiceConstructor }, @@ -1107,6 +1141,9 @@ const mozilla::Module::ContractIDEntry kMailNewsContracts[] = { #ifdef XP_WIN { NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGERWININTEGRATION_CID }, #endif +#ifdef XP_MACOSX + { NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGEROSXINTEGRATION_CID }, +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) { NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGERUNIXINTEGRATION_CID }, #endif @@ -1153,6 +1190,11 @@ const mozilla::Module::ContractIDEntry kMailNewsContracts[] = { #endif { NS_ABDIRECTORYQUERYPROXY_CONTRACTID, &kNS_ABDIRECTORYQUERYPROXY_CID }, +#ifdef XP_MACOSX + { NS_ABOSXDIRECTORY_CONTRACTID, &kNS_ABOSXDIRECTORY_CID }, + { NS_ABOSXCARD_CONTRACTID, &kNS_ABOSXCARD_CID }, + { NS_ABOSXDIRFACTORY_CONTRACTID, &kNS_ABOSXDIRFACTORY_CID }, +#endif { NS_ABVIEW_CONTRACTID, &kNS_ABVIEW_CID }, { NS_MSGVCARDSERVICE_CONTRACTID, &kNS_MSGVCARDSERVICE_CID }, { NS_ABLDIFSERVICE_CONTRACTID, &kNS_ABLDIFSERVICE_CID }, @@ -1301,6 +1343,10 @@ static const mozilla::Module::CategoryEntry kMailNewsCategories[] = { { XPCOM_DIRECTORY_PROVIDER_CATEGORY, "mail-directory-provider", NS_MAILDIRPROVIDER_CONTRACTID }, { "content-policy", NS_MSGCONTENTPOLICY_CONTRACTID, NS_MSGCONTENTPOLICY_CONTRACTID }, MAILNEWSDLF_CATEGORIES +#ifdef XP_MACOSX + { "app-startup", NS_MESSENGEROSINTEGRATION_CONTRACTID, "service," NS_MESSENGEROSINTEGRATION_CONTRACTID} +, +#endif // Address Book Entries { "command-line-handler", "m-addressbook", NS_ABMANAGERSTARTUPHANDLER_CONTRACTID }, // Bayesian Filter Entries diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.cpp b/mailnews/compose/src/nsMsgAttachmentHandler.cpp index 3c7e08bc13..4994c3fe69 100644 --- a/mailnews/compose/src/nsMsgAttachmentHandler.cpp +++ b/mailnews/compose/src/nsMsgAttachmentHandler.cpp @@ -36,6 +36,77 @@ #include "mozilla/mailnews/MimeEncoder.h" #include "nsIPrincipal.h" +/////////////////////////////////////////////////////////////////////////// +// Mac Specific Attachment Handling for AppleDouble Encoded Files +/////////////////////////////////////////////////////////////////////////// +#ifdef XP_MACOSX + +#define AD_WORKING_BUFF_SIZE FILE_IO_BUFFER_SIZE + +extern void MacGetFileType(nsIFile *fs, bool *useDefault, char **type, char **encoding); + +#include "nsILocalFileMac.h" + +/* static */ +nsresult nsSimpleZipper::Zip(nsIFile *aInputFile, nsIFile *aOutputFile) +{ + // create zipwriter object + nsresult rv; + nsCOMPtr<nsIZipWriter> zipWriter = do_CreateInstance("@mozilla.org/zipwriter;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = zipWriter->Open(aOutputFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + NS_ENSURE_SUCCESS(rv, rv); + + rv = AddToZip(zipWriter, aInputFile, EmptyCString()); + NS_ENSURE_SUCCESS(rv, rv); + + // we're done. + zipWriter->Close(); + return rv; +} + +/* static */ +nsresult nsSimpleZipper::AddToZip(nsIZipWriter *aZipWriter, + nsIFile *aFile, + const nsACString &aPath) +{ + // find out the path this file/dir should have in the zip + nsCString leafName; + aFile->GetNativeLeafName(leafName); + nsCString currentPath(aPath); + currentPath += leafName; + + bool isDirectory; + aFile->IsDirectory(&isDirectory); + // append slash for a directory entry + if (isDirectory) + currentPath.Append('/'); + + // add the file or directory entry to the zip + nsresult rv = aZipWriter->AddEntryFile(currentPath, nsIZipWriter::COMPRESSION_DEFAULT, aFile, false); + NS_ENSURE_SUCCESS(rv, rv); + + // if it's a directory, add all its contents too + if (isDirectory) { + nsCOMPtr<nsISimpleEnumerator> e; + nsresult rv = aFile->GetDirectoryEntries(getter_AddRefs(e)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIDirectoryEnumerator> dirEnumerator = do_QueryInterface(e, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIFile> currentFile; + while (NS_SUCCEEDED(dirEnumerator->GetNextFile(getter_AddRefs(currentFile))) && currentFile) { + rv = AddToZip(aZipWriter, currentFile, currentPath); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + return NS_OK; +} +#endif // XP_MACOSX + // // Class implementation... // @@ -168,7 +239,12 @@ NS_IMETHODIMP nsMsgAttachmentHandler::GetAlreadyEncoded(bool* aAlreadyEncoded) void nsMsgAttachmentHandler::CleanupTempFile() { -/** Mac Stub **/ +#ifdef XP_MACOSX + if (mEncodedWorkingFile) { + mEncodedWorkingFile->Remove(false); + mEncodedWorkingFile = nullptr; + } +#endif // XP_MACOSX } void @@ -473,8 +549,13 @@ FetcherURLDoneCallback(nsresult aStatus, ma->m_size = totalSize; if (!aContentType.IsEmpty()) { - // can't send appledouble on non-macs +#ifdef XP_MACOSX + //Do not change the type if we are dealing with an encoded (e.g., appledouble or zip) file + if (!ma->mEncodedWorkingFile) +#else + // can't send appledouble on non-macs if (!aContentType.EqualsLiteral("multipart/appledouble")) +#endif ma->m_type = aContentType; } @@ -617,6 +698,15 @@ done: return rv; } +#ifdef XP_MACOSX +bool nsMsgAttachmentHandler::HasResourceFork(FSRef *fsRef) +{ + FSCatalogInfo catalogInfo; + OSErr err = FSGetCatalogInfo(fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes, &catalogInfo, nullptr, nullptr, nullptr); + return (err == noErr && catalogInfo.rsrcLogicalSize != 0); +} +#endif + nsresult nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields) { @@ -657,6 +747,33 @@ nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields) nsCString sourceURISpec; rv = mURL->GetSpec(sourceURISpec); NS_ENSURE_SUCCESS(rv, rv); +#ifdef XP_MACOSX + if (!m_bogus_attachment && StringBeginsWith(sourceURISpec, NS_LITERAL_CSTRING("file://"))) + { + // Unescape the path (i.e. un-URLify it) before making a FSSpec + nsAutoCString filePath; + filePath.Adopt(nsMsgGetLocalFileFromURL(sourceURISpec.get())); + nsAutoCString unescapedFilePath; + MsgUnescapeString(filePath, 0, unescapedFilePath); + + nsCOMPtr<nsIFile> sourceFile; + NS_NewNativeLocalFile(unescapedFilePath, true, getter_AddRefs(sourceFile)); + if (!sourceFile) + return NS_ERROR_FAILURE; + + // check if it is a bundle. if it is, we'll zip it. + // if not, we'll apple encode it (applesingle or appledouble) + nsCOMPtr<nsILocalFileMac> macFile(do_QueryInterface(sourceFile)); + bool isPackage; + macFile->IsPackage(&isPackage); + if (isPackage) + rv = ConvertToZipFile(macFile); + else + rv = ConvertToAppleEncoding(sourceURISpec, unescapedFilePath, macFile); + + NS_ENSURE_SUCCESS(rv, rv); + } +#endif /* XP_MACOSX */ // // Ok, here we are, we need to fire the URL off and get the data @@ -676,6 +793,236 @@ nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields) return fetcher->FireURLRequest(mURL, mTmpFile, mOutFile, FetcherURLDoneCallback, this); } +#ifdef XP_MACOSX +nsresult +nsMsgAttachmentHandler::ConvertToZipFile(nsILocalFileMac *aSourceFile) +{ + // append ".zip" to the real file name + nsAutoCString zippedName; + nsresult rv = aSourceFile->GetNativeLeafName(zippedName); + NS_ENSURE_SUCCESS(rv, rv); + zippedName.AppendLiteral(".zip"); + + // create a temporary file that we'll work on + nsCOMPtr <nsIFile> tmpFile; + rv = nsMsgCreateTempFile(zippedName.get(), getter_AddRefs(tmpFile)); + NS_ENSURE_SUCCESS(rv, rv); + mEncodedWorkingFile = do_QueryInterface(tmpFile); + + // point our URL at the zipped temp file + NS_NewFileURI(getter_AddRefs(mURL), mEncodedWorkingFile); + + // zip it! + rv = nsSimpleZipper::Zip(aSourceFile, mEncodedWorkingFile); + NS_ENSURE_SUCCESS(rv, rv); + + // set some metadata for this attachment, that will affect the MIME headers. + m_type = APPLICATION_ZIP; + m_realName = zippedName.get(); + + return NS_OK; +} + +nsresult +nsMsgAttachmentHandler::ConvertToAppleEncoding(const nsCString &aFileURI, + const nsCString &aFilePath, + nsILocalFileMac *aSourceFile) +{ + // convert the apple file to AppleDouble first, and then patch the + // address in the url. + + //We need to retrieve the file type and creator... + + char fileInfo[32]; + OSType type, creator; + + nsresult rv = aSourceFile->GetFileType(&type); + if (NS_FAILED(rv)) + return rv; + PR_snprintf(fileInfo, sizeof(fileInfo), "%X", type); + m_xMacType = fileInfo; + + rv = aSourceFile->GetFileCreator(&creator); + if (NS_FAILED(rv)) + return rv; + PR_snprintf(fileInfo, sizeof(fileInfo), "%X", creator); + m_xMacCreator = fileInfo; + + FSRef fsRef; + aSourceFile->GetFSRef(&fsRef); + bool sendResourceFork = HasResourceFork(&fsRef); + + // if we have a resource fork, check the filename extension, maybe we don't need the resource fork! + if (sendResourceFork) + { + nsCOMPtr<nsIURL> fileUrl(do_CreateInstance(NS_STANDARDURL_CONTRACTID)); + if (fileUrl) + { + rv = fileUrl->SetSpec(aFileURI); + if (NS_SUCCEEDED(rv)) + { + nsAutoCString ext; + rv = fileUrl->GetFileExtension(ext); + if (NS_SUCCEEDED(rv) && !ext.IsEmpty()) + { + sendResourceFork = + PL_strcasecmp(ext.get(), "TXT") && + PL_strcasecmp(ext.get(), "JPG") && + PL_strcasecmp(ext.get(), "GIF") && + PL_strcasecmp(ext.get(), "TIF") && + PL_strcasecmp(ext.get(), "HTM") && + PL_strcasecmp(ext.get(), "HTML") && + PL_strcasecmp(ext.get(), "ART") && + PL_strcasecmp(ext.get(), "XUL") && + PL_strcasecmp(ext.get(), "XML") && + PL_strcasecmp(ext.get(), "CSS") && + PL_strcasecmp(ext.get(), "JS"); + } + } + } + } + + // Only use appledouble if we aren't uuencoding. + if( sendResourceFork ) + { + char *separator; + + separator = mime_make_separator("ad"); + if (!separator) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr <nsIFile> tmpFile; + nsresult rv = nsMsgCreateTempFile("appledouble", getter_AddRefs(tmpFile)); + if (NS_SUCCEEDED(rv)) + mEncodedWorkingFile = do_QueryInterface(tmpFile); + if (!mEncodedWorkingFile) + { + PR_FREEIF(separator); + return NS_ERROR_OUT_OF_MEMORY; + } + + // + // RICHIE_MAC - ok, here's the deal, we have a file that we need + // to encode in appledouble encoding for the resource fork and put that + // into the mEncodedWorkingFile location. Then, we need to patch the new file + // spec into the array and send this as part of the 2 part appledouble/mime + // encoded mime part. + // + AppleDoubleEncodeObject *obj = new (AppleDoubleEncodeObject); + if (obj == NULL) + { + mEncodedWorkingFile = nullptr; + PR_FREEIF(separator); + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = MsgGetFileStream(mEncodedWorkingFile, getter_AddRefs(obj->fileStream)); + if (NS_FAILED(rv) || !obj->fileStream) + { + PR_FREEIF(separator); + delete obj; + return NS_ERROR_OUT_OF_MEMORY; + } + + char *working_buff = (char *) PR_Malloc(AD_WORKING_BUFF_SIZE); + if (!working_buff) + { + PR_FREEIF(separator); + delete obj; + return NS_ERROR_OUT_OF_MEMORY; + } + + obj->buff = working_buff; + obj->s_buff = AD_WORKING_BUFF_SIZE; + + // + // Setup all the need information on the apple double encoder. + // + ap_encode_init(&(obj->ap_encode_obj), aFilePath.get(), separator); + + int32_t count; + + OSErr status = noErr; + m_size = 0; + while (status == noErr) + { + status = ap_encode_next(&(obj->ap_encode_obj), obj->buff, obj->s_buff, &count); + if (status == noErr || status == errDone) + { + // + // we got the encode data, so call the next stream to write it to the disk. + // + uint32_t bytesWritten; + obj->fileStream->Write(obj->buff, count, &bytesWritten); + if (bytesWritten != (uint32_t) count) + status = errFileWrite; + } + } + + ap_encode_end(&(obj->ap_encode_obj), (status >= 0)); // if this is true, ok, false abort + if (obj->fileStream) + obj->fileStream->Close(); + + PR_FREEIF(obj->buff); /* free the working buff. */ + PR_FREEIF(obj); + + nsCOMPtr <nsIURI> fileURI; + NS_NewFileURI(getter_AddRefs(fileURI), mEncodedWorkingFile); + + nsCOMPtr<nsIFileURL> theFileURL = do_QueryInterface(fileURI, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsCString newURLSpec; + rv = fileURI->GetSpec(newURLSpec); + NS_ENSURE_SUCCESS(rv, rv); + + if (newURLSpec.IsEmpty()) + { + PR_FREEIF(separator); + return NS_ERROR_OUT_OF_MEMORY; + } + + if (NS_FAILED(nsMsgNewURL(getter_AddRefs(mURL), newURLSpec.get()))) + { + PR_FREEIF(separator); + return NS_ERROR_OUT_OF_MEMORY; + } + + // Now after conversion, also patch the types. + char tmp[128]; + PR_snprintf(tmp, sizeof(tmp), MULTIPART_APPLEDOUBLE ";\r\n boundary=\"%s\"", separator); + PR_FREEIF(separator); + m_type = tmp; + } + else + { + if ( sendResourceFork ) + { + // For now, just do the encoding, but in the old world we would ask the + // user about doing this conversion + printf("...we could ask the user about this conversion, but for now, nahh..\n"); + } + + bool useDefault; + char *macType, *macEncoding; + if (m_type.IsEmpty() || m_type.LowerCaseEqualsLiteral(TEXT_PLAIN)) + { +# define TEXT_TYPE 0x54455854 /* the characters 'T' 'E' 'X' 'T' */ +# define text_TYPE 0x74657874 /* the characters 't' 'e' 'x' 't' */ + + if (type != TEXT_TYPE && type != text_TYPE) + { + MacGetFileType(aSourceFile, &useDefault, &macType, &macEncoding); + m_type = macType; + } + } + // don't bother to set the types if we failed in getting the file info. + } + + return NS_OK; +} +#endif // XP_MACOSX + nsresult nsMsgAttachmentHandler::LoadDataFromFile(nsIFile *file, nsString &sigData, bool charsetConversion) { diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.h b/mailnews/compose/src/nsMsgAttachmentHandler.h index 67ac474abd..2034cba032 100644 --- a/mailnews/compose/src/nsMsgAttachmentHandler.h +++ b/mailnews/compose/src/nsMsgAttachmentHandler.h @@ -16,6 +16,42 @@ #include "nsAutoPtr.h" #include "nsIMsgAttachmentHandler.h" +#ifdef XP_MACOSX + +#include "nsMsgAppleDouble.h" +#include "nsILocalFileMac.h" + +class AppleDoubleEncodeObject +{ +public: + appledouble_encode_object ap_encode_obj; + char *buff; // the working buff + int32_t s_buff; // the working buff size + nsCOMPtr <nsIOutputStream> fileStream; // file to hold the encoding +}; + +class nsILocalFileMac; +class nsIZipWriter; + +/* Simple utility class that will synchronously zip any file + (or folder hierarchy) you give it. */ +class nsSimpleZipper +{ + public: + + // Synchronously zips the input file/folder and writes all + // data to the output file. + static nsresult Zip(nsIFile *aInputFile, nsIFile *aOutputFile); + + private: + + // Recursively adds the file or folder to aZipWriter. + static nsresult AddToZip(nsIZipWriter *aZipWriter, + nsIFile *aFile, + const nsACString &aPath); +}; +#endif // XP_MACOSX + namespace mozilla { namespace mailnews { class MimeEncoder; @@ -59,6 +95,14 @@ private: bool UseUUEncode_p(void); void AnalyzeDataChunk (const char *chunk, int32_t chunkSize); nsresult LoadDataFromFile(nsIFile *file, nsString &sigData, bool charsetConversion); //A similar function already exist in nsMsgCompose! +#ifdef XP_MACOSX + nsresult ConvertToAppleEncoding(const nsCString &aFileSpecURI, + const nsCString &aFilePath, + nsILocalFileMac *aSourceFile); + // zips this attachment and does the work to make this attachment handler handle it properly. + nsresult ConvertToZipFile(nsILocalFileMac *aSourceFile); + bool HasResourceFork(FSRef *fsRef); +#endif // public: @@ -69,6 +113,12 @@ public: nsMsgCompFields *mCompFields; // Message composition fields for the sender bool m_bogus_attachment; // This is to catch problem children... +#ifdef XP_MACOSX + // if we need to encode this file into for example an appledouble, or zip file, + // this file is our working file. currently only needed on mac. + nsCOMPtr<nsIFile> mEncodedWorkingFile; +#endif + nsCString m_xMacType; // Mac file type nsCString m_xMacCreator; // Mac file creator diff --git a/mailnews/compose/src/nsMsgSend.cpp b/mailnews/compose/src/nsMsgSend.cpp index e328a9e21d..919d9bfc54 100644 --- a/mailnews/compose/src/nsMsgSend.cpp +++ b/mailnews/compose/src/nsMsgSend.cpp @@ -2088,7 +2088,9 @@ nsMsgComposeAndSend::AddCompFieldLocalAttachments() if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) { nsAutoCString type; mimeFinder->GetTypeFromExtension(fileExt, type); + #ifndef XP_MACOSX if (!type.Equals("multipart/appledouble")) // can't do apple double on non-macs + #endif m_attachments[newLoc]->m_type = type; } } @@ -2103,7 +2105,9 @@ nsMsgComposeAndSend::AddCompFieldLocalAttachments() if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) { nsAutoCString type; mimeFinder->GetTypeFromExtension(fileExt, type); + #ifndef XP_MACOSX if (!type.Equals("multipart/appledouble")) // can't do apple double on non-macs + #endif m_attachments[newLoc]->m_type = type; // rtf and vcs files may look like text to sniffers, // but they're not human readable. diff --git a/mailnews/imap/src/nsIMAPBodyShell.cpp b/mailnews/imap/src/nsIMAPBodyShell.cpp index b81978cc7b..087fe20337 100644 --- a/mailnews/imap/src/nsIMAPBodyShell.cpp +++ b/mailnews/imap/src/nsIMAPBodyShell.cpp @@ -724,8 +724,27 @@ bool nsIMAPBodypartLeaf::ShouldFetchInline(nsIMAPBodyShell *aShell) return false; // we can leave it on the server } +#ifdef XP_MACOSX + // If it is either applesingle, or a resource fork for appledouble + if (!PL_strcasecmp(m_contentType, "application/applefile")) + { + // if it is appledouble + if (m_parentPart->GetType() == IMAP_BODY_MULTIPART && + !PL_strcasecmp(m_parentPart->GetBodySubType(), "appledouble")) + { + // This is the resource fork of a multipart/appledouble. + // We inherit the inline attributes of the parent, + // which was derived from its OTHER child. (The data fork.) + return m_parentPart->ShouldFetchInline(aShell); + } + else // it is applesingle + { + return false; // we can leave it on the server + } + } +#endif // XP_MACOSX - // Leave out parts with type application/(*) + // Leave out parts with type application/* if (!PL_strcasecmp(m_bodyType, "APPLICATION") && // If it is of type "application" PL_strncasecmp(m_bodySubType, "x-pkcs7", 7) // and it's not a signature (signatures are inline) ) diff --git a/mailnews/import/applemail/src/moz.build b/mailnews/import/applemail/src/moz.build new file mode 100644 index 0000000000..fafbebc990 --- /dev/null +++ b/mailnews/import/applemail/src/moz.build @@ -0,0 +1,14 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + 'nsAppleMailImport.cpp', +] + +SOURCES += [ + 'nsEmlxHelperUtils.mm', +] + +FINAL_LIBRARY = 'import' + diff --git a/mailnews/import/applemail/src/nsAppleMailImport.cpp b/mailnews/import/applemail/src/nsAppleMailImport.cpp new file mode 100644 index 0000000000..3097b7df5e --- /dev/null +++ b/mailnews/import/applemail/src/nsAppleMailImport.cpp @@ -0,0 +1,623 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsStringGlue.h" +#include "nsCOMPtr.h" +#include "nsISupportsPrimitives.h" +#include "nsIImportService.h" +#include "nsIImportMailboxDescriptor.h" +#include "nsIImportGeneric.h" +#include "nsIFile.h" +#include "nsIStringBundle.h" +#include "nsIMsgFolder.h" +#include "nsIMsgHdr.h" +#include "nsIMsgPluggableStore.h" +#include "nsIMutableArray.h" +#include "nsNetUtil.h" +#include "nsMsgUtils.h" +#include "mozilla/Services.h" + +#include "nsEmlxHelperUtils.h" +#include "nsAppleMailImport.h" +#include "nsIOutputStream.h" + +PRLogModuleInfo *APPLEMAILLOGMODULE = nullptr; + +// some hard-coded strings +#define DEFAULT_MAIL_FOLDER "~/Library/Mail/" +#define POP_MBOX_SUFFIX ".mbox" +#define IMAP_MBOX_SUFFIX ".imapmbox" + +// stringbundle URI +#define APPLEMAIL_MSGS_URL "chrome://messenger/locale/appleMailImportMsgs.properties" + +// magic constants +#define kAccountMailboxID 1234 + +nsAppleMailImportModule::nsAppleMailImportModule() +{ + // Init logging module. + if (!APPLEMAILLOGMODULE) + APPLEMAILLOGMODULE = PR_NewLogModule("APPLEMAILIMPORTLOG"); + + IMPORT_LOG0("nsAppleMailImportModule Created"); + + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + if (bundleService) + bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(mBundle)); +} + + +nsAppleMailImportModule::~nsAppleMailImportModule() +{ + IMPORT_LOG0("nsAppleMailImportModule Deleted"); +} + + +NS_IMPL_ISUPPORTS(nsAppleMailImportModule, nsIImportModule) + + +NS_IMETHODIMP nsAppleMailImportModule::GetName(char16_t **aName) +{ + return mBundle ? + mBundle->GetStringFromName(u"ApplemailImportName", aName) : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetDescription(char16_t **aName) +{ + return mBundle ? + mBundle->GetStringFromName(u"ApplemailImportDescription", aName) : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetSupports(char **aSupports) +{ + NS_ENSURE_ARG_POINTER(aSupports); + *aSupports = strdup(NS_IMPORT_MAIL_STR); + return NS_OK; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetSupportsUpgrade(bool *aUpgrade) +{ + NS_ENSURE_ARG_POINTER(aUpgrade); + *aUpgrade = false; + return NS_OK; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetImportInterface(const char *aImportType, nsISupports **aInterface) +{ + NS_ENSURE_ARG_POINTER(aImportType); + NS_ENSURE_ARG_POINTER(aInterface); + *aInterface = nullptr; + nsresult rv = NS_ERROR_NOT_AVAILABLE; + + if (!strcmp(aImportType, "mail")) { + nsCOMPtr<nsIImportMail> mail(do_CreateInstance(NS_APPLEMAILIMPL_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIImportGeneric> generic; + rv = impSvc->CreateNewGenericMail(getter_AddRefs(generic)); + if (NS_SUCCEEDED(rv)) { + nsAutoString name; + rv = mBundle->GetStringFromName(u"ApplemailImportName", getter_Copies(name)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsISupportsString> nameString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + nameString->SetData(name); + + generic->SetData("name", nameString); + generic->SetData("mailInterface", mail); + + generic.forget(aInterface); + } + } + } + } + + return rv; +} + +#pragma mark - + +nsAppleMailImportMail::nsAppleMailImportMail() : mProgress(0), mCurDepth(0) +{ + IMPORT_LOG0("nsAppleMailImportMail created"); +} + +nsresult nsAppleMailImportMail::Initialize() +{ + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED); + + return bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(mBundle)); +} + +nsAppleMailImportMail::~nsAppleMailImportMail() +{ + IMPORT_LOG0("nsAppleMailImportMail destroyed"); +} + +NS_IMPL_ISUPPORTS(nsAppleMailImportMail, nsIImportMail) + +NS_IMETHODIMP nsAppleMailImportMail::GetDefaultLocation(nsIFile **aLocation, bool *aFound, bool *aUserVerify) +{ + NS_ENSURE_ARG_POINTER(aFound); + NS_ENSURE_ARG_POINTER(aLocation); + NS_ENSURE_ARG_POINTER(aUserVerify); + + *aLocation = nullptr; + *aFound = false; + *aUserVerify = true; + + // try to find current user's top-level Mail folder + nsCOMPtr<nsIFile> mailFolder(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + if (mailFolder) { + nsresult rv = mailFolder->InitWithNativePath(NS_LITERAL_CSTRING(DEFAULT_MAIL_FOLDER)); + if (NS_SUCCEEDED(rv)) { + *aFound = true; + *aUserVerify = false; + mailFolder.forget(aLocation); + } + } + + return NS_OK; +} + +// this is the method that initiates all searching for mailboxes. +// it will assume that it has a directory like ~/Library/Mail/ +NS_IMETHODIMP nsAppleMailImportMail::FindMailboxes(nsIFile *aMailboxFile, nsIArray **aResult) +{ + NS_ENSURE_ARG_POINTER(aMailboxFile); + NS_ENSURE_ARG_POINTER(aResult); + + IMPORT_LOG0("FindMailboxes for Apple mail invoked"); + + bool exists = false; + nsresult rv = aMailboxFile->Exists(&exists); + if (NS_FAILED(rv) || !exists) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIImportService> importService(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMutableArray> resultsArray(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv)); + if (!resultsArray) + return NS_ERROR_OUT_OF_MEMORY; + + mCurDepth = 1; + + // 1. look for accounts with mailboxes + FindAccountMailDirs(aMailboxFile, resultsArray, importService); + mCurDepth--; + + if (NS_SUCCEEDED(rv)) { + // 2. look for "global" mailboxes, that don't belong to any specific account. they are inside the + // root's Mailboxes/ folder + nsCOMPtr<nsIFile> mailboxesDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + mailboxesDir->InitWithFile(aMailboxFile); + rv = mailboxesDir->Append(NS_LITERAL_STRING("Mailboxes")); + if (NS_SUCCEEDED(rv)) { + IMPORT_LOG0("Looking for global Apple mailboxes"); + + mCurDepth++; + rv = FindMboxDirs(mailboxesDir, resultsArray, importService); + mCurDepth--; + } + } + } + + if (NS_SUCCEEDED(rv) && resultsArray) + resultsArray.forget(aResult); + + return rv; +} + +// operates on the Mail/ directory root, trying to find accounts (which are folders named something like "POP-hwaara@gmail.com") +// and add their .mbox dirs +void nsAppleMailImportMail::FindAccountMailDirs(nsIFile *aRoot, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService) +{ + nsCOMPtr<nsISimpleEnumerator> directoryEnumerator; + nsresult rv = aRoot->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv)) + return; + + bool hasMore = false; + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + + // get the next file entry + nsCOMPtr<nsIFile> currentEntry; + { + nsCOMPtr<nsISupports> rawSupports; + directoryEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + currentEntry = do_QueryInterface(rawSupports); + if (!currentEntry) + continue; + } + + // make sure it's a directory + bool isDirectory = false; + currentEntry->IsDirectory(&isDirectory); + + if (isDirectory) { + // now let's see if it's an account folder. if so, we want to traverse it for .mbox children + nsAutoString folderName; + currentEntry->GetLeafName(folderName); + bool isAccountFolder = false; + + if (StringBeginsWith(folderName, NS_LITERAL_STRING("POP-"))) { + // cut off "POP-" prefix so we get a nice folder name + folderName.Cut(0, 4); + isAccountFolder = true; + } + else if (StringBeginsWith(folderName, NS_LITERAL_STRING("IMAP-"))) { + // cut off "IMAP-" prefix so we get a nice folder name + folderName.Cut(0, 5); + isAccountFolder = true; + } + + if (isAccountFolder) { + IMPORT_LOG1("Found account: %s\n", NS_ConvertUTF16toUTF8(folderName).get()); + + // create a mailbox for this account, so we get a parent for "Inbox", "Sent Messages", etc. + nsCOMPtr<nsIImportMailboxDescriptor> desc; + nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc)); + desc->SetSize(1); + desc->SetDepth(mCurDepth); + desc->SetDisplayName(folderName.get()); + desc->SetIdentifier(kAccountMailboxID); + + nsCOMPtr<nsIFile> mailboxDescFile; + rv = desc->GetFile(getter_AddRefs(mailboxDescFile)); + if (!mailboxDescFile) + continue; + + mailboxDescFile->InitWithFile(currentEntry); + + // add this mailbox descriptor to the list + aMailboxDescs->AppendElement(desc, false); + + // now add all the children mailboxes + mCurDepth++; + FindMboxDirs(currentEntry, aMailboxDescs, aImportService); + mCurDepth--; + } + } + } +} + +// adds the specified file as a mailboxdescriptor to the array +nsresult nsAppleMailImportMail::AddMboxDir(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService) +{ + nsAutoString folderName; + aFolder->GetLeafName(folderName); + + // cut off the suffix, if any, or prefix if this is an account folder. + if (StringEndsWith(folderName, NS_LITERAL_STRING(POP_MBOX_SUFFIX))) + folderName.SetLength(folderName.Length()-5); + else if (StringEndsWith(folderName, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX))) + folderName.SetLength(folderName.Length()-9); + else if (StringBeginsWith(folderName, NS_LITERAL_STRING("POP-"))) + folderName.Cut(4, folderName.Length()); + else if (StringBeginsWith(folderName, NS_LITERAL_STRING("IMAP-"))) + folderName.Cut(5, folderName.Length()); + + nsCOMPtr<nsIImportMailboxDescriptor> desc; + nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc)); + if (NS_SUCCEEDED(rv)) { + // find out number of messages in this .mbox + uint32_t numMessages = 0; + { + // move to the .mbox's Messages folder + nsCOMPtr<nsIFile> messagesFolder; + aFolder->Clone(getter_AddRefs(messagesFolder)); + nsresult rv = messagesFolder->Append(NS_LITERAL_STRING("Messages")); + NS_ENSURE_SUCCESS(rv, rv); + + // count the number of messages in this folder. it sucks that we have to iterate through the folder + // but XPCOM doesn't give us any way to just get the file count, unfortunately. :-( + nsCOMPtr<nsISimpleEnumerator> dirEnumerator; + messagesFolder->GetDirectoryEntries(getter_AddRefs(dirEnumerator)); + if (dirEnumerator) { + bool hasMore = false; + while (NS_SUCCEEDED(dirEnumerator->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr<nsISupports> rawSupports; + dirEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + + nsCOMPtr<nsIFile> file(do_QueryInterface(rawSupports)); + if (file) { + bool isFile = false; + file->IsFile(&isFile); + if (isFile) + numMessages++; + } + } + } + } + + desc->SetSize(numMessages); + desc->SetDisplayName(folderName.get()); + desc->SetDepth(mCurDepth); + + IMPORT_LOG3("Will import %s with approx %d messages, depth is %d", NS_ConvertUTF16toUTF8(folderName).get(), numMessages, mCurDepth); + + // XXX: this is silly. there's no setter for the mailbox descriptor's file, so we need to get it, and then modify it. + nsCOMPtr<nsIFile> mailboxDescFile; + rv = desc->GetFile(getter_AddRefs(mailboxDescFile)); + NS_ENSURE_SUCCESS(rv, rv); + + if (mailboxDescFile) + mailboxDescFile->InitWithFile(aFolder); + + // add this mailbox descriptor to the list + aMailboxDescs->AppendElement(desc, false); + } + + return NS_OK; +} + +// Starts looking for .mbox dirs in the specified dir. The .mbox dirs contain messages and can be considered leafs in a tree of +// nested mailboxes (subfolders). +// +// If a mailbox has sub-mailboxes, they are contained in a sibling folder with the same name without the ".mbox" part. +// example: +// MyParentMailbox.mbox/ +// MyParentMailbox/ +// MyChildMailbox.mbox/ +// MyOtherChildMailbox.mbox/ +// +nsresult nsAppleMailImportMail::FindMboxDirs(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService) +{ + NS_ENSURE_ARG_POINTER(aFolder); + NS_ENSURE_ARG_POINTER(aMailboxDescs); + NS_ENSURE_ARG_POINTER(aImportService); + + // make sure this is a directory. + bool isDir = false; + if (NS_FAILED(aFolder->IsDirectory(&isDir)) || !isDir) + return NS_ERROR_FAILURE; + + // iterate through the folder contents + nsCOMPtr<nsISimpleEnumerator> directoryEnumerator; + nsresult rv = aFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv) || !directoryEnumerator) + return rv; + + bool hasMore = false; + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + + // get the next file entry + nsCOMPtr<nsIFile> currentEntry; + { + nsCOMPtr<nsISupports> rawSupports; + directoryEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + currentEntry = do_QueryInterface(rawSupports); + if (!currentEntry) + continue; + } + + // we only care about directories... + if (NS_FAILED(currentEntry->IsDirectory(&isDir)) || !isDir) + continue; + + // now find out if this is a .mbox dir + nsAutoString currentFolderName; + if (NS_SUCCEEDED(currentEntry->GetLeafName(currentFolderName)) && + (StringEndsWith(currentFolderName, NS_LITERAL_STRING(POP_MBOX_SUFFIX)) || + StringEndsWith(currentFolderName, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX)))) { + IMPORT_LOG1("Adding .mbox dir: %s", NS_ConvertUTF16toUTF8(currentFolderName).get()); + + // add this .mbox + rv = AddMboxDir(currentEntry, aMailboxDescs, aImportService); + if (NS_FAILED(rv)) { + IMPORT_LOG1("Couldn't add .mbox for import: %s ... continuing anyway", NS_ConvertUTF16toUTF8(currentFolderName).get()); + continue; + } + + // see if this .mbox dir has any sub-mailboxes + nsAutoString siblingMailboxDirPath; + currentEntry->GetPath(siblingMailboxDirPath); + + // cut off suffix + if (StringEndsWith(siblingMailboxDirPath, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX))) + siblingMailboxDirPath.SetLength(siblingMailboxDirPath.Length()-9); + else if (StringEndsWith(siblingMailboxDirPath, NS_LITERAL_STRING(POP_MBOX_SUFFIX))) + siblingMailboxDirPath.SetLength(siblingMailboxDirPath.Length()-5); + + IMPORT_LOG1("trying to locate a '%s'", NS_ConvertUTF16toUTF8(siblingMailboxDirPath).get()); + nsCOMPtr<nsIFile> siblingMailboxDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + continue; + + rv = siblingMailboxDir->InitWithPath(siblingMailboxDirPath); + bool reallyExists = false; + siblingMailboxDir->Exists(&reallyExists); + + if (NS_SUCCEEDED(rv) && reallyExists) { + IMPORT_LOG1("Found what looks like an .mbox container: %s", NS_ConvertUTF16toUTF8(currentFolderName).get()); + + // traverse this folder for other .mboxes + mCurDepth++; + FindMboxDirs(siblingMailboxDir, aMailboxDescs, aImportService); + mCurDepth--; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsAppleMailImportMail::ImportMailbox(nsIImportMailboxDescriptor *aMailbox, + nsIMsgFolder *aDstFolder, + char16_t **aErrorLog, + char16_t **aSuccessLog, bool *aFatalError) +{ + nsAutoString errorLog, successLog; + + // reset progress + mProgress = 0; + + nsAutoString mailboxName; + aMailbox->GetDisplayName(getter_Copies(mailboxName)); + + nsCOMPtr<nsIFile> mboxFolder; + nsresult rv = aMailbox->GetFile(getter_AddRefs(mboxFolder)); + if (NS_FAILED(rv) || !mboxFolder) { + ReportStatus(u"ApplemailImportMailboxConverterror", mailboxName, errorLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_ERROR_FAILURE; + } + + // if we're an account mailbox, nothing do. if we're a real mbox + // then we've got some messages to import! + uint32_t mailboxIdentifier; + aMailbox->GetIdentifier(&mailboxIdentifier); + + if (mailboxIdentifier != kAccountMailboxID) { + // move to the .mbox's Messages folder + nsCOMPtr<nsIFile> messagesFolder; + mboxFolder->Clone(getter_AddRefs(messagesFolder)); + rv = messagesFolder->Append(NS_LITERAL_STRING("Messages")); + if (NS_FAILED(rv)) { + // even if there are no messages, it might still be a valid mailbox, or even + // a parent for other mailboxes. + // + // just indicate that we're done, using the same number that we used to estimate + // number of messages earlier. + uint32_t finalSize; + aMailbox->GetSize(&finalSize); + mProgress = finalSize; + + // report that we successfully imported this mailbox + ReportStatus(u"ApplemailImportMailboxSuccess", mailboxName, successLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_OK; + } + + // let's import the messages! + nsCOMPtr<nsISimpleEnumerator> directoryEnumerator; + rv = messagesFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv)) { + ReportStatus(u"ApplemailImportMailboxConvertError", mailboxName, errorLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_ERROR_FAILURE; + } + + // prepare an outstream to the destination file + nsCOMPtr<nsIMsgPluggableStore> msgStore; + rv = aDstFolder->GetMsgStore(getter_AddRefs(msgStore)); + if (!msgStore || NS_FAILED(rv)) { + ReportStatus(u"ApplemailImportMailboxConverterror", mailboxName, errorLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_ERROR_FAILURE; + } + + bool hasMore = false; + nsCOMPtr<nsIOutputStream> outStream; + + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + // get the next file entry + nsCOMPtr<nsIFile> currentEntry; + { + nsCOMPtr<nsISupports> rawSupports; + directoryEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + currentEntry = do_QueryInterface(rawSupports); + if (!currentEntry) + continue; + } + + // make sure it's an .emlx file + bool isFile = false; + currentEntry->IsFile(&isFile); + if (!isFile) + continue; + + nsAutoString leafName; + currentEntry->GetLeafName(leafName); + if (!StringEndsWith(leafName, NS_LITERAL_STRING(".emlx"))) + continue; + + nsCOMPtr<nsIMsgDBHdr> msgHdr; + bool reusable; + rv = msgStore->GetNewMsgOutputStream(aDstFolder, getter_AddRefs(msgHdr), + &reusable, + getter_AddRefs(outStream)); + if (NS_FAILED(rv)) + break; + + // add the data to the mbox stream + if (NS_SUCCEEDED(nsEmlxHelperUtils::AddEmlxMessageToStream(currentEntry, outStream))) { + mProgress++; + msgStore->FinishNewMessage(outStream, msgHdr); + } + else { + msgStore->DiscardNewMessage(outStream, msgHdr); + break; + } + if (!reusable) + outStream->Close(); + } + if (outStream) + outStream->Close(); + } + // just indicate that we're done, using the same number that we used to estimate + // number of messages earlier. + uint32_t finalSize; + aMailbox->GetSize(&finalSize); + mProgress = finalSize; + + // report that we successfully imported this mailbox + ReportStatus(u"ApplemailImportMailboxSuccess", mailboxName, successLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + + return NS_OK; +} + +void nsAppleMailImportMail::ReportStatus(const char16_t* aErrorName, nsString &aName, + nsAString &aStream) +{ + // get (and format, if needed) the error string from the bundle + nsAutoString outString; + const char16_t *fmt = { aName.get() }; + nsresult rv = mBundle->FormatStringFromName(aErrorName, &fmt, 1, getter_Copies(outString)); + // write it out the stream + if (NS_SUCCEEDED(rv)) { + aStream.Append(outString); + aStream.Append(char16_t('\n')); + } +} + +void nsAppleMailImportMail::SetLogs(const nsAString &aSuccess, const nsAString &aError, char16_t **aOutSuccess, char16_t **aOutError) +{ + if (aOutError && !*aOutError) + *aOutError = ToNewUnicode(aError); + if (aOutSuccess && !*aOutSuccess) + *aOutSuccess = ToNewUnicode(aSuccess); +} + +NS_IMETHODIMP nsAppleMailImportMail::GetImportProgress(uint32_t *aDoneSoFar) +{ + NS_ENSURE_ARG_POINTER(aDoneSoFar); + *aDoneSoFar = mProgress; + return NS_OK; +} + +NS_IMETHODIMP nsAppleMailImportMail::TranslateFolderName(const nsAString &aFolderName, nsAString &aResult) +{ + aResult = aFolderName; + return NS_OK; +} diff --git a/mailnews/import/applemail/src/nsAppleMailImport.h b/mailnews/import/applemail/src/nsAppleMailImport.h new file mode 100644 index 0000000000..b906aecf56 --- /dev/null +++ b/mailnews/import/applemail/src/nsAppleMailImport.h @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsAppleMailImport_h___ +#define nsAppleMailImport_h___ + +#include "mozilla/Logging.h" +#include "nsIImportModule.h" +#include "nsCOMPtr.h" +#include "nsIStringBundle.h" +#include "nsIImportMail.h" + +// logging facilities +extern PRLogModuleInfo *APPLEMAILLOGMODULE; + +#define IMPORT_LOG0(x) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x)) +#define IMPORT_LOG1(x, y) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x, y)) +#define IMPORT_LOG2(x, y, z) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x, y, z)) +#define IMPORT_LOG3(a, b, c, d) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (a, b, c, d)) + +#define NS_APPLEMAILIMPL_CID \ +{ 0x9117a1ea, 0xe012, 0x43b5, { 0xa0, 0x20, 0xcb, 0x8a, 0x66, 0xcc, 0x09, 0xe1 } } + +#define NS_APPLEMAILIMPORT_CID \ +{ 0x6d3f101c, 0x70ec, 0x4e04, { 0xb6, 0x8d, 0x99, 0x08, 0xd1, 0xae, 0xdd, 0xf3 } } + +#define NS_APPLEMAILIMPL_CONTRACTID "@mozilla.org/import/import-appleMailImpl;1" + +#define kAppleMailSupportsString "mail" + +class nsIImportService; +class nsIMutableArray; + +class nsAppleMailImportModule : public nsIImportModule +{ + public: + + nsAppleMailImportModule(); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIIMPORTMODULE + + private: + virtual ~nsAppleMailImportModule(); + + nsCOMPtr<nsIStringBundle> mBundle; +}; + +class nsAppleMailImportMail : public nsIImportMail +{ + public: + + nsAppleMailImportMail(); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIIMPORTMAIL + + nsresult Initialize(); + + private: + virtual ~nsAppleMailImportMail(); + + void FindAccountMailDirs(nsIFile *aRoot, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService); + nsresult FindMboxDirs(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService); + nsresult AddMboxDir(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService); + + // aInfoString is the format to a "foo %s" string. It may be NULL if the error string needs no such format. + void ReportStatus(const char16_t* aErrorName, nsString &aName, nsAString &aStream); + static void SetLogs(const nsAString& success, const nsAString& error, char16_t **aOutErrorLog, char16_t **aSuccessLog); + + nsCOMPtr<nsIStringBundle> mBundle; + uint32_t mProgress; + uint16_t mCurDepth; +}; + +#endif /* nsAppleMailImport_h___ */ diff --git a/mailnews/import/applemail/src/nsEmlxHelperUtils.h b/mailnews/import/applemail/src/nsEmlxHelperUtils.h new file mode 100644 index 0000000000..728b725b60 --- /dev/null +++ b/mailnews/import/applemail/src/nsEmlxHelperUtils.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsEmlxHelperUtils_h___ +#define nsEmlxHelperUtils_h___ + +#include "nscore.h" +#include "nsStringGlue.h" + +class nsIOutputStream; +class nsIFile; + +class nsEmlxHelperUtils { + /* All emlx messages have a "flags" number in the metadata. + These are the masks to decode that, found via http://jwz.livejournal.com/505711.html */ + enum EmlxMetadataMask { + kRead = 1 << 0, // read + // 1 << 1, // deleted + kAnswered = 1 << 2, // answered + // 1 << 3, // encrypted + kFlagged = 1 << 4, // flagged + // 1 << 5, // recent + // 1 << 6, // draft + // 1 << 7, // initial (no longer used) + kForwarded = 1 << 8, // forwarded + // 1 << 9, // redirected + // 3F << 10, // attachment count (6 bits) + // 7F << 16, // priority level (7 bits) + // 1 << 23, // signed + // 1 << 24, // is junk + // 1 << 25, // is not junk + // 1 << 26, // font size delta 7 (3 bits) + // 1 << 29, // junk mail level recorded + // 1 << 30, // highlight text in toc + // 1 << 31 // (unused) + }; + + // This method will scan the raw EMLX message buffer for "dangerous" so-called "From-lines" that we need to escape. + // If it needs to modify any lines, it will return a non-NULL aOutBuffer. If aOutBuffer is NULL, no modification needed + // to be made. + static nsresult ConvertToMboxRD(const char *aMessageBufferStart, const char *aMessageBufferEnd, nsCString &aOutBuffer); + + // returns an int representing the X-Mozilla-Status flags set (e.g. "read", "flagged") converted from EMLX flags. + static nsresult ConvertToMozillaStatusFlags(const char *aXMLBufferStart, const char *aXMLBufferEnd, uint32_t *aMozillaStatusFlags); + + public: + + // add an .emlx message to the mbox output + static nsresult AddEmlxMessageToStream(nsIFile *aEmlxFile, nsIOutputStream *aOutoutStream); + +}; + +#endif // nsEmlxHelperUtils_h___ diff --git a/mailnews/import/applemail/src/nsEmlxHelperUtils.mm b/mailnews/import/applemail/src/nsEmlxHelperUtils.mm new file mode 100644 index 0000000000..d2feb166e6 --- /dev/null +++ b/mailnews/import/applemail/src/nsEmlxHelperUtils.mm @@ -0,0 +1,240 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsEmlxHelperUtils.h" +#include "nsIFileStreams.h" +#include "nsIBufferedStreams.h" +#include "nsIOutputStream.h" +#include "nsNetUtil.h" +#include "nsCOMPtr.h" +#include "nsObjCExceptions.h" +#include "nsMsgMessageFlags.h" +#include "nsMsgLocalFolderHdrs.h" +#include "msgCore.h" +#include "nsTArray.h" +#include "nsAppleMailImport.h" +#include "prprf.h" +#include "nsIFile.h" + +#import <Cocoa/Cocoa.h> + + +nsresult nsEmlxHelperUtils::ConvertToMozillaStatusFlags(const char *aXMLBufferStart, + const char *aXMLBufferEnd, + uint32_t *aMozillaStatusFlags) +{ + // create a NSData wrapper around the buffer, so we can use the Cocoa call below + NSData *metadata = + [[[NSData alloc] initWithBytesNoCopy:(void *)aXMLBufferStart length:(aXMLBufferEnd-aXMLBufferStart) freeWhenDone:NO] autorelease]; + + // get the XML data as a dictionary + NSPropertyListFormat format; + id plist = [NSPropertyListSerialization propertyListWithData:metadata + options:NSPropertyListImmutable + format:&format + error:NULL]; + + if (!plist) + return NS_ERROR_FAILURE; + + // find the <flags>...</flags> value and convert to int + const uint32_t emlxMessageFlags = [[(NSDictionary *)plist objectForKey:@"flags"] intValue]; + + if (emlxMessageFlags == 0) + return NS_ERROR_FAILURE; + + if (emlxMessageFlags & nsEmlxHelperUtils::kRead) + *aMozillaStatusFlags |= nsMsgMessageFlags::Read; + if (emlxMessageFlags & nsEmlxHelperUtils::kForwarded) + *aMozillaStatusFlags |= nsMsgMessageFlags::Forwarded; + if (emlxMessageFlags & nsEmlxHelperUtils::kAnswered) + *aMozillaStatusFlags |= nsMsgMessageFlags::Replied; + if (emlxMessageFlags & nsEmlxHelperUtils::kFlagged) + *aMozillaStatusFlags |= nsMsgMessageFlags::Marked; + + return NS_OK; +} + +nsresult nsEmlxHelperUtils::ConvertToMboxRD(const char *aMessageBufferStart, const char *aMessageBufferEnd, nsCString &aOutBuffer) +{ + nsTArray<const char *> foundFromLines; + + const char *cur = aMessageBufferStart; + while (cur < aMessageBufferEnd) { + + const char *foundFromStr = strnstr(cur, "From ", aMessageBufferEnd-cur); + + if (foundFromStr) { + // skip all prepending '>' chars + const char *fromLineStart = foundFromStr; + while (fromLineStart-- >= aMessageBufferStart) { + if (*fromLineStart == '\n' || fromLineStart == aMessageBufferStart) { + if (fromLineStart > aMessageBufferStart) + fromLineStart++; + foundFromLines.AppendElement(fromLineStart); + break; + } + else if (*fromLineStart != '>') + break; + } + + // advance past the last found From string. + cur = foundFromStr + 5; + + // look for more From lines. + continue; + } + + break; + } + + // go through foundFromLines + if (foundFromLines.Length()) { + + const char *chunkStart = aMessageBufferStart; + for (unsigned i=0; i<foundFromLines.Length(); ++i) { + aOutBuffer.Append(chunkStart, (foundFromLines[i]-chunkStart)); + aOutBuffer.Append(NS_LITERAL_CSTRING(">")); + + chunkStart = foundFromLines[i]; + } + aOutBuffer.Append(chunkStart, (aMessageBufferEnd - chunkStart)); + } + + return NS_OK; +} + +nsresult nsEmlxHelperUtils::AddEmlxMessageToStream(nsIFile *aMessage, nsIOutputStream *aOut) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + // needed to be sure autoreleased objects are released too, which they might not + // in a C++ environment where the main event loop has no autorelease pool (e.g on a XPCOM thread) + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + nsresult rv = NS_ERROR_FAILURE; + + nsAutoCString path; + aMessage->GetNativePath(path); + + NSData *data = [NSData dataWithContentsOfFile:[NSString stringWithUTF8String:path.get()]]; + if (!data) { + [pool release]; + return NS_ERROR_FAILURE; + } + + char *startOfMessageData = NULL; + uint32_t actualBytesWritten = 0; + + // The anatomy of an EMLX file: + // + // ------------------------------- + // < A number describing how many bytes ahead there is message data > + // < Message data > + // < XML metadata for this message > + // ------------------------------- + + // read the first line of the emlx file, which is a number of how many bytes ahead the actual + // message data is. + uint64_t numberOfBytesToRead = strtol((char *)[data bytes], &startOfMessageData, 10); + if (numberOfBytesToRead <= 0 || !startOfMessageData) { + [pool release]; + return NS_ERROR_FAILURE; + } + + // skip whitespace + while (*startOfMessageData == ' ' || + *startOfMessageData == '\n' || + *startOfMessageData == '\r' || + *startOfMessageData == '\t') + ++startOfMessageData; + + NS_NAMED_LITERAL_CSTRING(kBogusFromLine, "From \n"); + NS_NAMED_LITERAL_CSTRING(kEndOfMessage, "\n\n"); + + // write the bogus "From " line which is a magic separator in the mbox format + rv = aOut->Write(kBogusFromLine.get(), kBogusFromLine.Length(), &actualBytesWritten); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // now read the XML metadata, so we can extract info like which flags (read? replied? flagged? etc) this message has. + const char *startOfXMLMetadata = startOfMessageData + numberOfBytesToRead; + const char *endOfXMLMetadata = (char *)[data bytes] + [data length]; + + uint32_t x_mozilla_flags = 0; + ConvertToMozillaStatusFlags(startOfXMLMetadata, endOfXMLMetadata, &x_mozilla_flags); + + // write the X-Mozilla-Status header according to which flags we've gathered above. + uint32_t dummyRv; + nsAutoCString buf(PR_smprintf(X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, x_mozilla_flags)); + NS_ASSERTION(!buf.IsEmpty(), "printf error with X-Mozilla-Status header"); + if (buf.IsEmpty()) { + [pool release]; + return rv; + } + + rv = aOut->Write(buf.get(), buf.Length(), &dummyRv); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // write out X-Mozilla-Keywords header as well to reserve some space for it + // in the mbox file. + rv = aOut->Write(X_MOZILLA_KEYWORDS, X_MOZILLA_KEYWORDS_LEN, &dummyRv); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // write out empty X-Mozilla_status2 header + buf.Adopt(PR_smprintf(X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, 0)); + NS_ASSERTION(!buf.IsEmpty(), "printf error with X-Mozilla-Status2 header"); + if (buf.IsEmpty()) { + [pool release]; + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = aOut->Write(buf.get(), buf.Length(), &dummyRv); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // do any conversion needed for the mbox data to be valid mboxrd. + nsCString convertedData; + rv = ConvertToMboxRD(startOfMessageData, (startOfMessageData + numberOfBytesToRead), convertedData); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // write the actual message data. + if (convertedData.IsEmpty()) + rv = aOut->Write(startOfMessageData, (uint32_t)numberOfBytesToRead, &actualBytesWritten); + else { + IMPORT_LOG1("Escaped From-lines in %s!", path.get()); + rv = aOut->Write(convertedData.get(), convertedData.Length(), &actualBytesWritten); + } + + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + NS_ASSERTION(actualBytesWritten == (convertedData.IsEmpty() ? numberOfBytesToRead : convertedData.Length()), + "Didn't write as many bytes as expected for .emlx file?"); + + // add newlines to denote the end of this message in the mbox + rv = aOut->Write(kEndOfMessage.get(), kEndOfMessage.Length(), &actualBytesWritten); + + [pool release]; + + return rv; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} diff --git a/mailnews/import/build/nsImportModule.cpp b/mailnews/import/build/nsImportModule.cpp index 813271b08f..f8f3814e6e 100644 --- a/mailnews/import/build/nsImportModule.cpp +++ b/mailnews/import/build/nsImportModule.cpp @@ -33,6 +33,16 @@ NS_DEFINE_NAMED_CID(NS_TEXTIMPORT_CID); NS_DEFINE_NAMED_CID(NS_VCARDIMPORT_CID); //////////////////////////////////////////////////////////////////////////////// +// Apple Mail import Include Files +//////////////////////////////////////////////////////////////////////////////// +#if defined(XP_MACOSX) +#include "nsAppleMailImport.h" + +NS_DEFINE_NAMED_CID(NS_APPLEMAILIMPORT_CID); +NS_DEFINE_NAMED_CID(NS_APPLEMAILIMPL_CID); +#endif + +//////////////////////////////////////////////////////////////////////////////// // outlook import Include Files //////////////////////////////////////////////////////////////////////////////// #ifdef XP_WIN @@ -76,6 +86,14 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextImport) NS_GENERIC_FACTORY_CONSTRUCTOR(nsVCardImport) //////////////////////////////////////////////////////////////////////////////// +// apple mail import factories +//////////////////////////////////////////////////////////////////////////////// +#if defined(XP_MACOSX) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAppleMailImportModule) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAppleMailImportMail, Initialize) +#endif + +//////////////////////////////////////////////////////////////////////////////// // outlook import factories //////////////////////////////////////////////////////////////////////////////// #ifdef XP_WIN @@ -103,6 +121,9 @@ static const mozilla::Module::CategoryEntry kMailNewsImportCategories[] = { { "mailnewsimport", "{1DB469A0-8B00-11d3-A206-00A0CC26DA63}", kOutlookSupportsString }, #endif #endif +#if defined(XP_MACOSX) + { "mailnewsimport", "{6d3f101c-70ec-4e04-b68d-9908d1aeddf3}", kAppleMailSupportsString }, +#endif { NULL } }; @@ -111,6 +132,11 @@ const mozilla::Module::CIDEntry kMailNewsImportCIDs[] = { { &kNS_IMPORTMIMEENCODE_CID, false, NULL, nsIImportMimeEncodeImplConstructor }, { &kNS_TEXTIMPORT_CID, false, NULL, nsTextImportConstructor }, { &kNS_VCARDIMPORT_CID, false, NULL, nsVCardImportConstructor }, +#if defined(XP_MACOSX) + { &kNS_APPLEMAILIMPORT_CID, false, NULL, nsAppleMailImportModuleConstructor }, + { &kNS_APPLEMAILIMPL_CID, false, NULL, nsAppleMailImportMailConstructor }, +#endif + #ifdef XP_WIN { &kNS_WMIMPORT_CID, false, NULL, nsWMImportConstructor }, { &kNS_BECKYIMPORT_CID, false, NULL, nsBeckyImportConstructor }, @@ -126,6 +152,11 @@ const mozilla::Module::ContractIDEntry kMailNewsImportContracts[] = { { "@mozilla.org/import/import-mimeencode;1", &kNS_IMPORTMIMEENCODE_CID }, { "@mozilla.org/import/import-text;1", &kNS_TEXTIMPORT_CID }, { "@mozilla.org/import/import-vcard;1", &kNS_VCARDIMPORT_CID }, +#if defined(XP_MACOSX) + { "@mozilla.org/import/import-applemail;1", &kNS_APPLEMAILIMPORT_CID }, + { NS_APPLEMAILIMPL_CONTRACTID, &kNS_APPLEMAILIMPL_CID }, +#endif + #ifdef XP_WIN { "@mozilla.org/import/import-wm;1", &kNS_WMIMPORT_CID }, { "@mozilla.org/import/import-becky;1", &kNS_BECKYIMPORT_CID }, diff --git a/mailnews/import/content/importDialog.xul b/mailnews/import/content/importDialog.xul index 1223a12635..383585f83e 100644 --- a/mailnews/import/content/importDialog.xul +++ b/mailnews/import/content/importDialog.xul @@ -15,7 +15,11 @@ <window xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="OnLoadImportDialog()" +#ifdef XP_MACOSX + style="width: &window.macWidth; !important;" +#else style="width: &window.width; !important;" +#endif title="&importDialog.windowTitle;"> <stringbundle id="bundle_importMsgs" src="chrome://messenger/locale/importMsgs.properties"/> diff --git a/mailnews/jar.mn b/mailnews/jar.mn index 8b850ecb91..71539e9aa0 100644 --- a/mailnews/jar.mn +++ b/mailnews/jar.mn @@ -131,6 +131,8 @@ messenger.jar: content/messenger/dateFormat.js (base/content/dateFormat.js) content/messenger/shutdownWindow.xul (base/content/shutdownWindow.xul) content/messenger/shutdownWindow.js (base/content/shutdownWindow.js) +#ifndef XP_MACOSX content/messenger/newmailalert.css (base/content/newmailalert.css) content/messenger/newmailalert.js (base/content/newmailalert.js) content/messenger/newmailalert.xul (base/content/newmailalert.xul) +#endif diff --git a/mailnews/mailnews.js b/mailnews/mailnews.js index ae172305d2..49ac33827e 100644 --- a/mailnews/mailnews.js +++ b/mailnews/mailnews.js @@ -696,7 +696,11 @@ pref("mail.biff.alert.show_subject", true); pref("mail.biff.alert.show_sender", true); pref("mail.biff.alert.preview_length", 40); +#ifdef XP_MACOSX +pref("mail.biff.play_sound", false); +#else pref("mail.biff.play_sound", true); +#endif // 0 == default system sound, 1 == user specified wav pref("mail.biff.play_sound.type", 0); // _moz_mailbeep is a magic key, for the default sound. @@ -706,6 +710,8 @@ pref("mail.biff.show_alert", true); #ifdef XP_WIN pref("mail.biff.show_tray_icon", true); pref("mail.biff.show_balloon", false); +#elifdef XP_MACOSX +pref("mail.biff.animate_dock_icon", false); #elifdef XP_UNIX pref("mail.biff.use_system_alert", false); #endif @@ -718,6 +724,13 @@ pref("mail.biff.add_interval_jitter", true); pref("mail.biff.on_new_window", true); #endif +#ifdef XP_MACOSX +// If true, the number used in the Mac OS X dock notification will be the +// the number of "new" messages, as per the classic Thunderbird definition. +// Defaults to false, which notifies about the number of unread messages. +pref("mail.biff.use_new_count_in_mac_dock", false); +#endif + // For feed account serverType=rss sound on biff; if true, mail.biff.play_sound.* settings are used. pref("mail.feed.play_sound", false); @@ -834,6 +847,15 @@ pref("ldap_2.servers.oe.description", "chrome://messenger/locale/addressbook/add pref("ldap_2.servers.oe.dirType", 3); #endif #endif +#ifdef XP_MACOSX +pref("ldap_2.servers.osx.uri", "moz-abosxdirectory:///"); +pref("ldap_2.servers.osx.description", "chrome://messenger/locale/addressbook/addressBook.properties"); +pref("ldap_2.servers.osx.dirType", 3); +pref("mail.notification.sound", ""); +pref("mail.notification.count.inbox_only", true); +// Work around bug 482811 by disabling slow script warning for chrome scripts on Mac +pref("dom.max_chrome_script_run_time", 0); +#endif // gtk2 (*nix) lacks transparent/translucent drag support (bug 376238), so we // want to disable it so people can see where they are dragging things. diff --git a/mailnews/mime/src/mimeebod.cpp b/mailnews/mime/src/mimeebod.cpp index ee66c40ca2..2ca056feb8 100644 --- a/mailnews/mime/src/mimeebod.cpp +++ b/mailnews/mime/src/mimeebod.cpp @@ -21,6 +21,10 @@ MimeDefClass(MimeExternalBody, MimeExternalBodyClass, mimeExternalBodyClass, &MIME_SUPERCLASS); +#ifdef XP_MACOSX +extern MimeObjectClass mimeMultipartAppleDoubleClass; +#endif + static int MimeExternalBody_initialize (MimeObject *); static void MimeExternalBody_finalize (MimeObject *); static int MimeExternalBody_parse_line (const char *, int32_t, MimeObject *); @@ -248,6 +252,12 @@ MimeExternalBody_parse_eof (MimeObject *obj, bool abort_p) status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p); if (status < 0) return status; +#ifdef XP_MACOSX + if (obj->parent && mime_typep(obj->parent, + (MimeObjectClass*) &mimeMultipartAppleDoubleClass)) + goto done; +#endif /* XP_MACOSX */ + if (!abort_p && obj->output_p && obj->options && @@ -415,6 +425,10 @@ FAIL: PR_FREEIF(subj); } +#ifdef XP_MACOSX +done: +#endif + return status; } diff --git a/mailnews/mime/src/mimemapl.cpp b/mailnews/mime/src/mimemapl.cpp index c7363ceff1..449d80ac08 100644 --- a/mailnews/mime/src/mimemapl.cpp +++ b/mailnews/mime/src/mimemapl.cpp @@ -55,6 +55,19 @@ MimeMultipartAppleDouble_parse_begin (MimeObject *obj) NS_ASSERTION(obj->options->state->first_data_written_p, "first data not written"); } +#ifdef XP_MACOSX + if (obj->options && obj->options->state) + { +// obj->options->state->separator_suppressed_p = true; + goto done; + } + /* + * It would be nice to not showing the resource fork links + * if we are displaying inline. But, there is no way we could + * know ahead of time that we could display the data fork and + * the data fork is always hidden on MAC platform. + */ +#endif /* If we're writing this object as HTML, then emit a link for the multipart/appledouble part (both links) that looks just like the links that MimeExternalObject emits for external leaf parts. @@ -143,6 +156,10 @@ GOTTA STILL DO THIS FOR QUOTING! if (status < 0) return status; } +#ifdef XP_MACOSX +done: +#endif + return 0; } @@ -159,8 +176,13 @@ MimeMultipartAppleDouble_output_child_p(MimeObject *obj, MimeObject *child) if (cont->nchildren >= 1 && cont->children[0] == child && child->content_type && !PL_strcasecmp(child->content_type, APPLICATION_APPLEFILE)) { - /* Don't emit the resources fork. */ +#ifdef XP_MACOSX + if (obj->output_p && obj->options && obj->options->write_html_p) //output HTML + return false; +#else + /* if we are not on a Macintosh, don't emitte the resources fork at all. */ return false; +#endif } return true; diff --git a/mailnews/mime/src/mimemult.cpp b/mailnews/mime/src/mimemult.cpp index c92cc44dcf..4695ba9910 100644 --- a/mailnews/mime/src/mimemult.cpp +++ b/mailnews/mime/src/mimemult.cpp @@ -16,6 +16,10 @@ #include "nsMimeTypes.h" #include <ctype.h> +#ifdef XP_MACOSX + extern MimeObjectClass mimeMultipartAppleDoubleClass; +#endif + #define MIME_SUPERCLASS mimeContainerClass MimeDefClass(MimeMultipart, MimeMultipartClass, mimeMultipartClass, &MIME_SUPERCLASS); @@ -488,6 +492,19 @@ MimeMultipart_create_child(MimeObject *obj) { status = body->clazz->parse_begin(body); +#ifdef XP_MACOSX + /* if we are saving an apple double attachment, we need to set correctly the conten type of the channel */ + if (mime_typep(obj, (MimeObjectClass *) &mimeMultipartAppleDoubleClass)) + { + mime_stream_data *msd = (mime_stream_data *)body->options->stream_closure; + if (!body->options->write_html_p && body->content_type && !PL_strcasecmp(body->content_type, APPLICATION_APPLEFILE)) + { + if (msd && msd->channel) + msd->channel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_APPLEFILE)); + } + } +#endif + if (status < 0) return status; } diff --git a/mailnews/moz.build b/mailnews/moz.build index 55b80c443a..6e75c8012e 100644 --- a/mailnews/moz.build +++ b/mailnews/moz.build @@ -23,6 +23,11 @@ DIRS += [ 'news', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + DIRS += [ + 'import/applemail/src', + ] + if CONFIG['OS_ARCH'] == 'WINNT': DIRS += [ 'import/becky/src' ] |