*** empty log message ***
authorMatthew Mondor <mmondor@pulsar-zone.net>
Sun, 26 Nov 2006 05:58:58 +0000 (05:58 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Sun, 26 Nov 2006 05:58:58 +0000 (05:58 +0000)
mmsoftware/js/js-sh/app/httpd/httpd.js
mmsoftware/js/js-sh/app/irclog/irclog.js [new file with mode: 0644]

index 23c2225..e5f23e7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: httpd.js,v 1.45 2006/11/24 00:58:45 mmondor Exp $ */
+/* $Id: httpd.js,v 1.46 2006/11/26 05:58:55 mmondor Exp $ */
 
 /*
  * Copyright (c) 2005-2006, Matthew Mondor
@@ -76,7 +76,7 @@
  * Server identification
  */
 const SERVER_VERSION = 'mmondor_js_httpd/0.2.1 (NetBSD)';
-const SERVER_CVSID = '$Id: httpd.js,v 1.45 2006/11/24 00:58:45 mmondor Exp $';
+const SERVER_CVSID = '$Id: httpd.js,v 1.46 2006/11/26 05:58:55 mmondor Exp $';
 
 
 
@@ -2048,6 +2048,10 @@ function main() {
 
                        if (efd.stat != PSTAT_CONTINUE) {
                                try {
+                                       /*
+                                        * XXX This is our closing point,
+                                        * where we actually should log.
+                                        */
                                        efd.close();
                                } catch (x) {}
                                if (efd.type == STYPE_APPSERV) {
diff --git a/mmsoftware/js/js-sh/app/irclog/irclog.js b/mmsoftware/js/js-sh/app/irclog/irclog.js
new file mode 100644 (file)
index 0000000..8168dc9
--- /dev/null
@@ -0,0 +1,300 @@
+/* $Id: irclog.js,v 1.1 2006/11/26 05:58:58 mmondor Exp $ */
+
+/* Configuration */
+var irc_channel = '#test';
+var irc_servers = [
+/*
+       'irc.freenode.net:6667'
+ */
+       'ginseng.xisop:6667',
+       'mudbug.org:6667'
+];
+var irc_nicknames = [
+       'nanobit',
+       'e-chemical',
+       'e-alchemy',
+       'nick_',
+       'nick__'
+];
+var irc_user = 'nanobit', irc_name = 'e-chemical e-alchemy';
+var irc_reconnect_delay = 4;
+var irc_version = '$Id: irclog.js,v 1.1 2006/11/26 05:58:58 mmondor Exp $';
+
+/* XXX Would be more complex, but ideal
+var networks = [
+       {
+               name: "rubiks",
+               channels: [
+                       "#test"
+               ],
+               servers: [
+                       "ginseng.xisop:6667"
+               ]
+       }
+];
+*/
+
+
+
+function sleep(seconds)
+{
+       try {
+               var fh = File.popen('/bin/sleep ' + seconds, 'r');
+               try {
+                       for (;;)
+                               fh.read(256);
+               } catch (x) {}
+               fh.close();
+       } catch (x) { stderr.write(x + "\n"); }
+}
+
+/*
+ * Returns an object with the address and port of a server to (re)connect to.
+ * Uses round-robin among the specified servers array.  We also sleep during
+ * a few seconds to prevent connect-flooding.
+ */
+var last_server = 0;
+function select_server()
+{
+       var w = irc_servers[last_server++].split(':');
+
+       if (last_server == irc_servers.length)
+               last_server = 0;
+       if (w[1] == undefined)
+               w[1] = 6667;
+       else
+               w[1] = Number(w[1]);
+
+       last_nickname = 0;
+
+       return { address: w[0], port: w[1] };
+}
+
+var last_nickname = 0;
+function select_nickname()
+{
+       var s = irc_nicknames[last_nickname++];
+
+       if (last_nickname == irc_nicknames.length)
+               last_nickname = 0;
+
+       irc_nickname = s;
+       return s;
+}
+
+function log_init()
+{
+       var i;
+
+       log_digits = [];
+       for (i = 0; i < 60; i++) {
+               if (i < 10)
+                       log_digits[i] = '0' + i;
+               else
+                       log_digits[i] = i.toString();
+       }
+
+       stdout.setvbuf(File._IOLBF, 0);
+}
+
+function log_timestamp()
+{
+       var t = new Date();
+       var s = t.getUTCFullYear() + log_digits[t.getUTCMonth()] +
+           log_digits[t.getUTCDate()] + log_digits[t.getUTCHours()] +
+           log_digits[t.getUTCMinutes()] + log_digits[t.getUTCSeconds()] +
+           '-0000';
+
+       return s;
+}
+
+File.prototype.getline = function()
+{
+       var line = this.gets(1024, true);
+
+       /* Specifying false to gets() should strip these, but it's broken */
+       line = line.substr(0, line.length - 2);
+
+       /* Log input line as-is with timestamp immediately */
+       stdout.write(log_timestamp() + ' < ' + line + "\n");
+
+       return line;
+}
+
+File.prototype.putline = function(line)
+{
+       stdout.write(log_timestamp() + ' > ' + line + "\n");
+       this.write(line + "\r\n");
+}
+
+File.prototype.state_all = function(line)
+{
+       var s, w, from, to, msg;
+
+       /* PING :<server> */
+       if (line.match(/^PING :/) != null) {
+               this.putline('PONG ' + line.substr(5));
+               return true;
+       }
+
+       /* :<nick>!<user>@<host> PRIVMSG <to> :<message> */
+       if ((s = line.match(/^:[^\b!:]*![^\b@:]*@[^\b:]* PRIVMSG [^\b:]* :/))
+           != null) {
+               s = s.toString();
+               msg = line.substr(s.length);
+               from = line.substr(1, line.indexOf('!') - 1);
+               w = line.split(' ');
+               to = w[2];
+               if (msg.charCodeAt(0) == 0x01 &&
+                   msg.charCodeAt(msg.length - 1) == 0x01) {
+                       /* CTCP */
+                       msg = msg.substr(1, msg.length - 2);
+                       if (msg.match(/^PING [0-9]* [0-9]*$/) != null)
+                               this.putline('NOTICE ' + from + " :\001" +
+                                   msg + "\001");
+                       else if (msg == 'VERSION')
+                               this.putline('NOTICE ' + from + " :\001" +
+                                   'VERSION ' + irc_version + "\001");
+                       else if (msg == 'TIME')
+                               this.putline('NOTICE ' + from + " :\001" +
+                                   'TIME ' + (new Date()).toUTCString() +
+                                   "\001");
+               }
+               return true;
+       }
+
+       return false;
+}
+
+File.prototype.state_nick = function()
+{
+       var line, w;
+
+       stdout.write(log_timestamp() + ' -^- Entering state_nick()' + "\n");
+
+       this.putline('NICK ' + select_nickname());
+       for (;;) {
+               line = this.getline();
+
+               if (this.state_all(line))
+                       continue;
+
+               /* :<server> 433 * <nick> :Nick already used */
+               if (line.match(/^:[^\b:]* 433 * [^\b:]* :/) != null) {
+                       this.putline('NICK ' + select_nickname());
+                       continue;
+               }
+
+               /* :<server> 376 <nick> :End of MOTD */
+               if (line.match(/^:[^\b:]* 376 [^\b:]* :/) != null)
+                       break;
+       }
+
+       this.state = File.prototype.state_log;
+       return true;
+}
+
+File.prototype.state_log = function()
+{
+       var line, from, to, chan, msg, w;
+
+       stdout.write(log_timestamp() + ' -^- Entering state_log()' + "\n");
+
+       for (;;) {
+               if (!on_channel) {
+                       sleep(++join_attempts);
+                       if (join_attempts > 10)
+                               join_attempts = 10;
+                       this.putline('JOIN :' + irc_channel);
+               }
+
+               line = this.getline();
+
+               if (this.state_all(line))
+                       continue;
+
+               /*
+                * XXX
+                * Ideally, for more security, we should detect JOIN and PART
+                * events which are for us but which we did not trigger.
+                * For instance, we want to leave automatically channels
+                * which an oper might have forced us into.  Similarily,
+                * we want to rejoin in case of an unexpected PART event from
+                * our part.  Moreover, it would be nice to also auto-detect
+                * further nickname changes applied to us automatically so
+                * that we may return to the nick state.
+                */
+
+               /* :<nick>!<user>@<host> JOIN :<channel> */
+               if ((s = line.match(/^:[^\b!:]*![^\b@:]*@[^\b:]* JOIN :/))
+                   != null) {
+                       s = s.toString();
+                       msg = line.substr(s.length);
+                       from = line.substr(1, line.indexOf('!') - 1);
+                       if (from.toLowerCase() == irc_nickname.toLowerCase() &&
+                           msg.toLowerCase() == irc_channel.toLowerCase()) {
+                               on_channel = true;
+                               continue;
+                       }
+               }
+
+               /* :<nick>!<user>@<host> KICK <channel> <nick> :<message> */
+               if (line.match(
+                   /^:[^\b!:]*![^\b@:]*@[^\b:]* KICK [^\b:]* [^\b:]* :/)
+                   != null) {
+                       w = line.split(' ');
+                       chan = w[2];
+                       to = w[3];
+                       if (chan.toLowerCase() == irc_channel.toLowerCase() &&
+                           to.toLowerCase() == irc_nickname.toLowerCase()) {
+                               on_channel = false;
+                               join_attempts = 10;
+                               continue;
+                       }
+               }
+       }
+
+       this.putline('QUIT :' + irc_quit_message);
+       return false;
+}
+
+function main()
+{
+       var server;
+       var fd = new FD();
+       var fh;
+       var line;
+
+       log_init();
+       on_channel = false;
+       join_attempts = 0;
+
+       for (;;) { try {
+               server = select_server();
+               stdout.write(log_timestamp() + ' -+- Connecting to ' +
+                   server.address + ':' + server.port + "\n");
+               fd.socket(FD.AF_INET, FD.SOCK_STREAM, 0);
+               fd.connect(server.address, server.port);
+               fd.setsockopt(FD.SO_KEEPALIVE, 1);
+               fh = new File(fd.fd, 'r+');
+               fh.putline('USER ' + irc_user + ' hostname servername :' +
+                   irc_name);
+               fh.state = File.prototype.state_nick;
+               for (;;) {
+                       if (!fh.state())
+                               break;
+               }
+       } catch (x) {
+               stdout.write(log_timestamp() + ' -*- Error: ' + x + "\n");
+       }
+       try {
+               fh.close();
+               fd.close();
+       } catch (x) {}
+       stdout.write(log_timestamp() + ' -+- Disconnected from ' +
+           server.address + ':' + server.port + "\n");
+       sleep(irc_reconnect_delay);
+       }
+}
+
+main();