From ef5aa6469e0bfd2f83d5acee3f75a30baf798acb Mon Sep 17 00:00:00 2001
From: deuce <>
Date: Fri, 19 Mar 2010 07:36:53 +0000
Subject: [PATCH] Initial checking of ZuulTerm (working title).

Currently suports RLogin to my BBS as me only.
---
 src/ZuulTerm/Protocol.txt                  | 91 ++++++++++++++++++++++
 src/ZuulTerm/application.ini               |  9 +++
 src/ZuulTerm/chrome/chrome.manifest        |  1 +
 src/ZuulTerm/chrome/content/RLogin.js      | 33 ++++++++
 src/ZuulTerm/chrome/content/Socket.js      | 85 ++++++++++++++++++++
 src/ZuulTerm/chrome/content/Term.js        | 61 +++++++++++++++
 src/ZuulTerm/chrome/content/Util.js        | 39 ++++++++++
 src/ZuulTerm/chrome/content/ZuulTerm.xul   | 29 +++++++
 src/ZuulTerm/chrome/content/default.html   |  3 +
 src/ZuulTerm/defaults/preferences/prefs.js |  2 +
 src/ZuulTerm/zt                            |  2 +
 src/ZuulTerm/zt.cmd                        |  1 +
 12 files changed, 356 insertions(+)
 create mode 100644 src/ZuulTerm/Protocol.txt
 create mode 100644 src/ZuulTerm/application.ini
 create mode 100644 src/ZuulTerm/chrome/chrome.manifest
 create mode 100644 src/ZuulTerm/chrome/content/RLogin.js
 create mode 100644 src/ZuulTerm/chrome/content/Socket.js
 create mode 100644 src/ZuulTerm/chrome/content/Term.js
 create mode 100644 src/ZuulTerm/chrome/content/Util.js
 create mode 100644 src/ZuulTerm/chrome/content/ZuulTerm.xul
 create mode 100644 src/ZuulTerm/chrome/content/default.html
 create mode 100644 src/ZuulTerm/defaults/preferences/prefs.js
 create mode 100755 src/ZuulTerm/zt
 create mode 100644 src/ZuulTerm/zt.cmd

diff --git a/src/ZuulTerm/Protocol.txt b/src/ZuulTerm/Protocol.txt
new file mode 100644
index 0000000000..cfa6dfc06b
--- /dev/null
+++ b/src/ZuulTerm/Protocol.txt
@@ -0,0 +1,91 @@
+                            ZuulTerm Protocol v0.1
+
+
+The ZuulTerm protocol runs on top of an 8-bit clean connection.
+
+The Zuul protocol is a client/server protocol for session control data.
+The idea is that a control connection exists where session data is transferred
+and one or more auxiliary connections for stateless data.
+
+The session is in UTF-8 mode at all times, and the string control characters are
+used as defined in http://www.ecma-inte rnational.org/publications/files/ECMA-ST/Ecma-048.pdf
+No other control characters are supported however.
+
+U+0090
+	Device Control String
+	The contained string contains one of the folowing commands (case sensitive):
+	GET <URL>
+		Where URL is replaced with a valid URL.  The current page is replaced with the contents of the specified
+		URL.
+
+	8.3.27 DCS - DEVICE CONTROL STRING
+    	Notation: (C1)
+    	Representation: 09/00 or ESC 05/00
+    	DCS is used as the opening delimiter of a control string for device control use. The command string
+    	following may consist of bit combinations in the range 00/08 to 00/13 and 02/00 to 07/14. The control
+    	string is closed by the terminating delimiter STRING TERMINATOR (ST).
+    	The command string represents either one or more commands for the receiving device, or one or more
+    	status reports from the sending device. The purpose and the format of the command string are specified
+    	by the most recent occurrence of IDENTIFY DEVICE CONTROL STRING (IDCS), if any, or depend on
+    	the sending and/or the receiving device.
+
+U+009D
+	Operating System Command
+	Used to interact with the OS.  This is *not* a command line to run,
+	but an abstract description of one.
+
+	8.3.89 OSC - OPERATING SYSTEM COMMAND
+		Notation: (C1)
+		Representation: 09/13 or ESC 05/13
+		OSC is used as the opening delimiter of a control string for operating system use. The command string
+		following may consist of a sequence of bit combinations in the range 00/08 to 00/13 and 02/00 to 07/14.
+		The control string is closed by the terminating delimiter STRING TERMINATOR (ST). The
+		interpretation of the command string depends on the relevant operating system.
+
+U+009F 
+	Application Program Command
+	The contained string is JavaScript to be executed in the context of the window current window.  Note the
+	character set restriction however, the JS must be written in a subset of ASCII.
+
+	8.3.2 APC - APPLICATION PROGRAM COMMAND
+		Notation: (C1)
+		Representation: 09/15 or ESC 05/15
+		APC is used as the opening delimiter of a control string for application program use. The command
+		string following may consist of bit combinations in the range 00/08 to 00/13 and 02/00 to 07/14. The
+		control string is closed by the terminating delimiter STRING TERMINATOR (ST). The interpretation of
+		the command string depends on the relevant application program.
+
+U+009C
+    String Terminator
+    Marks the end of a string.
+
+	8.3.143 ST - STRING TERMINATOR
+		Notation: (C1)
+		Representation: 09/12 or ESC 05/12
+		ST is used as the closing delimiter of a control string opened by APPLICATION PROGRAM
+		COMMAND (APC), DEVICE CONTROL STRING (DCS), OPERATING SYSTEM COMMAND
+		(OSC), PRIVACY MESSAGE (PM), or START OF STRING (SOS).
+
+U+009E
+	Privacy Message
+	Unused, must be ignored
+
+	8.3.94 PM - PRIVACY MESSAGE
+		Notation: (C1)
+		Representation: 09/14 or ESC 05/14
+		PM is used as the opening delimiter of a control string for privacy message use. The command string
+		following may consist of a sequence of bit combinations in the range 00/08 to 00/13 and 02/00 to 07/14.
+		The control string is closed by the terminating delimiter STRING TERMINATOR (ST). The
+		interpretation of the command string depends on the relevant privacy discipline.
+
+U+0098
+	Start of String
+	Unused, must be ignored
+
+	8.3.128 SOS - START OF STRING
+		Notation: (C1)
+		Representation: 09/08 or ESC 05/08
+		SOS is used as the opening delimiter of a control string. The character string following may consist of
+		any bit combination, except those representing SOS or STRING TERMINATOR (ST). The control string
+		is closed by the terminating delimiter STRING TERMINATOR (ST). The interpretation of the character
+		string depends on the application.
diff --git a/src/ZuulTerm/application.ini b/src/ZuulTerm/application.ini
new file mode 100644
index 0000000000..7756681ce4
--- /dev/null
+++ b/src/ZuulTerm/application.ini
@@ -0,0 +1,9 @@
+[App]
+Name=ZuulTerm
+Version=0.1
+BuildID=0
+ID=zuulterm@bbsdev.net
+Vendor=Synchronet
+
+[Gecko]
+MinVersion=1.5
diff --git a/src/ZuulTerm/chrome/chrome.manifest b/src/ZuulTerm/chrome/chrome.manifest
new file mode 100644
index 0000000000..dce83ee278
--- /dev/null
+++ b/src/ZuulTerm/chrome/chrome.manifest
@@ -0,0 +1 @@
+content ZuulTerm file:content/
diff --git a/src/ZuulTerm/chrome/content/RLogin.js b/src/ZuulTerm/chrome/content/RLogin.js
new file mode 100644
index 0000000000..857e1c5dbf
--- /dev/null
+++ b/src/ZuulTerm/chrome/content/RLogin.js
@@ -0,0 +1,33 @@
+function RLoginConnection(address, port, recvfunc)
+{
+	this.recvfunc=recvfunc;
+
+	this.onStartRequest=function(request, context) {};
+	this.onStopRequest=function(request, context, status) {
+		alert("Disconnected!");
+		endTerm();
+	};
+	this.onDataAvailable=function(request, context, inputStream, offset, count) {
+		this.recvfunc(this.sock.read(count, count, 0));
+	};
+
+	this.write=function(data)
+	{
+		this.sock.write(data);
+	}
+	this.close=function()
+	{
+		this.sock.close();
+	}
+	this.connected=function()
+	{
+		return(this.sock.transport.isAlive());
+	}
+
+	this.sock=new Socket();
+	this.sock.connect(address,port);
+	this.write("\x00admin\x00deuce\x00ZuulTerm/115200\x00");
+	if(this.sock.read(1,1,10000)!='\x00')
+		alert("No RLogin ack!");
+	this.sock.asyncRead(this);
+}
diff --git a/src/ZuulTerm/chrome/content/Socket.js b/src/ZuulTerm/chrome/content/Socket.js
new file mode 100644
index 0000000000..8c1d1c6981
--- /dev/null
+++ b/src/ZuulTerm/chrome/content/Socket.js
@@ -0,0 +1,85 @@
+function Socket()
+{
+    const sockServiceClass =
+        Components.classes["@mozilla.org/network/socket-transport-service;1"];
+
+    this.sockService = sockServiceClass.getService().QueryInterface(Components.interfaces.nsISocketTransportService);
+}
+
+Socket.prototype.connect=function(addr,port,handler)
+{
+    this.addr = addr.toLowerCase();
+    this.port = port;
+
+    var usingHTTPCONNECT = false;
+
+	this.transport = this.sockService.createTransport(null, 0, addr, port, null);
+	if(!this.transport)
+		throw("Could not create transport!");
+
+	this.outputStream = this.transport.openOutputStream(Components.interfaces.nsITransport.OPEN_BLOCKING, 0, 0);
+	if(!this.outputStream)
+		throw("Could not create output stream!");
+	this.sOutputStream = Components.classes["@mozilla.org/binaryoutputstream;1"].createInstance(Components.interfaces.nsIBinaryOutputStream);
+	if(!this.sOutputStream)
+		throw("Could not create sOutput stream!");
+	this.sOutputStream.setOutputStream(this.outputStream);
+	this.inputStream = this.transport.openInputStream(0/*Components.interfaces.nsITransport.OPEN_BLOCKING*/, 0, 0);
+	if(!this.inputStream)
+		throw("Could not create input stream!");
+	this.sInputStream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
+	if(!this.sInputStream)
+		throw("Could not create Sinput stream!");
+	this.sInputStream.setInputStream(this.inputStream);
+
+    return true;
+}
+
+Socket.prototype.write=function(data)
+{
+	this.sOutputStream.writeBytes(data, data.length);
+}
+
+Socket.prototype.read=function(minbytes, maxbytes, timeout /* milliseconds */)
+{
+	var buf='';
+	var total_delay=0;
+	var recv=0;
+
+	if(typeof(maxbytes) != 'number')
+		maxbytes=1024*1024*1;		// One megabyte
+	if(typeof(minbytes) != 'number')
+		minbytes=1;
+	while(buf.length < minbytes && (typeof(timeout != 'number') || total_delay < timeout)) {
+		if(total_delay) {
+			nsWaitForDelay(100);
+			total_delay += 100;
+		}
+		try {
+			recv=this.sInputStream.available();
+			if(recv > maxbytes)
+				recv=maxbytes;
+			if(recv < minbytes)
+				recv = minbytes;
+			buf += this.sInputStream.readBytes(recv);
+		}
+		catch(e) {
+			// Is this "Would Block"?
+		}
+	}
+	return buf;
+}
+
+Socket.prototype.asyncRead=function(handlers)
+{
+	var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].createInstance(Components.interfaces.nsIInputStreamPump);
+	pump.init(this.inputStream, -1, -1, 1, 1024*1024, false);
+	this.handlers=handlers;
+	pump.asyncRead(handlers, this);
+}
+
+Socket.prototype.close=function()
+{
+	this.inputStream.close();
+	this.outputStream.close();
+}
diff --git a/src/ZuulTerm/chrome/content/Term.js b/src/ZuulTerm/chrome/content/Term.js
new file mode 100644
index 0000000000..2b2e62bde1
--- /dev/null
+++ b/src/ZuulTerm/chrome/content/Term.js
@@ -0,0 +1,61 @@
+var connection=null;
+
+function UpdateTerm(data)
+{
+	var term=document.getElementById("frame").contentDocument.getElementById("terminal");
+	var win=document.getElementById("frame").contentWindow;
+
+	term.innerHTML += data;
+	win.scroll(0, term.clientHeight);
+}
+
+function doTerm(host, port)
+{
+	var ConnOpt=document.getElementById("MainConnectionMenu-connect").disabled=true;
+	var DisconnOpt=document.getElementById("MainConnectionMenu-disconnect").disabled=false;
+	connection=new RLoginConnection(host,port,UpdateTerm);
+}
+
+function endTerm()
+{
+	if(connection != null)
+		connection.close();
+	connection=null;
+
+	var ConnOpt=document.getElementById("MainConnectionMenu-connect").disabled=false;
+	var DisconnOpt=document.getElementById("MainConnectionMenu-disconnect").disabled=true;
+}
+
+function dumpObj(obj,name)
+{
+	var i;
+
+	for(i in obj) {
+//		if(typeof(obj[i]=='object')) {
+//			dumpObj(obj[i],name+"["+i+"]");
+//		}
+//		else {
+			alert(name+"["+i+"]="+obj[i]);
+//		}
+	}
+}
+
+function translateKey(key)
+{
+	var str;
+
+	if(key.charCode==0) {
+		if(key.keyCode < 32)
+			return String.fromCharCode(key.keyCode);
+		alert("Unhandled key code "+key.keyCode);
+		return('');
+	}
+	return String.fromCharCode(key.charCode);
+}
+
+function sendKey(key)
+{
+	if(connection != null) {
+		connection.write(translateKey(key));
+	}
+}
diff --git a/src/ZuulTerm/chrome/content/Util.js b/src/ZuulTerm/chrome/content/Util.js
new file mode 100644
index 0000000000..e826152ffb
--- /dev/null
+++ b/src/ZuulTerm/chrome/content/Util.js
@@ -0,0 +1,39 @@
+
+// From http://sejq.blogspot.com/2008/12/two-javascript-synchronous-sleep.html
+/**
+ * Netscape compatible WaitForDelay function.
+ * You can use it as an alternative to Thread.Sleep() in any major programming language
+ * that support it while JavaScript it self doesn't have any built-in function to do such a thing.
+ * parameters:
+ *  (Number) delay in millisecond
+*/
+function nsWaitForDelay(delay) {
+    /**
+    * Just uncomment this code if you're building an extention for Firefox.
+    * Since FF3, we'll have to ask for user permission to execute XPCOM objects.
+    */
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+    // Get the current thread.
+    var thread = Components.classes["@mozilla.org/thread-manager;1"].getService(Components.interfaces.nsIThreadManager).currentThread;
+
+    // Create an inner property to be used later as a notifier.
+    this.delayed = true;
+
+    /* Call JavaScript setTimeout function
+     * to execute this.delayed = false
+     * after it finish.
+     */
+    setTimeout("this.delayed = false;", delay);
+
+    /**
+     * Keep looping until this.delayed = false
+    */
+    while (this.delayed) {
+        /**
+         * This code will not freeze your browser as it's documented in here:
+         * https://developer.mozilla.org/en/Code_snippets/Threads#Waiting_for_a_background_task_to_complete
+        */
+        thread.processNextEvent(true);
+    }
+}
diff --git a/src/ZuulTerm/chrome/content/ZuulTerm.xul b/src/ZuulTerm/chrome/content/ZuulTerm.xul
new file mode 100644
index 0000000000..3f4d15ce19
--- /dev/null
+++ b/src/ZuulTerm/chrome/content/ZuulTerm.xul
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window id="MainWindow" title="ZuulTerm" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" persist="width height">
+  <script src="chrome://ZuulTerm/content/Util.js" />
+  <script src="chrome://ZuulTerm/content/Socket.js" />
+  <script src="chrome://ZuulTerm/content/RLogin.js" />
+  <script src="chrome://ZuulTerm/content/Term.js" />
+  <menubar id="MainMenubar">
+    <menu id="MainFileMenu" label="File" accesskey="F">
+      <menupopup id="MainFileMenu-popup">
+        <menuitem label="Exit" accesskey="x" oncommand="window.close();"/>
+      </menupopup>
+    </menu>
+    <menu id="MainViewMenu" label="View" accesskey="V">
+      <menupopup id="MainViewMenu-popup">
+        <menuitem label="Directory"  accesskey="D"/>
+        <menuitem label="Scrollback" accesskey="S"/>
+      </menupopup>
+    </menu>
+    <menu id="MainConnectionMenu" label="Connection" accesskey="C">
+      <menupopup id="MainConnectionMenu-popup">
+        <menuitem label="Connect" accesskey="C" disabled="false" oncommand="doTerm('nix.synchro.net', 513);" id="MainConnectionMenu-connect"/>
+        <menuitem label="Disconnect" accesskey="D" disabled="true" oncommand="endTerm();" id="MainConnectionMenu-disconnect"/>
+      </menupopup>
+    </menu>
+  </menubar>
+  <iframe id="frame" src="chrome://ZuulTerm/content/default.html" showcaret="true" onkeypress="sendKey(event)" type="content-primary" flex="1"/>
+</window>
diff --git a/src/ZuulTerm/chrome/content/default.html b/src/ZuulTerm/chrome/content/default.html
new file mode 100644
index 0000000000..e38decf7a2
--- /dev/null
+++ b/src/ZuulTerm/chrome/content/default.html
@@ -0,0 +1,3 @@
+<html>
+  <body><pre id="terminal"></pre></body>
+</html>
diff --git a/src/ZuulTerm/defaults/preferences/prefs.js b/src/ZuulTerm/defaults/preferences/prefs.js
new file mode 100644
index 0000000000..37c7cc71be
--- /dev/null
+++ b/src/ZuulTerm/defaults/preferences/prefs.js
@@ -0,0 +1,2 @@
+pref("toolkit.defaultChromeURI", "chrome://ZuulTerm/content/ZuulTerm.xul");
+pref("javascript.options.showInConsole",true);
diff --git a/src/ZuulTerm/zt b/src/ZuulTerm/zt
new file mode 100755
index 0000000000..18f7882ba2
--- /dev/null
+++ b/src/ZuulTerm/zt
@@ -0,0 +1,2 @@
+#!/bin/sh
+xulrunner application.ini
diff --git a/src/ZuulTerm/zt.cmd b/src/ZuulTerm/zt.cmd
new file mode 100644
index 0000000000..5dece7bfcb
--- /dev/null
+++ b/src/ZuulTerm/zt.cmd
@@ -0,0 +1 @@
+"C:\Program Files\Mozilla Firefox\Firefox.exe" -app application.ini
-- 
GitLab