tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsMacShellService.cpp (11740B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "CocoaFileUtils.h"
      7 #include "nsDirectoryServiceDefs.h"
      8 #include "nsIImageLoadingContent.h"
      9 #include "mozilla/dom/Document.h"
     10 #include "nsComponentManagerUtils.h"
     11 #include "nsIContent.h"
     12 #include "nsICookieJarSettings.h"
     13 #include "nsIObserverService.h"
     14 #include "nsIWebBrowserPersist.h"
     15 #include "nsMacShellService.h"
     16 #include "nsIProperties.h"
     17 #include "nsServiceManagerUtils.h"
     18 #include "nsShellService.h"
     19 #include "nsString.h"
     20 #include "nsIDocShell.h"
     21 #include "nsILoadContext.h"
     22 #include "nsIPrefService.h"
     23 #include "mozilla/dom/Element.h"
     24 #include "mozilla/dom/ReferrerInfo.h"
     25 #include "DesktopBackgroundImage.h"
     26 
     27 #include <Carbon/Carbon.h>
     28 #include <CoreFoundation/CoreFoundation.h>
     29 #include <ApplicationServices/ApplicationServices.h>
     30 
     31 using mozilla::dom::Element;
     32 using mozilla::widget::SetDesktopImage;
     33 
     34 #define NETWORK_PREFPANE "/System/Library/PreferencePanes/Network.prefPane"_ns
     35 #define DESKTOP_PREFPANE \
     36  nsLiteralCString(      \
     37      "/System/Library/PreferencePanes/DesktopScreenEffectsPref.prefPane")
     38 
     39 #define SAFARI_BUNDLE_IDENTIFIER "com.apple.Safari"
     40 
     41 NS_IMPL_ISUPPORTS(nsMacShellService, nsIMacShellService, nsIShellService,
     42                  nsIToolkitShellService, nsIWebProgressListener)
     43 
     44 NS_IMETHODIMP
     45 nsMacShellService::IsDefaultBrowser(bool aForAllTypes,
     46                                    bool* aIsDefaultBrowser) {
     47  *aIsDefaultBrowser = false;
     48 
     49  CFStringRef firefoxID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
     50  if (!firefoxID) {
     51    // CFBundleGetIdentifier is expected to return nullptr only if the specified
     52    // bundle doesn't have a bundle identifier in its plist. In this case, that
     53    // means a failure, since our bundle does have an identifier.
     54    return NS_ERROR_FAILURE;
     55  }
     56 
     57  // Get the default http handler's bundle ID (or nullptr if it has not been
     58  // explicitly set)
     59  CFStringRef defaultBrowserID =
     60      ::LSCopyDefaultHandlerForURLScheme(CFSTR("http"));
     61  if (defaultBrowserID) {
     62    *aIsDefaultBrowser =
     63        ::CFStringCompare(firefoxID, defaultBrowserID, 0) == kCFCompareEqualTo;
     64    ::CFRelease(defaultBrowserID);
     65  }
     66 
     67  return NS_OK;
     68 }
     69 
     70 NS_IMETHODIMP
     71 nsMacShellService::SetDefaultBrowser(bool aForAllUsers) {
     72  // Note: We don't support aForAllUsers on Mac OS X.
     73 
     74  CFStringRef firefoxID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
     75  if (!firefoxID) {
     76    return NS_ERROR_FAILURE;
     77  }
     78 
     79  if (::LSSetDefaultHandlerForURLScheme(CFSTR("http"), firefoxID) != noErr) {
     80    return NS_ERROR_FAILURE;
     81  }
     82  if (::LSSetDefaultHandlerForURLScheme(CFSTR("https"), firefoxID) != noErr) {
     83    return NS_ERROR_FAILURE;
     84  }
     85 
     86  if (::LSSetDefaultRoleHandlerForContentType(kUTTypeHTML, kLSRolesAll,
     87                                              firefoxID) != noErr) {
     88    return NS_ERROR_FAILURE;
     89  }
     90 
     91  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
     92  if (prefs) {
     93    (void)prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
     94    // Reset the number of times the dialog should be shown
     95    // before it is silenced.
     96    (void)prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
     97  }
     98 
     99  return NS_OK;
    100 }
    101 
    102 NS_IMETHODIMP
    103 nsMacShellService::SetDesktopBackground(Element* aElement, int32_t aPosition,
    104                                        const nsACString& aImageName) {
    105  // Note: We don't support aPosition on OS X.
    106 
    107  // Get the image URI:
    108  nsresult rv;
    109  nsCOMPtr<nsIImageLoadingContent> imageContent =
    110      do_QueryInterface(aElement, &rv);
    111  NS_ENSURE_SUCCESS(rv, rv);
    112  nsCOMPtr<nsIURI> imageURI;
    113  rv = imageContent->GetCurrentURI(getter_AddRefs(imageURI));
    114  NS_ENSURE_SUCCESS(rv, rv);
    115 
    116  nsIURI* docURI = aElement->OwnerDoc()->GetDocumentURI();
    117  if (!docURI) return NS_ERROR_FAILURE;
    118 
    119  nsCOMPtr<nsIProperties> fileLocator(
    120      do_GetService("@mozilla.org/file/directory_service;1", &rv));
    121  NS_ENSURE_SUCCESS(rv, rv);
    122 
    123  // Get the current user's "Pictures" folder (That's ~/Pictures):
    124  fileLocator->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile),
    125                   getter_AddRefs(mBackgroundFile));
    126  if (!mBackgroundFile) return NS_ERROR_OUT_OF_MEMORY;
    127 
    128  nsAutoString fileNameUnicode;
    129  CopyUTF8toUTF16(aImageName, fileNameUnicode);
    130 
    131  // and add the imgage file name itself:
    132  mBackgroundFile->Append(fileNameUnicode);
    133 
    134  // Download the image; the desktop background will be set in OnStateChange()
    135  nsCOMPtr<nsIWebBrowserPersist> wbp(do_CreateInstance(
    136      "@mozilla.org/embedding/browser/nsWebBrowserPersist;1", &rv));
    137  NS_ENSURE_SUCCESS(rv, rv);
    138 
    139  uint32_t flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION |
    140                   nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES |
    141                   nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
    142 
    143  wbp->SetPersistFlags(flags);
    144  wbp->SetProgressListener(this);
    145 
    146  nsCOMPtr<nsILoadContext> loadContext;
    147  nsCOMPtr<nsISupports> container = aElement->OwnerDoc()->GetContainer();
    148  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
    149  if (docShell) {
    150    loadContext = do_QueryInterface(docShell);
    151  }
    152 
    153  auto referrerInfo =
    154      mozilla::MakeRefPtr<mozilla::dom::ReferrerInfo>(*aElement);
    155 
    156  nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
    157      aElement->OwnerDoc()->CookieJarSettings();
    158  return wbp->SaveURI(imageURI, aElement->NodePrincipal(), 0, referrerInfo,
    159                      cookieJarSettings, nullptr, nullptr, mBackgroundFile,
    160                      nsIContentPolicy::TYPE_IMAGE,
    161                      loadContext->UsePrivateBrowsing());
    162 }
    163 
    164 NS_IMETHODIMP
    165 nsMacShellService::OnProgressChange(nsIWebProgress* aWebProgress,
    166                                    nsIRequest* aRequest,
    167                                    int32_t aCurSelfProgress,
    168                                    int32_t aMaxSelfProgress,
    169                                    int32_t aCurTotalProgress,
    170                                    int32_t aMaxTotalProgress) {
    171  return NS_OK;
    172 }
    173 
    174 NS_IMETHODIMP
    175 nsMacShellService::OnLocationChange(nsIWebProgress* aWebProgress,
    176                                    nsIRequest* aRequest, nsIURI* aLocation,
    177                                    uint32_t aFlags) {
    178  return NS_OK;
    179 }
    180 
    181 NS_IMETHODIMP
    182 nsMacShellService::OnStatusChange(nsIWebProgress* aWebProgress,
    183                                  nsIRequest* aRequest, nsresult aStatus,
    184                                  const char16_t* aMessage) {
    185  return NS_OK;
    186 }
    187 
    188 NS_IMETHODIMP
    189 nsMacShellService::OnSecurityChange(nsIWebProgress* aWebProgress,
    190                                    nsIRequest* aRequest, uint32_t aState) {
    191  return NS_OK;
    192 }
    193 
    194 NS_IMETHODIMP
    195 nsMacShellService::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
    196                                          nsIRequest* aRequest,
    197                                          uint32_t aEvent) {
    198  return NS_OK;
    199 }
    200 
    201 NS_IMETHODIMP
    202 nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress,
    203                                 nsIRequest* aRequest, uint32_t aStateFlags,
    204                                 nsresult aStatus) {
    205  if (NS_SUCCEEDED(aStatus) && (aStateFlags & STATE_STOP) &&
    206      (aRequest == nullptr)) {
    207    nsCOMPtr<nsIObserverService> os(
    208        do_GetService("@mozilla.org/observer-service;1"));
    209    if (os)
    210      os->NotifyObservers(nullptr, "shell:desktop-background-changed", nullptr);
    211 
    212    bool exists = false;
    213    nsresult rv = mBackgroundFile->Exists(&exists);
    214    if (NS_FAILED(rv) || !exists) {
    215      return NS_OK;
    216    }
    217 
    218    SetDesktopImage(mBackgroundFile);
    219  }
    220 
    221  return NS_OK;
    222 }
    223 
    224 NS_IMETHODIMP
    225 nsMacShellService::ShowDesktopPreferences() {
    226  nsCOMPtr<nsIFile> lf;
    227  nsresult rv = NS_NewNativeLocalFile(DESKTOP_PREFPANE, getter_AddRefs(lf));
    228  NS_ENSURE_SUCCESS(rv, rv);
    229  bool exists;
    230  lf->Exists(&exists);
    231  if (!exists) return NS_ERROR_FILE_NOT_FOUND;
    232  return lf->Launch();
    233 }
    234 
    235 NS_IMETHODIMP
    236 nsMacShellService::GetDesktopBackgroundColor(uint32_t* aColor) {
    237  // This method and |SetDesktopBackgroundColor| has no meaning on Mac OS X.
    238  // The mac desktop preferences UI uses pictures for the few solid colors it
    239  // supports.
    240  return NS_ERROR_NOT_IMPLEMENTED;
    241 }
    242 
    243 NS_IMETHODIMP
    244 nsMacShellService::SetDesktopBackgroundColor(uint32_t aColor) {
    245  // This method and |GetDesktopBackgroundColor| has no meaning on Mac OS X.
    246  // The mac desktop preferences UI uses pictures for the few solid colors it
    247  // supports.
    248  return NS_ERROR_NOT_IMPLEMENTED;
    249 }
    250 
    251 NS_IMETHODIMP
    252 nsMacShellService::ShowSecurityPreferences(const nsACString& aPaneID) {
    253  nsresult rv = NS_ERROR_NOT_AVAILABLE;
    254 
    255  CFStringRef paneID = ::CFStringCreateWithBytes(
    256      kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aPaneID).get(),
    257      aPaneID.Length(), kCFStringEncodingUTF8, false);
    258 
    259  if (paneID) {
    260    CFStringRef format =
    261        CFSTR("x-apple.systempreferences:com.apple.preference.security?%@");
    262    if (format) {
    263      CFStringRef urlStr =
    264          CFStringCreateWithFormat(kCFAllocatorDefault, NULL, format, paneID);
    265      if (urlStr) {
    266        CFURLRef url = ::CFURLCreateWithString(NULL, urlStr, NULL);
    267        rv = CocoaFileUtils::OpenURL(url);
    268 
    269        ::CFRelease(urlStr);
    270      }
    271 
    272      ::CFRelease(format);
    273    }
    274 
    275    ::CFRelease(paneID);
    276  }
    277  return rv;
    278 }
    279 
    280 nsString ConvertCFStringToNSString(CFStringRef aSrc) {
    281  nsString aDest;
    282  auto len = ::CFStringGetLength(aSrc);
    283  aDest.SetLength(len);
    284  ::CFStringGetCharacters(aSrc, ::CFRangeMake(0, len),
    285                          (UniChar*)aDest.BeginWriting());
    286  return aDest;
    287 }
    288 
    289 NS_IMETHODIMP
    290 nsMacShellService::GetAvailableApplicationsForProtocol(
    291    const nsACString& protocol, nsTArray<nsTArray<nsString>>& aHandlerPaths) {
    292  class CFTypeRefAutoDeleter {
    293   public:
    294    explicit CFTypeRefAutoDeleter(CFTypeRef ref) : mRef(ref) {}
    295    ~CFTypeRefAutoDeleter() {
    296      if (mRef != NULL) ::CFRelease(mRef);
    297    }
    298 
    299   private:
    300    CFTypeRef mRef;
    301  };
    302 
    303  aHandlerPaths.Clear();
    304  nsCString protocolSep = protocol + "://"_ns;
    305  CFStringRef cfProtocol = ::CFStringCreateWithBytes(
    306      kCFAllocatorDefault, (const UInt8*)protocolSep.BeginReading(),
    307      protocolSep.Length(), kCFStringEncodingUTF8, false);
    308  CFTypeRefAutoDeleter cfProtocolAuto((CFTypeRef)cfProtocol);
    309  if (cfProtocol == NULL) {
    310    return NS_ERROR_ILLEGAL_VALUE;
    311  }
    312  CFURLRef protocolURL =
    313      ::CFURLCreateWithString(kCFAllocatorDefault, cfProtocol, NULL);
    314  CFTypeRefAutoDeleter cfProtocolURLAuto((CFTypeRef)protocolURL);
    315  if (protocolURL == NULL) {
    316    return NS_ERROR_MALFORMED_URI;
    317  }
    318  CFArrayRef appURLs = ::LSCopyApplicationURLsForURL(protocolURL, kLSRolesAll);
    319  CFTypeRefAutoDeleter cfAppURLsAuto((CFTypeRef)appURLs);
    320  if (appURLs == NULL) {
    321    return NS_ERROR_NOT_AVAILABLE;
    322  }
    323  for (CFIndex i = 0; i < ::CFArrayGetCount(appURLs); i++) {
    324    CFURLRef appURL = (CFURLRef)::CFArrayGetValueAtIndex(appURLs, i);
    325    CFBundleRef appBundle = ::CFBundleCreate(kCFAllocatorDefault, appURL);
    326    CFTypeRefAutoDeleter cfAppBundleAuto((CFTypeRef)appBundle);
    327    if (appBundle == NULL) {
    328      continue;
    329    }
    330    CFDictionaryRef appInfo = ::CFBundleGetInfoDictionary(appBundle);
    331    if (appInfo == NULL) {
    332      continue;
    333    }
    334    CFStringRef displayName =
    335        (CFStringRef)::CFDictionaryGetValue(appInfo, kCFBundleNameKey);
    336    if (displayName == NULL) {
    337      continue;
    338    }
    339    CFStringRef appPath = ::CFURLGetString(appURL);
    340    nsTArray<nsString> handlerPath = {ConvertCFStringToNSString(displayName),
    341                                      ConvertCFStringToNSString(appPath)};
    342    aHandlerPaths.AppendElement(handlerPath.Clone());
    343  }
    344  return NS_OK;
    345 }