summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/shell/nsMacShellService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/shell/nsMacShellService.cpp')
-rw-r--r--comm/mail/components/shell/nsMacShellService.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/comm/mail/components/shell/nsMacShellService.cpp b/comm/mail/components/shell/nsMacShellService.cpp
new file mode 100644
index 0000000000..383e3a2896
--- /dev/null
+++ b/comm/mail/components/shell/nsMacShellService.cpp
@@ -0,0 +1,156 @@
+/* -*- 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 "nsMacShellService.h"
+#include "nsCOMPtr.h"
+#include "nsIServiceManager.h"
+#include "nsIStringBundle.h"
+#include "nsIPromptService.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsString.h"
+#include "nsEmbedCID.h"
+
+// These Launch Services functions are undocumented. We're using them since
+// they're the only way to set the default opener for URLs
+extern "C" {
+// Returns the CFURL for application currently set as the default opener for
+// the given URL scheme. appURL must be released by the caller.
+extern OSStatus _LSCopyDefaultSchemeHandlerURL(CFStringRef scheme,
+ CFURLRef* appURL);
+extern OSStatus _LSSetDefaultSchemeHandlerURL(CFStringRef scheme,
+ CFURLRef appURL);
+extern OSStatus _LSSaveAndRefresh(void);
+}
+
+NS_IMPL_ISUPPORTS(nsMacShellService, nsIShellService, nsIToolkitShellService)
+
+nsMacShellService::nsMacShellService() : mCheckedThisSession(false) {}
+
+NS_IMETHODIMP
+nsMacShellService::IsDefaultClient(bool aStartupCheck, uint16_t aApps,
+ bool* aIsDefaultClient) {
+ *aIsDefaultClient = true;
+ if (aApps & nsIShellService::MAIL)
+ *aIsDefaultClient &= isDefaultHandlerForProtocol(CFSTR("mailto"));
+ if (aApps & nsIShellService::NEWS)
+ *aIsDefaultClient &= isDefaultHandlerForProtocol(CFSTR("news"));
+ if (aApps & nsIShellService::RSS)
+ *aIsDefaultClient &= isDefaultHandlerForProtocol(CFSTR("feed"));
+ if (aApps & nsIShellService::CALENDAR)
+ *aIsDefaultClient &= isDefaultHandlerForProtocol(CFSTR("webcal"));
+
+ // if this is the first mail window, maintain internal state that we've
+ // checked this session (so that subsequent window opens don't show the
+ // default client dialog.
+
+ if (aStartupCheck) mCheckedThisSession = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::SetDefaultClient(bool aForAllUsers, uint16_t aApps) {
+ nsresult rv = NS_OK;
+ if (aApps & nsIShellService::MAIL) {
+ rv = setAsDefaultHandlerForProtocol(CFSTR("mailto"));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = setAsDefaultHandlerForProtocol(CFSTR("mid"));
+ }
+ if (NS_SUCCEEDED(rv) && aApps & nsIShellService::NEWS)
+ rv = setAsDefaultHandlerForProtocol(CFSTR("news"));
+ if (NS_SUCCEEDED(rv) && aApps & nsIShellService::RSS)
+ rv = setAsDefaultHandlerForProtocol(CFSTR("feed"));
+ if (NS_SUCCEEDED(rv) && aApps & nsIShellService::CALENDAR) {
+ rv = setAsDefaultHandlerForProtocol(CFSTR("webcal"));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = setAsDefaultHandlerForProtocol(CFSTR("webcals"));
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsMacShellService::GetShouldCheckDefaultClient(bool* aResult) {
+ if (mCheckedThisSession) {
+ *aResult = false;
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ return prefs->GetBoolPref("mail.shell.checkDefaultClient", aResult);
+}
+
+NS_IMETHODIMP
+nsMacShellService::SetShouldCheckDefaultClient(bool aShouldCheck) {
+ nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ return prefs->SetBoolPref("mail.shell.checkDefaultClient", aShouldCheck);
+}
+
+bool nsMacShellService::isDefaultHandlerForProtocol(CFStringRef aScheme) {
+ bool isDefault = false;
+ // Since neither Launch Services nor Internet Config actually differ between
+ // bundles which have the same bundle identifier (That is, if we set our
+ // URL of our bundle as the default handler for the given protocol,
+ // Launch Service might return the URL of another thunderbird bundle as the
+ // default handler for that protocol), we are comparing the identifiers of the
+ // bundles rather than their URLs.
+
+ CFStringRef tbirdID = ::CFBundleGetIdentifier(CFBundleGetMainBundle());
+ if (!tbirdID) {
+ // CFBundleGetIdentifier is expected to return NULL only if the specified
+ // bundle doesn't have a bundle identifier in its dictionary. In this case,
+ // that means a failure, since our bundle does have an identifier.
+ return isDefault;
+ }
+
+ ::CFRetain(tbirdID);
+
+ // Get the default handler URL of the given protocol
+ CFURLRef defaultHandlerURL;
+ OSStatus err = ::_LSCopyDefaultSchemeHandlerURL(aScheme, &defaultHandlerURL);
+
+ if (err == noErr) {
+ // Get a reference to the bundle (based on its URL)
+ CFBundleRef defaultHandlerBundle =
+ ::CFBundleCreate(NULL, defaultHandlerURL);
+ if (defaultHandlerBundle) {
+ CFStringRef defaultHandlerID =
+ ::CFBundleGetIdentifier(defaultHandlerBundle);
+ if (defaultHandlerID) {
+ ::CFRetain(defaultHandlerID);
+ // and compare it to our bundle identifier
+ isDefault = ::CFStringCompare(tbirdID, defaultHandlerID, 0) ==
+ kCFCompareEqualTo;
+ ::CFRelease(defaultHandlerID);
+ } else {
+ // If the bundle doesn't have an identifier in its info property list,
+ // it's not our bundle.
+ isDefault = false;
+ }
+
+ ::CFRelease(defaultHandlerBundle);
+ }
+
+ ::CFRelease(defaultHandlerURL);
+ } else {
+ // If |_LSCopyDefaultSchemeHandlerURL| failed, there's no default
+ // handler for the given protocol
+ isDefault = false;
+ }
+
+ ::CFRelease(tbirdID);
+ return isDefault;
+}
+
+nsresult nsMacShellService::setAsDefaultHandlerForProtocol(
+ CFStringRef aScheme) {
+ CFURLRef tbirdURL = ::CFBundleCopyBundleURL(CFBundleGetMainBundle());
+
+ ::_LSSetDefaultSchemeHandlerURL(aScheme, tbirdURL);
+ ::_LSSaveAndRefresh();
+ ::CFRelease(tbirdURL);
+
+ return NS_OK;
+}