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