For quite some time, I have wanted to have a Jabber library in Firefox that I could build extensions around. For my experiments with Google Talk on the desktop, I have been using the Smack API. Smack has served me well, so I decided to try to use it as a model for an equivalent library written in JavaScript for Firefox, leveraging XPCOM. It turns out that Smack has a kickass debug mode that shows all of the XML messages that are sent back and forth while communicating with the server. Below, you can see the messages that Smack and Google Talk exchange when initiating a connection (client messages are in red, server messages are in blue):
<stream:stream to="gmail.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">
<stream:stream from="gmail.com" id="ABAC7E59A46C522E" version="1.0" xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client">
<stream:features>
<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls">
<required/>
</starttls>
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<mechanism>X-GOOGLE-TOKEN</mechanism>
</mechanisms>
</stream:features>
<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
By following a XULPlanet tutorial on sockets, I successfully duplicated the above exchange in Firefox using trusted JavaScript. Unfortunately, then I hit a snag when I tried to replicate the following Java code in JavaScript:
/**
* proceedTLSReceived() in org.jivesoftware.smack.XMPPConnection
*/
void proceedTLSReceived() throws Exception {
SSLContext context = SSLContext.getInstance("TLS");
// Verify certificate presented by the server
context.init(null, // KeyManager not required
new javax.net.ssl.TrustManager[]{new ServerTrustManager(serviceName, configuration)},
new java.security.SecureRandom());
Socket plain = socket;
// Secure the plain connection
socket = context.getSocketFactory().createSocket(plain,
plain.getInetAddress().getHostName(), plain.getPort(), true);
socket.setSoTimeout(0);
socket.setKeepAlive(true);
// Initialize the reader and writer with the new secured version
initReaderAndWriter();
// Proceed to do the handshake
((SSLSocket) socket).startHandshake();
// Set that TLS was successful
usingTLS = true;
// Set the new writer to use
packetWriter.setWriter(writer);
// Send a new opening stream to the server
packetWriter.openStream();
}
As you can see, this requires some logic to deal with security. Although it appears that Firefox has code to handle SSL and TLS, I haven't figured out a way to access it from JavaScript. One option would be to write my own XPCOM object in C++, which is what I suspect Process-one did for their XUL-based XMPP client. Unfortunately, I am not that comfortable with C++, nor am I interested in the overhead involved in compiling for multiple platforms, which is really why I was looking for an existing, scriptable XPCOM object to do the heavy-lifting for me in the first place.
Another possibility is writing an XPCOM object in a language other than C++. I started to explore PyXPCOM for writing modules in Python, but got discouraged when I discovered that Brendan Eich himself commented that PyXPCOM does not make it practical to write Firefox extensions in Python because it requires bundling Python with the extension. I'm guessing that the XPCOM language bindings for Perl, Ruby, and Java have similar limitations.
Then again, what about Java? Unlike Perl and Ruby, there is a standard Java plugin for Firefox, so maybe using JavaXPCOM is a possibility. And even if not, LiveConnect might do the trick, since we have successfully used it for Java-JavaScript communication in Chickenfoot. Being able to leverage Smack as-is would certainly be a windfall if it worked!
Though I am likely going to pursue the Java path to make this happen, I think it would be great if someone with the right know-how created a C++ XPCOM object that exposed a scriptable interface that would let you connect to a Jabber server (using TLS) and provide access to input and output streams for that socket. If anyone knows his way around the GAIM code, he or she could likely leverage what is already there to make this happen. I expect the "plumbing" involved in bringing in the existing C++ code, creating the IDL, and compiling for the major platforms, is likely where more than 80% of the work is – the new code that needs to be written should be fairly minimal.
For the end-user, this would provide the best experience since he would be able to install a Firefox extension without having to install the Java plugin on top of it. Also, the C++ XPCOM object would likely be faster, because in developing Chickenfoot, I learned that crossing the Java/C++ process boundary can be expensive. (This is described in section 8.1.1 of my thesis.) So if anyone is interested in taking on this project, or if you know of an existing solution, then please let me know!