/browser/components/search/nsSearchService.js
JavaScript | 3199 lines | 2060 code | 452 blank | 687 comment | 309 complexity | 72265a636c3a10096ba296862d48b7e9 MD5 | raw file
Possible License(s): LGPL-3.0, MIT, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- # ***** 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 the Browser Search Service.
- #
- # The Initial Developer of the Original Code is
- # Google Inc.
- # Portions created by the Initial Developer are Copyright (C) 2005-2006
- # the Initial Developer. All Rights Reserved.
- #
- # Contributor(s):
- # Ben Goodger <beng@google.com> (Original author)
- # Gavin Sharp <gavin@gavinsharp.com>
- # Joe Hughes <joe@retrovirus.com>
- # Pamela Greene <pamg.bugs@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 Ci = Components.interfaces;
- const Cc = Components.classes;
- const Cr = Components.results;
- const PERMS_FILE = 0644;
- const PERMS_DIRECTORY = 0755;
- const MODE_RDONLY = 0x01;
- const MODE_WRONLY = 0x02;
- const MODE_CREATE = 0x08;
- const MODE_APPEND = 0x10;
- const MODE_TRUNCATE = 0x20;
- // Directory service keys
- const NS_APP_SEARCH_DIR_LIST = "SrchPluginsDL";
- const NS_APP_USER_SEARCH_DIR = "UsrSrchPlugns";
- const NS_APP_SEARCH_DIR = "SrchPlugns";
- const NS_APP_USER_PROFILE_50_DIR = "ProfD";
- // Search engine "locations". If this list is changed, be sure to update
- // the engine's _isDefault function accordingly.
- const SEARCH_APP_DIR = 1;
- const SEARCH_PROFILE_DIR = 2;
- const SEARCH_IN_EXTENSION = 3;
- // See documentation in nsIBrowserSearchService.idl.
- const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
- const QUIT_APPLICATION_TOPIC = "quit-application";
- const SEARCH_ENGINE_REMOVED = "engine-removed";
- const SEARCH_ENGINE_ADDED = "engine-added";
- const SEARCH_ENGINE_CHANGED = "engine-changed";
- const SEARCH_ENGINE_LOADED = "engine-loaded";
- const SEARCH_ENGINE_CURRENT = "engine-current";
- const SEARCH_TYPE_MOZSEARCH = Ci.nsISearchEngine.TYPE_MOZSEARCH;
- const SEARCH_TYPE_OPENSEARCH = Ci.nsISearchEngine.TYPE_OPENSEARCH;
- const SEARCH_TYPE_SHERLOCK = Ci.nsISearchEngine.TYPE_SHERLOCK;
- const SEARCH_DATA_XML = Ci.nsISearchEngine.DATA_XML;
- const SEARCH_DATA_TEXT = Ci.nsISearchEngine.DATA_TEXT;
- // File extensions for search plugin description files
- const XML_FILE_EXT = "xml";
- const SHERLOCK_FILE_EXT = "src";
- // Delay for lazy serialization (ms)
- const LAZY_SERIALIZE_DELAY = 100;
- const ICON_DATAURL_PREFIX = "data:image/x-icon;base64,";
- // Supported extensions for Sherlock plugin icons
- const SHERLOCK_ICON_EXTENSIONS = [".gif", ".png", ".jpg", ".jpeg"];
- const NEW_LINES = /(\r\n|\r|\n)/;
- // Set an arbitrary cap on the maximum icon size. Without this, large icons can
- // cause big delays when loading them at startup.
- const MAX_ICON_SIZE = 10000;
- // Default charset to use for sending search parameters. ISO-8859-1 is used to
- // match previous nsInternetSearchService behavior.
- const DEFAULT_QUERY_CHARSET = "ISO-8859-1";
- const SEARCH_BUNDLE = "chrome://browser/locale/search.properties";
- const BRAND_BUNDLE = "chrome://branding/locale/brand.properties";
- const OPENSEARCH_NS_10 = "http://a9.com/-/spec/opensearch/1.0/";
- const OPENSEARCH_NS_11 = "http://a9.com/-/spec/opensearch/1.1/";
- // Although the specification at http://opensearch.a9.com/spec/1.1/description/
- // gives the namespace names defined above, many existing OpenSearch engines
- // are using the following versions. We therefore allow either.
- const OPENSEARCH_NAMESPACES = [
- OPENSEARCH_NS_11, OPENSEARCH_NS_10,
- "http://a9.com/-/spec/opensearchdescription/1.1/",
- "http://a9.com/-/spec/opensearchdescription/1.0/"
- ];
- const OPENSEARCH_LOCALNAME = "OpenSearchDescription";
- const MOZSEARCH_NS_10 = "http://www.mozilla.org/2006/browser/search/";
- const MOZSEARCH_LOCALNAME = "SearchPlugin";
- const URLTYPE_SUGGEST_JSON = "application/x-suggestions+json";
- const URLTYPE_SEARCH_HTML = "text/html";
- // Empty base document used to serialize engines to file.
- const EMPTY_DOC = "<?xml version=\"1.0\"?>\n" +
- "<" + MOZSEARCH_LOCALNAME +
- " xmlns=\"" + MOZSEARCH_NS_10 + "\"" +
- " xmlns:os=\"" + OPENSEARCH_NS_11 + "\"" +
- "/>";
- const BROWSER_SEARCH_PREF = "browser.search.";
- const USER_DEFINED = "{searchTerms}";
- // Custom search parameters
- #ifdef OFFICIAL_BUILD
- const MOZ_OFFICIAL = "official";
- #else
- const MOZ_OFFICIAL = "unofficial";
- #endif
- #expand const MOZ_DISTRIBUTION_ID = __MOZ_DISTRIBUTION_ID__;
- const MOZ_PARAM_LOCALE = /\{moz:locale\}/g;
- const MOZ_PARAM_DIST_ID = /\{moz:distributionID\}/g;
- const MOZ_PARAM_OFFICIAL = /\{moz:official\}/g;
- // Supported OpenSearch parameters
- // See http://opensearch.a9.com/spec/1.1/querysyntax/#core
- const OS_PARAM_USER_DEFINED = /\{searchTerms\??\}/g;
- const OS_PARAM_INPUT_ENCODING = /\{inputEncoding\??\}/g;
- const OS_PARAM_LANGUAGE = /\{language\??\}/g;
- const OS_PARAM_OUTPUT_ENCODING = /\{outputEncoding\??\}/g;
- // Default values
- const OS_PARAM_LANGUAGE_DEF = "*";
- const OS_PARAM_OUTPUT_ENCODING_DEF = "UTF-8";
- const OS_PARAM_INPUT_ENCODING_DEF = "UTF-8";
- // "Unsupported" OpenSearch parameters. For example, we don't support
- // page-based results, so if the engine requires that we send the "page index"
- // parameter, we'll always send "1".
- const OS_PARAM_COUNT = /\{count\??\}/g;
- const OS_PARAM_START_INDEX = /\{startIndex\??\}/g;
- const OS_PARAM_START_PAGE = /\{startPage\??\}/g;
- // Default values
- const OS_PARAM_COUNT_DEF = "20"; // 20 results
- const OS_PARAM_START_INDEX_DEF = "1"; // start at 1st result
- const OS_PARAM_START_PAGE_DEF = "1"; // 1st page
- // Optional parameter
- const OS_PARAM_OPTIONAL = /\{(?:\w+:)?\w+\?\}/g;
- // A array of arrays containing parameters that we don't fully support, and
- // their default values. We will only send values for these parameters if
- // required, since our values are just really arbitrary "guesses" that should
- // give us the output we want.
- var OS_UNSUPPORTED_PARAMS = [
- [OS_PARAM_COUNT, OS_PARAM_COUNT_DEF],
- [OS_PARAM_START_INDEX, OS_PARAM_START_INDEX_DEF],
- [OS_PARAM_START_PAGE, OS_PARAM_START_PAGE_DEF],
- ];
- // The default engine update interval, in days. This is only used if an engine
- // specifies an updateURL, but not an updateInterval.
- const SEARCH_DEFAULT_UPDATE_INTERVAL = 7;
- // Returns false for whitespace-only or commented out lines in a
- // Sherlock file, true otherwise.
- function isUsefulLine(aLine) {
- return !(/^\s*($|#)/i.test(aLine));
- }
- /**
- * Prefixed to all search debug output.
- */
- const SEARCH_LOG_PREFIX = "*** Search: ";
- /**
- * Outputs aText to the JavaScript console as well as to stdout.
- */
- function DO_LOG(aText) {
- dump(SEARCH_LOG_PREFIX + aText + "\n");
- var consoleService = Cc["@mozilla.org/consoleservice;1"].
- getService(Ci.nsIConsoleService);
- consoleService.logStringMessage(aText);
- }
- #ifdef DEBUG
- /**
- * In debug builds, use a live, pref-based (browser.search.log) LOG function
- * to allow enabling/disabling without a restart.
- */
- function PREF_LOG(aText) {
- var prefB = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch);
- var shouldLog = false;
- try {
- shouldLog = prefB.getBoolPref(BROWSER_SEARCH_PREF + "log");
- } catch (ex) {}
- if (shouldLog) {
- DO_LOG(aText);
- }
- }
- var LOG = PREF_LOG;
- #else
- /**
- * Otherwise, don't log at all by default. This can be overridden at startup
- * by the pref, see SearchService's _init method.
- */
- var LOG = function(){};
- #endif
- function ERROR(message, resultCode) {
- NS_ASSERT(false, SEARCH_LOG_PREFIX + message);
- throw resultCode;
- }
- /**
- * Ensures an assertion is met before continuing. Should be used to indicate
- * fatal errors.
- * @param assertion
- * An assertion that must be met
- * @param message
- * A message to display if the assertion is not met
- * @param resultCode
- * The NS_ERROR_* value to throw if the assertion is not met
- * @throws resultCode
- */
- function ENSURE_WARN(assertion, message, resultCode) {
- NS_ASSERT(assertion, SEARCH_LOG_PREFIX + message);
- if (!assertion)
- throw resultCode;
- }
- /**
- * Ensures an assertion is met before continuing, but does not warn the user.
- * Used to handle normal failure conditions.
- * @param assertion
- * An assertion that must be met
- * @param message
- * A message to display if the assertion is not met
- * @param resultCode
- * The NS_ERROR_* value to throw if the assertion is not met
- * @throws resultCode
- */
- function ENSURE(assertion, message, resultCode) {
- if (!assertion) {
- LOG(message);
- throw resultCode;
- }
- }
- /**
- * Ensures an argument assertion is met before continuing.
- * @param assertion
- * An argument assertion that must be met
- * @param message
- * A message to display if the assertion is not met
- * @throws NS_ERROR_INVALID_ARG for invalid arguments
- */
- function ENSURE_ARG(assertion, message) {
- ENSURE(assertion, message, Cr.NS_ERROR_INVALID_ARG);
- }
- function loadListener(aChannel, aEngine, aCallback) {
- this._channel = aChannel;
- this._bytes = [];
- this._engine = aEngine;
- this._callback = aCallback;
- }
- loadListener.prototype = {
- _callback: null,
- _channel: null,
- _countRead: 0,
- _engine: null,
- _stream: null,
- QueryInterface: function SRCH_loadQI(aIID) {
- if (aIID.equals(Ci.nsISupports) ||
- aIID.equals(Ci.nsIRequestObserver) ||
- aIID.equals(Ci.nsIStreamListener) ||
- aIID.equals(Ci.nsIChannelEventSink) ||
- aIID.equals(Ci.nsIInterfaceRequestor) ||
- aIID.equals(Ci.nsIBadCertListener2) ||
- aIID.equals(Ci.nsISSLErrorListener) ||
- // See FIXME comment below
- aIID.equals(Ci.nsIHttpEventSink) ||
- aIID.equals(Ci.nsIProgressEventSink) ||
- false)
- return this;
- throw Cr.NS_ERROR_NO_INTERFACE;
- },
- // nsIRequestObserver
- onStartRequest: function SRCH_loadStartR(aRequest, aContext) {
- LOG("loadListener: Starting request: " + aRequest.name);
- this._stream = Cc["@mozilla.org/binaryinputstream;1"].
- createInstance(Ci.nsIBinaryInputStream);
- },
- onStopRequest: function SRCH_loadStopR(aRequest, aContext, aStatusCode) {
- LOG("loadListener: Stopping request: " + aRequest.name);
- var requestFailed = !Components.isSuccessCode(aStatusCode);
- if (!requestFailed && (aRequest instanceof Ci.nsIHttpChannel))
- requestFailed = !aRequest.requestSucceeded;
- if (requestFailed || this._countRead == 0) {
- LOG("loadListener: request failed!");
- // send null so the callback can deal with the failure
- this._callback(null, this._engine);
- } else
- this._callback(this._bytes, this._engine);
- this._channel = null;
- this._engine = null;
- },
- // nsIStreamListener
- onDataAvailable: function SRCH_loadDAvailable(aRequest, aContext,
- aInputStream, aOffset,
- aCount) {
- this._stream.setInputStream(aInputStream);
- // Get a byte array of the data
- this._bytes = this._bytes.concat(this._stream.readByteArray(aCount));
- this._countRead += aCount;
- },
- // nsIChannelEventSink
- onChannelRedirect: function SRCH_loadCRedirect(aOldChannel, aNewChannel,
- aFlags) {
- this._channel = aNewChannel;
- },
- // nsIInterfaceRequestor
- getInterface: function SRCH_load_GI(aIID) {
- return this.QueryInterface(aIID);
- },
- // nsIBadCertListener2
- notifyCertProblem: function SRCH_certProblem(socketInfo, status, targetSite) {
- return true;
- },
- // nsISSLErrorListener
- notifySSLError: function SRCH_SSLError(socketInfo, error, targetSite) {
- return true;
- },
- // FIXME: bug 253127
- // nsIHttpEventSink
- onRedirect: function (aChannel, aNewChannel) {},
- // nsIProgressEventSink
- onProgress: function (aRequest, aContext, aProgress, aProgressMax) {},
- onStatus: function (aRequest, aContext, aStatus, aStatusArg) {}
- }
- /**
- * Used to verify a given DOM node's localName and namespaceURI.
- * @param aElement
- * The element to verify.
- * @param aLocalNameArray
- * An array of strings to compare against aElement's localName.
- * @param aNameSpaceArray
- * An array of strings to compare against aElement's namespaceURI.
- *
- * @returns false if aElement is null, or if its localName or namespaceURI
- * does not match one of the elements in the aLocalNameArray or
- * aNameSpaceArray arrays, respectively.
- * @throws NS_ERROR_INVALID_ARG if aLocalNameArray or aNameSpaceArray are null.
- */
- function checkNameSpace(aElement, aLocalNameArray, aNameSpaceArray) {
- ENSURE_ARG(aLocalNameArray && aNameSpaceArray, "missing aLocalNameArray or \
- aNameSpaceArray for checkNameSpace");
- return (aElement &&
- (aLocalNameArray.indexOf(aElement.localName) != -1) &&
- (aNameSpaceArray.indexOf(aElement.namespaceURI) != -1));
- }
- /**
- * Safely close a nsISafeOutputStream.
- * @param aFOS
- * The file output stream to close.
- */
- function closeSafeOutputStream(aFOS) {
- if (aFOS instanceof Ci.nsISafeOutputStream) {
- try {
- aFOS.finish();
- return;
- } catch (e) { }
- }
- aFOS.close();
- }
- /**
- * Wrapper function for nsIIOService::newURI.
- * @param aURLSpec
- * The URL string from which to create an nsIURI.
- * @returns an nsIURI object, or null if the creation of the URI failed.
- */
- function makeURI(aURLSpec, aCharset) {
- var ios = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
- try {
- return ios.newURI(aURLSpec, aCharset, null);
- } catch (ex) { }
- return null;
- }
- /**
- * Gets a directory from the directory service.
- * @param aKey
- * The directory service key indicating the directory to get.
- */
- function getDir(aKey) {
- ENSURE_ARG(aKey, "getDir requires a directory key!");
- var fileLocator = Cc["@mozilla.org/file/directory_service;1"].
- getService(Ci.nsIProperties);
- var dir = fileLocator.get(aKey, Ci.nsIFile);
- return dir;
- }
- /**
- * The following two functions are essentially copied from
- * nsInternetSearchService. They are required for backwards compatibility.
- */
- function queryCharsetFromCode(aCode) {
- const codes = [];
- codes[0] = "x-mac-roman";
- codes[6] = "x-mac-greek";
- codes[35] = "x-mac-turkish";
- codes[513] = "ISO-8859-1";
- codes[514] = "ISO-8859-2";
- codes[517] = "ISO-8859-5";
- codes[518] = "ISO-8859-6";
- codes[519] = "ISO-8859-7";
- codes[520] = "ISO-8859-8";
- codes[521] = "ISO-8859-9";
- codes[1049] = "IBM864";
- codes[1280] = "windows-1252";
- codes[1281] = "windows-1250";
- codes[1282] = "windows-1251";
- codes[1283] = "windows-1253";
- codes[1284] = "windows-1254";
- codes[1285] = "windows-1255";
- codes[1286] = "windows-1256";
- codes[1536] = "us-ascii";
- codes[1584] = "GB2312";
- codes[1585] = "x-gbk";
- codes[1600] = "EUC-KR";
- codes[2080] = "ISO-2022-JP";
- codes[2096] = "ISO-2022-CN";
- codes[2112] = "ISO-2022-KR";
- codes[2336] = "EUC-JP";
- codes[2352] = "GB2312";
- codes[2353] = "x-euc-tw";
- codes[2368] = "EUC-KR";
- codes[2561] = "Shift_JIS";
- codes[2562] = "KOI8-R";
- codes[2563] = "Big5";
- codes[2565] = "HZ-GB-2312";
- if (codes[aCode])
- return codes[aCode];
- return getLocalizedPref("intl.charset.default", DEFAULT_QUERY_CHARSET);
- }
- function fileCharsetFromCode(aCode) {
- const codes = [
- "x-mac-roman", // 0
- "Shift_JIS", // 1
- "Big5", // 2
- "EUC-KR", // 3
- "X-MAC-ARABIC", // 4
- "X-MAC-HEBREW", // 5
- "X-MAC-GREEK", // 6
- "X-MAC-CYRILLIC", // 7
- "X-MAC-DEVANAGARI" , // 9
- "X-MAC-GURMUKHI", // 10
- "X-MAC-GUJARATI", // 11
- "X-MAC-ORIYA", // 12
- "X-MAC-BENGALI", // 13
- "X-MAC-TAMIL", // 14
- "X-MAC-TELUGU", // 15
- "X-MAC-KANNADA", // 16
- "X-MAC-MALAYALAM", // 17
- "X-MAC-SINHALESE", // 18
- "X-MAC-BURMESE", // 19
- "X-MAC-KHMER", // 20
- "X-MAC-THAI", // 21
- "X-MAC-LAOTIAN", // 22
- "X-MAC-GEORGIAN", // 23
- "X-MAC-ARMENIAN", // 24
- "GB2312", // 25
- "X-MAC-TIBETAN", // 26
- "X-MAC-MONGOLIAN", // 27
- "X-MAC-ETHIOPIC", // 28
- "X-MAC-CENTRALEURROMAN", // 29
- "X-MAC-VIETNAMESE", // 30
- "X-MAC-EXTARABIC" // 31
- ];
- // Sherlock files have always defaulted to x-mac-roman, so do that here too
- return codes[aCode] || codes[0];
- }
- /**
- * Returns a string interpretation of aBytes using aCharset, or null on
- * failure.
- */
- function bytesToString(aBytes, aCharset) {
- var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
- createInstance(Ci.nsIScriptableUnicodeConverter);
- LOG("bytesToString: converting using charset: " + aCharset);
- try {
- converter.charset = aCharset;
- return converter.convertFromByteArray(aBytes, aBytes.length);
- } catch (ex) {}
- return null;
- }
- /**
- * Converts an array of bytes representing a Sherlock file into an array of
- * lines representing the useful data from the file.
- *
- * @param aBytes
- * The array of bytes representing the Sherlock file.
- * @param aCharsetCode
- * An integer value representing a character set code to be passed to
- * fileCharsetFromCode, or null for the default Sherlock encoding.
- */
- function sherlockBytesToLines(aBytes, aCharsetCode) {
- // fileCharsetFromCode returns the default encoding if aCharsetCode is null
- var charset = fileCharsetFromCode(aCharsetCode);
- var dataString = bytesToString(aBytes, charset);
- ENSURE(dataString, "sherlockBytesToLines: Couldn't convert byte array!",
- Cr.NS_ERROR_FAILURE);
- // Split the string into lines, and filter out comments and
- // whitespace-only lines
- return dataString.split(NEW_LINES).filter(isUsefulLine);
- }
- /**
- * Gets the current value of the locale. It's possible for this preference to
- * be localized, so we have to do a little extra work here. Similar code
- * exists in nsHttpHandler.cpp when building the UA string.
- */
- function getLocale() {
- const localePref = "general.useragent.locale";
- var locale = getLocalizedPref(localePref);
- if (locale)
- return locale;
- // Not localized
- var prefs = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch);
- return prefs.getCharPref(localePref);
- }
- /**
- * Wrapper for nsIPrefBranch::getComplexValue.
- * @param aPrefName
- * The name of the pref to get.
- * @returns aDefault if the requested pref doesn't exist.
- */
- function getLocalizedPref(aPrefName, aDefault) {
- var prefB = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch);
- const nsIPLS = Ci.nsIPrefLocalizedString;
- try {
- return prefB.getComplexValue(aPrefName, nsIPLS).data;
- } catch (ex) {}
- return aDefault;
- }
- /**
- * Wrapper for nsIPrefBranch::setComplexValue.
- * @param aPrefName
- * The name of the pref to set.
- */
- function setLocalizedPref(aPrefName, aValue) {
- var prefB = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch);
- const nsIPLS = Ci.nsIPrefLocalizedString;
- try {
- var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
- .createInstance(Ci.nsIPrefLocalizedString);
- pls.data = aValue;
- prefB.setComplexValue(aPrefName, nsIPLS, pls);
- } catch (ex) {}
- }
- /**
- * Wrapper for nsIPrefBranch::getBoolPref.
- * @param aPrefName
- * The name of the pref to get.
- * @returns aDefault if the requested pref doesn't exist.
- */
- function getBoolPref(aName, aDefault) {
- var prefB = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch);
- try {
- return prefB.getBoolPref(aName);
- } catch (ex) {
- return aDefault;
- }
- }
- /**
- * Get a unique nsIFile object with a sanitized name, based on the engine name.
- * @param aName
- * A name to "sanitize". Can be an empty string, in which case a random
- * 8 character filename will be produced.
- * @returns A nsIFile object in the user's search engines directory with a
- * unique sanitized name.
- */
- function getSanitizedFile(aName) {
- var fileName = sanitizeName(aName) + "." + XML_FILE_EXT;
- var file = getDir(NS_APP_USER_SEARCH_DIR);
- file.append(fileName);
- file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
- return file;
- }
- /**
- * Removes all characters not in the "chars" string from aName.
- *
- * @returns a sanitized name to be used as a filename, or a random name
- * if a sanitized name cannot be obtained (if aName contains
- * no valid characters).
- */
- function sanitizeName(aName) {
- const chars = "-abcdefghijklmnopqrstuvwxyz0123456789";
- const maxLength = 60;
- var name = aName.toLowerCase();
- name = name.replace(/ /g, "-");
- name = name.split("").filter(function (el) {
- return chars.indexOf(el) != -1;
- }).join("");
- if (!name) {
- // Our input had no valid characters - use a random name
- var cl = chars.length - 1;
- for (var i = 0; i < 8; ++i)
- name += chars.charAt(Math.round(Math.random() * cl));
- }
- if (name.length > maxLength)
- name = name.substring(0, maxLength);
- return name;
- }
- /**
- * Notifies watchers of SEARCH_ENGINE_TOPIC about changes to an engine or to
- * the state of the search service.
- *
- * @param aEngine
- * The nsISearchEngine object to which the change applies.
- * @param aVerb
- * A verb describing the change.
- *
- * @see nsIBrowserSearchService.idl
- */
- function notifyAction(aEngine, aVerb) {
- var os = Cc["@mozilla.org/observer-service;1"].
- getService(Ci.nsIObserverService);
- LOG("NOTIFY: Engine: \"" + aEngine.name + "\"; Verb: \"" + aVerb + "\"");
- os.notifyObservers(aEngine, SEARCH_ENGINE_TOPIC, aVerb);
- }
- /**
- * Simple object representing a name/value pair.
- */
- function QueryParameter(aName, aValue) {
- ENSURE_ARG(aName && (aValue != null),
- "missing name or value for QueryParameter!");
- this.name = aName;
- this.value = aValue;
- }
- /**
- * Perform OpenSearch parameter substitution on aParamValue.
- *
- * @param aParamValue
- * A string containing OpenSearch search parameters.
- * @param aSearchTerms
- * The user-provided search terms. This string will inserted into
- * aParamValue as the value of the OS_PARAM_USER_DEFINED parameter.
- * This value must already be escaped appropriately - it is inserted
- * as-is.
- * @param aQueryEncoding
- * The value to use for the OS_PARAM_INPUT_ENCODING parameter. See
- * definition in the OpenSearch spec.
- *
- * @see http://opensearch.a9.com/spec/1.1/querysyntax/#core
- */
- function ParamSubstitution(aParamValue, aSearchTerms, aEngine) {
- var value = aParamValue;
- var distributionID = MOZ_DISTRIBUTION_ID;
- try {
- var prefB = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch);
- distributionID = prefB.getCharPref(BROWSER_SEARCH_PREF + "distributionID");
- }
- catch (ex) { }
- // Custom search parameters. These are only available to default search
- // engines.
- if (aEngine._isDefault) {
- value = value.replace(MOZ_PARAM_LOCALE, getLocale());
- value = value.replace(MOZ_PARAM_DIST_ID, distributionID);
- value = value.replace(MOZ_PARAM_OFFICIAL, MOZ_OFFICIAL);
- }
- // Insert the OpenSearch parameters we're confident about
- value = value.replace(OS_PARAM_USER_DEFINED, aSearchTerms);
- value = value.replace(OS_PARAM_INPUT_ENCODING, aEngine.queryCharset);
- value = value.replace(OS_PARAM_LANGUAGE,
- getLocale() || OS_PARAM_LANGUAGE_DEF);
- value = value.replace(OS_PARAM_OUTPUT_ENCODING,
- OS_PARAM_OUTPUT_ENCODING_DEF);
- // Replace any optional parameters
- value = value.replace(OS_PARAM_OPTIONAL, "");
- // Insert any remaining required params with our default values
- for (var i = 0; i < OS_UNSUPPORTED_PARAMS.length; ++i) {
- value = value.replace(OS_UNSUPPORTED_PARAMS[i][0],
- OS_UNSUPPORTED_PARAMS[i][1]);
- }
- return value;
- }
- /**
- * Creates a mozStorage statement that can be used to access the database we
- * use to hold metadata.
- *
- * @param dbconn the database that the statement applies to
- * @param sql a string specifying the sql statement that should be created
- */
- function createStatement (dbconn, sql) {
- var stmt = dbconn.createStatement(sql);
- var wrapper = Cc["@mozilla.org/storage/statement-wrapper;1"].
- createInstance(Ci.mozIStorageStatementWrapper);
- wrapper.initialize(stmt);
- return wrapper;
- }
- /**
- * Creates an engineURL object, which holds the query URL and all parameters.
- *
- * @param aType
- * A string containing the name of the MIME type of the search results
- * returned by this URL.
- * @param aMethod
- * The HTTP request method. Must be a case insensitive value of either
- * "GET" or "POST".
- * @param aTemplate
- * The URL to which search queries should be sent. For GET requests,
- * must contain the string "{searchTerms}", to indicate where the user
- * entered search terms should be inserted.
- *
- * @see http://opensearch.a9.com/spec/1.1/querysyntax/#urltag
- *
- * @throws NS_ERROR_NOT_IMPLEMENTED if aType is unsupported.
- */
- function EngineURL(aType, aMethod, aTemplate) {
- ENSURE_ARG(aType && aMethod && aTemplate,
- "missing type, method or template for EngineURL!");
- var method = aMethod.toUpperCase();
- var type = aType.toLowerCase();
- ENSURE_ARG(method == "GET" || method == "POST",
- "method passed to EngineURL must be \"GET\" or \"POST\"");
- this.type = type;
- this.method = method;
- this.params = [];
- var templateURI = makeURI(aTemplate);
- ENSURE(templateURI, "new EngineURL: template is not a valid URI!",
- Cr.NS_ERROR_FAILURE);
- switch (templateURI.scheme) {
- case "http":
- case "https":
- // Disable these for now, see bug 295018
- // case "file":
- // case "resource":
- this.template = aTemplate;
- break;
- default:
- ENSURE(false, "new EngineURL: template uses invalid scheme!",
- Cr.NS_ERROR_FAILURE);
- }
- }
- EngineURL.prototype = {
- addParam: function SRCH_EURL_addParam(aName, aValue) {
- this.params.push(new QueryParameter(aName, aValue));
- },
- getSubmission: function SRCH_EURL_getSubmission(aSearchTerms, aEngine) {
- var url = ParamSubstitution(this.template, aSearchTerms, aEngine);
- // Create an application/x-www-form-urlencoded representation of our params
- // (name=value&name=value&name=value)
- var dataString = "";
- for (var i = 0; i < this.params.length; ++i) {
- var param = this.params[i];
- var value = ParamSubstitution(param.value, aSearchTerms, aEngine);
- dataString += (i > 0 ? "&" : "") + param.name + "=" + value;
- }
- var postData = null;
- if (this.method == "GET") {
- // GET method requests have no post data, and append the encoded
- // query string to the url...
- if (url.indexOf("?") == -1 && dataString)
- url += "?";
- url += dataString;
- } else if (this.method == "POST") {
- // POST method requests must wrap the encoded text in a MIME
- // stream and supply that as POSTDATA.
- var stringStream = Cc["@mozilla.org/io/string-input-stream;1"].
- createInstance(Ci.nsIStringInputStream);
- #ifdef MOZILLA_1_8_BRANCH
- # bug 318193
- stringStream.setData(dataString, dataString.length);
- #else
- stringStream.data = dataString;
- #endif
- postData = Cc["@mozilla.org/network/mime-input-stream;1"].
- createInstance(Ci.nsIMIMEInputStream);
- postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
- postData.addContentLength = true;
- postData.setData(stringStream);
- }
- return new Submission(makeURI(url), postData);
- },
- /**
- * Serializes the engine object to a OpenSearch Url element.
- * @param aDoc
- * The document to use to create the Url element.
- * @param aElement
- * The element to which the created Url element is appended.
- *
- * @see http://opensearch.a9.com/spec/1.1/querysyntax/#urltag
- */
- _serializeToElement: function SRCH_EURL_serializeToEl(aDoc, aElement) {
- var url = aDoc.createElementNS(OPENSEARCH_NS_11, "Url");
- url.setAttribute("type", this.type);
- url.setAttribute("method", this.method);
- url.setAttribute("template", this.template);
- for (var i = 0; i < this.params.length; ++i) {
- var param = aDoc.createElementNS(OPENSEARCH_NS_11, "Param");
- param.setAttribute("name", this.params[i].name);
- param.setAttribute("value", this.params[i].value);
- url.appendChild(aDoc.createTextNode("\n "));
- url.appendChild(param);
- }
- url.appendChild(aDoc.createTextNode("\n"));
- aElement.appendChild(url);
- }
- };
- /**
- * nsISearchEngine constructor.
- * @param aLocation
- * A nsILocalFile or nsIURI object representing the location of the
- * search engine data file.
- * @param aSourceDataType
- * The data type of the file used to describe the engine. Must be either
- * DATA_XML or DATA_TEXT.
- * @param aIsReadOnly
- * Boolean indicating whether the engine should be treated as read-only.
- * Read only engines cannot be serialized to file.
- */
- function Engine(aLocation, aSourceDataType, aIsReadOnly) {
- this._dataType = aSourceDataType;
- this._readOnly = aIsReadOnly;
- this._urls = [];
- if (aLocation instanceof Ci.nsILocalFile) {
- // we already have a file (e.g. loading engines from disk)
- this._file = aLocation;
- } else if (aLocation instanceof Ci.nsIURI) {
- this._uri = aLocation;
- switch (aLocation.scheme) {
- case "https":
- case "http":
- case "ftp":
- case "data":
- case "file":
- case "resource":
- this._uri = aLocation;
- break;
- default:
- ERROR("Invalid URI passed to the nsISearchEngine constructor",
- Cr.NS_ERROR_INVALID_ARG);
- }
- } else
- ERROR("Engine location is neither a File nor a URI object",
- Cr.NS_ERROR_INVALID_ARG);
- }
- Engine.prototype = {
- // The engine's alias.
- _alias: null,
- // The data describing the engine. Is either an array of bytes, for Sherlock
- // files, or an XML document element, for XML plugins.
- _data: null,
- // The engine's data type. See data types (DATA_) defined above.
- _dataType: null,
- // Whether or not the engine is readonly.
- _readOnly: true,
- // The engine's description
- _description: "",
- // Used to store the engine to replace, if we're an update to an existing
- // engine.
- _engineToUpdate: null,
- // The file from which the plugin was loaded.
- _file: null,
- // Set to true if the engine has a preferred icon (an icon that should not be
- // overridden by a non-preferred icon).
- _hasPreferredIcon: null,
- // Whether the engine is hidden from the user.
- _hidden: null,
- // The engine's name.
- _name: null,
- // The engine type. See engine types (TYPE_) defined above.
- _type: null,
- // The name of the charset used to submit the search terms.
- _queryCharset: null,
- // A URL string pointing to the engine's search form.
- __searchForm: null,
- get _searchForm() {
- return this.__searchForm;
- },
- set _searchForm(aValue) {
- if (/^https?:/i.test(aValue))
- this.__searchForm = aValue;
- else
- LOG("_searchForm: Invalid URL dropped for " + this._name ||
- "the current engine");
- },
- // The URI object from which the engine was retrieved.
- // This is null for local plugins, and is used for error messages and logging.
- _uri: null,
- // Whether to obtain user confirmation before adding the engine. This is only
- // used when the engine is first added to the list.
- _confirm: false,
- // Whether to set this as the current engine as soon as it is loaded. This
- // is only used when the engine is first added to the list.
- _useNow: true,
- // Where the engine was loaded from. Can be one of: SEARCH_APP_DIR,
- // SEARCH_PROFILE_DIR, SEARCH_IN_EXTENSION.
- __installLocation: null,
- // The number of days between update checks for new versions
- _updateInterval: null,
- // The url to check at for a new update
- _updateURL: null,
- // The url to check for a new icon
- _iconUpdateURL: null,
- // A reference to the timer used for lazily serializing the engine to file
- _serializeTimer: null,
- /**
- * Retrieves the data from the engine's file. If the engine's dataType is
- * XML, the document element is placed in the engine's data field. For text
- * engines, the data is just read directly from file and placed as an array
- * of lines in the engine's data field.
- */
- _initFromFile: function SRCH_ENG_initFromFile() {
- ENSURE(this._file && this._file.exists(),
- "File must exist before calling initFromFile!",
- Cr.NS_ERROR_UNEXPECTED);
- var fileInStream = Cc["@mozilla.org/network/file-input-stream;1"].
- createInstance(Ci.nsIFileInputStream);
- fileInStream.init(this._file, MODE_RDONLY, PERMS_FILE, false);
- switch (this._dataType) {
- case SEARCH_DATA_XML:
- var domParser = Cc["@mozilla.org/xmlextras/domparser;1"].
- createInstance(Ci.nsIDOMParser);
- var doc = domParser.parseFromStream(fileInStream, "UTF-8",
- this._file.fileSize,
- "text/xml");
- this._data = doc.documentElement;
- break;
- case SEARCH_DATA_TEXT:
- var binaryInStream = Cc["@mozilla.org/binaryinputstream;1"].
- createInstance(Ci.nsIBinaryInputStream);
- binaryInStream.setInputStream(fileInStream);
- var bytes = binaryInStream.readByteArray(binaryInStream.available());
- this._data = bytes;
- break;
- default:
- ERROR("Bogus engine _dataType: \"" + this._dataType + "\"",
- Cr.NS_ERROR_UNEXPECTED);
- }
- fileInStream.close();
- // Now that the data is loaded, initialize the engine object
- this._initFromData();
- },
- /**
- * Retrieves the engine data from a URI.
- */
- _initFromURI: function SRCH_ENG_initFromURI() {
- ENSURE_WARN(this._uri instanceof Ci.nsIURI,
- "Must have URI when calling _initFromURI!",
- Cr.NS_ERROR_UNEXPECTED);
- LOG("_initFromURI: Downloading engine from: \"" + this._uri.spec + "\".");
- var ios = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
- var chan = ios.newChannelFromURI(this._uri);
- if (this._engineToUpdate && (chan instanceof Ci.nsIHttpChannel)) {
- var lastModified = engineMetadataService.getAttr(this._engineToUpdate,
- "updatelastmodified");
- if (lastModified)
- chan.setRequestHeader("If-Modified-Since", lastModified, false);
- }
- var listener = new loadListener(chan, this, this._onLoad);
- chan.notificationCallbacks = listener;
- chan.asyncOpen(listener, null);
- },
- /**
- * Attempts to find an EngineURL object in the set of EngineURLs for
- * this Engine that has the given type string. (This corresponds to the
- * "type" attribute in the "Url" node in the OpenSearch spec.)
- * This method will return the first matching URL object found, or null
- * if no matching URL is found.
- *
- * @param aType string to match the EngineURL's type attribute
- */
- _getURLOfType: function SRCH_ENG__getURLOfType(aType) {
- for (var i = 0; i < this._urls.length; ++i) {
- if (this._urls[i].type == aType)
- return this._urls[i];
- }
- return null;
- },
- _confirmAddEngine: function SRCH_SVC_confirmAddEngine() {
- var sbs = Cc["@mozilla.org/intl/stringbundle;1"].
- getService(Ci.nsIStringBundleService);
- var stringBundle = sbs.createBundle(SEARCH_BUNDLE);
- var titleMessage = stringBundle.GetStringFromName("addEngineConfirmTitle");
- // Display only the hostname portion of the URL.
- var dialogMessage =
- stringBundle.formatStringFromName("addEngineConfirmation",
- [this._name, this._uri.host], 2);
- var checkboxMessage = stringBundle.GetStringFromName("addEngineUseNowText");
- var addButtonLabel =
- stringBundle.GetStringFromName("addEngineAddButtonLabel");
- var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"].
- getService(Ci.nsIPromptService);
- var buttonFlags = (ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0) +
- (ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1) +
- ps.BUTTON_POS_0_DEFAULT;
- var checked = {value: false};
- // confirmEx returns the index of the button that was pressed. Since "Add"
- // is button 0, we want to return the negation of that value.
- var confirm = !ps.confirmEx(null,
- titleMessage,
- dialogMessage,
- buttonFlags,
- addButtonLabel,
- null, null, // button 1 & 2 names not used
- checkboxMessage,
- checked);
- return {confirmed: confirm, useNow: checked.value};
- },
- /**
- * Handle the successful download of an engine. Initializes the engine and
- * triggers parsing of the data. The engine is then flushed to disk. Notifies
- * the search service once initialization is complete.
- */
- _onLoad: function SRCH_ENG_onLoad(aBytes, aEngine) {
- /**
- * Handle an error during the load of an engine by prompting the user to
- * notify him that the load failed.
- */
- function onError(aErrorString, aTitleString) {
- if (aEngine._engineToUpdate) {
- // We're in an update, so just fail quietly
- LOG("updating " + aEngine._engineToUpdate.name + " failed");
- return;
- }
- var sbs = Cc["@mozilla.org/intl/stringbundle;1"].
- getService(Ci.nsIStringBundleService);
- var brandBundle = sbs.createBundle(BRAND_BUNDLE);
- var brandName = brandBundle.GetStringFromName("brandShortName");
- var searchBundle = sbs.createBundle(SEARCH_BUNDLE);
- var msgStringName = aErrorString || "error_loading_engine_msg2";
- var titleStringName = aTitleString || "error_loading_engine_title";
- var title = searchBundle.GetStringFromName(titleStringName);
- var text = searchBundle.formatStringFromName(msgStringName,
- [brandName, aEngine._location],
- 2);
- var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
- getService(Ci.nsIWindowWatcher);
- ww.getNewPrompter(null).alert(title, text);
- }
- if (!aBytes) {
- onError();
- return;
- }
- var engineToUpdate = null;
- if (aEngine._engineToUpdate) {
- engineToUpdate = aEngine._engineToUpdate.wrappedJSObject;
- // Make this new engine use the old engine's file.
- aEngine._file = engineToUpdate._file;
- }
- switch (aEngine._dataType) {
- case SEARCH_DATA_XML:
- var parser = Cc["@mozilla.org/xmlextras/domparser;1"].
- createInstance(Ci.nsIDOMParser);
- var doc = parser.parseFromBuffer(aBytes, aBytes.length, "text/xml");
- aEngine._data = doc.documentElement;
- break;
- case SEARCH_DATA_TEXT:
- aEngine._data = aBytes;
- break;
- default:
- onError();
- LOG("_onLoad: Bogus engine _dataType: \"" + this._dataType + "\"");
- return;
- }
- try {
- // Initialize the engine from the obtained data
- aEngine._initFromData();
- } catch (ex) {
- LOG("_onLoad: Failed to init engine!\n" + ex);
- // Report an error to the user
- onError();
- return;
- }
- // Check to see if this is a duplicate engine. If we're confirming the
- // engine load, then we display a "this is a duplicate engine" prompt,
- // otherwise we fail silently.
- if (!engineToUpdate) {
- var ss = Cc["@mozilla.org/browser/search-service;1"].
- getService(Ci.nsIBrowserSearchService);
- if (ss.getEngineByName(aEngine.name)) {
- if (aEngine._confirm)
- onError("error_duplicate_engine_msg", "error_invalid_engine_title");
- LOG("_onLoad: duplicate engine found, bailing");
- return;
- }
- }
- // If requested, confirm the addition now that we have the title.
- // This property is only ever true for engines added via
- // nsIBrowserSearchService::addEngine.
- if (aEngine._confirm) {
- var confirmation = aEngine._confirmAddEngine();
- LOG("_onLoad: confirm is " + confirmation.confirmed +
- "; useNow is " + confirmation.useNow);
- if (!confirmation.confirmed)
- return;
- aEngine._useNow = confirmation.useNow;
- }
- // If we don't yet have a file, get one now. The only case where we would
- // already have a file is if this is an update and _file was set above.
- if (!aEngine._file)
- aEngine._file = getSanitizedFile(aEngine.name);
- if (engineToUpdate) {
- // Keep track of the last modified date, so that we can make conditional
- // requests for future updates.
- engineMetadataService.setAttr(aEngine, "updatelastmodified",
- (new Date()).toUTCString());
- // Set the new engine's icon, if it doesn't yet have one.
- if (!aEngine._iconURI && engineToUpdate._iconURI)
- aEngine._iconURI = engineToUpdate._iconURI;
- // Clear the "use now" flag since we don't want to be changing the
- // current engine for an update.
- aEngine._useNow = false;
- }
- // Write the engine to file
- aEngine._serializeToFile();
- // Notify the search service of the sucessful load. It will deal with
- // updates by checking aEngine._engineToUpdate.
- notifyAction(aEngine, SEARCH_ENGINE_LOADED);
- },
- /**
- * Sets the .iconURI property of the engine.
- *
- * @param aIconURL
- * A URI string pointing to the engine's icon. Must have a http[s],
- * ftp, or data scheme. Icons with HTTP[S] or FTP schemes will be
- * downloaded and converted to data URIs for storage in the engine
- * XML files, if the engine is not readonly.
- * @param aIsPreferred
- * Whether or not this icon is to be preferred. Preferred icons can
- * override non-preferred icons.
- */
- _setIcon: function SRCH_ENG_setIcon(aIconURL, aIsPreferred) {
- // If we already have a preferred icon, and this isn't a preferred icon,
- // just ignore it.
- if (this._hasPreferredIcon && !aIsPreferred)
- return;
- var uri = makeURI(aIconURL);
- // Ignore bad URIs
- if (!uri)
- return;
- LOG("_setIcon: Setting icon url \"" + uri.spec + "\" for engine \""
- + this.name + "\".");
- // Only accept remote icons from http[s] or ftp
- switch (uri.scheme) {
- case "data":
- this._iconURI = uri;
- notifyAction(this, SEARCH_ENGINE_CHANGED);
- this._hasPreferredIcon = aIsPreferred;
- break;
- case "http":
- case "https":
- case "ftp":
- // No use downloading the icon if the engine file is read-only
- if (!this._readOnly) {
- LOG("_setIcon: Downloading icon: \"" + uri.spec +
- "\" for engine: \"" + this.name + "\"");
- var ios = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
- var chan = ios.newChannelFromURI(uri);
- function iconLoadCallback(aByteArray, aEngine) {
- // This callback may run after we've already set a preferred icon,
- // so check again.
- if (aEngine._hasPreferredIcon && !aIsPreferred)
- return;
- if (!aByteArray || aByteArray.length > MAX_ICON_SIZE) {
- LOG("iconLoadCallback: load failed, or the icon was too large!");
- return;
- }
- var str = btoa(String.fromCharCode.apply(null, aByteArray));
- aEngine._iconURI = makeURI(ICON_DATAURL_PREFIX + str);
- // The engine might not have a file yet, if it's being downloaded,
- // because the request for the engine file itself (_onLoad) may not
- // yet be complete. In that case, this change will be written to
- // file when _onLoad is called.
- if (aEngine._file)
- aEngine._serializeToFile();
- notifyAction(aEngine, SEARCH_ENGINE_CHANGED);
- aEngine._hasPreferredIcon = aIsPreferred;
- }
- // If we're currently acting as an "update engine", then the callback
- // should set the icon on the engine we're updating and not us, since
- // |this| might be gone by the time the callback runs.
- var engineToSet = this._engineToUpdate || this;
- var listener = new loadListener(chan, engineToSet, iconLoadCallback);
- chan.notificationCallbacks = listener;
- chan.asyncOpen(listener, null);
- }
- break;
- }
- },
- /**
- * Initialize this Engine object from the collected data.
- */
- _initFromData: function SRCH_ENG_initFromData() {
- ENSURE_WARN(this._data, "Can't init an engine with no data!",
- Cr.NS_ERROR_UNEXPECTED);
- // Find out what type of engine we are
- switch (this._dataType) {
- case SEARCH_DATA_XML:
- if (checkNameSpace(this._data, [MOZSEARCH_LOCALNAME],
- [MOZSEARCH_NS_10])) {
- LOG("_init: Initing MozSearch plugin from " + this._location);
- this._type = SEARCH_TYPE_MOZSEARCH;
- this._parseAsMozSearch();
- } else if (checkNameSpace(this._data, [OPENSEARCH_LOCALNAME],
- OPENSEARCH_NAMESPACES)) {
- LOG("_init: Initing OpenSearch plugin from " + this._location);
- this._type = SEARCH_TYPE_OPENSEARCH;
- this._parseAsOpenSearch();
- } else
- ENSURE(false, this._location + " is not a valid search plugin.",
- Cr.NS_ERROR_FAILURE);
- break;
- case SEARCH_DATA_TEXT:
- LOG("_init: Initing Sherlock plugin from " + this._location);
- // the only text-based format we support is Sherlock
- this._type = SEARCH_TYPE_SHERLOCK;
- this._parseAsSherlock();
- }
- // No need to keep a ref to our data (which in some cases can be a document
- // element) past this point
- this._data = null;
- },
- /**
- * Initialize this Engine object from a collection of metadata.
- */
- _initFromMetadata: function SRCH_ENG_initMetaData(aName, aIconURL, aAlias,
- aDescription, aMethod,
- aTemplate) {
- ENSURE_WARN(!this._readOnly,
- "Can't call _initFromMetaData on a readonly engine!",
- Cr.NS_ERROR_FAILURE);
- this._urls.push(new EngineURL("text/html", aMethod, aTemplate));
- this._name = aName;
- this.alias = aAlias;
- this._description = aDescription;
- this._setIcon(aIconURL, true);
- this._serializeToFile();
- },
- /**
- * Extracts data from an OpenSearch URL element and creates an EngineURL
- * object which is then added to the engine's list of URLs.
- *
- * @throws NS_ERROR_FAILURE if a URL object could not be created.
- *
- * @see http://opensearch.a9.com/spec/1.1/querysyntax/#urltag.
- * @see EngineURL()
- */
- _parseURL: function SRCH_ENG_parseURL(aElement) {
- var type = aElement.getAttribute("type");
- // According to the spec, method is optional, defaulting to "GET" if not
- // specified
- var method = aElement.getAttribute("method") || "GET";
- var template = aElement.getAttribute("template");
- try {
- var url = new EngineURL(type, method, template);
- } catch (ex) {
- LOG("_parseURL: failed to add " + template + " as a URL");
- throw Cr.NS_ERROR_FAILURE;
- }
- for (var i = 0; i < aElement.childNodes.length; ++i) {
- var param = aElement.childNodes[i];
- if (param.localName == "Param") {
- try {
- url.addParam(param.getAttribute("name"), param.getAttribute("value"));
- } catch (ex) {
- // Ignore failure
- LOG("_parseURL: Url element has an invalid param");
- }
- } else if (param.localName == "MozParam" &&
- // We only support MozParams for default search engines
- this._isDefault) {
- var value;
- switch (par…
Large files files are truncated, but you can click here to view the full file