[Ovirt-devel] [PATCH server] updated anyterm/ovirt integration
Mohammed Morsi
mmorsi at redhat.com
Thu Jul 16 21:04:22 UTC 2009
host static anyterm content locally,
url parameterize anyterm rows/cols/general param
update spec/makefile
Ideally I wanted and tried hard to put all this into a
seperate ovirt-server--anyterm subpackage, but we cannot
'reopen' the ovirt server virtual host defined in
ovirt-server.conf to add the neccessary rewrite rules. it would
be nice to figure out a way to do this
---
Makefile.am | 1 +
anyterm/anyterm.css | 132 ++++++++
anyterm/anyterm.html | 72 +++++
anyterm/anyterm.js | 799 ++++++++++++++++++++++++++++++++++++++++++++++++
anyterm/copy.gif | Bin 0 -> 911 bytes
anyterm/copy.png | Bin 0 -> 232 bytes
anyterm/paste.gif | Bin 0 -> 148 bytes
anyterm/paste.png | Bin 0 -> 225 bytes
conf/ovirt-server.conf | 13 +-
ovirt-server.spec.in | 7 +
scripts/ovirt-vm2node | 16 +-
11 files changed, 1022 insertions(+), 18 deletions(-)
create mode 100644 anyterm/anyterm.css
create mode 100644 anyterm/anyterm.html
create mode 100644 anyterm/anyterm.js
create mode 100644 anyterm/copy.gif
create mode 100644 anyterm/copy.png
create mode 100644 anyterm/paste.gif
create mode 100644 anyterm/paste.png
diff --git a/Makefile.am b/Makefile.am
index f115c8f..a143663 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,6 +23,7 @@ EXTRA_DIST = \
ovirt-server.spec.in \
scripts \
conf \
+ anyterm \
src \
installer
diff --git a/anyterm/anyterm.css b/anyterm/anyterm.css
new file mode 100644
index 0000000..6e68281
--- /dev/null
+++ b/anyterm/anyterm.css
@@ -0,0 +1,132 @@
+/* browser/anyterm.css
+ This file is part of Anyterm; see http://anyterm.org/
+ (C) 2005-2008 Philip Endecott
+
+ This program 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
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+/* These are the background colours: */
+.a { background-color: #000000; } /* black */
+.b { background-color: #cd0000; } /* red */
+.c { background-color: #00cd00; } /* green */
+.d { background-color: #cdcd00; } /* yellow */
+.e { background-color: #0000cd; } /* blue */
+.f { background-color: #cd00cd; } /* magenta */
+.g { background-color: #00cdcd; } /* cyan */
+.h { background-color: #e5e5e5; } /* white */
+
+/* These are the foreground colours used when bold mode is NOT enabled.
+ They're the same as the background colours. */
+.i { color: #000000; } /* black */
+.j { color: #cd0000; } /* red */
+.k { color: #00cd00; } /* green */
+.l { color: #cdcd00; } /* yellow */
+.m { color: #0000cd; } /* blue */
+.n { color: #cd00cd; } /* magenta */
+.o { color: #00cdcd; } /* cyan */
+.p { color: #e5e5e5; } /* white */
+
+/* These are the brighter foreground colours used when bold mode IS enabled.
+ The business with !important and .p .z is because the .p default is set
+ on the enclosing term element; I can't see a better way to get the desired
+ behaviour. */
+.z.i { color: #4d4d4d !important; } /* black */
+.z.j { color: #ff0000 !important; } /* red */
+.z.k { color: #00ff00 !important; } /* green */
+.z.l { color: #ffff00 !important; } /* yellow */
+.z.m { color: #0000ff !important; } /* blue */
+.z.n { color: #ff00ff !important; } /* magenta */
+.z.o { color: #00ffff !important; } /* cyan */
+.z.p, .p .z { color: #ffffff; } /* white */
+
+/* If you want a black-on-white colour scheme like xterm, rather than the
+ default white-on-black, you need to change the lines for black and white
+ above to something like the following:
+ .a { background-color: #ffffff; }
+ .h { background-color: #000000; }
+ .i { color: #e5e5e5; }
+ .p { color: #000000; }
+ .z.i { color: #ffffff !important; }
+ .z.p, .p .z { color: #000000; }
+*/
+
+/* If the following rule is enabled, bold mode will actually use a bold font.
+ This is not a good idea in general as the bold font will probably be wider
+ than the normal font, messing up the layout, at least for some subset of
+ the character set. So it's commented out; bold characters will be
+ distinguished only by their brighter colours (above) */
+/* .z { font-weight: bold; } */
+
+/* The cursor. You can make it blink if you really want to (on some browsers). */
+.cursor {
+ border: 1px solid red;
+ margin: -1px;
+/*text-decoration: blink;*/
+}
+
+
+/* Properties for the page outside the terminal: */
+
+body {
+ background-color: white;
+ /* Don't like the white background? How about this:
+ background-color: #222222;
+ */
+}
+
+noscript {
+ /* This is for the message that users see if they don't have Javascript
+ enabled. We want it to be visible whatever the page background colour
+ (above) is set to, so we give it its own background colour. */
+ color: black;
+ background-color: white;
+}
+
+
+/* The remaining definitions determine the appearance of the frame around the
+ terminal, its title bar, and buttons: */
+
+.termframe {
+ float: left;
+ background-color: rgb(63,63,161);
+ padding: 0.4ex;
+}
+
+.termframe p {
+ margin: 0;
+ color: white;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+.termframe a {
+ cursor: pointer;
+}
+
+img.button {
+ margin: 0 3px;
+ cursor: pointer;
+ vertical-align: top;
+}
+
+.term {
+ margin: 0.4ex 0 0 0;
+ padding: 1px;
+
+ overflow: auto;
+ overflow-x: visible;
+}
+
diff --git a/anyterm/anyterm.html b/anyterm/anyterm.html
new file mode 100644
index 0000000..7e6e702
--- /dev/null
+++ b/anyterm/anyterm.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<!--
+browser/anyterm.html
+This file is part of Anyterm; see http://anyterm.org/
+(C) 2005-2007 Philip Endecott
+
+This program 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
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-->
+
+<html>
+<head>
+<title>Anyterm</title>
+
+<script type="text/javascript" src="anyterm.js">
+</script>
+
+<script type="text/javascript">
+ var rows = get_url_param("rows");
+ var columns = get_url_param("columns");
+ var general_param = get_url_param("param");
+
+ if(rows == ""){
+ rows = 25;
+ }
+
+ if(columns == ""){
+ columns = 80;
+ }
+
+ // To create the terminal, just call create_term. The paramters are:
+ // - The id of a <div> element that will become the terminal.
+ // - The title. %h and %v expand to the hostname and Anyterm version.
+ // - The number of rows and columns.
+ // - An optional parameter which is substituted for %p in the command string.
+ // - An optional character set.
+ // - An option number of lines of scrollback (default 0).
+ window.onload=function() {create_term("term","%h (Anyterm%v)",rows,columns,general_param,"",50);};
+
+ // When the user closes the terminal, by default they'll see a blank page.
+ // Generally you'll want to be more friendly than that. If you set the
+ // variable on_close_goto_url to a URL, they'll be sent to that page after
+ // closing. You could send them back to your home page, or something.
+ var on_close_goto_url = "";
+
+</script>
+
+<link rel="stylesheet" type="text/css" href="anyterm.css">
+
+</head>
+
+<body>
+
+<noscript>Javascript is essential for this page. Please use a browser
+that supports Javascript.</noscript>
+
+<div id="term"></div>
+
+</body>
+</html>
diff --git a/anyterm/anyterm.js b/anyterm/anyterm.js
new file mode 100644
index 0000000..775970e
--- /dev/null
+++ b/anyterm/anyterm.js
@@ -0,0 +1,799 @@
+// browser/anyterm.js
+// This file is part of Anyterm; see http://anyterm.org/
+// (C) 2005-2006 Philip Endecott
+
+// This program 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
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+var undefined;
+
+var url_prefix = "";
+
+var frame;
+var term;
+var open=false;
+var session;
+
+var method="POST";
+//var method="GET";
+
+// Random sequence numbers are needed to prevent Opera from caching
+// replies
+
+var is_opera = navigator.userAgent.toLowerCase().indexOf("opera") != -1;
+if (is_opera) {
+ method="GET";
+}
+
+var seqnum_val=Math.round(Math.random()*100000);
+function cachebust() {
+ if (is_opera) {
+ seqnum_val++;
+ return "&x="+seqnum_val;
+ } else {
+ return "";
+ }
+}
+
+
+// Cross-platform creation of XMLHttpRequest object:
+
+function new_XMLHttpRequest() {
+ if (window.XMLHttpRequest) {
+ // For most browsers:
+ return new XMLHttpRequest();
+ } else {
+ // For IE, it's active-X voodoo.
+ // There are different versions in different browsers.
+ // The ones we try are the ones that Sarissa tried. The disabled ones
+ // apparently also exist, but it seems to work OK without trying them.
+
+ //try{ return new ActiveXObject("MSXML3.XMLHTTP"); } catch(e){}
+ try{ return new ActiveXObject("Msxml2.XMLHTTP.5.0"); } catch(e){}
+ try{ return new ActiveXObject("Msxml2.XMLHTTP.4.0"); } catch(e){}
+ try{ return new ActiveXObject("MSXML2.XMLHTTP.3.0"); } catch(e){}
+ try{ return new ActiveXObject("MSXML2.XMLHTTP"); } catch(e){}
+ //try{ return new ActiveXObject("Msxml2.XMLHTTP"); } catch(e){}
+ try{ return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e){}
+ throw new Error("Could not find an XMLHttpRequest active-X class.")
+ }
+}
+
+
+// Asynchronous and Synchronous XmlHttpRequest wrappers
+
+// AsyncLoader is a class; an instance specifies a callback function.
+// Call load to get something and the callback is invoked with the
+// returned document.
+
+function AsyncLoader(cb) {
+ this.callback = cb;
+ this.load = function (url,query) {
+ var xmlhttp = new_XMLHttpRequest();
+ var cbk = this.callback;
+ //var timeoutID = window.setTimeout("alert('No response after 20 secs')",20000);
+ xmlhttp.onreadystatechange = function () {
+ if (xmlhttp.readyState==4) {
+ //window.clearTimeout(timeoutID);
+ if (xmlhttp.status==200) {
+ cbk(xmlhttp.responseText);
+ } else {
+ alert("Server returned status code "+xmlhttp.status+":\n"+xmlhttp.statusText);
+ cbk(null);
+ }
+ }
+ }
+ if (method=="GET") {
+ xmlhttp.open(method, url+"?"+query, true);
+ xmlhttp.send(null);
+ } else if (method=="POST") {
+ xmlhttp.open(method, url, true);
+ xmlhttp.setRequestHeader('Content-Type',
+ 'application/x-www-form-urlencoded');
+ xmlhttp.send(query);
+ }
+
+ }
+}
+
+
+// Synchronous loader is a simple function
+
+function sync_load(url,query) {
+ var xmlhttp = new_XMLHttpRequest();
+ if (method=="GET") {
+ xmlhttp.open(method, url+"?"+query, false);
+ xmlhttp.send(null);
+ } else if (method=="POST") {
+ xmlhttp.open(method, url, false);
+ xmlhttp.setRequestHeader('Foo','1234');
+ xmlhttp.setRequestHeader('Content-Type',
+ 'application/x-www-form-urlencoded');
+ xmlhttp.send(query);
+ }
+ if (xmlhttp.status!=200) {
+ alert("Server returned status code "+xmlhttp.status+":\n"+xmlhttp.statusText);
+ return null;
+ }
+ return xmlhttp.responseText;
+}
+
+
+// Process error message from server:
+
+function handle_resp_error(resp) {
+ if (resp.charAt(0)=="E") {
+ var msg = resp.substr(1);
+ alert(msg);
+ return true;
+ }
+ return false;
+}
+
+
+// Receive channel:
+
+var rcv_loader;
+
+var disp="";
+
+
+
+function process_editscript(edscr) {
+
+ var ndisp="";
+
+ var i=0;
+ var dp=0;
+ while (i<edscr.length) {
+ var cmd=edscr.charAt(i);
+ i++;
+ var cp=edscr.indexOf(":",i);
+ var num=Number(edscr.substr(i,cp-i));
+ i=cp+1;
+ //alert("cmd="+cmd+" num="+num);
+ if (cmd=="d") {
+ dp+=num;
+ } else if (cmd=="k") {
+ ndisp+=disp.substr(dp,num);
+ dp+=num;
+ } else if (cmd=="i") {
+ //if (edscr.length<i+num) {
+ //alert("edit script ended early; expecting "+num+" but got only "+edscr.length-cp);
+ //}
+ ndisp+=edscr.substr(i,num);
+ i+=num;
+ }
+ }
+
+ return ndisp;
+}
+
+
+var visible_height_frac = 1;
+
+function display(edscr) {
+
+ //alert(edscr);
+
+ var ndisp;
+ if (edscr=="n") {
+ return;
+ } else if (edscr.charAt(0)=="R") {
+ ndisp = edscr.substr(1);
+ } else {
+ ndisp = process_editscript(edscr);
+ }
+
+ disp=ndisp;
+
+ term.innerHTML=ndisp;
+
+ if (visible_height_frac != 1) {
+ var termheight = visible_height_frac * term.scrollHeight;
+ term.style.height = termheight+"px";
+ term.scrollTop = term.scrollHeight;
+ }
+}
+
+
+function scrollterm(pages) {
+ term.scrollTop += pages * visible_height_frac * term.scrollHeight;
+}
+
+
+var rcv_timeout;
+
+function get() {
+ //alert("get");
+ rcv_loader.load(url_prefix+"anyterm-module","a=rcv&s="+session+cachebust());
+ rcv_timeout = window.setTimeout("alert('no response from server after 60 secs')",60000);
+}
+
+function rcv(resp) {
+ // Called asynchronously when the received document has returned
+ // from the server.
+
+ window.clearTimeout(rcv_timeout);
+
+ if (!open) {
+ return;
+ }
+
+ if (resp=="") {
+ // We seem to get this if the connection to the server fails.
+ alert("Connection to server failed");
+ return;
+ }
+
+ if (handle_resp_error(resp)) {
+ return;
+ }
+
+ display(resp);
+ get();
+}
+
+rcv_loader = new AsyncLoader(rcv);
+
+
+// Transmit channel:
+
+var kb_buf="";
+var send_loader;
+var send_in_progress=false;
+
+function send() {
+ send_in_progress=true;
+ send_loader.load(url_prefix+"anyterm-module",
+ "a=send&s="+session+cachebust()+"&k="+encodeURIComponent(kb_buf));
+ kb_buf="";
+}
+
+function send_done(resp) {
+ send_in_progress=false;
+ if (handle_resp_error(resp)) {
+ return;
+ }
+ if (kb_buf!="") {
+ send();
+ }
+}
+
+send_loader = new AsyncLoader(send_done);
+
+
+function maybe_send() {
+ if (!send_in_progress && open && kb_buf!="") {
+ send();
+ }
+}
+
+
+function process_key(k) {
+// alert("key="+k);
+// return;
+ kb_buf+=k;
+ maybe_send();
+}
+
+
+function esc_seq(s) {
+ return String.fromCharCode(27)+"["+s;
+}
+
+
+function key_ev_stop(ev) {
+ // We want this key event to do absolutely nothing else.
+ ev.cancelBubble=true;
+ if (ev.stopPropagation) ev.stopPropagation();
+ if (ev.preventDefault) ev.preventDefault();
+ try { ev.keyCode=0; } catch(e){}
+}
+
+function key_ev_supress(ev) {
+ // We want this keydown event to become a keypress event, but nothing else.
+ ev.cancelBubble=true;
+ if (ev.stopPropagation) ev.stopPropagation();
+}
+
+
+// When a key is pressed the browser delivers several events: typically first a keydown
+// event, then a keypress event, then a keyup event. Ideally we'd just use the keypress
+// event, but there's a problem with that: the browser may not send a keypress event for
+// unusual keys such as function keys, control keys, cursor keys and so on. The exact
+// behaviour varies between browsers and probably versions of browsers.
+//
+// So to get these keys we need to get the keydown events. They have a couple of
+// problems. Firstly, you get these events for things like pressing the shift key.
+// Secondly, unlike keypress events you don't get auto-repeat.
+
+function keypress(ev) {
+ if (!ev) var ev=window.event;
+
+ // Only handle "safe" characters here. Anything unusual is ignored; it would
+ // have been handled earlier by the keydown function below.
+ if ((ev.ctrlKey && !ev.altKey) // Ctrl is pressed (but not altgr, which is reported
+ // as ctrl+alt in at least some browsers).
+ || (ev.which==0) // there's no key in the event; maybe a shift key?
+ // (Mozilla sends which==0 && keyCode==0 when you press
+ // the 'windows logo' key.)
+ || (ev.keyCode==8) // backspace
+ || (ev.keyCode==16)) { // shift; Opera sends this.
+ key_ev_stop(ev);
+ return false;
+ }
+
+ var kc;
+ if (ev.keyCode) kc=ev.keyCode;
+ if (ev.which) kc=ev.which;
+
+ var k=String.fromCharCode(kc);
+
+ // When a key is pressed with ALT, we send ESC followed by the key's normal
+ // code. But we don't want to do this when ALT-GR is pressed.
+ if (ev.altKey && !ev.ctrlKey) {
+ k = String.fromCharCode(27)+k;
+ }
+
+// alert("keypress keyCode="+ev.keyCode+" which="+ev.which+
+// " shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey);
+
+ process_key(k);
+
+ key_ev_stop(ev);
+ return false;
+}
+
+
+function keydown(ev) {
+ if (!ev) var ev=window.event;
+
+ // alert("keydown keyCode="+ev.keyCode+" which="+ev.which+
+ // " shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey);
+
+ var k;
+
+ var kc=ev.keyCode;
+
+ // Handle special keys. We do this here because IE doesn't send
+ // keypress events for these (or at least some versions of IE don't for
+ // at least many of them). This is unfortunate as it means that the
+ // cursor keys don't auto-repeat, even in browsers where that would be
+ // possible. That could be improved.
+
+ // Interpret shift-pageup/down locally
+ if (ev.shiftKey && kc==33) { scrollterm(-0.5); key_ev_stop(ev); return false; }
+ else if (ev.shiftKey && kc==34) { scrollterm(0.5); key_ev_stop(ev); return false; }
+
+ else if (kc==33) k=esc_seq("5~"); // PgUp
+ else if (kc==34) k=esc_seq("6~"); // PgDn
+ else if (kc==35) k=esc_seq("4~"); // End
+ else if (kc==36) k=esc_seq("1~"); // Home
+ else if (kc==37) k=esc_seq("D"); // Left
+ else if (kc==38) k=esc_seq("A"); // Up
+ else if (kc==39) k=esc_seq("C"); // Right
+ else if (kc==40) k=esc_seq("B"); // Down
+ else if (kc==45) k=esc_seq("2~"); // Ins
+ else if (kc==46) k=esc_seq("3~"); // Del
+ else if (kc==27) k=String.fromCharCode(27); // Escape
+ else if (kc==9) k=String.fromCharCode(9); // Tab
+ else if (kc==8) k=String.fromCharCode(8); // Backspace
+ else if (kc==112) k=esc_seq(ev.shiftKey ? "25~" : "[A"); // F1
+ else if (kc==113) k=esc_seq(ev.shiftKey ? "26~" : "[B"); // F2
+ else if (kc==114) k=esc_seq(ev.shiftKey ? "28~" : "[C"); // F3
+ else if (kc==115) k=esc_seq(ev.shiftKey ? "29~" : "[D"); // F4
+ else if (kc==116) k=esc_seq(ev.shiftKey ? "31~" : "[E"); // F5
+ else if (kc==117) k=esc_seq(ev.shiftKey ? "32~" : "17~"); // F6
+ else if (kc==118) k=esc_seq(ev.shiftKey ? "33~" : "18~"); // F7
+ else if (kc==119) k=esc_seq(ev.shiftKey ? "34~" : "19~"); // F8
+ else if (kc==120) k=esc_seq("20~"); // F9
+ else if (kc==121) k=esc_seq("21~"); // F10
+ else if (kc==122) k=esc_seq("23~"); // F11
+ else if (kc==123) k=esc_seq("24~"); // F12
+
+ else {
+
+ // For most keys we'll stop now and let the subsequent keypress event
+ // process the key. This has the advantage that auto-repeat will work.
+ // But we'll carry on here for control keys.
+ // Note that when altgr is pressed, the event reports ctrl and alt being
+ // pressed because it doesn't have a separate field for altgr. We'll
+ // handle altgr in the keypress handler.
+ if (!ev.ctrlKey // ctrl not pressed
+ || (ev.ctrlKey && ev.altKey) // altgr pressed
+ || (ev.keyCode==17)) { // I think that if you press shift-control,
+ // you'll get an event with !ctrlKey && keyCode==17.
+ key_ev_supress(ev);
+ return; // Note that we don't "return false" here, as we want the
+ // keypress handler to be invoked.
+ }
+
+ // OK, so now we're handling a ctrl key combination.
+
+ // There are some assumptions below about whether these symbols are shifted
+ // or not; does this work with different keyboards?
+ if (ev.shiftKey) {
+ if (kc==50) k=String.fromCharCode(0); // Ctrl-@
+ else if (kc==54) k=String.fromCharCode(30); // Ctrl-^, doesn't work
+ else if (kc==94) k=String.fromCharCode(30); // Ctrl-^, doesn't work
+ else if (kc==109) k=String.fromCharCode(31); // Ctrl-_
+ else {
+ key_ev_supress(ev);
+ return;
+ }
+ } else {
+ if (kc>=65 && kc<=90) k=String.fromCharCode(kc-64); // Ctrl-A..Z
+ else if (kc==219) k=String.fromCharCode(27); // Ctrl-[
+ else if (kc==220) k=String.fromCharCode(28); // Ctrl-\ .
+ else if (kc==221) k=String.fromCharCode(29); // Ctrl-]
+ else if (kc==190) k=String.fromCharCode(30); // Since ctrl-^ doesn't work, map
+ // ctrl-. to its code.
+ else if (kc==32) k=String.fromCharCode(0); // Ctrl-space sends 0, like ctrl- at .
+ else {
+ key_ev_supress(ev);
+ return;
+ }
+ }
+ }
+
+// alert("keydown keyCode="+ev.keyCode+" which="+ev.which+
+// " shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey);
+
+ process_key(k);
+
+ key_ev_stop(ev);
+ return false;
+}
+
+
+// Open, close and initialisation:
+
+function open_term(rows,cols,p,charset,scrollback) {
+ var params = "a=open&rows="+rows+"&cols="+cols;
+ if (p) {
+ params += "&p="+p;
+ }
+ if (charset) {
+ params += "&ch="+charset;
+ }
+ if (scrollback) {
+ if (scrollback>1000) {
+ alert("The maximum scrollback is currently limited to 1000 lines. "
+ +"Please choose a smaller value and try again.");
+ return;
+ }
+ params += "&sb="+scrollback;
+ }
+ params += cachebust();
+ var resp = sync_load(url_prefix+"anyterm-module",params);
+
+ if (handle_resp_error(resp)) {
+ return;
+ }
+
+ open=true;
+ session=resp;
+}
+
+function close_term() {
+ if (!open) {
+ alert("Connection is not open");
+ return;
+ }
+ open=false;
+ var resp = sync_load(url_prefix+"anyterm-module","a=close&s="+session+cachebust());
+ handle_resp_error(resp); // If we get an error, we still close everything.
+ document.onkeypress=null;
+ document.onkeydown=null;
+ window.onbeforeunload=null;
+ var e;
+ while (e=frame.firstChild) {
+ frame.removeChild(e);
+ }
+ frame.className="";
+ if (on_close_goto_url) {
+ document.location = on_close_goto_url;
+ }
+}
+
+
+function get_anyterm_version() {
+ var svn_url="$URL: http://svn.anyterm.org/anyterm/tags/releases/1.1/1.1.29/browser/anyterm.js $";
+ var re = /releases\/[0-9]+\.[0-9]+\/([0-9\.]+)/;
+ var match = re.exec(svn_url);
+ if (match) {
+ return match[1];
+ } else {
+ return "";
+ }
+}
+
+function substitute_variables(s) {
+ var version = get_anyterm_version();
+ if (version!="") {
+ version="-"+version;
+ }
+ var hostname=document.location.host;
+ return s.replace(/%v/g,version).replace(/%h/g,hostname);
+}
+
+
+// Copying
+
+function copy_ie_clipboard() {
+ try {
+ window.document.execCommand("copy",false,null);
+ } catch (err) {
+ return undefined;
+ }
+ return 1;
+}
+
+function copy_mozilla_clipboard() {
+ // Thanks to Simon Wissinger for this function.
+
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ } catch (err) {
+ return undefined;
+ }
+
+ var sel=window.getSelection();
+ var copytext=sel.toString();
+
+ var str=Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(Components.interfaces.nsISupportsString);
+ if (!str) return undefined;
+
+ str.data=copytext;
+
+ var trans=Components.classes["@mozilla.org/widget/transferable;1"]
+ .createInstance(Components.interfaces.nsITransferable);
+ if (!trans) return undefined;
+
+ trans.addDataFlavor("text/unicode");
+ trans.setTransferData("text/unicode", str, copytext.length * 2);
+
+ var clipid=Components.interfaces.nsIClipboard;
+
+ var clip=Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
+ if (!clip) return undefined;
+
+ clip.setData(trans, null, clipid.kGlobalClipboard);
+
+ return 1;
+}
+
+function copy_to_clipboard() {
+ var r=copy_ie_clipboard();
+ if (r==undefined) {
+ r=copy_mozilla_clipboard();
+ }
+ if (r==undefined) {
+ alert("Copy seems to be disabled; maybe you need to change your security settings?"
+ +"\n(Copy on the Edit menu will probably work)");
+ }
+}
+
+
+// Pasting
+
+function get_mozilla_clipboard() {
+ // This function is taken from
+ // http://www.nomorepasting.com/paste.php?action=getpaste&pasteID=41974&PHPSESSID=e6565dcf5de07256345e562b97ac9f46
+ // which does not indicate any particular copyright conditions. It
+ // is a public forum, so one might conclude that it is public
+ // domain.
+
+ // IMHO it's disgraceful that Mozilla makes us use these 30 lines of
+ // undocumented gobledegook to do what IE does, and documents, with
+ // just 'window.clipboardData.getData("Text")'. What on earth were
+ // they thinking?
+
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ } catch (err) {
+ return undefined;
+ }
+
+ var clip = Components.classes["@mozilla.org/widget/clipboard;1"]
+ .createInstance(Components.interfaces.nsIClipboard);
+ if (!clip) {
+ return undefined;
+ }
+
+ var trans = Components.classes["@mozilla.org/widget/transferable;1"]
+ .createInstance(Components.interfaces.nsITransferable);
+ if (!trans) {
+ return undefined;
+ }
+
+ trans.addDataFlavor("text/unicode");
+ clip.getData(trans,clip.kGlobalClipboard);
+
+ var str=new Object();
+ var strLength=new Object();
+
+ try {
+ trans.getTransferData("text/unicode",str,strLength);
+ } catch(err) {
+ // One reason for getting here seems to be that nothing is selected
+ return "";
+ }
+
+ if (str) {
+ str=str.value.QueryInterface(Components.interfaces.nsISupportsString);
+ }
+
+ if (str) {
+ return str.data.substring(0,strLength.value / 2);
+ } else {
+ return ""; // ? is this "clipboard empty" or "cannot access"?
+ }
+}
+
+function get_ie_clipboard() {
+ if (window.clipboardData) {
+ return window.clipboardData.getData("Text");
+ }
+ return undefined;
+}
+
+function get_default_clipboard() {
+ return prompt("Paste into this box and press OK:","");
+}
+
+function paste_from_clipboard() {
+ var p = get_ie_clipboard();
+ if (p==undefined) {
+ p = get_mozilla_clipboard();
+ }
+ if (p==undefined) {
+ p = get_default_clipboard();
+ if (p) {
+ process_key(p);
+ }
+ return;
+ }
+
+ if (p=="") {
+ alert("The clipboard seems to be empty");
+ return;
+ }
+
+ if (confirm('Click OK to "type" the following into the terminal:\n'+p)) {
+ process_key(p);
+ }
+}
+
+
+function create_button(label,fn) {
+ var button=document.createElement("A");
+ var button_t=document.createTextNode("["+label+"] ");
+ button.appendChild(button_t);
+ button.onclick=fn;
+ return button;
+}
+
+function create_img_button(imgfn,label,fn) {
+ var button=document.createElement("A");
+ var button_img=document.createElement("IMG");
+ var class_attr=document.createAttribute("CLASS");
+ class_attr.value="button";
+ button_img.setAttributeNode(class_attr);
+ var src_attr=document.createAttribute("SRC");
+ src_attr.value=imgfn;
+ button_img.setAttributeNode(src_attr);
+ var alt_attr=document.createAttribute("ALT");
+ alt_attr.value="["+label+"] ";
+ button_img.setAttributeNode(alt_attr);
+ var title_attr=document.createAttribute("TITLE");
+ title_attr.value=label;
+ button_img.setAttributeNode(title_attr);
+ button.appendChild(button_img);
+ button.onclick=fn;
+ return button;
+}
+
+function create_term(elem_id,title,rows,cols,p,charset,scrollback) {
+ if (open) {
+ alert("Terminal is already open");
+ return;
+ }
+ title=substitute_variables(title);
+ frame=document.getElementById(elem_id);
+ if (!frame) {
+ alert("There is no element named '"+elem_id+"' in which to build a terminal");
+ return;
+ }
+ frame.className="termframe";
+ var title_p=document.createElement("P");
+ title_p.appendChild(create_img_button("copy.gif","Copy",copy_to_clipboard));
+ title_p.appendChild(create_img_button("paste.gif","Paste",paste_from_clipboard));
+ title_p.appendChild(create_ctrlkey_menu());
+ var title_t=document.createTextNode(" "+title+" ");
+ title_p.appendChild(title_t);
+ title_p.appendChild(create_button("close",close_term));
+ frame.appendChild(title_p);
+ term=document.createElement("PRE");
+ frame.appendChild(term);
+ term.className="term a p";
+ var termbody=document.createTextNode("");
+ term.appendChild(termbody);
+ visible_height_frac=Number(rows)/(Number(rows)+Number(scrollback));
+ if (scrollback>0) {
+ term.style.overflowY="scroll";
+ }
+ document.onhelp = function() { return false; };
+ document.onkeypress=keypress;
+ document.onkeydown=keydown;
+ open_term(rows,cols,p,charset,scrollback);
+ if (open) {
+ window.onbeforeunload=warn_unload;
+ get();
+ maybe_send();
+ }
+}
+
+
+function warn_unload() {
+ if (open) {
+ return "Leaving this page will close the terminal.";
+ }
+}
+
+
+function create_ctrlkey_menu() {
+ var sel=document.createElement("SELECT");
+ create_ctrlkey_menu_entry(sel,"Control keys...",-1);
+ create_ctrlkey_menu_entry(sel,"Ctrl-@",0);
+ for (var code=1; code<27; code++) {
+ var letter=String.fromCharCode(64+code);
+ create_ctrlkey_menu_entry(sel,"Ctrl-"+letter,code);
+ }
+ create_ctrlkey_menu_entry(sel,"Ctrl-[",27);
+ create_ctrlkey_menu_entry(sel,"Ctrl-\\",28);
+ create_ctrlkey_menu_entry(sel,"Ctrl-]",29);
+ create_ctrlkey_menu_entry(sel,"Ctrl-^",30);
+ create_ctrlkey_menu_entry(sel,"Ctrl-_",31);
+ sel.onchange=function() {
+ var code = sel.options[sel.selectedIndex].value;
+ if (code>=0) {
+ process_key(String.fromCharCode(code));
+ }
+ };
+ return sel;
+}
+
+function create_ctrlkey_menu_entry(sel,name,code) {
+ var opt=document.createElement("OPTION");
+ opt.appendChild(document.createTextNode(name));
+ var value_attr=document.createAttribute("VALUE");
+ value_attr.value=code;
+ opt.setAttributeNode(value_attr);
+ sel.appendChild(opt);
+}
+
+function get_url_param( name )
+{
+ var regexS = "[\\?&]"+name+"=([^&#]*)";
+ var regex = new RegExp( regexS );
+ var results = regex.exec( window.location.href );
+ if( results == null )
+ return "";
+ else
+ return results[1];
+}
diff --git a/anyterm/copy.gif b/anyterm/copy.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2ab719e349efd9e003b4b420449c68fecea004ed
GIT binary patch
literal 911
zcmV;A191FDNk%w1VG;lq0QUd at 000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c
z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM
z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C at 3f?DJd!{Dl021EG#T7
zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}?
zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy
zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy at _IT3cINTwGjTU0q&YUSD5dU|?Wj
zVPRroVq;@tWMpJzWo2e&W at l$-XlQ6 at X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T
za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm at et&;|fPjF3fq{a8f`fyD
zgoK2Jg at uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8 at l$4Z}
zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5(
zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p
zxVX5vxw*Q!y1To(yu7@<y}iD^zQ4b}z`(%4!NJ19!o$PE#KgqK#l^<P#>dCU$jHda
z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1<F+1c9K
z+S}XP+}zyV-QC{a-rwKf;Nall;o;)q;^X7v<mBY#<>lt)=I7_<=;-L_>FMg~>g((4
z?Ck9A?d|UF?(gsK at bK{Q@$vHV^7Hfa^z`)g_4W4l_V at Sq`1ttw`T6?#`uqF){QUg=
z{r&#_{{R2~A^8LW006%LEC2ui01^Ne000PV0DlP_NU-2Q00<K%G<fiz!-xM6GW-Pq
z;zIzL05GhmkmJIF6)i&42r^<qizEq#6zMQ!!;u|7QZ(6;rNo&dZDz!I(d5aFC|O=y
lSyLg(m_$Xo6qppHL61NqJ{8(>D%GVtZCVwI6=}zS06UUJu*?7e
literal 0
HcmV?d00001
diff --git a/anyterm/copy.png b/anyterm/copy.png
new file mode 100644
index 0000000000000000000000000000000000000000..1cdd8c1de2770d63ed9d9ae80ed2e2e44216598b
GIT binary patch
literal 232
zcmeAS at N?(olHy`uVBq!ia0vp^LO?9W!2%@H!&puMDW)WEcNd2L?fqx=19_YU9+AZi
z4BWyX%*Zfnjs#GUy~NYkmHiqsx0s>WCWE6%K%q)c7sn8d^IL;X3La44U`dzWd?qA0
z^GRY4i`f&=I6j>>hOZ{P588M`%F97aO7hyLkIuU$dRG_j|7&_?qQwm*UWHnQqJ>gH
z<tKkHeIu5qvPIN=c1eDVai7ES#}0Q=3l*$SCb;<f$kzP1+hrg*cYidO{=QT56+$+J
a&z*HdEg_w2**~Bo7(8A5T-G at yGywp=dQPqY
literal 0
HcmV?d00001
diff --git a/anyterm/paste.gif b/anyterm/paste.gif
new file mode 100644
index 0000000000000000000000000000000000000000..65ddba8bacc994f6347e950a5f73182c141ca7b8
GIT binary patch
literal 148
zcmZ?wbhEHb6k!l!_{7Wr1aoH1dH($Qe=q>?!9ejR3nK#q3xf`b2U5$x9O<!(>wtlo
z;=CNa at C}<)9TeDPQri}{PKujtmaKF9RnGngwby^0xx7})hfPAF-|hH>HkUTJ)mIcO
pzW$gMas2A!-mb2Q<<mvP@|zR3EUx)ua3JS9Q{1%VD>GRbtO4Q=IkW%(
literal 0
HcmV?d00001
diff --git a/anyterm/paste.png b/anyterm/paste.png
new file mode 100644
index 0000000000000000000000000000000000000000..034debdbf7033e46e9d7d45e239a664a7f92d9fb
GIT binary patch
literal 225
zcmV<703QE|P)<h;3K|Lk000e1NJLTq000yK000&U1^@s6z(KqQ0001}Nkl<ZILpnI
zVG6 at A2!)@cm+*d}hbq0F$8dilG>MCL3v>^Jg7)<@CMgh0YotVxnTP-Ym^o8FP&6ST
z?z0mOp`ORtxR<@a$a*m|yn3VG`WI at _T69(RGMJhM!%u}-y|7sSZ at A5pHlSsO0H8WQ
zBt*2n<+?L8Md(rV^p~a4l;N!HYmSJ%Bb<HUXToRqVKfwX9i!X$PP;Y~3NGGf&vN)r
bxoh|a{{&3{JLUuL00000NkvXXu0mjfLOWi3
literal 0
HcmV?d00001
diff --git a/conf/ovirt-server.conf b/conf/ovirt-server.conf
index 0fb4b94..e4ebd5b 100644
--- a/conf/ovirt-server.conf
+++ b/conf/ovirt-server.conf
@@ -23,15 +23,11 @@ NameVirtualHost AdminNetIpAddress:80
RewriteEngine On
RewriteMap vmnodes prg:/usr/bin/ovirt-vm2node
- RewriteRule ^/terminal/(.*)/(.*\.(js|css|gif))$ http://${vmnodes:anyterm}:81/$2 [P]
- RewriteRule ^/terminal/(.*)/proxy/anyterm-module$ http://${vmnodes:$1}:81/$1 [P]
- RewriteRule ^/terminal/(.*)/$ http://${vmnodes:$1}:81/anyterm.html?param=$1 [P,NE]
-
-
+ RewriteRule ^/terminal/(.+)/anyterm-module$ http://${vmnodes:$1}:81/anyterm-module [P]
+ RewriteRule ^/terminal/(.+)/(.*\.(html|js|css|gif))*$ http://127.0.0.1/terminal/$2 [P,NE]
ProxyPass /ovirt http://AdminNodeFQDN/ovirt retry=3
ProxyPassReverse /ovirt http://AdminNodeFQDN/ovirt
-
</VirtualHost>
<VirtualHost AdminNetIpAddress:80>
@@ -85,3 +81,8 @@ ProxyPassReverse /ovirt/stylesheets !
ProxyPassReverse /ovirt/errors !
</VirtualHost>
+
+Alias /terminal /usr/share/ovirt-anyterm
+<Location /terminal>
+ DirectoryIndex anyterm.html
+</Location>
diff --git a/ovirt-server.spec.in b/ovirt-server.spec.in
index 1bf73c7..d762178 100644
--- a/ovirt-server.spec.in
+++ b/ovirt-server.spec.in
@@ -150,6 +150,11 @@ touch %{buildroot}%{_localstatedir}/log/%{name}/db-omatic.log
%{__cp} -pr %{pbuild}/installer/appliances %{buildroot}/%{acehome}
%{__cp} -pr %{pbuild}/installer/bin/ovirt-installer %{buildroot}%{_sbindir}
+# setup the anyterm config
+%{__mkdir} -p %{buildroot}%{_datadir}/ovirt-anyterm/
+for f in anyterm/*.{html,css,js,png,gif}; do
+ %{__install} -m644 "$f" %{buildroot}%{_datadir}/ovirt-anyterm/
+done
%clean
rm -rf $RPM_BUILD_ROOT
@@ -244,11 +249,13 @@ fi
%config(noreplace) %{_sysconfdir}/%{name}/development.rb
%config(noreplace) %{_sysconfdir}/%{name}/production.rb
%config(noreplace) %{_sysconfdir}/%{name}/test.rb
+%{_datadir}/ovirt-anyterm
%files installer
%{_sbindir}/ovirt-installer
%{acehome}
+
%changelog
* Thu May 29 2008 Alan Pevec <apevec at redhat.com> - 0.0.5-0
- use rubygem-krb5-auth
diff --git a/scripts/ovirt-vm2node b/scripts/ovirt-vm2node
index 1d6104c..4ef3d6c 100755
--- a/scripts/ovirt-vm2node
+++ b/scripts/ovirt-vm2node
@@ -1,23 +1,15 @@
#!/usr/bin/ruby
-$: << '/usr/share/ovirt-server'
-$: << '/usr/share/ovirt-server/dutils'
+#$: << '/usr/share/ovirt-server'
+#$: << '/usr/share/ovirt-server/dutils'
-require 'dutils'
+#require 'dutils'
########################## retreive host from vm w/ specified name
$stdin.each{ |vmname| # get vm name from stdin
begin
vmname.chomp! # remove the newline
-
- # specially handle 'anyterm' to just return
- # first host (for css/js/etc which aren't
- # vm dependent)
- if vmname == 'anyterm'
- puts Host.find(:first, :conditions => "state = 'available'").hostname
- else
- puts Vm.find(:first, :conditions => ['description = ?', vmname]).host.hostname
- end
+ puts Vm.find(:first, :conditions => ['description = ?', vmname]).host.hostname
rescue Exception => e
puts
end
--
1.6.0.6
More information about the ovirt-devel
mailing list