Mohammed Morsi
2009-Jul-16 21:04 UTC
[Ovirt-devel] [PATCH server] updated anyterm/ovirt integration
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){QUgz{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
Ian Main
2009-Jul-20 17:46 UTC
[Ovirt-devel] [PATCH server] updated anyterm/ovirt integration
On Thu, 16 Jul 2009 17:04:22 -0400 Mohammed Morsi <mmorsi at redhat.com> wrote:> 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 thisHoly whitespace errors batman! :) "warning: 23 lines add whitespace errors." Will get to testing shortly :) Ian
Mohammed Morsi
2009-Jul-20 20:07 UTC
[Ovirt-devel] [PATCH server] updated anyterm/ovirt integration
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 | 13 +- 11 files changed, 1021 insertions(+), 16 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..6bfea1f --- /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..bf063de --- /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..fc0aa18 --- /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){QUgz{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..01e25bb 100755 --- a/scripts/ovirt-vm2node +++ b/scripts/ovirt-vm2node @@ -9,17 +9,10 @@ require 'dutils' $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 + puts "Error looking node with VM: #{ex.class}: #{ex.message}" + puts ex.backtrace end $stdout.flush -- 1.6.0.6
Seemingly Similar Threads
- [PATCH server] Fix anyterm for multinode support
- [PATCH server] Fix for anyterm and multiple nodes
- [PATCH node] changed fickle anyterm sysconfig changes to something more robust (revised)
- innerHTML and scripts not running
- [PATCH server] oVirt server single network installer