/***********************************************************************
This file is part of the webtty package. The webtty package was
written by Martin Steen Nielsen
Development is hosted by testape.com at www.testape.com/webtty
webtty is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***********************************************************************/
/***********************************************************************
Resize terminal
***********************************************************************/
function resize(id)
{
var elem = document.getElementById(id);
elem.cols+=20;
elem.rows+=6;
if (elem.cols>20*4) {
elem.cols-=(20*4);
elem.rows-=(6*4);
}
elem.scrollTop=elem.scrollHeight;
return false;
}
/***********************************************************************
Toggles scrollbars on terminal
***********************************************************************/
function bars(id)
{
var elem = document.getElementById(id);
if (elem.style.overflow!='scroll')
elem.style.overflow='scroll';
else
elem.style.overflow='hidden';
return false;
}
/***********************************************************************
closes terminal
***********************************************************************/
function wclose(id)
{
var elem = document.getElementById(id);
elem.style.display='none';
return false;
}
function webtty()
{
/***********************************************************************
Creates XMLHTTPRequest object
***********************************************************************/
this.create_transfer_object = function()
{
try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
try { return new XMLHttpRequest(); } catch(e) {}
return null;
}
/***********************************************************************
callback function whenever html data is ready
***********************************************************************/
this.get_html_state = function()
{
if (this.xhr_out.readyState == 4)
{
if ((this.xhr_out.status!=200)&&(this.xhr_out.status!=0))
this.error();
this.element.innerHTML = this.xhr_out.responseText;
var tmp = document.getElementById('webtty_session_id');
this.session_id = tmp.innerHTML;
//document.getElementById('webtty_session_id').id='default';
this.output_area = document.getElementById('webtty_output');
this.output_area.id = 'default';
var obj = this;
this.output_area.onkeypress = function(e) { if (obj.running) return obj.key_event(e); }
this.output_area.onkeydown = function(e) { if (obj.running) return obj.special_key_event(e); }
this.get_data();
}
}
/***********************************************************************
Request a new process and HTML data from server
***********************************************************************/
this.get_html = function()
{
var obj = this;
if (null == this.xhr_out)
this.xhr_out = this.create_transfer_object();
this.xhr_out.onreadystatechange = function() {};
this.xhr_out.open('GET', 'webtty.php?shell=virt', true);
this.xhr_out.onreadystatechange = function() { if (obj.running) obj.get_html_state(); }
this.xhr_out.send('');
}
/***********************************************************************
callback function whenever process data is ready
***********************************************************************/
this.get_data_state = function()
{
if (this.xhr_out.readyState == 4) {
if ((this.xhr_out.status!=200)&&(this.xhr_out.status!=0))
this.error();
var data = this.xhr_out.responseText;
if (data == '_C_L_O_S_E_D_') {
this.session_id=null;
this.webtty_exit(0);
this.cleanup();
} else {
if (data != '')
this.handle_data(data);
this.get_data();
}
}
}
/***********************************************************************
Request new data from the server
***********************************************************************/
this.get_data = function()
{
if (null == this.session_id)
return this.error();
if (null == this.xhr_out)
this.xhr_out = this.create_transfer_object();
var obj = this;
this.xhr_out.onreadystatechange = function() { }
this.xhr_out.open('GET', 'webtty.php?outp=1&id='+this.session_id, true);
this.xhr_out.onreadystatechange = function() { return obj.get_data_state(); }
this.xhr_out.send('');
}
/***********************************************************************
exit page. Remove handles and terminate session
***********************************************************************/
this.cleanup = function()
{
this.running = false;
if (this.xhr_kbd) {
this.xhr_kbd.onreadystatechange = function() {};
this.xhr_kbd.abort();
delete this.xhr_kbd;
}
if (this.xhr_out) {
this.xhr_out.onreadystatechange = function() {};
this.xhr_out.abort();
delete xhr_out;
}
if (null != this.session_id) {
var exit_req = this.create_transfer_object();
exit_req.open('GET', 'webtty.php?id='+this.session_id+'&shell=kill', true);
exit_req.send('');
delete exit_req;
this.session_id=null;
}
}
this.x = 0;
this.y = 0;
this.saveX = 0;
this.saveY = 0;
this.lines = new Array(25);
for (i = 0; i < 25; i++ ) {
this.lines[i] = new Array(80);
}
/***********************************************************************
handles process data
***********************************************************************/
this.handle_data = function(data)
{
var newLines = data.split("\n");
for (j = 0; j < newLines.length; j++) {
for (i = 0; i < newLines[j].length; i++) {
if (newLines[j].charCodeAt(i) == 27) {
i++;
//i++;
var escaped = true;
while (escaped == true) {
//i--;
if ( newLines[j].slice(i).match(/^\[K/) ) { // erase to EOL
for (z = this.x; z < 80; z++)
this.lines[this.y][z] = "";
i = i + 2;
} else if ( newLines[j].slice(i).match(/^\[1K/) ) { // erase to SOL
for (z = 0; z <= this.x; z++)
this.lines[this.y][z] = "";
i = i + 3;
} else if ( newLines[j].slice(i).match(/^\[2K/) ) { // erase line
this.lines[this.y] = new Array(80);
i = i + 3;
} else if ( newLines[j].slice(i).match(/^\[J/) ) { // erase down
for (z = this.y; z < 25; z++)
this.lines[z] = new Array(80);
i = i + 2;
} else if ( newLines[j].slice(i).match(/^\[1J/) ) { // erase up
for (z = 0; z <= this.y; z++)
this.lines[z] = new Array(80);
i = i + 3;
} else if ( newLines[j].slice(i).match(/^\[2J/) ) { // erase screen
for (z = 0; z < 25; z++ ) {
this.lines[z] = new Array(80);
this.x = 0;
this.y = 0;
}
i = i + 3;
} else if ( newLines[j].slice(i).match(/^\[r/) ) { // enable scrolling
i = i + 2; // XXX
} else if ( newLines[j].slice(i).match(/^\[[0-9]*\;[0-9]*r/) ) { // scroll
var m = newLines[j].slice(i).match(/^\[[0-9]*\;[0-9]*r/);
i += (m+"-").length - 1; // XXX
} else if ( newLines[j].slice(i).match(/^D/) ) { // scroll down
var newLine = new Array(1);
newLine[0] = new Array(80);
this.lines = newLine.concat(this.lines).slice(0,25);
i++;
} else if ( newLines[j].slice(i).match(/^M/) ) { // scroll up
this.lines = this.lines.slice(1);
var newLine = new Array(1);
newLine[0] = new Array(80);
this.lines = this.lines.concat(newLine);
i++;
} else if ( newLines[j].slice(i).match(/^\[s/) ) { // save cursor pos
this.saveX = this.x;
this.saveY = this.y;
i = i + 2;
} else if ( newLines[j].slice(i).match(/^\[u/) ) { // unsave cursor pos
this.x = this.saveX;
this.y = this.saveY;
i = i + 2;
} else if ( newLines[j].slice(i).match(/^\[[Hf]/) ) { // move cursor home
i = i + 2;
this.x = 0;
this.y = 0;
} else if ( newLines[j].slice(i).match(/^\[[0-9]*\;[0-9]*[Hf]/) ) { // move cursor
//alert( "text: -" + newLines[j].slice(i) + "-");
i++;
var x2 = 0;
var y2 = 0;
y2 = newLines[j].slice(i).match(/^[0-9]*/);
//if ( y2 ) {
i += (y2+"-").length;
x2 = newLines[j].slice(i).match(/^[0-9]*/);
// if ( x2 ) {
i += (x2+"-").length;
//alert("Move To -" + x2 + "- -" + y2 + "-");
this.x = x2;
this.y = y2;
// } else {
// alert( "text: -" + newLines[j].slice(i) + "-");
// }
//}
} else if ( newLines[j].slice(i).match(/^\[A/) ) {
i = i + 2;
this.y = this.y - 1;
} else if ( newLines[j].slice(i).match(/^\[[0-9]*A/) ) { // cursor up
i++;
var y2 = 0;
y2 = newLines[j].slice(i).match(/^[0-9]*/);
i += (y2+"-").length;
this.y = this.y - y2;
} else if ( newLines[j].slice(i).match(/^\[B/) ) {
i = i + 2;
this.y = this.y + 1;
} else if ( newLines[j].slice(i).match(/^\[[0-9]*B/) ) { // cursor up
i++;
var y2 = 0;
y2 = newLines[j].slice(i).match(/^[0-9]*/);
i += (y2+"-").length;
this.y = this.y + y2;
} else if ( newLines[j].slice(i).match(/^\[C/) ) {
i = i + 2;
this.x = this.x + 1;
} else if ( newLines[j].slice(i).match(/^\[[0-9]*C/) ) { // cursor forward
i++;
var x2 = 0;
x2 = newLines[j].slice(i).match(/^[0-9]*/);
i += (x2+"-").length;
this.x = this.x + x2;
} else if ( newLines[j].slice(i).match(/^\[D/) ) {
i = i + 2;
this.x = this.x - 1;
} else if ( newLines[j].slice(i).match(/^\[[0-9]*D/) ) { // cursor backward
i++;
var x2 = 0;
x2 = newLines[j].slice(i).match(/^[0-9]*/);
i += (x2+"-").length;
this.x = this.x - x2;
} else if ( newLines[j].slice(i).match(/^\[[0-9]*m/) ) { // attrib
i++;
var x2 = 0;
x2 = newLines[j].slice(i).match(/^[0-9]*/);
i += (x2+"-").length; // XXX
/*
if ( x2 == 34 )
this.lines[this.y][this.x] = "<font color=#FF00FF />" + this.lines[this.y][this.x];
else if ( x2 == 35 )
this.lines[this.y][this.x] = "<font color=#FF00FF />" + this.lines[this.y][this.x];
else if ( x2 == 0 )
this.lines[this.y][this.x] = "</font>" + this.lines[this.y][this.x];
*/
} else if ( newLines[j].slice(i).match(/^\[[0-9]*;[0-9]*m/) ) { // attrib
i++;
var x2 = 0;
x2 = newLines[j].slice(i).match(/^[0-9]*;[0-9]*/);
i += (x2+"-").length;
} else if ( newLines[j].slice(i).match(/^\[[0-9]*;[0-9]*;[0-9]*m/) ) { // attrib
i++;
var x2 = 0;
x2 = newLines[j].slice(i).match(/^[0-9]*;[0-9]*;[0-9]*/);
i += (x2+"-").length;
} else {
i--;
escaped = false;
}
}
// alert("Escape vals -" + newLines[j][i] + newLines[j][i] + "-");
} else {
this.lines[this.y][this.x] = newLines[j][i];
this.x++;
if ( this.x >= 80 ) {
// this.x = 80;
this.x = 0;
this.y++;
if ( this.y >= 25 ) {
this.lines = this.lines.slice(1);
var newLine = new Array(1);
newLine[0] = new Array(80);
this.lines = this.lines.concat(newLine);
this.y--;
}
}
}
}
if (j < (newLines.length - 1)) {
this.y++;
this.x = 0;
}
if ( this.y >= 25 ) {
this.lines = this.lines.slice(1);
var newLine = new Array(1);
newLine[0] = new Array(80);
this.lines = this.lines.concat(newLine);
this.y--;
}
}
//this.lines[this.lines.length-1] += outLines[0];
//this.lines = this.lines.concat(outLines.slice(1));
//this.lines = this.lines.slice(this.lines.length - 25);
//this.ypos = this.lines.length; // this.ypos + 1;
var output = "";
for (i = 0; i < 25; i++) {
output += this.lines[i].join("") + "\n";
}
this.output_area.value = output; // this.lines.join("\n");//data;//lines[0];//
//this.output_area.value = this.handle_special_chars(this.output_area.value + data, 2*data.length);
//this.output_area.value = this.handle_special_chars(this.output_area.value + data, 2*data.length);
//this.output_area.scrollTop=this.output_area.scrollHeight;
}
/***********************************************************************
Handle special characters. Simulates applying backspace, bell etc to
a string
***********************************************************************/
this.handle_special_chars = function(streng, max_look_back)
{
var startpos=0;
var write_pos=0;
var new_str='';
var subs='';
if (max_look_back>80)
max_look_back=80;
if (streng.length>max_look_back)
startpos = streng.length-max_look_back;
for (tl=startpos; tl<streng.length; tl++)
{
if (streng.charCodeAt(tl)==8) {
write_pos--;
subs = subs.substr(0,write_pos);
} else if (streng.charCodeAt(tl)==27) {
if (streng[tl+1]=="[") {
subs += "escaped";
}
} else if (streng.charCodeAt(tl)==7) {
;
} else {
write_pos++;
subs += streng.charAt(tl);
}
}
return streng.substr(0,startpos)+subs;
}
/***********************************************************************
callback function whenever data has been transmitted
***********************************************************************/
this.put_kbd_state = function()
{
if (this.xhr_kbd.readyState == 4)
{
delete this.xhr_kbd;
this.put_kbd();
}
}
/***********************************************************************
send data to server
***********************************************************************/
this.put_kbd = function()
{
if ('' == this.kbd_buffer)
return;
this.xhr_kbd=this.create_transfer_object();
this.xhr_kbd.open('POST', "webtty.php", true);
var obj = this;
this.xhr_kbd.onreadystatechange = function() { if (obj.running) return obj.put_kbd_state(); }
this.xhr_kbd.setRequestHeader("Connection", "close")
this.xhr_kbd.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
this.xhr_kbd.send("id="+this.session_id+"&inp="+this.kbd_buffer);
this.kbd_buffer='';
}
/***********************************************************************
buffer data and send to server
***********************************************************************/
this.buffer_next_data = function(cmd)
{
this.kbd_buffer += cmd;
if (undefined == this.xhr_kbd)
this.put_kbd();
//this.xhr_kbd.send("id="+this.session_id+"&inp="+this.kbd_buffer);
}
/***********************************************************************
handles normal keypresses
***********************************************************************/
this.key_event = function(e)
{
if (!e) var e = window.event
if (e.keyCode) key = e.keyCode;
else if (e.which) key = e.which;
if (!(window.event || e.charCode))
return true;
this.buffer_next_data(escape(String.fromCharCode(key)));
return false;
}
/***********************************************************************
handles special keypresses
***********************************************************************/
this.special_key_event = function (e)
{
if (!e) var e = window.event
if (e.keyCode) key = e.keyCode;
else if (e.which) key = e.which;
if (key==9)
{
this.buffer_next_data(escape("\t"));
return false;
}
else if (key==8)
{
this.buffer_next_data(escape("\010"));
return false;
}
else if (key == 40)
{
this.buffer_next_data(escape("\033[B"));
return false;
}
else if (key == 38)
{
this.buffer_next_data(escape("\033[A"));
return false;
}
else if (key == 38)
{
this.buffer_next_data(escape("\033[A"));
return false;
}
else if (key == 13)
{
this.buffer_next_data(escape("\n"));
return false;
}
}
/***********************************************************************
handles errors
***********************************************************************/
this.error = function()
{
this.webtty_exit(1);
alert("Error");
this.cleanup();
}
/***********************************************************************
exit handler
***********************************************************************/
this.webtty_exit = function(val)
{
alert("Refresh page to get a new virtual machine");
}
this.element = document.getElementById('dynamic');
if (null == this.element)
return this.error();
this.running = true;
this.session_id = null;
this.output_area = null;
this.kbd_buffer = '';
this.get_html();
}