rename from browser/modules/AttributionCode.jsm
rename to browser/components/attribution/AttributionCode.jsm
--- a/browser/modules/AttributionCode.jsm
+++ b/browser/components/attribution/AttributionCode.jsm
@@ -7,22 +7,24 @@ var EXPORTED_SYMBOLS = ["AttributionCode
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
ChromeUtils.defineModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
const ATTR_CODE_MAX_LENGTH = 200;
const ATTR_CODE_KEYS_REGEX = /^source|medium|campaign|content$/;
const ATTR_CODE_VALUE_REGEX = /[a-zA-Z0-9_%\\-\\.\\(\\)]*/;
const ATTR_CODE_FIELD_SEPARATOR = "%26"; // URL-encoded &
const ATTR_CODE_KEY_VALUE_SEPARATOR = "%3D"; // URL-encoded =
+const ATTR_CODE_KEYS = ["source", "medium", "campaign", "content"];
let gCachedAttrData = null;
/**
* Returns an nsIFile for the file containing the attribution data.
*/
function getAttributionFile() {
let file = Services.dirsvc.get("LocalAppData", Ci.nsIFile);
@@ -60,35 +62,59 @@ function parseAttributionCode(code) {
}
var AttributionCode = {
/**
* Reads the attribution code, either from disk or a cached version.
* Returns a promise that fulfills with an object containing the parsed
* attribution data if the code could be read and is valid,
* or an empty object otherwise.
+ *
+ * On windows the attribution service converts utm_* keys, removing "utm_".
+ * On OSX the attributions are set directly on download and retain "utm_". We
+ * strip "utm_" while retrieving the params.
*/
getAttrDataAsync() {
return (async function() {
if (gCachedAttrData != null) {
return gCachedAttrData;
}
- let code = "";
- try {
- let bytes = await OS.File.read(getAttributionFile().path);
- let decoder = new TextDecoder();
- code = decoder.decode(bytes);
- } catch (ex) {
- // The attribution file may already have been deleted,
- // or it may have never been installed at all;
- // failure to open or read it isn't an error.
+ gCachedAttrData = {};
+ if (AppConstants.platform == "win") {
+ try {
+ let bytes = await OS.File.read(getAttributionFile().path);
+ let decoder = new TextDecoder();
+ let code = decoder.decode(bytes);
+ gCachedAttrData = parseAttributionCode(code);
+ } catch (ex) {
+ // The attribution file may already have been deleted,
+ // or it may have never been installed at all;
+ // failure to open or read it isn't an error.
+ }
+ } else if (AppConstants.platform == "macosx") {
+ try {
+ let appPath = Services.dirsvc.get("GreD", Ci.nsIFile).parent.parent.path;
+ let attributionSvc = Cc["@mozilla.org/mac-attribution;1"]
+ .getService(Ci.nsIMacAttributionService);
+ let referrer = attributionSvc.getReferrerUrl(appPath);
+ let params = new URL(referrer).searchParams;
+ for (let key of ATTR_CODE_KEYS) {
+ let utm_key = `utm_${key}`;
+ if (params.has(utm_key)) {
+ let value = params.get(utm_key);
+ if (value && ATTR_CODE_VALUE_REGEX.test(value)) {
+ gCachedAttrData[key] = value;
+ }
+ }
+ }
+ } catch (ex) {
+ // No attributions
+ }
}
-
- gCachedAttrData = parseAttributionCode(code);
return gCachedAttrData;
})();
},
/**
* Return the cached attribution data synchronously without hitting
* the disk.
* @returns A dictionary with the attribution data if it's available,
new file mode 100644
--- /dev/null
+++ b/browser/components/attribution/moz.build
@@ -0,0 +1,31 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+with Files("**"):
+ BUG_COMPONENT = ("Toolkit", "Telemetry")
+
+XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
+
+EXTRA_JS_MODULES += [
+ 'AttributionCode.jsm',
+]
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+ XPIDL_SOURCES += [
+ 'nsIMacAttribution.idl',
+ ]
+
+ XPIDL_MODULE = 'attribution'
+
+ EXPORTS += [
+ 'nsMacAttribution.h',
+ ]
+
+ SOURCES += [
+ 'nsMacAttribution.cpp',
+ ]
+
+ FINAL_LIBRARY = 'browsercomps'
new file mode 100644
--- /dev/null
+++ b/browser/components/attribution/nsIMacAttribution.idl
@@ -0,0 +1,29 @@
+/* -*- 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 "nsISupports.idl"
+
+[scriptable, uuid(6FC66A78-6CBC-4B3F-B7BA-379289B29276)]
+interface nsIMacAttributionService : nsISupports
+{
+ /**
+ * Used by the Attributions system to get the download referrer.
+ *
+ * @param filePath A path to the file to get the quarantine data from.
+ * @returns referrerUrl
+ */
+ AString getReferrerUrl(in ACString aFilePath);
+
+ /**
+ * Used by the tests.
+ *
+ * @param filePath A path to the file to set the quarantine data on.
+ * @param referrer A url to set as the referrer for the download.
+ * @param create Create new quarantine properties, overwriting any
+ * existing properties. If false, the referrer is only
+ * set if quarantine properties already exist on the file.
+ */
+ void setReferrerUrl(in ACString aFilePath, in ACString aReferrer, in boolean aCreate);
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/attribution/nsMacAttribution.cpp
@@ -0,0 +1,70 @@
+/* -*- 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 "nsMacAttribution.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "../../../xpcom/io/CocoaFileUtils.h"
+#include "nsCocoaFeatures.h"
+#include "nsString.h"
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS(nsMacAttributionService, nsIMacAttributionService)
+
+NS_IMETHODIMP
+nsMacAttributionService::GetReferrerUrl(const nsACString& aFilePath,
+ nsAString& aReferrer)
+{
+ const nsCString& flat = PromiseFlatCString(aFilePath);
+ CFStringRef filePath = ::CFStringCreateWithCString(kCFAllocatorDefault,
+ flat.get(),
+ kCFStringEncodingUTF8);
+
+ CocoaFileUtils::CopyQuarantineReferrerUrl(filePath, aReferrer);
+
+ ::CFRelease(filePath);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacAttributionService::SetReferrerUrl(const nsACString& aFilePath,
+ const nsACString& aReferrerUrl,
+ const bool aCreate)
+{
+ const nsCString& flat = PromiseFlatCString(aFilePath);
+ CFStringRef filePath = ::CFStringCreateWithCString(kCFAllocatorDefault,
+ flat.get(),
+ kCFStringEncodingUTF8);
+
+ if (!filePath) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ const nsCString& flatReferrer = PromiseFlatCString(aReferrerUrl);
+ CFStringRef referrer = ::CFStringCreateWithCString(kCFAllocatorDefault,
+ flatReferrer.get(),
+ kCFStringEncodingUTF8);
+ if (!referrer) {
+ ::CFRelease(filePath);
+ return NS_ERROR_UNEXPECTED;
+ }
+ CFURLRef referrerURL = ::CFURLCreateWithString(kCFAllocatorDefault,
+ referrer, nullptr);
+
+ CocoaFileUtils::AddQuarantineMetadataToFile(filePath,
+ NULL,
+ referrerURL,
+ true,
+ aCreate);
+
+ ::CFRelease(filePath);
+ ::CFRelease(referrer);
+ ::CFRelease(referrerURL);
+
+ return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/attribution/nsMacAttribution.h
@@ -0,0 +1,23 @@
+/* -*- 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 nsmacattribution_h____
+#define nsmacattribution_h____
+
+#include "nsIMacAttribution.h"
+
+class nsMacAttributionService : public nsIMacAttributionService
+{
+public:
+ nsMacAttributionService() {};
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIMACATTRIBUTIONSERVICE
+
+protected:
+ virtual ~nsMacAttributionService() {};
+};
+
+#endif // nsmacattribution_h____
new file mode 100644
--- /dev/null
+++ b/browser/components/attribution/test/.eslintrc.js
@@ -0,0 +1,5 @@
+"use strict";
+
+module.exports = {
+ "extends": "plugin:mozilla/xpcshell-test",
+};
rename from browser/modules/test/unit/test_AttributionCode.js
rename to browser/components/attribution/test/xpcshell/test_AttributionCode.js
new file mode 100644
--- /dev/null
+++ b/browser/components/attribution/test/xpcshell/test_attribution.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+add_task(async function test_attribution() {
+ let appPath = Services.dirsvc.get("GreD", Ci.nsIFile).parent.parent.path;
+ let attributionSvc = Cc["@mozilla.org/mac-attribution;1"]
+ .getService(Ci.nsIMacAttributionService);
+
+ attributionSvc.setReferrerUrl(appPath, "", true);
+ let referrer = attributionSvc.getReferrerUrl(appPath);
+ equal(referrer, "", "force an empty referrer url");
+
+ // Set a url referrer
+ let url = "http://example.com";
+ attributionSvc.setReferrerUrl(appPath, url, true);
+ referrer = attributionSvc.getReferrerUrl(appPath);
+ equal(referrer, url, "overwrite referrer url");
+
+ // Does not overwrite existing properties.
+ attributionSvc.setReferrerUrl(appPath, "http://test.com", false);
+ referrer = attributionSvc.getReferrerUrl(appPath);
+ equal(referrer, url, "referrer url is not changed");
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/attribution/test/xpcshell/xpcshell.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+firefox-appdir = browser
+skip-if = toolkit == 'android'
+
+[test_AttributionCode.js]
+skip-if = os != 'win' # windows specific tests
+[test_attribution.js]
+skip-if = toolkit != "cocoa" # osx specific tests
--- a/browser/components/build/nsBrowserCompsCID.h
+++ b/browser/components/build/nsBrowserCompsCID.h
@@ -36,8 +36,16 @@
// 7e4bb6ad-2fc4-4dc6-89ef-23e8e5ccf980
#define NS_BROWSER_ABOUT_REDIRECTOR_CID \
{ 0x7e4bb6ad, 0x2fc4, 0x4dc6, { 0x89, 0xef, 0x23, 0xe8, 0xe5, 0xcc, 0xf9, 0x80 } }
// {6DEB193C-F87D-4078-BC78-5E64655B4D62}
#define NS_BROWSERDIRECTORYPROVIDER_CID \
{ 0x6deb193c, 0xf87d, 0x4078, { 0xbc, 0x78, 0x5e, 0x64, 0x65, 0x5b, 0x4d, 0x62 } }
+
+#if defined(MOZ_WIDGET_COCOA)
+#define NS_MACATTRIBUTIONSERVICE_CONTRACTID \
+ "@mozilla.org/mac-attribution;1"
+
+#define NS_MACATTRIBUTIONSERVICE_CID \
+{ 0x6FC66A78, 0x6CBC, 0x4B3F, { 0xB7, 0xBA, 0x37, 0x92, 0x89, 0xB2, 0x92, 0x76 } }
+#endif
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -11,16 +11,20 @@
#if defined(XP_WIN)
#include "nsWindowsShellService.h"
#elif defined(XP_MACOSX)
#include "nsMacShellService.h"
#elif defined(MOZ_WIDGET_GTK)
#include "nsGNOMEShellService.h"
#endif
+#if defined(MOZ_WIDGET_COCOA)
+#include "nsMacAttribution.h"
+#endif
+
#if defined(XP_WIN)
#include "nsIEHistoryEnumerator.h"
#endif
#include "nsFeedSniffer.h"
#include "AboutRedirector.h"
#include "nsIAboutModule.h"
@@ -34,16 +38,20 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(Directory
#if defined(XP_WIN)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindowsShellService)
#elif defined(XP_MACOSX)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacShellService)
#elif defined(MOZ_WIDGET_GTK)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
#endif
+#if defined(MOZ_WIDGET_COCOA)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacAttributionService)
+#endif
+
#if defined(XP_WIN)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
NS_DEFINE_NAMED_CID(NS_BROWSERDIRECTORYPROVIDER_CID);
#if defined(XP_WIN)
@@ -53,31 +61,37 @@ NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID)
#endif
NS_DEFINE_NAMED_CID(NS_FEEDSNIFFER_CID);
NS_DEFINE_NAMED_CID(NS_BROWSER_ABOUT_REDIRECTOR_CID);
#if defined(XP_WIN)
NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
#elif defined(XP_MACOSX)
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
#endif
+#if defined(MOZ_WIDGET_COCOA)
+NS_DEFINE_NAMED_CID(NS_MACATTRIBUTIONSERVICE_CID);
+#endif
static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
{ &kNS_BROWSERDIRECTORYPROVIDER_CID, false, nullptr, DirectoryProviderConstructor },
#if defined(XP_WIN)
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsWindowsShellServiceConstructor },
#elif defined(MOZ_WIDGET_GTK)
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsGNOMEShellServiceConstructor },
#endif
{ &kNS_FEEDSNIFFER_CID, false, nullptr, nsFeedSnifferConstructor },
{ &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, nullptr, AboutRedirector::Create },
#if defined(XP_WIN)
{ &kNS_WINIEHISTORYENUMERATOR_CID, false, nullptr, nsIEHistoryEnumeratorConstructor },
#elif defined(XP_MACOSX)
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
#endif
+#if defined(MOZ_WIDGET_COCOA)
+ { &kNS_MACATTRIBUTIONSERVICE_CID, false, nullptr, nsMacAttributionServiceConstructor },
+#endif
{ nullptr }
};
static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
{ NS_BROWSERDIRECTORYPROVIDER_CONTRACTID, &kNS_BROWSERDIRECTORYPROVIDER_CID },
#if defined(XP_WIN)
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
#elif defined(MOZ_WIDGET_GTK)
@@ -102,16 +116,19 @@ static const mozilla::Module::ContractID
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "restartrequired", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "welcome", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#if defined(XP_WIN)
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
#elif defined(XP_MACOSX)
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
#endif
+#if defined(MOZ_WIDGET_COCOA)
+ { NS_MACATTRIBUTIONSERVICE_CONTRACTID, &kNS_MACATTRIBUTIONSERVICE_CID },
+#endif
{ nullptr }
};
static const mozilla::Module::CategoryEntry kBrowserCategories[] = {
{ XPCOM_DIRECTORY_PROVIDER_CATEGORY, "browser-directory-provider", NS_BROWSERDIRECTORYPROVIDER_CONTRACTID },
{ NS_CONTENT_SNIFFER_CATEGORY, "Feed Sniffer", NS_FEEDSNIFFER_CONTRACTID },
{ nullptr }
};
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -29,16 +29,17 @@ with Files("safebrowsing/**"):
BUG_COMPONENT = ("Toolkit", "Safe Browsing")
with Files('controlcenter/**'):
BUG_COMPONENT = ('Firefox', 'General')
DIRS += [
'about',
+ 'attribution',
'contextualidentity',
'customizableui',
'dirprovider',
'downloads',
'enterprisepolicies',
'extensions',
'feeds',
'library',
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -23,37 +23,31 @@ with Files("test/browser/browser_Unsubmi
BUG_COMPONENT = ("Toolkit", "Crash Reporting")
with Files("test/browser/browser_taskbar_preview.js"):
BUG_COMPONENT = ("Firefox", "Shell Integration")
with Files("test/browser/browser_urlBar_zoom.js"):
BUG_COMPONENT = ("Firefox", "General")
-with Files("test/unit/test_AttributionCode.js"):
- BUG_COMPONENT = ("Toolkit", "Telemetry")
-
with Files("test/unit/test_E10SUtils_nested_URIs.js"):
BUG_COMPONENT = ("Core", "Security: Process Sandboxing")
with Files("test/unit/test_LaterRun.js"):
BUG_COMPONENT = ("Firefox", "Tours")
with Files("test/unit/test_SitePermissions.js"):
BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
with Files("AboutNewTab.jsm"):
BUG_COMPONENT = ("Firefox", "New Tab Page")
with Files('AsyncTabSwitcher.jsm'):
BUG_COMPONENT = ('Firefox', 'Tabbed Browser')
-with Files("AttributionCode.jsm"):
- BUG_COMPONENT = ("Toolkit", "Telemetry")
-
with Files("BrowserWindowTracker.jsm"):
BUG_COMPONENT = ("Core", "Networking")
with Files("*Telemetry.jsm"):
BUG_COMPONENT = ("Toolkit", "Telemetry")
with Files("ContentCrashHandlers.jsm"):
BUG_COMPONENT = ("Toolkit", "Crash Reporting")
@@ -132,17 +126,16 @@ BROWSER_CHROME_MANIFESTS += [
'test/browser/browser.ini',
'test/browser/formValidation/browser.ini',
]
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
EXTRA_JS_MODULES += [
'AboutNewTab.jsm',
'AsyncTabSwitcher.jsm',
- 'AttributionCode.jsm',
'BlockedSiteContent.jsm',
'BrowserErrorReporter.jsm',
'BrowserUsageTelemetry.jsm',
'BrowserWindowTracker.jsm',
'ContentClick.jsm',
'ContentCrashHandlers.jsm',
'ContentLinkHandler.jsm',
'ContentMetaHandler.jsm',
--- a/browser/modules/test/unit/xpcshell.ini
+++ b/browser/modules/test/unit/xpcshell.ini
@@ -1,11 +1,9 @@
[DEFAULT]
head =
firefox-appdir = browser
skip-if = toolkit == 'android'
-[test_AttributionCode.js]
-skip-if = os != 'win'
[test_E10SUtils_nested_URIs.js]
[test_Sanitizer_interrupted.js]
[test_SitePermissions.js]
[test_LaterRun.js]
--- a/xpcom/io/CocoaFileUtils.h
+++ b/xpcom/io/CocoaFileUtils.h
@@ -6,30 +6,33 @@
// This namespace contains methods with Obj-C/Cocoa implementations. The header
// is C/C++ for inclusion in C/C++-only files.
#ifndef CocoaFileUtils_h_
#define CocoaFileUtils_h_
#include "nscore.h"
+#include "nsString.h"
#include <CoreFoundation/CoreFoundation.h>
namespace CocoaFileUtils {
nsresult RevealFileInFinder(CFURLRef aUrl);
nsresult OpenURL(CFURLRef aUrl);
nsresult GetFileCreatorCode(CFURLRef aUrl, OSType* aCreatorCode);
nsresult SetFileCreatorCode(CFURLRef aUrl, OSType aCreatorCode);
nsresult GetFileTypeCode(CFURLRef aUrl, OSType* aTypeCode);
nsresult SetFileTypeCode(CFURLRef aUrl, OSType aTypeCode);
void AddOriginMetadataToFile(const CFStringRef filePath,
const CFURLRef sourceURL,
const CFURLRef referrerURL);
void AddQuarantineMetadataToFile(const CFStringRef filePath,
const CFURLRef sourceURL,
const CFURLRef referrerURL,
- const bool isFromWeb);
+ const bool isFromWeb,
+ const bool createProps=false);
+void CopyQuarantineReferrerUrl(const CFStringRef filePath, nsAString& referrer);
CFURLRef GetTemporaryFolderCFURLRef();
} // namespace CocoaFileUtils
#endif
--- a/xpcom/io/CocoaFileUtils.mm
+++ b/xpcom/io/CocoaFileUtils.mm
@@ -5,16 +5,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CocoaFileUtils.h"
#include "nsCocoaFeatures.h"
#include "nsCocoaUtils.h"
#include <Cocoa/Cocoa.h>
#include "nsObjCExceptions.h"
#include "nsDebug.h"
+#include "nsString.h"
+#include "../base/MacStringHelpers.h"
// Need to cope with us using old versions of the SDK and needing this on 10.10+
#if !defined(MAC_OS_X_VERSION_10_10) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10)
const CFStringRef kCFURLQuarantinePropertiesKey = CFSTR("NSURLQuarantinePropertiesKey");
#endif
namespace CocoaFileUtils {
@@ -186,57 +188,72 @@ void AddOriginMetadataToFile(const CFStr
}
mdItemSetAttributeFunc(mdItem, kMDItemWhereFroms, list);
::CFRelease(list);
::CFRelease(mdItem);
}
-void AddQuarantineMetadataToFile(const CFStringRef filePath,
- const CFURLRef sourceURL,
- const CFURLRef referrerURL,
- const bool isFromWeb) {
- CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
- filePath,
- kCFURLPOSIXPathStyle,
- false);
+CFStringRef GetQuarantinePropKey() {
+ if (nsCocoaFeatures::OnYosemiteOrLater()) {
+ return kCFURLQuarantinePropertiesKey;
+ }
+ return kLSItemQuarantineProperties;
+}
+CFMutableDictionaryRef CreateQuarantineDictionary(const CFURLRef fileURL, const bool createProps) {
// The properties key changed in 10.10:
- CFStringRef quarantinePropKey;
- if (nsCocoaFeatures::OnYosemiteOrLater()) {
- quarantinePropKey = kCFURLQuarantinePropertiesKey;
+ CFDictionaryRef quarantineProps = NULL;
+ if (createProps) {
+ quarantineProps = ::CFDictionaryCreate(NULL, NULL, NULL, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
} else {
- quarantinePropKey = kLSItemQuarantineProperties;
- }
- CFDictionaryRef quarantineProps = NULL;
- Boolean success = ::CFURLCopyResourcePropertyForKey(fileURL,
- quarantinePropKey,
- &quarantineProps,
- NULL);
-
- // If there aren't any quarantine properties then the user probably
- // set up an exclusion and we don't need to add metadata.
- if (!success || !quarantineProps) {
- ::CFRelease(fileURL);
- return;
+ Boolean success = ::CFURLCopyResourcePropertyForKey(fileURL,
+ GetQuarantinePropKey(),
+ &quarantineProps,
+ NULL);
+ // If there aren't any quarantine properties then the user probably
+ // set up an exclusion and we don't need to add metadata.
+ if (!success || !quarantineProps) {
+ return NULL;
+ }
}
// We don't know what to do if the props aren't a dictionary.
if (::CFGetTypeID(quarantineProps) != ::CFDictionaryGetTypeID()) {
- ::CFRelease(fileURL);
::CFRelease(quarantineProps);
- return;
+ return NULL;
}
// Make a mutable copy of the properties.
CFMutableDictionaryRef mutQuarantineProps =
::CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, (CFDictionaryRef)quarantineProps);
::CFRelease(quarantineProps);
+ return mutQuarantineProps;
+}
+
+void AddQuarantineMetadataToFile(const CFStringRef filePath,
+ const CFURLRef sourceURL,
+ const CFURLRef referrerURL,
+ const bool isFromWeb,
+ const bool createProps /* = false */) {
+ CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
+ filePath,
+ kCFURLPOSIXPathStyle,
+ false);
+
+ CFMutableDictionaryRef mutQuarantineProps = CreateQuarantineDictionary(fileURL, createProps);
+ if (!mutQuarantineProps) {
+ ::CFRelease(fileURL);
+ return;
+ }
+
// Add metadata that the OS couldn't infer.
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineTypeKey)) {
CFStringRef type = isFromWeb ? kLSQuarantineTypeWebDownload : kLSQuarantineTypeOtherDownload;
::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineTypeKey, type);
}
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineOriginURLKey) && referrerURL) {
@@ -244,24 +261,46 @@ void AddQuarantineMetadataToFile(const C
}
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineDataURLKey) && sourceURL) {
::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineDataURLKey, sourceURL);
}
// Set quarantine properties on file.
::CFURLSetResourcePropertyForKey(fileURL,
- quarantinePropKey,
+ GetQuarantinePropKey(),
mutQuarantineProps,
NULL);
::CFRelease(fileURL);
::CFRelease(mutQuarantineProps);
}
+void CopyQuarantineReferrerUrl(const CFStringRef aFilePath, nsAString& aReferrer)
+{
+ CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
+ aFilePath,
+ kCFURLPOSIXPathStyle,
+ false);
+
+ CFMutableDictionaryRef mutQuarantineProps = CreateQuarantineDictionary(fileURL, false);
+ ::CFRelease(fileURL);
+ if (!mutQuarantineProps) {
+ return;
+ }
+
+ CFTypeRef referrerRef = ::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineOriginURLKey);
+ if (referrerRef && ::CFGetTypeID(referrerRef) == ::CFURLGetTypeID()) {
+ // URL string must be copied prior to releasing the dictionary.
+ mozilla::CopyCocoaStringToXPCOMString((NSString*)::CFURLGetString(static_cast<CFURLRef>(referrerRef)), aReferrer);
+ }
+
+ ::CFRelease(mutQuarantineProps);
+}
+
CFURLRef GetTemporaryFolderCFURLRef()
{
NSString* tempDir = ::NSTemporaryDirectory();
return tempDir == nil ? NULL : (CFURLRef)[NSURL fileURLWithPath:tempDir
isDirectory:YES];
}
} // namespace CocoaFileUtils