Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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/. */
const RDFS_CONTRACTID = "@mozilla.org/rdf/rdf-service;1";
const CLINE_SERVICE_CID = Components.ID(
"{38a95514-1dd2-11b2-97e7-9da958640f2c}"
);
const STARTUP_CID = Components.ID("{ae6ad015-433b-42ab-9afc-1636af5a7fc4}");
const IRCPROT_HANDLER_CONTRACTID = "@mozilla.org/network/protocol;1?name=irc";
const IRCSPROT_HANDLER_CONTRACTID = "@mozilla.org/network/protocol;1?name=ircs";
const IRCPROT_HANDLER_CID = Components.ID(
"{f21c35f4-1dd1-11b2-a503-9bf8a539ea39}"
);
const IRCSPROT_HANDLER_CID = Components.ID(
"{f21c35f4-1dd1-11b2-a503-9bf8a539ea3a}"
);
function spawnChatZilla(uri, count) {
const hiddenWin = Services.appShell.hiddenDOMWindow;
// Ok, not starting currently, so check if we've got existing windows.
const w = Services.wm.getMostRecentWindow("irc:chatzilla");
// Claiming that a ChatZilla window is loading.
if ("ChatZillaStarting" in hiddenWin) {
dump("cz-service: ChatZilla claiming to be starting.\n");
if (
w &&
"client" in w &&
"initialized" in w.client &&
w.client.initialized
) {
dump("cz-service: It lied. It's finished starting.\n");
// It's actually loaded ok.
delete hiddenWin.ChatZillaStarting;
}
}
if ("ChatZillaStarting" in hiddenWin) {
count = count || 0;
if (new Date() - hiddenWin.ChatZillaStarting > 10000) {
dump("cz-service: Continuing to be unable to talk to existing window!\n");
} else {
// We have a ChatZilla window, but we're still loading.
hiddenWin.setTimeout(
function (count) {
spawnChatZilla(uri, count + 1);
},
250,
count
);
return true;
}
}
// We have a window.
if (w) {
dump("cz-service: Existing, fully loaded window. Using.\n");
// Window is working and initialized ok. Use it.
w.focus();
if (uri) {
w.gotoIRCURL(uri);
}
return true;
}
dump("cz-service: No windows, starting new one.\n");
// Ok, no available window, loading or otherwise, so start ChatZilla.
const args = {};
if (uri) {
args.url = uri;
}
hiddenWin.ChatZillaStarting = new Date();
hiddenWin.openDialog(
"_blank",
"chrome,menubar,toolbar,status,resizable,dialog=no",
args
);
return true;
}
function CommandLineService() {}
CommandLineService.prototype = {
classID: CLINE_SERVICE_CID,
QueryInterface: ChromeUtils.generateQI([Ci.nsICommandLineHandler]),
/* nsICommandLineHandler */
handle(cmdLine) {
var uri;
try {
uri = cmdLine.handleFlagWithParam("chat", false);
} catch (e) {}
if (uri || cmdLine.handleFlag("chat", false)) {
spawnChatZilla(uri || null);
cmdLine.preventDefault = true;
}
},
helpInfo: "-chat [<ircurl>] Start with an IRC chat client.\n",
};
/* factory for command line handler service (CommandLineService) */
const CommandLineFactory = {
createInstance(outer, iid) {
if (outer != null) {
throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
}
return new CommandLineService().QueryInterface(iid);
},
};
function ProcessHandler() {}
ProcessHandler.prototype = {
classID: STARTUP_CID,
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
/* nsIObserver */
observe(subject, topic, data) {
if (topic !== "profile-after-change") {
return;
}
const compMgr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
compMgr.registerFactory(
IRCPROT_HANDLER_CID,
"IRC protocol handler",
IRCPROT_HANDLER_CONTRACTID,
IRCProtocolHandlerFactory
);
compMgr.registerFactory(
IRCSPROT_HANDLER_CID,
"IRCS protocol handler",
IRCSPROT_HANDLER_CONTRACTID,
IRCSProtocolHandlerFactory
);
},
};
const StartupFactory = {
createInstance(outer, iid) {
if (outer) {
throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
}
if (!iid.equals(Ci.nsISupports)) {
throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
}
// startup:
return new ProcessHandler();
},
};
const IRC_MIMETYPE = "application/x-irc";
const IRCS_MIMETYPE = "application/x-ircs";
//XXXgijs: Because necko is annoying and doesn't expose this error flag, we
// define our own constant for it. Throwing something else will show
// ugly errors instead of seeminly doing nothing.
const NS_ERROR_MODULE_NETWORK_BASE = 0x804b0000;
const NS_ERROR_NO_CONTENT = NS_ERROR_MODULE_NETWORK_BASE + 17;
function GenericIRCProtocolHandler(isSecure) {
this.isSecure = isSecure;
this.scheme = isSecure ? "ircs" : "irc";
this.classID = isSecure ? IRCSPROT_HANDLER_CID : IRCPROT_HANDLER_CID;
this.defaultPort = isSecure ? 6697 : 6667;
}
GenericIRCProtocolHandler.prototype = {
QueryInterface: ChromeUtils.generateQI([Ci.nsIProtocolHandler]),
protocolFlags:
Ci.nsIProtocolHandler.URI_NORELATIVE |
Ci.nsIProtocolHandler.ALLOWS_PROXY |
Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE |
Ci.nsIProtocolHandler.URI_NON_PERSISTABLE |
Ci.nsIProtocolHandler.URI_DOES_NOT_RETURN_DATA,
allowPort(port, scheme) {
// Allow all ports to connect, so long as they are irc: or ircs:
return scheme === "irc" || scheme === "ircs";
},
newURI(spec, charset, baseURI) {
return Cc["@mozilla.org/network/standard-url-mutator;1"]
.createInstance(Ci.nsIStandardURLMutator)
.init(
Ci.nsIStandardURL.URLTYPE_STANDARD,
this.defaultPort,
spec,
charset,
baseURI
)
.finalize()
.QueryInterface(Ci.nsIStandardURL);
},
newChannel(URI) {
if (!Services.io.allowPort(URI.port, URI.scheme)) {
throw Components.Exception("", Cr.NS_ERROR_FAILURE);
}
return new BogusChannel(URI, this.isSecure);
},
};
/* Bogus IRC channel used by the IRCProtocolHandler */
function BogusChannel(URI, isSecure) {
this.URI = URI;
this.originalURI = URI;
this.isSecure = isSecure;
this.contentType = this.isSecure ? IRCS_MIMETYPE : IRC_MIMETYPE;
}
BogusChannel.prototype = {
QueryInterface: ChromeUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest]),
/* nsIChannel */
loadAttributes: null,
contentLength: 0,
owner: null,
loadGroup: null,
notificationCallbacks: null,
securityInfo: null,
open(observer, context) {
spawnChatZilla(this.URI.spec);
// We don't throw this (a number, not a real 'resultcode') because it
// upsets xpconnect if we do (error in the js console).
Components.returnCode = NS_ERROR_NO_CONTENT;
},
asyncOpen(observer, context) {
spawnChatZilla(this.URI.spec);
// We don't throw this (a number, not a real 'resultcode') because it
// upsets xpconnect if we do (error in the js console).
Components.returnCode = NS_ERROR_NO_CONTENT;
},
asyncRead(listener, context) {
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
},
/* nsIRequest */
isPending() {
return true;
},
status: Cr.NS_OK,
cancel(status) {
this.status = status;
},
suspend() {
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
},
resume() {
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
},
};
const IRCProtocolHandlerFactory = {
createInstance(outer, iid) {
if (outer != null) {
throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
}
if (!iid.equals(Ci.nsIProtocolHandler) && !iid.equals(Ci.nsISupports)) {
throw Components.Exception("", Cr.NS_ERROR_INVALID_ARG);
}
return new GenericIRCProtocolHandler(false);
},
};
const IRCSProtocolHandlerFactory = {
createInstance(outer, iid) {
if (outer != null) {
throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
}
if (!iid.equals(Ci.nsIProtocolHandler) && !iid.equals(Ci.nsISupports)) {
throw Components.Exception("", Cr.NS_ERROR_INVALID_ARG);
}
return new GenericIRCProtocolHandler(true);
},
};
/* entrypoint */
function NSGetFactory(cid) {
// Checking if we're disabled in the Chrome Registry.
var rv;
try {
const rdfSvc = Cc[RDFS_CONTRACTID].getService(Ci.nsIRDFService);
const rdfDS = rdfSvc.GetDataSource("rdf:chrome");
const resSelf = rdfSvc.GetResource("urn:mozilla:package:chatzilla");
const resDisabled = rdfSvc.GetResource(
);
rv = rdfDS.GetTarget(resSelf, resDisabled, true);
} catch (e) {}
if (rv) {
throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
}
if (cid.equals(CLINE_SERVICE_CID)) {
return CommandLineFactory;
}
if (cid.equals(STARTUP_CID)) {
return StartupFactory;
}
if (cid.equals(IRCPROT_HANDLER_CID)) {
return IRCProtocolHandlerFactory;
}
if (cid.equals(IRCSPROT_HANDLER_CID)) {
return IRCSProtocolHandlerFactory;
}
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
}