diff --git a/browser/gopher/LICENSE.txt b/browser/gopher/LICENSE.txt new file mode 100644 index 0000000000..15a04b314c --- /dev/null +++ b/browser/gopher/LICENSE.txt @@ -0,0 +1,68 @@ +*** FOR MORE DETAILED CREDIT INFORMATION, SEE THE SOURCE AND BUILD DOCUMENTATION *** + +This code is issued under a disjunctive tri-license giving you the choice of +one of the three following sets of free software/open source licensing terms: + + * Mozilla Public License, version 1.1 + * GNU General Public License, version 2.0 + * GNU Lesser General Public License, version 2.1 + +For users under the Mozilla Public License: + +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 OverbiteFF Gopher addon. + +The Initial Developer of the Original Code is Cameron Kaiser. +Portions created by Cameron Kaiser are Copyright (C) 2008-2011 +Cameron Kaiser. All Rights Reserved. Copyright (C) 2008-2011 Contributors +to the Overbite Project. + +For users under the GNU Public License: + +OverbiteFF Gopher/CSO Firefox addon +Copyright (C) 2008-2011 Cameron Kaiser +Copyright (C) 2008-2011 Contributors to the Overbite Project + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +[ or http://www.gnu.org/licenses/gpl-2.0.html ] + +For users under the GNU Lesser General Public License: + +OverbiteFF Gopher/CSO Firefox addon +Copyright (C) 2008-2011 Cameron Kaiser +Copyright (C) 2008-2011 Contributors to the Overbite Project + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; version 2.1. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +[ or http://www.gnu.org/licenses/lgpl-2.1.html ] + diff --git a/browser/gopher/README.md b/browser/gopher/README.md new file mode 100644 index 0000000000..5cb004ec11 --- /dev/null +++ b/browser/gopher/README.md @@ -0,0 +1,45 @@ +## libgopher + +libgopher (a fork of overbiteff) lets you browse Gopher sites directly in legacy Firefox-based browsers such as Dactyloidae. + +In this tree it is built into the browser rather than installed as an add-on. The browser registers the Gopher protocol handler during startup, so `gopher://` links work immediately in a new profile. + +### Built-in integration + +The integration is split into the same pieces used by other browser-native features: + +- `moz.build` adds the component files, default preferences, and chrome package to the browser build. +- `components/protocol.manifest` registers the Gopher protocol. +- `components/protocol.js` implements Gopher networking, directory conversion, internal resources, and supported item types. +- `jar.mn` packages the `libgopher` content and locale namespaces. +- `defaults/preferences/gopher.js` initializes the build marker preference. + +The browser-level build entry is `browser/moz.build`; no XPI installation or add-on manager registration is required. + +### Supported URLs + +The primary entry point is any Gopher URL, for example: + +```text +gopher://gopher.floodgap.com/ +``` + +There are no built-in informational `about:` pages; navigation starts from a normal `gopher://` URL. + +The protocol handler also serves the generated internal resources used by Gopher directory pages, including icons, CSS, and the page interaction script. These resources are addressed through `gopher:///internal-*` URLs and are resolved from the packaged `content/chrome/` directory. + +### Gopher item types + +Directory conversion includes the traditional Gopher item types for text, menus, CSO/ph, errors, archives, searches, Telnet, images, sound, HTML, movies, PNG, PDF, and generic binary content. Unknown types receive the generic icon and label instead of preventing the directory from loading. + +### Profile customization + +The protocol handler first checks the profile’s `gopherchrome` directory for replacements for internal CSS, JavaScript, and image resources. This allows local visual or behavior changes without editing the browser package. + +The following preferences are recognized when present: + +- `network.gopher.dotless` — enables dotless text cleanup. +- `network.gopher.fixitype` — enables the legacy item-type correction behavior. +- `network.gopher.buildmark` — records the initialized libgopher build number. + +Only the build marker is given a default value by the built-in preference file; the other options remain opt-in. diff --git a/browser/gopher/components/protocol.js b/browser/gopher/components/protocol.js new file mode 100644 index 0000000000..7b543587b3 --- /dev/null +++ b/browser/gopher/components/protocol.js @@ -0,0 +1,1951 @@ +/* + +This code is issued under a disjunctive tri-license giving you the choice of +one of the three following sets of free software/open source licensing terms: + + * Mozilla Public License, version 1.1 + * GNU General Public License, version 2.0 + * GNU Lesser General Public License, version 2.1 + +For users under the Mozilla Public License: + +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 OverbiteFF Gopher addon. + +The Initial Developer of the Original Code is Cameron Kaiser. +Portions created by Cameron Kaiser are Copyright (C) 2008-2016 +Cameron Kaiser. All Rights Reserved. Copyright (C) 2008-2016 Contributors +to the Overbite Project. + +For users under the GNU Public License: + +OverbiteFF Gopher/CSO Firefox addon +Copyright (C) 2008-2016 Cameron Kaiser +Copyright (C) 2008-2016 Contributors to the Overbite Project + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +[ or http://www.gnu.org/licenses/gpl-2.0.html ] + +For users under the GNU Lesser General Public License: + +OverbiteFF Gopher/CSO Firefox addon +Copyright (C) 2008-2016 Cameron Kaiser +Copyright (C) 2008-2016 Contributors to the Overbite Project + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; version 2.1. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +[ or http://www.gnu.org/licenses/lgpl-2.1.html ] + +*/ +const OBFFVERS = 3.1; +const OBFFBUILD = 1695; +const OBFFBUILDPREF = "network.gopher.buildmark"; +const OBFFDOTLESSPREF = "network.gopher.dotless"; +const OBFFFIXITYPEPREF = "network.gopher.fixitype"; +const OBFFSCHEME = "gopher"; +const OBFFCHROMEURL = "chrome://libgopher"; +const OBFFRABOUTURL = (OBFFCHROMEURL + "/content/startpage.html"); +const OBFFPROT_HANDLER_CONTRACTID = "@mozilla.org/network/protocol;1?name="+OBFFSCHEME; +const OBFFPROT_HANDLER_CID = Components.ID("{977ffc4c-a635-433d-8477-ea575bfb7b19}"); + +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +const nsILoadInfo = Ci.nsILoadInfo; +const nsIFactory = Ci.nsIFactory; +const nsISupports = Ci.nsISupports; +const nsIProtocolHandler = Ci.nsIProtocolHandler; +const nsIProxiedProtocolHandler = Ci.nsIProxiedProtocolHandler; + +const nsIRequest = Ci.nsIRequest; +const nsIChannel = Ci.nsIChannel; +const nsIProxiedChannel = Ci.nsIProxiedChannel; +const nsIProgressEventSink = Ci.nsIProgressEventSink; + +const nsISocketTransport = Ci.nsISocketTransport; +const nsIStreamConverter = Ci.nsIStreamConverter; +const nsIStreamListener = Ci.nsIStreamListener; +const nsIObserver = Ci.nsIObserver; +const nsIRequestObserver = Ci.nsIRequestObserver; +const nsITimerCallback = Ci.nsITimerCallback; + +/* port control */ +// 80 is okay because of some hybrid servers that can speak both on one port +var alwayslet = [ 13, 43, 70, 71, 72, 79, 80, 105, 1070, 2347, 3000, 3070, + 3099, 4323, 7055, 7070, 7071, 7072, 7077, 7080, 7777, 27070 ]; +//var badports = [ 20,21,22,23,25,53,69,111,115,137,138,139,443,513,514,548 ]; + +/* cache */ +var capscache = new Object(); +var nullcaps = { + PathKeepPreDelimiter : false, + PathParentDouble : false, + PathDelimiter : "", + CapsVersion : 1 +}; + +/* global functions for logging to the error console */ +function OverbiteLogAlways(msg, error) { + var consoleService = Cc["@mozilla.org/consoleservice;1"] + .getService(Ci.nsIConsoleService); + msg = "libgopher: "+msg; + if (error) { + consoleService.logStringError(msg); + } else { + consoleService.logStringMessage(msg); + } +} + +function OverbiteLog(msg, error) { + + // return Cr.NS_OK; // comment out for logging + + // OverbiteLogAlways(msg, error); +} + +/* crap on a stick. + you mean I have to implement my own NS_QueryNotificationCallbacks? + so what do I have XPConnect for anyway?! + rot in hell. */ +function OverbiteQNC(one, two, three) { + var progsink = null; + + if (three) + return three; + if (one.notificationCallbacks) { + progsink = one.notificationCallbacks + .getInterface(nsIProgressEventSink); + if (!progsink && two) { + // try that instead + var cbs = two.notificationCallbacks; + if (cbs) + progsink = cbs.getInterface( + nsIProgressEventSink); + } + } + return(progsink); +} + +/* global functions for processing caps */ +function OverbiteCapsKey(host, port) { + var nport = (port < 1) ? 70 : port; + return host.toLowerCase()+":"+nport; +} +function OverbiteCapsPro(caps) { + if (caps.substr(0, 4) != "CAPS") + return nullcaps; + + var capsarr = caps.substr(4).split(/[\r\n]{1,2}/); + var ncapsarr = nullcaps; + var i; + + try { + for (i=0; i opaque, jump to root + var i = sel.lastIndexOf(d); + if (i == -1) return ""; // no delimeter in sel => jump to root + + // putative + var s = sel.substr(0, i); + + // handle the situation where the delimiter was on the end with nothing + // after it + if ((s + d) == sel) { // grrr + i = s.lastIndexOf(d); + if (i == -1) return ""; // no delimiter in sel => jump to root + s = s.substr(0, i); + } + + return s; +} +function OverbiteCapsUniversalBackURL(host, port, itype, sel) { + // based on the caps, return either a .caps pseudo URL, a real URL or + // nothing. used for the direct links. the capupurl is only valid iff: + // + // 1. we have a cached caps *and* it supports path delimeters + // or + // 2. we have no cached caps, in which case we hope for the best + // + // I thought about having this suppress the capupurl if it equals the + // root, but this is inconsistent, especially with new hosts. + + var capupurl = ''; + var caps = capscache[OverbiteCapsKey(host, port)]; + + // the itype could be in one of two places: either itself, or the + // first character of the sel. if itype == '' then get it from there. + if (itype == '') { + itype = sel.substr(0, 1); + sel = sel.substr(1); + } + // by definition backing up only can *ever* go up to a menu. + itype = '1'; + + if (!caps) { // no cache; construct pseudo URL + capupurl = OverbiteURLFromSel( + host + '.caps', port, itype, sel); + } else { + var kk = caps["PathDelimiter"]; + // if we have a path delimeter, use it + if (kk && kk.length) + capupurl = OverbiteURLFromSel( + host, port, itype, + OverbiteCapsBackPathFromSel(caps, sel)); + } + return capupurl; +} + +// utility function, used by lots of things +function OverbiteURLFromSel(host, port, itype, sel) { + var nport = (!port || port < 1) ? 70 : port; + var suburl = OBFFSCHEME + '://' + host + + ((nport != 70)?(':'+nport): '') + + '/' + encodeURI(itype + sel); + ; + return suburl; +} + +/* + * HACK! + * the OverbitePrompter "debounces" back to back alerts and acts + * effectively as the front end mutex. Needed since our channels + * can get multiplexed even in single-process Firefox and our + * channel object does a certain amount of front-end work currently. + * + * TODO: For e10s, remove all use of the prompter and use content + * controls (a form for searches, HTML error messages, etc.) +*/ + +var lastPromptKey = null; +var lastCachedResponse = null; +// These need to be globals so that responses cache properly. +var chequestub = { value : false }; +var query = { value : '' }; +function OverbitePrompter(newkey, response) { + if (lastPromptKey == newkey) { +OverbiteLog("prompter key "+lastPromptKey+" returning cached "+lastCachedResponse); + lastPromptKey = null; + return lastCachedResponse; + } + query = { value : '' }; + lastPromptKey = newkey; + lastCachedResponse = response(); +OverbiteLog("caching prompt "+newkey+" responded "+lastCachedResponse); + return lastCachedResponse; +} + +/* + * the OverbiteCaps object is a pseudo-object that controls browser navigation + * and stores caps data in the cache. it is mostly the same as Dotless and + * implements the same interfaces. + * + * future expansion: have the caps display a proper info page. +*/ + +function OverbiteCaps() { } +OverbiteCaps.prototype = { + + // my stuff + _contentType: null, + _listener : null, + _context : null, + _buf : '', + _sstream : null, + _browser_callback : null, + _host : '', + _port : -1, + _itemtype : '', + _selector : '', + + // feed the beast (i.e., the listener on the other end) + _feedBeast : function(request, listener, context, what) { + // create a new instance each time (instead of reusing one) + // just to make sure the previous instance has time to finish + var stringstream = Cc["@mozilla.org/io/string-input-stream;1"] + .createInstance(Ci.nsIStringInputStream); + stringstream.setData(what, what.length); + listener.onDataAvailable(request, context, + stringstream, 0, what.length); + }, + + // nsISupports + QueryInterface : XPCOMUtils.generateQI([nsISupports, + nsIStreamListener, + nsIStreamConverter, + nsIRequestObserver]), + + // nsIRequestObserver + onStartRequest : function(request, context) { + // init the channel with data and content type + // this is almost always text/plain but we are flexible + + this._context = context; + this._buf = ''; + + var chan = request.QueryInterface(nsIChannel); + if (chan) + chan.contentType = "text/html"; + this._listener.onStartRequest(request, context); + }, + + /* when the request terminates, we then parse the data (using the + global functions above) and manipulate the browser. the other + end gets a StopRequest but we don't pass it any data. */ + + onStopRequest : function(request, context, status) { + // stop the stream and destroy it + if (this._sstream) + this._sstream.close(); + this._sstream = null; + + // process it here before we tear down everything + var w = OverbiteCapsPro(this._buf); + var k = OverbiteCapsKey(this._host, this._port); + capscache[k] = w; + OverbiteLog("cached caps entry created for "+k); + + // if there is a callback, send NO data. manipulate the URL + // and we are done! + if (this._browser_callback) { + // compute the new URL ... + var s = OverbiteCapsBackPathFromSel(w, this._selector); + s = OverbiteURLFromSel(this._host, this._port, + this._itemtype, s); + OverbiteLog("backing up to "+s); + + // briefly stop the load group before we retarget ... + this._listener.onStopRequest(request, this._context, status); + this._listener = null; + this._context = null; + + // ... and force the browser to the new URL. + // we need to biff the current history entry so that + // the caps redirect is seamless. + this._browser_callback.webNavigation.loadURI(s, + 128, // LOAD_FLAGS_REPLACE_HISTORY + null, null, null); + return; + } + + // we are being asked to display the caps, so squirt it out + // to the _listener, and conclude. + var x = ""; + for (var i in w) { + if (w.hasOwnProperty(i)) { + var v = w[i]; + if (v == true) + v = "true"; + if (v == false) + v = "false"; + x += i + " ==> " +w[i] + "
\n"; + } + } + this._feedBeast(request, this._listener, this._context, + x); + this._listener.onStopRequest(request, this._context, status); + this._listener = null; + this._context = null; + }, + + // nsIStreamListener + onDataAvailable : function(request, context, stream, offset, count) { + var nbuf; + + if (!this._sstream) { + // create (and cache) our scriptable input stream + // note: this is NOT BINARY SAFE (but Gopher is + // mostly 7-bit) + this._sstream = Cc["@mozilla.org/scriptableinputstream;1"] + .createInstance(Ci.nsIScriptableInputStream); + this._sstream.init(stream); + } + nbuf = this._sstream.read(count); + this._buf += nbuf; + }, + + // nsIStreamConverter + convert : function(from, to, listener, context) { + // synchronous conversion will not be supported w/o good reason + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + asyncConvertData : function(from, to, listener, context) { + // if this were a real translator, we'd uncomment this +// if (from != ... || to != ...) +// throw Cr.NS_ERROR_NOT_IMPLEMENTED; + this._contentType = to; + this._listener = listener; + this._context = context; + } +} + +/* + * the dotless object handles things like svg and xml that barf on the + * terminal period that certain servers emit, and is also nice for + * text/plain. it is similar to Caps and implements the same interfaces. +*/ + +function OverbiteDotless() { } +OverbiteDotless.prototype = { + + // my stuff + _contentType: null, + _listener : null, + _context : null, + _buf : '', + _sstream : null, + + // useful internal functions + + // feed the beast (i.e., the listener on the other end) + _feedBeast : function(request, listener, context, what) { + // create a new instance each time (instead of reusing one) + // just to make sure the previous instance has time to finish + var stringstream = Cc["@mozilla.org/io/string-input-stream;1"] + .createInstance(Ci.nsIStringInputStream); + stringstream.setData(what, what.length); + listener.onDataAvailable(request, context, + stringstream, 0, what.length); + }, + // charAtEnd allows easier snarfing of trailing characters + _charAtEnd : function(index) { + return this._buf.charAt(this._buf.length - index); + }, + _lopOff : function(index) { + OverbiteLog("dotless removed "+index+" characters"); + this._buf = this._buf.substr(0, this._buf.length - index); + OverbiteLog("now "+this._buf.length+" long"); + }, + + // nsISupports + QueryInterface : XPCOMUtils.generateQI([nsISupports, + nsIStreamListener, + nsIStreamConverter, + nsIRequestObserver]), + + // nsIRequestObserver + onStartRequest : function(request, context) { + // init the channel with data and content type + + var chan = request.QueryInterface(nsIChannel); + if (chan) + chan.contentType = this._contentType; + // from asyncConvertData + this._context = context; + this._buf = ''; + this._listener.onStartRequest(request, context); + }, + + /* this is a very simple construct with a rolling buffer. essentially + we start by priming the pump with a small one character output, + then delaying and buffering data until the last pulse of data and + onStopRequest gets called, which if there is a final dot, should + be in the leftover buffer. */ + + onStopRequest : function(request, context, status) { + // trim the end of _buf + if (this._buf.indexOf(".")) { // don't bother if there's no dot + // check for very specific sequences + var l = this._buf.length; + if (l == 1) + this._buf = ""; // must be a bare dot + else if (this._buf == ".\r\n" || this._buf == ".\n") + this._buf = ""; + else if (this._buf == "\n." || this._buf == "\r\n.") + this._buf = ""; + else if (this._charAtEnd(1) == "." && + this._charAtEnd(2) == "\n"){ + this._lopOff(1); + } else if (this._charAtEnd(1) == "\n") { + if (l > 3 && this._charAtEnd(2) == "\r" && + this._charAtEnd(3) == "." && + this._charAtEnd(4) == "\n") { + this._lopOff(3); + } else if (l > 2 && this._charAtEnd(2) == "." + && this._charAtEnd(3) == "\n") { + this._lopOff(2); + } + } + // otherwise must be some other construction + } + this._feedBeast(request, this._listener, + this._context, this._buf) + if (this._buf.length); + this._buf = ''; + this._listener.onStopRequest(request, this._context, status); + this._listener = null; + this._context = null; + if (this._sstream) + this._sstream.close(); + this._sstream = null; + }, + + // nsIStreamListener + onDataAvailable : function(request, context, stream, offset, count) { + var nbuf; + + if (!this._sstream) { + // create (and cache) our scriptable input stream + // note: this is NOT BINARY SAFE (but Gopher is + // mostly 7-bit) + this._sstream = Cc["@mozilla.org/scriptableinputstream;1"] + .createInstance(Ci.nsIScriptableInputStream); + this._sstream.init(stream); + } + nbuf = this._sstream.read(count); + if (this._buf.length) { + this._feedBeast(request, this._listener, this._context, + this._buf); + this._buf = nbuf; + } else { + if (count == 1) { // degenerate case + this._feedBeast(request, this._listener, + this._context, nbuf); + // come back for more + } else { + this._buf = nbuf.substr(1); + this._feedBeast(request, this._listener, + this._context, nbuf.substr(0,1)); + } + } + }, + + // nsIStreamConverter + convert : function(from, to, listener, context) { + // synchronous conversion will not be supported w/o good reason + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + asyncConvertData : function(from, to, listener, context) { + // if this were a real translator, we'd uncomment this +// if (from != ... || to != ...) +// throw Cr.NS_ERROR_NOT_IMPLEMENTED; + this._contentType = to; + this._listener = listener; + this._context = context; + } +} + +/* + * the converter object for turning a gopher directory into HTML. we no + * longer use HTTP_INDEX because frankly it can't handle all that gopher + * offers. +*/ + +function OverbiteDirconv() { } +OverbiteDirconv.prototype = { + + // my stuff + _listener : null, + _context : null, + _buf : '', + _pbuf : '', + _sstream : null, + _divlevel : 0, + + /* l10n/i18n support and string bundles */ + + // for strings that are already Unicode (like our localization) + _unicodeEntityFix : function(what) { + // needed to ampersand-encode ALT text and other stuff + return "&#" + what.charCodeAt(0) + ";"; + }, + _unicodeStringFix : function(what) { + var q; + q = what; + q = q.replace(/([\u0080-\uFFFF])/g, this._unicodeEntityFix); + return q; + }, + + // we load both itypes and obff because we use both of them now. + _bundle : Cc["@mozilla.org/intl/stringbundle;1"] + .getService(Ci.nsIStringBundleService) + .createBundle(OBFFCHROMEURL + "/locale/itypes.properties"), + _getL10NString : function(msg, args) { + var q; + OverbiteLog("string query: "+msg); + + if (args) + return this._unicodeStringFix( + this._bundle.formatStringFromName(msg, args, + args.length)); + else + return this._unicodeStringFix( + this._bundle.GetStringFromName(msg)); + }, + _obundle : Cc["@mozilla.org/intl/stringbundle;1"] + .getService(Ci.nsIStringBundleService) + .createBundle(OBFFCHROMEURL + "/locale/obff.properties"), + _ogetL10NString : function(msg, args) { + if (args) + return this._obundle.formatStringFromName(msg, args, + args.length); + else + return this._obundle.GetStringFromName(msg); + }, + + _itypes : [ '0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', 'g', 'I', 's', 'h', ';', + 'p', 'd', 'T' ] , + + // useful internal functions + + // feed the beast (i.e., the listener on the other end) + _feedBeast : function(request, listener, context, what) { + // create a new instance each time (instead of reusing one) + // just to make sure the previous instance has time to finish + var stringstream = Cc["@mozilla.org/io/string-input-stream;1"] + .createInstance(Ci.nsIStringInputStream); + stringstream.setData(what, what.length); + listener.onDataAvailable(request, context, + stringstream, 0, what.length); + }, + // mungers and twisters to convert RFC-1436 cdata into valid SGML + _dsSpaceFix : function(what) { + var wout = what; + wout = wout.replace(/ /g, "  "); + wout = wout.replace(/ \ /g, "  "); + wout = wout.replace(/\  /g, "  "); + wout = wout.replace(/^ /, " "); + return wout; + }, + _entityFix : function(what) { + var wout = what; + wout = wout.replace(/\&/g, "&"); + wout = wout.replace(/>/g, ">"); + wout = wout.replace(/' ; + + rootbutt = +'
' + capupurl + +'' + +'
' + +"\n"; + } + whoami = whoami.asciiSpec; + } + if (whoami && whoami.length) { + twhoami = ": "+whoami; + if (whoami.indexOf("?") > -1) + whoami = ((whoami.split("?"))[0]) + "?..."; + else if (whoami.indexOf("%09") > -1) + whoami = ((whoami.split("%09"))[0]) + "?..."; + } + if (!whoami) + whoami = ''; + + var ibuf = +'' + "\n" + +"\n"+ +"\n"+ +'' + "\n" + +'' + "\n" + +"Gopher document" + twhoami + "\n"+ +''+ +'\n"+ +"\n"+ +'
'+ +'
'+ +'
'+ +'
' + whoami + '
' + + "\n" + +rootbutt + +'
'+ +'
' + "\n" + +'' + "\n"; + + // init the channel with data and content type + var chan = request.QueryInterface(nsIChannel); + if (chan) + chan.contentType = 'text/html'; + this._context = context; + this._listener.onStartRequest(request, context); + this._feedBeast(request, this._listener, context, ibuf); + + }, + + onStopRequest : function(request, context, status) { + this._buf += +"
\n"+ +"
\n"+ +"
\n"+ +"\n"+ +"\n"; + + this._feedBeast(request, this._listener, + this._context, this._buf); + this._buf = ''; + this._listener.onStopRequest(request, this._context, status); + this._listener = null; + this._context = null; + if (this._sstream) + this._sstream.close(); + this._sstream = null; + }, + + // nsIStreamListener + onDataAvailable : function(request, context, stream, offset, count) { + var i; + var obuf = ''; + + if (!this._sstream) { + // create (and cache) our scriptable input stream + // note: this is NOT BINARY SAFE (but Gopher is + // mostly 7-bit) + this._sstream = Cc["@mozilla.org/scriptableinputstream;1"] + .createInstance(Ci.nsIScriptableInputStream); + this._sstream.init(stream); + } + this._pbuf += this._sstream.read(count); + while((i = this._pbuf.indexOf("\n")) > -1) { + // pull the next tab-delimited string off the buffer + var w = this._pbuf.substr(0, i); + if (i < this._pbuf.length) + this._pbuf = this._pbuf.substr(i+1); + else + this._pbuf = ''; + + w = w.replace("\r", ""); + w = w.replace("\n", ""); + + var itype = w.substr(0,1); + + var attribs = w.substr(1).split("\t"); + var ds = this._dsSpaceFix(this._entityFix( + attribs.shift())); + if (!ds.length) + ds = " "; + + var sel = attribs.shift(); + if (!sel) + sel = ''; + + var host = attribs.shift(); + if (host && host.length) + host = encodeURI(host); + var port = parseInt(attribs.shift()); + if (isNaN(port)) + port = 0; // falls through to bogosity filter + var icalt = (this._itypes.indexOf(itype) > -1) + ? this._getL10NString(itype) + : this._getL10NString('unknown'); + var iconbase = "gopher:///internal-"; + + if (itype == "'" || itype == '"') { + // these are just going to cause all kinds of + // problems, so they are simply suppressed + obuf += +'\n"; + } else if (itype == 'i' || itype == '3') { + var lclass = (itype == '3') ? 'erroritem' + : 'infoitem'; + if (itype == '3') { + obuf += + '' + + ''; + //+ 'border = "0">'; + } else + obuf += ""; + obuf += '' + + '' + + ds + "\n"; + } else if (host && host.length && port > 1) { + var suburl; + var icon = "icn.png"; + var lclass = "fileitem"; + var spannable = 0; + + if (itype == '8' || itype == 'T') { + // don't let them inject + // arbitrary HTML with " + sel = sel.replace(/["']/g, ""); + suburl = "telnet://" + host + ":" + + port + "/" + sel; + var icon = "icn" + itype + ".png"; + var lclass = "telnetitem"; + icalt = this._getL10NString('telnet'); + } else if (itype == 'h' && + (sel.substr(0,4) == "URL:" || + sel.substr(0,5) == "/URL:")) { + var subn = (sel.substr(0,1) == "/") + ? 5 : 4; + suburl = encodeURI(sel.substr(subn)); + if (suburl.match(/^javascript:/) || + suburl.match(/^data:/)) { + suburl = ""; + ds += + ' (' + this._getL10NString('unsafeurl') + ')'; + } + icon = "icnhURL.png"; + lclass = "urlitem"; + icalt = this._getL10NString('exturl'); + } else if (port >= 80 && itype == 'h' && + sel.match(/^[A-Z]+(%20| )/)) { + sel = sel.replace(/^[A-Z]+(%20| )/,''); + suburl = "http://"+host+":"+port+ + (sel.substr(0,1) == "/" ? + "" : "/") + + encodeURI(unescape(sel)); + icon = "icnhURL.png"; + lclass = "urlitem"; + icalt = this._getL10NString('exturl'); + } else { + suburl = OverbiteURLFromSel(host, port, + itype, sel); + + if (itype == "g" + || itype == "h" + || itype == "p" + || itype == "I" + || itype == "7" + || itype == "0") spannable = 1; + this._divlevel += spannable; + var dl = this._divlevel; + + // attempt to escape weird itypes + var eitype = escape(itype); + if (eitype.length > 1) // it was + eitype = eitype.substr(1) + .toLowerCase(); + icon = (this._itypes.indexOf(itype)>-1) + ? ("icn"+eitype+".png") + : "icn.png"; + lclass = + (itype == '7' || itype == '2') + ? 'searchitem': + (itype == '1') ? 'diritem' : + 'fileitem'; + } + obuf += + ''; + if (spannable) obuf += +''; + obuf += + '' + + '' + + '' + + '' + + '' + + ds + "\n"; + if (spannable) obuf += + ''+ + '
'+"\n"; + + } else { + obuf += // no point in localizing this, I think + "\n"; + } + } + this._feedBeast(request, this._listener, this._context, obuf); + }, + + // nsIStreamConverter + convert : function(from, to, listener, context) { + // synchronous conversion will not be supported w/o good reason + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + asyncConvertData : function(from, to, listener, context) { + // if this were a real translator, we'd uncomment this +// if (from != "text/x-overbite-gopher-dir" || to != "text/html") +// throw Cr.NS_ERROR_NOT_IMPLEMENTED; + this._listener = listener; + this._context = context; + } + +}; + +/* + * the channel object that actually does the protocol negotiation. +*/ + +function OverbiteChannel(input_uri, proxyinfo, loadinfo) { + this.init(input_uri, proxyinfo, loadinfo); +} + +OverbiteChannel.prototype = { + + // my stuff + _itemtype : null, + _selector : null, + _host : null, + _port : null, + _transport : null, + _proxyinfo : null, + _pump : null, + _listener : null, + _context : null, + _progsink : null, + _browser_callback : null, + _is_caps : false, + + // for bug 769764 + _proxyresolveflags : null, + _proxy_uri : null, + + csoargs : '', + queryargs : '', + transreq : null, // actual transmitted request (see sendRequest) + + // we only need itypes for the notification helper. + _bundle : Cc["@mozilla.org/intl/stringbundle;1"] + .getService(Ci.nsIStringBundleService) + .createBundle(OBFFCHROMEURL + "/locale/itypes.properties"), + _getL10NString : function(msg, args) { + var q; + OverbiteLog("string query: "+msg); + + if (args) + return this._bundle.formatStringFromName(msg, args, + args.length); + else + return this._bundle.GetStringFromName(msg); + }, + // for strings that are already Unicode (like our localization) + _unicodeEntityFix : function(what) { + // needed to ampersand-encode ALT text and other stuff + return "&#" + what.charCodeAt(0) + ";"; + }, + _unicodeStringFix : function(what) { + var q; + q = what; + q = q.replace(/([\u0080-\uFFFF])/g, this._unicodeEntityFix); + return q; + }, + + // nsISupports + // we can simplify this later; see nsIProxiedProtocolHandler + QueryInterface : XPCOMUtils.generateQI(((Ci.nsIProtocolProxyCallback) + ? [nsISupports, nsIChannel, nsIRequest, Ci.nsIProtocolProxyCallback] + : [nsISupports, nsIChannel, nsIRequest])), + + // nsIRequest + loadFlags : 0, + name : null, + _pending : false, + isPending : function() { return this._pending; }, + _status : Cr.NS_OK, + _loadGroup : null, + + get status() { + if (this._pump) + return (this._pump.status); + else + return this._status; + }, + set status(status) { this._status = status; }, + cancel : function(status) { + if (this._pump) + return (this._pump.cancel(status)); + else + return Cr.NS_OK; + }, + suspend : function() { + if (this._pump) + return (this._pump.suspend()); + else + return Cr.NS_OK; + }, + resume : function() { + if (this._pump) + return (this._pump.resume()); + else + return Cr.NS_OK; + }, + + // nsIChannel + loadInfo : null, + loadAttributes : null, + contentCharset : null, + contentLength : -1, + contentType : null, + _notificationCallbacks : null , + originalURI : null, + owner : null, + URI : null, + init : function(input_uri, proxyinfo, loadinfo) { + // constructor + this.URI = input_uri; + this.originalURI = input_uri; + this.name = input_uri; + if (proxyinfo) + this._proxyinfo = proxyinfo; + + // process item type and set contentType + var sel = decodeURI(input_uri.path); + if (sel == null || !sel.length || sel == '/') { + this._itemtype = '1'; + this._selector = ''; + } else if (sel.length == 1) { + this._itemtype = sel; + this._selector = ''; + } else { + this._itemtype = sel.substr(1,1); + this._selector = sel.substr(2); + } + + if (!input_uri.host || !input_uri.host.length) + throw Cr.NS_ERROR_MALFORMED_URI; + else + this._host = input_uri.host; + if (!input_uri.port || input_uri.port < 1) + this._port = 70; + else + this._port = input_uri.port; + + // force our itemtype. realistically, the old Gopher let people + // slide a lot with content sniffing, but that's not going to + // happen anymore. this is written to be as rigid as possible + // for a particular itemtype (but see type I, sigh). + var c; + switch(this._itemtype) { + case '1' : + case '7' : + c = 'application/x-overbite-gopher-dir'; + // this lets us override 1.9's gopher support + break; + + case 'c' : + c = 'text/css'; + break; + + case 'x' : + c = 'application/xml'; // I miss text/xml + break; + + case '0' : + case '2' : + c = 'text/plain'; + break; + + case 'g' : + c = 'image/gif' ; + break; + + case 'I' : + // oh, man, this is gross -- designed to + // support both the common use of I for + // JPEG images, and the official spec that + // I is a 'general image type' (we only + // support the ones Mozilla will display) + // + // taken from netwerk/mime/public/nsMimeTypes.h + if (this._selector.match(/\.jpe?g$/i)) + c = 'image/jpeg' ; + else if (this._selector.match(/\.gif$/i)) + c = 'image/gif' ; // grrRRR! use 'g'!! + else if (this._selector.match(/\.xbm$/i)) + c = 'image/x-xbitmap' ; + else if (this._selector.match(/\.png$/i)) + c = 'image/png' ; + else if (this._selector.match(/\.svg$/i)) + c = 'image/svg+xml' ; + else if (this._selector.match(/\.bmp$/i)) + c = 'image/bmp' ; + else if (this._selector.match(/\.icon?$/i)) + c = 'image/x-icon' ; + else if (this._selector.match(/\.tiff?$/i)) + c = 'image/tiff' ; + else + c = 'image/jpeg' ; + // this broke too many things + //c = 'application/octet-stream'; + break; + + case 'h' : + c = 'text/html'; + break; + + case 'p' : + c = 'image/png'; + break; + + case 'd' : + c = 'application/pdf'; + break; + + case '8' : + case 'T' : + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + break; + + default : + c = 'application/octet-stream'; + break; + } + this.contentType = c; + this.loadInfo = loadinfo; + + OverbiteLog(("channel initialized: "+ + this._host + " " + + this._port + " " + + this._itemtype + " " + + this._selector + " " + + "")); + return Cr.NS_OK; + }, + + /* open is not being implemented */ + open : function() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + + asyncOpen2 : function (listener) { + return asyncOpen(listener, null); + }, + + asyncOpen : function (listener, context) { + this._listener = listener; + this._context = context; + + // we can simplify this later; see nsIProxiedProtocolHandler + if (Ci.nsIProtocolProxyCallback) { + // if we can do asynchronous proxy resolution, ask + // the proxy service what to do + var nsPPS = Cc["@mozilla.org/network/protocol-proxy-service;1"] + .getService(Ci.nsIProtocolProxyService); + OverbiteLog(("async proxy resolution in progress")); + nsPPS.asyncResolve(this.URI, this._proxyresolveflags, + this); + OverbiteLog(("waiting for proxy")); + } else { + // otherwise assume already synchronously resolved + OverbiteLog(("no proxy callback needed")); + this.onProxyAvailable(null, null, this._proxyinfo, + Cr.NS_OK); + } + }, + + onProxyAvailable : function(request, uri, proxyinfo, status) { + if (proxyinfo) + OverbiteLog(("proxyinfo: "+proxyinfo)); + + this._proxyinfo = proxyinfo; + OverbiteLog(("proxyinfo on; trying to initialize transport")); + + var transportService = Cc["@mozilla.org/network/socket-transport-service;1"] + .getService(Ci.nsISocketTransportService); + this._transport = transportService + .createTransport(null, 0, + this._host, + this._port, + this._proxyinfo); + if (!(this.loadFlags & nsIRequest.LOAD_BACKGROUND)) { + // hook up our event sink to the current UI thread + var cq = Cc["@mozilla.org/thread-manager;1"] + .getService().currentThread; + OverbiteLog("yes, we have sink "+cq); + this._transport.setEventSink(this, cq); + } + // open and initialize the data pump to read from the socket + var sinput = + this._transport.openInputStream(0,0,0); + this.sendRequest(); + this._pump = Cc["@mozilla.org/network/input-stream-pump;1"]. + createInstance(Ci.nsIInputStreamPump); + this._pump.init(sinput, -1, -1, 0, 0, true); + this._pump.asyncRead(this, null); + if (this._loadGroup) { + this._loadGroup.addRequest(this, null); + OverbiteLog("load group added"); + } + this._pending = true; + + // if this is caps, start it and abort now + if (this._is_caps) { + OverbiteLog("caps request in progress"); + var caps = new OverbiteCaps(); + caps._host = this._host; + caps._port = this._port; + caps._itemtype = this._itemtype; + caps._selector = this._selector; + caps.asyncConvertData( + 'generic/caps', + this.contentType, + this._listener, + this._context); + this._listener = caps; + this._context = null; + caps._browser_callback = this._browser_callback; + OverbiteLog(("now with caps: "+caps)); + return Cr.NS_OK; + } + + // push on another content listener (in this case us) for + // those itemtypes requiring translation to something else + var transitives = [ '1', '7' ]; // item types for translation + if (transitives.indexOf(this._itemtype) > -1) { + OverbiteLog(("this type requires translation")); + var dirconv = new OverbiteDirconv(); + dirconv.asyncConvertData( + 'application/x-overbite-gopher-dir', + 'text/html', + this._listener, + this._context); + this._listener = dirconv; + this._context = null; + OverbiteLog(("now with dirconv: "+dirconv)); + } + // dotless conversion + var prefs = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefBranch); + var do_dotless = true; + // first load hidden preference for dotless + if (prefs.getPrefType(OBFFDOTLESSPREF) == prefs.PREF_BOOL) { + do_dotless = prefs.getBoolPref(OBFFDOTLESSPREF); + OverbiteLog(("dotless has been set to "+do_dotless)); + // otherwise default is true + } else { + OverbiteLog(("no "+OBFFDOTLESSPREF+" not bool")); + } + if (do_dotless && ( + this.contentType.match(/^text\//) || + this.contentType == 'application/xml' || + this.contentType == 'image/svg+xml' || + 0)) { + OverbiteLog("this type needs to be dotless"); + var dotless = new OverbiteDotless(); + dotless.asyncConvertData( + 'generic/dotless-type', + this.contentType, + this._listener, + this._context); + this._listener = dotless; + this._context = null; + OverbiteLog(("now with dotless: "+dotless)); + } + OverbiteLog(("transport service for "+ + this._host + " initialized")); + return Cr.NS_OK; + }, + + get loadGroup() { return this._loadGroup; }, + set loadGroup(loadGroup) { + this._loadGroup = loadGroup; + this._progsink = null; + }, + get notificationCallbacks() { + return this._notificationCallbacks; + }, + set notificationCallbacks(nc) { + this._notificationCallbacks = nc; + this._progsink = null; + }, + get securityInfo() { + if (this._transport) + return this._transport.securityInfo; + //throw Cr.NS_ERROR_NOT_AVAILABLE; + return null; + }, + // set securityInfo? bwahahaha + set securityInfo(foo) { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + return null; + }, + + + onStartRequest : function(request, context) { + if (this._listener) + this._listener.onStartRequest(this, + this._context); + OverbiteLog(("onStartRequest"+this._listener)); + }, + onStopRequest : function(request, context, status) { + OverbiteLog(("onStopRequest: "+status)); + if(Components.isSuccessCode(status)) + this.status = status; + + if (this._listener) { + this._listener.onStopRequest(this, + this._context, + this.status); + OverbiteLog("listener stopped"); + this._listener = null; + this._context = null; + } + if (this._loadGroup) { + this._loadGroup.removeRequest(this, + context, // null, + this.status); + OverbiteLog("load group stopped"); + } + + this._pump = null; + this._transport.close(this.status); + this._transport = null; + this.notificationCallbacks = null; // use our own getter/setter + this._progsink = null; + this._pending = false; + + OverbiteLog("end of request"); + + // Attach a notification box for navigation. + // Attach only iff: + // - the tab URL matches ours. (We could be in an iframe.) + // - there is no notification box there already. + // - this is not a gopher menu. We do this in the HTML instead. + // Backing up to a menu doesn't restore this box, so we should + // only do this to a terminal document. + var transitives = [ '1', '7' ]; // item types that are menus + if (transitives.indexOf(this._itemtype) == -1) { + try { // no meaning if this fails. + OverbiteLog("attempting to load nav bar "+this.originalURI.spec); + // XXX try selected tab first for speed? + + // Iterate over all windows and tabs to find us. + // If there are multiple instances, add the box; it + // won't hurt (as long as we didn't before). + + var wm = Cc["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator); + var be = wm.getEnumerator("navigator:browser"); + while(be.hasMoreElements()) { + var win = be.getNext(); + var tabb = win.gBrowser; + + // check each tab + var tabs = tabb.browsers.length; + for (var i=0; i 1 && + (input_uri.path.charAt(input_uri.path.length-1) == "/" || + input_uri.path.match(/^\/[^1]$/))) { + var prefs = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefBranch); + // first load hidden preference for cluefulness + if (prefs.getPrefType(OBFFFIXITYPEPREF) == + prefs.PREF_BOOL) { + rv = prefs.getBoolPref(OBFFFIXITYPEPREF); + // this is our default answer + } else { + rv = OverbitePrompter("swapitype", function() { + return prompter.confirm(null, + self._getL10NString('swapitype.title'), + self._getL10NString('swapitype')) + }); + } + if (rv) { + var newuri = "gopher://" + input_uri.host + + ((input_uri.port == 70 || + input_uri.port == -1) ? "" : + (":"+input_uri.port)) + + "/1" + input_uri.path.substr(2); + this._getBrowser().webNavigation.loadURI( + newuri, 0, null, null, null); + // this is a bit cheap, but we don't want + // Fx freaking that we didn't give it a channel + throw Cr.NS_ERROR_ABORT; + return null; // above will do redirect + } else { + // INSERT COINS AND CONTINUE + } + } + + // handle itemtype 7 at this stage and turn into a channel + // for itemtype 1 instead, except if this particular URL has + // arguments (but wouldn't you want to do that as itype 1?). + if (input_uri.path.substr(0,2) == "/7" && + input_uri.path.indexOf("?") == -1 && + input_uri.path.indexOf("%09") == -1) { + // we will accept "blank" responses -- could be valid + // use the global prompter objects + var rv = OverbitePrompter("search", function() { + return prompter.prompt(null, + self._getL10NString('search.title'), + self._getL10NString('search'), + query, null, chequestub) + }); + if (!rv) { + throw Cr.NS_ERROR_ABORT; + return null; + } + // stuff query into channel query args rather than + // kludging it into a URL + var ob = new OverbiteChannel(input_uri, proxyinfo, + loadinfo); + ob._proxyresolveflags = proxyresolveflags; + ob._proxy_uri = proxy_uri; + ob.queryargs = query.value; + return ob; + } + + // similarly handle itemtype 2 + // if it's /2....fjhgkrjgh then pass that on to the CSO server + // (it's a fully qualified query that requires no parsing) + if (input_uri.path == "/2" || input_uri.path == "/2/") { + // unlike itype 7 we MUST enter a query for this + var rv = OverbitePrompter("cso", function() { + return prompter.prompt(null, + self._getL10NString('cso.title'), + self._getL10NString('cso'), + query, null, chequestub) + }); + if (rv && !query.value.length) // blank query + OverbitePrompter("csobogus", function() { + prompter.alert(null, + self._getL10NString('csobogus.title'), + self._getL10NString('csobogus')) + }); + if (!rv || !query.value.length) { + throw Cr.NS_ERROR_ABORT; + return null; + } + // stuff query into channel csoargs + var ob = new OverbiteChannel(input_uri, proxyinfo, + loadinfo); + ob._proxyresolveflags = proxyresolveflags; + ob._proxy_uri = proxy_uri; + ob.csoargs = query.value; + return ob; + } + + // make chrome channel either to images or CSS if + // input_uri is "gopher:///internal-" and no / and + // extension is .png, .css or .js + if (!input_uri.host.length && + // PARANOIA STRIKES DEEP IN THE HEARTLAND!!!1 + !input_uri.path.substr(1).match(/\//) && + input_uri.path.match(/^\/internal-[^/ ]+\.(css|png|js)$/)) { + OverbiteLog("handling internal chrome: " + +input_uri.asciiSpec); + var IURL; + var mpath = input_uri.path.substr(1) + .replace(/^internal-/, ""); + + // try profile directory + var dirService = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties); + + var uprof = dirService.get("ProfD", Ci.nsIFile); + var basedir = "gopherchrome"; + //uprof.appendRelativePath(basedir); + uprof.append(basedir); + + if (uprof.exists() && uprof.isDirectory()) { + // use the user's gopherchrome directory for + // CSS, icons and content level javascript + OverbiteLog("trying user directory"); + var fileProServ = Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService) + .getProtocolHandler("file") + .QueryInterface(Ci + .nsIFileProtocolHandler); + + uprof.append(mpath); + if (uprof.exists() && uprof.isFile()) + IURL = fileProServ.getURLSpecFromFile( + uprof); + } + if (!IURL) { + OverbiteLog("trying internal chrome dir"); + IURL = OBFFCHROMEURL+ "/content/chrome/" + +mpath; + } + OverbiteLog("resulting URL: "+IURL); + return ioService.newChannel(IURL, null, null); + } + + // Reject empty-host Gopher URLs. The legacy about-page fallback has + // intentionally been removed from the built-in browser integration. + if (!input_uri.host.length) { + throw Cr.NS_ERROR_MALFORMED_URI; + } + + // otherwise + // immediately reject "pseudo" item types we don't handle + // do this here because it traps internal URLs + var wontshow = ['/i', '/3', '/8', '/T']; + if (input_uri.path && input_uri.path.length > 1 && + wontshow.indexOf(input_uri.path.substr(0,2)) > -1) { + OverbitePrompter("baditype", function() { + prompter.alert(null, + self._getL10NString('baditype.title'), + self._getL10NString('baditype')) + }); + throw Cr.NS_ERROR_ABORT; + return null; + } + + // silently reject port numbers we will never allow + //if (badports.indexOf(input_uri.port) > -1) { + if (input_uri.port && input_uri.port >= 0 + && alwayslet.indexOf(input_uri.port)== -1) { + OverbiteLog("illegal port: "+input_uri.port); + throw Cr.NS_ERROR_PORT_ACCESS_NOT_ALLOWED; + return null; + } + + // else it's a legit gopher request + // make our channel and gopher it + ob = new OverbiteChannel(input_uri, proxyinfo, loadinfo); + ob._proxyresolveflags = proxyresolveflags; + ob._proxy_uri = proxy_uri; + return ob; + } +}; + +/* Startup code */ + +var components = [ OverbiteProtocol ]; +function NSGetModule(compMgr, fileSpec) { + return XPCOMUtils.generateModule(components); +} +/* for Gecko 2 (deprecated) */ +if (XPCOMUtils.generateNSGetFactory) + var NSGetFactory = XPCOMUtils.generateNSGetFactory(components); + +OverbiteLog("startup with version "+OBFFVERS+" build "+OBFFBUILD); + +// Built-in browser integration must not create or select a tab during +// application startup. diff --git a/browser/gopher/components/protocol.manifest b/browser/gopher/components/protocol.manifest new file mode 100644 index 0000000000..bd8695e11d --- /dev/null +++ b/browser/gopher/components/protocol.manifest @@ -0,0 +1,3 @@ +component {977ffc4c-a635-433d-8477-ea575bfb7b19} protocol.js +contract @mozilla.org/network/protocol;1?name=gopher {977ffc4c-a635-433d-8477-ea575bfb7b19} +category profile-after-change GopherProtocol @mozilla.org/network/protocol;1?name=gopher diff --git a/browser/gopher/content/chrome/favicon.png b/browser/gopher/content/chrome/favicon.png new file mode 100644 index 0000000000..b1bd4a558f Binary files /dev/null and b/browser/gopher/content/chrome/favicon.png differ diff --git a/browser/gopher/content/chrome/gopherchrome.css b/browser/gopher/content/chrome/gopherchrome.css new file mode 100644 index 0000000000..85f17800a6 --- /dev/null +++ b/browser/gopher/content/chrome/gopherchrome.css @@ -0,0 +1,150 @@ +/* You can modify this to your heart's content. This version tries to + harmonize with your computer's theme. */ + +img.gicon { + border: 0px; +} +table.gmenu { + width: 100%; + border: 0px; +} +td.gicon { + text-align: right; + vertical-align: middle; + padding: 0px; + margin: 1px; +} +td.ds { + text-align: left; + vertical-align: middle; + width: 100%; + padding: 0px; + margin: 1px; +} +span.diritem { + font-family: lucida sans typewriter, lucida console, droid sans mono, liberation mono, monaco, andale mono, bitstream vera sans mono, monospace; + font-size: small; +} +span.fileitem { + font-family: lucida sans typewriter, lucida console, droid sans mono, liberation mono, monaco, andale mono, bitstream vera sans mono, monospace; + font-size: small; +} +span.infoitem { + font-family: lucida sans typewriter, lucida console, droid sans mono, liberation mono, monaco, andale mono, bitstream vera sans mono, monospace; + font-size: small; + opacity: 0.9; +} +span.searchitem { + font-family: lucida sans typewriter, lucida console, droid sans mono, liberation mono, monaco, andale mono, bitstream vera sans mono, monospace; + font-size: small; + font-weight: bold; +} +span.urlitem { + font-family: lucida sans typewriter, lucida console, droid sans mono, liberation mono, monaco, andale mono, bitstream vera sans mono, monospace; + font-size: small; + font-weight: bold; +} +span.telnetitem { + font-family: lucida sans typewriter, lucida console, droid sans mono, liberation mono, monaco, andale mono, bitstream vera sans mono, monospace; + font-size: small; + font-weight: bold; +} +span.erroritem { + font-family: lucida sans typewriter, lucida console, droid sans mono, liberation mono, monaco, andale mono, bitstream vera sans mono, monospace; + font-size: small; + font-weight: bold; +} +span.purl { + /* font-family: lucida sans, lucida grande, droid sans, droid sans mono, monospace; */ + font: message-box; + font-weight: bold; + font-size: 1.5em; +} +div#topbar { + display: table-row; + padding: 0px; + margin: 0px; +} +div#urlparent { + display: table-cell; + width: 100%; + text-align: left; + padding: 0px; + margin: 0px; +} +div#urlarea { + padding: 8px; + margin-bottom: 0px; + border-style: none; + border-top-width: 1px; + border-left-width: 1px; + border-right-width: 1px; + border-bottom-width: 0px; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + -moz-border-radius-topleft: 10px; + -moz-border-radius-topright: 10px; + display: table-cell; + vertical-align: text-bottom; +} +div#buttonarea { + padding: 8px; + margin-bottom: 0px; + border-color: ThreeDShadow; + border-style: solid; + border-top-width: 1px; + border-left-width: 1px; + border-right-width: 1px; + border-bottom-width: 0px; + display: table-cell; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + -moz-border-radius-topleft: 10px; + -moz-border-radius-topright: 10px; +} +div#contentarea { + clear: both; + padding: 5px; + margin-top: 0px; + border-style: solid; + border-width: 1px; + border-color: ThreeDShadow; + -moz-border-radius-topleft: 10px; + -moz-border-radius-bottomleft: 10px; + -moz-border-radius-bottomright: 10px; + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; +} +div#everything { + background-color: #ffffff; + -moz-border-radius: 10px; + border-radius: 10px; +} +body { + background-color: -moz-Dialog; +} +a.plus { + text-decoration: none; + font-family: monospace; + font-weight: bold; + font-size: 2.0em; + padding-right: 2px; + color: #000000; +} +span.inlineprompt { + font: message-box; +} +div.inlineprompt { + border: 1px solid #b0b0b0; + background-color: #d8d8c8; + -moz-border-radius-topleft: 7px; + -moz-border-radius-topright: 7px; + -moz-border-radius-bottomleft: 7px; + -moz-border-radius-bottomright: 7px; + border-top-left-radius: 7px; + border-top-right-radius: 7px; + border-bottom-left-radius: 7px; + border-bottom-right-radius: 7px; + padding: 10px; +} diff --git a/browser/gopher/content/chrome/icn.png b/browser/gopher/content/chrome/icn.png new file mode 100644 index 0000000000..03d5e71490 Binary files /dev/null and b/browser/gopher/content/chrome/icn.png differ diff --git a/browser/gopher/content/chrome/icn0.png b/browser/gopher/content/chrome/icn0.png new file mode 100644 index 0000000000..35fe814acb Binary files /dev/null and b/browser/gopher/content/chrome/icn0.png differ diff --git a/browser/gopher/content/chrome/icn1.png b/browser/gopher/content/chrome/icn1.png new file mode 100644 index 0000000000..8bef0842df Binary files /dev/null and b/browser/gopher/content/chrome/icn1.png differ diff --git a/browser/gopher/content/chrome/icn2.png b/browser/gopher/content/chrome/icn2.png new file mode 100644 index 0000000000..bcd2c66d20 Binary files /dev/null and b/browser/gopher/content/chrome/icn2.png differ diff --git a/browser/gopher/content/chrome/icn3.png b/browser/gopher/content/chrome/icn3.png new file mode 100644 index 0000000000..947538bf93 Binary files /dev/null and b/browser/gopher/content/chrome/icn3.png differ diff --git a/browser/gopher/content/chrome/icn3b.png b/browser/gopher/content/chrome/icn3b.png new file mode 100644 index 0000000000..fe07681eac Binary files /dev/null and b/browser/gopher/content/chrome/icn3b.png differ diff --git a/browser/gopher/content/chrome/icn4.png b/browser/gopher/content/chrome/icn4.png new file mode 100644 index 0000000000..5b0ebe6e90 Binary files /dev/null and b/browser/gopher/content/chrome/icn4.png differ diff --git a/browser/gopher/content/chrome/icn5.png b/browser/gopher/content/chrome/icn5.png new file mode 100644 index 0000000000..5b0ebe6e90 Binary files /dev/null and b/browser/gopher/content/chrome/icn5.png differ diff --git a/browser/gopher/content/chrome/icn6.png b/browser/gopher/content/chrome/icn6.png new file mode 100644 index 0000000000..5b0ebe6e90 Binary files /dev/null and b/browser/gopher/content/chrome/icn6.png differ diff --git a/browser/gopher/content/chrome/icn7.png b/browser/gopher/content/chrome/icn7.png new file mode 100644 index 0000000000..bcd2c66d20 Binary files /dev/null and b/browser/gopher/content/chrome/icn7.png differ diff --git a/browser/gopher/content/chrome/icn8.png b/browser/gopher/content/chrome/icn8.png new file mode 100644 index 0000000000..629cd3eb22 Binary files /dev/null and b/browser/gopher/content/chrome/icn8.png differ diff --git a/browser/gopher/content/chrome/icn9.png b/browser/gopher/content/chrome/icn9.png new file mode 100644 index 0000000000..5b0ebe6e90 Binary files /dev/null and b/browser/gopher/content/chrome/icn9.png differ diff --git a/browser/gopher/content/chrome/icnI.png b/browser/gopher/content/chrome/icnI.png new file mode 100644 index 0000000000..dc1e0c4bc7 Binary files /dev/null and b/browser/gopher/content/chrome/icnI.png differ diff --git a/browser/gopher/content/chrome/icnT.png b/browser/gopher/content/chrome/icnT.png new file mode 100644 index 0000000000..629cd3eb22 Binary files /dev/null and b/browser/gopher/content/chrome/icnT.png differ diff --git a/browser/gopher/content/chrome/icnd.png b/browser/gopher/content/chrome/icnd.png new file mode 100644 index 0000000000..9c1814f145 Binary files /dev/null and b/browser/gopher/content/chrome/icnd.png differ diff --git a/browser/gopher/content/chrome/icng.png b/browser/gopher/content/chrome/icng.png new file mode 100644 index 0000000000..dc1e0c4bc7 Binary files /dev/null and b/browser/gopher/content/chrome/icng.png differ diff --git a/browser/gopher/content/chrome/icnh.png b/browser/gopher/content/chrome/icnh.png new file mode 100644 index 0000000000..0ca7da3ae9 Binary files /dev/null and b/browser/gopher/content/chrome/icnh.png differ diff --git a/browser/gopher/content/chrome/icnhURL.png b/browser/gopher/content/chrome/icnhURL.png new file mode 100644 index 0000000000..c6e7de5c7e Binary files /dev/null and b/browser/gopher/content/chrome/icnhURL.png differ diff --git a/browser/gopher/content/chrome/icnp.png b/browser/gopher/content/chrome/icnp.png new file mode 100644 index 0000000000..dc1e0c4bc7 Binary files /dev/null and b/browser/gopher/content/chrome/icnp.png differ diff --git a/browser/gopher/content/chrome/icns.png b/browser/gopher/content/chrome/icns.png new file mode 100644 index 0000000000..dff7c2123a Binary files /dev/null and b/browser/gopher/content/chrome/icns.png differ diff --git a/browser/gopher/content/chrome/interface.js b/browser/gopher/content/chrome/interface.js new file mode 100644 index 0000000000..f3a2acedc2 --- /dev/null +++ b/browser/gopher/content/chrome/interface.js @@ -0,0 +1,180 @@ +/* + +This code is issued under a disjunctive tri-license giving you the choice of +one of the three following sets of free software/open source licensing terms: + + * Mozilla Public License, version 1.1 + * GNU General Public License, version 2.0 + * GNU Lesser General Public License, version 2.1 + +For users under the Mozilla Public License: + +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 OverbiteFF Gopher addon. + +The Initial Developer of the Original Code is Cameron Kaiser. +Portions created by Cameron Kaiser are Copyright (C) 2008-2016 +Cameron Kaiser. All Rights Reserved. Copyright (C) 2008-2016 Contributors +to the Overbite Project. + +For users under the GNU Public License: + +OverbiteFF Gopher/CSO Firefox addon +Copyright (C) 2008-2016 Cameron Kaiser +Copyright (C) 2008-2016 Contributors to the Overbite Project + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +[ or http://www.gnu.org/licenses/gpl-2.0.html ] + +For users under the GNU Lesser General Public License: + +OverbiteFF Gopher/CSO Firefox addon +Copyright (C) 2008-2016 Cameron Kaiser +Copyright (C) 2008-2016 Contributors to the Overbite Project + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; version 2.1. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +[ or http://www.gnu.org/licenses/lgpl-2.1.html ] + +*/ + +/* This controls the JavaScript interface. This runs with content privileges, + not with chrome privileges, by design. It can be blocked by NoScript and + other such tools. It cannot call back to chrome, so it ought not be + naughty. Assuming Mozilla did their job. COW's n'at. */ + +var openstates = new Object(); +var opacstates = new Object(); +var timestates = new Object(); +var localization = new Object(); +const outtime = 30; + +/* Function names are short because: + 1. I am a lousy programmer + 2. I don't care + 3. To avoid lots of crap */ + +/* Reviewer note: You'll see lots of simplistic templating below. The + functions are being called by the HTML generated for gopher menus in + the main nsIChannel object. The nsIChannel thoroughly sanitizes them. + They are never directly called by anything that gets unfiltered user + input, and this script runs with content privileges, not chrome. */ + +// Store something in localization (passed from chrome bundle) +function l(x, z) { + localization[x] = decodeURI(z); +} + +// Create the disclosure "icon" +function w(x, y, z) { + document.write('+'); +} + +// Toggle the disclosure icon, and insert the page image or iframe or +// form for [pgI], [0h] or 7. This uses the
scaffolding that chrome +// has already set up for us; we just fill it in. +function x(x, y, z) { + if (!openstates[z]) { + var h = window.innerHeight / 3; + openstates[z] = 1; + document.getElementById("pl"+z).innerHTML = "-"; + if (timestates[z]) + clearTimeout(timestates[z]); + try { + document.getElementById("pv"+z).style.opacity = 0.0; + opacstates[z] = 0.0; + timestates[z] = setTimeout("fade("+z+")", outtime); + } catch(e) { alert(e); } + if (y == "p" || y == "g" || y == "I") { + document.getElementById("pv"+z).innerHTML = +'' + } else if (y == "7") { + document.getElementById("pv"+z).innerHTML = +'
'+ +'
'+ +''+localization[0]+'

'+ +' ' + + '
'; + document.getElementById("src"+z).focus(); + } else { + document.getElementById("pv"+z).innerHTML = +''; + } + } else { + openstates[z] = 0; + if (timestates[z]) + clearTimeout(timestates[z]); + timestates[z] = null; + document.getElementById("pl"+z).innerHTML = "+"; + document.getElementById("pv"+z).innerHTML = ""; + } + return false; +} + +// Resize images (onLoad handler for images) +function s(i) { + var w = window.innerWidth - 100; + if (!i.width) return; + if (i.width > w) { + i.width = w; + i.height = w / (i.width / i.height); + } +} + +// Dynamically turn a form into a Gopher item type 7 query +function f(u, r) { + window.location=u+"%09"+encodeURI(document.getElementById("src"+r).value); + return false; +} + +function fade(z) { + opacstates[z] += 0.1; + document.getElementById("pv"+z).style.opacity = opacstates[z]; + if (opacstates[z] >= 1.0) { + timestates[z] = null; + } else { + timestates[z] = setTimeout("fade("+z+")", outtime); + } +} +// future expansion +function edaf(z) { + opacstates[z] -= 0.1; + document.getElementById("pv"+z).style.opacity = opacstates[z]; + if (opacstates[z] <= 0.0) { + timestates[z] = null; + } else { + timestates[z] = setTimeout("edaf("+z+")", outtime); + } +} diff --git a/browser/gopher/content/chrome/root.png b/browser/gopher/content/chrome/root.png new file mode 100644 index 0000000000..5c5a24262c Binary files /dev/null and b/browser/gopher/content/chrome/root.png differ diff --git a/browser/gopher/content/chrome/up.png b/browser/gopher/content/chrome/up.png new file mode 100644 index 0000000000..d465b5c1d8 Binary files /dev/null and b/browser/gopher/content/chrome/up.png differ diff --git a/browser/gopher/defaults/preferences/gopher.js b/browser/gopher/defaults/preferences/gopher.js new file mode 100644 index 0000000000..d07b33537a --- /dev/null +++ b/browser/gopher/defaults/preferences/gopher.js @@ -0,0 +1 @@ +pref("network.gopher.buildmark", 0); diff --git a/browser/gopher/jar.mn b/browser/gopher/jar.mn new file mode 100644 index 0000000000..5002f63c3b --- /dev/null +++ b/browser/gopher/jar.mn @@ -0,0 +1,33 @@ +# -*- Mode: makefile; tab-width: 8; indent-tabs-mode: t; -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +gopher.jar: +% content libgopher %content/ +% locale libgopher da-DK %locale/da-DK/ +% locale libgopher de-DE %locale/de-DE/ +% locale libgopher en-US %locale/en-US/ +% locale libgopher es-ES %locale/es-ES/ +% locale libgopher fr-FR %locale/fr-FR/ +% locale libgopher hu-HU %locale/hu-HU/ +% locale libgopher ja-JP %locale/ja-JP/ +% locale libgopher nb-NO %locale/nb-NO/ +% locale libgopher nl-NL %locale/nl-NL/ +% locale libgopher pl-PL %locale/pl-PL/ +% locale libgopher ru-RU %locale/ru-RU/ +% locale libgopher tr-TR %locale/tr-TR/ + + content/ (content/*) + locale/da-DK/ (locale/da-DK/*) + locale/de-DE/ (locale/de-DE/*) + locale/en-US/ (locale/en-US/*) + locale/es-ES/ (locale/es-ES/*) + locale/fr-FR/ (locale/fr-FR/*) + locale/hu-HU/ (locale/hu-HU/*) + locale/ja-JP/ (locale/ja-JP/*) + locale/nb-NO/ (locale/nb-NO/*) + locale/nl-NL/ (locale/nl-NL/*) + locale/pl-PL/ (locale/pl-PL/*) + locale/ru-RU/ (locale/ru-RU/*) + locale/tr-TR/ (locale/tr-TR/*) diff --git a/browser/gopher/locale/da-DK/itypes.properties b/browser/gopher/locale/da-DK/itypes.properties new file mode 100644 index 0000000000..0684749a5d --- /dev/null +++ b/browser/gopher/locale/da-DK/itypes.properties @@ -0,0 +1,25 @@ +unknown=Ukendt type +telnet=Forbundet til vært gennem Telnet/TN3270 +exturl=Ekstern URL +unsafeurl=Usikkert URL data udeladt +backpath=Gå til roden af denne server +uplev=Up +preview=View inline +0=Tekst dokument +1=Gopher menu +2=CSO/ph/qi telefone søgning +3=Gopher fejl +4=BinHex arkive +5=ZIP eller binært arkive +6=UUenkoded arkive +7=Applikation eller søgemaskine +8=Telnet forbindelse +9=Binær file +g=GIF billede +I=JPEG eller andet generisk billede +s=Lyd file +h=HTML file +;=Film/animations file +p=PNG billede +d=PDF dokument +T=Telnet/TN3270 forbindelse diff --git a/browser/gopher/locale/da-DK/obff.properties b/browser/gopher/locale/da-DK/obff.properties new file mode 100644 index 0000000000..cb638d0321 --- /dev/null +++ b/browser/gopher/locale/da-DK/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Gopher tilføjelse til firefox +hurl.error.title=Usikker URL %S +hurl.error=Denne URL indholder et usikker mål for omdirigering og er blevet udeladt. +hurl.warning.title=Gopher hURL omdirigering +hurl.warning=Dette element vil omdirigere dig til følgende ny URL:\n\n\t%S\n\nHvis du ikke genkender eller stoler på denne url, skal du trykke Cancel. Ellers tryk OK for at forsætte. +search.title=Angive parametere +search=Angive parametere som fjern serveren skal behandele: +cso.title=Angive CSO/ph forspørsel +cso=Angive nøgleord som der skal søges efter (eller en fuldstændig CSO/ph kommand begyndene med 'query').\n\nDin forspørgsel vil blive sendt uden nogen signatur. +csobogus.title=Ugyldig CSO/ph forspørgelse +csobogus=Denne forspørgelse er blevet annuleret da ingen kommando eller nøgleord blev modtaget. +baditype.title=Ugyldig element type +baditype=Dette element kan ikke vises direkte i din browser. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/de-DE/itypes.properties b/browser/gopher/locale/de-DE/itypes.properties new file mode 100644 index 0000000000..dcb0897b79 --- /dev/null +++ b/browser/gopher/locale/de-DE/itypes.properties @@ -0,0 +1,25 @@ +unknown=Unbekannter Typ +telnet=Verbindung zu Host via Telnet/TN3270 +exturl=Externe URL +unsafeurl=Unsichere URL-Daten wurden geblockt. +backpath=Zurück zum Wurzelmenü dieses Servers +preview=Sehe inline +uplev=Umgebende Menü +0=Textdokument +1=Gopher Menü +2=CSO/ph/qi-Adressbuchsuche +3=Gopher Fehler +4=BinHex-Archiv +5=ZIP oder Binärarchiv +6=UUencodiertes Archiv +7=Anwendung oder Suchmaschine +8=Telnet-Verbindung +9=Binärdatei +g=GIF-Bild +I=JPEG oder anderes Bildformat +s=Klangdatei +h=HTML-Datei +;=Film oder Animation +p=PNG-Bild +d=PDF-Dokument +T=Telnet/TN3270-Verbindung diff --git a/browser/gopher/locale/de-DE/obff.properties b/browser/gopher/locale/de-DE/obff.properties new file mode 100644 index 0000000000..20a256bf77 --- /dev/null +++ b/browser/gopher/locale/de-DE/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Gopher-Erweiterung für Firefox +hurl.error.title=Unsichere URL %S +hurl.error=Diese URL verweist auf ein unsicheres Ziel. Die Weiterleitung wurde darum nicht durchgeführt. +hurl.warning.title=Gopher hURL-Weiterleitung +hurl.warning=Dieser Selektor leitet Sie zur folgenden URL weiter:\n\n\t%S\n\nFalls Sie diese URL nicht kennen, oder sich ihrer Vertrauenswürdigkeit unsicher sind, sollten Sie auf Abbrechen drücken. Andernfalls drücken Sie bitte auf OK um fortzufahren. +search.title=Suchparameter +search=Bitte geben Sie die Parameter für den entfernten Server ein: +cso.title=CSO/ph-Anfrage +cso=Bitte geben Sie die zu suchenden Schlagwörter (oder ein komplettes CSO/ph-Kommando beginnend mit 'query') ein.\n\nIhre Anfrage wird ohne Authentifizierung gesendet. +csobogus.title=Ungültige CSO/ph-Anfrage +csobogus=Die Anfrage konnte nicht durchgeführt werden, da weder ein Schlagwort noch ein Kommando angegeben wurde. +baditype.title=Ungültiger Item-Typ +baditype=Ihr Browser kann mit diesem Item-Typ leider nicht umgehen. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/en-US/itypes.properties b/browser/gopher/locale/en-US/itypes.properties new file mode 100644 index 0000000000..3805e2002d --- /dev/null +++ b/browser/gopher/locale/en-US/itypes.properties @@ -0,0 +1,25 @@ +unknown=Unknown type +telnet=Connect to host via Telnet/TN3270 +exturl=External URL +unsafeurl=Unsafe URL data suppressed +backpath=Go to root menu for this server +preview=View this file inline +uplev=Up a menu +0=Text document +1=Gopher menu +2=CSO/ph/qi phonebook search +3=Gopher error +4=BinHex archive +5=ZIP or binary archive +6=UUencoded archive +7=Application or search engine +8=Telnet connection +9=Binary file +g=GIF image +I=JPEG or other generic image +s=Sound file +h=HTML file +;=Movie/animation file +p=PNG image +d=PDF document +T=Telnet/TN3270 connection diff --git a/browser/gopher/locale/en-US/obff.properties b/browser/gopher/locale/en-US/obff.properties new file mode 100644 index 0000000000..adca1790c0 --- /dev/null +++ b/browser/gopher/locale/en-US/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Gopher extension for Firefox +hurl.error.title=Unsafe URL %S +hurl.error=This URL contains an unsafe target for redirection and has been suppressed. +hurl.warning.title=Gopher hURL redirect +hurl.warning=This selector will redirect you to the following new URL:\n\n\t%S\n\nIf you do not recognize or trust this URL, you should click Cancel. Otherwise, click OK to continue. +search.title=Enter parameters +search=Enter parameters for the remote server to process: +cso.title=Enter CSO/ph query +cso=Enter keywords to search for (or a complete CSO/ph command starting with 'query').\n\nYour request will be sent without authentication. +csobogus.title=Invalid CSO/ph query +csobogus=The query is cancelled because no command or keyword was received. +baditype.title=Invalid item type +baditype=This item type cannot be directly displayed by your browser. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/es-ES/itypes.properties b/browser/gopher/locale/es-ES/itypes.properties new file mode 100644 index 0000000000..61aa393552 --- /dev/null +++ b/browser/gopher/locale/es-ES/itypes.properties @@ -0,0 +1,25 @@ +unknown=Tipo desconocido +telnet=Conectar a anfitrión atraves de Telnet/TN3270 +exturl=URL externo +unsafeurl=Datos suprimidos de URL inseguro +backpath=Ir a menú raiz de este servidor +preview=Mirar en linea +uplev=Ir a menú rodeando +0=Documento de texto +1=Menú Gopher +2=Buscar directorio telefonica CSO/ph/qi +3=Error de Gopher +4=Bin-Hex Archivo +5=ZIP o archivo binario +6=Archivo UUencoded +7=Aplicación o motor de búsqueda +8=Conexión Telnet +9=Archivo binario +g=Imagen tipo GIF +I=JPEG u otra imagen genérica +s=Archivo de sonido +h=Archivo HTML +;=Archivo de pelicula/animación +p=Imagen tipo PNG +d=Documento tipo PDF +T=Conexión Telnet/TN3270 diff --git a/browser/gopher/locale/es-ES/obff.properties b/browser/gopher/locale/es-ES/obff.properties new file mode 100644 index 0000000000..c7281a8bbd --- /dev/null +++ b/browser/gopher/locale/es-ES/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Extensión Gopher para Firefox +hurl.error.title=URL Insegura %S +hurl.error=Esta URL contiene un destino de reorientación inseguro y ha sido suprimida. +hurl.warning.title=Redirección Gopher hURL +hurl.warning=Este selector lo redireccionará a la siguiente URL:\n\n\t%S\n\nSi no reconoce o confia en esta URL, usted debe hacer clic en el botón de Cancelar. De otro modo, haga clic OK para continuar. +search.title=Introduzca los parámetros +search=Introduzca los parámetros para ejecutar proceso en servidor remoto: +cso.title=Introducir consulta CSO/ph +cso=Introducir palabras clave para buscar (o comando completo CSO/ph comenzando con 'query').\n\nSu solicitud sera enviada sin autenticación. +csobogus.title=Consulta CSO/ph no válida. +csobogus=Su consulta fue cancelada porque ningun commando o palabra clave fue recibido. +baditype.title=Tipo de elemento no válido +baditype=Este tipo de artículo no puede ser mostrado directamente en su navegador. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/fr-FR/itypes.properties b/browser/gopher/locale/fr-FR/itypes.properties new file mode 100644 index 0000000000..49873d014e --- /dev/null +++ b/browser/gopher/locale/fr-FR/itypes.properties @@ -0,0 +1,25 @@ +unknown=Type inconnu +telnet=Connexion à l'hôte via Telnet/TN3270 +exturl=URL externe +unsafeurl=URL peu sûr, données supprimées +backpath=Aller au menu racine de ce serveur +preview=Afficher ce fichier ici +uplev=Aller au menu enfermant +0=Document texte +1=Menu Gopher +2=Recherche CSO/ph/qi dans un annuaire +3=Erreur Gopher +4=Archive BinHex +5=Archive ZIP ou binaire +6=Archive encodée avec UUencode +7=Application ou moteur de recherche +8=Connexion telnet +9=Fichier binaire +g=Image GIF +I=Image générique ou JPEG +s=Fichier son +h=Fichier HTML +;=Vidéo/fichier d'animation +p=Image PNG +d=Document PDF +T=Connexion Telnet/TN3270 diff --git a/browser/gopher/locale/fr-FR/obff.properties b/browser/gopher/locale/fr-FR/obff.properties new file mode 100644 index 0000000000..2ac126bbda --- /dev/null +++ b/browser/gopher/locale/fr-FR/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Extension Gopher pour Firefox +hurl.error.title=URL peu sûr %S +hurl.error=Cet URL contient une cible de redirection peu sûre et a été supprimée. +hurl.warning.title=Redirection hURL Gopher +hurl.warning=Ce sélecteur va vous rediriger vers l'URL suivant :\n\n\t%S\n\nSi vous ne connaissez ou ne faites pas confiance à cet URL, vous devriez cliquer sur Annuler. Sinon, cliquez sur OK pour continuer. +search.title=Entrez les paramètres +search=Entrez les paramètres à traiter par l'hôte distant : +cso.title=Entrez une requête CSO/ph +cso=Entrez les mots-clefs à rechercher (ou bien un commande CSO/ph complète commençant par 'query').\n\nVotre requête sera envoyée sans authentification. +csobogus.title=Requête CSO/ph non valide. +csobogus=La requête a été annulée parce qu'aucune commande ou mot-clef n'a été reçu. +baditype.title=Type d'item non valide. +baditype=Ce type d'item ne peut pas être affiché directement par votre navigateur. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/hu-HU/itypes.properties b/browser/gopher/locale/hu-HU/itypes.properties new file mode 100644 index 0000000000..815fbaace3 --- /dev/null +++ b/browser/gopher/locale/hu-HU/itypes.properties @@ -0,0 +1,25 @@ +unknown=Ismeretlen típus +telnet=Kapcsolódás a szerverhez Telneten/TN3270-en keresztül +exturl=Külső URL +unsafeurl=Nem biztonságos URL adat figyelmen kívül hagyva +backpath=Ugrás a szerver külső menüjére +preview=View inline +uplev=Up +0=Szöveges dokumentum +1=Gopher menü +2=CSO/ph/qi telefonkönyv keresés +3=Gopher hiba +4=BinHex archív +5=ZIP vagy bináris archív +6=UUencode archív +7=Alkalmazás vagy keresőmotor +8=Telnet kapcsolat +9=Bináris fájl +g=GIF kép +I=JPEG vagy más kép +s=Hangfájl +h=HTML fájl +;=Film/animációs fájl +p=PNG kép +d=PDF dokumentum +T=Telnet/TN3270 kapcsolat diff --git a/browser/gopher/locale/hu-HU/obff.properties b/browser/gopher/locale/hu-HU/obff.properties new file mode 100644 index 0000000000..3aef92a5a7 --- /dev/null +++ b/browser/gopher/locale/hu-HU/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Gopher kiegészítés a Firefox-hoz +hurl.error.title=Nem biztonságos URL %S +hurl.error=Ez az URL átirányítást tartalmaz egy nem biztonságos címre, ezért figyelmen kívül hagytam. +hurl.warning.title=Gopher hURL átirányítás +hurl.warning=Ez a selector átirányít erre az URL-re:\n\n\t%S\n\nHa nem ismeri fel vagy bízik meg ebben az URL-ben, kattintson a Mégsem gombra, egyébként pedig az OK gombra a folytatáshoz. +search.title=Írja be a paramétereket +search=Írja be a paramétereket, amiket a távoli szerver feldolgozzon: +cso.title=Írja be a CSO/ph lekérdezést +cso=Írja be a kulcsszavakat, amikre keresni akar (vagy egy teljes CSO/ph parancsot, 'query' kezdettel).\n\nA kérést autentikáció nélkül küldöm el. +csobogus.title=Hibás CSO/ph lekérdezés +csobogus=A lekérdezés sikertelen volt, mert nem kaptam parancsot vagy kulcsszót. +baditype.title=Hibás elemtípus +baditype=Ezt az elemtípust a böngésző nem tudja közvetlenül megjeleníteni. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/ja-JP/itypes.properties b/browser/gopher/locale/ja-JP/itypes.properties new file mode 100644 index 0000000000..4b8dda9839 --- /dev/null +++ b/browser/gopher/locale/ja-JP/itypes.properties @@ -0,0 +1,25 @@ +unknown=未知タイプ +telnet=Telnet/TN3270ホスト接続 +exturl=外部URL +unsafeurl=危険なURLデータを抑制した +backpath=当サーバのルート・メニューへ +preview=インライン表示する +uplev=Up +0=テキスト文書 +1=Gopherメニュー +2=CSO/ph/qi電話帳検索 +3=Gopherエラー +4=BinHexファイル +5=ZIP・その他圧縮ファイル +6=UUencodeファイル +7=アプリケーション・検索エンジン +8=Telnet接続 +9=バイナリ・ファイル +g=GIF画像 +I=JPEG・その他画像 +s=音声ファイル +h=HTMLファイル +;=動画ファイル +p=PNG画像 +d=PDF文書 +T=Telnet/TN3270接続 diff --git a/browser/gopher/locale/ja-JP/obff.properties b/browser/gopher/locale/ja-JP/obff.properties new file mode 100644 index 0000000000..a83478a506 --- /dev/null +++ b/browser/gopher/locale/ja-JP/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=GopherのFirefox拡張機能 +hurl.error.title=危険なURL:%S +hurl.error=このURLは危険なリダイレクト先を含んでいるため抑制された。 +hurl.warning.title=Gopher hURLリダイレクト +hurl.warning=このセレクターは次のURLへリダイレクトする:\n\n\t%S\n\n以上のURLを信頼しない場合Cancelをクリック。URLを開くにはOKをクリック。 +search.title=検索条件を入力 +search=リモート・サーバのパレメータを入力: +cso.title=CSO/phクエリーを入力 +cso=検索のキーワード(もしくは'query'で始まる完全なCSO/phコマンド)を入力。\n\nあなたの要求を認証なしで送信する: +csobogus.title=無効なCSO/phクエリー +csobogus=コマンドまたはキーワードを受け付けなかったためこのクエリーを中止した。 +baditype.title=無効な項目タイプ +baditype=あなたのブラウザではこの項目タイプを直接に表示できない。 +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/nb-NO/itypes.properties b/browser/gopher/locale/nb-NO/itypes.properties new file mode 100644 index 0000000000..08dceecc6e --- /dev/null +++ b/browser/gopher/locale/nb-NO/itypes.properties @@ -0,0 +1,25 @@ +unknown=Ukjent type +telnet=Tilkobling til vert gjennom Telnet/TN3270 +exturl=Ekstern URL +unsafeurl=Usikker URL-data utestengt +backpath=Gå til rotmenyen for denne server +preview=View inline +uplev=Up +0=Tekstdokument +1=Gopher-meny +2=CSO/ph/qi telefonboksøking +3=Gopher-feil +4=BinHex-arkiv +5=ZIP eller binært arkiv +6=UUkomprimert arkiv +7=Program eller søkemotor +8=Telnet tilkobling +9=Binær fil +g=GIF-bilde +I=JPEG eller annet generisk bilde +s=Lyd-fil +h=HTML-fil +;=Film/animasjons fil +p=PNG-bilde +d=PDF-dokument +T=Telnet/TN3270 tilkobling diff --git a/browser/gopher/locale/nb-NO/obff.properties b/browser/gopher/locale/nb-NO/obff.properties new file mode 100644 index 0000000000..1644e64757 --- /dev/null +++ b/browser/gopher/locale/nb-NO/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Gopher utvidelse til firefox +hurl.error.title=Usikker URL %S +hurl.error=Denne URL peker mot et usikker mål for videresending og har blitt utestengt. +hurl.warning.title=Gopher hURL videresending +hurl.warning=Dette elementet vil videresende deg til følgende URL:\n\n\t%S\n\nHvis du ikke gjenkjenner eller stoler på denne URLen, må du trykke Cancel. Ellers trykk OK for å fortsette. +search.title=Angi parametere +search=Angi parametere som verten skal behandle: +cso.title=Angi CSO/ph forespørsel +cso=Angi nøkkelord som skal søkes etter (eller en fulstendig CSO/ph kommando som begynner med 'query').\n\nDin forespørsel vil bli sendt uten noen signatur. +csobogus.title=Ugyldig CSO/ph forespørsel +csobogus=Denne forespørselen har blitt annulert da ingen kommando eller nøkkelord ble mottatt.. +baditype.title=Ugyldig element type +baditype=Dette elementet kan ikke vises direkte i din nettleser. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/nl-NL/itypes.properties b/browser/gopher/locale/nl-NL/itypes.properties new file mode 100644 index 0000000000..5b9e38e484 --- /dev/null +++ b/browser/gopher/locale/nl-NL/itypes.properties @@ -0,0 +1,25 @@ +unknown=Onbekende type +telnet=Maak een verbinding met de host via Telnet/TN3270 +exturl=Externe URL +unsafeurl=Onveilige URL-data geblokkeerd +backpath=Ga naar het hoofdmenu van deze server +preview=Bekijk binnen menu +uplev=Up +0=Tekstdocument +1=Gophermenu +2=CSO/ph/qi telefoonboek +3=Gopherfout +4=BinHex-archief +5=ZIP of binair archief +6=UU-gecodeerd archief +7=Toepassing of zoekmachine +8=Telnetverbinding +9=Binair bestand +g=GIF-afbeelding +I=JPEG of andere afbeelding +s=Geluidsopname +h=HTML-bestand +;=Film/animatie +p=PNG-afbeelding +d=PDF-document +T=Telnet/TN3270-verbinding diff --git a/browser/gopher/locale/nl-NL/obff.properties b/browser/gopher/locale/nl-NL/obff.properties new file mode 100644 index 0000000000..fb9ad7859d --- /dev/null +++ b/browser/gopher/locale/nl-NL/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Gopherextensie voor Firefox +hurl.error.title=Onveilige URL %S +hurl.error=Deze URL bevat een onveilige doorverwijzing en is daarom geblokkeerd. +hurl.warning.title=Gopher-hURL-doorverwijzing +hurl.warning=Deze selector zal u doorsturen naar de volgende nieuwe URL:\n\n\t%S\n\nAls u deze URL niet herkend of vertrouwd, klik dan op Annuleren. Klik anders op OK om door te gaan. +search.title=Voer zoektermen in +search=Geef de zoektermen op die de server moet verwerken: +cso.title=Voer de CS/ph zoekterm in +cso=Voer zoektermen in (of een complete CSO/ph opdracht door te beginnen met 'query').\n\nUw verzoek zal zonder authenticatie worden verstuurd. +csobogus.title=Ongeldige CSO/ph zoekterm +csobogus=De zoekopdracht is geannuleerd omdat er geen opdracht of zoekterm is ontvangen. +baditype.title=Ongeldig itemtype +baditype=Dit itemtype kan niet in uw internetbrowser worden weergegeven. +swapitype.title=Verkeerd itemtype? +swapitype=Menu's hebben meestal het itemtype 1. Wilt u dat de internetbrowser dit aanpast? diff --git a/browser/gopher/locale/pl-PL/itypes.properties b/browser/gopher/locale/pl-PL/itypes.properties new file mode 100644 index 0000000000..07f0f0fa6d --- /dev/null +++ b/browser/gopher/locale/pl-PL/itypes.properties @@ -0,0 +1,25 @@ +unknown=Nieznany rodzaj +telnet=Połącz się z hostem przez Telnet/TN3270 +exturl=Zewnętrzny URL +unsafeurl=Wstrzymano dane z niepewnego URL +backpath=Przejdź do menu głównego tego serwera +preview=View inline +uplev=Up +0=Dokument tekstowy +1=Menu gophera +2=Wyszukiwane książki telefonicznej CSO/ph/qi +3=Błąd gophera +4=Archiwum BinHex +5=Archiwum binarne lub zip +6=Archiwum UUencode +7=Aplikacja sieciowa lub wyszukiwarka +8=Połączenie Telnet +9=Plik binarny +g=Plik GIF +I=Plik JPEG lub inny standardowy obrazek +s=Plik dźwiękowy +h=Plik HTML +;=Plik wideo/animacji +p=Plik PNG +d=Dokument PDF +T=Połączenie Telnet/TN3270 diff --git a/browser/gopher/locale/pl-PL/obff.properties b/browser/gopher/locale/pl-PL/obff.properties new file mode 100644 index 0000000000..31135c6c7f --- /dev/null +++ b/browser/gopher/locale/pl-PL/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Rozszerzenie protokołu Gopher dla Firefox +hurl.error.title=Niepewny URL %S +hurl.error=Ten URL zawiera niepewny cel przekierowania i został wstrzymany. +hurl.warning.title=Przekierowanie Gopher hURL +hurl.warning=Ten selektor przekieruje Ciebie do następującego URL:\n\n\t%S\n\nJeśli nie rozpoznajesz i nie ufasz temu URL, powinieneś anulować operację. W przeciwnym razie kliknij OK, aby kontynować. +search.title=Wprowadź parametry +search=Wprowadź parametry do przetworzenia przez zdalny serwer: +cso.title=Wpisz zapytanie CSO/ph +cso=Wprowadź słowa kluczowe do wyszukania (bądź całą komendę CSO/ph zaczynając od 'query').\n\nTwoje zapytanie będzie wysłane bez uwierzytelnienia. +csobogus.title=Niewłaściwe zapytanie CSO/ph +csobogus=Anulowano zapytanie ponieważ nie otrzymano komendy lub słowa kluczowego. +baditype.title=Niewłaściwy rodzaj elementu +baditype=Ten rodzaj elementu nie może być bezpośrednio wyświetlony na Twojej przeglądarce. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/ru-RU/itypes.properties b/browser/gopher/locale/ru-RU/itypes.properties new file mode 100644 index 0000000000..5d6fb0ce09 --- /dev/null +++ b/browser/gopher/locale/ru-RU/itypes.properties @@ -0,0 +1,25 @@ +unknown=Неизвестный тип +telnet=Соединение с сервером Telnet/TN3270 +exturl=Внешний URL +unsafeurl=Данные небезопасного URL блокированы +backpath=Перейти к корневому меню этого сервера +preview=Показать содержимое файла +uplev=Up +0=Текстовый документ +1=Меню Gopher +2=Поиск в справочнике CSO/ph/qi +3=Ошибка +4=Архив BinHex +5=ZIP или бинарный архив +6=Архив UUencode +7=Приложение или поисковая система +8=Соединение Telnet +9=Двоичный файл +g=Изображение GIF +I=JPEG или другой стандартный графический формат +s=Звуковой файл +h=Файл HTML +;=Видеофайл/графическая анимация +p=Изображение PNG +d=Документ PDF +T=Соединение Telnet/TN3270 diff --git a/browser/gopher/locale/ru-RU/obff.properties b/browser/gopher/locale/ru-RU/obff.properties new file mode 100644 index 0000000000..b88ed60780 --- /dev/null +++ b/browser/gopher/locale/ru-RU/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Расширение Gopher для Firefox +hurl.error.title=Небезопасный URL %S +hurl.error=Этот URL отклонён, поскольку содержит переадресацию на небезопасный ресурс. +hurl.warning.title=Переадресация Gopher hURL +hurl.warning=Этот селектор перенаправит вас на следующий URL:\n\n\t%S\n\nЕсли вы не знаете этот URL или не доверяете ему, нажмите Отмена. Чтобы продолжить, нажмите OK. +search.title=Ввод параметров +search=Введите параметры для обработки удалённым сервером: +cso.title=Ввод запроса CSO/ph +cso=Введите ключевые слова для поиска (или полную команду CSO/ph, начиная с 'query').\n\nВаш запрос будет отправлен без авторизации. +csobogus.title=Неверный запрос CSO/ph +csobogus=Запрос отменён, так как не получено команды или ключевого слова. +baditype.title=Неверный тип объекта +baditype=Этот тип объекта не может быть непосредственно отображён вашим браузером. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/locale/tr-TR/itypes.properties b/browser/gopher/locale/tr-TR/itypes.properties new file mode 100644 index 0000000000..2697d55261 --- /dev/null +++ b/browser/gopher/locale/tr-TR/itypes.properties @@ -0,0 +1,25 @@ +unknown=Bilinmeyen tip +telnet=Sunucuya Telnet/TN3270 yoluyla bağlantı +exturl=Harici URL +unsafeurl=Güvenli olmayan URL verisi silindi +backpath=Bu sunucunun ana menüsüne git +preview=View inline +uplev=Up +0=Metin döküman +1=Gopher menüsü +2=CSO/ph/qi telefon rehberi arama +3=Gopher hatası +4=BinHex arşiv +5=ZIP ya da ikili (binary) arşiv +6=UUencod'lanmış arşiv +7=Uygulama ya da arama motoru +8=Telnet bağlantısı +9=İkili (binary) dosya +g=GIF görüntü +I=JPEG ya da başka jenerik görüntü +s=Ses dosyası +h=HTML dosya +;=Film/animasyon dosyası +p=PNG görüntü +d=PDF doküman +T=Telnet/TN3270 bağlantısı diff --git a/browser/gopher/locale/tr-TR/obff.properties b/browser/gopher/locale/tr-TR/obff.properties new file mode 100644 index 0000000000..9cc7de3f44 --- /dev/null +++ b/browser/gopher/locale/tr-TR/obff.properties @@ -0,0 +1,15 @@ +network.gopher.description=Firefox için Gopher eklentisi +hurl.error.title=Güvenli olmayan URL %S +hurl.error=Bu URL yönlendirme için güvenli olmayan bir hedef içerir ve silinmiştir. +hurl.warning.title=Gopher hURL yönlendirme +hurl.warning=Bu selektör sizi şu adrese (URL) yönlendirecektir:\n\n\t%S\n\nEğer bu adresi tanımıyor ya da ona güvenmiyorsanız, İptal butonuna tıklamanız önerilir. Aksi takdirde devam etmek için Tamam butonuna tıklayınız. +search.title=Parametreleri giriniz +search=Uzaktaki sunucunun işlemesi için parametreleri giriniz: +cso.title=CSO/ph sorgusu giriniz +cso=Aramak istediğiniz anahtar kelimeleri (ya da 'query' ile başlayan bir CSO/ph komutu) giriniz.\n\nSorgunuz doğruluğu kanıtlanmadan gönderilecektir. +csobogus.title=Geçersiz CSO/ph sorgusu +csobogus=Hiçbir komut ya da anahtar kelime alınamadığından bu sorgu iptal edildi. +baditype.title=Geçersiz item tipi +baditype=Bu item tipi tarayıcınızda doğrudan görüntülenemez. +swapitype.title=Wrong item type? +swapitype=Usually menus are itemtype 1. Would you like the browser to fix this for you? diff --git a/browser/gopher/moz.build b/browser/gopher/moz.build new file mode 100644 index 0000000000..7b4e9758aa --- /dev/null +++ b/browser/gopher/moz.build @@ -0,0 +1,17 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] + +FINAL_TARGET = 'dist/bin/browser' + +FINAL_TARGET_FILES.components += [ + 'components/protocol.js', + 'components/protocol.manifest', +] + +FINAL_TARGET_FILES['defaults/preferences'] += [ + 'defaults/preferences/gopher.js', +] diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 11f7bf04c8..0d0b453f1c 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -360,6 +360,8 @@ @RESPATH@/browser/components/nsSetDefaultBrowser.js @RESPATH@/browser/components/internaluserscripts.js @RESPATH@/browser/components/internaluserscripts.manifest +@RESPATH@/browser/components/protocol.manifest +@RESPATH@/browser/components/protocol.js @RESPATH@/browser/components/devtools-startup.manifest @RESPATH@/browser/components/devtools-startup.js @RESPATH@/browser/components/webideCli.js @@ -590,6 +592,8 @@ @RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf @RESPATH@/browser/chrome/internaluserscripts.manifest @RESPATH@/browser/chrome/internaluserscripts/* +@RESPATH@/browser/chrome/gopher.manifest +@RESPATH@/browser/chrome/gopher@JAREXT@ @RESPATH@/browser/internal-userscripts/* @RESPATH@/chrome/toolkit@JAREXT@ @RESPATH@/chrome/toolkit.manifest @@ -628,6 +632,7 @@ @RESPATH@/browser/@PREF_DIR@/basilisk.js @RESPATH@/browser/@PREF_DIR@/basilisk-branding.js @RESPATH@/browser/@PREF_DIR@/internaluserscripts.js +@RESPATH@/browser/@PREF_DIR@/gopher.js @RESPATH@/goanna.js @RESPATH@/defaults/autoconfig/prefcalls.js @RESPATH@/browser/defaults/permissions diff --git a/browser/moz.build b/browser/moz.build index 6e339e1888..adb91d9669 100644 --- a/browser/moz.build +++ b/browser/moz.build @@ -10,6 +10,7 @@ SPHINX_TREES['browser'] = 'docs' DIRS += [ 'base', 'components', + 'gopher', 'internaluserscripts', 'locales', 'modules', diff --git a/docshell/base/moz.build b/docshell/base/moz.build index 62a31ae0a2..697d1a31a7 100644 --- a/docshell/base/moz.build +++ b/docshell/base/moz.build @@ -38,6 +38,7 @@ XPIDL_MODULE = 'docshell' EXPORTS += [ 'nsDocShellLoadTypes.h', + 'nsILinkHandler.h', 'nsIScrollObserver.h', 'nsIWebShellServices.h', 'SerializedLoadContext.h', diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index aad1cb7533..459ed7523a 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -956,6 +956,7 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell) NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider) NS_INTERFACE_MAP_ENTRY(nsILoadContext) NS_INTERFACE_MAP_ENTRY(nsIWebShellServices) + NS_INTERFACE_MAP_ENTRY(nsILinkHandler) NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands) NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager) NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController) @@ -14057,7 +14058,7 @@ OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler, { } -nsresult +NS_IMETHODIMP nsDocShell::OnLinkClick(nsIContent* aContent, nsIURI* aURI, const char16_t* aTargetSpec, @@ -14109,7 +14110,7 @@ nsDocShell::OnLinkClick(nsIContent* aContent, return NS_DispatchToCurrentThread(ev); } -nsresult +NS_IMETHODIMP nsDocShell::OnLinkClickSync(nsIContent* aContent, nsIURI* aURI, const char16_t* aTargetSpec, @@ -14275,7 +14276,7 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent, return rv; } -nsresult +NS_IMETHODIMP nsDocShell::OnOverLink(nsIContent* aContent, nsIURI* aURI, const char16_t* aTargetSpec) @@ -14328,7 +14329,7 @@ nsDocShell::OnOverLink(nsIContent* aContent, return rv; } -nsresult +NS_IMETHODIMP nsDocShell::OnLeaveLink() { nsCOMPtr browserChrome(do_GetInterface(mTreeOwner)); diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 60facc81af..2bb71911b9 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -51,6 +51,7 @@ #include "nsIAuthPromptProvider.h" #include "nsILoadContext.h" #include "nsIWebShellServices.h" +#include "nsILinkHandler.h" #include "nsIClipboardCommands.h" #include "nsITabParent.h" #include "nsCRT.h" @@ -142,6 +143,7 @@ class nsDocShell final , public nsIAuthPromptProvider , public nsILoadContext , public nsIWebShellServices + , public nsILinkHandler , public nsIClipboardCommands , public nsIDOMStorageManager , public nsINetworkInterceptController @@ -191,70 +193,28 @@ public: // nsIWebProgressListener has methods with identical names... NS_FORWARD_NSISECURITYEVENTSINK(nsDocLoader::) - /** - * Process a click on a link. - * - * @param aContent the content for the frame that generated the trigger - * @param aURI a URI object that defines the destination for the link - * @param aTargetSpec indicates where the link is targeted (may be an empty - * string) - * @param aFileName non-null when the link should be downloaded as the given file - * @param aPostDataStream the POST data to send - * @param aHeadersDataStream ??? (only used for plugins) - * @param aIsTrusted false if the triggerer is an untrusted DOM event. - * @param aTriggeringPrincipal, if not passed explicitly we fall back to - * the document's principal. - */ - nsresult OnLinkClick(nsIContent* aContent, - nsIURI* aURI, - const char16_t* aTargetSpec, - const nsAString& aFileName, - nsIInputStream* aPostDataStream, - nsIInputStream* aHeadersDataStream, - bool aIsTrusted, - nsIPrincipal* aTriggeringPrincipal); - /** - * Process a click on a link. - * - * Works the same as OnLinkClick() except it happens immediately rather than - * through an event. - * - * @param aContent the content for the frame that generated the trigger - * @param aURI a URI obect that defines the destination for the link - * @param aTargetSpec indicates where the link is targeted (may be an empty - * string) - * @param aFileName non-null when the link should be downloaded as the given file - * @param aPostDataStream the POST data to send - * @param aHeadersDataStream ??? (only used for plugins) - * @param aDocShell (out-param) the DocShell that the request was opened on - * @param aRequest the request that was opened - * @param aTriggeringPrincipal, if not passed explicitly we fall back to - * the document's principal. - */ - nsresult OnLinkClickSync(nsIContent* aContent, - nsIURI* aURI, - const char16_t* aTargetSpec, - const nsAString& aFileName, - nsIInputStream* aPostDataStream = nullptr, - nsIInputStream* aHeadersDataStream = nullptr, - nsIDocShell** aDocShell = nullptr, - nsIRequest** aRequest = nullptr, - nsIPrincipal* aTriggeringPrincipal = nullptr); - /** - * Process a mouse-over a link. - * - * @param aContent the linked content. - * @param aURI an URI object that defines the destination for the link - * @param aTargetSpec indicates where the link is targeted (it may be an empty - * string) - */ - nsresult OnOverLink(nsIContent* aContent, - nsIURI* aURI, - const char16_t* aTargetSpec); - /** - * Process the mouse leaving a link. - */ - nsresult OnLeaveLink(); + // nsILinkHandler + NS_IMETHOD OnLinkClick(nsIContent* aContent, + nsIURI* aURI, + const char16_t* aTargetSpec, + const nsAString& aFileName, + nsIInputStream* aPostDataStream, + nsIInputStream* aHeadersDataStream, + bool aIsTrusted, + nsIPrincipal* aTriggeringPrincipal) override; + NS_IMETHOD OnLinkClickSync(nsIContent* aContent, + nsIURI* aURI, + const char16_t* aTargetSpec, + const nsAString& aFileName, + nsIInputStream* aPostDataStream = 0, + nsIInputStream* aHeadersDataStream = 0, + nsIDocShell** aDocShell = 0, + nsIRequest** aRequest = 0, + nsIPrincipal* aTriggeringPrincipal = nullptr) override; + NS_IMETHOD OnOverLink(nsIContent* aContent, + nsIURI* aURI, + const char16_t* aTargetSpec) override; + NS_IMETHOD OnLeaveLink() override; nsDocShellInfoLoadType ConvertLoadTypeToDocShellLoadInfo(uint32_t aLoadType); uint32_t ConvertDocShellLoadInfoToLoadType( diff --git a/docshell/base/nsILinkHandler.h b/docshell/base/nsILinkHandler.h new file mode 100644 index 0000000000..c7e9db6959 --- /dev/null +++ b/docshell/base/nsILinkHandler.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef nsILinkHandler_h___ +#define nsILinkHandler_h___ + +#include "nsISupports.h" +#include "mozilla/EventForwards.h" + +class nsIContent; +class nsIDocShell; +class nsIInputStream; +class nsIRequest; + +#define NS_ILINKHANDLER_IID \ + { 0xceb9aade, 0x43da, 0x4f1a, \ + { 0xac, 0x8a, 0xc7, 0x09, 0xfb, 0x22, 0x46, 0x64 } } + +/** + * Interface used for handling clicks on links + */ +class nsILinkHandler : public nsISupports +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_ILINKHANDLER_IID) + + /** + * Process a click on a link. + * + * @param aContent the content for the frame that generated the trigger + * @param aURI a URI object that defines the destination for the link + * @param aTargetSpec indicates where the link is targeted (may be an empty + * string) + * @param aPostDataStream the POST data to send + * @param aFileName non-null when the link should be downloaded as the given file + * @param aHeadersDataStream ??? + * @param aIsTrusted false if the triggerer is an untrusted DOM event. + * @param aTriggeringPrincipal, if not passed explicitly we fall back to + * the document's principal. + */ + NS_IMETHOD OnLinkClick(nsIContent* aContent, + nsIURI* aURI, + const char16_t* aTargetSpec, + const nsAString& aFileName, + nsIInputStream* aPostDataStream, + nsIInputStream* aHeadersDataStream, + bool aIsTrusted, + nsIPrincipal* aTriggeringPrincipal) = 0; + + /** + * Process a click on a link. + * + * Works the same as OnLinkClick() except it happens immediately rather than + * through an event. + * + * @param aContent the content for the frame that generated the trigger + * @param aURI a URI obect that defines the destination for the link + * @param aTargetSpec indicates where the link is targeted (may be an empty + * string) + * @param aFileName non-null when the link should be downloaded as the given file + * @param aPostDataStream the POST data to send + * @param aHeadersDataStream ??? + * @param aDocShell (out-param) the DocShell that the request was opened on + * @param aRequest the request that was opened + * @param aTriggeringPrincipal, if not passed explicitly we fall back to + * the document's principal. + */ + NS_IMETHOD OnLinkClickSync(nsIContent* aContent, + nsIURI* aURI, + const char16_t* aTargetSpec, + const nsAString& aFileName, + nsIInputStream* aPostDataStream = 0, + nsIInputStream* aHeadersDataStream = 0, + nsIDocShell** aDocShell = 0, + nsIRequest** aRequest = 0, + nsIPrincipal* aTriggeringPrincipal = nullptr) = 0; + + /** + * Process a mouse-over a link. + * + * @param aContent the linked content. + * @param aURI an URI object that defines the destination for the link + * @param aTargetSpec indicates where the link is targeted (it may be an empty + * string) + */ + NS_IMETHOD OnOverLink(nsIContent* aContent, + nsIURI* aURLSpec, + const char16_t* aTargetSpec) = 0; + + /** + * Process the mouse leaving a link. + */ + NS_IMETHOD OnLeaveLink() = 0; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsILinkHandler, NS_ILINKHANDLER_IID) + +#endif /* nsILinkHandler_h___ */ diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 18858a159f..e8b4364ad6 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -27,6 +27,7 @@ #include "nsIContentIterator.h" #include "nsFocusManager.h" #include "nsFrameManager.h" +#include "nsILinkHandler.h" #include "nsIScriptGlobalObject.h" #include "nsIURL.h" #include "nsContainerFrame.h" diff --git a/dom/base/Element.h b/dom/base/Element.h index 14c53ae465..45c952cae9 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -17,6 +17,7 @@ #include "mozilla/EventStates.h" // for member #include "mozilla/dom/DirectionalityUtils.h" #include "nsIDOMElement.h" +#include "nsILinkHandler.h" #include "nsINodeList.h" #include "nsNodeUtils.h" #include "nsAttrAndChildArray.h" diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 073e0bc192..be9fd44974 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -31,6 +31,7 @@ #include "nsIDOMNodeList.h" #include "nsIContentIterator.h" #include "nsFocusManager.h" +#include "nsILinkHandler.h" #include "nsIScriptGlobalObject.h" #include "nsIURL.h" #include "nsNetUtil.h" diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index abfa901d80..0a82eecf7a 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -60,6 +60,7 @@ #include "nsIDOMNodeList.h" #include "nsIEditor.h" #include "nsIEditorIMESupport.h" +#include "nsILinkHandler.h" #include "mozilla/dom/NodeInfo.h" #include "mozilla/dom/NodeInfoInlines.h" #include "nsIPresShell.h" diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index a5f2442489..3a6c8c293b 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -49,7 +49,6 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsIWebProgress.h" #include "nsIDocShell.h" -#include "nsDocShell.h" // for ::Cast #include "nsIPrompt.h" #include "nsIStringBundle.h" @@ -812,8 +811,9 @@ HTMLFormElement::SubmitSubmission(HTMLFormSubmission* aFormSubmission) // If there is no link handler, then we won't actually be able to submit. nsIDocument* doc = GetComposedDoc(); - nsCOMPtr container = doc ? doc->GetDocShell() : nullptr; - if (!container || IsEditable()) { + nsCOMPtr container = doc ? doc->GetContainer() : nullptr; + nsCOMPtr linkHandler(do_QueryInterface(container)); + if (!linkHandler || IsEditable()) { mIsSubmitting = false; return NS_OK; } @@ -892,12 +892,12 @@ HTMLFormElement::SubmitSubmission(HTMLFormSubmission* aFormSubmission) getter_AddRefs(postDataStream)); NS_ENSURE_SUBMIT_SUCCESS(rv); - rv = nsDocShell::Cast(container)->OnLinkClickSync(this, actionURI, - target.get(), - NullString(), - postDataStream, nullptr, - getter_AddRefs(docShell), - getter_AddRefs(mSubmittingRequest)); + rv = linkHandler->OnLinkClickSync(this, actionURI, + target.get(), + NullString(), + postDataStream, nullptr, + getter_AddRefs(docShell), + getter_AddRefs(mSubmittingRequest)); NS_ENSURE_SUBMIT_SUCCESS(rv); } diff --git a/dom/html/HTMLFormSubmission.cpp b/dom/html/HTMLFormSubmission.cpp index 573e54c674..6a931858b3 100644 --- a/dom/html/HTMLFormSubmission.cpp +++ b/dom/html/HTMLFormSubmission.cpp @@ -7,6 +7,7 @@ #include "nsCOMPtr.h" #include "nsIForm.h" +#include "nsILinkHandler.h" #include "nsIDocument.h" #include "nsGkAtoms.h" #include "nsIFormControl.h" diff --git a/dom/plugins/base/moz.build b/dom/plugins/base/moz.build index b5efcf3b8c..1b6658c283 100644 --- a/dom/plugins/base/moz.build +++ b/dom/plugins/base/moz.build @@ -79,7 +79,6 @@ else: ] LOCAL_INCLUDES += [ - '/docshell/base', '/dom/base', '/dom/plugins/ipc', '/layout/generic', diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index adcfacac37..a424af6e17 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -27,6 +27,7 @@ using mozilla::DefaultXDisplay; #include "nsIStringStream.h" #include "nsNetUtil.h" #include "mozilla/Preferences.h" +#include "nsILinkHandler.h" #include "nsIDocShellTreeItem.h" #include "nsIWebBrowserChrome.h" #include "nsLayoutUtils.h" @@ -45,7 +46,6 @@ using mozilla::DefaultXDisplay; #include "nsIScriptSecurityManager.h" #include "nsIScrollableFrame.h" #include "nsIDocShell.h" -#include "nsDocShell.h" // for ::Cast #include "ImageContainer.h" #include "nsIDOMHTMLCollection.h" #include "GLContext.h" @@ -440,8 +440,10 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, } // the container of the pres context will give us the link handler - nsCOMPtr container = presContext->GetDocShell(); + nsCOMPtr container = presContext->GetContainerWeak(); NS_ENSURE_TRUE(container,NS_ERROR_FAILURE); + nsCOMPtr lh = do_QueryInterface(container); + NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE); nsAutoString unitarget; if ((0 == PL_strcmp(aTarget, "newwindow")) || @@ -493,14 +495,8 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, triggeringPrincipal = BasePrincipal::CreateCodebasePrincipal(uri, attrs); } - rv = nsDocShell::Cast(container)->OnLinkClick(content, - uri, - unitarget.get(), - NullString(), - aPostStream, - headersDataStream, - true, - triggeringPrincipal); + rv = lh->OnLinkClick(content, uri, unitarget.get(), NullString(), + aPostStream, headersDataStream, true, triggeringPrincipal); return rv; } diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 767856a1bc..895de90206 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -34,6 +34,7 @@ #include "nsIDOMHTMLAnchorElement.h" #include "nsISelectionController.h" #include "nsIDOMHTMLDocument.h" +#include "nsILinkHandler.h" #include "nsIInlineSpellChecker.h" #include "mozilla/css/Loader.h" diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 1bde07d467..e10980aecc 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -24,6 +24,7 @@ #include "nsIWritablePropertyBag2.h" #include "nsSubDocumentFrame.h" +#include "nsILinkHandler.h" #include "nsIDOMDocument.h" #include "nsISelectionListener.h" #include "mozilla/dom/Selection.h" diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 0b2f6a17f0..ba99cdf070 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -52,6 +52,7 @@ class nsITheme; class nsIContent; class nsIFrame; class nsFrameManager; +class nsILinkHandler; class nsIAtom; class nsIRunnable; class gfxUserFontEntry; diff --git a/layout/xul/nsImageBoxFrame.cpp b/layout/xul/nsImageBoxFrame.cpp index 2116d39fb0..aa00c5174d 100644 --- a/layout/xul/nsImageBoxFrame.cpp +++ b/layout/xul/nsImageBoxFrame.cpp @@ -3,6 +3,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// +// Eric Vaughan +// Netscape Communications +// +// See documentation in associated header file +// + #include "nsImageBoxFrame.h" #include "nsGkAtoms.h" #include "nsRenderingContext.h" @@ -19,6 +26,7 @@ #include "nsIPresShell.h" #include "nsIDocument.h" #include "nsImageMap.h" +#include "nsILinkHandler.h" #include "nsIURL.h" #include "nsILoadGroup.h" #include "nsContainerFrame.h"