diff --git a/mozilla/mail/locales/en-US/chrome/messenger/appleMailImportMsgs.properties b/mozilla/mail/locales/en-US/chrome/messenger/appleMailImportMsgs.properties new file mode 100644 index 00000000000..b035715d875 --- /dev/null +++ b/mozilla/mail/locales/en-US/chrome/messenger/appleMailImportMsgs.properties @@ -0,0 +1,64 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Apple Mail importer code. +# +# The Initial Developer of the Original Code is +# Håkan Waara . +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +# Short name of import module +## @name APPLEMAILIMPORT_NAME +## @loc None +2000=Apple Mail + +# Description of import module +## @name APPLEMAILIMPORT_DESCRIPTION +## @loc None +2001=Import Local Mail from Mac OS X Mail + +# Success Message +# LOCALIZATION NOTE : Do not translate the word "%S" below. +## @name APPLEMAILIMPORT_MAILBOX_SUCCESS +## @loc None +2002=Local messages were successfully imported from %S + +# Error Message +## @name APPLEMAILIMPORT_MAILBOX_BADPARAM +## @loc None +2003=An internal error occurred. Importing failed. Try importing again. + +# Error message +# LOCALIZATION NOTE : Do not translate the word "%S" below. +## @name APPLEMAILIMPORT_MAILBOX_CONVERTERROR +## @loc None +2004=An error occurred while importing messages from %S. Messages were not imported. + diff --git a/mozilla/mail/locales/en-US/chrome/messenger/importMsgs.properties b/mozilla/mail/locales/en-US/chrome/messenger/importMsgs.properties index e3003e4c56d..23339489528 100644 --- a/mozilla/mail/locales/en-US/chrome/messenger/importMsgs.properties +++ b/mozilla/mail/locales/en-US/chrome/messenger/importMsgs.properties @@ -352,7 +352,7 @@ WorkButtonDesc=Work # Folder Names for imported Mail DefaultFolderName=Imported Mail # LOCALIZATION NOTE: Do not translate the word "%S" below. -ModuleFolderName=%S Mail +ImportModuleFolderName=%S Import # LOCALIZATION NOTE : "Communicator 4.x" is the used for previous versions of Netscape Communicator # Please translate using the brandname in respective languages for Netscape Communicator 4 releases. diff --git a/mozilla/mail/locales/jar.mn b/mozilla/mail/locales/jar.mn index 601714098ef..168e96656ff 100644 --- a/mozilla/mail/locales/jar.mn +++ b/mozilla/mail/locales/jar.mn @@ -78,6 +78,7 @@ locale/@AB_CD@/messenger/fieldMapImport.dtd (%chrome/messenger/fieldMapImport.dtd) locale/@AB_CD@/messenger/fieldMapExport.dtd (%chrome/messenger/fieldMapExport.dtd) locale/@AB_CD@/messenger/textImportMsgs.properties (%chrome/messenger/textImportMsgs.properties) + locale/@AB_CD@/messenger/appleMailImportMsgs.properties (%chrome/messenger/appleMailImportMsgs.properties) locale/@AB_CD@/messenger/comm4xMailImportMsgs.properties (%chrome/messenger/comm4xMailImportMsgs.properties) locale/@AB_CD@/messenger/eudoraImportMsgs.properties (%chrome/messenger/eudoraImportMsgs.properties) locale/@AB_CD@/messenger/oeImportMsgs.properties (%chrome/messenger/oeImportMsgs.properties) diff --git a/mozilla/mailnews/base/public/nsMsgLocalFolderHdrs.h b/mozilla/mailnews/base/public/nsMsgLocalFolderHdrs.h index 812153806c3..22511c6b445 100644 --- a/mozilla/mailnews/base/public/nsMsgLocalFolderHdrs.h +++ b/mozilla/mailnews/base/public/nsMsgLocalFolderHdrs.h @@ -65,6 +65,7 @@ #define EMPTY_MESSAGE_LINE(buf) (buf[0] == '\r' || buf[0] == '\n' || buf[0] == '\0') /* blank filled header to store keyword/tags in the mailbox */ -#define X_MOZILLA_KEYWORDS HEADER_X_MOZILLA_KEYWORDS ": " MSG_LINEBREAK +#define X_MOZILLA_KEYWORDS "X-Mozilla-Keys" ": " MSG_LINEBREAK +#define X_MOZILLA_KEYWORDS_LEN (sizeof(X_MOZILLA_KEYWORDS) - 1) #endif diff --git a/mozilla/mailnews/import/Makefile.in b/mozilla/mailnews/import/Makefile.in index 439b3489dc7..a8b0470ac14 100644 --- a/mozilla/mailnews/import/Makefile.in +++ b/mozilla/mailnews/import/Makefile.in @@ -49,7 +49,7 @@ PACKAGE_FILE = msgimport.pkg DIRS = public src text comm4x ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) -DIRS += eudora +DIRS += eudora applemail endif ifeq ($(OS_ARCH),WINNT) diff --git a/mozilla/mailnews/import/applemail/Makefile.in b/mozilla/mailnews/import/applemail/Makefile.in new file mode 100644 index 00000000000..a06be4d7530 --- /dev/null +++ b/mozilla/mailnews/import/applemail/Makefile.in @@ -0,0 +1,47 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mailnews import code. +# +# The Initial Developer of the Original Code is +# Håkan Waara . +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +VPATH = @srcdir@ +srcdir = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = applemail +DIRS = src + +include $(topsrcdir)/config/rules.mk diff --git a/mozilla/mailnews/import/applemail/src/Makefile.in b/mozilla/mailnews/import/applemail/src/Makefile.in new file mode 100644 index 00000000000..ed2ec9df8a0 --- /dev/null +++ b/mozilla/mailnews/import/applemail/src/Makefile.in @@ -0,0 +1,74 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mailnews import code. +# +# The Initial Developer of the Original Code is +# Håkan Waara . +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = impapplemail +LIBRARY_NAME = applmail_s + +PACKAGE_FILE = importapplemail.pkg +MOZILLA_INTERNAL_API = 1 + +META_COMPONENT = mail +REQUIRES = \ + xpcom \ + string \ + intl \ + import \ + necko \ + msgbase \ + msgbaseutil \ + unicharutil \ + libreg \ + $(NULL) + +CPPSRCS = \ + nsAppleMailImport.cpp \ + $(NULL) + +CMMSRCS = \ + nsEmlxHelperUtils.mm \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk diff --git a/mozilla/mailnews/import/applemail/src/nsAppleMailImport.cpp b/mozilla/mailnews/import/applemail/src/nsAppleMailImport.cpp new file mode 100644 index 00000000000..d00bd03b9f5 --- /dev/null +++ b/mozilla/mailnews/import/applemail/src/nsAppleMailImport.cpp @@ -0,0 +1,651 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mailnews import code. + * + * The Initial Developer of the Original Code is + * Håkan Waara . + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifdef MOZ_LOGGING +// sorry, this has to be before the pre-compiled header +#define FORCE_PR_LOG /* Allow logging in the release build */ +#endif + +#include "nsStringGlue.h" +#include "nsCOMPtr.h" +#include "nsISupportsPrimitives.h" +#include "nsIImportService.h" +#include "nsIImportMailboxDescriptor.h" +#include "nsIImportGeneric.h" +#include "nsILocalFile.h" +#include "nsIStringBundle.h" +#include "nsIProxyObjectManager.h" +#include "nsXPCOMCIDInternal.h" +#include "nsNetUtil.h" + +#include "nsEmlxHelperUtils.h" +#include "nsAppleMailImport.h" + +PRLogModuleInfo *APPLEMAILLOGMODULE = nsnull; + +// 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" + +// stringbundle IDs +#define APPLEMAILIMPORT_NAME 2000 +#define APPLEMAILIMPORT_DESCRIPTION 2001 +#define APPLEMAILIMPORT_MAILBOX_SUCCESS 2002 +#define APPLEMAILIMPORT_MAILBOX_BADPARAM 2003 +#define APPLEMAILIMPORT_MAILBOX_CONVERTERROR 2004 + +// magic constants +#define kAccountMailboxID 1234 + +nsAppleMailImportModule::nsAppleMailImportModule() +{ + // Init logging module. + if (!APPLEMAILLOGMODULE) + APPLEMAILLOGMODULE = PR_NewLogModule("APPLEMAILIMPORTLOG"); + + IMPORT_LOG0("nsAppleMailImportModule Created"); + + nsCOMPtr bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID)); + if (bundleService) + bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(mBundle)); +} + + +nsAppleMailImportModule::~nsAppleMailImportModule() +{ + IMPORT_LOG0("nsAppleMailImportModule Deleted"); +} + + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsAppleMailImportModule, nsIImportModule) + + +NS_IMETHODIMP nsAppleMailImportModule::GetName(PRUnichar **aName) +{ + return mBundle ? + mBundle->GetStringFromID(APPLEMAILIMPORT_NAME, aName) : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetDescription(PRUnichar **aName) +{ + return mBundle ? + mBundle->GetStringFromID(APPLEMAILIMPORT_DESCRIPTION, 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(PRBool *aUpgrade) +{ + NS_ENSURE_ARG_POINTER(aUpgrade); + *aUpgrade = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetImportInterface(const char *aImportType, nsISupports **aInterface) +{ + NS_ENSURE_ARG_POINTER(aImportType); + NS_ENSURE_ARG_POINTER(aInterface); + *aInterface = nsnull; + nsresult rv = NS_ERROR_NOT_AVAILABLE; + + if (!strcmp(aImportType, "mail")) { + nsCOMPtr mail(do_CreateInstance(NS_APPLEMAILIMPL_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr generic; + rv = impSvc->CreateNewGenericMail(getter_AddRefs(generic)); + if (NS_SUCCEEDED(rv)) { + nsAutoString name; + rv = mBundle->GetStringFromID(APPLEMAILIMPORT_NAME, getter_Copies(name)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr nameString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + nameString->SetData(name); + + generic->SetData("name", nameString); + generic->SetData("mailInterface", mail); + + rv = CallQueryInterface(generic, aInterface); + } + } + } + } + + return rv; +} + +#pragma mark - + +nsAppleMailImportMail::nsAppleMailImportMail() : mProgress(0), mCurDepth(0) +{ + IMPORT_LOG0("nsAppleMailImportMail created"); +} + +nsresult nsAppleMailImportMail::Initialize() +{ + nsresult rv; + nsCOMPtr bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr bundle; + rv = bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(bundle)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr proxyObjectManager = + do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + return proxyObjectManager->GetProxyForObject(NS_PROXY_TO_MAIN_THREAD, + NS_GET_IID(nsIStringBundle), + bundle, NS_PROXY_SYNC | NS_PROXY_ALWAYS, + getter_AddRefs(mBundleProxy)); +} + +nsAppleMailImportMail::~nsAppleMailImportMail() +{ + IMPORT_LOG0("nsAppleMailImportMail destroyed"); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsAppleMailImportMail, nsIImportMail) + +NS_IMETHODIMP nsAppleMailImportMail::GetDefaultLocation(nsIFile **aLocation, PRBool *aFound, PRBool *aUserVerify) +{ + NS_ENSURE_ARG_POINTER(aFound); + NS_ENSURE_ARG_POINTER(aLocation); + NS_ENSURE_ARG_POINTER(aUserVerify); + + *aLocation = nsnull; + *aFound = PR_FALSE; + *aUserVerify = PR_TRUE; + + // try to find current user's top-level Mail folder + nsCOMPtr mailFolder(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + if (mailFolder) { + nsresult rv = mailFolder->InitWithNativePath(NS_LITERAL_CSTRING(DEFAULT_MAIL_FOLDER)); + if (NS_SUCCEEDED(rv)) { + *aFound = PR_TRUE; + *aUserVerify = PR_FALSE; + CallQueryInterface(mailFolder, 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, nsISupportsArray **aResult) +{ + NS_ENSURE_ARG_POINTER(aMailboxFile); + NS_ENSURE_ARG_POINTER(aResult); + + IMPORT_LOG0("FindMailboxes for Apple mail invoked"); + + PRBool exists = PR_FALSE; + nsresult rv = aMailboxFile->Exists(&exists); + if (NS_FAILED(rv) || !exists) + return NS_ERROR_FAILURE; + + nsCOMPtr importService(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr resultsArray; + NS_NewISupportsArray(getter_AddRefs(resultsArray)); + 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 mailboxesDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr loc(do_QueryInterface(aMailboxFile, &rv)); + if (NS_SUCCEEDED(rv)) { + mailboxesDir->InitWithFile(loc); + 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.swap(*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, nsISupportsArray *aMailboxDescs, nsIImportService *aImportService) +{ + nsCOMPtr directoryEnumerator; + nsresult rv = aRoot->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv)) + return; + + PRBool hasMore = PR_FALSE; + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + + // get the next file entry + nsCOMPtr currentEntry; + { + nsCOMPtr rawSupports; + directoryEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + currentEntry = do_QueryInterface(rawSupports); + if (!currentEntry) + continue; + } + + // make sure it's a directory + PRBool isDirectory = PR_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); + PRBool isAccountFolder = PR_FALSE; + + if (StringBeginsWith(folderName, NS_LITERAL_STRING("POP-"))) { + // cut off "POP-" prefix so we get a nice folder name + folderName.Cut(0, 4); + isAccountFolder = PR_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 = PR_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 desc; + nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc)); + desc->SetSize(1); + desc->SetDepth(mCurDepth); + desc->SetDisplayName(folderName.get()); + desc->SetIdentifier(kAccountMailboxID); + + nsCOMPtr mailboxDescFile; + rv = desc->GetFile(getter_AddRefs(mailboxDescFile)); + if (!mailboxDescFile) + continue; + + mailboxDescFile->InitWithFile(currentEntry); + + // add this mailbox descriptor to the list + aMailboxDescs->AppendElement(desc); + + // 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(nsILocalFile *aFolder, nsISupportsArray *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 desc; + nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc)); + if (NS_SUCCEEDED(rv)) { + // find out number of messages in this .mbox + PRUint32 numMessages = 0; + { + // move to the .mbox's Messages folder + nsCOMPtr 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 dirEnumerator; + messagesFolder->GetDirectoryEntries(getter_AddRefs(dirEnumerator)); + if (dirEnumerator) { + PRBool hasMore = PR_FALSE; + while (NS_SUCCEEDED(dirEnumerator->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr rawSupports; + dirEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + + nsCOMPtr file(do_QueryInterface(rawSupports)); + if (file) { + PRBool isFile = PR_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 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); + } + + 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(nsILocalFile *aFolder, nsISupportsArray *aMailboxDescs, nsIImportService *aImportService) +{ + NS_ENSURE_ARG_POINTER(aFolder); + NS_ENSURE_ARG_POINTER(aMailboxDescs); + NS_ENSURE_ARG_POINTER(aImportService); + + // make sure this is a directory. + PRBool isDir = PR_FALSE; + if (NS_FAILED(aFolder->IsDirectory(&isDir)) || !isDir) + return NS_ERROR_FAILURE; + + // iterate through the folder contents + nsCOMPtr directoryEnumerator; + nsresult rv = aFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv) || !directoryEnumerator) + return rv; + + PRBool hasMore = PR_FALSE; + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + + // get the next file entry + nsCOMPtr currentEntry; + { + nsCOMPtr 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 siblingMailboxDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + continue; + + rv = siblingMailboxDir->InitWithPath(siblingMailboxDirPath); + PRBool reallyExists = PR_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, nsIFile *aDestination, + PRUnichar **aErrorLog, PRUnichar **aSuccessLog, PRBool *aFatalError) +{ + nsAutoString errorLog, successLog; + + // reset progress + mProgress = 0; + + nsAutoString mailboxName; + aMailbox->GetDisplayName(getter_Copies(mailboxName)); + + nsCOMPtr mboxFolder; + nsresult rv = aMailbox->GetFile(getter_AddRefs(mboxFolder)); + if (NS_FAILED(rv) || !mboxFolder) { + ReportStatus(APPLEMAILIMPORT_MAILBOX_CONVERTERROR, 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! + PRUint32 mailboxIdentifier; + aMailbox->GetIdentifier(&mailboxIdentifier); + + if (mailboxIdentifier != kAccountMailboxID) { + // move to the .mbox's Messages folder + nsCOMPtr 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. + PRUint32 finalSize; + aMailbox->GetSize(&finalSize); + mProgress = finalSize; + + // report that we successfully imported this mailbox + ReportStatus(APPLEMAILIMPORT_MAILBOX_SUCCESS, mailboxName, successLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_OK; + } + + // let's import the messages! + nsCOMPtr directoryEnumerator; + rv = messagesFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv)) { + ReportStatus(APPLEMAILIMPORT_MAILBOX_CONVERTERROR, mailboxName, errorLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_ERROR_FAILURE; + } + + // prepare an outstream to the destination file + nsCOMPtr outStream; + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), aDestination); + if (!outStream || NS_FAILED(rv)) { + ReportStatus(APPLEMAILIMPORT_MAILBOX_CONVERTERROR, mailboxName, errorLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_ERROR_FAILURE; + } + + PRBool hasMore = PR_FALSE; + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + // get the next file entry + nsCOMPtr currentEntry; + { + nsCOMPtr rawSupports; + directoryEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + currentEntry = do_QueryInterface(rawSupports); + if (!currentEntry) + continue; + } + + // make sure it's an .emlx file + PRBool isFile = PR_FALSE; + currentEntry->IsFile(&isFile); + if (!isFile) + continue; + + nsAutoString leafName; + currentEntry->GetLeafName(leafName); + if (!StringEndsWith(leafName, NS_LITERAL_STRING(".emlx"))) + continue; + + // add the data to the mbox stream + if (NS_SUCCEEDED(nsEmlxHelperUtils::AddEmlxMessageToStream(currentEntry, outStream))) + mProgress++; + } + } + + // just indicate that we're done, using the same number that we used to estimate + // number of messages earlier. + PRUint32 finalSize; + aMailbox->GetSize(&finalSize); + mProgress = finalSize; + + // report that we successfully imported this mailbox + ReportStatus(APPLEMAILIMPORT_MAILBOX_SUCCESS, mailboxName, successLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + + return NS_OK; +} + +void nsAppleMailImportMail::ReportStatus(PRInt32 aErrorNum, nsString &aName, nsAString &aStream) +{ + // get (and format, if needed) the error string from the bundle + nsAutoString outString; + const PRUnichar *fmt = { aName.get() }; + nsresult rv = mBundleProxy->FormatStringFromID(aErrorNum, &fmt, 1, getter_Copies(outString)); + // write it out the stream + if (NS_SUCCEEDED(rv)) + aStream.Append(outString + NS_LITERAL_STRING("\n")); +} + +void nsAppleMailImportMail::SetLogs(const nsAString &aSuccess, const nsAString &aError, PRUnichar **aOutSuccess, PRUnichar **aOutError) +{ + if (aOutError && !*aOutError) + *aOutError = ToNewUnicode(aError); + if (aOutSuccess && !*aOutSuccess) + *aOutSuccess = ToNewUnicode(aSuccess); +} + +NS_IMETHODIMP nsAppleMailImportMail::GetImportProgress(PRUint32 *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/mozilla/mailnews/import/applemail/src/nsAppleMailImport.h b/mozilla/mailnews/import/applemail/src/nsAppleMailImport.h new file mode 100644 index 00000000000..676682540a3 --- /dev/null +++ b/mozilla/mailnews/import/applemail/src/nsAppleMailImport.h @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mailnews import code. + * + * The Initial Developer of the Original Code is + * Håkan Waara . + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsAppleMailImport_h___ +#define nsAppleMailImport_h___ + +#include "prlog.h" +#include "nsIImportModule.h" +#include "nsCOMPtr.h" +#include "nsIStringBundle.h" +#include "nsIImportMail.h" +#include "nsISupportsArray.h" + +// logging facilities +extern PRLogModuleInfo *APPLEMAILLOGMODULE; + +#define IMPORT_LOG0(x) PR_LOG(APPLEMAILLOGMODULE, PR_LOG_DEBUG, (x)) +#define IMPORT_LOG1(x, y) PR_LOG(APPLEMAILLOGMODULE, PR_LOG_DEBUG, (x, y)) +#define IMPORT_LOG2(x, y, z) PR_LOG(APPLEMAILLOGMODULE, PR_LOG_DEBUG, (x, y, z)) +#define IMPORT_LOG3(a, b, c, d) PR_LOG(APPLEMAILLOGMODULE, PR_LOG_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 nsAppleMailImportModule : public nsIImportModule +{ + public: + + nsAppleMailImportModule(); + virtual ~nsAppleMailImportModule(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIIMPORTMODULE + + private: + + nsCOMPtr mBundle; +}; + +class nsAppleMailImportMail : public nsIImportMail +{ + public: + + nsAppleMailImportMail(); + virtual ~nsAppleMailImportMail(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIIMPORTMAIL + + nsresult Initialize(); + + private: + + void FindAccountMailDirs(nsIFile *aRoot, nsISupportsArray *aMailboxDescs, nsIImportService *aImportService); + nsresult FindMboxDirs(nsILocalFile *aFolder, nsISupportsArray *aMailboxDescs, nsIImportService *aImportService); + nsresult AddMboxDir(nsILocalFile *aFolder, nsISupportsArray *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(PRInt32 aErrorNum, nsString &aName, nsAString &aStream); + static void SetLogs(const nsAString& success, const nsAString& error, PRUnichar **aOutErrorLog, PRUnichar **aSuccessLog); + + nsCOMPtr mBundleProxy; + PRUint32 mProgress; + PRUint16 mCurDepth; +}; + +#endif /* nsAppleMailImport_h___ */ diff --git a/mozilla/mailnews/import/applemail/src/nsEmlxHelperUtils.h b/mozilla/mailnews/import/applemail/src/nsEmlxHelperUtils.h new file mode 100644 index 00000000000..c95c56c47ab --- /dev/null +++ b/mozilla/mailnews/import/applemail/src/nsEmlxHelperUtils.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mailnews import code. + * + * The Initial Developer of the Original Code is + * Håkan Waara . + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsEmlxHelperUtils_h___ +#define nsEmlxHelperUtils_h___ + +#include "nscore.h" +#include "nsStringGlue.h" + +class nsIOutputStream; +class nsILocalFile; + +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, PRUint32 *aMozillaStatusFlags); + + public: + + // add an .emlx message to the mbox output + static nsresult AddEmlxMessageToStream(nsILocalFile *aEmlxFile, nsIOutputStream *aOutoutStream); + +}; + +#endif // nsEmlxHelperUtils_h___ diff --git a/mozilla/mailnews/import/applemail/src/nsEmlxHelperUtils.mm b/mozilla/mailnews/import/applemail/src/nsEmlxHelperUtils.mm new file mode 100644 index 00000000000..f14c544208f --- /dev/null +++ b/mozilla/mailnews/import/applemail/src/nsEmlxHelperUtils.mm @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mailnews import code. + * + * The Initial Developer of the Original Code is + * Håkan Waara . + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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" + +#import + + +nsresult nsEmlxHelperUtils::ConvertToMozillaStatusFlags(const char *aXMLBufferStart, + const char *aXMLBufferEnd, + PRUint32 *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 propertyListFromData:metadata + mutabilityOption:NSPropertyListImmutable + format:&format + errorDescription:NULL]; + + if (!plist) + return NS_ERROR_FAILURE; + + // find the ... value and convert to int + const PRUint32 emlxMessageFlags = [[(NSDictionary *)plist objectForKey:@"flags"] integerValue]; + + if (emlxMessageFlags == 0) + return NS_ERROR_FAILURE; + + if (emlxMessageFlags & nsEmlxHelperUtils::kRead) + *aMozillaStatusFlags |= MSG_FLAG_READ; + if (emlxMessageFlags & nsEmlxHelperUtils::kForwarded) + *aMozillaStatusFlags |= MSG_FLAG_FORWARDED; + if (emlxMessageFlags & nsEmlxHelperUtils::kAnswered) + *aMozillaStatusFlags |= MSG_FLAG_REPLIED; + if (emlxMessageFlags & nsEmlxHelperUtils::kFlagged) + *aMozillaStatusFlags |= MSG_FLAG_MARKED; + + return NS_OK; +} + +nsresult nsEmlxHelperUtils::ConvertToMboxRD(const char *aMessageBufferStart, const char *aMessageBufferEnd, nsCString &aOutBuffer) +{ + nsTArray 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) { + fromLineStart++; + foundFromLines.AppendElement(aMessageBufferStart); + 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()) { + // pre-grow the string to the right size + aOutBuffer.SetLength((aMessageBufferEnd-aMessageBufferStart) + foundFromLines.Length()); + + const char *chunkStart = aMessageBufferStart; + for (unsigned i=0; i")); + + chunkStart = foundFromLines[i]; + } + } + + return NS_OK; +} + +nsresult nsEmlxHelperUtils::AddEmlxMessageToStream(nsILocalFile *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; + + nsCAutoString path; + aMessage->GetNativePath(path); + + NSData *data = [NSData dataWithContentsOfFile:[NSString stringWithUTF8String:path.get()]]; + if (!data) { + [pool release]; + return NS_ERROR_FAILURE; + } + + char *startOfMessageData = NULL; + PRUint32 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. + PRUint64 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]; + + PRUint32 x_mozilla_flags = 0; + ConvertToMozillaStatusFlags(startOfXMLMetadata, endOfXMLMetadata, &x_mozilla_flags); + + // write the X-Mozilla-Status header according to which flags we've gathered above. + PRUint32 dummyRv; + nsCAutoString 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 + char x_mozilla_status_2[40]; + PR_snprintf(x_mozilla_status_2, sizeof(x_mozilla_status_2), X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, 0); + rv = aOut->Write(x_mozilla_status_2, strlen(x_mozilla_status_2), &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, (PRUint32)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/mozilla/mailnews/import/build/Makefile.in b/mozilla/mailnews/import/build/Makefile.in index aa41700526d..9d0281610ba 100644 --- a/mozilla/mailnews/import/build/Makefile.in +++ b/mozilla/mailnews/import/build/Makefile.in @@ -59,7 +59,7 @@ REQUIRES = xpcom \ $(NULL) ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) -REQUIRES += impEudra +REQUIRES += impEudra impapplemail endif ifeq ($(OS_ARCH),WINNT) @@ -83,6 +83,7 @@ SHARED_LIBRARY_LIBS = \ ifneq (,$(filter mac cocoa, $(MOZ_WIDGET_TOOLKIT))) SHARED_LIBRARY_LIBS += ../eudora/src/$(LIB_PREFIX)impEudra_s.$(LIB_SUFFIX) +SHARED_LIBRARY_LIBS += ../applemail/src/$(LIB_PREFIX)applmail_s.$(LIB_SUFFIX) endif ifeq ($(OS_ARCH),WINNT) @@ -101,7 +102,9 @@ LOCAL_INCLUDES += -I$(srcdir)/../src \ $(NULL) ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) -LOCAL_INCLUDES += -I$(srcdir)/../eudora/src +LOCAL_INCLUDES += -I$(srcdir)/../eudora/src \ + -I$(srcdir)/../applemail/src \ + $(NULL) endif ifeq ($(OS_ARCH),WINNT) @@ -132,7 +135,9 @@ EXTRA_DSO_LDOPTS += \ $(NULL) ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) -EXTRA_DSO_LDOPTS += $(TK_LIBS) +EXTRA_DSO_LDOPTS += -framework Cocoa \ + $(TK_LIBS) \ + $(NULL) endif include $(topsrcdir)/config/rules.mk diff --git a/mozilla/mailnews/import/build/nsImportModule.cpp b/mozilla/mailnews/import/build/nsImportModule.cpp index 46c8fc5b49f..8e215db1fad 100644 --- a/mozilla/mailnews/import/build/nsImportModule.cpp +++ b/mozilla/mailnews/import/build/nsImportModule.cpp @@ -77,6 +77,15 @@ static NS_DEFINE_CID(kComm4xMailImportCID, NS_COMM4XMAILIMPORT_CID); static NS_DEFINE_CID(kEudoraImportCID, NS_EUDORAIMPORT_CID); #endif +//////////////////////////////////////////////////////////////////////////////// +// Apple Mail import Include Files +//////////////////////////////////////////////////////////////////////////////// +#if defined(XP_MACOSX) +#include "nsAppleMailImport.h" + +static NS_DEFINE_CID(kAppleMailImportCID, NS_APPLEMAILIMPORT_CID); +#endif + //////////////////////////////////////////////////////////////////////////////// // outlook import Include Files //////////////////////////////////////////////////////////////////////////////// @@ -172,6 +181,32 @@ NS_METHOD EudoraRegister(nsIComponentManager *aCompMgr, } #endif +//////////////////////////////////////////////////////////////////////////////// +// apple mail import factories +//////////////////////////////////////////////////////////////////////////////// +#if defined(XP_MACOSX) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAppleMailImportModule) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAppleMailImportMail, Initialize) + +NS_METHOD AppleMailRegister(nsIComponentManager *aCompMgr, + nsIFile *aPath, const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + nsresult rv; + + nsCOMPtr catMan = do_GetService( NS_CATEGORYMANAGER_CONTRACTID, &rv); + if (NS_SUCCEEDED( rv)) { + nsCString replace; + char *theCID = kAppleMailImportCID.ToString(); + rv = catMan->AddCategoryEntry( "mailnewsimport", theCID, kAppleMailSupportsString, PR_TRUE, PR_TRUE, getter_Copies( replace)); + NS_Free( theCID); + } + + return( rv); +} +#endif + //////////////////////////////////////////////////////////////////////////////// // outlook import factories //////////////////////////////////////////////////////////////////////////////// @@ -255,6 +290,16 @@ static const nsModuleComponentInfo components[] = { "@mozilla.org/import/import-eudora;1", nsEudoraImportConstructor, EudoraRegister, nsnull } #endif + //////////////////////////////////////////////////////////////////////////////// + // apple mail import components + //////////////////////////////////////////////////////////////////////////////// +#if defined(XP_MACOSX) + ,{ "Apple Mail Import Component", NS_APPLEMAILIMPORT_CID, + "@mozilla.org/import/import-applemail;1", nsAppleMailImportModuleConstructor, AppleMailRegister, nsnull }, + { "Apple Mail Import Implementation", NS_APPLEMAILIMPL_CID, + NS_APPLEMAILIMPL_CONTRACTID, nsAppleMailImportMailConstructor }, +#endif + #ifdef XP_WIN #if defined(_MSC_VER) && _MSC_VER >= 1100 //////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/mailnews/import/public/nsIImportMail.idl b/mozilla/mailnews/import/public/nsIImportMail.idl index 11819015dbd..da6217b7cc2 100644 --- a/mozilla/mailnews/import/public/nsIImportMail.idl +++ b/mozilla/mailnews/import/public/nsIImportMail.idl @@ -93,7 +93,7 @@ interface nsIImportMail : nsISupports /* Import a specific mailbox into the destination file supplied. If an error - occurs that is non-fatal, the destination will be deleted and other mailbox's + occurs that is non-fatal, the destination will be deleted and other mailboxes will be imported. If a fatal error occurs, the destination will be deleted and the import operation will abort. */ diff --git a/mozilla/mailnews/import/resources/content/importDialog.js b/mozilla/mailnews/import/resources/content/importDialog.js index f6a6aa6af7d..152f50c92ad 100644 --- a/mozilla/mailnews/import/resources/content/importDialog.js +++ b/mozilla/mailnews/import/resources/content/importDialog.js @@ -1,4 +1,4 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 diff --git a/mozilla/mailnews/import/src/nsImportMail.cpp b/mozilla/mailnews/import/src/nsImportMail.cpp index 07d9deb0220..3c1ac1a4a68 100644 --- a/mozilla/mailnews/import/src/nsImportMail.cpp +++ b/mozilla/mailnews/import/src/nsImportMail.cpp @@ -1004,7 +1004,7 @@ PRBool nsImportGenericMail::CreateFolder( nsIMsgFolder **ppFolder) nsString folderName; if (!m_pName.IsEmpty()) { const PRUnichar *moduleName[] = { m_pName.get() }; - rv = bundle->FormatStringFromName(NS_LITERAL_STRING("ModuleFolderName").get(), + rv = bundle->FormatStringFromName(NS_LITERAL_STRING("ImportModuleFolderName").get(), moduleName, 1, getter_Copies(folderName)); } diff --git a/mozilla/suite/locales/en-US/chrome/mailnews/appleMailImportMsgs.properties b/mozilla/suite/locales/en-US/chrome/mailnews/appleMailImportMsgs.properties new file mode 100644 index 00000000000..b035715d875 --- /dev/null +++ b/mozilla/suite/locales/en-US/chrome/mailnews/appleMailImportMsgs.properties @@ -0,0 +1,64 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Apple Mail importer code. +# +# The Initial Developer of the Original Code is +# Håkan Waara . +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +# Short name of import module +## @name APPLEMAILIMPORT_NAME +## @loc None +2000=Apple Mail + +# Description of import module +## @name APPLEMAILIMPORT_DESCRIPTION +## @loc None +2001=Import Local Mail from Mac OS X Mail + +# Success Message +# LOCALIZATION NOTE : Do not translate the word "%S" below. +## @name APPLEMAILIMPORT_MAILBOX_SUCCESS +## @loc None +2002=Local messages were successfully imported from %S + +# Error Message +## @name APPLEMAILIMPORT_MAILBOX_BADPARAM +## @loc None +2003=An internal error occurred. Importing failed. Try importing again. + +# Error message +# LOCALIZATION NOTE : Do not translate the word "%S" below. +## @name APPLEMAILIMPORT_MAILBOX_CONVERTERROR +## @loc None +2004=An error occurred while importing messages from %S. Messages were not imported. + diff --git a/mozilla/suite/locales/en-US/chrome/mailnews/importMsgs.properties b/mozilla/suite/locales/en-US/chrome/mailnews/importMsgs.properties index 5c47e441631..760f988fdaa 100644 --- a/mozilla/suite/locales/en-US/chrome/mailnews/importMsgs.properties +++ b/mozilla/suite/locales/en-US/chrome/mailnews/importMsgs.properties @@ -339,7 +339,7 @@ Comm4xFiles=Communicator Address Book files (*.na2) # Folder Names for imported Mail DefaultFolderName=Imported Mail # LOCALIZATION NOTE: Do not translate the word "%S" below. -ModuleFolderName=%S Mail +ImportModuleFolderName=%S Import # LOCALIZATION NOTE : "Communicator 4.x" is the used for previous versions of Netscape Communicator # Please translate using the brandname in respective languages for Netscape Communicator 4 releases. diff --git a/mozilla/suite/locales/jar.mn b/mozilla/suite/locales/jar.mn index aa37eee043e..eb0629ea022 100644 --- a/mozilla/suite/locales/jar.mn +++ b/mozilla/suite/locales/jar.mn @@ -220,6 +220,7 @@ locale/@AB_CD@/messenger/am-serverwithnoidentities.dtd (%chrome/mailnews/pref/am-serverwithnoidentities.dtd) locale/@AB_CD@/messenger/am-server-advanced.dtd (%chrome/mailnews/pref/am-server-advanced.dtd) locale/@AB_CD@/messenger/am-server-top.dtd (%chrome/mailnews/pref/am-server-top.dtd) + locale/@AB_CD@/messenger/appleMailImportMsgs.properties (%chrome/messenger/appleMailImportMsgs.properties) locale/@AB_CD@/messenger/comm4xMailImportMsgs.properties (%chrome/mailnews/comm4xMailImportMsgs.properties) locale/@AB_CD@/messenger/custom.properties (%chrome/mailnews/custom.properties) locale/@AB_CD@/messenger/CustomHeaders.dtd (%chrome/mailnews/CustomHeaders.dtd)