|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 const Ci = Components.interfaces; |
|
6 const Cc = Components.classes; |
|
7 const Cu = Components.utils; |
|
8 |
|
9 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
10 Cu.import("resource://gre/modules/Services.jsm"); |
|
11 |
|
12 const SIDEBAR_CID = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}"); |
|
13 const SIDEBAR_CONTRACTID = "@mozilla.org/sidebar;1"; |
|
14 |
|
15 function Sidebar() { |
|
16 // Depending on if we are in the parent or child, prepare to remote |
|
17 // certain calls |
|
18 var appInfo = Cc["@mozilla.org/xre/app-info;1"]; |
|
19 if (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { |
|
20 // Parent process |
|
21 |
|
22 this.inContentProcess = false; |
|
23 |
|
24 // Used for wakeups service. FIXME: clean up with bug 593407 |
|
25 this.wrappedJSObject = this; |
|
26 |
|
27 // Setup listener for child messages. We don't need to call |
|
28 // addMessageListener as the wakeup service will do that for us. |
|
29 this.receiveMessage = function(aMessage) { |
|
30 switch (aMessage.name) { |
|
31 case "Sidebar:AddSearchProvider": |
|
32 this.AddSearchProvider(aMessage.json.descriptionURL); |
|
33 } |
|
34 }; |
|
35 } else { |
|
36 // Child process |
|
37 |
|
38 this.inContentProcess = true; |
|
39 this.messageManager = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender); |
|
40 } |
|
41 } |
|
42 |
|
43 Sidebar.prototype = { |
|
44 // =========================== utility code =========================== |
|
45 _validateSearchEngine: function validateSearchEngine(engineURL, iconURL) { |
|
46 try { |
|
47 // Make sure we're using HTTP, HTTPS, or FTP. |
|
48 if (! /^(https?|ftp):\/\//i.test(engineURL)) |
|
49 throw "Unsupported search engine URL"; |
|
50 |
|
51 // Make sure we're using HTTP, HTTPS, or FTP and refering to a |
|
52 // .gif/.jpg/.jpeg/.png/.ico file for the icon. |
|
53 if (iconURL && |
|
54 ! /^(https?|ftp):\/\/.+\.(gif|jpg|jpeg|png|ico)$/i.test(iconURL)) |
|
55 throw "Unsupported search icon URL."; |
|
56 } catch(ex) { |
|
57 Cu.reportError("Invalid argument passed to window.sidebar.addSearchEngine: " + ex); |
|
58 |
|
59 var searchBundle = Services.strings.createBundle("chrome://global/locale/search/search.properties"); |
|
60 var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties"); |
|
61 var brandName = brandBundle.GetStringFromName("brandShortName"); |
|
62 var title = searchBundle.GetStringFromName("error_invalid_engine_title"); |
|
63 var msg = searchBundle.formatStringFromName("error_invalid_engine_msg", |
|
64 [brandName], 1); |
|
65 Services.prompt.alert(null, title, msg); |
|
66 return false; |
|
67 } |
|
68 |
|
69 return true; |
|
70 }, |
|
71 |
|
72 // The suggestedTitle and suggestedCategory parameters are ignored, but remain |
|
73 // for backward compatibility. |
|
74 addSearchEngine: function addSearchEngine(engineURL, iconURL, suggestedTitle, |
|
75 suggestedCategory) { |
|
76 if (!this._validateSearchEngine(engineURL, iconURL)) |
|
77 return; |
|
78 |
|
79 // File extension for Sherlock search plugin description files |
|
80 const SHERLOCK_FILE_EXT_REGEXP = /\.src$/i; |
|
81 |
|
82 // OpenSearch files will likely be far more common than Sherlock files, and |
|
83 // have less consistent suffixes, so we assume that ".src" is a Sherlock |
|
84 // (text) file, and anything else is OpenSearch (XML). |
|
85 var dataType; |
|
86 if (SHERLOCK_FILE_EXT_REGEXP.test(engineURL)) |
|
87 dataType = Ci.nsISearchEngine.DATA_TEXT; |
|
88 else |
|
89 dataType = Ci.nsISearchEngine.DATA_XML; |
|
90 |
|
91 Services.search.addEngine(engineURL, dataType, iconURL, true); |
|
92 }, |
|
93 |
|
94 // This function exists to implement window.external.AddSearchProvider(), |
|
95 // to match other browsers' APIs. The capitalization, although nonstandard here, |
|
96 // is therefore important. |
|
97 AddSearchProvider: function AddSearchProvider(aDescriptionURL) { |
|
98 if (!this._validateSearchEngine(aDescriptionURL, "")) |
|
99 return; |
|
100 |
|
101 if (this.inContentProcess) { |
|
102 this.messageManager.sendAsyncMessage("Sidebar:AddSearchProvider", |
|
103 { descriptionURL: aDescriptionURL }); |
|
104 return; |
|
105 } |
|
106 |
|
107 const typeXML = Ci.nsISearchEngine.DATA_XML; |
|
108 Services.search.addEngine(aDescriptionURL, typeXML, "", true); |
|
109 }, |
|
110 |
|
111 // This function exists to implement window.external.IsSearchProviderInstalled(), |
|
112 // for compatibility with other browsers. It will return an integer value |
|
113 // indicating whether the given engine is installed for the current user. |
|
114 // However, it is currently stubbed out due to security/privacy concerns |
|
115 // stemming from difficulties in determining what domain issued the request. |
|
116 // See bug 340604 and |
|
117 // http://msdn.microsoft.com/en-us/library/aa342526%28VS.85%29.aspx . |
|
118 // XXX Implement this! |
|
119 IsSearchProviderInstalled: function IsSearchProviderInstalled(aSearchURL) { |
|
120 return 0; |
|
121 }, |
|
122 |
|
123 // =========================== nsISupports =========================== |
|
124 QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]), |
|
125 |
|
126 // XPCOMUtils stuff |
|
127 classID: SIDEBAR_CID, |
|
128 }; |
|
129 |
|
130 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Sidebar]); |