mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-02 13:27:33 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
7f068ecce3
969 changed files with 96279 additions and 469 deletions
|
|
@ -387,6 +387,47 @@
|
|||
#define NS_ABVIEW_CONTRACTID \
|
||||
"@mozilla.org/addressbook/abview;1"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
//
|
||||
// nsAbOSXDirectory
|
||||
//
|
||||
#define NS_ABOSXDIRECTORY_PREFIX "moz-abosxdirectory"
|
||||
#define NS_ABOSXCARD_PREFIX "moz-abosxcard"
|
||||
|
||||
#define NS_ABOSXDIRECTORY_CONTRACTID \
|
||||
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABOSXDIRECTORY_PREFIX
|
||||
|
||||
#define NS_ABOSXDIRECTORY_CID \
|
||||
{ /* {83781cc6-c682-11d6-bdeb-0005024967b8}*/ \
|
||||
0x83781cc6, 0xc682, 0x11d6, \
|
||||
{0xbd, 0xeb, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \
|
||||
}
|
||||
|
||||
//
|
||||
// nsAbOSXCard
|
||||
//
|
||||
#define NS_ABOSXCARD_CONTRACTID \
|
||||
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABOSXCARD_PREFIX
|
||||
|
||||
#define NS_ABOSXCARD_CID \
|
||||
{ /* {89bbf582-c682-11d6-bc9d-0005024967b8}*/ \
|
||||
0x89bbf582, 0xc682, 0x11d6, \
|
||||
{0xbc, 0x9d, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \
|
||||
}
|
||||
|
||||
//
|
||||
// OS X directory factory
|
||||
//
|
||||
#define NS_ABOSXDIRFACTORY_CONTRACTID \
|
||||
NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX NS_ABOSXDIRECTORY_PREFIX
|
||||
|
||||
#define NS_ABOSXDIRFACTORY_CID \
|
||||
{ /* {90efe2fe-c682-11d6-9c83-0005024967b8}*/ \
|
||||
0x90efe2fe, 0xc682, 0x11d6, \
|
||||
{0x9c, 0x83, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NS_MSGVCARDSERVICE_CID \
|
||||
{ 0x3c4ac0da, 0x2cda, 0x4018, \
|
||||
{ 0x95, 0x51, 0xe1, 0x58, 0xb2, 0xe1, 0x22, 0xd3 }}
|
||||
|
|
|
|||
|
|
@ -2,4 +2,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Stub. This was configuring special snowflake OSX stuff.
|
||||
# Disable movemail for Thunderbird on OSX
|
||||
if CONFIG['MOZ_MOVEMAIL'] and not (CONFIG['MOZ_THUNDERBIRD'] and CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa'):
|
||||
FINAL_TARGET_FILES.isp += ['movemail.rdf']
|
||||
|
|
|
|||
|
|
@ -343,7 +343,11 @@
|
|||
checked="true"/>
|
||||
</hbox>
|
||||
<spacer flex="1"/>
|
||||
#ifndef XP_MACOSX
|
||||
<description>&clickFinish.label;</description>
|
||||
#else
|
||||
<description>&clickFinish.labelMac;</description>
|
||||
#endif
|
||||
</vbox>
|
||||
</wizardpage>
|
||||
|
||||
|
|
|
|||
|
|
@ -822,6 +822,11 @@ nsresult nsMsgFilter::ConvertMoveOrCopyToFolderValue(nsIMsgRuleAction *filterAct
|
|||
if (offset != -1)
|
||||
moveValue.Cut(offset, 4);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
nsCString unescapedMoveValue;
|
||||
MsgUnescapeString(moveValue, 0, unescapedMoveValue);
|
||||
moveValue = unescapedMoveValue;
|
||||
#endif
|
||||
destFolderUri.Append('/');
|
||||
if (filterVersion == k45Version)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'qt'):
|
||||
SOURCES += ['nsMessengerUnixIntegration.cpp']
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += ['nsMessengerOSXIntegration.mm']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'folderLookupService.js',
|
||||
|
|
|
|||
|
|
@ -698,6 +698,7 @@ nsresult nsMessenger::SaveAttachment(nsIFile *aFile,
|
|||
saveListener->QueryInterface(NS_GET_IID(nsIStreamListener),
|
||||
getter_AddRefs(convertedListener));
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
// if the content type is bin hex we are going to do a hokey hack and make sure we decode the bin hex
|
||||
// when saving an attachment to disk..
|
||||
if (MsgLowerCaseEqualsLiteral(aContentType, APPLICATION_BINHEX))
|
||||
|
|
@ -712,6 +713,7 @@ nsresult nsMessenger::SaveAttachment(nsIFile *aFile,
|
|||
channelSupport,
|
||||
getter_AddRefs(convertedListener));
|
||||
}
|
||||
#endif
|
||||
nsCOMPtr<nsIURI> dummyNull;
|
||||
if (fetchService)
|
||||
rv = fetchService->FetchMimePart(URL, fullMessageUri.get(),
|
||||
|
|
@ -769,6 +771,10 @@ nsMessenger::SaveAttachmentToFolder(const nsACString& contentType, const nsACStr
|
|||
ConvertAndSanitizeFileName(PromiseFlatCString(displayName).get(), unescapedFileName);
|
||||
rv = attachmentDestination->Append(unescapedFileName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
#ifdef XP_MACOSX
|
||||
rv = attachmentDestination->CreateUnique(nsIFile::NORMAL_FILE_TYPE, ATTACHMENT_PERMISSION);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
#endif
|
||||
|
||||
rv = SaveAttachment(attachmentDestination, url, messageUri, contentType, nullptr, nullptr);
|
||||
attachmentDestination.swap(*aOutFile);
|
||||
|
|
|
|||
63
mailnews/base/src/nsMessengerOSXIntegration.h
Normal file
63
mailnews/base/src/nsMessengerOSXIntegration.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __nsMessengerOSXIntegration_h
|
||||
#define __nsMessengerOSXIntegration_h
|
||||
|
||||
#include "nsIMessengerOSIntegration.h"
|
||||
#include "nsIFolderListener.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIAlertsService.h"
|
||||
#include "mozINewMailListener.h"
|
||||
|
||||
#define NS_MESSENGEROSXINTEGRATION_CID \
|
||||
{0xaa83266, 0x4225, 0x4c4b, \
|
||||
{0x93, 0xf8, 0x94, 0xb1, 0x82, 0x58, 0x6f, 0x93}}
|
||||
|
||||
class nsIStringBundle;
|
||||
|
||||
class nsMessengerOSXIntegration : public nsIMessengerOSIntegration,
|
||||
public nsIFolderListener,
|
||||
public nsIObserver,
|
||||
public mozINewMailListener
|
||||
{
|
||||
public:
|
||||
nsMessengerOSXIntegration();
|
||||
virtual nsresult Init();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMESSENGEROSINTEGRATION
|
||||
NS_DECL_NSIFOLDERLISTENER
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_MOZINEWMAILLISTENER
|
||||
|
||||
private:
|
||||
virtual ~nsMessengerOSXIntegration();
|
||||
|
||||
nsCOMPtr<nsIAtom> mBiffStateAtom;
|
||||
nsCOMPtr<nsIAtom> mNewMailReceivedAtom;
|
||||
nsresult ShowAlertMessage(const nsAString& aAlertTitle, const nsAString& aAlertText, const nsACString& aFolderURI);
|
||||
nsresult OnAlertFinished();
|
||||
nsresult OnAlertClicked(const char16_t * aAlertCookie);
|
||||
#ifdef MOZ_SUITE
|
||||
nsresult OnAlertClickedSimple();
|
||||
#endif
|
||||
nsresult GetStringBundle(nsIStringBundle **aBundle);
|
||||
void FillToolTipInfo(nsIMsgFolder *aFolder, int32_t aNewCount);
|
||||
nsresult GetFirstFolderWithNewMail(nsIMsgFolder* aFolder, nsCString& aFolderURI);
|
||||
nsresult BadgeDockIcon();
|
||||
nsresult RestoreDockIcon();
|
||||
nsresult BounceDockIcon();
|
||||
nsresult GetNewMailAuthors(nsIMsgFolder* aFolder, nsString& aAuthors, int32_t aNewCount, int32_t* aNotDisplayed);
|
||||
|
||||
int32_t mUnreadTotal;
|
||||
int32_t mUnreadChat;
|
||||
};
|
||||
|
||||
#endif // __nsMessengerOSXIntegration_h
|
||||
700
mailnews/base/src/nsMessengerOSXIntegration.mm
Normal file
700
mailnews/base/src/nsMessengerOSXIntegration.mm
Normal file
|
|
@ -0,0 +1,700 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsMsgUtils.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsMessengerOSXIntegration.h"
|
||||
#include "nsIMsgMailSession.h"
|
||||
#include "nsIMsgIncomingServer.h"
|
||||
#include "nsIMsgIdentity.h"
|
||||
#include "nsIMsgAccount.h"
|
||||
#include "nsIMsgFolder.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsMsgBaseCID.h"
|
||||
#include "nsMsgFolderFlags.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsIDirectoryService.h"
|
||||
#include "MailNewsTypes.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
#include "nsIDOMChromeWindow.h"
|
||||
#include "mozIDOMWindow.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIMessengerWindowService.h"
|
||||
#include "prprf.h"
|
||||
#include "nsIAlertsService.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsIMsgDatabase.h"
|
||||
#include "nsIMsgHdr.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsMsgLocalCID.h"
|
||||
#include "nsIMsgMailNewsUrl.h"
|
||||
#include "nsIMsgWindow.h"
|
||||
#include "nsIMsgAccountManager.h"
|
||||
#include "nsIMessenger.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozINewMailNotificationService.h"
|
||||
#include "mozilla/mailnews/MimeHeaderParser.h"
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#define kBiffAnimateDockIconPref "mail.biff.animate_dock_icon"
|
||||
#define kMaxDisplayCount 10
|
||||
|
||||
using namespace mozilla::mailnews;
|
||||
|
||||
// HACK: Limitations in Focus/SetFocus on Mac (see bug 465446)
|
||||
nsresult FocusAppNative()
|
||||
{
|
||||
ProcessSerialNumber psn;
|
||||
|
||||
if (::GetCurrentProcess(&psn) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (::SetFrontProcess(&psn) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void openMailWindow(const nsCString& aUri)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMsgMailSession> mailSession ( do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIMsgWindow> topMostMsgWindow;
|
||||
rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(topMostMsgWindow));
|
||||
if (topMostMsgWindow)
|
||||
{
|
||||
if (!aUri.IsEmpty())
|
||||
{
|
||||
nsCOMPtr<nsIMsgMailNewsUrl> msgUri(do_CreateInstance(NS_MAILBOXURL_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
rv = msgUri->SetSpec(aUri);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
bool isMessageUri = false;
|
||||
msgUri->GetIsMessageUri(&isMessageUri);
|
||||
if (isMessageUri)
|
||||
{
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
// SeaMonkey only supports message uris, whereas Thunderbird only
|
||||
// supports message headers. This should be simplified/removed when
|
||||
// bug 507593 is implemented.
|
||||
#ifdef MOZ_SUITE
|
||||
nsCOMPtr<mozIDOMWindowProxy> newWindow;
|
||||
wwatch->OpenWindow(0, "chrome://messenger/content/messageWindow.xul",
|
||||
"_blank", "all,chrome,dialog=no,status,toolbar", msgUri,
|
||||
getter_AddRefs(newWindow));
|
||||
#else
|
||||
nsCOMPtr<nsIMessenger> messenger(do_CreateInstance(NS_MESSENGER_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIMsgDBHdr> msgHdr;
|
||||
messenger->MsgHdrFromURI(aUri, getter_AddRefs(msgHdr));
|
||||
if (msgHdr)
|
||||
{
|
||||
nsCOMPtr<mozIDOMWindowProxy> newWindow;
|
||||
wwatch->OpenWindow(0, "chrome://messenger/content/messageWindow.xul",
|
||||
"_blank", "all,chrome,dialog=no,status,toolbar", msgHdr,
|
||||
getter_AddRefs(newWindow));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIMsgWindowCommands> windowCommands;
|
||||
topMostMsgWindow->GetWindowCommands(getter_AddRefs(windowCommands));
|
||||
if (windowCommands)
|
||||
windowCommands->SelectFolder(aUri);
|
||||
}
|
||||
}
|
||||
|
||||
FocusAppNative();
|
||||
nsCOMPtr<mozIDOMWindowProxy> domWindow;
|
||||
topMostMsgWindow->GetDomWindow(getter_AddRefs(domWindow));
|
||||
if (domWindow) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> privateWindow = nsPIDOMWindowOuter::From(domWindow);
|
||||
privateWindow->Focus();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the user doesn't have a mail window open already so open one for them...
|
||||
nsCOMPtr<nsIMessengerWindowService> messengerWindowService =
|
||||
do_GetService(NS_MESSENGERWINDOWSERVICE_CONTRACTID);
|
||||
// if we want to preselect the first account with new mail,
|
||||
// here is where we would try to generate a uri to pass in
|
||||
// (and add code to the messenger window service to make that work)
|
||||
if (messengerWindowService)
|
||||
messengerWindowService->OpenMessengerWindowWithUri(
|
||||
"mail:3pane", aUri.get(), nsMsgKey_None);
|
||||
}
|
||||
}
|
||||
|
||||
nsMessengerOSXIntegration::nsMessengerOSXIntegration()
|
||||
{
|
||||
mBiffStateAtom = MsgGetAtom("BiffState");
|
||||
mNewMailReceivedAtom = MsgGetAtom("NewMailReceived");
|
||||
mUnreadTotal = 0;
|
||||
}
|
||||
|
||||
nsMessengerOSXIntegration::~nsMessengerOSXIntegration()
|
||||
{
|
||||
RestoreDockIcon();
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsMessengerOSXIntegration)
|
||||
NS_IMPL_RELEASE(nsMessengerOSXIntegration)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsMessengerOSXIntegration)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMessengerOSIntegration)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMessengerOSIntegration)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFolderListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(mozINewMailListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return observerService->AddObserver(this, "mail-startup-done", false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnItemPropertyChanged(nsIMsgFolder *, nsIAtom *, char const *, char const *)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnItemUnicharPropertyChanged(nsIMsgFolder *, nsIAtom *, const char16_t *, const char16_t *)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnItemRemoved(nsIMsgFolder *, nsISupports *)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "alertfinished"))
|
||||
return OnAlertFinished();
|
||||
|
||||
if (!strcmp(aTopic, "alertclickcallback"))
|
||||
return OnAlertClicked(aData);
|
||||
|
||||
#ifdef MOZ_SUITE
|
||||
// SeaMonkey does most of the GUI work in JS code when clicking on a mail
|
||||
// notification, so it needs an extra function here
|
||||
if (!strcmp(aTopic, "alertclicksimplecallback"))
|
||||
return OnAlertClickedSimple();
|
||||
#endif
|
||||
|
||||
if (!strcmp(aTopic, "mail-startup-done")) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
observerService->RemoveObserver(this, "mail-startup-done");
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
}
|
||||
|
||||
// Register with the new mail service for changes to the unread message count
|
||||
nsCOMPtr<mozINewMailNotificationService> newmail
|
||||
= do_GetService(MOZ_NEWMAILNOTIFICATIONSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv); // This should really be an assert with a helpful message
|
||||
rv = newmail->AddListener(this, mozINewMailNotificationService::count);
|
||||
NS_ENSURE_SUCCESS(rv, rv); // This should really be an assert with a helpful message
|
||||
|
||||
// Get the initial unread count. Ignore return value; if code above didn't fail, this won't
|
||||
rv = newmail->GetMessageCount(&mUnreadTotal);
|
||||
BadgeDockIcon();
|
||||
|
||||
// register with the mail sesson for folder events
|
||||
// we care about new count, biff status
|
||||
nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return mailSession->AddFolderListener(this, nsIFolderListener::boolPropertyChanged | nsIFolderListener::intPropertyChanged);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::GetStringBundle(nsIStringBundle **aBundle)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aBundle);
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
if (bundleService && NS_SUCCEEDED(rv))
|
||||
bundleService->CreateBundle("chrome://messenger/locale/messenger.properties", getter_AddRefs(bundle));
|
||||
bundle.swap(*aBundle);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsMessengerOSXIntegration::FillToolTipInfo(nsIMsgFolder *aFolder, int32_t aNewCount)
|
||||
{
|
||||
if (aFolder)
|
||||
{
|
||||
nsString authors;
|
||||
int32_t numNotDisplayed;
|
||||
nsresult rv = GetNewMailAuthors(aFolder, authors, aNewCount, &numNotDisplayed);
|
||||
|
||||
// If all senders are vetoed, the authors string will be empty.
|
||||
if (NS_FAILED(rv) || authors.IsEmpty())
|
||||
return;
|
||||
|
||||
// If this isn't the root folder, get it so we can report for it.
|
||||
// GetRootFolder always returns the server's root, so calling on the root itself is fine.
|
||||
nsCOMPtr<nsIMsgFolder> rootFolder;
|
||||
aFolder->GetRootFolder(getter_AddRefs(rootFolder));
|
||||
if (!rootFolder)
|
||||
return;
|
||||
|
||||
nsString accountName;
|
||||
rootFolder->GetPrettiestName(accountName);
|
||||
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
GetStringBundle(getter_AddRefs(bundle));
|
||||
if (bundle)
|
||||
{
|
||||
nsAutoString numNewMsgsText;
|
||||
numNewMsgsText.AppendInt(aNewCount);
|
||||
nsString finalText;
|
||||
nsCString uri;
|
||||
aFolder->GetURI(uri);
|
||||
|
||||
if (numNotDisplayed > 0)
|
||||
{
|
||||
nsAutoString numNotDisplayedText;
|
||||
numNotDisplayedText.AppendInt(numNotDisplayed);
|
||||
const char16_t *formatStrings[3] = { numNewMsgsText.get(), authors.get(), numNotDisplayedText.get() };
|
||||
bundle->FormatStringFromName(u"macBiffNotification_messages_extra",
|
||||
formatStrings,
|
||||
3,
|
||||
getter_Copies(finalText));
|
||||
}
|
||||
else
|
||||
{
|
||||
const char16_t *formatStrings[2] = { numNewMsgsText.get(), authors.get() };
|
||||
|
||||
if (aNewCount == 1)
|
||||
{
|
||||
bundle->FormatStringFromName(u"macBiffNotification_message",
|
||||
formatStrings,
|
||||
2,
|
||||
getter_Copies(finalText));
|
||||
// Since there is only 1 message, use the most recent mail's URI instead of the folder's
|
||||
nsCOMPtr<nsIMsgDatabase> db;
|
||||
rv = aFolder->GetMsgDatabase(getter_AddRefs(db));
|
||||
if (NS_SUCCEEDED(rv) && db)
|
||||
{
|
||||
uint32_t numNewKeys;
|
||||
uint32_t *newMessageKeys;
|
||||
rv = db->GetNewList(&numNewKeys, &newMessageKeys);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsCOMPtr<nsIMsgDBHdr> hdr;
|
||||
rv = db->GetMsgHdrForKey(newMessageKeys[numNewKeys - 1],
|
||||
getter_AddRefs(hdr));
|
||||
if (NS_SUCCEEDED(rv) && hdr)
|
||||
aFolder->GetUriForMsg(hdr, uri);
|
||||
}
|
||||
NS_Free(newMessageKeys);
|
||||
}
|
||||
}
|
||||
else
|
||||
bundle->FormatStringFromName(u"macBiffNotification_messages",
|
||||
formatStrings,
|
||||
2,
|
||||
getter_Copies(finalText));
|
||||
}
|
||||
ShowAlertMessage(accountName, finalText, uri);
|
||||
} // if we got a bundle
|
||||
} // if we got a folder
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::ShowAlertMessage(const nsAString& aAlertTitle,
|
||||
const nsAString& aAlertText,
|
||||
const nsACString& aFolderURI)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIAlertsService> alertsService (do_GetService(NS_ALERTSERVICE_CONTRACTID, &rv));
|
||||
// If we have an nsIAlertsService implementation, use it:
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
alertsService->ShowAlertNotification(EmptyString(),
|
||||
aAlertTitle, aAlertText, true,
|
||||
NS_ConvertASCIItoUTF16(aFolderURI),
|
||||
this, EmptyString(),
|
||||
NS_LITERAL_STRING("auto"),
|
||||
EmptyString(), EmptyString(),
|
||||
nullptr,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
BounceDockIcon();
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
OnAlertFinished();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnItemIntPropertyChanged(nsIMsgFolder *aFolder,
|
||||
nsIAtom *aProperty,
|
||||
int64_t aOldValue,
|
||||
int64_t aNewValue)
|
||||
{
|
||||
// if we got new mail show an alert
|
||||
if (aNewValue == nsIMsgFolder::nsMsgBiffState_NewMail)
|
||||
{
|
||||
bool performingBiff = false;
|
||||
nsCOMPtr<nsIMsgIncomingServer> server;
|
||||
aFolder->GetServer(getter_AddRefs(server));
|
||||
if (server)
|
||||
server->GetPerformingBiff(&performingBiff);
|
||||
if (!performingBiff)
|
||||
return NS_OK; // kick out right now...
|
||||
|
||||
// Biff happens for the root folder, but we want info for the child with new mail
|
||||
nsCString folderUri;
|
||||
GetFirstFolderWithNewMail(aFolder, folderUri);
|
||||
nsCOMPtr<nsIMsgFolder> childFolder;
|
||||
nsresult rv = aFolder->GetChildWithURI(folderUri, true, true,
|
||||
getter_AddRefs(childFolder));
|
||||
if (NS_FAILED(rv) || !childFolder)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
int32_t numNewMessages = 0;
|
||||
childFolder->GetNumNewMessages(true, &numNewMessages);
|
||||
FillToolTipInfo(childFolder, numNewMessages);
|
||||
}
|
||||
else if (mNewMailReceivedAtom == aProperty)
|
||||
{
|
||||
FillToolTipInfo(aFolder, aNewValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::OnAlertClicked(const char16_t* aAlertCookie)
|
||||
{
|
||||
openMailWindow(NS_ConvertUTF16toUTF8(aAlertCookie));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_SUITE
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::OnAlertClickedSimple()
|
||||
{
|
||||
// SeaMonkey only function; only focus the app here, rest of the work will
|
||||
// be done in suite/mailnews/mailWidgets.xml
|
||||
FocusAppNative();
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::OnAlertFinished()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::BounceDockIcon()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool bounceDockIcon = false;
|
||||
rv = prefBranch->GetBoolPref(kBiffAnimateDockIconPref, &bounceDockIcon);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!bounceDockIcon)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
|
||||
if (mediator)
|
||||
{
|
||||
nsCOMPtr<mozIDOMWindowProxy> domWindow;
|
||||
mediator->GetMostRecentWindow(u"mail:3pane", getter_AddRefs(domWindow));
|
||||
if (domWindow)
|
||||
{
|
||||
nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(domWindow));
|
||||
chromeWindow->GetAttention();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::RestoreDockIcon()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
id tile = [[NSApplication sharedApplication] dockTile];
|
||||
[tile setBadgeLabel: nil];
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::BadgeDockIcon()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
int32_t unreadCount = mUnreadTotal;
|
||||
// If count is less than one, we should restore the original dock icon.
|
||||
if (unreadCount < 1)
|
||||
{
|
||||
RestoreDockIcon();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Draw the number, first giving extensions a chance to modify.
|
||||
// Extensions might wish to transform "1000" into "100+" or some
|
||||
// other short string. Getting back the empty string will cause
|
||||
// nothing to be drawn and us to return early.
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIObserverService> os
|
||||
(do_GetService("@mozilla.org/observer-service;1", &rv));
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
RestoreDockIcon();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupportsString> str
|
||||
(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
RestoreDockIcon();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoString total;
|
||||
total.AppendInt(unreadCount);
|
||||
str->SetData(total);
|
||||
os->NotifyObservers(str, "before-unread-count-display",
|
||||
total.get());
|
||||
nsAutoString badgeString;
|
||||
str->GetData(badgeString);
|
||||
if (badgeString.IsEmpty())
|
||||
{
|
||||
RestoreDockIcon();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
id tile = [[NSApplication sharedApplication] dockTile];
|
||||
[tile setBadgeLabel:[NSString stringWithFormat:@"%S", (const unichar*)badgeString.get()]];
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnItemPropertyFlagChanged(nsIMsgDBHdr *item, nsIAtom *property, uint32_t oldFlag, uint32_t newFlag)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnItemAdded(nsIMsgFolder *, nsISupports *)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnItemBoolPropertyChanged(nsIMsgFolder *aItem,
|
||||
nsIAtom *aProperty,
|
||||
bool aOldValue,
|
||||
bool aNewValue)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnItemEvent(nsIMsgFolder *, nsIAtom *)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::GetNewMailAuthors(nsIMsgFolder* aFolder,
|
||||
nsString& aAuthors,
|
||||
int32_t aNewCount,
|
||||
int32_t* aNotDisplayed)
|
||||
{
|
||||
// Get a list of names or email addresses for the folder's authors
|
||||
// with new mail. Note that we only process the most recent "new"
|
||||
// mail (aNewCount), working from most recently added. Duplicates
|
||||
// are removed, and names are displayed to a set limit
|
||||
// (kMaxDisplayCount) with the remaining count being returned in
|
||||
// aNotDisplayed. Extension developers can listen for
|
||||
// "newmail-notification-requested" and then make a decision about
|
||||
// including a given author or not. As a result, it is possible that
|
||||
// the resulting length of aAuthors will be 0.
|
||||
nsCOMPtr<nsIMsgDatabase> db;
|
||||
nsresult rv = aFolder->GetMsgDatabase(getter_AddRefs(db));
|
||||
uint32_t numNewKeys = 0;
|
||||
if (NS_SUCCEEDED(rv) && db)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> os =
|
||||
do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get proper l10n list separator -- ", " in English
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
GetStringBundle(getter_AddRefs(bundle));
|
||||
if (!bundle)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
uint32_t *newMessageKeys;
|
||||
rv = db->GetNewList(&numNewKeys, &newMessageKeys);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsString listSeparator;
|
||||
bundle->GetStringFromName(u"macBiffNotification_separator", getter_Copies(listSeparator));
|
||||
|
||||
int32_t displayed = 0;
|
||||
for (int32_t i = numNewKeys - 1; i >= 0; i--, aNewCount--)
|
||||
{
|
||||
if (0 == aNewCount || displayed == kMaxDisplayCount)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIMsgDBHdr> hdr;
|
||||
rv = db->GetMsgHdrForKey(newMessageKeys[i],
|
||||
getter_AddRefs(hdr));
|
||||
if (NS_SUCCEEDED(rv) && hdr)
|
||||
{
|
||||
nsString author;
|
||||
rv = hdr->GetMime2DecodedAuthor(author);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
nsString name;
|
||||
ExtractName(DecodedHeader(author), name);
|
||||
|
||||
// Give extensions a chance to suppress notifications for this author
|
||||
nsCOMPtr<nsISupportsPRBool> notify =
|
||||
do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
|
||||
|
||||
notify->SetData(true);
|
||||
os->NotifyObservers(notify, "newmail-notification-requested",
|
||||
author.get());
|
||||
|
||||
bool includeSender;
|
||||
notify->GetData(&includeSender);
|
||||
|
||||
// Don't add unwanted or duplicate names
|
||||
if (includeSender && aAuthors.Find(name, true) == -1)
|
||||
{
|
||||
if (displayed > 0)
|
||||
aAuthors.Append(listSeparator);
|
||||
aAuthors.Append(name);
|
||||
displayed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_Free(newMessageKeys);
|
||||
}
|
||||
*aNotDisplayed = aNewCount;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMessengerOSXIntegration::GetFirstFolderWithNewMail(nsIMsgFolder* aFolder, nsCString& aFolderURI)
|
||||
{
|
||||
// Find the subfolder in aFolder with new mail and return the folderURI
|
||||
if (aFolder)
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> msgFolder;
|
||||
// enumerate over the folders under this root folder till we find one with new mail....
|
||||
nsCOMPtr<nsIArray> allFolders;
|
||||
nsresult rv = aFolder->GetDescendants(getter_AddRefs(allFolders));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> enumerator;
|
||||
rv = allFolders->Enumerate(getter_AddRefs(enumerator));
|
||||
if (NS_SUCCEEDED(rv) && enumerator)
|
||||
{
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
int32_t numNewMessages = 0;
|
||||
bool hasMore = false;
|
||||
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore)
|
||||
{
|
||||
rv = enumerator->GetNext(getter_AddRefs(supports));
|
||||
if (NS_SUCCEEDED(rv) && supports)
|
||||
{
|
||||
msgFolder = do_QueryInterface(supports, &rv);
|
||||
if (msgFolder)
|
||||
{
|
||||
numNewMessages = 0;
|
||||
msgFolder->GetNumNewMessages(false, &numNewMessages);
|
||||
if (numNewMessages)
|
||||
break; // kick out of the while loop
|
||||
}
|
||||
} // if we have a folder
|
||||
} // if we have more potential folders to enumerate
|
||||
} // if enumerator
|
||||
|
||||
if (msgFolder)
|
||||
msgFolder->GetURI(aFolderURI);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Method implementations for mozINewMailListener
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsMessengerOSXIntegration::OnCountChanged(uint32_t count)
|
||||
{
|
||||
mUnreadTotal = count;
|
||||
BadgeDockIcon();
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -353,9 +353,11 @@ NS_IMETHODIMP nsMsgMailSession::AddMsgWindow(nsIMsgWindow *msgWindow)
|
|||
NS_IMETHODIMP nsMsgMailSession::RemoveMsgWindow(nsIMsgWindow *msgWindow)
|
||||
{
|
||||
mWindows.RemoveObject(msgWindow);
|
||||
// For suite, we don't want to disable mailnews when the last mail window
|
||||
// is closed (other component windows may still be open).
|
||||
#if !defined(MOZ_SUITE)
|
||||
// Mac keeps a hidden window open so the app doesn't shut down when
|
||||
// the last window is closed. So don't shutdown the account manager in that
|
||||
// case. Similarly, for suite, we don't want to disable mailnews when the
|
||||
// last mail window is closed.
|
||||
#if !defined(XP_MACOSX) && !defined(MOZ_SUITE)
|
||||
if (!mWindows.Count())
|
||||
{
|
||||
nsresult rv;
|
||||
|
|
|
|||
|
|
@ -136,11 +136,13 @@ nsresult nsStatusBarBiffManager::PlayBiffSound(const char *aPrefBranch)
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifndef XP_MACOSX
|
||||
// if nothing played, play the default system sound
|
||||
if (!customSoundPlayed) {
|
||||
rv = mSound->PlayEventSound(nsISound::EVENT_NEW_MAIL_RECEIVED);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -611,7 +611,7 @@ nsresult NS_MsgCreatePathStringFromFolderURI(const char *aFolderURI,
|
|||
? oldPath.FindChar('/', startSlashPos + 1) - 1 : oldPath.Length() - 1;
|
||||
if (endSlashPos < 0)
|
||||
endSlashPos = oldPath.Length();
|
||||
#if defined(XP_UNIX)
|
||||
#if defined(XP_UNIX) || defined(XP_MACOSX)
|
||||
bool isLocalUri = aScheme.EqualsLiteral("none") ||
|
||||
aScheme.EqualsLiteral("pop3") ||
|
||||
aScheme.EqualsLiteral("rss");
|
||||
|
|
@ -636,7 +636,7 @@ nsresult NS_MsgCreatePathStringFromFolderURI(const char *aFolderURI,
|
|||
CopyUTF16toMUTF7(pathPiece, tmp);
|
||||
CopyASCIItoUTF16(tmp, pathPiece);
|
||||
}
|
||||
#if defined(XP_UNIX)
|
||||
#if defined(XP_UNIX) || defined(XP_MACOSX)
|
||||
// Don't hash path pieces because local mail folder uri's have already
|
||||
// been hashed. We're only doing this on the mac to limit potential
|
||||
// regressions.
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
else:
|
||||
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
OS_LIBS += CONFIG['TK_LIBS']
|
||||
OS_LIBS += ['-framework Cocoa']
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/mailnews/addrbook/src',
|
||||
'/mailnews/base/search/src',
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@
|
|||
#ifdef XP_WIN
|
||||
#include "nsMessengerWinIntegration.h"
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
#include "nsMessengerOSXIntegration.h"
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
|
||||
#include "nsMessengerUnixIntegration.h"
|
||||
#endif
|
||||
|
|
@ -154,6 +157,12 @@
|
|||
#include "nsAbOutlookDirectory.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "nsAbOSXDirectory.h"
|
||||
#include "nsAbOSXCard.h"
|
||||
#include "nsAbOSXDirFactory.h"
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// bayesian spam filter includes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -370,6 +379,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgShutdownService)
|
|||
#ifdef XP_WIN
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerWinIntegration, Init)
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerOSXIntegration, Init)
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerUnixIntegration, Init)
|
||||
#endif
|
||||
|
|
@ -427,6 +439,9 @@ NS_DEFINE_NAMED_CID(NS_MSGNOTIFICATIONSERVICE_CID);
|
|||
#ifdef XP_WIN
|
||||
NS_DEFINE_NAMED_CID(NS_MESSENGERWININTEGRATION_CID);
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
NS_DEFINE_NAMED_CID(NS_MESSENGEROSXINTEGRATION_CID);
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
|
||||
NS_DEFINE_NAMED_CID(NS_MESSENGERUNIXINTEGRATION_CID);
|
||||
#endif
|
||||
|
|
@ -484,6 +499,12 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbView)
|
|||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgVCardService)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDIFService)
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXDirectory)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXCard)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXDirFactory)
|
||||
#endif
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_ABMANAGER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ABDIRECTORY_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ABMDBDIRECTORY_CID);
|
||||
|
|
@ -515,6 +536,11 @@ NS_DEFINE_NAMED_CID(NS_ABLDAP_REPLICATIONQUERY_CID);
|
|||
NS_DEFINE_NAMED_CID(NS_ABLDAP_PROCESSREPLICATIONDATA_CID);
|
||||
#endif
|
||||
NS_DEFINE_NAMED_CID(NS_ABDIRECTORYQUERYPROXY_CID);
|
||||
#ifdef XP_MACOSX
|
||||
NS_DEFINE_NAMED_CID(NS_ABOSXDIRECTORY_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ABOSXCARD_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ABOSXDIRFACTORY_CID);
|
||||
#endif
|
||||
NS_DEFINE_NAMED_CID(NS_ABVIEW_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_MSGVCARDSERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ABLDIFSERVICE_CID);
|
||||
|
|
@ -897,6 +923,9 @@ const mozilla::Module::CIDEntry kMailNewsCIDs[] = {
|
|||
#ifdef XP_WIN
|
||||
{ &kNS_MESSENGERWININTEGRATION_CID, false, NULL, nsMessengerWinIntegrationConstructor},
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
{ &kNS_MESSENGEROSXINTEGRATION_CID, false, NULL, nsMessengerOSXIntegrationConstructor},
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
|
||||
{ &kNS_MESSENGERUNIXINTEGRATION_CID, false, NULL, nsMessengerUnixIntegrationConstructor},
|
||||
#endif
|
||||
|
|
@ -939,6 +968,11 @@ const mozilla::Module::CIDEntry kMailNewsCIDs[] = {
|
|||
{ &kNS_ABLDAPDIRFACTORY_CID, false, NULL, nsAbLDAPDirFactoryConstructor },
|
||||
#endif
|
||||
{ &kNS_ABDIRECTORYQUERYPROXY_CID, false, NULL, nsAbDirectoryQueryProxyConstructor },
|
||||
#ifdef XP_MACOSX
|
||||
{ &kNS_ABOSXDIRECTORY_CID, false, NULL, nsAbOSXDirectoryConstructor },
|
||||
{ &kNS_ABOSXCARD_CID, false, NULL, nsAbOSXCardConstructor },
|
||||
{ &kNS_ABOSXDIRFACTORY_CID, false, NULL, nsAbOSXDirFactoryConstructor },
|
||||
#endif
|
||||
{ &kNS_ABVIEW_CID, false, NULL, nsAbViewConstructor },
|
||||
{ &kNS_MSGVCARDSERVICE_CID, false, NULL, nsMsgVCardServiceConstructor },
|
||||
{ &kNS_ABLDIFSERVICE_CID, false, NULL, nsAbLDIFServiceConstructor },
|
||||
|
|
@ -1107,6 +1141,9 @@ const mozilla::Module::ContractIDEntry kMailNewsContracts[] = {
|
|||
#ifdef XP_WIN
|
||||
{ NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGERWININTEGRATION_CID },
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
{ NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGEROSXINTEGRATION_CID },
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
|
||||
{ NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGERUNIXINTEGRATION_CID },
|
||||
#endif
|
||||
|
|
@ -1153,6 +1190,11 @@ const mozilla::Module::ContractIDEntry kMailNewsContracts[] = {
|
|||
#endif
|
||||
|
||||
{ NS_ABDIRECTORYQUERYPROXY_CONTRACTID, &kNS_ABDIRECTORYQUERYPROXY_CID },
|
||||
#ifdef XP_MACOSX
|
||||
{ NS_ABOSXDIRECTORY_CONTRACTID, &kNS_ABOSXDIRECTORY_CID },
|
||||
{ NS_ABOSXCARD_CONTRACTID, &kNS_ABOSXCARD_CID },
|
||||
{ NS_ABOSXDIRFACTORY_CONTRACTID, &kNS_ABOSXDIRFACTORY_CID },
|
||||
#endif
|
||||
{ NS_ABVIEW_CONTRACTID, &kNS_ABVIEW_CID },
|
||||
{ NS_MSGVCARDSERVICE_CONTRACTID, &kNS_MSGVCARDSERVICE_CID },
|
||||
{ NS_ABLDIFSERVICE_CONTRACTID, &kNS_ABLDIFSERVICE_CID },
|
||||
|
|
@ -1301,6 +1343,10 @@ static const mozilla::Module::CategoryEntry kMailNewsCategories[] = {
|
|||
{ XPCOM_DIRECTORY_PROVIDER_CATEGORY, "mail-directory-provider", NS_MAILDIRPROVIDER_CONTRACTID },
|
||||
{ "content-policy", NS_MSGCONTENTPOLICY_CONTRACTID, NS_MSGCONTENTPOLICY_CONTRACTID },
|
||||
MAILNEWSDLF_CATEGORIES
|
||||
#ifdef XP_MACOSX
|
||||
{ "app-startup", NS_MESSENGEROSINTEGRATION_CONTRACTID, "service," NS_MESSENGEROSINTEGRATION_CONTRACTID}
|
||||
,
|
||||
#endif
|
||||
// Address Book Entries
|
||||
{ "command-line-handler", "m-addressbook", NS_ABMANAGERSTARTUPHANDLER_CONTRACTID },
|
||||
// Bayesian Filter Entries
|
||||
|
|
|
|||
|
|
@ -35,6 +35,16 @@ SOURCES += [
|
|||
'nsURLFetcher.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'nsMsgAppleDoubleEncode.cpp',
|
||||
'nsMsgAppleEncode.cpp',
|
||||
]
|
||||
EXPORTS += [
|
||||
'nsMsgAppleCodes.h',
|
||||
'nsMsgAppleDouble.h',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsSMTPProtocolHandler.js',
|
||||
'nsSMTPProtocolHandler.manifest',
|
||||
|
|
|
|||
106
mailnews/compose/src/nsMsgAppleCodes.h
Normal file
106
mailnews/compose/src/nsMsgAppleCodes.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
** AD_Codes.h
|
||||
**
|
||||
** ---------------
|
||||
**
|
||||
** Head file for Apple Decode/Encode essential codes.
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef ad_codes_h
|
||||
#define ad_codes_h
|
||||
|
||||
/*
|
||||
** applefile definitions used
|
||||
*/
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
|
||||
#define APPLESINGLE_MAGIC 0x00051600L
|
||||
#define APPLEDOUBLE_MAGIC 0x00051607L
|
||||
#define VERSION 0x00020000
|
||||
|
||||
#define NUM_ENTRIES 6
|
||||
|
||||
#define ENT_DFORK 1L
|
||||
#define ENT_RFORK 2L
|
||||
#define ENT_NAME 3L
|
||||
#define ENT_COMMENT 4L
|
||||
#define ENT_DATES 8L
|
||||
#define ENT_FINFO 9L
|
||||
#define CONVERT_TIME 1265437696L
|
||||
|
||||
/*
|
||||
** data type used in the encoder/decoder.
|
||||
*/
|
||||
typedef struct ap_header
|
||||
{
|
||||
int32_t magic;
|
||||
int32_t version;
|
||||
char fill[16];
|
||||
int16_t entries;
|
||||
|
||||
} ap_header;
|
||||
|
||||
typedef struct ap_entry
|
||||
{
|
||||
int32_t id;
|
||||
int32_t offset;
|
||||
int32_t length;
|
||||
|
||||
} ap_entry;
|
||||
|
||||
typedef struct ap_dates
|
||||
{
|
||||
int32_t create, modify, backup, access;
|
||||
|
||||
} ap_dates;
|
||||
|
||||
typedef struct myFInfo /* the mac FInfo structure for the cross platform. */
|
||||
{
|
||||
int32_t fdType, fdCreator;
|
||||
int16_t fdFlags;
|
||||
int32_t fdLocation; /* it really should be a pointer, but just a place-holder */
|
||||
int16_t fdFldr;
|
||||
|
||||
} myFInfo;
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
/*
|
||||
** string utils.
|
||||
*/
|
||||
int write_stream(appledouble_encode_object *p_ap_encode_obj, const char *s,int len);
|
||||
|
||||
int fill_apple_mime_header(appledouble_encode_object *p_ap_encode_obj);
|
||||
int ap_encode_file_infor(appledouble_encode_object *p_ap_encode_obj);
|
||||
int ap_encode_header(appledouble_encode_object* p_ap_encode_obj, bool firstTime);
|
||||
int ap_encode_data( appledouble_encode_object* p_ap_encode_obj, bool firstTime);
|
||||
|
||||
/*
|
||||
** the prototypes for the ap_decoder.
|
||||
*/
|
||||
int fetch_a_line(appledouble_decode_object* p_ap_decode_obj, char *buff);
|
||||
int ParseFileHeader(appledouble_decode_object* p_ap_decode_obj);
|
||||
int ap_seek_part_start(appledouble_decode_object* p_ap_decode_obj);
|
||||
void parse_param(char *p, char **param, char**define, char **np);
|
||||
int ap_seek_to_boundary(appledouble_decode_object* p_ap_decode_obj, bool firstime);
|
||||
int ap_parse_header(appledouble_decode_object* p_ap_decode_obj,bool firstime);
|
||||
int ap_decode_file_infor(appledouble_decode_object* p_ap_decode_obj);
|
||||
int ap_decode_process_header(appledouble_decode_object* p_ap_decode_obj, bool firstime);
|
||||
int ap_decode_process_data( appledouble_decode_object* p_ap_decode_obj, bool firstime);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
#endif /* ad_codes_h */
|
||||
207
mailnews/compose/src/nsMsgAppleDouble.h
Normal file
207
mailnews/compose/src/nsMsgAppleDouble.h
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* AppleDouble.h
|
||||
* -------------
|
||||
*
|
||||
* The header file for a stream based apple single/double encodor/decodor.
|
||||
*
|
||||
* 2aug95 mym
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AppleDouble_h
|
||||
#define AppleDouble_h
|
||||
|
||||
#include "msgCore.h"
|
||||
#include "nsComposeStrings.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#define NOERR 0
|
||||
#define errDone 1
|
||||
/* Done with current operation. */
|
||||
#define errEOB 2
|
||||
/* End of a buffer. */
|
||||
#define errEOP 3
|
||||
/* End of a Part. */
|
||||
|
||||
|
||||
#define errFileOpen NS_ERROR_GET_CODE(NS_MSG_UNABLE_TO_OPEN_TMP_FILE)
|
||||
#define errFileWrite -202 /*Error writing temporary file.*/
|
||||
#define errUsrCancel -2 /*MK_INTERRUPTED */
|
||||
#define errDecoding -1
|
||||
|
||||
/*
|
||||
** The envirment block data type.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kInit,
|
||||
kDoingHeaderPortion,
|
||||
kDoneHeaderPortion,
|
||||
kDoingDataPortion,
|
||||
kDoneDataPortion
|
||||
};
|
||||
|
||||
typedef struct _appledouble_encode_object
|
||||
{
|
||||
char fname[256];
|
||||
FSIORefNum fileId; /* the id for the open file (data/resource fork) */
|
||||
|
||||
int state;
|
||||
int text_file_type; /* if the file has a text file type with it. */
|
||||
char *boundary; /* the boundary string. */
|
||||
|
||||
int status; /* the error code if anyerror happens. */
|
||||
char b_overflow[200];
|
||||
int s_overflow;
|
||||
|
||||
int state64; /* the left over state of base64 enocding */
|
||||
int ct; /* the character count of base64 encoding */
|
||||
int c1, c2; /* the left of the last base64 encoding */
|
||||
|
||||
char *outbuff; /* the outbuff by the caller. */
|
||||
int s_outbuff; /* the size of the buffer. */
|
||||
int pos_outbuff; /* the offset in the current buffer. */
|
||||
|
||||
} appledouble_encode_object;
|
||||
|
||||
/* The possible content transfer encodings */
|
||||
|
||||
enum
|
||||
{
|
||||
kEncodeNone,
|
||||
kEncodeQP,
|
||||
kEncodeBase64,
|
||||
kEncodeUU
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kGeneralMine,
|
||||
kAppleDouble,
|
||||
kAppleSingle
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kInline,
|
||||
kDontCare
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kHeaderPortion,
|
||||
kDataPortion
|
||||
};
|
||||
|
||||
/* the decode states. */
|
||||
enum
|
||||
{
|
||||
kBeginParseHeader = 3,
|
||||
kParsingHeader,
|
||||
kBeginSeekBoundary,
|
||||
kSeekingBoundary,
|
||||
kBeginHeaderPortion,
|
||||
kProcessingHeaderPortion,
|
||||
kBeginDataPortion,
|
||||
kProcessingDataPortion,
|
||||
kFinishing
|
||||
};
|
||||
|
||||
/* uuencode states */
|
||||
enum
|
||||
{
|
||||
kWaitingForBegin = (int) 0,
|
||||
kBegin,
|
||||
kMainBody,
|
||||
kEnd
|
||||
};
|
||||
|
||||
typedef struct _appledouble_decode_object
|
||||
{
|
||||
int is_binary;
|
||||
int is_apple_single; /* if the object encoded is in apple single */
|
||||
int write_as_binhex;
|
||||
|
||||
int messagetype;
|
||||
char* boundary0; /* the boundary for the enclosure. */
|
||||
int deposition; /* the deposition. */
|
||||
int encoding; /* the encoding method. */
|
||||
int which_part;
|
||||
|
||||
char fname[256];
|
||||
// nsIOFileStream *fileSpec; /* the stream for data fork work. */
|
||||
|
||||
int state;
|
||||
|
||||
int rksize; /* the resource fork size count. */
|
||||
int dksize; /* the data fork size count. */
|
||||
|
||||
int status; /* the error code if anyerror happens. */
|
||||
char b_leftover[256];
|
||||
int s_leftover;
|
||||
|
||||
int encode; /* the encode type of the message. */
|
||||
int state64; /* the left over state of base64 enocding */
|
||||
int left; /* the character count of base64 encoding */
|
||||
int c[4]; /* the left of the last base64 encoding */
|
||||
int uu_starts_line; /* is decoder at the start of a line? (uuencode) */
|
||||
int uu_state; /* state w/r/t the uuencode body */
|
||||
int uu_bytes_written; /* bytes written from the current tuple (uuencode) */
|
||||
int uu_line_bytes; /* encoded bytes remaining in the current line (uuencode) */
|
||||
|
||||
char *inbuff; /* the outbuff by the caller. */
|
||||
int s_inbuff; /* the size of the buffer. */
|
||||
int pos_inbuff; /* the offset in the current buffer. */
|
||||
|
||||
|
||||
nsCOMPtr <nsIFile> tmpFile; /* the temp file to hold the decode data fork */
|
||||
/* when doing the binhex exporting. */
|
||||
nsCOMPtr <nsIOutputStream> tmpFileStream; /* The output File Stream */
|
||||
int32_t data_size; /* the size of the data in the tmp file. */
|
||||
|
||||
} appledouble_decode_object;
|
||||
|
||||
|
||||
/*
|
||||
** The protypes.
|
||||
*/
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
int ap_encode_init(appledouble_encode_object *p_ap_encode_obj,
|
||||
const char* fname,
|
||||
char* separator);
|
||||
|
||||
int ap_encode_next(appledouble_encode_object* p_ap_encode_obj,
|
||||
char *to_buff,
|
||||
int32_t buff_size,
|
||||
int32_t* real_size);
|
||||
|
||||
int ap_encode_end(appledouble_encode_object* p_ap_encode_obj,
|
||||
bool is_aborting);
|
||||
|
||||
int ap_decode_init(appledouble_decode_object* p_ap_decode_obj,
|
||||
bool is_apple_single,
|
||||
bool write_as_bin_hex,
|
||||
void *closure);
|
||||
|
||||
int ap_decode_next(appledouble_decode_object* p_ap_decode_obj,
|
||||
char *in_buff,
|
||||
int32_t buff_size);
|
||||
|
||||
int ap_decode_end(appledouble_decode_object* p_ap_decode_obj,
|
||||
bool is_aborting);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif
|
||||
266
mailnews/compose/src/nsMsgAppleDoubleEncode.cpp
Normal file
266
mailnews/compose/src/nsMsgAppleDoubleEncode.cpp
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
*
|
||||
* apple-double.c
|
||||
* --------------
|
||||
*
|
||||
* The codes to do apple double encoding/decoding.
|
||||
*
|
||||
* 02aug95 mym created.
|
||||
*
|
||||
*/
|
||||
#include "nsID.h"
|
||||
#include "nscore.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsMsgAppleDouble.h"
|
||||
#include "nsMsgAppleCodes.h"
|
||||
#include "nsMsgCompUtils.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "prmem.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
|
||||
void
|
||||
MacGetFileType(nsIFile *fs,
|
||||
bool *useDefault,
|
||||
char **fileType,
|
||||
char **encoding)
|
||||
{
|
||||
if ((fs == NULL) || (fileType == NULL) || (encoding == NULL))
|
||||
return;
|
||||
|
||||
bool exists = false;
|
||||
fs->Exists(&exists);
|
||||
if (!exists)
|
||||
return;
|
||||
|
||||
*useDefault = TRUE;
|
||||
*fileType = NULL;
|
||||
*encoding = NULL;
|
||||
|
||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(fs);
|
||||
FSRef fsRef;
|
||||
FSCatalogInfo catalogInfo;
|
||||
OSErr err = errFileOpen;
|
||||
if (NS_SUCCEEDED(macFile->GetFSRef(&fsRef)))
|
||||
err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo, nullptr, nullptr, nullptr);
|
||||
|
||||
if ( (err != noErr) || (((FileInfo*)(&catalogInfo.finderInfo))->fileType == 'TEXT') )
|
||||
*fileType = strdup(APPLICATION_OCTET_STREAM);
|
||||
else
|
||||
{
|
||||
// At this point, we should call the mime service and
|
||||
// see what we can find out?
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIURI> tURI;
|
||||
if (NS_SUCCEEDED(NS_NewFileURI(getter_AddRefs(tURI), fs)) && tURI)
|
||||
{
|
||||
nsCOMPtr<nsIMIMEService> mimeFinder (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
|
||||
if (NS_SUCCEEDED(rv) && mimeFinder)
|
||||
{
|
||||
nsAutoCString mimeType;
|
||||
rv = mimeFinder->GetTypeFromURI(tURI, mimeType);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
*fileType = ToNewCString(mimeType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we hit here, return something...default to this...
|
||||
*fileType = strdup(APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
//#pragma cplusplus reset
|
||||
|
||||
/*
|
||||
* ap_encode_init
|
||||
* --------------
|
||||
*
|
||||
* Setup the encode envirment
|
||||
*/
|
||||
|
||||
int ap_encode_init( appledouble_encode_object *p_ap_encode_obj,
|
||||
const char *fname,
|
||||
char *separator)
|
||||
{
|
||||
nsCOMPtr <nsIFile> myFile;
|
||||
NS_NewNativeLocalFile(nsDependentCString(fname), true, getter_AddRefs(myFile));
|
||||
bool exists;
|
||||
if (myFile && NS_SUCCEEDED(myFile->Exists(&exists)) && !exists)
|
||||
return -1;
|
||||
|
||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(myFile);
|
||||
nsAutoCString path;
|
||||
macFile->GetNativePath(path);
|
||||
|
||||
memset(p_ap_encode_obj, 0, sizeof(appledouble_encode_object));
|
||||
|
||||
/*
|
||||
** Fill out the source file inforamtion.
|
||||
*/
|
||||
memcpy(p_ap_encode_obj->fname, path.get(), path.Length());
|
||||
p_ap_encode_obj->fname[path.Length()] = '\0';
|
||||
|
||||
p_ap_encode_obj->boundary = strdup(separator);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** ap_encode_next
|
||||
** --------------
|
||||
**
|
||||
** return :
|
||||
** noErr : everything is ok
|
||||
** errDone : when encoding is done.
|
||||
** errors : otherwise.
|
||||
*/
|
||||
int ap_encode_next(
|
||||
appledouble_encode_object* p_ap_encode_obj,
|
||||
char *to_buff,
|
||||
int32_t buff_size,
|
||||
int32_t* real_size)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
** install the out buff now.
|
||||
*/
|
||||
p_ap_encode_obj->outbuff = to_buff;
|
||||
p_ap_encode_obj->s_outbuff = buff_size;
|
||||
p_ap_encode_obj->pos_outbuff = 0;
|
||||
|
||||
/*
|
||||
** first copy the outstandind data in the overflow buff to the out buffer.
|
||||
*/
|
||||
if (p_ap_encode_obj->s_overflow)
|
||||
{
|
||||
status = write_stream(p_ap_encode_obj,
|
||||
(const char*)(p_ap_encode_obj->b_overflow),
|
||||
p_ap_encode_obj->s_overflow);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
p_ap_encode_obj->s_overflow = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** go the next processing stage based on the current state.
|
||||
*/
|
||||
switch (p_ap_encode_obj->state)
|
||||
{
|
||||
case kInit:
|
||||
/*
|
||||
** We are in the starting position, fill out the header.
|
||||
*/
|
||||
status = fill_apple_mime_header(p_ap_encode_obj);
|
||||
if (status != noErr)
|
||||
break; /* some error happens */
|
||||
|
||||
p_ap_encode_obj->state = kDoingHeaderPortion;
|
||||
status = ap_encode_header(p_ap_encode_obj, true);
|
||||
/* it is the first time to calling */
|
||||
if (status == errDone)
|
||||
{
|
||||
p_ap_encode_obj->state = kDoneHeaderPortion;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; /* we need more work on header portion. */
|
||||
}
|
||||
|
||||
/*
|
||||
** we are done with the header, so let's go to the data port.
|
||||
*/
|
||||
p_ap_encode_obj->state = kDoingDataPortion;
|
||||
status = ap_encode_data(p_ap_encode_obj, true);
|
||||
/* it is first time call do data portion */
|
||||
|
||||
if (status == errDone)
|
||||
{
|
||||
p_ap_encode_obj->state = kDoneDataPortion;
|
||||
status = noErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case kDoingHeaderPortion:
|
||||
|
||||
status = ap_encode_header(p_ap_encode_obj, false);
|
||||
/* continue with the header portion. */
|
||||
if (status == errDone)
|
||||
{
|
||||
p_ap_encode_obj->state = kDoneHeaderPortion;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; /* we need more work on header portion. */
|
||||
}
|
||||
|
||||
/*
|
||||
** start the data portion.
|
||||
*/
|
||||
p_ap_encode_obj->state = kDoingDataPortion;
|
||||
status = ap_encode_data(p_ap_encode_obj, true);
|
||||
/* it is the first time calling */
|
||||
if (status == errDone)
|
||||
{
|
||||
p_ap_encode_obj->state = kDoneDataPortion;
|
||||
status = noErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case kDoingDataPortion:
|
||||
|
||||
status = ap_encode_data(p_ap_encode_obj, false);
|
||||
/* it is not the first time */
|
||||
|
||||
if (status == errDone)
|
||||
{
|
||||
p_ap_encode_obj->state = kDoneDataPortion;
|
||||
status = noErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case kDoneDataPortion:
|
||||
status = errDone; /* we are really done. */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
*real_size = p_ap_encode_obj->pos_outbuff;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
** ap_encode_end
|
||||
** -------------
|
||||
**
|
||||
** clear the apple encoding.
|
||||
*/
|
||||
|
||||
int ap_encode_end(
|
||||
appledouble_encode_object *p_ap_encode_obj,
|
||||
bool is_aborting)
|
||||
{
|
||||
/*
|
||||
** clear up the apple doubler.
|
||||
*/
|
||||
if (p_ap_encode_obj == NULL)
|
||||
return noErr;
|
||||
|
||||
if (p_ap_encode_obj->fileId) /* close the file if it is open. */
|
||||
::FSCloseFork(p_ap_encode_obj->fileId);
|
||||
|
||||
PR_FREEIF(p_ap_encode_obj->boundary); /* the boundary string. */
|
||||
|
||||
return noErr;
|
||||
}
|
||||
703
mailnews/compose/src/nsMsgAppleEncode.cpp
Normal file
703
mailnews/compose/src/nsMsgAppleEncode.cpp
Normal file
|
|
@ -0,0 +1,703 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
*
|
||||
* apple_double_encode.c
|
||||
* ---------------------
|
||||
*
|
||||
* The routines doing the Apple Double Encoding.
|
||||
*
|
||||
* 2aug95 mym Created.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "prprf.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsMsgAppleDouble.h"
|
||||
#include "nsMsgAppleCodes.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
|
||||
/*
|
||||
** Local Functions prototypes.
|
||||
*/
|
||||
static int output64chunk( appledouble_encode_object* p_ap_encode_obj,
|
||||
int c1, int c2, int c3, int pads);
|
||||
|
||||
static int to64(appledouble_encode_object* p_ap_encode_obj,
|
||||
char *p,
|
||||
int in_size);
|
||||
|
||||
static int finish64(appledouble_encode_object* p_ap_encode_obj);
|
||||
|
||||
|
||||
#define BUFF_LEFT(p) ((p)->s_outbuff - (p)->pos_outbuff)
|
||||
|
||||
/*
|
||||
** write_stream.
|
||||
*/
|
||||
int write_stream(
|
||||
appledouble_encode_object *p_ap_encode_obj,
|
||||
const char *out_string,
|
||||
int len)
|
||||
{
|
||||
if (p_ap_encode_obj->pos_outbuff + len < p_ap_encode_obj->s_outbuff)
|
||||
{
|
||||
memcpy(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff,
|
||||
out_string,
|
||||
len);
|
||||
p_ap_encode_obj->pos_outbuff += len;
|
||||
return noErr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
** If the buff doesn't have enough space, use the overflow buffer then.
|
||||
*/
|
||||
int s_len = p_ap_encode_obj->s_outbuff - p_ap_encode_obj->pos_outbuff;
|
||||
|
||||
memcpy(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff,
|
||||
out_string,
|
||||
s_len);
|
||||
memcpy(p_ap_encode_obj->b_overflow + p_ap_encode_obj->s_overflow,
|
||||
out_string + s_len,
|
||||
p_ap_encode_obj->s_overflow += (len - s_len));
|
||||
p_ap_encode_obj->pos_outbuff += s_len;
|
||||
return errEOB;
|
||||
}
|
||||
}
|
||||
|
||||
int fill_apple_mime_header(
|
||||
appledouble_encode_object *p_ap_encode_obj)
|
||||
{
|
||||
int status;
|
||||
|
||||
char tmpstr[266];
|
||||
|
||||
#if 0
|
||||
// strcpy(tmpstr, "Content-Type: multipart/mixed; boundary=\"-\"\n\n---\n");
|
||||
// status = write_stream(p_ap_encode_env,
|
||||
// tmpstr,
|
||||
// strlen(tmpstr));
|
||||
// if (status != noErr)
|
||||
// return status;
|
||||
|
||||
PR_snprintf(tmpstr, sizeof(tmpstr),
|
||||
"Content-Type: multipart/appledouble; boundary=\"=\"; name=\"");
|
||||
status = write_stream(p_ap_encode_obj, (const char*)tmpstr, strlen(tmpstr));
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
status = write_stream(p_ap_encode_obj,
|
||||
p_ap_encode_obj->fname,
|
||||
strlen(p_ap_encode_obj->fname));
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
PR_snprintf(tmpstr, sizeof(tmpstr),
|
||||
"\"\r\nContent-Disposition: inline; filename=\"%s\"\r\n\r\n\r\n--=\r\n",
|
||||
p_ap_encode_obj->fname);
|
||||
#endif /* 0 */
|
||||
PR_snprintf(tmpstr, sizeof(tmpstr), "--%s" CRLF, p_ap_encode_obj->boundary);
|
||||
status = write_stream(p_ap_encode_obj, (const char*)tmpstr, strlen(tmpstr));
|
||||
return status;
|
||||
}
|
||||
|
||||
int ap_encode_file_infor(
|
||||
appledouble_encode_object *p_ap_encode_obj)
|
||||
{
|
||||
ap_header head;
|
||||
ap_entry entries[NUM_ENTRIES];
|
||||
ap_dates dates;
|
||||
short i;
|
||||
long comlen;
|
||||
char comment[256];
|
||||
int status;
|
||||
|
||||
nsCOMPtr <nsIFile> resFile;
|
||||
NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true,
|
||||
getter_AddRefs(resFile));
|
||||
if (!resFile)
|
||||
return errFileOpen;
|
||||
|
||||
FSRef ref;
|
||||
nsCOMPtr <nsILocalFileMac> macFile = do_QueryInterface(resFile);
|
||||
if (NS_FAILED(macFile->GetFSRef(&ref)))
|
||||
return errFileOpen;
|
||||
|
||||
FSCatalogInfo catalogInfo;
|
||||
if (::FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalogInfo, nullptr, nullptr, nullptr) != noErr)
|
||||
{
|
||||
return errFileOpen;
|
||||
}
|
||||
|
||||
/* get a file comment, if possible */
|
||||
#if 1
|
||||
// Carbon doesn't support GetWDInfo(). (Bug 555684)
|
||||
|
||||
// not sure why working directories are needed here...
|
||||
comlen = 0;
|
||||
#else
|
||||
long procID;
|
||||
procID = 0;
|
||||
GetWDInfo(p_ap_encode_obj->vRefNum, &fpb->ioVRefNum, &fpb->ioDirID, &procID);
|
||||
IOParam vinfo;
|
||||
memset((void *) &vinfo, '\0', sizeof (vinfo));
|
||||
GetVolParmsInfoBuffer vp;
|
||||
vinfo.ioCompletion = nil;
|
||||
vinfo.ioVRefNum = fpb->ioVRefNum;
|
||||
vinfo.ioBuffer = (Ptr) &vp;
|
||||
vinfo.ioReqCount = sizeof (vp);
|
||||
comlen = 0;
|
||||
if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr &&
|
||||
((vp.vMAttrib >> bHasDesktopMgr) & 1))
|
||||
{
|
||||
DTPBRec dtp;
|
||||
memset((void *) &dtp, '\0', sizeof (dtp));
|
||||
dtp.ioVRefNum = fpb->ioVRefNum;
|
||||
if (PBDTGetPath(&dtp) == noErr)
|
||||
{
|
||||
dtp.ioCompletion = nil;
|
||||
dtp.ioDTBuffer = (Ptr) comment;
|
||||
dtp.ioNamePtr = fpb->ioNamePtr;
|
||||
dtp.ioDirID = fpb->ioFlParID;
|
||||
if (PBDTGetCommentSync(&dtp) == noErr)
|
||||
comlen = dtp.ioDTActCount;
|
||||
}
|
||||
}
|
||||
#endif /* ! 1 */
|
||||
|
||||
/* write header */
|
||||
// head.magic = dfork ? APPLESINGLE_MAGIC : APPLEDOUBLE_MAGIC;
|
||||
head.magic = APPLEDOUBLE_MAGIC; /* always do apple double */
|
||||
head.version = VERSION;
|
||||
memset(head.fill, '\0', sizeof (head.fill));
|
||||
head.entries = NUM_ENTRIES - 1;
|
||||
status = to64(p_ap_encode_obj,
|
||||
(char *) &head,
|
||||
sizeof (head));
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
/* write entry descriptors */
|
||||
nsAutoCString leafname;
|
||||
macFile->GetNativeLeafName(leafname);
|
||||
entries[0].offset = sizeof (head) + sizeof (ap_entry) * head.entries;
|
||||
entries[0].id = ENT_NAME;
|
||||
entries[0].length = leafname.Length();
|
||||
entries[1].id = ENT_FINFO;
|
||||
entries[1].length = sizeof (FInfo) + sizeof (FXInfo);
|
||||
entries[2].id = ENT_DATES;
|
||||
entries[2].length = sizeof (ap_dates);
|
||||
entries[3].id = ENT_COMMENT;
|
||||
entries[3].length = comlen;
|
||||
entries[4].id = ENT_RFORK;
|
||||
entries[4].length = catalogInfo.rsrcLogicalSize;
|
||||
entries[5].id = ENT_DFORK;
|
||||
entries[5].length = catalogInfo.dataLogicalSize;
|
||||
|
||||
/* correct the link in the entries. */
|
||||
for (i = 1; i < NUM_ENTRIES; ++i)
|
||||
{
|
||||
entries[i].offset = entries[i-1].offset + entries[i-1].length;
|
||||
}
|
||||
status = to64(p_ap_encode_obj,
|
||||
(char *) entries,
|
||||
sizeof (ap_entry) * head.entries);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
/* write name */
|
||||
status = to64(p_ap_encode_obj,
|
||||
(char *) leafname.get(),
|
||||
leafname.Length());
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
/* write finder info */
|
||||
status = to64(p_ap_encode_obj,
|
||||
(char *) &catalogInfo.finderInfo,
|
||||
sizeof (FInfo));
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
status = to64(p_ap_encode_obj,
|
||||
(char *) &catalogInfo.extFinderInfo,
|
||||
sizeof (FXInfo));
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
/* write dates */
|
||||
dates.create = catalogInfo.createDate.lowSeconds + CONVERT_TIME;
|
||||
dates.modify = catalogInfo.contentModDate.lowSeconds + CONVERT_TIME;
|
||||
dates.backup = catalogInfo.backupDate.lowSeconds + CONVERT_TIME;
|
||||
dates.access = catalogInfo.accessDate.lowSeconds + CONVERT_TIME;
|
||||
status = to64(p_ap_encode_obj,
|
||||
(char *) &dates,
|
||||
sizeof (ap_dates));
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
/* write comment */
|
||||
if (comlen)
|
||||
{
|
||||
status = to64(p_ap_encode_obj,
|
||||
comment,
|
||||
comlen * sizeof(char));
|
||||
}
|
||||
/*
|
||||
** Get some help information on deciding the file type.
|
||||
*/
|
||||
if (((FileInfo*)(&catalogInfo.finderInfo))->fileType == 'TEXT' ||
|
||||
((FileInfo*)(&catalogInfo.finderInfo))->fileType == 'text')
|
||||
{
|
||||
p_ap_encode_obj->text_file_type = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
/*
|
||||
** ap_encode_header
|
||||
**
|
||||
** encode the file header and the resource fork.
|
||||
**
|
||||
*/
|
||||
int ap_encode_header(
|
||||
appledouble_encode_object* p_ap_encode_obj,
|
||||
bool firstime)
|
||||
{
|
||||
char rd_buff[256];
|
||||
FSIORefNum fileId;
|
||||
OSErr retval = noErr;
|
||||
int status;
|
||||
ByteCount inCount;
|
||||
|
||||
if (firstime)
|
||||
{
|
||||
PL_strcpy(rd_buff,
|
||||
"Content-Type: application/applefile\r\nContent-Transfer-Encoding: base64\r\n\r\n");
|
||||
status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff));
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
status = ap_encode_file_infor(p_ap_encode_obj);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
/*
|
||||
** preparing to encode the resource fork.
|
||||
*/
|
||||
nsCOMPtr <nsIFile> myFile;
|
||||
NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true, getter_AddRefs(myFile));
|
||||
if (!myFile)
|
||||
return errFileOpen;
|
||||
|
||||
FSRef ref;
|
||||
nsCOMPtr <nsILocalFileMac> macFile = do_QueryInterface(myFile);
|
||||
if (NS_FAILED(macFile->GetFSRef(&ref)))
|
||||
return errFileOpen;
|
||||
|
||||
HFSUniStr255 forkName;
|
||||
::FSGetResourceForkName(&forkName);
|
||||
retval = ::FSOpenFork(&ref, forkName.length, forkName.unicode, fsRdPerm, &p_ap_encode_obj->fileId);
|
||||
if (retval != noErr)
|
||||
return retval;
|
||||
}
|
||||
|
||||
fileId = p_ap_encode_obj->fileId;
|
||||
while (retval == noErr)
|
||||
{
|
||||
if (BUFF_LEFT(p_ap_encode_obj) < 400)
|
||||
break;
|
||||
|
||||
inCount = 0;
|
||||
retval = ::FSReadFork(fileId, fsAtMark, 0, 256, rd_buff, &inCount);
|
||||
if (inCount)
|
||||
{
|
||||
status = to64(p_ap_encode_obj,
|
||||
rd_buff,
|
||||
inCount);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == eofErr)
|
||||
{
|
||||
::FSCloseFork(fileId);
|
||||
p_ap_encode_obj->fileId = 0;
|
||||
|
||||
status = finish64(p_ap_encode_obj);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
/*
|
||||
** write out the boundary
|
||||
*/
|
||||
PR_snprintf(rd_buff, sizeof(rd_buff),
|
||||
CRLF "--%s" CRLF,
|
||||
p_ap_encode_obj->boundary);
|
||||
|
||||
status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff));
|
||||
if (status == noErr)
|
||||
status = errDone;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// This is unused for now and Clang complains about that is it is ifdefed out
|
||||
static void replace(char *p, int len, char frm, char to)
|
||||
{
|
||||
for (; len > 0; len--, p++)
|
||||
if (*p == frm) *p = to;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Description of the various file formats and their magic numbers */
|
||||
struct magic
|
||||
{
|
||||
const char *name; /* Name of the file format */
|
||||
const char *num; /* The magic number */
|
||||
int len; /* Length (0 means strlen(magicnum)) */
|
||||
};
|
||||
|
||||
/* The magic numbers of the file formats we know about */
|
||||
static struct magic magic[] =
|
||||
{
|
||||
{ "image/gif", "GIF", 0 },
|
||||
{ "image/jpeg", "\377\330\377", 0 },
|
||||
{ "video/mpeg", "\0\0\001\263", 4 },
|
||||
{ "application/postscript", "%!", 0 },
|
||||
};
|
||||
static int num_magic = MOZ_ARRAY_LENGTH(magic);
|
||||
|
||||
static const char *text_type = TEXT_PLAIN; /* the text file type. */
|
||||
static const char *default_type = APPLICATION_OCTET_STREAM;
|
||||
|
||||
|
||||
/*
|
||||
* Determins the format of the file "inputf". The name
|
||||
* of the file format (or NULL on error) is returned.
|
||||
*/
|
||||
static const char *magic_look(char *inbuff, int numread)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i=0; i<num_magic; i++)
|
||||
{
|
||||
if (magic[i].len == 0)
|
||||
magic[i].len = strlen(magic[i].num);
|
||||
}
|
||||
|
||||
for (i=0; i<num_magic; i++)
|
||||
{
|
||||
if (numread >= magic[i].len)
|
||||
{
|
||||
for (j=0; j<magic[i].len; j++)
|
||||
{
|
||||
if (inbuff[j] != magic[i].num[j]) break;
|
||||
}
|
||||
|
||||
if (j == magic[i].len)
|
||||
return magic[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return default_type;
|
||||
}
|
||||
/*
|
||||
** ap_encode_data
|
||||
**
|
||||
** ---------------
|
||||
**
|
||||
** encode on the data fork.
|
||||
**
|
||||
*/
|
||||
int ap_encode_data(
|
||||
appledouble_encode_object* p_ap_encode_obj,
|
||||
bool firstime)
|
||||
{
|
||||
char rd_buff[256];
|
||||
FSIORefNum fileId;
|
||||
OSErr retval = noErr;
|
||||
ByteCount in_count;
|
||||
int status;
|
||||
|
||||
if (firstime)
|
||||
{
|
||||
const char* magic_type;
|
||||
|
||||
/*
|
||||
** preparing to encode the data fork.
|
||||
*/
|
||||
nsCOMPtr <nsIFile> resFile;
|
||||
NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true,
|
||||
getter_AddRefs(resFile));
|
||||
if (!resFile)
|
||||
return errFileOpen;
|
||||
|
||||
FSRef ref;
|
||||
nsCOMPtr <nsILocalFileMac> macFile = do_QueryInterface(resFile);
|
||||
if (NS_FAILED(macFile->GetFSRef(&ref)))
|
||||
return errFileOpen;
|
||||
|
||||
HFSUniStr255 forkName;
|
||||
::FSGetDataForkName(&forkName);
|
||||
retval = ::FSOpenFork(&ref, forkName.length, forkName.unicode, fsRdPerm, &fileId);
|
||||
if (retval != noErr)
|
||||
return retval;
|
||||
|
||||
p_ap_encode_obj->fileId = fileId;
|
||||
|
||||
|
||||
if (!p_ap_encode_obj->text_file_type)
|
||||
{
|
||||
/*
|
||||
** do a smart check for the file type.
|
||||
*/
|
||||
in_count = 0;
|
||||
retval = ::FSReadFork(fileId, fsFromStart, 0, 256, rd_buff, &in_count);
|
||||
magic_type = magic_look(rd_buff, in_count);
|
||||
|
||||
/* don't forget to rewind the index to start point. */
|
||||
::FSSetForkPosition(fileId, fsFromStart, 0);
|
||||
/* and reset retVal just in case... */
|
||||
if (retval == eofErr)
|
||||
retval = noErr;
|
||||
}
|
||||
else
|
||||
{
|
||||
magic_type = text_type; /* we already know it is a text type. */
|
||||
}
|
||||
|
||||
/*
|
||||
** the data portion header information.
|
||||
*/
|
||||
nsAutoCString leafName;
|
||||
resFile->GetNativeLeafName(leafName);
|
||||
PR_snprintf(rd_buff, sizeof(rd_buff),
|
||||
"Content-Type: %s; name=\"%s\"" CRLF "Content-Transfer-Encoding: base64" CRLF "Content-Disposition: inline; filename=\"%s\"" CRLF CRLF,
|
||||
magic_type,
|
||||
leafName.get(),
|
||||
leafName.get());
|
||||
|
||||
status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff));
|
||||
if (status != noErr)
|
||||
return status;
|
||||
}
|
||||
|
||||
while (retval == noErr)
|
||||
{
|
||||
if (BUFF_LEFT(p_ap_encode_obj) < 400)
|
||||
break;
|
||||
|
||||
in_count = 0;
|
||||
retval = ::FSReadFork(p_ap_encode_obj->fileId, fsAtMark, 0, 256, rd_buff, &in_count);
|
||||
if (in_count)
|
||||
{
|
||||
#if 0
|
||||
/* replace(rd_buff, in_count, '\r', '\n'); */
|
||||
#endif
|
||||
/* ** may be need to do character set conversion here for localization. ** */
|
||||
status = to64(p_ap_encode_obj,
|
||||
rd_buff,
|
||||
in_count);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == eofErr)
|
||||
{
|
||||
::FSCloseFork(p_ap_encode_obj->fileId);
|
||||
p_ap_encode_obj->fileId = 0;
|
||||
|
||||
status = finish64(p_ap_encode_obj);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
/* write out the boundary */
|
||||
|
||||
PR_snprintf(rd_buff, sizeof(rd_buff),
|
||||
CRLF "--%s--" CRLF CRLF,
|
||||
p_ap_encode_obj->boundary);
|
||||
|
||||
status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff));
|
||||
|
||||
if (status == noErr)
|
||||
status = errDone;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static char basis_64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/*
|
||||
** convert the stream in the inbuff to 64 format and put it in the out buff.
|
||||
** To make the life easier, the caller will responcable of the cheking of the outbuff's bundary.
|
||||
*/
|
||||
static int
|
||||
to64(appledouble_encode_object* p_ap_encode_obj,
|
||||
char *p,
|
||||
int in_size)
|
||||
{
|
||||
int status;
|
||||
int c1, c2, c3, ct;
|
||||
unsigned char *inbuff = (unsigned char*)p;
|
||||
|
||||
ct = p_ap_encode_obj->ct; /* the char count left last time. */
|
||||
|
||||
/*
|
||||
** resume the left state of the last conversion.
|
||||
*/
|
||||
switch (p_ap_encode_obj->state64)
|
||||
{
|
||||
case 0:
|
||||
p_ap_encode_obj->c1 = c1 = *inbuff ++;
|
||||
if (--in_size <= 0)
|
||||
{
|
||||
p_ap_encode_obj->state64 = 1;
|
||||
return noErr;
|
||||
}
|
||||
p_ap_encode_obj->c2 = c2 = *inbuff ++;
|
||||
if (--in_size <= 0)
|
||||
{
|
||||
p_ap_encode_obj->state64 = 2;
|
||||
return noErr;
|
||||
}
|
||||
c3 = *inbuff ++; --in_size;
|
||||
break;
|
||||
case 1:
|
||||
c1 = p_ap_encode_obj->c1;
|
||||
p_ap_encode_obj->c2 = c2 = *inbuff ++;
|
||||
if (--in_size <= 0)
|
||||
{
|
||||
p_ap_encode_obj->state64 = 2;
|
||||
return noErr;
|
||||
}
|
||||
c3 = *inbuff ++; --in_size;
|
||||
break;
|
||||
case 2:
|
||||
c1 = p_ap_encode_obj->c1;
|
||||
c2 = p_ap_encode_obj->c2;
|
||||
c3 = *inbuff ++; --in_size;
|
||||
break;
|
||||
}
|
||||
|
||||
while (in_size >= 0)
|
||||
{
|
||||
status = output64chunk(p_ap_encode_obj,
|
||||
c1,
|
||||
c2,
|
||||
c3,
|
||||
0);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
ct += 4;
|
||||
if (ct > 71)
|
||||
{
|
||||
status = write_stream(p_ap_encode_obj,
|
||||
CRLF,
|
||||
2);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
|
||||
ct = 0;
|
||||
}
|
||||
|
||||
if (in_size <= 0)
|
||||
{
|
||||
p_ap_encode_obj->state64 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
c1 = (int)*inbuff++;
|
||||
if (--in_size <= 0)
|
||||
{
|
||||
p_ap_encode_obj->c1 = c1;
|
||||
p_ap_encode_obj->state64 = 1;
|
||||
break;
|
||||
}
|
||||
c2 = *inbuff++;
|
||||
if (--in_size <= 0)
|
||||
{
|
||||
p_ap_encode_obj->c1 = c1;
|
||||
p_ap_encode_obj->c2 = c2;
|
||||
p_ap_encode_obj->state64 = 2;
|
||||
break;
|
||||
}
|
||||
c3 = *inbuff++;
|
||||
in_size--;
|
||||
}
|
||||
p_ap_encode_obj->ct = ct;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
** clear the left base64 encodes.
|
||||
*/
|
||||
static int
|
||||
finish64(appledouble_encode_object* p_ap_encode_obj)
|
||||
{
|
||||
int status;
|
||||
|
||||
switch (p_ap_encode_obj->state64)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
status = output64chunk(p_ap_encode_obj,
|
||||
p_ap_encode_obj->c1,
|
||||
0,
|
||||
0,
|
||||
2);
|
||||
break;
|
||||
case 2:
|
||||
status = output64chunk(p_ap_encode_obj,
|
||||
p_ap_encode_obj->c1,
|
||||
p_ap_encode_obj->c2,
|
||||
0,
|
||||
1);
|
||||
break;
|
||||
}
|
||||
status = write_stream(p_ap_encode_obj, CRLF, 2);
|
||||
p_ap_encode_obj->state64 = 0;
|
||||
p_ap_encode_obj->ct = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int output64chunk(
|
||||
appledouble_encode_object* p_ap_encode_obj,
|
||||
int c1, int c2, int c3, int pads)
|
||||
{
|
||||
char tmpstr[32];
|
||||
char *p = tmpstr;
|
||||
|
||||
*p++ = basis_64[c1>>2];
|
||||
*p++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
|
||||
if (pads == 2)
|
||||
{
|
||||
*p++ = '=';
|
||||
*p++ = '=';
|
||||
}
|
||||
else if (pads)
|
||||
{
|
||||
*p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
||||
*p++ = '=';
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
||||
*p++ = basis_64[c3 & 0x3F];
|
||||
}
|
||||
return write_stream(p_ap_encode_obj, (const char*) tmpstr, p-tmpstr);
|
||||
}
|
||||
|
|
@ -36,6 +36,77 @@
|
|||
#include "mozilla/mailnews/MimeEncoder.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Mac Specific Attachment Handling for AppleDouble Encoded Files
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#ifdef XP_MACOSX
|
||||
|
||||
#define AD_WORKING_BUFF_SIZE FILE_IO_BUFFER_SIZE
|
||||
|
||||
extern void MacGetFileType(nsIFile *fs, bool *useDefault, char **type, char **encoding);
|
||||
|
||||
#include "nsILocalFileMac.h"
|
||||
|
||||
/* static */
|
||||
nsresult nsSimpleZipper::Zip(nsIFile *aInputFile, nsIFile *aOutputFile)
|
||||
{
|
||||
// create zipwriter object
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIZipWriter> zipWriter = do_CreateInstance("@mozilla.org/zipwriter;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = zipWriter->Open(aOutputFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = AddToZip(zipWriter, aInputFile, EmptyCString());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// we're done.
|
||||
zipWriter->Close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult nsSimpleZipper::AddToZip(nsIZipWriter *aZipWriter,
|
||||
nsIFile *aFile,
|
||||
const nsACString &aPath)
|
||||
{
|
||||
// find out the path this file/dir should have in the zip
|
||||
nsCString leafName;
|
||||
aFile->GetNativeLeafName(leafName);
|
||||
nsCString currentPath(aPath);
|
||||
currentPath += leafName;
|
||||
|
||||
bool isDirectory;
|
||||
aFile->IsDirectory(&isDirectory);
|
||||
// append slash for a directory entry
|
||||
if (isDirectory)
|
||||
currentPath.Append('/');
|
||||
|
||||
// add the file or directory entry to the zip
|
||||
nsresult rv = aZipWriter->AddEntryFile(currentPath, nsIZipWriter::COMPRESSION_DEFAULT, aFile, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if it's a directory, add all its contents too
|
||||
if (isDirectory) {
|
||||
nsCOMPtr<nsISimpleEnumerator> e;
|
||||
nsresult rv = aFile->GetDirectoryEntries(getter_AddRefs(e));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDirectoryEnumerator> dirEnumerator = do_QueryInterface(e, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIFile> currentFile;
|
||||
while (NS_SUCCEEDED(dirEnumerator->GetNextFile(getter_AddRefs(currentFile))) && currentFile) {
|
||||
rv = AddToZip(aZipWriter, currentFile, currentPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif // XP_MACOSX
|
||||
|
||||
//
|
||||
// Class implementation...
|
||||
//
|
||||
|
|
@ -168,7 +239,12 @@ NS_IMETHODIMP nsMsgAttachmentHandler::GetAlreadyEncoded(bool* aAlreadyEncoded)
|
|||
void
|
||||
nsMsgAttachmentHandler::CleanupTempFile()
|
||||
{
|
||||
/** Mac Stub **/
|
||||
#ifdef XP_MACOSX
|
||||
if (mEncodedWorkingFile) {
|
||||
mEncodedWorkingFile->Remove(false);
|
||||
mEncodedWorkingFile = nullptr;
|
||||
}
|
||||
#endif // XP_MACOSX
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -473,8 +549,13 @@ FetcherURLDoneCallback(nsresult aStatus,
|
|||
ma->m_size = totalSize;
|
||||
if (!aContentType.IsEmpty())
|
||||
{
|
||||
// can't send appledouble on non-macs
|
||||
#ifdef XP_MACOSX
|
||||
//Do not change the type if we are dealing with an encoded (e.g., appledouble or zip) file
|
||||
if (!ma->mEncodedWorkingFile)
|
||||
#else
|
||||
// can't send appledouble on non-macs
|
||||
if (!aContentType.EqualsLiteral("multipart/appledouble"))
|
||||
#endif
|
||||
ma->m_type = aContentType;
|
||||
}
|
||||
|
||||
|
|
@ -617,6 +698,15 @@ done:
|
|||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
bool nsMsgAttachmentHandler::HasResourceFork(FSRef *fsRef)
|
||||
{
|
||||
FSCatalogInfo catalogInfo;
|
||||
OSErr err = FSGetCatalogInfo(fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes, &catalogInfo, nullptr, nullptr, nullptr);
|
||||
return (err == noErr && catalogInfo.rsrcLogicalSize != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields)
|
||||
{
|
||||
|
|
@ -657,6 +747,33 @@ nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields)
|
|||
nsCString sourceURISpec;
|
||||
rv = mURL->GetSpec(sourceURISpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
#ifdef XP_MACOSX
|
||||
if (!m_bogus_attachment && StringBeginsWith(sourceURISpec, NS_LITERAL_CSTRING("file://")))
|
||||
{
|
||||
// Unescape the path (i.e. un-URLify it) before making a FSSpec
|
||||
nsAutoCString filePath;
|
||||
filePath.Adopt(nsMsgGetLocalFileFromURL(sourceURISpec.get()));
|
||||
nsAutoCString unescapedFilePath;
|
||||
MsgUnescapeString(filePath, 0, unescapedFilePath);
|
||||
|
||||
nsCOMPtr<nsIFile> sourceFile;
|
||||
NS_NewNativeLocalFile(unescapedFilePath, true, getter_AddRefs(sourceFile));
|
||||
if (!sourceFile)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// check if it is a bundle. if it is, we'll zip it.
|
||||
// if not, we'll apple encode it (applesingle or appledouble)
|
||||
nsCOMPtr<nsILocalFileMac> macFile(do_QueryInterface(sourceFile));
|
||||
bool isPackage;
|
||||
macFile->IsPackage(&isPackage);
|
||||
if (isPackage)
|
||||
rv = ConvertToZipFile(macFile);
|
||||
else
|
||||
rv = ConvertToAppleEncoding(sourceURISpec, unescapedFilePath, macFile);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
#endif /* XP_MACOSX */
|
||||
|
||||
//
|
||||
// Ok, here we are, we need to fire the URL off and get the data
|
||||
|
|
@ -676,6 +793,236 @@ nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields)
|
|||
return fetcher->FireURLRequest(mURL, mTmpFile, mOutFile, FetcherURLDoneCallback, this);
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
nsresult
|
||||
nsMsgAttachmentHandler::ConvertToZipFile(nsILocalFileMac *aSourceFile)
|
||||
{
|
||||
// append ".zip" to the real file name
|
||||
nsAutoCString zippedName;
|
||||
nsresult rv = aSourceFile->GetNativeLeafName(zippedName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
zippedName.AppendLiteral(".zip");
|
||||
|
||||
// create a temporary file that we'll work on
|
||||
nsCOMPtr <nsIFile> tmpFile;
|
||||
rv = nsMsgCreateTempFile(zippedName.get(), getter_AddRefs(tmpFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mEncodedWorkingFile = do_QueryInterface(tmpFile);
|
||||
|
||||
// point our URL at the zipped temp file
|
||||
NS_NewFileURI(getter_AddRefs(mURL), mEncodedWorkingFile);
|
||||
|
||||
// zip it!
|
||||
rv = nsSimpleZipper::Zip(aSourceFile, mEncodedWorkingFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// set some metadata for this attachment, that will affect the MIME headers.
|
||||
m_type = APPLICATION_ZIP;
|
||||
m_realName = zippedName.get();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMsgAttachmentHandler::ConvertToAppleEncoding(const nsCString &aFileURI,
|
||||
const nsCString &aFilePath,
|
||||
nsILocalFileMac *aSourceFile)
|
||||
{
|
||||
// convert the apple file to AppleDouble first, and then patch the
|
||||
// address in the url.
|
||||
|
||||
//We need to retrieve the file type and creator...
|
||||
|
||||
char fileInfo[32];
|
||||
OSType type, creator;
|
||||
|
||||
nsresult rv = aSourceFile->GetFileType(&type);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
PR_snprintf(fileInfo, sizeof(fileInfo), "%X", type);
|
||||
m_xMacType = fileInfo;
|
||||
|
||||
rv = aSourceFile->GetFileCreator(&creator);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
PR_snprintf(fileInfo, sizeof(fileInfo), "%X", creator);
|
||||
m_xMacCreator = fileInfo;
|
||||
|
||||
FSRef fsRef;
|
||||
aSourceFile->GetFSRef(&fsRef);
|
||||
bool sendResourceFork = HasResourceFork(&fsRef);
|
||||
|
||||
// if we have a resource fork, check the filename extension, maybe we don't need the resource fork!
|
||||
if (sendResourceFork)
|
||||
{
|
||||
nsCOMPtr<nsIURL> fileUrl(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
|
||||
if (fileUrl)
|
||||
{
|
||||
rv = fileUrl->SetSpec(aFileURI);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsAutoCString ext;
|
||||
rv = fileUrl->GetFileExtension(ext);
|
||||
if (NS_SUCCEEDED(rv) && !ext.IsEmpty())
|
||||
{
|
||||
sendResourceFork =
|
||||
PL_strcasecmp(ext.get(), "TXT") &&
|
||||
PL_strcasecmp(ext.get(), "JPG") &&
|
||||
PL_strcasecmp(ext.get(), "GIF") &&
|
||||
PL_strcasecmp(ext.get(), "TIF") &&
|
||||
PL_strcasecmp(ext.get(), "HTM") &&
|
||||
PL_strcasecmp(ext.get(), "HTML") &&
|
||||
PL_strcasecmp(ext.get(), "ART") &&
|
||||
PL_strcasecmp(ext.get(), "XUL") &&
|
||||
PL_strcasecmp(ext.get(), "XML") &&
|
||||
PL_strcasecmp(ext.get(), "CSS") &&
|
||||
PL_strcasecmp(ext.get(), "JS");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only use appledouble if we aren't uuencoding.
|
||||
if( sendResourceFork )
|
||||
{
|
||||
char *separator;
|
||||
|
||||
separator = mime_make_separator("ad");
|
||||
if (!separator)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr <nsIFile> tmpFile;
|
||||
nsresult rv = nsMsgCreateTempFile("appledouble", getter_AddRefs(tmpFile));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mEncodedWorkingFile = do_QueryInterface(tmpFile);
|
||||
if (!mEncodedWorkingFile)
|
||||
{
|
||||
PR_FREEIF(separator);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
//
|
||||
// RICHIE_MAC - ok, here's the deal, we have a file that we need
|
||||
// to encode in appledouble encoding for the resource fork and put that
|
||||
// into the mEncodedWorkingFile location. Then, we need to patch the new file
|
||||
// spec into the array and send this as part of the 2 part appledouble/mime
|
||||
// encoded mime part.
|
||||
//
|
||||
AppleDoubleEncodeObject *obj = new (AppleDoubleEncodeObject);
|
||||
if (obj == NULL)
|
||||
{
|
||||
mEncodedWorkingFile = nullptr;
|
||||
PR_FREEIF(separator);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = MsgGetFileStream(mEncodedWorkingFile, getter_AddRefs(obj->fileStream));
|
||||
if (NS_FAILED(rv) || !obj->fileStream)
|
||||
{
|
||||
PR_FREEIF(separator);
|
||||
delete obj;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char *working_buff = (char *) PR_Malloc(AD_WORKING_BUFF_SIZE);
|
||||
if (!working_buff)
|
||||
{
|
||||
PR_FREEIF(separator);
|
||||
delete obj;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
obj->buff = working_buff;
|
||||
obj->s_buff = AD_WORKING_BUFF_SIZE;
|
||||
|
||||
//
|
||||
// Setup all the need information on the apple double encoder.
|
||||
//
|
||||
ap_encode_init(&(obj->ap_encode_obj), aFilePath.get(), separator);
|
||||
|
||||
int32_t count;
|
||||
|
||||
OSErr status = noErr;
|
||||
m_size = 0;
|
||||
while (status == noErr)
|
||||
{
|
||||
status = ap_encode_next(&(obj->ap_encode_obj), obj->buff, obj->s_buff, &count);
|
||||
if (status == noErr || status == errDone)
|
||||
{
|
||||
//
|
||||
// we got the encode data, so call the next stream to write it to the disk.
|
||||
//
|
||||
uint32_t bytesWritten;
|
||||
obj->fileStream->Write(obj->buff, count, &bytesWritten);
|
||||
if (bytesWritten != (uint32_t) count)
|
||||
status = errFileWrite;
|
||||
}
|
||||
}
|
||||
|
||||
ap_encode_end(&(obj->ap_encode_obj), (status >= 0)); // if this is true, ok, false abort
|
||||
if (obj->fileStream)
|
||||
obj->fileStream->Close();
|
||||
|
||||
PR_FREEIF(obj->buff); /* free the working buff. */
|
||||
PR_FREEIF(obj);
|
||||
|
||||
nsCOMPtr <nsIURI> fileURI;
|
||||
NS_NewFileURI(getter_AddRefs(fileURI), mEncodedWorkingFile);
|
||||
|
||||
nsCOMPtr<nsIFileURL> theFileURL = do_QueryInterface(fileURI, &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsCString newURLSpec;
|
||||
rv = fileURI->GetSpec(newURLSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (newURLSpec.IsEmpty())
|
||||
{
|
||||
PR_FREEIF(separator);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (NS_FAILED(nsMsgNewURL(getter_AddRefs(mURL), newURLSpec.get())))
|
||||
{
|
||||
PR_FREEIF(separator);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Now after conversion, also patch the types.
|
||||
char tmp[128];
|
||||
PR_snprintf(tmp, sizeof(tmp), MULTIPART_APPLEDOUBLE ";\r\n boundary=\"%s\"", separator);
|
||||
PR_FREEIF(separator);
|
||||
m_type = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( sendResourceFork )
|
||||
{
|
||||
// For now, just do the encoding, but in the old world we would ask the
|
||||
// user about doing this conversion
|
||||
printf("...we could ask the user about this conversion, but for now, nahh..\n");
|
||||
}
|
||||
|
||||
bool useDefault;
|
||||
char *macType, *macEncoding;
|
||||
if (m_type.IsEmpty() || m_type.LowerCaseEqualsLiteral(TEXT_PLAIN))
|
||||
{
|
||||
# define TEXT_TYPE 0x54455854 /* the characters 'T' 'E' 'X' 'T' */
|
||||
# define text_TYPE 0x74657874 /* the characters 't' 'e' 'x' 't' */
|
||||
|
||||
if (type != TEXT_TYPE && type != text_TYPE)
|
||||
{
|
||||
MacGetFileType(aSourceFile, &useDefault, &macType, &macEncoding);
|
||||
m_type = macType;
|
||||
}
|
||||
}
|
||||
// don't bother to set the types if we failed in getting the file info.
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif // XP_MACOSX
|
||||
|
||||
nsresult
|
||||
nsMsgAttachmentHandler::LoadDataFromFile(nsIFile *file, nsString &sigData, bool charsetConversion)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,42 @@
|
|||
#include "nsAutoPtr.h"
|
||||
#include "nsIMsgAttachmentHandler.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
||||
#include "nsMsgAppleDouble.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
|
||||
class AppleDoubleEncodeObject
|
||||
{
|
||||
public:
|
||||
appledouble_encode_object ap_encode_obj;
|
||||
char *buff; // the working buff
|
||||
int32_t s_buff; // the working buff size
|
||||
nsCOMPtr <nsIOutputStream> fileStream; // file to hold the encoding
|
||||
};
|
||||
|
||||
class nsILocalFileMac;
|
||||
class nsIZipWriter;
|
||||
|
||||
/* Simple utility class that will synchronously zip any file
|
||||
(or folder hierarchy) you give it. */
|
||||
class nsSimpleZipper
|
||||
{
|
||||
public:
|
||||
|
||||
// Synchronously zips the input file/folder and writes all
|
||||
// data to the output file.
|
||||
static nsresult Zip(nsIFile *aInputFile, nsIFile *aOutputFile);
|
||||
|
||||
private:
|
||||
|
||||
// Recursively adds the file or folder to aZipWriter.
|
||||
static nsresult AddToZip(nsIZipWriter *aZipWriter,
|
||||
nsIFile *aFile,
|
||||
const nsACString &aPath);
|
||||
};
|
||||
#endif // XP_MACOSX
|
||||
|
||||
namespace mozilla {
|
||||
namespace mailnews {
|
||||
class MimeEncoder;
|
||||
|
|
@ -59,6 +95,14 @@ private:
|
|||
bool UseUUEncode_p(void);
|
||||
void AnalyzeDataChunk (const char *chunk, int32_t chunkSize);
|
||||
nsresult LoadDataFromFile(nsIFile *file, nsString &sigData, bool charsetConversion); //A similar function already exist in nsMsgCompose!
|
||||
#ifdef XP_MACOSX
|
||||
nsresult ConvertToAppleEncoding(const nsCString &aFileSpecURI,
|
||||
const nsCString &aFilePath,
|
||||
nsILocalFileMac *aSourceFile);
|
||||
// zips this attachment and does the work to make this attachment handler handle it properly.
|
||||
nsresult ConvertToZipFile(nsILocalFileMac *aSourceFile);
|
||||
bool HasResourceFork(FSRef *fsRef);
|
||||
#endif
|
||||
|
||||
//
|
||||
public:
|
||||
|
|
@ -69,6 +113,12 @@ public:
|
|||
nsMsgCompFields *mCompFields; // Message composition fields for the sender
|
||||
bool m_bogus_attachment; // This is to catch problem children...
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// if we need to encode this file into for example an appledouble, or zip file,
|
||||
// this file is our working file. currently only needed on mac.
|
||||
nsCOMPtr<nsIFile> mEncodedWorkingFile;
|
||||
#endif
|
||||
|
||||
nsCString m_xMacType; // Mac file type
|
||||
nsCString m_xMacCreator; // Mac file creator
|
||||
|
||||
|
|
|
|||
|
|
@ -2088,7 +2088,9 @@ nsMsgComposeAndSend::AddCompFieldLocalAttachments()
|
|||
if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) {
|
||||
nsAutoCString type;
|
||||
mimeFinder->GetTypeFromExtension(fileExt, type);
|
||||
#ifndef XP_MACOSX
|
||||
if (!type.Equals("multipart/appledouble")) // can't do apple double on non-macs
|
||||
#endif
|
||||
m_attachments[newLoc]->m_type = type;
|
||||
}
|
||||
}
|
||||
|
|
@ -2103,7 +2105,9 @@ nsMsgComposeAndSend::AddCompFieldLocalAttachments()
|
|||
if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) {
|
||||
nsAutoCString type;
|
||||
mimeFinder->GetTypeFromExtension(fileExt, type);
|
||||
#ifndef XP_MACOSX
|
||||
if (!type.Equals("multipart/appledouble")) // can't do apple double on non-macs
|
||||
#endif
|
||||
m_attachments[newLoc]->m_type = type;
|
||||
// rtf and vcs files may look like text to sniffers,
|
||||
// but they're not human readable.
|
||||
|
|
|
|||
|
|
@ -724,6 +724,25 @@ bool nsIMAPBodypartLeaf::ShouldFetchInline(nsIMAPBodyShell *aShell)
|
|||
|
||||
return false; // we can leave it on the server
|
||||
}
|
||||
#ifdef XP_MACOSX
|
||||
// If it is either applesingle, or a resource fork for appledouble
|
||||
if (!PL_strcasecmp(m_contentType, "application/applefile"))
|
||||
{
|
||||
// if it is appledouble
|
||||
if (m_parentPart->GetType() == IMAP_BODY_MULTIPART &&
|
||||
!PL_strcasecmp(m_parentPart->GetBodySubType(), "appledouble"))
|
||||
{
|
||||
// This is the resource fork of a multipart/appledouble.
|
||||
// We inherit the inline attributes of the parent,
|
||||
// which was derived from its OTHER child. (The data fork.)
|
||||
return m_parentPart->ShouldFetchInline(aShell);
|
||||
}
|
||||
else // it is applesingle
|
||||
{
|
||||
return false; // we can leave it on the server
|
||||
}
|
||||
}
|
||||
#endif // XP_MACOSX
|
||||
|
||||
// Leave out parts with type application/(*)
|
||||
if (!PL_strcasecmp(m_bodyType, "APPLICATION") && // If it is of type "application"
|
||||
|
|
|
|||
14
mailnews/import/applemail/src/moz.build
Normal file
14
mailnews/import/applemail/src/moz.build
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
SOURCES += [
|
||||
'nsAppleMailImport.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'nsEmlxHelperUtils.mm',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'import'
|
||||
|
||||
623
mailnews/import/applemail/src/nsAppleMailImport.cpp
Normal file
623
mailnews/import/applemail/src/nsAppleMailImport.cpp
Normal file
|
|
@ -0,0 +1,623 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIImportService.h"
|
||||
#include "nsIImportMailboxDescriptor.h"
|
||||
#include "nsIImportGeneric.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIMsgFolder.h"
|
||||
#include "nsIMsgHdr.h"
|
||||
#include "nsIMsgPluggableStore.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsMsgUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#include "nsEmlxHelperUtils.h"
|
||||
#include "nsAppleMailImport.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
PRLogModuleInfo *APPLEMAILLOGMODULE = nullptr;
|
||||
|
||||
// some hard-coded strings
|
||||
#define DEFAULT_MAIL_FOLDER "~/Library/Mail/"
|
||||
#define POP_MBOX_SUFFIX ".mbox"
|
||||
#define IMAP_MBOX_SUFFIX ".imapmbox"
|
||||
|
||||
// stringbundle URI
|
||||
#define APPLEMAIL_MSGS_URL "chrome://messenger/locale/appleMailImportMsgs.properties"
|
||||
|
||||
// magic constants
|
||||
#define kAccountMailboxID 1234
|
||||
|
||||
nsAppleMailImportModule::nsAppleMailImportModule()
|
||||
{
|
||||
// Init logging module.
|
||||
if (!APPLEMAILLOGMODULE)
|
||||
APPLEMAILLOGMODULE = PR_NewLogModule("APPLEMAILIMPORTLOG");
|
||||
|
||||
IMPORT_LOG0("nsAppleMailImportModule Created");
|
||||
|
||||
nsCOMPtr<nsIStringBundleService> bundleService =
|
||||
mozilla::services::GetStringBundleService();
|
||||
if (bundleService)
|
||||
bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(mBundle));
|
||||
}
|
||||
|
||||
|
||||
nsAppleMailImportModule::~nsAppleMailImportModule()
|
||||
{
|
||||
IMPORT_LOG0("nsAppleMailImportModule Deleted");
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAppleMailImportModule, nsIImportModule)
|
||||
|
||||
|
||||
NS_IMETHODIMP nsAppleMailImportModule::GetName(char16_t **aName)
|
||||
{
|
||||
return mBundle ?
|
||||
mBundle->GetStringFromName(u"ApplemailImportName", aName) : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleMailImportModule::GetDescription(char16_t **aName)
|
||||
{
|
||||
return mBundle ?
|
||||
mBundle->GetStringFromName(u"ApplemailImportDescription", aName) : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleMailImportModule::GetSupports(char **aSupports)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aSupports);
|
||||
*aSupports = strdup(NS_IMPORT_MAIL_STR);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleMailImportModule::GetSupportsUpgrade(bool *aUpgrade)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aUpgrade);
|
||||
*aUpgrade = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleMailImportModule::GetImportInterface(const char *aImportType, nsISupports **aInterface)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aImportType);
|
||||
NS_ENSURE_ARG_POINTER(aInterface);
|
||||
*aInterface = nullptr;
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if (!strcmp(aImportType, "mail")) {
|
||||
nsCOMPtr<nsIImportMail> mail(do_CreateInstance(NS_APPLEMAILIMPL_CONTRACTID, &rv));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIImportGeneric> generic;
|
||||
rv = impSvc->CreateNewGenericMail(getter_AddRefs(generic));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoString name;
|
||||
rv = mBundle->GetStringFromName(u"ApplemailImportName", getter_Copies(name));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISupportsString> nameString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nameString->SetData(name);
|
||||
|
||||
generic->SetData("name", nameString);
|
||||
generic->SetData("mailInterface", mail);
|
||||
|
||||
generic.forget(aInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
nsAppleMailImportMail::nsAppleMailImportMail() : mProgress(0), mCurDepth(0)
|
||||
{
|
||||
IMPORT_LOG0("nsAppleMailImportMail created");
|
||||
}
|
||||
|
||||
nsresult nsAppleMailImportMail::Initialize()
|
||||
{
|
||||
nsCOMPtr<nsIStringBundleService> bundleService =
|
||||
mozilla::services::GetStringBundleService();
|
||||
NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
|
||||
|
||||
return bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(mBundle));
|
||||
}
|
||||
|
||||
nsAppleMailImportMail::~nsAppleMailImportMail()
|
||||
{
|
||||
IMPORT_LOG0("nsAppleMailImportMail destroyed");
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAppleMailImportMail, nsIImportMail)
|
||||
|
||||
NS_IMETHODIMP nsAppleMailImportMail::GetDefaultLocation(nsIFile **aLocation, bool *aFound, bool *aUserVerify)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFound);
|
||||
NS_ENSURE_ARG_POINTER(aLocation);
|
||||
NS_ENSURE_ARG_POINTER(aUserVerify);
|
||||
|
||||
*aLocation = nullptr;
|
||||
*aFound = false;
|
||||
*aUserVerify = true;
|
||||
|
||||
// try to find current user's top-level Mail folder
|
||||
nsCOMPtr<nsIFile> mailFolder(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
|
||||
if (mailFolder) {
|
||||
nsresult rv = mailFolder->InitWithNativePath(NS_LITERAL_CSTRING(DEFAULT_MAIL_FOLDER));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*aFound = true;
|
||||
*aUserVerify = false;
|
||||
mailFolder.forget(aLocation);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// this is the method that initiates all searching for mailboxes.
|
||||
// it will assume that it has a directory like ~/Library/Mail/
|
||||
NS_IMETHODIMP nsAppleMailImportMail::FindMailboxes(nsIFile *aMailboxFile, nsIArray **aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aMailboxFile);
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
IMPORT_LOG0("FindMailboxes for Apple mail invoked");
|
||||
|
||||
bool exists = false;
|
||||
nsresult rv = aMailboxFile->Exists(&exists);
|
||||
if (NS_FAILED(rv) || !exists)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIImportService> importService(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMutableArray> resultsArray(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
|
||||
if (!resultsArray)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mCurDepth = 1;
|
||||
|
||||
// 1. look for accounts with mailboxes
|
||||
FindAccountMailDirs(aMailboxFile, resultsArray, importService);
|
||||
mCurDepth--;
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// 2. look for "global" mailboxes, that don't belong to any specific account. they are inside the
|
||||
// root's Mailboxes/ folder
|
||||
nsCOMPtr<nsIFile> mailboxesDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mailboxesDir->InitWithFile(aMailboxFile);
|
||||
rv = mailboxesDir->Append(NS_LITERAL_STRING("Mailboxes"));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
IMPORT_LOG0("Looking for global Apple mailboxes");
|
||||
|
||||
mCurDepth++;
|
||||
rv = FindMboxDirs(mailboxesDir, resultsArray, importService);
|
||||
mCurDepth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && resultsArray)
|
||||
resultsArray.forget(aResult);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// operates on the Mail/ directory root, trying to find accounts (which are folders named something like "POP-hwaara@gmail.com")
|
||||
// and add their .mbox dirs
|
||||
void nsAppleMailImportMail::FindAccountMailDirs(nsIFile *aRoot, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService)
|
||||
{
|
||||
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
|
||||
nsresult rv = aRoot->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
bool hasMore = false;
|
||||
while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) {
|
||||
|
||||
// get the next file entry
|
||||
nsCOMPtr<nsIFile> currentEntry;
|
||||
{
|
||||
nsCOMPtr<nsISupports> rawSupports;
|
||||
directoryEnumerator->GetNext(getter_AddRefs(rawSupports));
|
||||
if (!rawSupports)
|
||||
continue;
|
||||
currentEntry = do_QueryInterface(rawSupports);
|
||||
if (!currentEntry)
|
||||
continue;
|
||||
}
|
||||
|
||||
// make sure it's a directory
|
||||
bool isDirectory = false;
|
||||
currentEntry->IsDirectory(&isDirectory);
|
||||
|
||||
if (isDirectory) {
|
||||
// now let's see if it's an account folder. if so, we want to traverse it for .mbox children
|
||||
nsAutoString folderName;
|
||||
currentEntry->GetLeafName(folderName);
|
||||
bool isAccountFolder = false;
|
||||
|
||||
if (StringBeginsWith(folderName, NS_LITERAL_STRING("POP-"))) {
|
||||
// cut off "POP-" prefix so we get a nice folder name
|
||||
folderName.Cut(0, 4);
|
||||
isAccountFolder = true;
|
||||
}
|
||||
else if (StringBeginsWith(folderName, NS_LITERAL_STRING("IMAP-"))) {
|
||||
// cut off "IMAP-" prefix so we get a nice folder name
|
||||
folderName.Cut(0, 5);
|
||||
isAccountFolder = true;
|
||||
}
|
||||
|
||||
if (isAccountFolder) {
|
||||
IMPORT_LOG1("Found account: %s\n", NS_ConvertUTF16toUTF8(folderName).get());
|
||||
|
||||
// create a mailbox for this account, so we get a parent for "Inbox", "Sent Messages", etc.
|
||||
nsCOMPtr<nsIImportMailboxDescriptor> desc;
|
||||
nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc));
|
||||
desc->SetSize(1);
|
||||
desc->SetDepth(mCurDepth);
|
||||
desc->SetDisplayName(folderName.get());
|
||||
desc->SetIdentifier(kAccountMailboxID);
|
||||
|
||||
nsCOMPtr<nsIFile> mailboxDescFile;
|
||||
rv = desc->GetFile(getter_AddRefs(mailboxDescFile));
|
||||
if (!mailboxDescFile)
|
||||
continue;
|
||||
|
||||
mailboxDescFile->InitWithFile(currentEntry);
|
||||
|
||||
// add this mailbox descriptor to the list
|
||||
aMailboxDescs->AppendElement(desc, false);
|
||||
|
||||
// now add all the children mailboxes
|
||||
mCurDepth++;
|
||||
FindMboxDirs(currentEntry, aMailboxDescs, aImportService);
|
||||
mCurDepth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adds the specified file as a mailboxdescriptor to the array
|
||||
nsresult nsAppleMailImportMail::AddMboxDir(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService)
|
||||
{
|
||||
nsAutoString folderName;
|
||||
aFolder->GetLeafName(folderName);
|
||||
|
||||
// cut off the suffix, if any, or prefix if this is an account folder.
|
||||
if (StringEndsWith(folderName, NS_LITERAL_STRING(POP_MBOX_SUFFIX)))
|
||||
folderName.SetLength(folderName.Length()-5);
|
||||
else if (StringEndsWith(folderName, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX)))
|
||||
folderName.SetLength(folderName.Length()-9);
|
||||
else if (StringBeginsWith(folderName, NS_LITERAL_STRING("POP-")))
|
||||
folderName.Cut(4, folderName.Length());
|
||||
else if (StringBeginsWith(folderName, NS_LITERAL_STRING("IMAP-")))
|
||||
folderName.Cut(5, folderName.Length());
|
||||
|
||||
nsCOMPtr<nsIImportMailboxDescriptor> desc;
|
||||
nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// find out number of messages in this .mbox
|
||||
uint32_t numMessages = 0;
|
||||
{
|
||||
// move to the .mbox's Messages folder
|
||||
nsCOMPtr<nsIFile> messagesFolder;
|
||||
aFolder->Clone(getter_AddRefs(messagesFolder));
|
||||
nsresult rv = messagesFolder->Append(NS_LITERAL_STRING("Messages"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// count the number of messages in this folder. it sucks that we have to iterate through the folder
|
||||
// but XPCOM doesn't give us any way to just get the file count, unfortunately. :-(
|
||||
nsCOMPtr<nsISimpleEnumerator> dirEnumerator;
|
||||
messagesFolder->GetDirectoryEntries(getter_AddRefs(dirEnumerator));
|
||||
if (dirEnumerator) {
|
||||
bool hasMore = false;
|
||||
while (NS_SUCCEEDED(dirEnumerator->HasMoreElements(&hasMore)) && hasMore) {
|
||||
nsCOMPtr<nsISupports> rawSupports;
|
||||
dirEnumerator->GetNext(getter_AddRefs(rawSupports));
|
||||
if (!rawSupports)
|
||||
continue;
|
||||
|
||||
nsCOMPtr<nsIFile> file(do_QueryInterface(rawSupports));
|
||||
if (file) {
|
||||
bool isFile = false;
|
||||
file->IsFile(&isFile);
|
||||
if (isFile)
|
||||
numMessages++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
desc->SetSize(numMessages);
|
||||
desc->SetDisplayName(folderName.get());
|
||||
desc->SetDepth(mCurDepth);
|
||||
|
||||
IMPORT_LOG3("Will import %s with approx %d messages, depth is %d", NS_ConvertUTF16toUTF8(folderName).get(), numMessages, mCurDepth);
|
||||
|
||||
// XXX: this is silly. there's no setter for the mailbox descriptor's file, so we need to get it, and then modify it.
|
||||
nsCOMPtr<nsIFile> mailboxDescFile;
|
||||
rv = desc->GetFile(getter_AddRefs(mailboxDescFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mailboxDescFile)
|
||||
mailboxDescFile->InitWithFile(aFolder);
|
||||
|
||||
// add this mailbox descriptor to the list
|
||||
aMailboxDescs->AppendElement(desc, false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Starts looking for .mbox dirs in the specified dir. The .mbox dirs contain messages and can be considered leafs in a tree of
|
||||
// nested mailboxes (subfolders).
|
||||
//
|
||||
// If a mailbox has sub-mailboxes, they are contained in a sibling folder with the same name without the ".mbox" part.
|
||||
// example:
|
||||
// MyParentMailbox.mbox/
|
||||
// MyParentMailbox/
|
||||
// MyChildMailbox.mbox/
|
||||
// MyOtherChildMailbox.mbox/
|
||||
//
|
||||
nsresult nsAppleMailImportMail::FindMboxDirs(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFolder);
|
||||
NS_ENSURE_ARG_POINTER(aMailboxDescs);
|
||||
NS_ENSURE_ARG_POINTER(aImportService);
|
||||
|
||||
// make sure this is a directory.
|
||||
bool isDir = false;
|
||||
if (NS_FAILED(aFolder->IsDirectory(&isDir)) || !isDir)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// iterate through the folder contents
|
||||
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
|
||||
nsresult rv = aFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
|
||||
if (NS_FAILED(rv) || !directoryEnumerator)
|
||||
return rv;
|
||||
|
||||
bool hasMore = false;
|
||||
while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) {
|
||||
|
||||
// get the next file entry
|
||||
nsCOMPtr<nsIFile> currentEntry;
|
||||
{
|
||||
nsCOMPtr<nsISupports> rawSupports;
|
||||
directoryEnumerator->GetNext(getter_AddRefs(rawSupports));
|
||||
if (!rawSupports)
|
||||
continue;
|
||||
currentEntry = do_QueryInterface(rawSupports);
|
||||
if (!currentEntry)
|
||||
continue;
|
||||
}
|
||||
|
||||
// we only care about directories...
|
||||
if (NS_FAILED(currentEntry->IsDirectory(&isDir)) || !isDir)
|
||||
continue;
|
||||
|
||||
// now find out if this is a .mbox dir
|
||||
nsAutoString currentFolderName;
|
||||
if (NS_SUCCEEDED(currentEntry->GetLeafName(currentFolderName)) &&
|
||||
(StringEndsWith(currentFolderName, NS_LITERAL_STRING(POP_MBOX_SUFFIX)) ||
|
||||
StringEndsWith(currentFolderName, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX)))) {
|
||||
IMPORT_LOG1("Adding .mbox dir: %s", NS_ConvertUTF16toUTF8(currentFolderName).get());
|
||||
|
||||
// add this .mbox
|
||||
rv = AddMboxDir(currentEntry, aMailboxDescs, aImportService);
|
||||
if (NS_FAILED(rv)) {
|
||||
IMPORT_LOG1("Couldn't add .mbox for import: %s ... continuing anyway", NS_ConvertUTF16toUTF8(currentFolderName).get());
|
||||
continue;
|
||||
}
|
||||
|
||||
// see if this .mbox dir has any sub-mailboxes
|
||||
nsAutoString siblingMailboxDirPath;
|
||||
currentEntry->GetPath(siblingMailboxDirPath);
|
||||
|
||||
// cut off suffix
|
||||
if (StringEndsWith(siblingMailboxDirPath, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX)))
|
||||
siblingMailboxDirPath.SetLength(siblingMailboxDirPath.Length()-9);
|
||||
else if (StringEndsWith(siblingMailboxDirPath, NS_LITERAL_STRING(POP_MBOX_SUFFIX)))
|
||||
siblingMailboxDirPath.SetLength(siblingMailboxDirPath.Length()-5);
|
||||
|
||||
IMPORT_LOG1("trying to locate a '%s'", NS_ConvertUTF16toUTF8(siblingMailboxDirPath).get());
|
||||
nsCOMPtr<nsIFile> siblingMailboxDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
rv = siblingMailboxDir->InitWithPath(siblingMailboxDirPath);
|
||||
bool reallyExists = false;
|
||||
siblingMailboxDir->Exists(&reallyExists);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && reallyExists) {
|
||||
IMPORT_LOG1("Found what looks like an .mbox container: %s", NS_ConvertUTF16toUTF8(currentFolderName).get());
|
||||
|
||||
// traverse this folder for other .mboxes
|
||||
mCurDepth++;
|
||||
FindMboxDirs(siblingMailboxDir, aMailboxDescs, aImportService);
|
||||
mCurDepth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAppleMailImportMail::ImportMailbox(nsIImportMailboxDescriptor *aMailbox,
|
||||
nsIMsgFolder *aDstFolder,
|
||||
char16_t **aErrorLog,
|
||||
char16_t **aSuccessLog, bool *aFatalError)
|
||||
{
|
||||
nsAutoString errorLog, successLog;
|
||||
|
||||
// reset progress
|
||||
mProgress = 0;
|
||||
|
||||
nsAutoString mailboxName;
|
||||
aMailbox->GetDisplayName(getter_Copies(mailboxName));
|
||||
|
||||
nsCOMPtr<nsIFile> mboxFolder;
|
||||
nsresult rv = aMailbox->GetFile(getter_AddRefs(mboxFolder));
|
||||
if (NS_FAILED(rv) || !mboxFolder) {
|
||||
ReportStatus(u"ApplemailImportMailboxConverterror", mailboxName, errorLog);
|
||||
SetLogs(successLog, errorLog, aSuccessLog, aErrorLog);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// if we're an account mailbox, nothing do. if we're a real mbox
|
||||
// then we've got some messages to import!
|
||||
uint32_t mailboxIdentifier;
|
||||
aMailbox->GetIdentifier(&mailboxIdentifier);
|
||||
|
||||
if (mailboxIdentifier != kAccountMailboxID) {
|
||||
// move to the .mbox's Messages folder
|
||||
nsCOMPtr<nsIFile> messagesFolder;
|
||||
mboxFolder->Clone(getter_AddRefs(messagesFolder));
|
||||
rv = messagesFolder->Append(NS_LITERAL_STRING("Messages"));
|
||||
if (NS_FAILED(rv)) {
|
||||
// even if there are no messages, it might still be a valid mailbox, or even
|
||||
// a parent for other mailboxes.
|
||||
//
|
||||
// just indicate that we're done, using the same number that we used to estimate
|
||||
// number of messages earlier.
|
||||
uint32_t finalSize;
|
||||
aMailbox->GetSize(&finalSize);
|
||||
mProgress = finalSize;
|
||||
|
||||
// report that we successfully imported this mailbox
|
||||
ReportStatus(u"ApplemailImportMailboxSuccess", mailboxName, successLog);
|
||||
SetLogs(successLog, errorLog, aSuccessLog, aErrorLog);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// let's import the messages!
|
||||
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
|
||||
rv = messagesFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
|
||||
if (NS_FAILED(rv)) {
|
||||
ReportStatus(u"ApplemailImportMailboxConvertError", mailboxName, errorLog);
|
||||
SetLogs(successLog, errorLog, aSuccessLog, aErrorLog);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// prepare an outstream to the destination file
|
||||
nsCOMPtr<nsIMsgPluggableStore> msgStore;
|
||||
rv = aDstFolder->GetMsgStore(getter_AddRefs(msgStore));
|
||||
if (!msgStore || NS_FAILED(rv)) {
|
||||
ReportStatus(u"ApplemailImportMailboxConverterror", mailboxName, errorLog);
|
||||
SetLogs(successLog, errorLog, aSuccessLog, aErrorLog);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool hasMore = false;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
|
||||
while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) {
|
||||
// get the next file entry
|
||||
nsCOMPtr<nsIFile> currentEntry;
|
||||
{
|
||||
nsCOMPtr<nsISupports> rawSupports;
|
||||
directoryEnumerator->GetNext(getter_AddRefs(rawSupports));
|
||||
if (!rawSupports)
|
||||
continue;
|
||||
currentEntry = do_QueryInterface(rawSupports);
|
||||
if (!currentEntry)
|
||||
continue;
|
||||
}
|
||||
|
||||
// make sure it's an .emlx file
|
||||
bool isFile = false;
|
||||
currentEntry->IsFile(&isFile);
|
||||
if (!isFile)
|
||||
continue;
|
||||
|
||||
nsAutoString leafName;
|
||||
currentEntry->GetLeafName(leafName);
|
||||
if (!StringEndsWith(leafName, NS_LITERAL_STRING(".emlx")))
|
||||
continue;
|
||||
|
||||
nsCOMPtr<nsIMsgDBHdr> msgHdr;
|
||||
bool reusable;
|
||||
rv = msgStore->GetNewMsgOutputStream(aDstFolder, getter_AddRefs(msgHdr),
|
||||
&reusable,
|
||||
getter_AddRefs(outStream));
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// add the data to the mbox stream
|
||||
if (NS_SUCCEEDED(nsEmlxHelperUtils::AddEmlxMessageToStream(currentEntry, outStream))) {
|
||||
mProgress++;
|
||||
msgStore->FinishNewMessage(outStream, msgHdr);
|
||||
}
|
||||
else {
|
||||
msgStore->DiscardNewMessage(outStream, msgHdr);
|
||||
break;
|
||||
}
|
||||
if (!reusable)
|
||||
outStream->Close();
|
||||
}
|
||||
if (outStream)
|
||||
outStream->Close();
|
||||
}
|
||||
// just indicate that we're done, using the same number that we used to estimate
|
||||
// number of messages earlier.
|
||||
uint32_t finalSize;
|
||||
aMailbox->GetSize(&finalSize);
|
||||
mProgress = finalSize;
|
||||
|
||||
// report that we successfully imported this mailbox
|
||||
ReportStatus(u"ApplemailImportMailboxSuccess", mailboxName, successLog);
|
||||
SetLogs(successLog, errorLog, aSuccessLog, aErrorLog);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsAppleMailImportMail::ReportStatus(const char16_t* aErrorName, nsString &aName,
|
||||
nsAString &aStream)
|
||||
{
|
||||
// get (and format, if needed) the error string from the bundle
|
||||
nsAutoString outString;
|
||||
const char16_t *fmt = { aName.get() };
|
||||
nsresult rv = mBundle->FormatStringFromName(aErrorName, &fmt, 1, getter_Copies(outString));
|
||||
// write it out the stream
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aStream.Append(outString);
|
||||
aStream.Append(char16_t('\n'));
|
||||
}
|
||||
}
|
||||
|
||||
void nsAppleMailImportMail::SetLogs(const nsAString &aSuccess, const nsAString &aError, char16_t **aOutSuccess, char16_t **aOutError)
|
||||
{
|
||||
if (aOutError && !*aOutError)
|
||||
*aOutError = ToNewUnicode(aError);
|
||||
if (aOutSuccess && !*aOutSuccess)
|
||||
*aOutSuccess = ToNewUnicode(aSuccess);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleMailImportMail::GetImportProgress(uint32_t *aDoneSoFar)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDoneSoFar);
|
||||
*aDoneSoFar = mProgress;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleMailImportMail::TranslateFolderName(const nsAString &aFolderName, nsAString &aResult)
|
||||
{
|
||||
aResult = aFolderName;
|
||||
return NS_OK;
|
||||
}
|
||||
78
mailnews/import/applemail/src/nsAppleMailImport.h
Normal file
78
mailnews/import/applemail/src/nsAppleMailImport.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAppleMailImport_h___
|
||||
#define nsAppleMailImport_h___
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsIImportModule.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIImportMail.h"
|
||||
|
||||
// logging facilities
|
||||
extern PRLogModuleInfo *APPLEMAILLOGMODULE;
|
||||
|
||||
#define IMPORT_LOG0(x) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x))
|
||||
#define IMPORT_LOG1(x, y) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x, y))
|
||||
#define IMPORT_LOG2(x, y, z) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x, y, z))
|
||||
#define IMPORT_LOG3(a, b, c, d) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (a, b, c, d))
|
||||
|
||||
#define NS_APPLEMAILIMPL_CID \
|
||||
{ 0x9117a1ea, 0xe012, 0x43b5, { 0xa0, 0x20, 0xcb, 0x8a, 0x66, 0xcc, 0x09, 0xe1 } }
|
||||
|
||||
#define NS_APPLEMAILIMPORT_CID \
|
||||
{ 0x6d3f101c, 0x70ec, 0x4e04, { 0xb6, 0x8d, 0x99, 0x08, 0xd1, 0xae, 0xdd, 0xf3 } }
|
||||
|
||||
#define NS_APPLEMAILIMPL_CONTRACTID "@mozilla.org/import/import-appleMailImpl;1"
|
||||
|
||||
#define kAppleMailSupportsString "mail"
|
||||
|
||||
class nsIImportService;
|
||||
class nsIMutableArray;
|
||||
|
||||
class nsAppleMailImportModule : public nsIImportModule
|
||||
{
|
||||
public:
|
||||
|
||||
nsAppleMailImportModule();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMPORTMODULE
|
||||
|
||||
private:
|
||||
virtual ~nsAppleMailImportModule();
|
||||
|
||||
nsCOMPtr<nsIStringBundle> mBundle;
|
||||
};
|
||||
|
||||
class nsAppleMailImportMail : public nsIImportMail
|
||||
{
|
||||
public:
|
||||
|
||||
nsAppleMailImportMail();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIMPORTMAIL
|
||||
|
||||
nsresult Initialize();
|
||||
|
||||
private:
|
||||
virtual ~nsAppleMailImportMail();
|
||||
|
||||
void FindAccountMailDirs(nsIFile *aRoot, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService);
|
||||
nsresult FindMboxDirs(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService);
|
||||
nsresult AddMboxDir(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService);
|
||||
|
||||
// aInfoString is the format to a "foo %s" string. It may be NULL if the error string needs no such format.
|
||||
void ReportStatus(const char16_t* aErrorName, nsString &aName, nsAString &aStream);
|
||||
static void SetLogs(const nsAString& success, const nsAString& error, char16_t **aOutErrorLog, char16_t **aSuccessLog);
|
||||
|
||||
nsCOMPtr<nsIStringBundle> mBundle;
|
||||
uint32_t mProgress;
|
||||
uint16_t mCurDepth;
|
||||
};
|
||||
|
||||
#endif /* nsAppleMailImport_h___ */
|
||||
55
mailnews/import/applemail/src/nsEmlxHelperUtils.h
Normal file
55
mailnews/import/applemail/src/nsEmlxHelperUtils.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsEmlxHelperUtils_h___
|
||||
#define nsEmlxHelperUtils_h___
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
class nsIOutputStream;
|
||||
class nsIFile;
|
||||
|
||||
class nsEmlxHelperUtils {
|
||||
/* All emlx messages have a "flags" number in the metadata.
|
||||
These are the masks to decode that, found via http://jwz.livejournal.com/505711.html */
|
||||
enum EmlxMetadataMask {
|
||||
kRead = 1 << 0, // read
|
||||
// 1 << 1, // deleted
|
||||
kAnswered = 1 << 2, // answered
|
||||
// 1 << 3, // encrypted
|
||||
kFlagged = 1 << 4, // flagged
|
||||
// 1 << 5, // recent
|
||||
// 1 << 6, // draft
|
||||
// 1 << 7, // initial (no longer used)
|
||||
kForwarded = 1 << 8, // forwarded
|
||||
// 1 << 9, // redirected
|
||||
// 3F << 10, // attachment count (6 bits)
|
||||
// 7F << 16, // priority level (7 bits)
|
||||
// 1 << 23, // signed
|
||||
// 1 << 24, // is junk
|
||||
// 1 << 25, // is not junk
|
||||
// 1 << 26, // font size delta 7 (3 bits)
|
||||
// 1 << 29, // junk mail level recorded
|
||||
// 1 << 30, // highlight text in toc
|
||||
// 1 << 31 // (unused)
|
||||
};
|
||||
|
||||
// This method will scan the raw EMLX message buffer for "dangerous" so-called "From-lines" that we need to escape.
|
||||
// If it needs to modify any lines, it will return a non-NULL aOutBuffer. If aOutBuffer is NULL, no modification needed
|
||||
// to be made.
|
||||
static nsresult ConvertToMboxRD(const char *aMessageBufferStart, const char *aMessageBufferEnd, nsCString &aOutBuffer);
|
||||
|
||||
// returns an int representing the X-Mozilla-Status flags set (e.g. "read", "flagged") converted from EMLX flags.
|
||||
static nsresult ConvertToMozillaStatusFlags(const char *aXMLBufferStart, const char *aXMLBufferEnd, uint32_t *aMozillaStatusFlags);
|
||||
|
||||
public:
|
||||
|
||||
// add an .emlx message to the mbox output
|
||||
static nsresult AddEmlxMessageToStream(nsIFile *aEmlxFile, nsIOutputStream *aOutoutStream);
|
||||
|
||||
};
|
||||
|
||||
#endif // nsEmlxHelperUtils_h___
|
||||
240
mailnews/import/applemail/src/nsEmlxHelperUtils.mm
Normal file
240
mailnews/import/applemail/src/nsEmlxHelperUtils.mm
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsEmlxHelperUtils.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIBufferedStreams.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsMsgMessageFlags.h"
|
||||
#include "nsMsgLocalFolderHdrs.h"
|
||||
#include "msgCore.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAppleMailImport.h"
|
||||
#include "prprf.h"
|
||||
#include "nsIFile.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
nsresult nsEmlxHelperUtils::ConvertToMozillaStatusFlags(const char *aXMLBufferStart,
|
||||
const char *aXMLBufferEnd,
|
||||
uint32_t *aMozillaStatusFlags)
|
||||
{
|
||||
// create a NSData wrapper around the buffer, so we can use the Cocoa call below
|
||||
NSData *metadata =
|
||||
[[[NSData alloc] initWithBytesNoCopy:(void *)aXMLBufferStart length:(aXMLBufferEnd-aXMLBufferStart) freeWhenDone:NO] autorelease];
|
||||
|
||||
// get the XML data as a dictionary
|
||||
NSPropertyListFormat format;
|
||||
id plist = [NSPropertyListSerialization propertyListWithData:metadata
|
||||
options:NSPropertyListImmutable
|
||||
format:&format
|
||||
error:NULL];
|
||||
|
||||
if (!plist)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// find the <flags>...</flags> value and convert to int
|
||||
const uint32_t emlxMessageFlags = [[(NSDictionary *)plist objectForKey:@"flags"] intValue];
|
||||
|
||||
if (emlxMessageFlags == 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (emlxMessageFlags & nsEmlxHelperUtils::kRead)
|
||||
*aMozillaStatusFlags |= nsMsgMessageFlags::Read;
|
||||
if (emlxMessageFlags & nsEmlxHelperUtils::kForwarded)
|
||||
*aMozillaStatusFlags |= nsMsgMessageFlags::Forwarded;
|
||||
if (emlxMessageFlags & nsEmlxHelperUtils::kAnswered)
|
||||
*aMozillaStatusFlags |= nsMsgMessageFlags::Replied;
|
||||
if (emlxMessageFlags & nsEmlxHelperUtils::kFlagged)
|
||||
*aMozillaStatusFlags |= nsMsgMessageFlags::Marked;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsEmlxHelperUtils::ConvertToMboxRD(const char *aMessageBufferStart, const char *aMessageBufferEnd, nsCString &aOutBuffer)
|
||||
{
|
||||
nsTArray<const char *> foundFromLines;
|
||||
|
||||
const char *cur = aMessageBufferStart;
|
||||
while (cur < aMessageBufferEnd) {
|
||||
|
||||
const char *foundFromStr = strnstr(cur, "From ", aMessageBufferEnd-cur);
|
||||
|
||||
if (foundFromStr) {
|
||||
// skip all prepending '>' chars
|
||||
const char *fromLineStart = foundFromStr;
|
||||
while (fromLineStart-- >= aMessageBufferStart) {
|
||||
if (*fromLineStart == '\n' || fromLineStart == aMessageBufferStart) {
|
||||
if (fromLineStart > aMessageBufferStart)
|
||||
fromLineStart++;
|
||||
foundFromLines.AppendElement(fromLineStart);
|
||||
break;
|
||||
}
|
||||
else if (*fromLineStart != '>')
|
||||
break;
|
||||
}
|
||||
|
||||
// advance past the last found From string.
|
||||
cur = foundFromStr + 5;
|
||||
|
||||
// look for more From lines.
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// go through foundFromLines
|
||||
if (foundFromLines.Length()) {
|
||||
|
||||
const char *chunkStart = aMessageBufferStart;
|
||||
for (unsigned i=0; i<foundFromLines.Length(); ++i) {
|
||||
aOutBuffer.Append(chunkStart, (foundFromLines[i]-chunkStart));
|
||||
aOutBuffer.Append(NS_LITERAL_CSTRING(">"));
|
||||
|
||||
chunkStart = foundFromLines[i];
|
||||
}
|
||||
aOutBuffer.Append(chunkStart, (aMessageBufferEnd - chunkStart));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsEmlxHelperUtils::AddEmlxMessageToStream(nsIFile *aMessage, nsIOutputStream *aOut)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
// needed to be sure autoreleased objects are released too, which they might not
|
||||
// in a C++ environment where the main event loop has no autorelease pool (e.g on a XPCOM thread)
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoCString path;
|
||||
aMessage->GetNativePath(path);
|
||||
|
||||
NSData *data = [NSData dataWithContentsOfFile:[NSString stringWithUTF8String:path.get()]];
|
||||
if (!data) {
|
||||
[pool release];
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char *startOfMessageData = NULL;
|
||||
uint32_t actualBytesWritten = 0;
|
||||
|
||||
// The anatomy of an EMLX file:
|
||||
//
|
||||
// -------------------------------
|
||||
// < A number describing how many bytes ahead there is message data >
|
||||
// < Message data >
|
||||
// < XML metadata for this message >
|
||||
// -------------------------------
|
||||
|
||||
// read the first line of the emlx file, which is a number of how many bytes ahead the actual
|
||||
// message data is.
|
||||
uint64_t numberOfBytesToRead = strtol((char *)[data bytes], &startOfMessageData, 10);
|
||||
if (numberOfBytesToRead <= 0 || !startOfMessageData) {
|
||||
[pool release];
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// skip whitespace
|
||||
while (*startOfMessageData == ' ' ||
|
||||
*startOfMessageData == '\n' ||
|
||||
*startOfMessageData == '\r' ||
|
||||
*startOfMessageData == '\t')
|
||||
++startOfMessageData;
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(kBogusFromLine, "From \n");
|
||||
NS_NAMED_LITERAL_CSTRING(kEndOfMessage, "\n\n");
|
||||
|
||||
// write the bogus "From " line which is a magic separator in the mbox format
|
||||
rv = aOut->Write(kBogusFromLine.get(), kBogusFromLine.Length(), &actualBytesWritten);
|
||||
if (NS_FAILED(rv)) {
|
||||
[pool release];
|
||||
return rv;
|
||||
}
|
||||
|
||||
// now read the XML metadata, so we can extract info like which flags (read? replied? flagged? etc) this message has.
|
||||
const char *startOfXMLMetadata = startOfMessageData + numberOfBytesToRead;
|
||||
const char *endOfXMLMetadata = (char *)[data bytes] + [data length];
|
||||
|
||||
uint32_t x_mozilla_flags = 0;
|
||||
ConvertToMozillaStatusFlags(startOfXMLMetadata, endOfXMLMetadata, &x_mozilla_flags);
|
||||
|
||||
// write the X-Mozilla-Status header according to which flags we've gathered above.
|
||||
uint32_t dummyRv;
|
||||
nsAutoCString buf(PR_smprintf(X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, x_mozilla_flags));
|
||||
NS_ASSERTION(!buf.IsEmpty(), "printf error with X-Mozilla-Status header");
|
||||
if (buf.IsEmpty()) {
|
||||
[pool release];
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = aOut->Write(buf.get(), buf.Length(), &dummyRv);
|
||||
if (NS_FAILED(rv)) {
|
||||
[pool release];
|
||||
return rv;
|
||||
}
|
||||
|
||||
// write out X-Mozilla-Keywords header as well to reserve some space for it
|
||||
// in the mbox file.
|
||||
rv = aOut->Write(X_MOZILLA_KEYWORDS, X_MOZILLA_KEYWORDS_LEN, &dummyRv);
|
||||
if (NS_FAILED(rv)) {
|
||||
[pool release];
|
||||
return rv;
|
||||
}
|
||||
|
||||
// write out empty X-Mozilla_status2 header
|
||||
buf.Adopt(PR_smprintf(X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, 0));
|
||||
NS_ASSERTION(!buf.IsEmpty(), "printf error with X-Mozilla-Status2 header");
|
||||
if (buf.IsEmpty()) {
|
||||
[pool release];
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = aOut->Write(buf.get(), buf.Length(), &dummyRv);
|
||||
if (NS_FAILED(rv)) {
|
||||
[pool release];
|
||||
return rv;
|
||||
}
|
||||
|
||||
// do any conversion needed for the mbox data to be valid mboxrd.
|
||||
nsCString convertedData;
|
||||
rv = ConvertToMboxRD(startOfMessageData, (startOfMessageData + numberOfBytesToRead), convertedData);
|
||||
if (NS_FAILED(rv)) {
|
||||
[pool release];
|
||||
return rv;
|
||||
}
|
||||
|
||||
// write the actual message data.
|
||||
if (convertedData.IsEmpty())
|
||||
rv = aOut->Write(startOfMessageData, (uint32_t)numberOfBytesToRead, &actualBytesWritten);
|
||||
else {
|
||||
IMPORT_LOG1("Escaped From-lines in %s!", path.get());
|
||||
rv = aOut->Write(convertedData.get(), convertedData.Length(), &actualBytesWritten);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
[pool release];
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ASSERTION(actualBytesWritten == (convertedData.IsEmpty() ? numberOfBytesToRead : convertedData.Length()),
|
||||
"Didn't write as many bytes as expected for .emlx file?");
|
||||
|
||||
// add newlines to denote the end of this message in the mbox
|
||||
rv = aOut->Write(kEndOfMessage.get(), kEndOfMessage.Length(), &actualBytesWritten);
|
||||
|
||||
[pool release];
|
||||
|
||||
return rv;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
|
@ -35,6 +35,13 @@ LOCAL_INCLUDES += [
|
|||
'../vcard/src',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
LOCAL_INCLUDES += [
|
||||
'../applemail/src',
|
||||
]
|
||||
OS_LIBS += CONFIG['TK_LIBS']
|
||||
OS_LIBS += ['-framework Cocoa']
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
LOCAL_INCLUDES += [
|
||||
]
|
||||
|
|
|
|||
|
|
@ -32,6 +32,16 @@ NS_DEFINE_NAMED_CID(NS_TEXTIMPORT_CID);
|
|||
|
||||
NS_DEFINE_NAMED_CID(NS_VCARDIMPORT_CID);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Apple Mail import Include Files
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined(XP_MACOSX)
|
||||
#include "nsAppleMailImport.h"
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_APPLEMAILIMPORT_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_APPLEMAILIMPL_CID);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// outlook import Include Files
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -78,6 +88,14 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextImport)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsVCardImport)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// apple mail import factories
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined(XP_MACOSX)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAppleMailImportModule)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAppleMailImportMail, Initialize)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// outlook import factories
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -107,6 +125,9 @@ static const mozilla::Module::CategoryEntry kMailNewsImportCategories[] = {
|
|||
#ifdef MOZ_MAPI_SUPPORT
|
||||
{ "mailnewsimport", "{1DB469A0-8B00-11d3-A206-00A0CC26DA63}", kOutlookSupportsString },
|
||||
#endif
|
||||
#endif
|
||||
#if defined(XP_MACOSX)
|
||||
{ "mailnewsimport", "{6d3f101c-70ec-4e04-b68d-9908d1aeddf3}", kAppleMailSupportsString },
|
||||
#endif
|
||||
{ NULL }
|
||||
};
|
||||
|
|
@ -116,6 +137,11 @@ const mozilla::Module::CIDEntry kMailNewsImportCIDs[] = {
|
|||
{ &kNS_IMPORTMIMEENCODE_CID, false, NULL, nsIImportMimeEncodeImplConstructor },
|
||||
{ &kNS_TEXTIMPORT_CID, false, NULL, nsTextImportConstructor },
|
||||
{ &kNS_VCARDIMPORT_CID, false, NULL, nsVCardImportConstructor },
|
||||
#if defined(XP_MACOSX)
|
||||
{ &kNS_APPLEMAILIMPORT_CID, false, NULL, nsAppleMailImportModuleConstructor },
|
||||
{ &kNS_APPLEMAILIMPL_CID, false, NULL, nsAppleMailImportMailConstructor },
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
{ &kNS_OEIMPORT_CID, false, NULL, nsOEImportConstructor },
|
||||
{ &kNS_WMIMPORT_CID, false, NULL, nsWMImportConstructor },
|
||||
|
|
@ -132,6 +158,11 @@ const mozilla::Module::ContractIDEntry kMailNewsImportContracts[] = {
|
|||
{ "@mozilla.org/import/import-mimeencode;1", &kNS_IMPORTMIMEENCODE_CID },
|
||||
{ "@mozilla.org/import/import-text;1", &kNS_TEXTIMPORT_CID },
|
||||
{ "@mozilla.org/import/import-vcard;1", &kNS_VCARDIMPORT_CID },
|
||||
#if defined(XP_MACOSX)
|
||||
{ "@mozilla.org/import/import-applemail;1", &kNS_APPLEMAILIMPORT_CID },
|
||||
{ NS_APPLEMAILIMPL_CONTRACTID, &kNS_APPLEMAILIMPL_CID },
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
{ "@mozilla.org/import/import-oe;1", &kNS_OEIMPORT_CID },
|
||||
{ "@mozilla.org/import/import-wm;1", &kNS_WMIMPORT_CID },
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@
|
|||
<window xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="OnLoadImportDialog()"
|
||||
#ifdef XP_MACOSX
|
||||
style="width: &window.macWidth; !important;"
|
||||
#else
|
||||
style="width: &window.width; !important;"
|
||||
#endif
|
||||
title="&importDialog.windowTitle;">
|
||||
|
||||
<stringbundle id="bundle_importMsgs" src="chrome://messenger/locale/importMsgs.properties"/>
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@ messenger.jar:
|
|||
content/messenger/dateFormat.js (base/content/dateFormat.js)
|
||||
content/messenger/shutdownWindow.xul (base/content/shutdownWindow.xul)
|
||||
content/messenger/shutdownWindow.js (base/content/shutdownWindow.js)
|
||||
#ifndef XP_MACOSX
|
||||
content/messenger/newmailalert.css (base/content/newmailalert.css)
|
||||
content/messenger/newmailalert.js (base/content/newmailalert.js)
|
||||
content/messenger/newmailalert.xul (base/content/newmailalert.xul)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -696,7 +696,11 @@ pref("mail.biff.alert.show_subject", true);
|
|||
pref("mail.biff.alert.show_sender", true);
|
||||
pref("mail.biff.alert.preview_length", 40);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
pref("mail.biff.play_sound", false);
|
||||
#else
|
||||
pref("mail.biff.play_sound", true);
|
||||
#endif
|
||||
// 0 == default system sound, 1 == user specified wav
|
||||
pref("mail.biff.play_sound.type", 0);
|
||||
// _moz_mailbeep is a magic key, for the default sound.
|
||||
|
|
@ -706,6 +710,8 @@ pref("mail.biff.show_alert", true);
|
|||
#ifdef XP_WIN
|
||||
pref("mail.biff.show_tray_icon", true);
|
||||
pref("mail.biff.show_balloon", false);
|
||||
#elifdef XP_MACOSX
|
||||
pref("mail.biff.animate_dock_icon", false);
|
||||
#elifdef XP_UNIX
|
||||
pref("mail.biff.use_system_alert", false);
|
||||
#endif
|
||||
|
|
@ -718,6 +724,13 @@ pref("mail.biff.add_interval_jitter", true);
|
|||
pref("mail.biff.on_new_window", true);
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// If true, the number used in the Mac OS X dock notification will be the
|
||||
// the number of "new" messages, as per the classic Thunderbird definition.
|
||||
// Defaults to false, which notifies about the number of unread messages.
|
||||
pref("mail.biff.use_new_count_in_mac_dock", false);
|
||||
#endif
|
||||
|
||||
// For feed account serverType=rss sound on biff; if true, mail.biff.play_sound.* settings are used.
|
||||
pref("mail.feed.play_sound", false);
|
||||
|
||||
|
|
@ -834,6 +847,15 @@ pref("ldap_2.servers.oe.description", "chrome://messenger/locale/addressbook/add
|
|||
pref("ldap_2.servers.oe.dirType", 3);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
pref("ldap_2.servers.osx.uri", "moz-abosxdirectory:///");
|
||||
pref("ldap_2.servers.osx.description", "chrome://messenger/locale/addressbook/addressBook.properties");
|
||||
pref("ldap_2.servers.osx.dirType", 3);
|
||||
pref("mail.notification.sound", "");
|
||||
pref("mail.notification.count.inbox_only", true);
|
||||
// Work around bug 482811 by disabling slow script warning for chrome scripts on Mac
|
||||
pref("dom.max_chrome_script_run_time", 0);
|
||||
#endif
|
||||
|
||||
// gtk2 (*nix) lacks transparent/translucent drag support (bug 376238), so we
|
||||
// want to disable it so people can see where they are dragging things.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
MimeDefClass(MimeExternalBody, MimeExternalBodyClass,
|
||||
mimeExternalBodyClass, &MIME_SUPERCLASS);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
extern MimeObjectClass mimeMultipartAppleDoubleClass;
|
||||
#endif
|
||||
|
||||
static int MimeExternalBody_initialize (MimeObject *);
|
||||
static void MimeExternalBody_finalize (MimeObject *);
|
||||
static int MimeExternalBody_parse_line (const char *, int32_t, MimeObject *);
|
||||
|
|
@ -248,6 +252,12 @@ MimeExternalBody_parse_eof (MimeObject *obj, bool abort_p)
|
|||
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
|
||||
if (status < 0) return status;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (obj->parent && mime_typep(obj->parent,
|
||||
(MimeObjectClass*) &mimeMultipartAppleDoubleClass))
|
||||
goto done;
|
||||
#endif /* XP_MACOSX */
|
||||
|
||||
if (!abort_p &&
|
||||
obj->output_p &&
|
||||
obj->options &&
|
||||
|
|
@ -415,6 +425,10 @@ FAIL:
|
|||
PR_FREEIF(subj);
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
done:
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,19 @@ MimeMultipartAppleDouble_parse_begin (MimeObject *obj)
|
|||
NS_ASSERTION(obj->options->state->first_data_written_p, "first data not written");
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (obj->options && obj->options->state)
|
||||
{
|
||||
// obj->options->state->separator_suppressed_p = true;
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* It would be nice to not showing the resource fork links
|
||||
* if we are displaying inline. But, there is no way we could
|
||||
* know ahead of time that we could display the data fork and
|
||||
* the data fork is always hidden on MAC platform.
|
||||
*/
|
||||
#endif
|
||||
/* If we're writing this object as HTML, then emit a link for the
|
||||
multipart/appledouble part (both links) that looks just like the
|
||||
links that MimeExternalObject emits for external leaf parts.
|
||||
|
|
@ -143,6 +156,10 @@ GOTTA STILL DO THIS FOR QUOTING!
|
|||
if (status < 0) return status;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
done:
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -159,8 +176,13 @@ MimeMultipartAppleDouble_output_child_p(MimeObject *obj, MimeObject *child)
|
|||
if (cont->nchildren >= 1 && cont->children[0] == child && child->content_type &&
|
||||
!PL_strcasecmp(child->content_type, APPLICATION_APPLEFILE))
|
||||
{
|
||||
/* Don't emit the resources fork. */
|
||||
#ifdef XP_MACOSX
|
||||
if (obj->output_p && obj->options && obj->options->write_html_p) //output HTML
|
||||
return false;
|
||||
#else
|
||||
/* if we are not on a Macintosh, don't emitte the resources fork at all. */
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
#include "nsMimeTypes.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
extern MimeObjectClass mimeMultipartAppleDoubleClass;
|
||||
#endif
|
||||
|
||||
#define MIME_SUPERCLASS mimeContainerClass
|
||||
MimeDefClass(MimeMultipart, MimeMultipartClass,
|
||||
mimeMultipartClass, &MIME_SUPERCLASS);
|
||||
|
|
@ -488,6 +492,19 @@ MimeMultipart_create_child(MimeObject *obj)
|
|||
{
|
||||
status = body->clazz->parse_begin(body);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
/* if we are saving an apple double attachment, we need to set correctly the conten type of the channel */
|
||||
if (mime_typep(obj, (MimeObjectClass *) &mimeMultipartAppleDoubleClass))
|
||||
{
|
||||
mime_stream_data *msd = (mime_stream_data *)body->options->stream_closure;
|
||||
if (!body->options->write_html_p && body->content_type && !PL_strcasecmp(body->content_type, APPLICATION_APPLEFILE))
|
||||
{
|
||||
if (msd && msd->channel)
|
||||
msd->channel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_APPLEFILE));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (status < 0) return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ DIRS += [
|
|||
'news',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
DIRS += [
|
||||
'import/applemail/src',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DIRS += [ 'import/becky/src' ]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue