/* * WebSockets IRC client * Copyright (C) 2011 Joel Martin * Licensed under LGPL-3 (see LICENSE.txt) * * Includes VT100.js from: * http://code.google.com/p/sshconsole * Which was modified from: * http://fzort.org/bi/o.php#vt100_js * IRC Client protocol: * http://www.faqs.org/rfcs/rfc2812.html */ function IRC(target, connect_callback, disconnect_callback) { var that = {}, // Public API interface vt100, ws, sQ = [], state = "unconnected", irc_nick, irc_channel, termType = "VT100"; Array.prototype.pushStr = function (str) { var n = str.length; for (var i=0; i < n; i++) { this.push(str.charCodeAt(i)); } } function do_send() { if (sQ.length > 0) { Util.Debug("Sending " + sQ); ws.send(sQ); sQ = []; } } function do_recv() { console.log(">> do_recv"); var rQ, rQi, i; while (ws.rQlen() > 1) { rQ = ws.get_rQ(); rQi = ws.get_rQi(); for (i = rQi; i < rQ.length; i++) { if (rQ[i] === 10) { break; } } if (i >= rQ.length) { // No line break found break; } recvMsg(ws.rQshiftStr((i-rQi) + 1)); } //console.log("<< do_recv"); } // Handle an IRC message function recvMsg(msg) { Util.Debug(">> recvMsg('" + msg + "')"); var tokens = msg.split(' '), in_params = true, prefix, command, params = [], trailing = []; Util.Info(" tokens: " + tokens); if (tokens[0].charAt(0) === ":") { prefix = tokens.shift(); } command = tokens.shift(); while (tokens.length > 0) { if (tokens[0].charAt(0) === ":") { in_params = false; } if (in_params) { params.push(tokens.shift()); } else { trailing.push(tokens.shift()); } } Util.Info(" prefix: " + prefix); Util.Info(" command: " + command); Util.Info(" params: " + params); Util.Info(" trailing: " + trailing); // Show raw received vt100.write(msg); switch (command) { case "004": state = "registered"; vt100.write("Joining channel #" + irc_channel); sendCmd("JOIN #" + irc_channel); break; case "JOIN": state = "joined"; vt100.write("Joined channel #" + irc_channel); break; } Util.Debug("<< recvMsg('" + msg + "')"); } function sendCmd(msg) { Util.Info("Sending: " + msg); sQ.pushStr(msg + "\r\n"); do_send(); } that.sendMsg = function(msg) { // TODO parse into message sendCmd("PRIVMSG #" + irc_channel + " :" + msg); } that.connect = function(host, port, encrypt, nick, channel) { var host = host, port = port, scheme = "ws://", uri; irc_nick = nick; irc_channel = channel; Util.Debug(">> connect"); if ((!host) || (!port)) { alert("must set host and port"); return false; } if (ws) { ws.close(); } if (encrypt) { scheme = "wss://"; } uri = scheme + host + ":" + port; Util.Info("connecting to " + uri); ws.open(uri); Util.Debug("<< connect"); return true; } that.disconnect = function() { Util.Debug(">> disconnect"); if (ws) { ws.close(); } disconnect_callback(); Util.Debug("<< disconnect"); } function constructor() { /* Initialize Websock object */ ws = new Websock(); ws.on('message', do_recv); ws.on('open', function(e) { Util.Info(">> WebSockets.onopen"); // Send registration commands state = "connected"; sendCmd("NICK " + irc_nick); // TODO: how to determine this? sendCmd("USER joelm 0 * :Joel Martin"); connect_callback(); Util.Info("<< WebSockets.onopen"); }); ws.on('close', function(e) { Util.Info(">> WebSockets.onclose"); that.disconnect(); Util.Info("<< WebSockets.onclose"); }); ws.on('error', function(e) { Util.Info(">> WebSockets.onerror"); that.disconnect(); Util.Info("<< WebSockets.onerror"); }); /* Initialize the terminal emulator/renderer */ vt100 = new VT100(80, 24, target); // Show cursor vt100.curs_set(true, false); /* * Override VT100 I/O routines */ // Set handler for sending characters vt100.getch( function send_chr(chr, vt) { var i; Util.Debug(">> send_chr: " + chr); for (i = 0; i < chr.length; i++) { sQ.push(chr.charCodeAt(i)); } do_send(); vt100.getch(send_chr); } ); vt100.debug = function(message) { Util.Debug(message + "\n"); } vt100.warn = function(message) { Util.Warn(message + "\n"); } vt100.curs_set = function(vis, grab, eventist) { this.debug("curs_set:: vis: " + vis + ", grab: " + grab); if (vis !== undefined) this.cursor_vis_ = (vis > 0); } return that; } return constructor(); // Return the public API interface } // End of Telnet()