--- a/mail/components/Makefile.in
+++ b/mail/components/Makefile.in
@@ -39,17 +39,17 @@ DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
# Only Mac and Windows have search integration components, but we include at
# least one module from search/ on all platforms
-DIRS = compose preferences addrbook migration activity search
+DIRS = compose preferences addrbook migration activity search about-support
ifneq (,$(filter windows gtk2 cocoa, $(MOZ_WIDGET_TOOLKIT)))
DIRS += shell
endif
ifdef MOZ_SAFE_BROWSING
DIRS += phishing
endif
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/Makefile.in
@@ -0,0 +1,21 @@
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+EXTRA_JS_MODULES = aboutSupport.js
+
+# Include the platform-specific module
+ifeq ($(MOZ_WIDGET_TOOLKIT), windows)
+EXTRA_JS_MODULES += aboutSupportWin32.js
+else
+ifeq ($(MOZ_WIDGET_TOOLKIT), cocoa)
+EXTRA_JS_MODULES += aboutSupportMac.js
+else
+EXTRA_JS_MODULES += aboutSupportUnix.js
+endif
+endif
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/aboutSupport.js
@@ -0,0 +1,186 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Thunderbird about:support.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var EXPORTED_SYMBOLS = ["AboutSupport"];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+// Platform-specific includes
+if ("@mozilla.org/windows-registry-key;1" in Components.classes)
+ Components.utils.import("resource:///modules/aboutSupportWin32.js");
+else if ("nsILocalFileMac" in Components.interfaces)
+ Components.utils.import("resource:///modules/aboutSupportMac.js");
+else
+ Components.utils.import("resource:///modules/aboutSupportUnix.js");
+
+Components.utils.import("resource:///modules/iteratorUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+var gMessengerBundle = Services.strings.createBundle(
+ "chrome://messenger/locale/messenger.properties");
+
+var gSMTPService = Cc["@mozilla.org/messengercompose/smtp;1"]
+ .getService(Ci.nsISmtpService);
+
+var gSocketTypes = {};
+for (let [str, index] in Iterator(Ci.nsMsgSocketType))
+ gSocketTypes[index] = str;
+
+var gAuthMethods = {};
+for (let [str, index] in Iterator(Ci.nsMsgAuthMethod))
+ gAuthMethods[index] = str;
+
+// l10n properties in messenger.properties corresponding to each auth method
+var gAuthMethodProperties = {
+ "1": "authOld",
+ "2": "authPasswordCleartextInsecurely",
+ "3": "authPasswordCleartextViaSSL",
+ "4": "authPasswordEncrypted",
+ "5": "authKerberos",
+ "6": "authNTLM",
+ "8": "authAnySecure"
+};
+
+var AboutSupport = {
+ __proto__: AboutSupportPlatform,
+
+ /**
+ * Gets details about SMTP servers for a given nsIMsgAccount.
+ *
+ * @returns A list of records, each record containing the name and other details
+ * about one SMTP server.
+ */
+ _getSMTPDetails: function AboutSupport__getSMTPDetails(aAccount) {
+ let identities = aAccount.identities;
+ let defaultIdentity = aAccount.defaultIdentity;
+ let smtpDetails = [];
+
+ for each (let identity in fixIterator(identities, Ci.nsIMsgIdentity)) {
+ let isDefault = identity == defaultIdentity;
+ let smtpServer = {};
+ gSMTPService.GetSmtpServerByIdentity(identity, smtpServer);
+ smtpDetails.push({name: smtpServer.value.displayname,
+ authMethod: smtpServer.value.authMethod,
+ socketType: smtpServer.value.socketType,
+ isDefault: isDefault});
+ }
+
+ return smtpDetails;
+ },
+
+ /**
+ * Returns account details as a list of records.
+ */
+ getAccountDetails: function AboutSupport_getAccountDetails() {
+ let accountDetails = [];
+ let accountManager = Cc["@mozilla.org/messenger/account-manager;1"]
+ .getService(Ci.nsIMsgAccountManager);
+ let accounts = accountManager.accounts;
+
+ for (let account in fixIterator(accounts, Ci.nsIMsgAccount)) {
+ let server = account.incomingServer;
+ accountDetails.push({
+ key: account.key,
+ name: server.prettyName,
+ hostDetails: "(" + server.type + ") " + server.hostName +
+ (server.port != -1 ? (":" + server.port) : ""),
+ socketType: server.socketType,
+ authMethod: server.authMethod,
+ smtpServers: this._getSMTPDetails(account),
+ });
+ }
+
+ function idCompare(accountA, accountB) {
+ let regex = /^account([0-9]+)$/;
+ let regexA = regex.exec(accountA.key);
+ let regexB = regex.exec(accountB.key);
+ // There's an off chance that the account ID isn't in the standard
+ // accountN form. If so, use the standard string compare against a fixed
+ // string ("account") to avoid correctness issues.
+ if (!regexA || !regexB) {
+ let keyA = regexA ? "account" : accountA.key;
+ let keyB = regexB ? "account" : accountB.key;
+ return keyA.localeCompare(keyB);
+ }
+ let idA = parseInt(regexA[1]);
+ let idB = parseInt(regexB[1]);
+ return idB - idA;
+ }
+
+ // Sort accountDetails by account ID.
+ accountDetails.sort(idCompare);
+ return accountDetails;
+ },
+
+ /**
+ * Returns the corresponding text for a given socket type index. The text is
+ * returned as a record with "localized" and "neutral" entries.
+ */
+ getSocketTypeText: function AboutSupport_getSocketTypeText(aIndex) {
+ let plainSocketType = (aIndex in gSocketTypes ?
+ gSocketTypes[aIndex] : aIndex);
+ let prettySocketType;
+ try {
+ prettySocketType = gMessengerBundle.GetStringFromName(
+ "smtpServer-ConnectionSecurityType-" + aIndex);
+ }
+ catch (e if e.result == Components.results.NS_ERROR_FAILURE) {
+ // The string wasn't found in the bundle. Make do without it.
+ prettySocketType = plainSocketType;
+ }
+ return {localized: prettySocketType, neutral: plainSocketType};
+ },
+
+ /**
+ * Returns the corresponding text for a given authentication method index. The
+ * text is returned as a record with "localized" and "neutral" entries.
+ */
+ getAuthMethodText: function AboutSupport_getAuthMethodText(aIndex) {
+ let prettyAuthMethod;
+ let plainAuthMethod = (aIndex in gAuthMethods ?
+ gAuthMethods[aIndex] : aIndex);
+ if (aIndex in gAuthMethodProperties) {
+ prettyAuthMethod =
+ gMessengerBundle.GetStringFromName(gAuthMethodProperties[aIndex]);
+ }
+ else {
+ prettyAuthMethod = plainAuthMethod;
+ }
+ return {localized: prettyAuthMethod, neutral: plainAuthMethod};
+ }
+};
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/aboutSupportMac.js
@@ -0,0 +1,49 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Thunderbird about:support.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var EXPORTED_SYMBOLS = ["AboutSupportPlatform"];
+
+var AboutSupportPlatform = {
+ /**
+ * Given an nsIFile, gets the file system type. The type is returned as a
+ * string. Possible values are "network", "local", "unknown" and null.
+ */
+ getFileSystemType: function ASPMac_getFileSystemType(aFile) {
+ // Not implemented
+ return null;
+ },
+};
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/aboutSupportUnix.js
@@ -0,0 +1,148 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Thunderbird about:support.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var EXPORTED_SYMBOLS = ["AboutSupportPlatform"];
+
+// JS ctypes are needed to get at the data we need
+Components.utils.import("resource://gre/modules/ctypes.jsm");
+const GFile = ctypes.StructType("GFile");
+const GFileInfo = ctypes.StructType("GFileInfo");
+const GError = ctypes.StructType("GError");
+const GCancellable = ctypes.StructType("GCancellable");
+
+const G_FILE_ATTRIBUTE_FILESYSTEM_TYPE = "filesystem::type";
+
+const kNetworkFilesystems = ["afs", "cifs", "nfs", "smb"];
+
+// GC is responsible for closing these libraries
+var glib = ctypes.open("libglib-2.0.so");
+var gobject = ctypes.open("libgobject-2.0.so");
+
+var g_free = glib.declare(
+ "g_free",
+ ctypes.default_abi,
+ ctypes.void_t,
+ ctypes.voidptr_t
+);
+
+var g_object_unref = gobject.declare(
+ "g_object_unref",
+ ctypes.default_abi,
+ ctypes.void_t,
+ ctypes.voidptr_t
+);
+
+var AboutSupportPlatform = {
+ /**
+ * Given an nsIFile, gets the file system type. The type is returned as a
+ * string. Possible values are "network", "local", "unknown" and null.
+ */
+ getFileSystemType: function ASPUnix_getFileSystemType(aFile) {
+ let gio = ctypes.open("libgio-2.0.so");
+ try {
+ // Given a UTF-8 string, converts it to the current Glib locale.
+ let g_filename_from_utf8 = glib.declare(
+ "g_filename_from_utf8",
+ ctypes.default_abi,
+ ctypes.char.ptr, // return type: glib locale string
+ ctypes.char.ptr, // in: utf8string
+ ctypes.ssize_t, // in: len
+ ctypes.size_t.ptr, // out: bytes_read
+ ctypes.size_t.ptr, // out: bytes_written
+ GError.ptr // out: error
+ );
+ // Yes, we want function scoping for variables we need to free in the
+ // finally block. I think this is better than declaring lots of variables
+ // on top.
+ var filePath = g_filename_from_utf8(aFile.path, -1, null, null, null);
+ if (filePath.isNull()) {
+ throw new Error("Unable to convert " + aFile.path +
+ " into GLib encoding");
+ }
+
+ // Given a path, creates a new GFile for it.
+ let g_file_new_for_path = gio.declare(
+ "g_file_new_for_path",
+ ctypes.default_abi,
+ GFile.ptr, // return type: a newly-allocated GFile
+ ctypes.char.ptr // in: path
+ );
+ var glibFile = g_file_new_for_path(filePath);
+
+ // Given a GFile, queries the given attributes and returns them
+ // as a GFileInfo.
+ let g_file_query_filesystem_info = gio.declare(
+ "g_file_query_filesystem_info",
+ ctypes.default_abi,
+ GFileInfo.ptr, // return type
+ GFile.ptr, // in: file
+ ctypes.char.ptr, // in: attributes
+ GCancellable.ptr, // in: cancellable
+ GError.ptr // out: error
+ );
+ var glibFileInfo = g_file_query_filesystem_info(
+ glibFile, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, null, null);
+ if (glibFileInfo.isNull())
+ throw new Error("Unabled to retrieve GLib file info for " + aFile.path);
+
+ let g_file_info_get_attribute_string = gio.declare(
+ "g_file_info_get_attribute_string",
+ ctypes.default_abi,
+ ctypes.char.ptr, // return type: file system type (do not free)
+ GFileInfo.ptr, // in: info
+ ctypes.char.ptr // in: attribute
+ );
+ let fsType = g_file_info_get_attribute_string(
+ glibFileInfo, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE);
+ if (fsType.isNull())
+ return "unknown";
+ else if (kNetworkFilesystems.indexOf(fsType.readString()) != -1)
+ return "network";
+ else
+ return "local";
+ }
+ finally {
+ if (filePath)
+ g_free(filePath);
+ if (glibFile && !glibFile.isNull())
+ g_object_unref(glibFile);
+ if (glibFileInfo && !glibFileInfo.isNull())
+ g_object_unref(glibFileInfo);
+ gio.close();
+ }
+ },
+};
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/aboutSupportWin32.js
@@ -0,0 +1,105 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Thunderbird about:support.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var EXPORTED_SYMBOLS = ["AboutSupportPlatform"];
+
+// JS ctypes are needed to get at the data we need
+Components.utils.import("resource://gre/modules/ctypes.jsm");
+
+const BOOL = ctypes.int32_t;
+const DRIVE_UNKNOWN = 0;
+const DRIVE_NETWORK = 4;
+
+var AboutSupportPlatform = {
+ /**
+ * Given an nsIFile, gets the file system type. The type is returned as a
+ * string. Possible values are "network", "local", "unknown" and null.
+ */
+ getFileSystemType: function ASPWin32_getFileSystemType(aFile) {
+ let kernel32 = ctypes.open("kernel32.dll");
+
+ try {
+ // Returns the path of the volume a file is on.
+ let GetVolumePathName = kernel32.declare(
+ "GetVolumePathNameW",
+ ctypes.winapi_abi,
+ BOOL, // return type: 1 indicates success, 0 failure
+ ctypes.jschar.ptr, // in: lpszFileName
+ ctypes.jschar.ptr, // out: lpszVolumePathName
+ ctypes.uint32_t // in: cchBufferLength
+ );
+
+ // Returns the last error.
+ let GetLastError = kernel32.declare(
+ "GetLastError",
+ ctypes.winapi_abi,
+ ctypes.uint32_t // return type: the last error
+ );
+
+ let filePath = aFile.path;
+ // The volume path should be at most 1 greater than than the length of the
+ // path -- add 1 for a trailing backslash if necessary, and 1 for the
+ // terminating null character. Note that the parentheses around the type are
+ // necessary for new to apply correctly.
+ let volumePath = new (ctypes.jschar.array(filePath.length + 2));
+
+ if (!GetVolumePathName(filePath, volumePath, volumePath.length)) {
+ throw new Error("Unable to get volume path for " + filePath + ", error " +
+ GetLastError());
+ }
+
+ // Returns the type of the drive.
+ let GetDriveType = kernel32.declare(
+ "GetDriveTypeW",
+ ctypes.winapi_abi,
+ ctypes.uint32_t, // return type: the drive type
+ ctypes.jschar.ptr // in: lpRootPathName
+ );
+ let type = GetDriveType(volumePath);
+ // http://msdn.microsoft.com/en-us/library/aa364939
+ if (type == DRIVE_UNKNOWN)
+ return "unknown";
+ else if (type == DRIVE_NETWORK)
+ return "network";
+ else
+ return "local";
+ }
+ finally {
+ kernel32.close();
+ }
+ },
+};
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/aboutSupport.xhtml
@@ -0,0 +1,314 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is aboutSupport.xhtml.
+ -
+ - The Initial Developer of the Original Code is
+ - Mozilla Foundation
+ - Portions created by the Initial Developer are Copyright (C) 2009
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ - Curtis Bartley <cbartley@mozilla.com>
+ - Siddharth Agarwal <sid.bugzilla@gmail.com>
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the GPL or the LGPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+ - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE html [
+ <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
+ <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
+ <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
+ <!ENTITY % aboutSupportDTD SYSTEM "chrome://global/locale/aboutSupport.dtd"> %aboutSupportDTD;
+ <!ENTITY % aboutSupportMailDTD SYSTEM "chrome://messenger/locale/aboutSupportMail.dtd"> %aboutSupportMailDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>&aboutSupport.pageTitle;</title>
+
+ <link rel="stylesheet" href="chrome://global/skin/aboutSupport.css"
+ type="text/css"/>
+ <link rel="stylesheet" href="chrome://messenger/skin/aboutSupport.css"
+ type="text/css"/>
+ <link rel="stylesheet" href="chrome://messenger/content/about-support/show-private.css"
+ type="text/css"/>
+ <!-- Private data is hidden by default. -->
+ <link rel="stylesheet" href="chrome://messenger/content/about-support/hide-private.css"
+ type="text/css" id="about-support-private"/>
+
+ <script type="application/javascript;version=1.7"
+ src="chrome://messenger/content/about-support/init.js"/>
+ <script type="application/javascript;version=1.7"
+ src="chrome://messenger/content/about-support/accounts.js"/>
+ <script type="application/javascript;version=1.7"
+ src="chrome://messenger/content/about-support/extensions.js"/>
+ <script type="application/javascript;version=1.7"
+ src="chrome://messenger/content/about-support/prefs.js"/>
+ <script type="application/javascript;version=1.7"
+ src="chrome://messenger/content/about-support/gfx.js"/>
+ <script type="application/javascript;version=1.7"
+ src="chrome://messenger/content/about-support/export.js"/>
+ </head>
+
+ <body dir="&locale.dir;">
+
+ <h1>
+ &aboutSupport.pageTitle;
+ </h1>
+
+ <div class="page-subtitle">
+ &aboutSupport.pageSubtitle;
+ </div>
+
+ <div>
+ <button onclick="copyToClipboard()">
+ &aboutSupport.copyToClipboard.label;
+ </button>
+ <button onclick="sendViaEmail()">
+ &aboutSupport.sendViaEmail.label;
+ </button>
+ <input type="checkbox" id="check-show-private-data" class="data-uionly"
+ onchange="onShowPrivateDataChange(this);" />
+ <label for="check-show-private-data">&aboutSupport.showPrivateData.mainText;
+ <span class="gray-text">&aboutSupport.showPrivateData.explanationText;</span></label>
+ </div>
+
+ <div id="contents">
+
+ <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+ <h2 class="major-section">
+ &aboutSupport.appBasicsTitle;
+ </h2>
+
+ <table>
+ <tbody>
+ <tr>
+ <th class="column">
+ &aboutSupport.appBasicsName;
+ </th>
+
+ <td id="application-box">
+ </td>
+ </tr>
+
+ <tr>
+ <th class="column">
+ &aboutSupport.appBasicsVersion;
+ </th>
+
+ <td id="version-box">
+ </td>
+ </tr>
+
+ <tr>
+ <th class="column">
+ &aboutSupport.appBasicsUserAgent;
+ </th>
+
+ <td id="useragent-box">
+ </td>
+ </tr>
+
+ <tr>
+ <th class="column">
+ &aboutSupport.appBasicsProfileDir;
+ </th>
+
+ <td>
+ <div id="profile-dir-button-box" class="data-public">
+ <button onclick="openProfileDirectory()">
+#ifdef XP_MACOSX
+ &aboutSupport.showMac.label;
+#else
+ &aboutSupport.show.label;
+#endif
+ </button>
+ </div>
+ <span id="profile-dir-box" class="data-private"></span>
+ <span id="profile-fs-type-box"></span>
+ </td>
+ </tr>
+
+ <tr>
+ <th class="column">
+ &aboutSupport.appBasicsAppBuildID;
+ </th>
+
+ <td id="buildid-box">
+ </td>
+ </tr>
+
+ <tr>
+ <th class="column">
+ &aboutSupport.appBasicsEnabledPlugins;
+ </th>
+
+ <td>
+ <a href="about:plugins" target="_blank">about:plugins</a>
+ </td>
+ </tr>
+
+ <tr>
+ <th class="column">
+ &aboutSupport.appBasicsBuildConfig;
+ </th>
+
+ <td>
+ <a href="about:buildconfig" target="_blank">about:buildconfig</a>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+ <h2 class="major-section">
+ &aboutSupport.accountsTitle;
+ </h2>
+
+ <table id="accounts-table">
+ <thead>
+ <tr>
+ <th rowspan="2">
+ &aboutSupport.accountsID;
+ </th>
+
+ <th rowspan="2" class="data-private">
+ &aboutSupport.accountsName;
+ </th>
+
+ <th colspan="3">
+ &aboutSupport.accountsIncomingServer;
+ </th>
+
+ <th colspan="4">
+ &aboutSupport.accountsOutgoingServers;
+ </th>
+ </tr>
+ <tr class="thead-level2">
+ <!-- Incoming server -->
+ <th>
+ &aboutSupport.accountsName;
+ </th>
+
+ <th>
+ &aboutSupport.accountsConnSecurity;
+ </th>
+
+ <th>
+ &aboutSupport.accountsAuthMethod;
+ </th>
+
+ <!-- Outgoing servers -->
+ <th>
+ &aboutSupport.accountsName;
+ </th>
+
+ <th>
+ &aboutSupport.accountsConnSecurity;
+ </th>
+
+ <th>
+ &aboutSupport.accountsAuthMethod;
+ </th>
+
+ <th>
+ &aboutSupport.accountsDefault;
+ </th>
+ </tr>
+ </thead>
+
+ <tbody id="accounts-tbody">
+ </tbody>
+ </table>
+
+ <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+ <h2 class="major-section">
+ &aboutSupport.extensionsTitle;
+ </h2>
+
+ <table id="extensions-table">
+ <thead>
+ <tr>
+ <th>
+ &aboutSupport.extensionName;
+ </th>
+ <th>
+ &aboutSupport.extensionVersion;
+ </th>
+ <th>
+ &aboutSupport.extensionEnabled;
+ </th>
+ <th>
+ &aboutSupport.extensionId;
+ </th>
+ </tr>
+ </thead>
+ <tbody id="extensions-tbody">
+ </tbody>
+ </table>
+
+ <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+ <h2 class="major-section">
+ &aboutSupport.modifiedPrefsTitle;
+ </h2>
+
+ <table class="prefs-table">
+ <thead>
+ <tr>
+ <th class="name">
+ &aboutSupport.modifiedPrefsName;
+ </th>
+
+ <th class="value">
+ &aboutSupport.modifiedPrefsValue;
+ </th>
+ </tr>
+ </thead>
+
+ <tbody id="prefs-tbody">
+ </tbody>
+ </table>
+
+ <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+ <h2 class="major-section">
+ &aboutSupport.graphicsTitle;
+ </h2>
+
+ <table>
+ <tbody id="graphics-tbody">
+ </tbody>
+ </table>
+
+ </div>
+
+ </body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/accounts.js
@@ -0,0 +1,160 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is aboutSupport.xhtml.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Curtis Bartley <cbartley@mozilla.com>
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * Coerces x into a string.
+ */
+function toStr(x) {
+ return "" + x;
+}
+
+/**
+ * Marks x as private (see below).
+ */
+function toPrivate(x) {
+ return {localized: x, neutral: x, isPrivate: true};
+}
+
+/**
+ * A list of fields for the incoming server of an account. Each element of the
+ * list is a pair of [property name, transforming function]. The transforming
+ * function should take the property and return either a string or an object
+ * with the following properties:
+ * - localized: the data in (possibly) localized form
+ * - neutral: the data in language-neutral form
+ * - isPrivate (optional): true if the data is private-only, false if public-only,
+ * not stated otherwise
+ */
+var gIncomingDetails = [
+ ["key", toStr],
+ ["name", toPrivate],
+ ["hostDetails", toStr],
+ ["socketType", AboutSupport.getSocketTypeText.bind(AboutSupport)],
+ ["authMethod", AboutSupport.getAuthMethodText.bind(AboutSupport)],
+];
+
+/**
+ * A list of fields for the outgoing servers associated with an account. This is
+ * similar to gIncomingDetails above.
+ */
+var gOutgoingDetails = [
+ ["name", toStr],
+ ["socketType", AboutSupport.getSocketTypeText.bind(AboutSupport)],
+ ["authMethod", AboutSupport.getAuthMethodText.bind(AboutSupport)],
+ ["isDefault", toStr],
+];
+
+/**
+ * A list of account details.
+ */
+XPCOMUtils.defineLazyGetter(window, "gAccountDetails",
+ function () AboutSupport.getAccountDetails());
+
+function populateAccountsSection() {
+ let trAccounts = [];
+
+ function createTD(data, rowSpan) {
+ let text = (typeof data == "string") ? data : data.localized;
+ let copyData = (typeof data == "string") ? null : data.neutral;
+ let attributes = {rowspan: rowSpan};
+ if (typeof data == "object" && "isPrivate" in data)
+ attributes.class = data.isPrivate ? CLASS_DATA_PRIVATE : CLASS_DATA_PUBLIC;
+
+ return createElement("td", text, attributes, copyData);
+ }
+
+ for (let [, account] in Iterator(gAccountDetails)) {
+ // We want a minimum rowspan of 1
+ let rowSpan = account.smtpServers.length || 1;
+ // incomingTDs is a list of TDs
+ let incomingTDs = [createTD(fn(account[prop]), rowSpan)
+ for ([, [prop, fn]] in Iterator(gIncomingDetails))];
+ // outgoingTDs is a list of list of TDs
+ let outgoingTDs = [[createTD(fn(smtp[prop]), 1)
+ for ([, [prop, fn]] in Iterator(gOutgoingDetails))]
+ for ([, smtp] in Iterator(account.smtpServers))];
+
+ // If there are no SMTP servers, add a dummy element to make life easier below
+ if (outgoingTDs.length == 0)
+ outgoingTDs = [[]];
+
+ // Add the first SMTP server to this tr.
+ let tr = createParentElement("tr", incomingTDs.concat(outgoingTDs[0]));
+ trAccounts.push(tr);
+ // Add the remaining SMTP servers as separate trs
+ for each (let [, tds] in Iterator(outgoingTDs.slice(1)))
+ trAccounts.push(createParentElement("tr", tds));
+ }
+
+ appendChildren(document.getElementById("accounts-tbody"), trAccounts);
+}
+
+/**
+ * Returns a plaintext representation of the accounts data.
+ */
+function getAccountsText(aHidePrivateData, aIndent) {
+ let accumulator = [];
+
+ // Given a string or object, converts it into a language-neutral form
+ function neutralizer(data) {
+ if (typeof data == "string")
+ return data;
+ if ("isPrivate" in data && (aHidePrivateData == data.isPrivate))
+ return "";
+ return data.neutral;
+ }
+
+ for (let [, account] in Iterator(gAccountDetails)) {
+ accumulator.push(aIndent + account.key + ":");
+ // incomingData is a list of strings
+ let incomingData = [neutralizer(fn(account[prop]))
+ for ([, [prop, fn]] in Iterator(gIncomingDetails))];
+ accumulator.push(aIndent + " INCOMING: " + incomingData.join(", "));
+
+ // outgoingData is a list of list of strings
+ let outgoingData = [[neutralizer(fn(smtp[prop]))
+ for ([, [prop, fn]] in Iterator(gOutgoingDetails))]
+ for ([, smtp] in Iterator(account.smtpServers))];
+ for (let [, data] in Iterator(outgoingData))
+ accumulator.push(aIndent + " OUTGOING: " + data.join(", "));
+
+ accumulator.push("");
+ }
+
+ return accumulator.join("\n");
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/export.js
@@ -0,0 +1,257 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is aboutSupport.xhtml.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Curtis Bartley <cbartley@mozilla.com>
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+/**
+ * Create warning text to add to any private data.
+ * @returns A HTML paragraph node containing the warning.
+ */
+function createWarning() {
+ let bundle = Services.strings.createBundle(
+ "chrome://messenger/locale/aboutSupportMail.properties");
+ return createParentElement("p", [
+ createElement("strong", bundle.GetStringFromName("warningLabel")),
+ // Add some whitespace between the label and the text
+ document.createTextNode(" "),
+ document.createTextNode(bundle.GetStringFromName("warningText")),
+ ]);
+}
+
+function getClipboardTransferable() {
+ // Get the HTML and text representations for the important part of the page.
+ let hidePrivateData = !document.getElementById("check-show-private-data").checked;
+ let contentsDiv = createCleanedUpContents(hidePrivateData);
+ let dataHtml = contentsDiv.innerHTML;
+ let dataText = createTextForElement(contentsDiv, hidePrivateData);
+
+ // We can't use plain strings, we have to use nsSupportsString.
+ let supportsStringClass = Cc["@mozilla.org/supports-string;1"];
+ let ssHtml = supportsStringClass.createInstance(Ci.nsISupportsString);
+ let ssText = supportsStringClass.createInstance(Ci.nsISupportsString);
+
+ let transferable = Cc["@mozilla.org/widget/transferable;1"]
+ .createInstance(Ci.nsITransferable);
+
+ // Add the HTML flavor.
+ transferable.addDataFlavor("text/html");
+ ssHtml.data = dataHtml;
+ transferable.setTransferData("text/html", ssHtml, dataHtml.length * 2);
+
+ // Add the plain text flavor.
+ transferable.addDataFlavor("text/unicode");
+ ssText.data = dataText;
+ transferable.setTransferData("text/unicode", ssText, dataText.length * 2);
+
+ return transferable;
+}
+
+function copyToClipboard() {
+ let transferable = getClipboardTransferable();
+ // Store the data into the clipboard.
+ let clipboard = Cc["@mozilla.org/widget/clipboard;1"]
+ .getService(Ci.nsIClipboard);
+ clipboard.setData(transferable, null, clipboard.kGlobalClipboard);
+}
+
+function sendViaEmail() {
+ // Get the HTML representation for the important part of the page.
+ let hidePrivateData = !document.getElementById("check-show-private-data").checked;
+ let contentsDiv = createCleanedUpContents(hidePrivateData);
+ let dataHtml = contentsDiv.innerHTML;
+ // The editor considers whitespace to be significant, so replace all
+ // whitespace with a single space.
+ dataHtml = dataHtml.replace(/\s+/g, " ");
+
+ // Set up parameters and fields to use for the compose window.
+ let params = Cc["@mozilla.org/messengercompose/composeparams;1"]
+ .createInstance(Ci.nsIMsgComposeParams);
+ params.type = Ci.nsIMsgCompType.New;
+ params.format = Ci.nsIMsgCompFormat.HTML;
+
+ let fields = Cc["@mozilla.org/messengercompose/composefields;1"]
+ .createInstance(Ci.nsIMsgCompFields);
+ fields.forcePlainText = false;
+ fields.body = dataHtml;
+ // In general we can have non-ASCII characters, and compose's charset
+ // detection doesn't seem to work when the HTML part is pure ASCII but the
+ // text isn't. So take the easy way out and force UTF-8.
+ fields.characterSet = "UTF-8";
+ fields.bodyIsAsciiOnly = false;
+ params.composeFields = fields;
+
+ // Our params are set up. Now open a compose window.
+ let composeService = Cc["@mozilla.org/messengercompose;1"]
+ .getService(Ci.nsIMsgComposeService);
+ composeService.OpenComposeWindowWithParams(null, params);
+}
+
+function createCleanedUpContents(aHidePrivateData) {
+ // Get the important part of the page.
+ let contentsDiv = document.getElementById("contents");
+ // Deep-clone the entire div.
+ let clonedDiv = contentsDiv.cloneNode(true);
+ // Go in and replace text with the text we actually want to copy.
+ // (this mutates the cloned node)
+ cleanUpText(clonedDiv, aHidePrivateData);
+ // Insert a warning if we need to
+ if (!aHidePrivateData)
+ clonedDiv.insertBefore(createWarning(), clonedDiv.firstChild);
+ return clonedDiv;
+}
+
+function cleanUpText(aElem, aHidePrivateData) {
+ let node = aElem.firstChild;
+ while (node) {
+ let className = ("className" in node && node.className) || "";
+ // Delete uionly nodes.
+ if (className.indexOf(CLASS_DATA_UIONLY) != -1) {
+ // Advance to the next node before removing the current node, since
+ // node.nextSibling is null after removeChild
+ let nextNode = node.nextSibling;
+ aElem.removeChild(node);
+ node = nextNode;
+ continue;
+ }
+ // Replace private data with a blank string
+ else if (aHidePrivateData && className.indexOf(CLASS_DATA_PRIVATE) != -1) {
+ node.textContent = "";
+ }
+ // Replace public data with a blank string
+ else if (!aHidePrivateData && className.indexOf(CLASS_DATA_PUBLIC) != -1) {
+ node.textContent = "";
+ }
+ else {
+ // Replace localized text with non-localized text
+ let copyData = node.getUserData("copyData");
+ if (copyData != null)
+ node.textContent = copyData;
+ }
+
+ if (node.nodeType == Node.ELEMENT_NODE)
+ cleanUpText(node, aHidePrivateData);
+
+ // Advance!
+ node = node.nextSibling;
+ }
+}
+
+// Return the plain text representation of an element. Do a little bit
+// of pretty-printing to make it human-readable.
+function createTextForElement(elem, aHidePrivateData) {
+ // Generate the initial text.
+ let textFragmentAccumulator = [];
+ generateTextForElement(elem, aHidePrivateData, "", textFragmentAccumulator);
+ let text = textFragmentAccumulator.join("");
+
+ // Trim extraneous whitespace before newlines, then squash extraneous
+ // blank lines.
+ text = text.replace(/[ \t]+\n/g, "\n");
+ text = text.replace(/\n{3,}/g, "\n\n");
+
+ // Actual CR/LF pairs are needed for some Windows text editors.
+ if ("@mozilla.org/windows-registry-key;1" in Cc)
+ text = text.replace(/\n/g, "\r\n");
+
+ return text;
+}
+
+/**
+ * Elements to replace entirely with custom text. Keys are element ids, values
+ * are functions that return the text. The functions themselves are defined in
+ * the files for their respective sections.
+ */
+var gElementsToReplace = {
+ "accounts-table": getAccountsText,
+ "extensions-table": getExtensionsText,
+};
+
+function generateTextForElement(elem, aHidePrivateData, indent,
+ textFragmentAccumulator) {
+ // Add a little extra spacing around most elements.
+ if (["td", "th", "span", "a"].indexOf(elem.tagName) == -1)
+ textFragmentAccumulator.push("\n");
+
+ // If this element is one of our elements to replace with text, do it.
+ if (elem.id in gElementsToReplace) {
+ let replaceFn = gElementsToReplace[elem.id];
+ textFragmentAccumulator.push(replaceFn(aHidePrivateData, indent + " "));
+ return;
+ };
+
+ let childCount = elem.childElementCount;
+
+ // We're not going to spread a two-column <tr> across multiple lines, so
+ // handle that separately.
+ if (elem.tagName == "tr" && childCount == 2) {
+ textFragmentAccumulator.push(indent);
+ textFragmentAccumulator.push(elem.children[0].textContent.trim() + ": " +
+ elem.children[1].textContent.trim());
+ return;
+ }
+
+ // Generate the text representation for each child node.
+ let node = elem.firstChild;
+ while (node) {
+ if (node.nodeType == Node.TEXT_NODE) {
+ // Text belonging to this element uses its indentation level.
+ generateTextForTextNode(node, indent, textFragmentAccumulator);
+ }
+ else if (node.nodeType == Node.ELEMENT_NODE) {
+ // Recurse on the child element with an extra level of indentation (but
+ // only if there's more than one child).
+ generateTextForElement(node, aHidePrivateData,
+ indent + (childCount > 1 ? " " : ""),
+ textFragmentAccumulator);
+ }
+ // Advance!
+ node = node.nextSibling;
+ }
+}
+
+function generateTextForTextNode(node, indent, textFragmentAccumulator) {
+ // If the text node is the first of a run of text nodes, then start
+ // a new line and add the initial indentation.
+ let prevNode = node.previousSibling;
+ if (!prevNode || prevNode.nodeType == Node.TEXT_NODE)
+ textFragmentAccumulator.push("\n" + indent);
+
+ // Trim the text node's text content and add proper indentation after
+ // any internal line breaks.
+ let text = node.textContent.trim().replace("\n", "\n" + indent, "g");
+ textFragmentAccumulator.push(text);
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/extensions.js
@@ -0,0 +1,75 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is aboutSupport.xhtml.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Curtis Bartley <cbartley@mozilla.com>
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * A list of extensions. This is assigned to by
+ * populateExtensionsSection. There's a potential race condition here, but it's
+ * not really going to happen in practice.
+ */
+var gExtensions;
+
+/**
+ * A list of fields for each extension.
+ */
+var gExtensionDetails = ["name", "version", "isActive", "id"];
+
+function populateExtensionsSection() {
+ AddonManager.getAddonsByTypes(["extension"], function (extensions) {
+ gExtensions = extensions;
+ let trExtensions = [];
+ for (let i = 0; i < extensions.length; i++) {
+ let extension = extensions[i];
+ let extensionTDs = [createElement("td", extension[prop])
+ for ([, prop] in Iterator(gExtensionDetails))];
+ let tr = createParentElement("tr", extensionTDs);
+ trExtensions.push(tr);
+ }
+ appendChildren(document.getElementById("extensions-tbody"), trExtensions);
+ });
+}
+
+/**
+ * Returns a plaintext representation of extension data.
+ */
+function getExtensionsText(aHidePrivateData, aIndent) {
+ let extensionData = [aIndent +
+ [extension[prop]
+ for ([, prop] in Iterator(gExtensionDetails))].join(", ")
+ for ([, extension] in Iterator(gExtensions))];
+ return extensionData.join("\n");
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/gfx.js
@@ -0,0 +1,172 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is aboutSupport.xhtml.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Curtis Bartley <cbartley@mozilla.com>
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function populateGraphicsSection() {
+ function createHeader(name)
+ {
+ let elem = createElement("th", name);
+ elem.className = "column";
+ return elem;
+ }
+
+ let bundle = Services.strings.createBundle("chrome://global/locale/aboutSupport.properties");
+ let graphics_tbody = document.getElementById("graphics-tbody");
+
+ var gfxInfo = null;
+ try {
+ // nsIGfxInfo is currently only implemented on Windows
+ gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
+ } catch(e) {}
+
+ if (gfxInfo) {
+ let trGraphics = [];
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("adapterDescription")),
+ createElement("td", gfxInfo.adapterDescription),
+ ]));
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("adapterVendorID")),
+ // pad with zeros. (printf would be nicer)
+ createElement("td", String('0000'+gfxInfo.adapterVendorID.toString(16)).slice(-4)),
+ ]));
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("adapterDeviceID")),
+ // pad with zeros. (printf would be nicer)
+ createElement("td", String('0000'+gfxInfo.adapterDeviceID.toString(16)).slice(-4)),
+ ]));
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("adapterRAM")),
+ createElement("td", gfxInfo.adapterRAM),
+ ]));
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("adapterDrivers")),
+ createElement("td", gfxInfo.adapterDriver),
+ ]));
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("driverVersion")),
+ createElement("td", gfxInfo.adapterDriverVersion),
+ ]));
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("driverDate")),
+ createElement("td", gfxInfo.adapterDriverDate),
+ ]));
+
+ var d2dEnabled = false;
+ try {
+ d2dEnabled = gfxInfo.D2DEnabled;
+ } catch(e) {}
+ var d2dMessage = d2dEnabled;
+ if (!d2dEnabled) {
+ var d2dStatus = -1; // different from any status value defined in the IDL
+ try {
+ d2dStatus = gfxInfo.getFeatureStatus(gfxInfo.FEATURE_DIRECT2D);
+ } catch(e) {
+ window.dump(e + '\n');
+ }
+ if (d2dStatus == gfxInfo.FEATURE_BLOCKED_DEVICE ||
+ d2dStatus == gfxInfo.FEATURE_DISCOURAGED)
+ {
+ d2dMessage = bundle.GetStringFromName("blockedGraphicsCard");
+ }
+ else if (d2dStatus == gfxInfo.FEATURE_BLOCKED_DRIVER_VERSION)
+ {
+ var d2dSuggestedDriverVersion = null;
+ try {
+ d2dSuggestedDriverVersion = gfxInfo.getFeatureSuggestedDriverVersion(gfxInfo.FEATURE_DIRECT2D);
+ } catch(e) {
+ window.dump(e + '\n');
+ }
+ if (d2dSuggestedDriverVersion) {
+ d2dMessage = bundle.GetStringFromName("tryNewerDriverVersion").replace("%1", d2dSuggestedDriverVersion);
+ }
+ }
+ }
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("direct2DEnabled")),
+ createElement("td", d2dMessage),
+ ]));
+
+ var dwEnabled = false;
+ try {
+ dwEnabled = gfxInfo.DWriteEnabled;
+ } catch(e) {}
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("directWriteEnabled")),
+ createElement("td", dwEnabled),
+ ]));
+
+ var webglrenderer;
+ try {
+ webglrenderer = gfxInfo.getWebGLParameter("full-renderer");
+ } catch (e) {
+ webglrenderer = "(WebGL unavailable)";
+ }
+ trGraphics.push(createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("webglRenderer")),
+ createElement("td", webglrenderer)
+ ]));
+
+ appendChildren(graphics_tbody, trGraphics);
+ } // end if (gfxInfo)
+
+ let windows = Services.ww.getWindowEnumerator();
+ let acceleratedWindows = 0;
+ let totalWindows = 0;
+ let mgrType;
+ while (windows.hasMoreElements()) {
+ totalWindows++;
+
+ let awindow = windows.getNext().QueryInterface(Ci.nsIInterfaceRequestor);
+ let windowutils = awindow.getInterface(Ci.nsIDOMWindowUtils);
+ if (windowutils.layerManagerType != "Basic") {
+ acceleratedWindows++;
+ mgrType = windowutils.layerManagerType;
+ }
+ }
+
+ let msg = acceleratedWindows + "/" + totalWindows;
+ if (acceleratedWindows)
+ msg += " " + mgrType;
+
+ appendChildren(graphics_tbody, [
+ createParentElement("tr", [
+ createHeader(bundle.GetStringFromName("acceleratedWindows")),
+ createElement("td", msg),
+ ])
+ ]);
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/hide-private.css
@@ -0,0 +1,44 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Thunderbird about:support.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+.data-private {
+ display: none;
+}
+
+.data-public {
+ display: inline;
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/init.js
@@ -0,0 +1,153 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is aboutSupport.xhtml.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Curtis Bartley <cbartley@mozilla.com>
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+Components.utils.import("resource:///modules/iteratorUtils.jsm");
+Components.utils.import("resource://gre/modules/AddonManager.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+Components.utils.import("resource:///modules/aboutSupport.js");
+
+/* Node classes. All of these are mutually exclusive. */
+
+// Any nodes marked with this class will be considered part of the UI only,
+// and therefore will not be copied.
+const CLASS_DATA_UIONLY = "data-uionly";
+
+// Any nodes marked with this class will be considered private and will be
+// hidden if the user requests only public data to be shown or copied.
+const CLASS_DATA_PRIVATE = "data-private";
+
+// Any nodes marked with this class will only be displayed when the user chooses
+// to not display private data.
+const CLASS_DATA_PUBLIC = "data-public";
+
+window.onload = function () {
+ // Get the support URL.
+ let supportUrl = Services.urlFormatter.formatURLPref("app.support.baseURL");
+
+ // Update the application basics section.
+ document.getElementById("application-box").textContent = Application.name;
+ document.getElementById("version-box").textContent = Application.version;
+ document.getElementById("useragent-box").textContent = navigator.userAgent;
+ document.getElementById("supportLink").href = supportUrl;
+ let currProfD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ appendChildren(document.getElementById("profile-dir-box"),
+ [createElement("a", currProfD.path,
+ {"href": Services.io.newFileURI(currProfD).spec,
+ "onclick": "openProfileDirectory(); event.preventDefault();"
+ })]);
+
+ let fsType;
+ try {
+ fsType = AboutSupport.getFileSystemType(currProfD);
+ }
+ catch (x) {
+ Components.utils.reportError(x);
+ }
+
+ if (fsType) {
+ let bundle = Services.strings.createBundle(
+ "chrome://messenger/locale/aboutSupportMail.properties");
+ let fsText = bundle.GetStringFromName("fsType." + fsType);
+ document.getElementById("profile-fs-type-box").textContent = fsText;
+ }
+
+ document.getElementById("buildid-box").textContent = Services.appinfo.appBuildID;
+
+ // Update the other sections.
+ populateAccountsSection();
+ populatePreferencesSection();
+ populateExtensionsSection();
+ populateGraphicsSection();
+}
+
+function userDataHandler(aOp, aKey, aData, aSrc, aDest) {
+ if (aOp == UserDataHandler.NODE_CLONED || aOp == UserDataHandler.NODE_IMPORTED)
+ aDest.setUserData(aKey, aData, userDataHandler);
+}
+
+function onShowPrivateDataChange(aCheckbox) {
+ document.getElementById("about-support-private").disabled = aCheckbox.checked;
+}
+
+function createParentElement(tagName, childElems) {
+ let elem = document.createElement(tagName);
+ appendChildren(elem, childElems);
+ return elem;
+}
+
+function createElement(tagName, textContent, opt_attributes, opt_copyData) {
+ if (opt_attributes == null)
+ opt_attributes = [];
+ let elem = document.createElement(tagName);
+ elem.textContent = textContent;
+ for each (let [key, value] in Iterator(opt_attributes))
+ elem.setAttribute(key, "" + value);
+
+ if (opt_copyData != null) {
+ // Look for the (only) text node.
+ let textNode = elem.firstChild;
+ while (textNode && textNode.nodeType != Node.TEXT_NODE)
+ textNode = textNode.nextSibling;
+ // XXX warn here if textNode not found
+ if (textNode)
+ textNode.setUserData("copyData", opt_copyData, userDataHandler);
+ }
+
+ return elem;
+}
+
+function appendChildren(parentElem, childNodes) {
+ for (let i = 0; i < childNodes.length; i++)
+ parentElem.appendChild(childNodes[i]);
+}
+
+function openProfileDirectory() {
+ // Get the profile directory.
+ let currProfD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ let profileDir = currProfD.path;
+
+ // Show the profile directory.
+ let nsLocalFile = Components.Constructor("@mozilla.org/file/local;1",
+ "nsILocalFile", "initWithPath");
+ new nsLocalFile(profileDir).reveal();
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/overlay.js
@@ -0,0 +1,45 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Thunderbird about:support.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var AboutSupportOverlay = {
+ openInNewTab: function AboutSupportOverlay_openInNewTab() {
+ let tabmail = document.getElementById("tabmail");
+ tabmail.openTab("contentTab",
+ {contentPage: "about:support",
+ clickHandler: "specialTabs.aboutClickHandler(event);" });
+ }
+};
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/overlay.xul
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is Thunderbird about:support.
+ -
+ - The Initial Developer of the Original Code is
+ - the Mozilla Foundation.
+ - Portions created by the Initial Developer are Copyright (C) 2010
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ - Siddharth Agarwal <sid.bugzilla@gmail.com>
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the GPL or the LGPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+ - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE overlay [
+<!ENTITY % baseMenuOverlayDTD SYSTEM "chrome://messenger/locale/baseMenuOverlay.dtd"> %baseMenuOverlayDTD;
+]>
+
+<overlay id="tb-about-support-overlay"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/x-javascript" src="chrome://messenger/content/about-support/overlay.js" />
+ <menupopup id="menu_HelpPopup">
+ <menuitem id="aboutsupport_open"
+ label="&helpTroubleshootingInfo.label;"
+ accesskey="&helpTroubleshootingInfo.accesskey;"
+ insertafter="menu_openHelp"
+ oncommand="AboutSupportOverlay.openInNewTab();" />
+ </menupopup>
+
+</overlay>
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/prefs.js
@@ -0,0 +1,141 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is aboutSupport.xhtml.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Curtis Bartley <cbartley@mozilla.com>
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis",
+ Ci.nsIPrefLocalizedString).data;
+
+// We use a preferences whitelist to make sure we only show preferences that
+// are useful for support and won't compromise the user's privacy. Note that
+// entries are *prefixes*: for example, "accessibility." applies to all prefs
+// under the "accessibility.*" branch.
+const PREFS_WHITELIST = [
+ "accessibility.",
+ "browser.fixup.",
+ "browser.history_expire_",
+ "browser.link.open_newwindow",
+ "browser.mousewheel.",
+ "browser.places.",
+ "browser.startup.homepage",
+ "browser.tabs.",
+ "browser.zoom.",
+ "dom.",
+ "extensions.checkCompatibility",
+ "extensions.lastAppVersion",
+ "font.",
+ "general.useragent.",
+ "gfx.color_management.mode",
+ "javascript.",
+ "keyword.",
+ "layout.css.dpi",
+ "mail.openMessageBehavior.",
+ "mail.spotlight.",
+ "mail.winsearch.",
+ "mailnews.database.",
+ "network.",
+ "places.",
+ "print.",
+ "privacy.",
+ "security."
+];
+
+// The blacklist, unlike the whitelist, is a list of regular expressions.
+const PREFS_BLACKLIST = [
+ /^network[.]proxy[.]/,
+ /[.]print_to_filename$/,
+ /[.]lastFolderIndexedUri/,
+];
+
+function populatePreferencesSection() {
+ let modifiedPrefs = getModifiedPrefs();
+
+ function comparePrefs(pref1, pref2) {
+ return pref1.name.localeCompare(pref2.name);
+ }
+
+ modifiedPrefs.sort(comparePrefs);
+
+ let trPrefs = [];
+ modifiedPrefs.forEach(function (pref) {
+ let tdName = createElement("td", pref.name, {"class": "pref-name"});
+ let tdValue = createElement("td", formatPrefValue(pref.value),
+ {"class": "pref-value"});
+ let tr = createParentElement("tr", [tdName, tdValue]);
+ trPrefs.push(tr);
+ });
+
+ appendChildren(document.getElementById("prefs-tbody"), trPrefs);
+}
+
+function formatPrefValue(prefValue) {
+ // Some pref values are really long and don't have spaces. This can cause
+ // problems when copying and pasting into some WYSIWYG editors. In general
+ // the exact contents of really long pref values aren't particularly useful,
+ // so we truncate them to some reasonable length.
+ let maxPrefValueLen = 120;
+ let text = "" + prefValue;
+ if (text.length > maxPrefValueLen)
+ text = text.substring(0, maxPrefValueLen) + ELLIPSIS;
+ return text;
+}
+
+function getModifiedPrefs() {
+ // We use the low-level prefs API to identify prefs that have been
+ // modified, rather that Application.prefs.all since the latter is
+ // much, much slower. Application.prefs.all also gets slower each
+ // time it's called. See bug 517312.
+ let prefNames = getWhitelistedPrefNames();
+ let prefs = [Application.prefs.get(prefName)
+ for each (prefName in prefNames)
+ if (Services.prefs.prefHasUserValue(prefName)
+ && !isBlacklisted(prefName))];
+ return prefs;
+}
+
+function getWhitelistedPrefNames() {
+ let results = [];
+ PREFS_WHITELIST.forEach(function (prefStem) {
+ let prefNames = Services.prefs.getChildList(prefStem, {});
+ results = results.concat(prefNames);
+ });
+ return results;
+}
+
+function isBlacklisted(prefName) {
+ return PREFS_BLACKLIST.some(function (re) re.test(prefName));
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/content/show-private.css
@@ -0,0 +1,40 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Thunderbird about:support.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+.data-public {
+ display: none;
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/about-support/jar.mn
@@ -0,0 +1,13 @@
+messenger.jar:
+% overlay chrome://messenger/content/messenger.xul chrome://messenger/content/about-support/overlay.xul
+ content/messenger/about-support/hide-private.css (content/hide-private.css)
+ content/messenger/about-support/show-private.css (content/show-private.css)
+ content/messenger/about-support/init.js (content/init.js)
+ content/messenger/about-support/accounts.js (content/accounts.js)
+ content/messenger/about-support/extensions.js (content/extensions.js)
+ content/messenger/about-support/prefs.js (content/prefs.js)
+ content/messenger/about-support/gfx.js (content/gfx.js)
+ content/messenger/about-support/export.js (content/export.js)
+* content/messenger/about-support/aboutSupport.xhtml (content/aboutSupport.xhtml)
+ content/messenger/about-support/overlay.js (content/overlay.js)
+ content/messenger/about-support/overlay.xul (content/overlay.xul)
--- a/mail/components/aboutRedirector.js
+++ b/mail/components/aboutRedirector.js
@@ -44,21 +44,24 @@ Components.utils.import("resource://gre/
function AboutRedirector() {}
AboutRedirector.prototype = {
classDescription: "Mail about: Redirector",
classID: Components.ID("{8cc51368-6aa0-43e8-b762-bde9b9fd828c}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
// Each entry in the map has the key as the part after the "about:" and the
- // value as a record with url and flags entries.
+ // value as a record with url and flags entries. Note that each addition here
+ // should be coupled with a corresponding addition in mailComponents.manifest.
_redirMap: {
"rights": {url: "chrome://messenger/content/aboutRights.xhtml",
flags: (Ci.nsIAboutModule.ALLOW_SCRIPT |
Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT)},
+ "support": {url: "chrome://messenger/content/about-support/aboutSupport.xhtml",
+ flags: Ci.nsIAboutModule.ALLOW_SCRIPT},
},
/**
* Gets the module name from the given URI.
*/
_getModuleName: function AboutRedirector__getModuleName(aURI) {
// Strip out the first ? or #, and anything following it
let name = (/[^?#]+/.exec(aURI.path))[0];
--- a/mail/components/mailComponents.manifest
+++ b/mail/components/mailComponents.manifest
@@ -1,10 +1,13 @@
component {8cc51368-6aa0-43e8-b762-bde9b9fd828c} aboutRedirector.js
+# Each addition here should be coupled with a corresponding addition in
+# aboutRedirector.js.
contract @mozilla.org/network/protocol/about;1?what=rights {8cc51368-6aa0-43e8-b762-bde9b9fd828c}
+contract @mozilla.org/network/protocol/about;1?what=support {8cc51368-6aa0-43e8-b762-bde9b9fd828c}
component {44346520-c5d2-44e5-a1ec-034e04d7fac4} nsMailDefaultHandler.js
contract @mozilla.org/mail/clh;1 {44346520-c5d2-44e5-a1ec-034e04d7fac4}
category command-line-handler x-default @mozilla.org/mail/clh;1
category command-line-validator b-default @mozilla.org/mail/clh;1
component {1c73f03a-b817-4640-b984-18c3478a9ae3} mailContentHandler.js
contract @mozilla.org/uriloader/content-handler;1?type=text/html {1c73f03a-b817-4640-b984-18c3478a9ae3}
new file mode 100644
--- /dev/null
+++ b/mail/locales/en-US/chrome/messenger/aboutSupportMail.dtd
@@ -0,0 +1,14 @@
+<!ENTITY aboutSupport.appBasicsAppBuildID "Application Build ID">
+
+<!ENTITY aboutSupport.accountsTitle "Mail and News Accounts">
+<!ENTITY aboutSupport.showPrivateData.mainText "Include account names">
+<!ENTITY aboutSupport.showPrivateData.explanationText "(possibly identifying information)">
+<!ENTITY aboutSupport.accountsID "ID">
+<!ENTITY aboutSupport.accountsName "Name">
+<!ENTITY aboutSupport.accountsIncomingServer "Incoming server">
+<!ENTITY aboutSupport.accountsOutgoingServers "Outgoing servers">
+<!ENTITY aboutSupport.accountsConnSecurity "Connection security">
+<!ENTITY aboutSupport.accountsAuthMethod "Authentication method">
+<!ENTITY aboutSupport.accountsDefault "Default?">
+
+<!ENTITY aboutSupport.sendViaEmail.label "Send via email">
new file mode 100644
--- /dev/null
+++ b/mail/locales/en-US/chrome/messenger/aboutSupportMail.properties
@@ -0,0 +1,11 @@
+# LOCALIZATION NOTE (warningLabel): Label for warning text that shows up when private data is included
+warningLabel=WARNING:
+# LOCALIZATION NOTE (warningText): Warning text that shows up when private data is included
+warningText=This contains sensitive information which shouldn't be forwarded or published without permission.
+
+# LOCALIZATION NOTE (fsType.local): Indicator that the displayed directory is on a local drive
+fsType.local = (Local drive)
+# LOCALIZATION NOTE (fsType.network): Indicator that the displayed directory is on the network
+fsType.network = (Network drive)
+# LOCALIZATION NOTE (fsType.unknown): Indicator that we couldn't figure out whether the directory is local or on a network
+fsType.unknown = (Unknown location)
--- a/mail/locales/en-US/chrome/messenger/baseMenuOverlay.dtd
+++ b/mail/locales/en-US/chrome/messenger/baseMenuOverlay.dtd
@@ -1,15 +1,17 @@
<!-- Help Menu -->
<!ENTITY helpMenu.label "Help">
<!ENTITY helpMenu.accesskey "H">
<!-- LOCALIZATION NOTE some localizations of Windows use "?"
for the help button in the menubar but Gnome does not. -->
<!ENTITY helpMenuWin.label "Help">
<!ENTITY helpMenuWin.accesskey "H">
+<!ENTITY helpTroubleshootingInfo.label "Troubleshooting Information">
+<!ENTITY helpTroubleshootingInfo.accesskey "T">
<!ENTITY releaseCmd.label "Release Notes">
<!ENTITY releaseCmd.accesskey "R">
<!ENTITY whatsNewCmd.label "What's New">
<!ENTITY whatsNewCmd.accesskey "W">
<!ENTITY featureConfiguratorCmd.label "Migration Assistant">
<!ENTITY featureConfiguratorCmd.accesskey "M">
<!ENTITY openHelp.label "Help Contents">
<!ENTITY openHelp.accesskey "H">
--- a/mail/locales/jar.mn
+++ b/mail/locales/jar.mn
@@ -4,16 +4,18 @@
@AB_CD@.jar:
% locale messenger @AB_CD@ %locale/@AB_CD@/messenger/
% override chrome://mozapps/locale/downloads/settingsChange.dtd chrome://messenger/locale/downloads/settingsChange.dtd
% override chrome://global/locale/netError.dtd chrome://messenger/locale/netError.dtd
locale/@AB_CD@/messenger/credits.dtd (%chrome/messenger/credits.dtd)
locale/@AB_CD@/messenger/aboutDialog.dtd (%chrome/messenger/aboutDialog.dtd)
locale/@AB_CD@/messenger/aboutRights.dtd (%chrome/messenger/aboutRights.dtd)
locale/@AB_CD@/messenger/aboutRights.properties (%chrome/messenger/aboutRights.properties)
+ locale/@AB_CD@/messenger/aboutSupportMail.dtd (%chrome/messenger/aboutSupportMail.dtd)
+ locale/@AB_CD@/messenger/aboutSupportMail.properties (%chrome/messenger/aboutSupportMail.properties)
locale/@AB_CD@/messenger/accountCreation.dtd (%chrome/messenger/accountCreation.dtd)
locale/@AB_CD@/messenger/accountCreation.properties (%chrome/messenger/accountCreation.properties)
locale/@AB_CD@/messenger/accountCreationModel.properties (%chrome/messenger/accountCreationModel.properties)
locale/@AB_CD@/messenger/accountCreationUtil.properties (%chrome/messenger/accountCreationUtil.properties)
locale/@AB_CD@/messenger/systemIntegrationDialog.dtd (%chrome/messenger/systemIntegrationDialog.dtd)
locale/@AB_CD@/messenger/virtualFolderProperties.dtd (%chrome/messenger/virtualFolderProperties.dtd)
locale/@AB_CD@/messenger/virtualFolderListDialog.dtd (%chrome/messenger/virtualFolderListDialog.dtd)
locale/@AB_CD@/messenger/multimessageview.properties (%chrome/messenger/multimessageview.properties)
new file mode 100644
--- /dev/null
+++ b/mail/test/mozmill/content-tabs/test-about-support.js
@@ -0,0 +1,268 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Thunderbird Mail Client.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var MODULE_NAME = 'test-about-support';
+
+var RELATIVE_ROOT = '../shared-modules';
+var MODULE_REQUIRES = ['folder-display-helpers', 'content-tab-helpers'];
+
+var controller = {};
+Components.utils.import('resource://mozmill/modules/controller.js', controller);
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+function setupModule(module) {
+ let fdh = collector.getModule("folder-display-helpers");
+ fdh.installInto(module);
+ let cth = collector.getModule("content-tab-helpers");
+ cth.installInto(module);
+}
+
+// After every test we want to close the about:support tab so that failures
+// don't cascade.
+function teardownTest(module) {
+ mc.tabmail.closeOtherTabs(mc.tabmail.tabInfo[0]);
+}
+
+/**
+ * Strings found in the about:support HTML or text that should clearly mark the
+ * data as being from about:support.
+ */
+const ABOUT_SUPPORT_STRINGS = ["Application Basics", "Mail and News Accounts",
+ "Extensions", "Modified Preferences", "Graphics"];
+
+/**
+ * Strings that if found in the about:support text or HTML usually indicate an
+ * error.
+ */
+const ABOUT_SUPPORT_ERROR_STRINGS = ["undefined", "null"];
+
+
+/*
+ * Helpers
+ */
+
+/**
+ * Opens about:support and waits for it to load.
+ *
+ * @returns the about:support tab.
+ */
+function open_about_support() {
+ let tab = open_content_tab_with_click(mc.menus.helpMenu.aboutsupport_open);
+ assert_content_tab_has_url(tab, "about:support");
+ // We have one variable that's asynchronously populated -- wait for it to be
+ // populated.
+ if (!controller.waitForEval("subject.gExtensions !== undefined",
+ NORMAL_TIMEOUT, FAST_INTERVAL,
+ tab.browser.contentWindow)) {
+ mark_failure(["Timeout waiting for about:support's gExtensions to populate."]);
+ }
+ return tab;
+}
+
+
+/*
+ * Tests
+ */
+
+/**
+ * Test displaying the about:support page. Also perform a couple of basic tests
+ * to check that no major errors have occurred. The basic tests are by no means
+ * comprehensive.
+ */
+function test_display_about_support() {
+ let tab = open_about_support();
+ // Check that the document has a few strings that indicate that we've loaded
+ // the right page.
+ for (let [, str] in Iterator(ABOUT_SUPPORT_STRINGS)) {
+ assert_content_tab_text_present(tab, str);
+ }
+
+ // Check that error strings aren't present anywhere
+ for (let [, str] in Iterator(ABOUT_SUPPORT_ERROR_STRINGS)) {
+ assert_content_tab_text_absent(tab, str);
+ }
+ close_tab(tab);
+}
+
+const UNIQUE_ID = "3a9e1694-7115-4237-8b1e-1cabe6e35073";
+
+/**
+ * Test that a modified preference on the whitelist but not on the blacklist
+ * shows up.
+ */
+function test_modified_pref_on_whitelist() {
+ const PREFIX = "accessibility.";
+ let prefName = PREFIX + UNIQUE_ID;
+ Services.prefs.setBoolPref(prefName, true);
+ let tab = open_about_support();
+ // Check that the prefix is actually in the whitelist.
+ if (tab.browser.contentWindow.PREFS_WHITELIST.indexOf(PREFIX) == -1)
+ mark_failure(["The prefs whitelist doesn't contain " + PREFIX]);
+
+ assert_content_tab_text_present(tab, prefName);
+ close_tab(tab);
+ Services.prefs.clearUserPref(prefName);
+}
+
+/**
+ * Test that a modified preference not on the whitelist doesn't show up.
+ */
+function test_modified_pref_not_on_whitelist() {
+ Services.prefs.setBoolPref(UNIQUE_ID, true);
+ let tab = open_about_support();
+ assert_content_tab_text_absent(tab, UNIQUE_ID);
+ close_tab(tab);
+ Services.prefs.clearUserPref(UNIQUE_ID);
+}
+
+/**
+ * Test that a modified preference on the blacklist doesn't show up.
+ */
+function test_modified_pref_on_blacklist() {
+ const PREFIX = "network.proxy.";
+ let prefName = PREFIX + UNIQUE_ID;
+ Services.prefs.setBoolPref(prefName, true);
+ let tab = open_about_support();
+ // Check that the prefix is in the blacklist.
+ if (!tab.browser.contentWindow.PREFS_BLACKLIST.some(
+ function(regex) regex.test(PREFIX))) {
+ mark_failure(["The prefs blacklist doesn't include " + PREFIX]);
+ }
+ assert_content_tab_text_absent(tab, prefName);
+ close_tab(tab);
+ Services.prefs.clearUserPref(prefName);
+}
+
+/**
+ * Test that private data isn't displayed by default, and that when it is
+ * displayed, it actually shows up.
+ */
+function test_private_data() {
+ let tab = open_about_support();
+ let checkbox = content_tab_e(tab, "check-show-private-data");
+ // We use the profile button's div as an example of a public-only element, and
+ // the profile directory display as an example of a private-only element.
+ let privateElem = content_tab_e(tab, "profile-dir-box");
+ let publicElem = content_tab_e(tab, "profile-dir-button-box");
+ assert_true(!checkbox.checked,
+ "Private data checkbox shouldn't be checked by default");
+ assert_element_visible(tab, publicElem);
+ assert_element_hidden(tab, privateElem);
+
+ // Now check the checkbox and see what happens
+ checkbox.click();
+ wait_for_element_display_value(tab, publicElem, "none");
+ wait_for_element_display_value(tab, privateElem, "inline");
+ close_tab(tab);
+}
+
+/**
+ * Test (well, sort of) the copy to clipboard function with public data.
+ */
+function test_copy_to_clipboard_public() {
+ let tab = open_about_support();
+ // To avoid destroying the current contents of the clipboard, instead of
+ // actually copying to it, we just retrieve what would have been copied to it
+ let transferable = tab.browser.contentWindow.getClipboardTransferable();
+ for (let [, flavor] in Iterator(["text/html", "text/unicode"])) {
+ let data = {};
+ transferable.getTransferData(flavor, data, {});
+ let text = data.value.data;
+
+ for (let [, str] in Iterator(ABOUT_SUPPORT_STRINGS)) {
+ if (text.indexOf(str) == -1)
+ mark_failure(["Unable to find \"" + str + "\" in flavor \"" + flavor + "\""]);
+ }
+
+ for (let [, str] in Iterator(ABOUT_SUPPORT_ERROR_STRINGS)) {
+ if (text.indexOf(str) != -1)
+ mark_failure(["Found \"" + str + "\" in flavor \"" + flavor + "\""]);
+ }
+
+ // Check that private data (profile directory) isn't in the output.
+ let profD = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
+ if (text.indexOf(profD) != -1)
+ mark_failure(["Found profile directory in flavor \"" + flavor + "\""]);
+ }
+ close_tab(tab);
+}
+
+/**
+ * Test (well, sort of) the copy to clipboard function with private data.
+ */
+function test_copy_to_clipboard_private() {
+ let bundle = Services.strings.createBundle(
+ "chrome://messenger/locale/aboutSupportMail.properties");
+ let warningText = bundle.GetStringFromName("warningText");
+
+ let tab = open_about_support();
+
+ // Display private data.
+ let privateElem = content_tab_e(tab, "profile-dir-box");
+ content_tab_e(tab, "check-show-private-data").click();
+ wait_for_element_display_value(tab, privateElem, "inline");
+
+ // To avoid destroying the current contents of the clipboard, instead of
+ // actually copying to it, we just retrieve what would have been copied to it
+ let transferable = tab.browser.contentWindow.getClipboardTransferable();
+ for (let [, flavor] in Iterator(["text/html", "text/unicode"])) {
+ let data = {};
+ transferable.getTransferData(flavor, data, {});
+ let text = data.value.data;
+
+ for (let [, str] in Iterator(ABOUT_SUPPORT_STRINGS)) {
+ if (text.indexOf(str) == -1)
+ mark_failure(["Unable to find \"" + str + "\" in flavor \"" + flavor + "\""]);
+ }
+
+ for (let [, str] in Iterator(ABOUT_SUPPORT_ERROR_STRINGS)) {
+ if (text.indexOf(str) != -1)
+ mark_failure(["Found \"" + str + "\" in flavor \"" + flavor + "\""]);
+ }
+
+ // Check that private data (profile directory) is in the output.
+ let profD = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
+ if (text.indexOf(profD) == -1)
+ mark_failure(["Unable to find profile directory in flavor \"" + flavor + "\""]);
+
+ // Check that the warning text is in the output.
+ if (text.indexOf(warningText) == -1)
+ mark_failure(["Unable to find warning text in flavor \"" + flavor + "\""]);
+ }
+ close_tab(tab);
+}
--- a/mail/test/mozmill/shared-modules/test-content-tab-helpers.js
+++ b/mail/test/mozmill/shared-modules/test-content-tab-helpers.js
@@ -73,16 +73,23 @@ function installInto(module) {
setupModule();
// Now copy helper functions
module.open_content_tab_with_url = open_content_tab_with_url;
module.open_content_tab_with_click = open_content_tab_with_click;
module.plan_for_content_tab_load = plan_for_content_tab_load;
module.wait_for_content_tab_load = wait_for_content_tab_load;
module.assert_content_tab_has_url = assert_content_tab_has_url;
+ module.content_tab_e = content_tab_e;
+ module.get_element_display = get_element_display;
+ module.assert_element_hidden = assert_element_hidden;
+ module.assert_element_visible = assert_element_visible;
+ module.wait_for_element_display_value = wait_for_element_display_value;
+ module.assert_content_tab_text_present = assert_content_tab_text_present;
+ module.assert_content_tab_text_absent = assert_content_tab_text_absent;
}
/**
* Opens a content tab with the given URL.
*
* @param aURL The URL to load (string).
* @param [aBackground] Whether the tab is opened in the background. Defaults to
* false.
@@ -130,16 +137,17 @@ function open_content_tab_with_click(aEl
if (!controller.waitForEval("subject.childNodes.length == " + (preCount + 1),
FAST_TIMEOUT, FAST_INTERVAL,
aController.tabmail.tabContainer))
mark_failure(["Timeout waiting for the content tab to open"]);
// We append new tabs at the end, so check the last one.
let expectedNewTab = aController.tabmail.tabInfo[preCount];
folderDisplayHelper.assert_selected_tab(expectedNewTab);
+ folderDisplayHelper.assert_tab_mode_name(expectedNewTab, "contentTab");
wait_for_content_tab_load(expectedNewTab);
return expectedNewTab;
}
/**
* Call this before triggering a page load that you are going to wait for using
* |wait_for_content_tab_load|. This ensures that if a page is already displayed
* in the given tab that state is sufficiently cleaned up so it doesn't trick us
@@ -189,8 +197,79 @@ function wait_for_content_tab_load(aTab)
/**
* Assert that the given content tab has the given URL (string) loaded.
*/
function assert_content_tab_has_url(aTab, aURL) {
if (aTab.browser.currentURI.spec != aURL)
mark_failure(["The tab", aTab, "should have URL", aURL, "but instead has",
aTab.browser.currentURI.spec]);
}
+
+/**
+ * Get the element with the given ID from the content tab's displayed page.
+ */
+function content_tab_e(aTab, aId) {
+ return aTab.browser.contentDocument.getElementById(aId);
+}
+
+/**
+ * Returns the current "display" style property of an element.
+ */
+function get_element_display(aTab, aElem) {
+ let style = aTab.browser.contentWindow.getComputedStyle(aElem);
+ return style.getPropertyValue("display");
+}
+
+/**
+ * Asserts that the given element is hidden from view on the page.
+ */
+function assert_element_hidden(aTab, aElem) {
+ let display = get_element_display(aTab, aElem);
+ if (display != "none") {
+ mark_failure(["Element", aElem, "should be hidden but has display", display,
+ "instead"]);
+ }
+}
+
+/**
+ * Asserts that the given element is visible on the page.
+ */
+function assert_element_visible(aTab, aElem) {
+ let display = get_element_display(aTab, aElem);
+ if (display != "inline") {
+ mark_failure(["Element", aElem, "should be visible but has display", display,
+ "instead"]);
+ }
+}
+
+/**
+ * Waits for the element's display property to be the given value.
+ */
+function wait_for_element_display_value(aTab, aElem, aValue) {
+ function isValue() {
+ return get_element_display(aTab, aElem) == aValue;
+ }
+ if (!controller.waitForEval("subject()", NORMAL_TIMEOUT, FAST_INTERVAL,
+ isValue)) {
+ mark_failure(["Timeout waiting for element", aElem, "to have display value",
+ aValue]);
+ }
+}
+
+/**
+ * Asserts that the given text is present on the content tab's page.
+ */
+function assert_content_tab_text_present(aTab, aText) {
+ let html = aTab.browser.contentDocument.documentElement.innerHTML;
+ if (html.indexOf(aText) == -1) {
+ mark_failure(["Unable to find string \"" + aText + "\" on the content tab's page"]);
+ }
+}
+
+/**
+ * Asserts that the given text is absent on the content tab's page.
+ */
+function assert_content_tab_text_absent(aTab, aText) {
+ let html = aTab.browser.contentDocument.documentElement.innerHTML;
+ if (html.indexOf(aText) != -1) {
+ mark_failure(["Found string \"" + aText + "\" on the content tab's page"]);
+ }
+}
--- a/mail/themes/gnomestripe/jar.mn
+++ b/mail/themes/gnomestripe/jar.mn
@@ -3,16 +3,17 @@ classic.jar:
% skin messenger classic/1.0 %skin/classic/messenger/
skin/classic/messenger/featureConfigurator.css (mail/featureConfigurator.css)
skin/classic/messenger/featureConfigurators/subpage.css (mail/featureConfigurators/subpage.css)
skin/classic/messenger/featureConfigurators/animation.png (mail/featureConfigurators/animation.png)
skin/classic/messenger/featureConfigurators/compact-header.png (mail/featureConfigurators/compact-header.png)
skin/classic/messenger/featureConfigurators/folder-columns.png (mail/featureConfigurators/folder-columns.png)
skin/classic/messenger/featureConfigurators/toolbars.png (mail/featureConfigurators/toolbars.png)
skin/classic/messenger/primaryToolbar.css (mail/primaryToolbar.css)
+ skin/classic/messenger/aboutSupport.css (../qute/mail/aboutSupport.css)
skin/classic/messenger/accountCentral.css (mail/accountCentral.css)
skin/classic/messenger/accountCreation.css (mail/accountCreation.css)
skin/classic/messenger/accountManage.css (mail/accountManage.css)
skin/classic/messenger/accountWizard.css (mail/accountWizard.css)
skin/classic/messenger/section_collapsed.png (mail/section_collapsed.png)
skin/classic/messenger/section_expanded.png (mail/section_expanded.png)
skin/classic/messenger/messageHeader.css (mail/messageHeader.css)
skin/classic/messenger/messageBody.css (mail/messageBody.css)
--- a/mail/themes/pinstripe/jar.mn
+++ b/mail/themes/pinstripe/jar.mn
@@ -6,16 +6,17 @@ classic.jar:
skin/classic/messenger/featureConfigurators/compact-header.png (mail/featureConfigurators/compact-header.png)
skin/classic/messenger/featureConfigurators/folder-columns.png (mail/featureConfigurators/folder-columns.png)
skin/classic/messenger/featureConfigurators/toolbars.png (mail/featureConfigurators/toolbars.png)
skin/classic/messenger/glodaFacetView.css (mail/glodaFacetView.css)
skin/classic/messenger/multimessageview.css (mail/multimessageview.css)
skin/classic/messenger/dialogs.css (mail/dialogs.css)
skin/classic/messenger/messenger.css (mail/messenger.css)
skin/classic/messenger/primaryToolbar.css (mail/primaryToolbar.css)
+ skin/classic/messenger/aboutSupport.css (../qute/mail/aboutSupport.css)
skin/classic/messenger/accountCentral.css (mail/accountCentral.css)
skin/classic/messenger/accountCreation.css (mail/accountCreation.css)
skin/classic/messenger/accountManage.css (mail/accountManage.css)
skin/classic/messenger/accountWizard.css (mail/accountWizard.css)
skin/classic/messenger/section_collapsed.png (mail/section_collapsed.png)
skin/classic/messenger/section_expanded.png (mail/section_expanded.png)
skin/classic/messenger/messageHeader.css (mail/messageHeader.css)
skin/classic/messenger/messageWindow.css (mail/messageWindow.css)
--- a/mail/themes/qute/jar.mn
+++ b/mail/themes/qute/jar.mn
@@ -43,16 +43,17 @@ classic.jar:
% skin messenger classic/1.0 %skin/classic/messenger/ os!=WINNT
skin/classic/messenger/featureConfigurator.css (mail/featureConfigurator.css)
skin/classic/messenger/featureConfigurators/subpage.css (mail/featureConfigurators/subpage.css)
skin/classic/messenger/featureConfigurators/animation.png (mail/featureConfigurators/animation.png)
skin/classic/messenger/featureConfigurators/compact-header.png (mail/featureConfigurators/compact-header.png)
skin/classic/messenger/featureConfigurators/folder-columns.png (mail/featureConfigurators/folder-columns.png)
skin/classic/messenger/featureConfigurators/toolbars.png (mail/featureConfigurators/toolbars.png)
skin/classic/messenger/primaryToolbar.css (mail/primaryToolbar.css)
+ skin/classic/messenger/aboutSupport.css (mail/aboutSupport.css)
skin/classic/messenger/accountCentral.css (mail/accountCentral.css)
skin/classic/messenger/accountCreation.css (mail/accountCreation.css)
skin/classic/messenger/accountManage.css (mail/accountManage.css)
skin/classic/messenger/accountWizard.css (mail/accountWizard.css)
skin/classic/messenger/section_collapsed.png (mail/section_collapsed.png)
skin/classic/messenger/section_expanded.png (mail/section_expanded.png)
skin/classic/messenger/messageHeader.css (mail/messageHeader.css)
skin/classic/messenger/messageBody.css (mail/messageBody.css)
@@ -271,16 +272,17 @@ classic.jar:
% skin messenger classic/1.0 %skin/classic/aero/messenger/ os=WINNT osversion>=6
skin/classic/aero/messenger/featureConfigurator.css (mail/featureConfigurator.css)
skin/classic/aero/messenger/featureConfigurators/subpage.css (mail/featureConfigurators/subpage.css)
skin/classic/aero/messenger/featureConfigurators/animation.png (mail/featureConfigurators/animation.png)
skin/classic/aero/messenger/featureConfigurators/compact-header.png (mail/featureConfigurators/compact-header.png)
skin/classic/aero/messenger/featureConfigurators/folder-columns.png (mail/featureConfigurators/folder-columns.png)
skin/classic/aero/messenger/featureConfigurators/toolbars.png (mail/featureConfigurators/toolbars.png)
* skin/classic/aero/messenger/primaryToolbar.css (mail/primaryToolbar-aero.css)
+ skin/classic/aero/messenger/aboutSupport.css (mail/aboutSupport.css)
skin/classic/aero/messenger/accountCentral.css (mail/accountCentral.css)
skin/classic/aero/messenger/accountCreation.css (mail/accountCreation.css)
skin/classic/aero/messenger/accountManage.css (mail/accountManage.css)
skin/classic/aero/messenger/accountWizard.css (mail/accountWizard.css)
skin/classic/aero/messenger/section_collapsed.png (mail/section_collapsed.png)
skin/classic/aero/messenger/section_expanded.png (mail/section_expanded.png)
* skin/classic/aero/messenger/messageHeader.css (mail/messageHeader-aero.css)
skin/classic/aero/messenger/messageBody.css (mail/messageBody.css)
new file mode 100644
--- /dev/null
+++ b/mail/themes/qute/mail/aboutSupport.css
@@ -0,0 +1,50 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is aboutSupport.css.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+.gray-text {
+ color: GrayText;
+}
+
+.thead-level2 > th {
+ background-color: -moz-Dialog;
+ color: -moz-DialogText;
+}
+
+td.data-private {
+ background-color: infobackground;
+ color: infotext;
+}