The branch, bug/15495 has been updated
Old revision: ea2b1026d99d10b0f0043555606c3a995a40903b, new revision: 56456f2f515340359c823c51aa8c0a118cf060bf.
via 56456f2f515340359c823c51aa8c0a118cf060bf (commit)
via 4d1d0c2a4fc3ca42d743f75fc9cd71a6069c948d (commit)
via 32c8094ce6e0908ba4efc2b7283deb9ddf9635f6 (commit)
via 9b2b6c38632f19905100860ffaf20dcad36b41a7 (commit)
via 4ba42de164769fa58a6ef6ccc10e003360b1e3a8 (commit)
via bc15477e4726cfd715894b2aa596f0784f2af5ce (commit)
via 6b454d2aa7881ae5f3c40bf1602199e1dbf2be97 (commit)
from ea2b1026d99d10b0f0043555606c3a995a40903b (commit)
- Log -----------------------------------------------------------------
commit 56456f2f515340359c823c51aa8c0a118cf060bf
Author: Jack Twilley <
j...@osuosl.org>
Date: Fri Dec 27 17:12:03 2013 -0800
Updated class models, URLs and views to support SSH.
Tons of new methods, URLs, and such -- mostly cut and pasted from VNC.
commit 4d1d0c2a4fc3ca42d743f75fc9cd71a6069c948d
Author: Jack Twilley <
j...@osuosl.org>
Date: Fri Dec 27 17:11:04 2013 -0800
Add separate tab for SSH and transform jsterm.html to use jsTerm!
The separate tab is temporary for testing purposes.
commit 32c8094ce6e0908ba4efc2b7283deb9ddf9635f6
Author: Jack Twilley <
j...@osuosl.org>
Date: Fri Dec 27 17:10:15 2013 -0800
Protective int casts!
They may not be requird, but they're in the other routine so I put them in this one.
commit 9b2b6c38632f19905100860ffaf20dcad36b41a7
Author: Jack Twilley <
j...@osuosl.org>
Date: Fri Dec 27 17:09:53 2013 -0800
Added support for reaching new static jsTerm files.
The static files are now reachable via 'jsterm'.
commit 4ba42de164769fa58a6ef6ccc10e003360b1e3a8
Author: Jack Twilley <
j...@osuosl.org>
Date: Fri Dec 27 17:09:00 2013 -0800
Added ssh_popout.html.
This is required for feature compatibility.
commit bc15477e4726cfd715894b2aa596f0784f2af5ce
Author: Jack Twilley <
j...@osuosl.org>
Date: Fri Dec 27 17:08:32 2013 -0800
Added jsTerm.js
The analogue to noVNC.js, where the magic should begin happening!
commit 6b454d2aa7881ae5f3c40bf1602199e1dbf2be97
Author: Jack Twilley <
j...@osuosl.org>
Date: Fri Dec 27 17:08:03 2013 -0800
Added jsTerm.
The entire jsTerm package is in the top level of the project.
Summary of changes:
ganeti_webmgr/ganeti_web/settings/base.py | 1 +
ganeti_webmgr/static/js/{noVNC.js => jsTerm.js} | 44 +-
.../templates/ganeti/virtual_machine/detail.html | 10 +-
.../templates/ganeti/virtual_machine/jsterm.html | 28 +-
.../{vnc_popout.html => ssh_popout.html} | 0
ganeti_webmgr/utils/vncdaemon/vapclient.py | 2 +
ganeti_webmgr/virtualmachines/models.py | 8 +-
ganeti_webmgr/virtualmachines/urls.py | 6 +
ganeti_webmgr/virtualmachines/views.py | 21 +
LICENSE.muddle => jsTerm/LICENSE | 4 +-
.../authentication/__init__.py => jsTerm/README | 0
jsTerm/example/index.html | 93 +++
jsTerm/fonts/ansilove_font_pc_80x25.png | Bin 0 -> 61132 bytes
jsTerm/src/Term.js | 32 +
jsTerm/src/parser/AnsiParser.js | 88 +++
jsTerm/src/parser/ByteArray.js | 32 +
jsTerm/src/parser/CharacterCodes.js | 260 +++++++
jsTerm/src/parser/EscapeSequencer.js | 379 ++++++++++
jsTerm/src/parser/Keyboard.js | 11 +
jsTerm/src/parser/NVTCodes.js | 79 ++
jsTerm/src/parser/SixteenColors.js | 20 +
jsTerm/src/parser/Telnet.js | 796 ++++++++++++++++++++
jsTerm/src/telnet/Session.js | 97 +++
jsTerm/src/telnet/Socket.js | 36 +
jsTerm/src/viewer/AnsiViewer.js | 187 +++++
jsTerm/src/viewer/Cursor.js | 65 ++
jsTerm/src/viewer/Font.js | 11 +
jsTerm/src/viewer/Point.js | 10 +
28 files changed, 2281 insertions(+), 39 deletions(-)
copy ganeti_webmgr/static/js/{noVNC.js => jsTerm.js} (83%)
copy ganeti_webmgr/templates/ganeti/virtual_machine/{vnc_popout.html => ssh_popout.html} (100%)
copy LICENSE.muddle => jsTerm/LICENSE (93%)
copy ganeti_webmgr/authentication/__init__.py => jsTerm/README (100%)
create mode 100755 jsTerm/example/index.html
create mode 100644 jsTerm/fonts/ansilove_font_pc_80x25.png
create mode 100644 jsTerm/src/Term.js
create mode 100644 jsTerm/src/parser/AnsiParser.js
create mode 100644 jsTerm/src/parser/ByteArray.js
create mode 100644 jsTerm/src/parser/CharacterCodes.js
create mode 100644 jsTerm/src/parser/EscapeSequencer.js
create mode 100644 jsTerm/src/parser/Keyboard.js
create mode 100644 jsTerm/src/parser/NVTCodes.js
create mode 100644 jsTerm/src/parser/SixteenColors.js
create mode 100644 jsTerm/src/parser/Telnet.js
create mode 100644 jsTerm/src/telnet/Session.js
create mode 100644 jsTerm/src/telnet/Socket.js
create mode 100644 jsTerm/src/viewer/AnsiViewer.js
create mode 100644 jsTerm/src/viewer/Cursor.js
create mode 100644 jsTerm/src/viewer/Font.js
create mode 100644 jsTerm/src/viewer/Point.js
diff --git a/ganeti_webmgr/ganeti_web/settings/base.py b/ganeti_webmgr/ganeti_web/settings/base.py
index 43ed494..5c2b699 100644
--- a/ganeti_webmgr/ganeti_web/settings/base.py
+++ b/ganeti_webmgr/ganeti_web/settings/base.py
@@ -244,6 +244,7 @@ STATICFILES_FINDERS = (
STATICFILES_DIRS = (
app_root('static'),
("novnc", root('noVNC', 'include')),
+ ("jsterm", root('jsTerm',)),
)
STATIC_ROOT = root("collected_static")
diff --git a/ganeti_webmgr/static/js/noVNC.js b/ganeti_webmgr/static/js/jsTerm.js
similarity index 83%
copy from ganeti_webmgr/static/js/noVNC.js
copy to ganeti_webmgr/static/js/jsTerm.js
index 5274126..84c0e67 100644
--- a/ganeti_webmgr/static/js/noVNC.js
+++ b/ganeti_webmgr/static/js/jsTerm.js
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2010 Oregon State University et al.
+ * Copyright (C) 2013 Oregon State University et al.
*
- * Javascript for custom noVNC interface.
+ * Javascript for custom jsTerm interface.
*/
var PROXY_REQUEST_URI;
@@ -21,16 +21,17 @@ $(function () {
// XXX remap document.write to a dom function so that it works after DOM is
// loaded function will be reset after noVNC scripts are loaded.
- var old = document.write;
- document.write = function(str) {$(document).append(str)};
- document.write('<script type="text/javascript" src="'+INCLUDE_URI+'vnc.js"><//script>');
- document.write = old;
+ // JMT Stolen from noVNC, will use for jsTerm
+ // var old = document.write;
+ // document.write = function(str) {$(document).append(str)};
+ // document.write('<script type="text/javascript" src="'+INCLUDE_URI+'vnc.js"><//script>');
+ // document.write = old;
// XXX manually call __initialize(). This normally happens onload, but
// won't work for us since document may have been loaded already
- if (!Websock_native) {WebSocket.__initialize();}
+ // if (!Websock_native) {WebSocket.__initialize();}
- var rfb;
+ var session;
var host, port, password; // VNC proxy connection settings
var connected = false;
@@ -55,7 +56,7 @@ $(function () {
event.preventDefault();
var $this = $(this);
if($this.hasClass('enabled')) {
- rfb.disconnect();
+ session.disconnect();
connected = false;
} else {
connected = true;
@@ -85,7 +86,7 @@ $(function () {
.click(function(event){
event.preventDefault();
if (!$(this).hasClass('disabled')) {
- rfb.sendCtrlAltDel();
+ session.sendCtrlAltDel();
}
});
@@ -93,7 +94,7 @@ $(function () {
popout.click(function(event) {
event.preventDefault();
var url;
- if (rfb == undefined) {
+ if (session == undefined) {
url = POPOUT_URL;
} else {
url = POPOUT_URL + '?auto_connect=1';
@@ -118,7 +119,7 @@ $(function () {
return true;
}
- function updateState(rfb, state, oldstate, msg) {
+ function updateState(session, state, oldstate, msg) {
var klass;
switch (state) {
case 'failed':
@@ -164,9 +165,9 @@ $(function () {
}
function stop() {
- if (rfb != undefined) {
- rfb.disconnect();
- rfb = undefined;
+ if (session != undefined) {
+ session.disconnect();
+ session = undefined;
}
}
@@ -195,17 +196,8 @@ $(function () {
});
if (!show_errors()) return false;
- rfb = new RFB({
- // jQuery doesn't work with that, need to stick
- // to pure DOM
- 'target': document.getElementById('VNC_canvas'),
- 'encrypt': is_encrypted,
- 'true_color': true,
- 'local_cursor': true,
- 'shared': true,
- 'updateState': updateState
- });
- rfb.connect(host, port, password);
+ session = new TERM.Session(INCLUDE_URI+"fonts/ansilove_font_pc_80x25.png");
+ session.connect(host, port); // , password);
return false;
}
});
diff --git a/ganeti_webmgr/templates/ganeti/virtual_machine/detail.html b/ganeti_webmgr/templates/ganeti/virtual_machine/detail.html
index 526e3b7..b81e490 100644
--- a/ganeti_webmgr/templates/ganeti/virtual_machine/detail.html
+++ b/ganeti_webmgr/templates/ganeti/virtual_machine/detail.html
@@ -199,9 +199,15 @@
{%endif%}
{% if admin or power %}
<li>
- <a title="console"
+ <a title="vnc-console"
href="{% url instance-vnc cluster.slug instance.hostname %}">
- {% trans "Console" %}
+ {% trans "VNC" %}
+ </a>
+ </li>
+ <li>
+ <a title="ssh-console"
+ href="{% url instance-ssh cluster.slug instance.hostname %}">
+ {% trans "SSH" %}
</a>
</li>
{% endif %}
diff --git a/ganeti_webmgr/templates/ganeti/virtual_machine/jsterm.html b/ganeti_webmgr/templates/ganeti/virtual_machine/jsterm.html
index eeca635..91b1ed1 100644
--- a/ganeti_webmgr/templates/ganeti/virtual_machine/jsterm.html
+++ b/ganeti_webmgr/templates/ganeti/virtual_machine/jsterm.html
@@ -3,15 +3,31 @@
#actions {margin-bottom:30px;}
</style>
<script type="text/javascript">
- // Set include path for noVNC scripts
- var INCLUDE_URI = "{{STATIC_URL}}/novnc/";
+ // Set include path for jsTerm scripts
+ var INCLUDE_URI = "{{STATIC_URL}}/jsterm/";
// Set path for proxy requests
- var PROXY_REQUEST_URI = "{% url instance-vnc-proxy cluster_slug instance.hostname %}";
+ var PROXY_REQUEST_URI = "{% url instance-ssh-proxy cluster_slug instance.hostname %}";
{% if not popout %}
- var POPOUT_URL = "{% url instance-vnc-popout cluster_slug instance.hostname %}";
+ // var POPOUT_URL = "{% url instance-ssh-popout cluster_slug instance.hostname %}";
{% endif %}
</script>
-<script type="text/javascript" src="{{STATIC_URL}}/js/noVNC.js"></script>
+ <script src='{{STATIC_URL}}/jsterm/src/Term.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/parser/Keyboard.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/parser/CharacterCodes.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/parser/SixteenColors.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/parser/ByteArray.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/parser/EscapeSequencer.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/parser/AnsiParser.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/parser/NVTCodes.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/parser/Telnet.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/viewer/Point.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/viewer/Font.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/viewer/Cursor.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/viewer/AnsiViewer.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/telnet/Socket.js'></script>
+ <script src='{{STATIC_URL}}/jsterm/src/telnet/Session.js'></script>
+
+<script type="text/javascript" src="{{STATIC_URL}}/js/jsTerm.js"></script>
<ul id="actions" class="horizontal">
<li><a id="encrypt" href="#" title="encrypt" class="button encrypt">{% trans "Encrypt" %}</a></li>
@@ -32,7 +48,7 @@
<div id="VNC_screen">
<div id="VNC_status_bar" class="VNC_status_bar">
- noVNC client
+ jsTerm client
</div>
<canvas id="VNC_canvas">
{% blocktrans %}Canvas is not supported in your browser. Please use new versions
diff --git a/ganeti_webmgr/templates/ganeti/virtual_machine/vnc_popout.html b/ganeti_webmgr/templates/ganeti/virtual_machine/ssh_popout.html
similarity index 100%
copy from ganeti_webmgr/templates/ganeti/virtual_machine/vnc_popout.html
copy to ganeti_webmgr/templates/ganeti/virtual_machine/ssh_popout.html
diff --git a/ganeti_webmgr/utils/vncdaemon/vapclient.py b/ganeti_webmgr/utils/vncdaemon/vapclient.py
index a1151da..315d335 100644
--- a/ganeti_webmgr/utils/vncdaemon/vapclient.py
+++ b/ganeti_webmgr/utils/vncdaemon/vapclient.py
@@ -78,6 +78,8 @@ def request_ssh(proxy, sport, daddr, dport, password, command):
"""
host, port = proxy
+ port = int(port)
+ dport = int(dport)
if not password or not command:
return False
diff --git a/ganeti_webmgr/virtualmachines/models.py b/ganeti_webmgr/virtualmachines/models.py
index 540d0d1..323acf0 100644
--- a/ganeti_webmgr/virtualmachines/models.py
+++ b/ganeti_webmgr/virtualmachines/models.py
@@ -292,12 +292,16 @@ class VirtualMachine(CachedClusterObject):
"""
command = self.rapi.GetInstanceConsole(self.hostname)["command"]
+ password = ''
+ info_ =
self.info
+ port = info_['network_port']
+ node = info_['pnode']
if settings.CONSOLE_PROXY:
proxy_server = settings.CONSOLE_PROXY.split(":")
password = generate_random_password()
- sport = request_ssh(proxy_server, sport,
self.info["pnode"],
-
self.info["network_port"], password, command)
+ sport = request_ssh(proxy_server, sport, node, port,
+ password, command)
if sport:
return proxy_server[0], sport, password
diff --git a/ganeti_webmgr/virtualmachines/urls.py b/ganeti_webmgr/virtualmachines/urls.py
index eb1934a..084bd94 100644
--- a/ganeti_webmgr/virtualmachines/urls.py
+++ b/ganeti_webmgr/virtualmachines/urls.py
@@ -28,10 +28,16 @@ urlpatterns = patterns(
url(r'^%s/vnc/?$' % vm_prefix, 'novnc', name="instance-vnc"),
+ url(r'^%s/ssh/?$' % vm_prefix, 'jsterm', name="instance-ssh"),
+
url(r'^%s/vnc/popout/?$' % vm_prefix, 'novnc',
{'template': 'ganeti/virtual_machine/vnc_popout.html'},
name="instance-vnc-popout"),
+ url(r'^%s/ssh/popout/?$' % vm_prefix, 'jsterm',
+ {'template': 'ganeti/virtual_machine/ssh_popout.html'},
+ name="instance-ssh-popout"),
+
url(r'^%s/vnc_proxy/?$' % vm_prefix, 'vnc_proxy',
name="instance-vnc-proxy"),
diff --git a/ganeti_webmgr/virtualmachines/views.py b/ganeti_webmgr/virtualmachines/views.py
index 0adfb62..ac643cd 100644
--- a/ganeti_webmgr/virtualmachines/views.py
+++ b/ganeti_webmgr/virtualmachines/views.py
@@ -271,6 +271,27 @@ def novnc(request,
context_instance=RequestContext(request), )
+@login_required
+def jsterm(request,
+ cluster_slug,
+ instance,
+ template="ganeti/virtual_machine/jsterm.html"):
+ vm = get_object_or_404(VirtualMachine, hostname=instance,
+ cluster__slug=cluster_slug)
+ user = request.user
+ if not (user.is_superuser
+ or user.has_any_perms(vm, ['admin', 'power'])
+ or user.has_perm('admin', vm.cluster)):
+ return HttpResponseForbidden(_('You do not have permission '
+ 'to vnc on this'))
+
+ return render_to_response(template,
+ {'cluster_slug': cluster_slug,
+ 'instance': vm,
+ },
+ context_instance=RequestContext(request), )
+
+
@require_POST
@login_required
def vnc_proxy(request, cluster_slug, instance):
diff --git a/LICENSE.muddle b/jsTerm/LICENSE
similarity index 93%
copy from LICENSE.muddle
copy to jsTerm/LICENSE
index 57db33a..ce2a40c 100644
--- a/LICENSE.muddle
+++ b/jsTerm/LICENSE
@@ -1,6 +1,4 @@
-The MIT License
-
-Copyright (c) 2010 Oregon State University
+Copyright (c) 2010 Peter Nitsch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/ganeti_webmgr/authentication/__init__.py b/jsTerm/README
similarity index 100%
copy from ganeti_webmgr/authentication/__init__.py
copy to jsTerm/README
diff --git a/jsTerm/example/index.html b/jsTerm/example/index.html
new file mode 100755
index 0000000..d4647e7
--- /dev/null
+++ b/jsTerm/example/index.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "
http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html>
+<head>
+ <title>jsTerm Example</title>
+ <script src='../src/Term.js'></script>
+ <script src='../src/parser/Keyboard.js'></script>
+ <script src='../src/parser/CharacterCodes.js'></script>
+ <script src='../src/parser/SixteenColors.js'></script>
+ <script src='../src/parser/ByteArray.js'></script>
+ <script src='../src/parser/EscapeSequencer.js'></script>
+ <script src='../src/parser/AnsiParser.js'></script>
+ <script src='../src/parser/NVTCodes.js'></script>
+ <script src='../src/parser/Telnet.js'></script>
+ <script src='../src/viewer/Point.js'></script>
+ <script src='../src/viewer/Font.js'></script>
+ <script src='../src/viewer/Cursor.js'></script>
+ <script src='../src/viewer/AnsiViewer.js'></script>
+ <script src='../src/telnet/Socket.js'></script>
+ <script src='../src/telnet/Session.js'></script>
+
+ <script src='
http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js'></script>
+ <script>
+ $(document).ready(function(){
+
+ var session = new TERM.Session("../fonts/ansilove_font_pc_80x25.png");
+ var host = document.getElementById("host");
+ var port = document.getElementById("port");
+ var connect = document.getElementById("connect");
+ var bookmarks = document.getElementById("bookmarks");
+
+ connect.onclick = function() {
+ session.connect(host.value, port.value);
+ }
+
+ bookmarks.onchange = function() {
+ var val = bookmarks.value;
+ if(val!=""){
+ var i = val.indexOf(":");
+ host.value = val.slice(0, i);
+ port.value = val.slice(i+1, val.length);
+ }
+ }
+
+ });
+ </script>
+</head>
+<body>
+ <div id="terminal"><canvas id="canvas" width="650" height="440"></canvas> </div>
+
+ <div id="panel">
+ <select id="bookmarks" name="bookmarks">
+ <option value="">- Bookmarks -</option>
+ <option value="
towel.blinkenlights.nl:23">
towel.blinkenlights.nl</option>
+ <option value="
vert.synchro.net:23">
vert.synchro.net</option>
+ <option value="
bbs.pharcyde.org:23">
bbs.pharcyde.org</option>
+ <option value="
d1st.org:23">
d1st.org</option>
+ <option value="
bbs.electronicchicken.com:23">
bbs.electronicchicken.com</option>
+ <option value="
entropybbs.co.nz:23">
entropybbs.co.nz</option>
+ <option value="
lunatic.zapto.org:23">
lunatic.zapto.org</option>
+ <option value="
bbs.roughneckbbs.com:23">
bbs.roughneckbbs.com</option>
+ <option value="
masqueradebbs.com:23">
masqueradebbs.com</option>
+ <option value="
alecoexp.dyndns.org:23">
alecoexp.dyndns.org</option>
+ <option value="
bluewavebbs.dyndns.org:23">
bluewavebbs.dyndns.org</option>
+ <option value="
bbs.akroncdnr.com:23">
bbs.akroncdnr.com</option>
+ <option value="
cbliss.synchro.net:23">
cbliss.synchro.net</option>
+ <option value="
ds69bbs.com:23">
ds69bbs.com</option>
+ <option value="
bbs.defcon.no:23">
bbs.defcon.no</option>
+ <option value="
bbs.dmine.net:23">
bbs.dmine.net</option>
+ <option value="
bbs.diskshop.ca:23">
bbs.diskshop.ca</option>
+ <option value="
eotd.com:23">
eotd.com</option>
+ <option value="
flashpointbbs.no-ip.org:23">
flashpointbbs.no-ip.org</option>
+ <option value="
fjbbs.gotdns.com:23">
fjbbs.gotdns.com</option>
+ <option value="
isisunveiled.no-ip.org:23">
isisunveiled.no-ip.org</option>
+ <option value="
bbs.zeusdev.co.uk:23">
bbs.zeusdev.co.uk</option>
+ <option value="
musicstation.spb.ru:5223">
musicstation.spb.ru</option>
+ <option value="
phybbs.dyndns.org:23">
phybbs.dyndns.org</option>
+ <option value="
rdfig.net:23">
rdfig.net</option>
+ <option value="
redhill.net.nz:4500">
redhill.net.nz</option>
+ <option value="
bbs.dxrw.org:23">
bbs.dxrw.org</option>
+ <option value="
bbs.scansoutheasternmass.com:23">
bbs.scansoutheasternmass.com</option>
+ <option value="
thechangeosp.nl:23">
thechangeosp.nl</option>
+ <option value="
darkside.dtdns.net:23">
darkside.dtdns.net</option>
+ <option value="
white-squirrel.dnsalias.net:23">
white-squirrel.dnsalias.net</option>
+ <option value="
wildcatcastle.gotdns.com:23">
wildcatcastle.gotdns.com</option>
+ <option value="
bbs.zzap.org:23">
bbs.zzap.org</option>
+ </select>
+ <input id="host" type="text" value="
towel.blinkenlights.nl">
+ <input id="port" type="text" value="23">
+ <input id="connect" type="button" value="Connect">
+ </div>
+</body>
+</html>
diff --git a/jsTerm/fonts/ansilove_font_pc_80x25.png b/jsTerm/fonts/ansilove_font_pc_80x25.png
new file mode 100644
index 0000000..98aa572
Binary files /dev/null and b/jsTerm/fonts/ansilove_font_pc_80x25.png differ
diff --git a/jsTerm/src/Term.js b/jsTerm/src/Term.js
new file mode 100644
index 0000000..64b3ab2
--- /dev/null
+++ b/jsTerm/src/Term.js
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2010 Peter Nitsch
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author Peter Nitsch
+ *
http://jsterm.com
+ *
http://www.peternitsch.net
+ */
+
+var TERM = TERM || {
+ socket : null,
+ SERVER_URL : "127.0.0.1", // Your node.js server IP
+ SERVER_PORT : "8888", // Your node.js server port
+ VERSION : "0.1 alpha"
+};
\ No newline at end of file
diff --git a/jsTerm/src/parser/AnsiParser.js b/jsTerm/src/parser/AnsiParser.js
new file mode 100644
index 0000000..7444771
--- /dev/null
+++ b/jsTerm/src/parser/AnsiParser.js
@@ -0,0 +1,88 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.AnsiParser = function (viewer){
+
+ var viewer = viewer;
+ var escapeCommand = [];
+ var bufferEscapeCommand = false;
+
+ this.escapeCommands = new TERM.EscapeSequencer(viewer);
+ this._bytes;
+
+ this.parse = function (bytes) {
+
+ if( bytes != null ) this._bytes = new TERM.ByteArray(bytes);
+
+ while( this._bytes.bytesAvailable > 0 ){
+ var result = this._bytes.readUnsignedByte();
+
+ if( result == SUBSTITUTE) {
+ break;
+ } else {
+ this.readByte( result );
+ }
+ }
+
+ this._bytes.position = 0;
+ };
+
+ this._exceptionsLib = [];
+ this._exceptions = [];
+
+ this.hasException = function( code ) {
+ if( this._exceptions.indexOf(code) != -1 )
+ return true;
+ return false;
+ };
+
+ this.writeException = function( code, callback ) {
+ if( !this.hasException(code) ){
+ this._exceptionsLib[code] = callback;
+ this._exceptions.push(code);
+ }
+ };
+
+ this.readByte = function (b) {
+
+ if(b == ESCAPE) {
+ escapeCommand = [];
+ escapeCommand.push(b);
+ bufferEscapeCommand = true;
+ } else {
+ if(bufferEscapeCommand){
+ escapeCommand.push(b);
+ if( this.escapeCommands.checkCommandAction(escapeCommand.length, b) ) {
+ this.escapeCommands.executeCommand(escapeCommand);
+ bufferEscapeCommand = false;
+ }
+ } else if( this.hasException(b) ) {
+ this._exceptionsLib[b]( b, this._bytes );
+ } else if(b >= SPACE) {
+ viewer.drawCharacter(b);
+ } else {
+ switch(b) {
+ case BACKSPACE:
+ viewer.moveBackward(1, true);
+ break;
+
+ case LINE_FEED:
+ viewer.carriageReturn();
+ viewer.moveDown(1);
+ break;
+
+ case CARRIAGE_RETURN:
+ viewer.carriageReturn();
+ break;
+
+ case FORM_FEED:
+ viewer.eraseScreen();
+ viewer.reposition(0, 0);
+ break;
+ }
+ }
+ }
+ };
+
+};
\ No newline at end of file
diff --git a/jsTerm/src/parser/ByteArray.js b/jsTerm/src/parser/ByteArray.js
new file mode 100644
index 0000000..482bf47
--- /dev/null
+++ b/jsTerm/src/parser/ByteArray.js
@@ -0,0 +1,32 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.ByteArray = function (bytes){
+
+ this.position = 0;
+ this.stringdata = bytes;
+
+ this.readUnsignedByte = function(){
+ var b = this.stringdata.charCodeAt(this.position);
+ if(this.position!=this.stringdata.length) this.position++;
+ return b;
+ };
+
+ this.writeByte = function(){
+ // TO DO
+ };
+
+};
+
+TERM.ByteArray.prototype = {
+
+ get bytesAvailable (){
+ return this.stringdata.length - this.position;
+ },
+ get length (){
+ return this.stringdata.length;
+ }
+
+};
+
diff --git a/jsTerm/src/parser/CharacterCodes.js b/jsTerm/src/parser/CharacterCodes.js
new file mode 100644
index 0000000..e1684af
--- /dev/null
+++ b/jsTerm/src/parser/CharacterCodes.js
@@ -0,0 +1,260 @@
+/**
+ * @author Peter Nitsch
+ */
+
+const NULL = 0
+const START_OF_HEADING = 1;
+const START_OF_TEXT = 2;
+const END_OF_TEXT = 3;
+const END_OF_TRANSMISSION = 4;
+const ENQUIRY = 5;
+const ACKNOWLEDGE = 6;
+const BELL = 7;
+const BACKSPACE = 8;
+const HORIZONTAL_TABULATION = 9;
+const LINE_FEED = 10;
+const VERTICAL_TABULATION = 11;
+const FORM_FEED = 12;
+const CARRIAGE_RETURN = 13;
+const SHIFT_OUT = 14;
+const SHIFT_IN = 15;
+const DATA_LINK_ESCAPE = 16;
+const DEVICE_CONTROL_ONE = 17;
+const DEVICE_CONTROL_TWO = 18;
+const DEVICE_CONTROL_THREE = 19;
+const DEVICE_CONTROL_FOUR = 20;
+const NEGATIVE_ACKNOWLEDGE = 21;
+const SYNCHRONOUS_IDLE = 22;
+const END_OF_TRANSMISSION_BLOCK = 23;
+const CANCEL = 24;
+const END_OF_MEDIUM = 25;
+const SUBSTITUTE = 26;
+const ESCAPE = 27;
+const FILE_SEPARATOR = 28;
+const GROUP_SEPARATOR = 29;
+const RECORD_SEPARATOR = 30;
+const UNIT_SEPARATOR = 31;
+const SPACE = 32;
+const EXCLAMATION_MARK = 33;
+const QUOTATION_MARK = 34;
+const uint_SIGN = 35;
+const DOLLAR_SIGN = 36;
+const PERCENT_SIGN = 37;
+const AMPERSAND = 38;
+const APOSTROPHE = 39;
+const LEFT_PARENTHESIS = 40;
+const RIGHT_PARENTHESIS = 41;
+const ASTERISK = 42;
+const PLUS_SIGN = 43;
+const COMMA = 44;
+const HYPHEN_MINUS = 45;
+const FULL_STOP = 46;
+const SOLIDUS = 47;
+const DIGIT_ZERO = 48;
+const DIGIT_ONE = 49;
+const DIGIT_TWO = 50;
+const DIGIT_THREE = 51;
+const DIGIT_FOUR = 52;
+const DIGIT_FIVE = 53;
+const DIGIT_SIX = 54;
+const DIGIT_SEVEN = 55;
+const DIGIT_EIGHT = 56;
+const DIGIT_NINE = 57;
+const COLON = 58;
+const SEMICOLON = 59;
+const LESS_THAN_SIGN = 60;
+const EQUALS_SIGN = 61;
+const GREATER_THAN_SIGN = 62;
+const QUESTION_MARK = 63;
+const COMMERCIAL_AT = 64;
+const LATIN_CAPITAL_LETTER_A = 65;
+const LATIN_CAPITAL_LETTER_B = 66;
+const LATIN_CAPITAL_LETTER_C = 67;
+const LATIN_CAPITAL_LETTER_D = 68;
+const LATIN_CAPITAL_LETTER_E = 69;
+const LATIN_CAPITAL_LETTER_F = 70;
+const LATIN_CAPITAL_LETTER_G = 71;
+const LATIN_CAPITAL_LETTER_H = 72;
+const LATIN_CAPITAL_LETTER_I = 73;
+const LATIN_CAPITAL_LETTER_J = 74;
+const LATIN_CAPITAL_LETTER_K = 75;
+const LATIN_CAPITAL_LETTER_L = 76;
+const LATIN_CAPITAL_LETTER_M = 77;
+const LATIN_CAPITAL_LETTER_N = 78;
+const LATIN_CAPITAL_LETTER_O = 79;
+const LATIN_CAPITAL_LETTER_P = 80;
+const LATIN_CAPITAL_LETTER_Q = 81;
+const LATIN_CAPITAL_LETTER_R = 82;
+const LATIN_CAPITAL_LETTER_S = 83;
+const LATIN_CAPITAL_LETTER_T = 84;
+const LATIN_CAPITAL_LETTER_U = 85;
+const LATIN_CAPITAL_LETTER_V = 86;
+const LATIN_CAPITAL_LETTER_W = 87;
+const LATIN_CAPITAL_LETTER_X = 88;
+const LATIN_CAPITAL_LETTER_Y = 89;
+const LATIN_CAPITAL_LETTER_Z = 90;
+const LEFT_SQUARE_BRACKET = 91;
+const REVERSE_SOLIDUS = 92;
+const RIGHT_SQUARE_BRACKET = 93;
+const CIRCUMFLEX_ACCENT = 94;
+const LOW_LINE = 95;
+const GRAVE_ACCENT = 96;
+const LATIN_SMALL_LETTER_A = 97;
+const LATIN_SMALL_LETTER_B = 98;
+const LATIN_SMALL_LETTER_C = 99;
+const LATIN_SMALL_LETTER_D = 100;
+const LATIN_SMALL_LETTER_E = 101;
+const LATIN_SMALL_LETTER_F = 102;
+const LATIN_SMALL_LETTER_G = 103;
+const LATIN_SMALL_LETTER_H = 104;
+const LATIN_SMALL_LETTER_I = 105;
+const LATIN_SMALL_LETTER_J = 106;
+const LATIN_SMALL_LETTER_K = 107;
+const LATIN_SMALL_LETTER_L = 108;
+const LATIN_SMALL_LETTER_M = 109;
+const LATIN_SMALL_LETTER_N = 110;
+const LATIN_SMALL_LETTER_O = 111;
+const LATIN_SMALL_LETTER_P = 112;
+const LATIN_SMALL_LETTER_Q = 113;
+const LATIN_SMALL_LETTER_R = 114;
+const LATIN_SMALL_LETTER_S = 115;
+const LATIN_SMALL_LETTER_T = 116;
+const LATIN_SMALL_LETTER_U = 117;
+const LATIN_SMALL_LETTER_V = 118;
+const LATIN_SMALL_LETTER_W = 119;
+const LATIN_SMALL_LETTER_X = 120;
+const LATIN_SMALL_LETTER_Y = 121;
+const LATIN_SMALL_LETTER_Z = 122;
+const LEFT_CURLY_BRACKET = 123;
+const VERTICAL_LINE = 124;
+const RIGHT_CURLY_BRACKET = 125;
+const TILDE = 126;
+const DELETE = 127;
+const LATIN_CAPITAL_LETTER_C_WITH_CEDILLA = 128;
+const LATIN_SMALL_LETTER_U_WITH_DIAERESIS = 129;
+const LATIN_SMALL_LETTER_E_WITH_ACUTE = 130;
+const LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX = 131;
+const LATIN_SMALL_LETTER_A_WITH_DIAERESIS = 132;
+const LATIN_SMALL_LETTER_A_WITH_GRAVE = 133;
+const LATIN_SMALL_LETTER_A_WITH_RING_ABOVE = 134;
+const LATIN_SMALL_LETTER_C_WITH_CEDILLA = 135;
+const LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX = 136;
+const LATIN_SMALL_LETTER_E_WITH_DIAERESIS = 137;
+const LATIN_SMALL_LETTER_E_WITH_GRAVE = 138;
+const LATIN_SMALL_LETTER_I_WITH_DIAERESIS = 139;
+const LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX = 140;
+const LATIN_SMALL_LETTER_I_WITH_GRAVE = 141;
+const LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS = 142;
+const LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE = 143;
+const LATIN_CAPITAL_LETTER_E_WITH_ACUTE = 144;
+const LATIN_SMALL_LETTER_AE = 145;
+const LATIN_CAPITAL_LETTER_AE = 146;
+const LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX = 147;
+const LATIN_SMALL_LETTER_O_WITH_DIAERESIS = 148;
+const LATIN_SMALL_LETTER_O_WITH_GRAVE = 149;
+const LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX = 150;
+const LATIN_SMALL_LETTER_U_WITH_GRAVE = 151;
+const LATIN_SMALL_LETTER_Y_WITH_DIAERESIS = 152;
+const LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS = 153;
+const LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS = 154;
+const CENT_SIGN = 155;
+const POUND_SIGN = 156;
+const YEN_SIGN = 157;
+const PESETA_SIGN = 158;
+const LATIN_SMALL_LETTER_F_WITH_HOOK = 159;
+const LATIN_SMALL_LETTER_A_WITH_ACUTE = 160;
+const LATIN_SMALL_LETTER_I_WITH_ACUTE = 161;
+const LATIN_SMALL_LETTER_O_WITH_ACUTE = 162;
+const LATIN_SMALL_LETTER_U_WITH_ACUTE = 163;
+const LATIN_SMALL_LETTER_N_WITH_TILDE = 164;
+const LATIN_CAPITAL_LETTER_N_WITH_TILDE = 165;
+const FEMININE_ORDINAL_INDICATOR = 166;
+const MASCULINE_ORDINAL_INDICATOR = 167;
+const INVERTED_QUESTION_MARK = 168;
+const REVERSED_NOT_SIGN = 169;
+const NOT_SIGN = 170;
+const VULGAR_FRACTION_ONE_HALF = 171;
+const VULGAR_FRACTION_ONE_QUARTER = 172;
+const INVERTED_EXCLAMATION_MARK = 173;
+const LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK = 174;
+const RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK = 175;
+const LIGHT_SHADE = 176;
+const MEDIUM_SHADE = 177;
+const DARK_SHADE = 178;
+const BOX_DRAWINGS_LIGHT_VERTICAL = 179;
+const BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT = 180;
+const BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE = 181;
+const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE = 182;
+const BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE = 183;
+const BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE = 184;
+const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT = 185;
+const BOX_DRAWINGS_DOUBLE_VERTICAL = 186;
+const BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT = 187;
+const BOX_DRAWINGS_DOUBLE_UP_AND_LEFT = 188;
+const BOX_DRAWINGS_UP_DOUBLE_AND_LEFT_SINGLE = 189;
+const BOX_DRAWINGS_UP_SINGLE_AND_LEFT_DOUBLE = 190;
+const BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT = 191;
+const BOX_DRAWINGS_LIGHT_UP_AND_RIGHT = 192;
+const BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL = 193;
+const BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL = 194;
+const BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT = 195;
+const BOX_DRAWINGS_LIGHT_HORIZONTAL = 196;
+const BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL = 197;
+const BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE = 198;
+const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE = 199;
+const BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT = 200;
+const BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT = 201;
+const BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL = 202;
+const BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL = 203;
+const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT = 204;
+const BOX_DRAWINGS_DOUBLE_HORIZONTAL = 205;
+const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL = 206;
+const BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE = 207;
+const BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE = 208;
+const BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE = 209;
+const BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE = 210;
+const BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE = 211;
+const BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE = 212;
+const BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE = 213;
+const BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE = 214;
+const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE = 215;
+const BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE = 216;
+const BOX_DRAWINGS_LIGHT_UP_AND_LEFT = 217;
+const BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT = 218;
+const FULL_BLOCK = 219;
+const LOWER_HALF_BLOCK = 220;
+const LEFT_HALF_BLOCK = 221;
+const RIGHT_HALF_BLOCK = 222;
+const UPPER_HALF_BLOCK = 223;
+const GREEK_SMALL_LETTER_ALPHA = 224;
+const LATIN_SMALL_LETTER_SHARP_S = 225;
+const GREEK_CAPITAL_LETTER_GAMMA = 226;
+const GREEK_SMALL_LETTER_PI = 227;
+const GREEK_CAPITAL_LETTER_SIGMA = 228;
+const GREEK_SMALL_LETTER_SIGMA = 229;
+const MICRO_SIGN = 230;
+const GREEK_SMALL_LETTER_TAU = 231;
+const GREEK_CAPITAL_LETTER_PHI = 232;
+const GREEK_CAPITAL_LETTER_THETA = 233;
+const GREEK_CAPITAL_LETTER_OMEGA = 234;
+const GREEK_SMALL_LETTER_DELTA = 235;
+const INFINITY = 236;
+const GREEK_SMALL_LETTER_PHI = 237;
+const GREEK_SMALL_LETTER_EPSILON = 238;
+const INTERSECTION = 239;
+const IDENTICAL_TO = 240;
+const PLUS_MINUS_SIGN = 241;
+const GREATER_THAN_OR_EQUAL_TO = 242;
+const LESS_THAN_OR_EQUAL_TO = 243;
+const TOP_HALF_INTEGRAL = 244;
+const BOTTOM_HALF_INTEGRAL = 245;
+const DIVISION_SIGN = 246;
+const ALMOST_EQUAL_TO = 247;
+const DEGREE_SIGN = 248;
+const BULLET_OPERATOR = 249;
+const MIDDLE_DOT = 250;
+const SQUARE_ROOT = 251;
+const SUPERSCRIPT_LATIN_SMALL_LETTER_N = 252;
+const SUPERSCRIPT_TWO = 253;
+const BLACK_SQUARE = 254;
+const NO_BREAK_SPACE = 255;
\ No newline at end of file
diff --git a/jsTerm/src/parser/EscapeSequencer.js b/jsTerm/src/parser/EscapeSequencer.js
new file mode 100644
index 0000000..50e32f7
--- /dev/null
+++ b/jsTerm/src/parser/EscapeSequencer.js
@@ -0,0 +1,379 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.EscapeSequencer = function (viewer){
+
+ var viewer = viewer;
+ var telnet;
+
+ var _customCommand;
+ var _currentCustomCommand = {};
+
+ this.actionCharacterLib = [];
+
+ this.init = function() {
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_H ] = this.cursorPosition;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_F ] = this.cursorPosition;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_A ] = this.cursorUp;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_B ] = this.cursorDown;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_C] = this.cursorForward;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_D ] = this.cursorBackward;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_S ] = this.saveCursorPosition;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_U ] = this.restoreCursorPosition;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_K ] = this.eraseLine;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_J ] = this.eraseDisplay;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_N ] = this.deviceRequest;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_M ] = this.setGraphicsMode;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_H ] = this.setMode;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_L ] = this.resetMode;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_P ] = this.setKeyboardStrings;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_M ] = this.scrollUp;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_R ] = this.scrollScreen;
+
+ // TO DO
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_A ] = this.unused;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_D ] = this.unused;
+ this.actionCharacterLib[ LATIN_SMALL_LETTER_E ] = this.unused;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_L ] = this.unused;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_P ] = this.unused;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_E ] = this.unused;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_F ] = this.unused;
+ this.actionCharacterLib[ LATIN_CAPITAL_LETTER_X ] = this.unused;
+
+ };
+
+ this.executeCommand = function(command) {
+ try {
+ this.actionCharacterLib[ command[command.length-1] ]( command );
+ } catch(error) {
+ console.log(error);
+ }
+ };
+
+ this.checkCommandAction = function(position, character) {
+ if( this.actionCharacterLib[character] != undefined )
+ return true;
+
+ return false;
+ };
+
+ this.unused = function(params) {
+ // EMPTY
+ };
+
+ this.deviceRequest = function(params) {
+ if( params[2]==DIGIT_FIVE ){
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(DIGIT_ZERO);
+ TERM.socket.writeByte(LATIN_SMALL_LETTER_N);
+ } else if( params[2]==DIGIT_SIX ) {
+ var i;
+ var rows = "" + viewer.cursor.y;
+ var cols = "" + viewer.cursor.x;
+
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ for(i=0;i<rows.length;i++) TERM.socket.writeByte(rows.charCodeAt(i));
+ TERM.socket.writeByte(SEMICOLON);
+ for(i=0;i<cols.length;i++) TERM.socket.writeByte(cols.charCodeAt(i));
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_R);
+ } else {
+ // 0 - Report Device OK
+ // 3 - Report Device Failure
+ }
+ };
+
+ this.cursorPosition = function(params) {
+ var lastCharacter = params[params.length-1];
+
+ if( params.length==3 && lastCharacter==LATIN_CAPITAL_LETTER_H){
+ viewer.home();
+ } else {
+ var lineArray = [];
+ var lineStr = "";
+ var line = 0;
+
+ var columnArray = [];
+ var columnStr = "";
+ var column = 0;
+
+ if(params.indexOf(SEMICOLON) != -1){
+ var semicolonIndex = params.indexOf(SEMICOLON);
+
+ if( params[semicolonIndex-1] != LEFT_SQUARE_BRACKET ) {
+ lineArray = params.slice(2, semicolonIndex);
+ for( i=0; i<lineArray.length; i++ ){
+ lineStr += (lineArray[i] - 48).toString();
+ }
+ line = parseInt(lineStr);
+ }
+
+ columnArray = params.slice(semicolonIndex+1, params.length-1);
+ for( i=0; i<columnArray.length; i++ ){
+ columnStr += (columnArray[i] - 48).toString();
+ }
+ column = parseInt(columnStr);
+
+ } else if(params.slice(2, params.indexOf(lastCharacter)).length > 0){
+ lineArray = params.slice(2, params.length-1);
+ for( i=0; i<lineArray.length; i++ ){
+ lineStr += (lineArray[i] - 48).toString();
+ }
+ line = parseInt(lineStr);
+ }
+
+ column = (column>0) ? column-1 : 0;
+ line = (line>0) ? line-1 : 0;
+
+ viewer.reposition(column, line);
+ }
+ };
+
+ this.cursorUp = function(params) {
+ var valueArray = params.slice(2, params.length-1);
+ var valueStr = "";
+ for( i=0; i<valueArray.length; i++ ){
+ valueStr += (valueArray[i] - 48).toString();
+ }
+ var value = (valueStr.length > 0) ? parseInt(valueStr) : 1;
+
+ viewer.moveUp(value);
+ };
+
+ this.cursorDown = function(params) {
+ var valueArray = params.slice(2, params.length-1);
+ var valueStr = "";
+ for( i=0; i<valueArray.length; i++ ){
+ valueStr += (valueArray[i] - 48).toString();
+ }
+ var value = (valueStr.length > 0) ? parseInt(valueStr) : 1;
+
+ viewer.moveDown(value);
+ };
+
+ this.cursorForward = function(params) {
+ var valueArray = params.slice(2, params.length-1);
+ var valueStr = "";
+ for( i=0; i<valueArray.length; i++ ){
+ valueStr += (valueArray[i] - 48).toString();
+ }
+ var value = (valueStr.length > 0) ? parseInt(valueStr) : 1;
+
+ viewer.moveForward(value);
+ };
+
+ this.cursorBackward = function(params) {
+ var valueArray = params.slice(2, params.length-1);
+ var valueStr = "";
+ for( i=0; i<valueArray.length; i++ ){
+ valueStr += (valueArray[i] - 48).toString();
+ }
+ var value = (valueStr.length > 0) ? parseInt(valueStr) : 1;
+
+ viewer.moveBackward(value);
+ };
+
+ this.saveCursorPosition = function(params) {
+ viewer.savePosition();
+ };
+
+ this.restoreCursorPosition = function(params) {
+ viewer.restorePosition();
+ };
+
+ // Set Graphic Mode functions
+ var _bold = false;
+ var _reverse = false;
+
+ var _boldColors = [BLACK_BOLD, RED_BOLD, GREEN_BOLD, YELLOW_BOLD, BLUE_BOLD, MAGENTA_BOLD, CYAN_BOLD, WHITE_BOLD];
+ var _normalColors = [BLACK_NORMAL, RED_NORMAL, GREEN_NORMAL, YELLOW_NORMAL, BLUE_NORMAL, MAGENTA_NORMAL, CYAN_NORMAL, WHITE_NORMAL];
+
+ var _currentForegroundColor = WHITE_NORMAL;
+ var _currentBackgroundColor = BLACK_NORMAL;
+
+ this.setGraphicsMode = function(params) {
+ for( i=2; i<params.length; i++ ){
+ switch( params[i] ){
+
+ /* Reset */
+ case LATIN_SMALL_LETTER_M:
+ case DIGIT_ZERO:
+ if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET){
+ _bold = false;
+ _reverse = false;
+
+ _currentForegroundColor = WHITE_NORMAL;
+ _currentBackgroundColor = BLACK_NORMAL;
+
+ viewer.foregroundColorChanged(_currentForegroundColor);
+ viewer.backgroundColorChanged(_currentBackgroundColor);
+ }
+ break;
+
+ /* Bold ON */
+ case DIGIT_ONE:
+ if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET) {
+ _bold = true;
+
+ for( j=0; j<_normalColors.length; j++ ){
+ if( _currentForegroundColor == _normalColors[j] )
+ _currentForegroundColor = _boldColors[j];
+ }
+
+ viewer.foregroundColorChanged(_currentForegroundColor);
+ }
+ break;
+
+ /* Dim */
+ case DIGIT_TWO:
+ if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET) {
+ _bold = false;
+
+ for( j=0; j<_normalColors.length; j++ ){
+ if( _currentForegroundColor == _boldColors[j] )
+ _currentForegroundColor = _normalColors[j];
+ }
+
+ viewer.foregroundColorChanged(_currentForegroundColor);
+ }
+ break;
+
+ /* Set foreground color */
+ case DIGIT_THREE:
+ if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET){
+ if(params[i+1] != SEMICOLON && params[i+1] != LATIN_SMALL_LETTER_M){
+
+ var position = params[i+1] - 48;
+ if(_reverse) {
+ _currentBackgroundColor = _normalColors[position];
+ viewer.backgroundColorChanged(_currentBackgroundColor);
+ }else {
+ _currentForegroundColor = (_bold) ? _boldColors[position] : _normalColors[position];
+ viewer.foregroundColorChanged(_currentForegroundColor);
+ }
+
+ }
+ }
+ break;
+
+ /* Set background color */
+ case DIGIT_FOUR:
+ if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET){
+ if(params[i+1] != SEMICOLON && params[i+1] != LATIN_SMALL_LETTER_M){
+ position = params[i+1] - 48;
+ if(_reverse) {
+ _currentForegroundColor = (_bold) ? _boldColors[position] : _normalColors[position];
+ viewer.foregroundColorChanged(_currentForegroundColor);
+ } else {
+ _currentBackgroundColor = _normalColors[position];
+ viewer.backgroundColorChanged(_currentBackgroundColor);
+ }
+
+ /* Underline ON */
+ } else {
+ // TO DO
+ }
+ }
+ break;
+
+ /* Blink ON */
+ case DIGIT_FIVE:
+ // TO DO
+ break;
+
+ /* Reverse ON */
+ case DIGIT_SEVEN:
+ if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET)
+ _reverse = true;
+ break;
+
+ /* Concealed ON */
+ case DIGIT_EIGHT:
+ // TO DO
+ break;
+
+ /* Reset to normal? */
+ case DIGIT_NINE:
+ // TO DO
+ break;
+ }
+ }
+ };
+
+ this.scrollScreen = function(params) {
+ if(params.length==3){
+ viewer.scrollScreen();
+ } else {
+ var lastCharacter = params[params.length-1];
+
+ var sArray = [];
+ var sStr = "";
+ var s = 0;
+
+ var eArray = [];
+ var eStr = "";
+ var e = 0;
+
+ var semicolonIndex = params.indexOf(SEMICOLON);
+
+ sArray = params.slice(2, semicolonIndex);
+ for( i=0; i<sArray.length; i++ ){
+ sStr += (sArray[i] - 48).toString();
+ }
+ s = parseInt(sStr);
+
+
+ eArray = params.slice(semicolonIndex+1, params.length-1);
+ for( i=0; i<eArray.length; i++ ){
+ eStr += (eArray[i] - 48).toString();
+ }
+ e = parseInt(eStr);
+
+ viewer.scrollScreen(s, e);
+ }
+ };
+
+ this.scrollUp = function(params) {
+ viewer.scrollUp(1);
+ };
+
+ this.eraseLine = function(params) {
+ if( params[2]==DIGIT_ONE ){
+ viewer.eraseStartOfLine();
+ } else if( params[2]==DIGIT_TWO ) {
+ viewer.eraseLine();
+ } else {
+ viewer.eraseEndOfLine();
+ }
+ };
+
+ this.eraseDisplay = function(params) {
+ if( params[2]==DIGIT_ONE ){
+ viewer.eraseUp();
+ viewer.reposition(0, 0);
+ } else if( params[2]==DIGIT_TWO ) {
+ viewer.eraseScreen();
+ viewer.reposition(0, 0);
+ } else {
+ viewer.eraseDown();
+ }
+ };
+
+ // Terminal functions
+ this.setMode = function(){
+ // TO DO
+ };
+
+ this.resetMode = function(){
+ // TO DO
+ };
+
+ this.setKeyboardStrings = function(){
+ // TO DO
+ };
+
+ this.init();
+
+};
\ No newline at end of file
diff --git a/jsTerm/src/parser/Keyboard.js b/jsTerm/src/parser/Keyboard.js
new file mode 100644
index 0000000..0854a13
--- /dev/null
+++ b/jsTerm/src/parser/Keyboard.js
@@ -0,0 +1,11 @@
+/**
+ * @author Peter Nitsch
+ */
+
+const KEYBOARD_LEFT = 37;
+const KEYBOARD_RIGHT = 39;
+const KEYBOARD_UP = 38;
+const KEYBOARD_DOWN = 40;
+const KEYBOARD_PAGE_UP = 33;
+const KEYBOARD_PAGE_DOWN = 34;
+const KEYBOARD_HOME = 36;
diff --git a/jsTerm/src/parser/NVTCodes.js b/jsTerm/src/parser/NVTCodes.js
new file mode 100644
index 0000000..5e4f947
--- /dev/null
+++ b/jsTerm/src/parser/NVTCodes.js
@@ -0,0 +1,79 @@
+/**
+ * @author Peter Nitsch
+ */
+
+const IAC = 255;
+const GA = 249;
+const WILL = 251;
+const WONT = 252;
+const DO = 253;
+const DONT = 254;
+const SB = 250;
+const SE = 240;
+const NOP = 241;
+const DM = 242;
+const BRK = 243;
+
+const IP = 244;
+const AO = 245;
+const AYT = 246;
+const EC = 247;
+const EL = 248;
+
+const ECHO = 1;
+const SUPGA = 3;
+
+const NAWS = 31;
+const TTYPE = 24;
+const IS = 0;
+const SEND = 1;
+const LOGOUT = 18;
+
+const LINEMODE = 34;
+const LM_MODE = 1;
+const LM_EDIT = 1;
+const LM_TRAPSIG = 2;
+const LM_MODEACK = 4;
+const LM_FORWARDMASK = 2;
+
+const LM_SLC = 3;
+const LM_SLC_NOSUPPORT = 0;
+const LM_SLC_DEFAULT = 3;
+const LM_SLC_VALUE = 2;
+const LM_SLC_CANTCHANGE = 1;
+const LM_SLC_LEVELBITS = 3;
+const LM_SLC_ACK = 128;
+const LM_SLC_FLUSHIN = 64;
+const LM_SLC_FLUSHOUT = 32;
+
+const LM_SLC_SYNCH = 1;
+const LM_SLC_BRK = 2;
+const LM_SLC_IP = 3;
+const LM_SLC_AO = 4;
+const LM_SLC_AYT = 5;
+const LM_SLC_EOR = 6;
+const LM_SLC_ABORT = 7;
+const LM_SLC_EOF = 8;
+const LM_SLC_SUSP = 9;
+
+const NEWENV = 39;
+const NE_INFO = 2;
+const NE_VAR = 0;
+const NE_VALUE = 1;
+const NE_ESC = 2;
+const NE_USERVAR = 3;
+
+const NE_VAR_OK = 2;
+const NE_VAR_DEFINED = 1;
+const NE_VAR_DEFINED_EMPTY = 0;
+const NE_VAR_UNDEFINED = -1;
+const NE_IN_ERROR = -2;
+const NE_IN_END = -3;
+const NE_VAR_NAME_MAXLENGTH = 50;
+const NE_VAR_VALUE_MAXLENGTH = 1000;
+
+// Unused
+const EXT_ASCII = 17;
+const SEND_LOC = 23;
+const AUTHENTICATION = 37;
+const ENCRYPT = 38;
\ No newline at end of file
diff --git a/jsTerm/src/parser/SixteenColors.js b/jsTerm/src/parser/SixteenColors.js
new file mode 100644
index 0000000..fdf658a
--- /dev/null
+++ b/jsTerm/src/parser/SixteenColors.js
@@ -0,0 +1,20 @@
+/**
+ * @author Peter Nitsch
+ */
+
+const BLACK_NORMAL = "#000000";
+const BLACK_BOLD = "#545454";
+const RED_NORMAL = "#a80000";
+const RED_BOLD = "#fc5454";
+const GREEN_NORMAL = "#00a800";
+const GREEN_BOLD = "#54fc54";
+const YELLOW_NORMAL = "#a85400";
+const YELLOW_BOLD = "#fcfc54";
+const BLUE_NORMAL = "#0000a8";
+const BLUE_BOLD = "#5454fc";
+const MAGENTA_NORMAL = "#a800a8";
+const MAGENTA_BOLD = "#fc54fc";
+const CYAN_NORMAL = "#00a8a8";
+const CYAN_BOLD = "#54fcfc";
+const WHITE_NORMAL = "#a8a8a8";
+const WHITE_BOLD = "#fcfcfc";
\ No newline at end of file
diff --git a/jsTerm/src/parser/Telnet.js b/jsTerm/src/parser/Telnet.js
new file mode 100644
index 0000000..74d68f2
--- /dev/null
+++ b/jsTerm/src/parser/Telnet.js
@@ -0,0 +1,796 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Telnet = function (viewer){
+
+ var parser = viewer.parser;
+ var _actionCharacterLib = [];
+
+ var bytes;
+
+ this.init = function() {
+ _actionCharacterLib[ IAC ] = interpretCommand;
+ parser.writeException(IAC, interpretCommand);
+ };
+
+ function interpretCommand(code, b) {
+ bytes = b;
+ var command = bytes.readUnsignedByte();
+ handleC(command);
+ };
+
+ function read16int () {
+ var c = 0;
+ try {
+ c = bytes.readUnsignedByte();
+ return c;
+ } catch (e) {
+ console.log(e);
+ }
+
+ return c;
+ };
+
+ function IamHere() {
+ try {
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(DO);
+ TERM.socket.writeByte(AYT);
+ } catch (error) {
+ console.log("IamHere() Error "+ error);
+ }
+ };
+
+ function nvtBreak() {
+ // TO DO
+ };
+
+ function setTerminalGeometry (width, height) {
+ // TO DO
+ };
+
+ function setEcho(b) {
+ // TO DO
+ };
+
+ var buffer = [0,0];
+
+ var DO_ECHO = false;
+ var DO_SUPGA = false;
+ var DO_NAWS = false;
+ var DO_TTYPE = false;
+ var DO_LINEMODE = false;
+ var DO_NEWENV = false;
+
+ var WAIT_DO_REPLY_SUPGA = false;
+ var WAIT_DO_REPLY_ECHO = false;
+ var WAIT_DO_REPLY_NAWS = false;
+ var WAIT_DO_REPLY_TTYPE = false;
+ var WAIT_DO_REPLY_LINEMODE = false;
+ var WAIT_LM_MODE_ACK = false;
+ var WAIT_LM_DO_REPLY_FORWARDMASK = false;
+ var WAIT_DO_REPLY_NEWENV = false;
+ var WAIT_NE_SEND_REPLY = false;
+
+ var WAIT_WILL_REPLY_SUPGA = false;
+ var WAIT_WILL_REPLY_ECHO = false;
+ var WAIT_WILL_REPLY_NAWS = false;
+ var WAIT_WILL_REPLY_TTYPE = false;
+
+ function doCharacterModeInit() {
+ sendCommand(WILL, ECHO, true);
+ sendCommand(DONT, ECHO, true);
+ sendCommand(DO, NAWS, true);
+ sendCommand(WILL, SUPGA, true);
+ sendCommand(DO, SUPGA, true);
+ sendCommand(DO, TTYPE, true);
+ sendCommand(DO, NEWENV, true);
+ };
+
+ function doLineModeInit() {
+ sendCommand(DO, NAWS, true);
+ sendCommand(WILL, SUPGA, true);
+ sendCommand(DO, SUPGA, true);
+ sendCommand(DO, TTYPE, true);
+ sendCommand(DO, LINEMODE, true);
+ sendCommand(DO, NEWENV, true);
+ };
+
+ function handleC(i) {
+ buffer[0] = i;
+ if (!parseTWO(buffer)) {
+ try {
+ buffer[1] = bytes.readUnsignedByte();
+ parse(buffer);
+ } catch(e) {
+ console.log(e);
+ }
+ }
+
+ buffer[0] = 0;
+ buffer[1] = 0;
+ };
+
+ function parseTWO(buf) {
+ switch (buf[0]) {
+ case IAC:
+ break;
+ case AYT:
+ IamHere();
+ break;
+ case AO:
+ case IP:
+ case EL:
+ case EC:
+ case NOP:
+ break;
+ case BRK:
+ nvtBreak();
+ break;
+ default:
+ return false;
+ }
+ return true;
+ };
+
+ function parse(buf) {
+ switch (buf[0]) {
+ case WILL:
+ if (supported(buf[1]) && isEnabled(buf[1])) {
+ ;
+ } else {
+ if (waitDOreply(buf[1]) && supported(buf[1])) {
+ enable(buf[1]);
+ setWait(DO, buf[1], false);
+ } else {
+ if (supported(buf[1])) {
+ sendCommand(DO, buf[1], false);
+ enable(buf[1]);
+ } else {
+ sendCommand(DONT, buf[1], false);
+ }
+ }
+ }
+ break;
+ case WONT:
+ if (waitDOreply(buf[1]) && supported(buf[1])) {
+ setWait(DO, buf[1], false);
+ } else {
+ if (supported(buf[1]) && isEnabled(buf[1])) {
+ enable(buf[1]);
+ }
+ }
+ break;
+ case DO:
+ if (supported(buf[1]) && isEnabled(buf[1])) {
+ } else {
+ if (waitWILLreply(buf[1]) && supported(buf[1])) {
+ enable(buf[1]);
+ setWait(WILL, buf[1], false);
+ } else {
+ if (supported(buf[1])) {
+ sendCommand(WILL, buf[1], false);
+ enable(buf[1]);
+ } else {
+ sendCommand(WONT, buf[1], false);
+ }
+ }
+ }
+ break;
+ case DONT:
+ if (waitWILLreply(buf[1]) && supported(buf[1])) {
+ setWait(WILL, buf[1], false);
+ } else {
+ if (supported(buf[1]) && isEnabled(buf[1])) {
+ enable(buf[1]);
+ }
+ }
+ break;
+
+ case DM:
+ break;
+ case SB:
+ if ((supported(buf[1])) && (isEnabled(buf[1]))) {
+ switch (buf[1]) {
+ case NAWS:
+ handleNAWS();
+ break;
+ case TTYPE:
+ handleTTYPE();
+ break;
+ case LINEMODE:
+ handleLINEMODE();
+ break;
+ case NEWENV:
+ handleNEWENV();
+ break;
+ default:
+ ;
+ }
+ } else {
+
+ }
+ break;
+ default:
+ ;
+ }
+ };
+
+
+ function handleNAWS() {
+ var width = read16int();
+ if (width == 255) {
+ width = read16int();
+ }
+ var height = read16int();
+ if (height == 255) {
+ height = read16int();
+ }
+ skipToSE();
+ setTerminalGeometry(width, height);
+ };
+
+ function handleTTYPE() {
+ var tmpstr = "";
+ var b = bytes.readUnsignedByte();
+
+ switch(b) {
+ case SEND:
+ var cont = true;
+ do {
+ var i;
+ i = bytes.readUnsignedByte();
+ if (i == SE) {
+ cont = false;
+ }
+
+ } while (cont);
+
+ _session.flush();
+
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SB);
+ TERM.socket.writeByte(TTYPE);
+ TERM.socket.writeByte(IS);
+ writeMultiByte("ansi", "us-ascii");
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SE);
+ break;
+
+ case IS:
+ tmpstr = readIACSETerminatedString(40);
+ break;
+ }
+ };
+
+ function handleLINEMODE() {
+ var c = bytes.readUnsignedByte();
+ switch (c) {
+ case LM_MODE:
+ handleLMMode();
+ break;
+ case LM_SLC:
+ handleLMSLC();
+ break;
+ case WONT:
+ case WILL:
+ handleLMForwardMask(c);
+ break;
+ default:
+ skipToSE();
+ }
+ };
+
+ function handleLMMode() {
+ if (WAIT_LM_MODE_ACK) {
+ var mask = bytes.readUnsignedByte();
+ if (mask != (LM_EDIT | LM_TRAPSIG | LM_MODEACK)) {
+ }
+ WAIT_LM_MODE_ACK = false;
+ }
+ skipToSE();
+ };
+
+ function handleLMSLC() {
+ var triple = [0,0,0];
+ if (!readTriple(triple)) return;
+
+ if ((triple[0] == 0) && (triple[1] == LM_SLC_DEFAULT) && (triple[2] == 0)) {
+ skipToSE();
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SB);
+ TERM.socket.writeByte(LINEMODE);
+ TERM.socket.writeByte(LM_SLC);
+
+ for (var i = 1; i < 12; i++) {
+ TERM.socket.writeByte(i);
+ TERM.socket.writeByte(LM_SLC_DEFAULT);
+ TERM.socket.writeByte(0);
+ }
+
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SE);
+ } else {
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SB);
+ TERM.socket.writeByte(LINEMODE);
+ TERM.socket.writeByte(LM_SLC);
+ TERM.socket.writeByte(triple[0]);
+ TERM.socket.writeByte(triple[1] | LM_SLC_ACK);
+ TERM.socket.writeByte(triple[2]);
+ while (readTriple(triple)) {
+ TERM.socket.writeByte(triple[0]);
+ TERM.socket.writeByte(triple[1] | LM_SLC_ACK);
+ TERM.socket.writeByte(triple[2]);
+ }
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SE);
+ }
+ };
+
+ function handleLMForwardMask(WHAT) {
+ switch (WHAT) {
+ case WONT:
+ if (WAIT_LM_DO_REPLY_FORWARDMASK) {
+ WAIT_LM_DO_REPLY_FORWARDMASK = false;
+ }
+ break;
+ }
+ skipToSE();
+ };
+
+ function handleNEWENV() {
+ var c = bytes.readUnsignedByte();
+ switch (c) {
+ case IS:
+ handleNEIs();
+ break;
+ case NE_INFO:
+ handleNEInfo();
+ break;
+ default:
+ skipToSE();
+ }
+ };
+
+ function readNEVariableName(sbuf) {
+ var i = -1;
+ do {
+ i = bytes.readUnsignedByte();
+ if (i == -1) {
+ return NE_IN_ERROR;
+ } else if (i == IAC) {
+ i = bytes.readUnsignedByte();
+ if (i == IAC) {
+ sbuf.concat(i);
+ } else if (i == SE) {
+ return NE_IN_END;
+ } else {
+ return NE_IN_ERROR;
+ }
+ } else if (i == NE_ESC) {
+ i = bytes.readUnsignedByte();
+ if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+ sbuf.concat(i);
+ } else {
+ return NE_IN_ERROR;
+ }
+ } else if (i == NE_VAR || i == NE_USERVAR) {
+ return NE_VAR_UNDEFINED;
+ } else if (i == NE_VALUE) {
+ return NE_VAR_DEFINED;
+ } else {
+ if (sbuf.length >= NE_VAR_NAME_MAXLENGTH) {
+ return NE_IN_ERROR;
+ } else {
+ sbuf.concat(i);
+ }
+ }
+ } while (true);
+
+ return i;
+ };
+
+ function readNEVariableValue(sbuf) {
+ var i = bytes.readUnsignedByte();
+ if (i == -1) {
+ return NE_IN_ERROR;
+ } else if (i == IAC) {
+ i = bytes.readUnsignedByte();
+ if (i == IAC) {
+ return NE_VAR_DEFINED_EMPTY;
+ } else if (i == SE) {
+ return NE_IN_END;
+ } else {
+ return NE_IN_ERROR;
+ }
+ } else if (i == NE_VAR || i == NE_USERVAR) {
+ return NE_VAR_DEFINED_EMPTY;
+ } else if (i == NE_ESC) {
+ i = bytes.readUnsignedByte();
+ if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+ sbuf.concat(i);
+ } else {
+ return NE_IN_ERROR;
+ }
+ } else {
+ sbuf.concat(i);
+ }
+
+ do {
+ i = bytes.readUnsignedByte();
+ if (i == -1) {
+ return NE_IN_ERROR;
+ } else if (i == IAC) {
+ i = bytes.readUnsignedByte();
+ if (i == IAC) {
+ sbuf.concat(i);
+ } else if (i == SE) {
+ return NE_IN_END;
+ } else {
+ return NE_IN_ERROR;
+ }
+ } else if (i == NE_ESC) {
+ i = bytes.readUnsignedByte();
+ if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+ sbuf.concat(i);
+ } else {
+ return NE_IN_ERROR;
+ }
+ } else if (i == NE_VAR || i == NE_USERVAR) {
+ return NE_VAR_OK;
+ } else {
+ if (sbuf.length > NE_VAR_VALUE_MAXLENGTH) {
+ return NE_IN_ERROR;
+ } else {
+ sbuf.concat(i);
+ }
+ }
+ } while (true);
+
+ return i;
+ };
+
+
+ function readNEVariables() {
+ var sbuf = "";
+ var i = bytes.readUnsignedByte();
+ if (i == IAC) {
+ skipToSE();
+ console.log("readNEVariables()::INVALID VARIABLE");
+ return;
+ }
+ var cont = true;
+ if (i == NE_VAR || i == NE_USERVAR) {
+ do {
+ switch (readNEVariableName(sbuf)) {
+ case NE_IN_ERROR:
+ console.log("readNEVariables()::NE_IN_ERROR");
+ return;
+ case NE_IN_END:
+ console.log("readNEVariables()::NE_IN_END");
+ return;
+ case NE_VAR_DEFINED:
+ console.log("readNEVariables()::NE_VAR_DEFINED");
+ var str = sbuf;
+ sbuf = "";
+ switch (readNEVariableValue(sbuf)) {
+ case NE_IN_ERROR:
+ console.log("readNEVariables()::NE_IN_ERROR");
+ return;
+ case NE_IN_END:
+ console.log("readNEVariables()::NE_IN_END");
+ return;
+ case NE_VAR_DEFINED_EMPTY:
+ console.log("readNEVariables()::NE_VAR_DEFINED_EMPTY");
+ break;
+ case NE_VAR_OK:
+ console.log("readNEVariables()::NE_VAR_OK:VAR=" + str + " VAL=" + sbuf.toString());
+ sbuf = "";
+ break;
+ }
+ break;
+ case NE_VAR_UNDEFINED:
+ console.log("readNEVariables()::NE_VAR_UNDEFINED");
+ break;
+ }
+ } while (cont);
+ }
+ };
+
+ function handleNEIs() {
+ if (isEnabled(NEWENV)) {
+ readNEVariables();
+ }
+ };
+
+ function handleNEInfo() {
+ if (isEnabled(NEWENV)) {
+ readNEVariables();
+ }
+ };
+
+ function getTTYPE() {
+ if (isEnabled(TTYPE)) {
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SB);
+ TERM.socket.writeByte(TTYPE);
+ TERM.socket.writeByte(SEND);
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SE);
+ }
+ };
+
+ function negotiateLineMode() {
+ if (isEnabled(LINEMODE)) {
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SB);
+ TERM.socket.writeByte(LINEMODE);
+ TERM.socket.writeByte(LM_MODE);
+ TERM.socket.writeByte(LM_EDIT | LM_TRAPSIG);
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SE);
+ WAIT_LM_MODE_ACK = true;
+
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SB);
+ TERM.socket.writeByte(LINEMODE);
+ TERM.socket.writeByte(DONT);
+ TERM.socket.writeByte(LM_FORWARDMASK);
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(SE);
+ WAIT_LM_DO_REPLY_FORWARDMASK = true;
+ }
+ };
+
+ function negotiateEnvironment() {
+ if (isEnabled(NEWENV)) {
+ ba.TERM.socket.writeByte(IAC);
+ ba.TERM.socket.writeByte(SB);
+ ba.TERM.socket.writeByte(NEWENV);
+ ba.TERM.socket.writeByte(SEND);
+ ba.TERM.socket.writeByte(NE_VAR);
+ ba.TERM.socket.writeByte(NE_USERVAR);
+ ba.TERM.socket.writeByte(IAC);
+ ba.TERM.socket.writeByte(SE);
+ WAIT_NE_SEND_REPLY = true;
+ }
+ };
+
+ function skipToSE() {
+ while (bytes.readUnsignedByte() != SE) ;
+ };
+
+ function readTriple(triple) {
+ triple[0] = bytes.readUnsignedByte();
+ triple[1] = bytes.readUnsignedByte();
+ if ((triple[0] == IAC) && (triple[1] == SE)) {
+ return false;
+ } else {
+ triple[2] = bytes.readUnsignedByte();
+ return true;
+ }
+
+ return false;
+ };
+
+
+ function readIACSETerminatedString(maxlength) {
+ var where = 0;
+ var cbuf = [];
+ var b = ' ';
+ var cont = true;
+
+ do {
+ var i;
+ i = bytes.readUnsignedByte();
+ switch (i) {
+ case IAC:
+ i = bytes.readUnsignedByte();
+ if (i == SE) {
+ cont = false;
+ }
+ break;
+ case -1:
+ return ("default");
+ default:
+ }
+ if (cont) {
+ b = i.toString();
+ if (b == '\n' || b == '\r' || where == maxlength) {
+ cont = false;
+ } else {
+ cbuf[where++] = b;
+ }
+ }
+ } while (cont);
+
+ var str = "";
+ for(var j=0; j<where; j++) {
+ str.concat(cbuf[i]);
+ }
+
+ return (str);
+ };
+
+ function supported(i) {
+ switch (i) {
+ case SUPGA:
+ case ECHO:
+ case NAWS:
+ case TTYPE:
+ return true;
+ case LINEMODE:
+ return false;
+ default:
+ return false;
+ }
+ };
+
+ function sendCommand(i, j, westarted) {
+ TERM.socket.writeByte(IAC);
+ TERM.socket.writeByte(i);
+ TERM.socket.writeByte(j);
+
+ if ((i == DO) && westarted) setWait(DO, j, true);
+ if ((i == WILL) && westarted) setWait(WILL, j, true);
+ };
+
+ function enable(i) {
+ switch (i) {
+ case SUPGA:
+ if (DO_SUPGA) {
+ DO_SUPGA = false;
+ } else {
+ DO_SUPGA = true;
+ }
+ break;
+ case ECHO:
+ if (DO_ECHO) {
+ DO_ECHO = false;
+ } else {
+ DO_ECHO = true;
+ }
+ break;
+ case NAWS:
+ if (DO_NAWS) {
+ DO_NAWS = false;
+ } else {
+ DO_NAWS = true;
+ }
+ break;
+ case TTYPE:
+ if (DO_TTYPE) {
+ DO_TTYPE = false;
+ } else {
+ DO_TTYPE = true;
+ getTTYPE();
+ }
+ break;
+ case LINEMODE:
+ if (DO_LINEMODE) {
+ DO_LINEMODE = false;
+ } else {
+ DO_LINEMODE = true;
+ negotiateLineMode();
+ }
+ break;
+ case NEWENV:
+ if (DO_NEWENV) {
+ DO_NEWENV = false;
+ } else {
+ DO_NEWENV = true;
+ negotiateEnvironment();
+ }
+ break;
+ }
+ };
+
+ function isEnabled(i) {
+ switch (i) {
+ case SUPGA:
+ return DO_SUPGA;
+ case ECHO:
+ return DO_ECHO;
+ case NAWS:
+ return DO_NAWS;
+ case TTYPE:
+ return DO_TTYPE;
+ case LINEMODE:
+ return DO_LINEMODE;
+ case NEWENV:
+ return DO_NEWENV;
+ default:
+ return false;
+ }
+
+ return false;
+ };
+
+ function waitWILLreply(i) {
+ switch (i) {
+ case SUPGA:
+ return WAIT_WILL_REPLY_SUPGA;
+ case ECHO:
+ return WAIT_WILL_REPLY_ECHO;
+ case NAWS:
+ return WAIT_WILL_REPLY_NAWS;
+ case TTYPE:
+ return WAIT_WILL_REPLY_TTYPE;
+ default:
+ return false;
+ }
+
+ return false;
+ };
+
+ function waitDOreply(i) {
+ switch (i) {
+ case SUPGA:
+ return WAIT_DO_REPLY_SUPGA;
+ case ECHO:
+ return WAIT_DO_REPLY_ECHO;
+ case NAWS:
+ return WAIT_DO_REPLY_NAWS;
+ case TTYPE:
+ return WAIT_DO_REPLY_TTYPE;
+ case LINEMODE:
+ return WAIT_DO_REPLY_LINEMODE;
+ case NEWENV:
+ return WAIT_DO_REPLY_NEWENV;
+ default:
+ return false;
+ }
+
+ return false;
+ };
+
+ function setWait(WHAT, OPTION, WAIT) {
+ switch (WHAT) {
+ case DO:
+ switch (OPTION) {
+ case SUPGA:
+ WAIT_DO_REPLY_SUPGA = WAIT;
+ break;
+ case ECHO:
+ WAIT_DO_REPLY_ECHO = WAIT;
+ break;
+ case NAWS:
+ WAIT_DO_REPLY_NAWS = WAIT;
+ break;
+ case TTYPE:
+ WAIT_DO_REPLY_TTYPE = WAIT;
+ break;
+ case LINEMODE:
+ WAIT_DO_REPLY_LINEMODE = WAIT;
+ break;
+ case NEWENV:
+ WAIT_DO_REPLY_NEWENV = WAIT;
+ break;
+ }
+ break;
+ case WILL:
+ switch (OPTION) {
+ case SUPGA:
+ WAIT_WILL_REPLY_SUPGA = WAIT;
+ break;
+ case ECHO:
+ WAIT_WILL_REPLY_ECHO = WAIT;
+ break;
+ case NAWS:
+ WAIT_WILL_REPLY_NAWS = WAIT;
+ break;
+ case TTYPE:
+ WAIT_WILL_REPLY_TTYPE = WAIT;
+ break;
+ }
+ break;
+ }
+
+ return false;
+ };
+
+ this.init();
+
+};
\ No newline at end of file
diff --git a/jsTerm/src/telnet/Session.js b/jsTerm/src/telnet/Session.js
new file mode 100644
index 0000000..ce15dcb
--- /dev/null
+++ b/jsTerm/src/telnet/Session.js
@@ -0,0 +1,97 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Session = function (fontMapURL){
+
+ var viewer;
+ var commands;
+
+ function initKeyboard() {
+ document.addEventListener("keydown", function(e) {
+ var key = e.keyCode;
+
+ switch (key) {
+ case KEYBOARD_LEFT :
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_D);
+ break;
+
+ case KEYBOARD_RIGHT :
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_C);
+ break;
+
+ case KEYBOARD_UP :
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_A);
+ break;
+
+ case KEYBOARD_DOWN :
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_B);
+ break;
+
+ case KEYBOARD_PAGE_UP :
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_M);
+ break;
+
+ case KEYBOARD_PAGE_DOWN :
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_H);
+ TERM.socket.writeByte(SEMICOLON);
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(DIGIT_TWO);
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_J);
+ break;
+
+ case KEYBOARD_HOME :
+ TERM.socket.writeByte(ESCAPE);
+ TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+ TERM.socket.writeByte(LATIN_CAPITAL_LETTER_H);
+ break;
+
+ default:
+ TERM.socket.writeByte( key );
+ break;
+ }
+
+ }, false);
+ };
+
+ var fontmap = new Image();
+ fontmap.onload = function (){
+ viewer = new TERM.AnsiViewer(this);
+ commands = new TERM.Telnet(viewer);
+
+ if(!("WebSocket" in window)) {
+ alert("Sorry, the build of your browser does not support HTML5 WebSockets.");
+ return;
+ }
+
+ initKeyboard();
+ };
+ fontmap.src = fontMapURL;
+
+ this.connect = function(host, port) {
+ if(TERM.socket != undefined && TERM.socket.readyState == 1) {
+ viewer.displayCleared();
+ viewer.reposition(0, 0);
+ TERM.socket.send("telnet|"+host+"|"+port);
+ } else if(TERM.socket == undefined ){
+ TERM.socket = new TERM.Socket();
+ TERM.socket.init(host, port, function(e){
+ viewer.readBytes(e.data.toString());
+ });
+ }
+ };
+
+}
\ No newline at end of file
diff --git a/jsTerm/src/telnet/Socket.js b/jsTerm/src/telnet/Socket.js
new file mode 100644
index 0000000..8b6e32e
--- /dev/null
+++ b/jsTerm/src/telnet/Socket.js
@@ -0,0 +1,36 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Socket = function (){
+
+ var ws;
+
+ this.init = function(host, port, onmessage){
+ ws = new WebSocket("ws://"+TERM.SERVER_URL+":"+TERM.SERVER_PORT+"/");
+ ws.onmessage = onmessage;
+ ws.onclose = function() {};
+ ws.onopen = function() {
+ ws.send("telnet|"+host+"|"+port);
+ };
+ };
+
+ this.writeByte = function(code) {
+ ws.send(String.fromCharCode(code));
+ };
+
+ this.writeMultiByte = function(string, code) {
+ ws.send(string);
+ };
+
+ this.send = function(packet){
+ ws.send(packet);
+ };
+
+};
+
+TERM.Socket.prototype = {
+ get readyState(){
+ return ws.readyState;
+ }
+};
\ No newline at end of file
diff --git a/jsTerm/src/viewer/AnsiViewer.js b/jsTerm/src/viewer/AnsiViewer.js
new file mode 100644
index 0000000..47510bc
--- /dev/null
+++ b/jsTerm/src/viewer/AnsiViewer.js
@@ -0,0 +1,187 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.AnsiViewer = function (fontmap){
+
+ this.cursor = new TERM.Cursor();
+ this.parser = new TERM.AnsiParser(this);
+
+ var fontmap = fontmap;
+ var font = new TERM.Font();
+ var canvas = document.getElementById("canvas");
+ var width = canvas.width;
+ var height = canvas.height;
+ var topMargin = 1;
+ var botMargin = 25;
+ var ctx = canvas.getContext("2d");
+ var scroll = true;
+ var _savedPosition = new TERM.Point();
+
+ this.readBytes = function (bytes) {
+ this.parser.parse(bytes);
+ };
+
+ this.clearCanvas = function(){
+ ctx.fillStyle = BLACK_NORMAL;
+ ctx.fillRect(0, 0, width, height);
+ };
+
+ this.colorTable = function(val) {
+ switch(val) {
+ case BLACK_NORMAL: return 0; break;
+ case BLUE_NORMAL: return 1; break;
+ case GREEN_NORMAL: return 2; break;
+ case CYAN_NORMAL: return 3; break;
+ case RED_NORMAL: return 4; break;
+ case MAGENTA_NORMAL: return 5; break;
+ case YELLOW_NORMAL: return 6; break;
+ case WHITE_NORMAL: return 7; break;
+ case BLACK_BOLD: return 8; break;
+ case BLUE_BOLD: return 9; break;
+ case GREEN_BOLD: return 10; break;
+ case CYAN_BOLD: return 11; break;
+ case RED_BOLD: return 12; break;
+ case MAGENTA_BOLD: return 13; break;
+ case YELLOW_BOLD: return 14; break;
+ case WHITE_BOLD: return 15; break;
+ }
+ return 0;
+ };
+
+ this.drawCharacter = function(character) {
+ this.draw(character);
+ this.cursor.moveForward(1);
+
+ if(!this.cursor.infinitewidth && this.cursor.x + this.cursor.columnwidth > this.cursor.maxColumnwidth * this.cursor.columnwidth){
+ this.moveDown(1);
+ this.cursor.carriageReturn();
+ }
+ };
+
+ this.draw = function(charCode) {
+ //console.log(charCode +" "+ this.cursor.x +" "+ this.cursor.y)
+
+ ctx.fillStyle = this.cursor.backgroundColor;
+ ctx.fillRect(this.cursor.x, this.cursor.y, font.width, font.height);
+
+ ctx.drawImage(fontmap,
+ charCode*(font.width+1), this.colorTable(this.cursor.foregroundColor)*font.height, font.width, font.height,
+ this.cursor.x, this.cursor.y, font.width, font.height);
+ };
+
+ this.carriageReturn = function() {
+ this.cursor.carriageReturn();
+ };
+
+ this.formFeed = function() {
+ this.cursor.x = 0;
+ this.cursor.y = 0;
+ };
+
+ this.moveBackward = function(val, erase) {
+ var movements = val;
+
+ while( movements > 0 ) {
+ this.cursor.moveBackward(1);
+ if(erase) this.draw(SPACE);
+ movements--;
+ }
+ };
+
+ this.moveDown = function(val) {
+ if(this.cursor.y >= this.cursor.lineheight*(botMargin-1) && scroll){
+ this.scrollUp(1);
+ } else {
+ this.cursor.moveDown(val);
+ }
+ };
+
+ this.moveForward = function(val) {
+ this.cursor.moveForward(val);
+ };
+
+ this.moveUp = function(val) {
+ this.cursor.moveUp(val);
+ };
+
+ this.reposition = function(x, y) {
+ this.cursor.x = x * this.cursor.columnwidth;
+ this.cursor.y = y * this.cursor.lineheight;
+ };
+
+ this.restorePosition = function() {
+ this.cursor.x = _savedPosition.x;
+ this.cursor.y = _savedPosition.y;
+ };
+
+ this.savePosition = function() {
+ _savedPosition.x = this.cursor.x;
+ _savedPosition.y = this.cursor.y;
+ };
+
+ this.displayCleared = function() {
+ ctx.fillStyle = BLACK_NORMAL;
+ ctx.fillRect(0, 0, this.cursor.maxColumnwidth * this.cursor.columnwidth, this.cursor.maxLineheight * this.cursor.lineheight);
+ };
+
+ this.eraseUp = function() {
+ ctx.fillStyle = BLACK_NORMAL;
+ ctx.fillRect(0, 0, this.cursor.maxColumnwidth * this.cursor.columnwidth, this.cursor.y);
+ };
+
+ this.eraseScreen = function() {
+ ctx.fillStyle = this.cursor.backgroundColor;
+ ctx.fillRect(0, 0, this.cursor.maxColumnwidth * this.cursor.columnwidth, this.cursor.maxLineheight * this.cursor.lineheight);
+ };
+
+ this.eraseDown = function() {
+ ctx.fillStyle = BLACK_NORMAL;
+ ctx.fillRect(0, this.cursor.y, this.cursor.maxColumnwidth * this.cursor.columnwidth, (this.cursor.maxLineheight * this.cursor.lineheight) - this.cursor.y);
+ };
+
+ this.eraseEndOfLine = function() {
+ ctx.fillStyle = BLACK_NORMAL;
+ var w = (this.cursor.maxColumnwidth * this.cursor.columnwidth) - (this.cursor.x - this.cursor.columnwidth);
+ ctx.fillRect(this.cursor.x, this.cursor.y, w, this.cursor.lineheight);
+ };
+
+ this.eraseStartOfLine = function() {
+ ctx.fillStyle = BLACK_NORMAL;
+ ctx.fillRect(0, this.cursor.y, this.cursor.x, this.cursor.lineheight);
+ };
+
+ this.eraseLine = function() {
+ ctx.fillStyle = BLACK_NORMAL;
+ ctx.fillRect(0, this.cursor.y, this.cursor.maxColumnwidth * this.cursor.columnwidth, this.cursor.lineheight);
+ };
+
+ this.backgroundColorChanged = function(color) {
+ this.cursor.backgroundColor = color;
+ };
+
+ this.foregroundColorChanged = function(color) {
+ this.cursor.foregroundColor = color;
+ };
+
+ this.home = function() {
+ this.cursor.x = 0;
+ this.cursor.y = (topMargin-1) * this.cursor.maxLineHeight;
+ };
+
+ this.scrollScreen = function(start, end) {
+ topMargin = start;
+ botMargin = end;
+
+ handleHome();
+ };
+
+ this.scrollUp = function(val) {
+ var canvasData = ctx.getImageData(0, topMargin * this.cursor.lineheight, this.cursor.maxColumnwidth*this.cursor.columnwidth, this.cursor.lineheight * (botMargin-topMargin));
+ this.displayCleared();
+ ctx.putImageData(canvasData, 0, this.cursor.lineheight*(topMargin-1));
+ };
+
+ this.clearCanvas();
+
+};
\ No newline at end of file
diff --git a/jsTerm/src/viewer/Cursor.js b/jsTerm/src/viewer/Cursor.js
new file mode 100644
index 0000000..ad5d9af
--- /dev/null
+++ b/jsTerm/src/viewer/Cursor.js
@@ -0,0 +1,65 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Cursor = function (){
+
+ this.foregroundColor = WHITE_NORMAL;
+ this.backgroundColor = BLACK_NORMAL;
+ this.position = new TERM.Point();
+ this.maxColumnWidth = 80;
+ this.maxLineHeight = 25;
+ this.columnWidth = 8;
+ this.lineHeight = 16;
+ this.maxColumns = 80;
+ this.infiniteWidth = false;
+ this.infiniteHeight = false;
+
+ this.moveForward = function(columns) {
+ if( this.position.x + (columns*this.columnWidth) <= this.maxColumns * this.columnWidth )
+ this.position.x = this.position.x + (columns*this.columnWidth);
+ else
+ this.position.x = (this.maxColumns * this.columnWidth) - this.columnWidth;
+ };
+
+ this.moveBackward = function(columns) {
+ if( this.position.x - (columns*this.columnWidth) >= 0 )
+ this.position.x = this.position.x - (columns*this.columnWidth);
+ else
+ this.position.x = 0;
+ };
+
+ this.moveDown = function(lines) {
+ this.position.y = this.position.y + (lines*this.lineHeight);
+ };
+
+ this.moveUp = function(lines) {
+ if( this.position.y - (lines*this.lineHeight) >= 0 )
+ this.position.y = this.position.y - (lines*this.lineHeight);
+ else
+ this.position.y = 0;
+ };
+
+ this.carriageReturn = function() {
+ this.position.x = 0;
+ };
+
+};
+
+TERM.Cursor.prototype = {
+
+ get x (){
+ return this.position.x;
+ },
+ set x (val){
+ this.position.x = val;
+ },
+
+ get y (){
+ return this.position.y;
+ },
+ set y (val){
+ this.position.y = val;
+ }
+
+};
\ No newline at end of file
diff --git a/jsTerm/src/viewer/Font.js b/jsTerm/src/viewer/Font.js
new file mode 100644
index 0000000..794290e
--- /dev/null
+++ b/jsTerm/src/viewer/Font.js
@@ -0,0 +1,11 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Font = function() {
+
+ this.width = 8;
+ this.height = 16;
+ this.lineHeight = 23;
+
+};
\ No newline at end of file
diff --git a/jsTerm/src/viewer/Point.js b/jsTerm/src/viewer/Point.js
new file mode 100644
index 0000000..b31b4c9
--- /dev/null
+++ b/jsTerm/src/viewer/Point.js
@@ -0,0 +1,10 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Point = function() {
+
+ this.x = 0;
+ this.y = 0;
+
+};
\ No newline at end of file