From eea3c362eb9b4dd2960b15a7d94d06b84bd1373d Mon Sep 17 00:00:00 2001 From: "gijskruitbosch%gmail.com" Date: Sat, 11 Feb 2006 19:26:14 +0000 Subject: [PATCH] Bug 40879 - Add ident server to ChatZilla. ChatZilla Only. p=rdmsoft@bugs.rdmsoft.com (Robert Marshall) r=silver --- extensions/irc/jar.mn | 1 + extensions/irc/js/lib/connection-xpcom.js | 2 +- extensions/irc/js/lib/ident.js | 238 ++++++++++++++++++ extensions/irc/xul/content/handlers.js | 13 + extensions/irc/xul/content/prefs.js | 8 + extensions/irc/xul/content/scripts.xul | 1 + extensions/irc/xul/content/static.js | 2 + .../irc/xul/locale/en-US/chatzilla.properties | 4 + 8 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 extensions/irc/js/lib/ident.js diff --git a/extensions/irc/jar.mn b/extensions/irc/jar.mn index 4e3f8ff6cfa7..25855017c88b 100644 --- a/extensions/irc/jar.mn +++ b/extensions/irc/jar.mn @@ -9,6 +9,7 @@ chatzilla.jar: content/chatzilla/lib/js/pref-manager.js (js/lib/pref-manager.js) content/chatzilla/lib/js/message-manager.js (js/lib/message-manager.js) content/chatzilla/lib/js/menu-manager.js (js/lib/menu-manager.js) + content/chatzilla/lib/js/ident.js (js/lib/ident.js) content/chatzilla/lib/js/irc.js (js/lib/irc.js) content/chatzilla/lib/js/irc-debug.js (js/lib/irc-debug.js) content/chatzilla/lib/js/file-utils.js (js/lib/file-utils.js) diff --git a/extensions/irc/js/lib/connection-xpcom.js b/extensions/irc/js/lib/connection-xpcom.js index 1f95a83477a4..3e4f0e724b93 100644 --- a/extensions/irc/js/lib/connection-xpcom.js +++ b/extensions/irc/js/lib/connection-xpcom.js @@ -339,7 +339,7 @@ function bc_accept(transport, observer) this.isConnected = true; // Clean up listening socket. - this._serverSock.close(); + this.close(); return this.isConnected; } diff --git a/extensions/irc/js/lib/ident.js b/extensions/irc/js/lib/ident.js new file mode 100644 index 000000000000..f21c312de567 --- /dev/null +++ b/extensions/irc/js/lib/ident.js @@ -0,0 +1,238 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Ident Server for ChatZilla. + * + * The Initial Developer of the Original Code is Robert Marshall. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Marshall (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// RFC1413-ish identification server for ChatZilla +// One Ident Server is used for all networks. When multiple networks are in the +// process of connecting, it won't stop listening until they're all done. + +function IdentServer(parent) +{ + this.responses = new Array(); + this.listening = false; + this.dns = getService("@mozilla.org/network/dns-service;1","nsIDNSService"); + + this.parent = parent; + this.eventPump = parent.eventPump; +} + +IdentServer.prototype.start = +function ident_start() +{ + if (this.listening) + return true; + + if (!this.socket) + this.socket = new CBSConnection(); + + if (!this.socket.listen(113, this)) + return false; + + this.listening = true; + return true; +} + +IdentServer.prototype.stop = +function ident_stop() +{ + if (!this.socket || !this.listening) + return; + + // No need to destroy socket, listen() will work again. + this.socket.close(); + this.listening = false; +} + +IdentServer.prototype.addNetwork = +function ident_add(net, serv) +{ + var addr, dnsRecord = this.dns.resolve(serv.hostname, 0); + + while (dnsRecord.hasMore()) + { + addr = dnsRecord.getNextAddrAsString(); + this.responses.push({net: net, ip: addr, port: serv.port, + username: net.INITIAL_NAME}); + } + + if (this.responses.length == 0) + return false; + + // Start the ident server if necessary. + if (!this.listening) + return this.start(); + + return true; +} + +IdentServer.prototype.removeNetwork = +function ident_remove(net) +{ + var newResponses = new Array(); + + for (var i = 0; i < this.responses.length; ++i) + { + if (this.responses[i].net != net) + newResponses.push(this.responses[i]); + } + this.responses = newResponses; + + // Only stop listening if responses is empty - no networks need us anymore. + if (this.responses.length == 0) + this.stop(); +} + +IdentServer.prototype.onSocketAccepted = +function ident_gotconn(serv, transport) +{ + // Using the listening CBSConnection to accept would stop it listening. + // A new CBSConnection does exactly what we want. + var connection = new CBSConnection(); + connection.accept(transport); + + if (jsenv.HAS_NSPR_EVENTQ) + connection.startAsyncRead(new IdentListener(this, connection)); + else + throw "IdentServer requires HAS_NSPR_EVENTQ."; // FIXME +} + +function IdentListener(server, connection) +{ + this.server = server; + this.connection = connection; +} + +IdentListener.prototype.onStreamDataAvailable = +function ident_listener_sda(request, inStream, sourceOffset, count) +{ + var ev = new CEvent("ident-listener", "data-available", this, + "onDataAvailable"); + ev.line = this.connection.readData(0, count); + this.server.eventPump.routeEvent(ev); +} + +IdentListener.prototype.onStreamClose = +function ident_listener_sclose(status) +{ +} + +IdentListener.prototype.onDataAvailable = +function ident_listener_dataavailable(e) +{ + var incomplete = (e.line.substr(-2) != "\r\n"); + var lines = e.line.split(/\r\n/); + + if (this.savedLine) + { + lines[0] = this.savedLine + lines[0]; + this.savedLine = ""; + } + + if (incomplete) + this.savedLine = lines.pop() + + for (var i in lines) + { + var ev = new CEvent("ident-listener", "rawdata", this, "onRawData"); + ev.line = lines[i]; + this.server.eventPump.routeEvent(ev); + } +} + +IdentListener.prototype.onRawData = +function ident_listener_rawdata(e) +{ + var ports = e.line.match(/(\d+) *, *(\d+)/); + // , + // (where "server" is the ident server) + + if (!ports) + { + this.disconnect(); // same meaning as "ERROR : UNKNOWN-ERROR" + return; + } + + e.type = "parsedrequest"; + e.destObject = this; + e.destMethod = "onParsedRequest"; + e.localPort = ports[1]; + e.remotePort = ports[2]; +} + +IdentListener.prototype.onParsedRequest = +function ident_listener_request(e) +{ + function response(str) + { + return e.localPort + " , " + e.remotePort + " : " + str + "\r\n"; + }; + + function validPort(p) + { + return (p >= 1) && (p <= 65535); + }; + + if (!validPort(e.localPort) || !validPort(e.remotePort)) + { + this.connection.sendData(response("ERROR : INVALID-PORT")); + this.disconnect(); + return; + } + + var found, responses = this.server.responses; + for (var i = 0; i < responses.length; ++i) + { + if ((e.remotePort == responses[i].port) && + (this.connection._transport.host == responses[i].ip)) + { + // charset defaults to US-ASCII + // anything except an OS username should use OTHER + // however, ircu sucks, so we can't do that. + this.connection.sendData(response("USERID : CHATZILLA :" + + responses[i].username)); + found = true; + break; + } + } + + if (!found) + this.connection.sendData(response("ERROR : NO-USER")); + + // Spec gives us a choice: drop the connection, or listen for more queries. + // Since IRC servers will only ever want one name, we disconnect. + this.disconnect(); +} diff --git a/extensions/irc/xul/content/handlers.js b/extensions/irc/xul/content/handlers.js index 90d3c8fe1e7f..bbe6864371b9 100644 --- a/extensions/irc/xul/content/handlers.js +++ b/extensions/irc/xul/content/handlers.js @@ -1075,6 +1075,8 @@ function my_showtonet (e) setTimeout(delayFn, 1000 * Math.random(), this); } + client.ident.removeNetwork(this); + // Had some collision during connect. if (this.primServ.me.unicodeName != this.prefs["nickname"]) { @@ -1741,6 +1743,14 @@ function my_sconnect (e) e.server.getURL(), e.connectAttempt, this.MAX_CONNECT_ATTEMPTS]), "INFO"); + + if (this.prefs["identd.enabled"]) + { + if (jsenv.HAS_SERVER_SOCKETS) + client.ident.addNetwork(this, e.server); + else + display(MSG_IDENT_SERVER_NOT_POSSIBLE, MT_WARN); + } } CIRCNetwork.prototype.onError = @@ -1787,6 +1797,7 @@ function my_neterror (e) updateProgress(); } + client.ident.removeNetwork(this); this.display(msg, type); @@ -1891,6 +1902,8 @@ function my_netdisconnect (e) updateProgress(); updateSecurityIcon(); + client.ident.removeNetwork(this); + if ("userClose" in client && client.userClose && client.getConnectionCount() == 0) window.close(); diff --git a/extensions/irc/xul/content/prefs.js b/extensions/irc/xul/content/prefs.js index a67ed1051ac3..b59e78d718ef 100644 --- a/extensions/irc/xul/content/prefs.js +++ b/extensions/irc/xul/content/prefs.js @@ -111,6 +111,12 @@ function initPrefs() } } + // Set a property so network ident prefs get the same group later: + client.prefManager.identGroup = ".connect"; + // Linux and OS X won't let non-root listen on port 113. + if ((client.platform == "Linux") || (client.platform == "Mac")) + client.prefManager.identGroup = "hidden"; + var prefs = [ ["activityFlashDelay", 200, "global"], @@ -145,6 +151,7 @@ function initPrefs() ["hasPrefs", false, "hidden"], ["font.family", "default", "appearance.misc"], ["font.size", 0, "appearance.misc"], + ["identd.enabled", false, client.prefManager.identGroup], ["initialURLs", [], "startup.initialURLs"], ["initialScripts", [getURLSpecFromFile(scriptPath.path)], "startup.initialScripts"], @@ -408,6 +415,7 @@ function getNetworkPrefManager(network) ["font.family", defer, "appearance.misc"], ["font.size", defer, "appearance.misc"], ["hasPrefs", false, "hidden"], + ["identd.enabled", defer, client.prefManager.identGroup], ["ignoreList", [], "hidden"], ["log", client.prefs["networkLog"], ".log"], ["logFileName", makeLogNameNetwork, ".log"], diff --git a/extensions/irc/xul/content/scripts.xul b/extensions/irc/xul/content/scripts.xul index e270b335eaab..341c3c23fe75 100644 --- a/extensions/irc/xul/content/scripts.xul +++ b/extensions/irc/xul/content/scripts.xul @@ -70,6 +70,7 @@