blob: 2a0b3840b4f11209623305b857398629e0f69c1f [file] [log] [blame]
Jeff Thompson6ad5c362012-12-27 17:57:02 -08001/*
2 * @author: Jeff Thompson
3 * See COPYING for copyright and distribution information.
4 */
5
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -08006var EXPORTED_SYMBOLS = ["NdnProtocolInfo"];
Jeff Thompson6ad5c362012-12-27 17:57:02 -08007
8const Cc = Components.classes;
9const Ci = Components.interfaces;
10const Cr = Components.results;
11
12Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Jeff Thompson4eb992a2013-03-09 21:05:53 -080013Components.utils.import("chrome://modules/content/ndn-js.jsm");
Jeff Thompson6ad5c362012-12-27 17:57:02 -080014
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -080015var NdnProtocolInfo = function NdnProtocolInfo(){
16};
17
Jeff Thompsond51cb582013-03-17 19:00:39 -070018NdnProtocolInfo.ndn = new NDN({ getTransport: function() { return new XpcomTransport(); },
Jeff Thompson4eb992a2013-03-09 21:05:53 -080019 verify: false });
20
21// These are set once a connection is established.
22NdnProtocolInfo.connectedNdnHubHost = null;
23NdnProtocolInfo.connectedNdnHubPort = null;
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -080024NdnProtocolInfo.ndnHubChangedListenerList = [];
Jeff Thompson6ad5c362012-12-27 17:57:02 -080025
26/*
27 * When the NDN hub host or port is changed, the system calls listener(host, port).
Jeff Thompsonf3ec9a12012-12-30 22:05:24 -080028 * If the current host and port are not null, call listener with the values to initialize.
Jeff Thompson6ad5c362012-12-27 17:57:02 -080029 */
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -080030NdnProtocolInfo.addNdnHubChangedListener = function(listener) {
31 NdnProtocolInfo.ndnHubChangedListenerList.push(listener);
Jeff Thompsonf3ec9a12012-12-30 22:05:24 -080032
Jeff Thompson4eb992a2013-03-09 21:05:53 -080033 if (NdnProtocolInfo.connectedNdnHubHost != null && NdnProtocolInfo.connectedNdnHubPort != null) {
Jeff Thompsonf3ec9a12012-12-30 22:05:24 -080034 try {
Jeff Thompson4eb992a2013-03-09 21:05:53 -080035 listener(NdnProtocolInfo.connectedNdnHubHost, NdnProtocolInfo.connectedNdnHubPort);
Jeff Thompsonf3ec9a12012-12-30 22:05:24 -080036 }
37 catch (ex) {
38 // Ignore error from the listener.
39 }
40 }
Jeff Thompsond51cb582013-03-17 19:00:39 -070041};
Jeff Thompson6ad5c362012-12-27 17:57:02 -080042
43/*
44 * If host and port are different than ndnHubHost or ndnHubPort, set them and call each
45 * listener in ndnHubChangedListenerList.
46 */
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -080047NdnProtocolInfo.setConnectedNdnHub = function(host, port) {
Jeff Thompson4eb992a2013-03-09 21:05:53 -080048 if (host == NdnProtocolInfo.connectedNdnHubHost && port == NdnProtocolInfo.connectedNdnHubPort)
Jeff Thompson6ad5c362012-12-27 17:57:02 -080049 // No change.
50 return;
51
Jeff Thompson4eb992a2013-03-09 21:05:53 -080052 NdnProtocolInfo.connectedNdnHubHost = host;
53 NdnProtocolInfo.connectedNdnHubPort = port;
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -080054 for (var i = 0; i < NdnProtocolInfo.ndnHubChangedListenerList.length; ++i) {
Jeff Thompson6ad5c362012-12-27 17:57:02 -080055 try {
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -080056 NdnProtocolInfo.ndnHubChangedListenerList[i](host, port);
Jeff Thompson6ad5c362012-12-27 17:57:02 -080057 }
58 catch (ex) {
59 // Ignore error from the listener.
60 }
61 }
Jeff Thompsond51cb582013-03-17 19:00:39 -070062};
Jeff Thompson8107ec82013-01-12 21:53:27 -080063
64/*
65 * Split the URI spec and return an object with protocol (including ':'), name,
66 * search (including '?') and hash value (including '#').
67 * All result strings are trimmed. This does not unescape the name.
68 * The name may include a host and port.
69 */
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -080070NdnProtocolInfo.splitUri = function(spec) {
Jeff Thompson8107ec82013-01-12 21:53:27 -080071 spec = spec.trim();
72 var result = {};
73 var preHash = spec.split('#', 1)[0];
74 result.hash = spec.substr(preHash.length).trim();
75 var preSearch = preHash.split('?', 1)[0];
76 result.search = preHash.substr(preSearch.length).trim();
77
78 preSearch = preSearch.trim();
79 var colonIndex = preSearch.indexOf(':');
80 if (colonIndex >= 0) {
81 result.protocol = preSearch.substr(0, colonIndex + 1).trim();
82 result.name = preSearch.substr(colonIndex + 1).trim();
83 }
84 else {
85 result.protocol = "";
86 result.name = preSearch;
87 }
88
89 return result;
Jeff Thompsond51cb582013-03-17 19:00:39 -070090};
91
92/*
93 * Do the work of the NDN Get Version buttons.
94 * selector is "earliest", "latest", "previous" or "next".
95 * currentWindow is the window with the address.
96 * alertFunction(message) shows an alert.
97 */
98NdnProtocolInfo.getVersion = function(selector, currentWindow, alertFunction) {
Jeff Thompsond51cb582013-03-17 19:00:39 -070099 try {
100 if (currentWindow._content.document.location.protocol != "ndn:") {
101 alertFunction("The address must start with ndn:");
102 return;
103 }
104
105 // Parse the same as in ndnProtocolService newChannel.
106 var uriParts = NdnProtocolInfo.splitUri(currentWindow._content.document.location.href);
107 var name = new Name(uriParts.name);
108 var indexOfVersion = getIndexOfVersion(name);
109 if (indexOfVersion < 0) {
110 alertFunction("The ndn address does not have a version");
111 return;
112 }
113
114 var escapedVersion = Name.toEscapedString(name.components[indexOfVersion]);
115
116 var childSelector;
117 if (selector == "earliest")
118 childSelector = "ndn.ChildSelector=0";
119 else if (selector == "latest")
120 childSelector = "ndn.ChildSelector=1";
121 else if (selector == "previous")
122 childSelector = "ndn.ChildSelector=1&ndn.Exclude=" + escapedVersion + ",*";
123 else if (selector == "next")
124 childSelector = "ndn.ChildSelector=0&ndn.Exclude=*," + escapedVersion;
125 else
126 // Don't expect this to happen.
127 return;
128
129 var nameWithoutVersion = new Name(name.components.slice(0, indexOfVersion));
130 var searchWithChildSelector = (uriParts.search == "" ? "?" : uriParts.search + "&") + childSelector;
131
132 var uri = "ndn:" + nameWithoutVersion.to_uri() + searchWithChildSelector + uriParts.hash;
133 currentWindow._content.document.location = uri;
134 } catch (ex) {
135 dump("ndnToolbarGetVersion exception: " + ex + "\n" + ex.stack);
136 }
137};
138
139/*
140 * Return the index of the last component that starts with 0xfd, or -1 if not found.
141 */
142function getIndexOfVersion(name) {
143 for (var i = name.components.length - 1; i >= 0; --i) {
144 if (name.components[i].length >= 1 && name.components[i][0] == 0xfd)
145 return i;
146 }
147
148 return -1;
Jeff Thompsonb2f91ea2013-01-13 15:59:26 -0800149}
Jeff Thompsonca5130a2013-03-17 20:35:51 -0700150
151/// The following is only used by Firefox for Android to set up the menus.
152/// It really doesn't belong in this file, but it needs to be in a module that we know is
153/// run on startup. If it can be put somewhere else without circular references, then it should be.
154
155function loadIntoWindow(window) {
156 if (!window)
157 return;
158
159 // Add to Firefox for Android menu.
Jeff Thompsoncd376e72013-03-17 21:34:36 -0700160 window.NativeWindow.menu.add("NDN Get Version...", null, function() {
Jeff Thompsonca5130a2013-03-17 20:35:51 -0700161 ndnGetVersionClick(window);
162 });
Jeff Thompsoncd376e72013-03-17 21:34:36 -0700163 window.NativeWindow.menu.add("NDN Hub...", null, function() {
164 ndnHubClick(window);
165 });
Jeff Thompsonca5130a2013-03-17 20:35:51 -0700166}
167
168function ndnGetVersionClick(window) {
169 var alertFunction = function(message) { window.NativeWindow.toast.show(message, "short"); };
170
171 var buttons = [
172 {
173 label: "Earliest",
174 callback: function () {
175 NdnProtocolInfo.getVersion("earliest", window, alertFunction);
176 }
177 },
178 {
179 label: "Prev.",
180 callback: function () {
181 NdnProtocolInfo.getVersion("previous", window, alertFunction);
182 }
183 },
184 {
185 label: "Next",
186 callback: function () {
187 NdnProtocolInfo.getVersion("next", window, alertFunction);
188 }
189 },
190 {
191 label: "Latest",
192 callback: function () {
193 NdnProtocolInfo.getVersion("latest", window, alertFunction);
194 }
195 }
196 ];
197
198 window.NativeWindow.doorhanger.show("NDN Get Version", "ndn-get-version", buttons,
199 window.BrowserApp.selectedTab.id, { persistence: 1 });
200}
Jeff Thompsoncd376e72013-03-17 21:34:36 -0700201
202function ndnHubClick(window) {
203 var alertFunction = function(message) { window.NativeWindow.toast.show(message, "short"); };
204
205 var buttons = [
206 {
207 label: "OK",
208 callback: function () {
209 }
210 }
211 ];
212
213 window.NativeWindow.doorhanger.show(androidHubMessage, "ndn-hub", buttons,
214 window.BrowserApp.selectedTab.id, { persistence: 1 });
215}
Jeff Thompsonca5130a2013-03-17 20:35:51 -0700216
217var windowListener = {
218 onOpenWindow: function(aWindow) {
219 // Wait for the window to finish loading
220 let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
221 domWindow.addEventListener("load", function() {
222 domWindow.removeEventListener("load", arguments.callee, false);
223 loadIntoWindow(domWindow);
224 }, false);
225 },
226
227 onCloseWindow: function(aWindow) {},
228 onWindowTitleChange: function(aWindow, aTitle) {}
229};
230
231function androidStartup(aData, aReason) {
232 let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
233
234 // Load into any existing windows
235 let windows = wm.getEnumerator("navigator:browser");
236 while (windows.hasMoreElements()) {
237 let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
238 loadIntoWindow(domWindow);
239 }
240
241 // Load into any new windows
242 wm.addListener(windowListener);
243}
244
Jeff Thompsoncd376e72013-03-17 21:34:36 -0700245var androidHubMessage = "Hub: not connected";
246
247function androidOnNdnHubChanged(host, port) {
248 androidHubMessage = "Hub: " + host + ":" + port;
249}
250
Jeff Thompsonca5130a2013-03-17 20:35:51 -0700251// Do this here instead of using bootstrap.js since we don't want to set bootstrap true in install.rdf.
Jeff Thompsoncd376e72013-03-17 21:34:36 -0700252try {
253 // startup() will only succeed on Android.
254 androidStartup();
255 NdnProtocolInfo.addNdnHubChangedListener(androidOnNdnHubChanged);
256} catch (ex) {}