summaryrefslogtreecommitdiff
path: root/mailnews
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2022-04-26 09:34:34 -0500
committerBrian Smith <brian@dbsoft.org>2022-04-26 10:19:00 -0500
commit378738aaa9924d0b95e2c57f27cbad2b2e644282 (patch)
tree34ce9c4ce3995576604fb4bc47d9405e661daf39 /mailnews
parent82f11ad8aaeff395629c3a3f72ece43712fd8e72 (diff)
downloaduxp-378738aaa9924d0b95e2c57f27cbad2b2e644282.tar.gz
Issue #1829 - Revert “Issue #1751 - Remove Mac code behind MOZ_WIDGET_TOOLKIT == 'cocoa’”
This reverts commit 1fe9c19305dadf2d5bcaa0e589fcd250389dfa8a.
Diffstat (limited to 'mailnews')
-rw-r--r--mailnews/base/ispdata/moz.build4
-rw-r--r--mailnews/base/src/moz.build2
-rw-r--r--mailnews/base/src/nsMessengerOSXIntegration.h63
-rw-r--r--mailnews/base/src/nsMessengerOSXIntegration.mm700
-rw-r--r--mailnews/build/moz.build4
-rw-r--r--mailnews/compose/src/moz.build10
-rw-r--r--mailnews/compose/src/nsMsgAppleCodes.h106
-rw-r--r--mailnews/compose/src/nsMsgAppleDouble.h207
-rw-r--r--mailnews/compose/src/nsMsgAppleDoubleEncode.cpp266
-rw-r--r--mailnews/compose/src/nsMsgAppleEncode.cpp703
-rw-r--r--mailnews/import/build/moz.build7
11 files changed, 2071 insertions, 1 deletions
diff --git a/mailnews/base/ispdata/moz.build b/mailnews/base/ispdata/moz.build
index 363c2ba0c2..7de5dc2e32 100644
--- a/mailnews/base/ispdata/moz.build
+++ b/mailnews/base/ispdata/moz.build
@@ -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. \ No newline at end of file
+# 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']
diff --git a/mailnews/base/src/moz.build b/mailnews/base/src/moz.build
index 65853daf96..91bf235c34 100644
--- a/mailnews/base/src/moz.build
+++ b/mailnews/base/src/moz.build
@@ -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',
diff --git a/mailnews/base/src/nsMessengerOSXIntegration.h b/mailnews/base/src/nsMessengerOSXIntegration.h
new file mode 100644
index 0000000000..91f42f2a2a
--- /dev/null
+++ b/mailnews/base/src/nsMessengerOSXIntegration.h
@@ -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
diff --git a/mailnews/base/src/nsMessengerOSXIntegration.mm b/mailnews/base/src/nsMessengerOSXIntegration.mm
new file mode 100644
index 0000000000..a38716e179
--- /dev/null
+++ b/mailnews/base/src/nsMessengerOSXIntegration.mm
@@ -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;
+}
diff --git a/mailnews/build/moz.build b/mailnews/build/moz.build
index 9561fd33d8..9620e8f3d4 100644
--- a/mailnews/build/moz.build
+++ b/mailnews/build/moz.build
@@ -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',
diff --git a/mailnews/compose/src/moz.build b/mailnews/compose/src/moz.build
index 831a0340f4..dcb9960a66 100644
--- a/mailnews/compose/src/moz.build
+++ b/mailnews/compose/src/moz.build
@@ -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',
diff --git a/mailnews/compose/src/nsMsgAppleCodes.h b/mailnews/compose/src/nsMsgAppleCodes.h
new file mode 100644
index 0000000000..d8ca2f327c
--- /dev/null
+++ b/mailnews/compose/src/nsMsgAppleCodes.h
@@ -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 */
diff --git a/mailnews/compose/src/nsMsgAppleDouble.h b/mailnews/compose/src/nsMsgAppleDouble.h
new file mode 100644
index 0000000000..f4ae934add
--- /dev/null
+++ b/mailnews/compose/src/nsMsgAppleDouble.h
@@ -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
diff --git a/mailnews/compose/src/nsMsgAppleDoubleEncode.cpp b/mailnews/compose/src/nsMsgAppleDoubleEncode.cpp
new file mode 100644
index 0000000000..4d71781233
--- /dev/null
+++ b/mailnews/compose/src/nsMsgAppleDoubleEncode.cpp
@@ -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;
+}
diff --git a/mailnews/compose/src/nsMsgAppleEncode.cpp b/mailnews/compose/src/nsMsgAppleEncode.cpp
new file mode 100644
index 0000000000..27e39a8cda
--- /dev/null
+++ b/mailnews/compose/src/nsMsgAppleEncode.cpp
@@ -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);
+}
diff --git a/mailnews/import/build/moz.build b/mailnews/import/build/moz.build
index 58814a6940..e8ac0751f5 100644
--- a/mailnews/import/build/moz.build
+++ b/mailnews/import/build/moz.build
@@ -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 += [
]