bug 420472: Implement ability to import mail from OS X's Mail.app in mailnews core. r=Standard8, sr=bienvenu

git-svn-id: svn://10.0.0.236/trunk@251511 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
hwaara%gmail.com
2008-05-10 09:01:34 +00:00
parent 8a2e5116f8
commit 50919e794a
19 changed files with 1425 additions and 10 deletions

View File

@@ -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 <hwaara@gmail.com>.
# 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.

View File

@@ -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.

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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 <hwaara@gmail.com>.
# 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

View File

@@ -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 <hwaara@gmail.com>.
# 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

View File

@@ -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 <hwaara@gmail.com>.
* 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<nsIStringBundleService> 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<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->GetStringFromID(APPLEMAILIMPORT_NAME, 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);
rv = CallQueryInterface(generic, aInterface);
}
}
}
}
return rv;
}
#pragma mark -
nsAppleMailImportMail::nsAppleMailImportMail() : mProgress(0), mCurDepth(0)
{
IMPORT_LOG0("nsAppleMailImportMail created");
}
nsresult nsAppleMailImportMail::Initialize()
{
nsresult rv;
nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(bundle));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIProxyObjectManager> 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<nsILocalFile> 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<nsIImportService> importService(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupportsArray> 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<nsILocalFile> mailboxesDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsILocalFile> 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<nsISimpleEnumerator> 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<nsILocalFile> 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
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<nsIImportMailboxDescriptor> desc;
nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc));
desc->SetSize(1);
desc->SetDepth(mCurDepth);
desc->SetDisplayName(folderName.get());
desc->SetIdentifier(kAccountMailboxID);
nsCOMPtr<nsILocalFile> 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<nsIImportMailboxDescriptor> 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<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) {
PRBool hasMore = PR_FALSE;
while (NS_SUCCEEDED(dirEnumerator->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> rawSupports;
dirEnumerator->GetNext(getter_AddRefs(rawSupports));
if (!rawSupports)
continue;
nsCOMPtr<nsILocalFile> 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<nsILocalFile> 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<nsISimpleEnumerator> 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<nsILocalFile> 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<nsILocalFile> 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<nsILocalFile> 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<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.
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<nsISimpleEnumerator> 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<nsIOutputStream> 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<nsILocalFile> 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
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;
}

View File

@@ -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 <hwaara@gmail.com>.
* 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<nsIStringBundle> 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<nsIStringBundle> mBundleProxy;
PRUint32 mProgress;
PRUint16 mCurDepth;
};
#endif /* nsAppleMailImport_h___ */

View File

@@ -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 <hwaara@gmail.com>.
* 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___

View File

@@ -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 <hwaara@gmail.com>.
* 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 <Cocoa/Cocoa.h>
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 <flags>...</flags> 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<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) {
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<foundFromLines.Length(); ++i) {
aOutBuffer.Append(chunkStart, (foundFromLines[i]-chunkStart));
aOutBuffer.Append(NS_LITERAL_CSTRING(">"));
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;
}

View File

@@ -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

View File

@@ -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<nsICategoryManager> 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
////////////////////////////////////////////////////////////////////////////////

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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 <hwaara@gmail.com>.
# 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.

View File

@@ -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.

View File

@@ -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)