]> andersk Git - test.git/blame - shellinabox/shell_in_a_box.js
Some minor tweaks to make newer versions of gcc and glibc compile without warnings.
[test.git] / shellinabox / shell_in_a_box.js
CommitLineData
7460295f 1// ShellInABox.js -- Use XMLHttpRequest to provide an AJAX terminal emulator.
e0bb8a33 2// Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
7460295f
MG
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License version 2 as
6// published by the Free Software Foundation.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License along
14// with this program; if not, write to the Free Software Foundation, Inc.,
15// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16//
17// In addition to these license terms, the author grants the following
18// additional rights:
19//
20// If you modify this program, or any covered work, by linking or
21// combining it with the OpenSSL project's OpenSSL library (or a
22// modified version of that library), containing parts covered by the
23// terms of the OpenSSL or SSLeay licenses, the author
24// grants you additional permission to convey the resulting work.
25// Corresponding Source for a non-source form of such a combination
26// shall include the source code for the parts of OpenSSL used as well
27// as that of the covered work.
28//
29// You may at your option choose to remove this additional permission from
30// the work, or from any part of it.
31//
32// It is possible to build this program in a way that it loads OpenSSL
33// libraries at run-time. If doing so, the following notices are required
34// by the OpenSSL and SSLeay licenses:
35//
36// This product includes software developed by the OpenSSL Project
37// for use in the OpenSSL Toolkit. (http://www.openssl.org/)
38//
39// This product includes cryptographic software written by Eric Young
40// (eay@cryptsoft.com)
41//
42//
43// The most up-to-date version of this program is always available from
44// http://shellinabox.com
45//
46//
47// Notes:
48//
49// The author believes that for the purposes of this license, you meet the
50// requirements for publishing the source code, if your web server publishes
51// the source in unmodified form (i.e. with licensing information, comments,
52// formatting, and identifier names intact). If there are technical reasons
53// that require you to make changes to the source code when serving the
54// JavaScript (e.g to remove pre-processor directives from the source), these
55// changes should be done in a reversible fashion.
56//
57// The author does not consider websites that reference this script in
58// unmodified form, and web servers that serve this script in unmodified form
59// to be derived works. As such, they are believed to be outside of the
60// scope of this license and not subject to the rights or restrictions of the
61// GNU General Public License.
62//
63// If in doubt, consult a legal professional familiar with the laws that
64// apply in your country.
65
c27d0db9
MG
66// #define XHR_UNITIALIZED 0
67// #define XHR_OPEN 1
68// #define XHR_SENT 2
69// #define XHR_RECEIVING 3
70// #define XHR_LOADED 4
7460295f
MG
71
72// IE does not define XMLHttpRequest by default, so we provide a suitable
73// wrapper.
74if (typeof XMLHttpRequest == 'undefined') {
75 XMLHttpRequest = function() {
76 try { return new ActiveXObject('Msxml2.XMLHTTP.6.0');} catch (e) { }
77 try { return new ActiveXObject('Msxml2.XMLHTTP.3.0');} catch (e) { }
78 try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { }
79 try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) { }
80 throw new Error('');
81 };
82}
83
84function extend(subClass, baseClass) {
85 function inheritance() { }
86 inheritance.prototype = baseClass.prototype;
87 subClass.prototype = new inheritance();
88 subClass.prototype.constructor = subClass;
89 subClass.prototype.superClass = baseClass.prototype;
90};
91
92function ShellInABox(url, container) {
93 if (url == undefined) {
3bdb4585 94 this.rooturl = document.location.href;
d1edcc0e 95 this.url = document.location.href.replace(/[?#].*/, '');
7460295f 96 } else {
3bdb4585 97 this.rooturl = url;
7460295f
MG
98 this.url = url;
99 }
d1edcc0e 100 if (document.location.hash != '') {
3240f75b 101 var hash = decodeURIComponent(document.location.hash).
d1edcc0e 102 replace(/^#/, '');
3240f75b
MG
103 this.nextUrl = hash.replace(/,.*/, '');
104 this.session = hash.replace(/[^,]*,/, '');
d1edcc0e
MG
105 } else {
106 this.nextUrl = this.url;
3240f75b 107 this.session = null;
d1edcc0e 108 }
7460295f
MG
109 this.pendingKeys = '';
110 this.keysInFlight = false;
3240f75b 111 this.connected = false;
7460295f
MG
112 this.superClass.constructor.call(this, container);
113
114 // We have to initiate the first XMLHttpRequest from a timer. Otherwise,
115 // Chrome never realizes that the page has loaded.
116 setTimeout(function(shellInABox) {
117 return function() {
118 shellInABox.sendRequest();
119 };
120 }(this), 1);
121};
122extend(ShellInABox, VT100);
123
124ShellInABox.prototype.sessionClosed = function() {
11cd1451
MG
125 try {
126 this.connected = false;
127 if (this.session) {
128 this.session = undefined;
129 if (this.cursorX > 0) {
130 this.vt100('\r\n');
131 }
132 this.vt100('Session closed.');
7460295f 133 }
11cd1451
MG
134 this.showReconnect(true);
135 } catch (e) {
7460295f 136 }
7460295f
MG
137};
138
139ShellInABox.prototype.reconnect = function() {
140 this.showReconnect(false);
141 if (!this.session) {
d1edcc0e
MG
142 if (document.location.hash != '') {
143 // A shellinaboxd daemon launched from a CGI only allows a single
144 // session. In order to reconnect, we must reload the frame definition
145 // and obtain a new port number. As this is a different origin, we
146 // need to get enclosing page to help us.
147 parent.location = this.nextUrl;
7460295f 148 } else {
d1edcc0e
MG
149 if (this.url != this.nextUrl) {
150 document.location.replace(this.nextUrl);
151 } else {
152 this.pendingKeys = '';
153 this.keysInFlight = false;
154 this.reset(true);
155 this.sendRequest();
156 }
7460295f
MG
157 }
158 }
d1edcc0e 159 return false;
7460295f
MG
160};
161
162ShellInABox.prototype.sendRequest = function(request) {
163 if (request == undefined) {
164 request = new XMLHttpRequest();
165 }
11cd1451
MG
166 request.open('POST', this.url + '?', true);
167 request.setRequestHeader('Cache-Control', 'no-cache');
7460295f
MG
168 request.setRequestHeader('Content-Type',
169 'application/x-www-form-urlencoded; charset=utf-8');
11cd1451
MG
170 var content = 'width=' + this.terminalWidth +
171 '&height=' + this.terminalHeight +
172 (this.session ? '&session=' +
3bdb4585
MG
173 encodeURIComponent(this.session) : '&rooturl='+
174 encodeURIComponent(this.rooturl));
11cd1451 175 request.setRequestHeader('Content-Length', content.length);
30046882 176
7460295f
MG
177 request.onreadystatechange = function(shellInABox) {
178 return function() {
179 try {
180 return shellInABox.onReadyStateChange(request);
181 } catch (e) {
182 shellInABox.sessionClosed();
183 }
184 }
185 }(this);
11cd1451 186 request.send(content);
7460295f
MG
187};
188
189ShellInABox.prototype.onReadyStateChange = function(request) {
c27d0db9 190 if (request.readyState == 4 /* XHR_LOADED */) {
7460295f 191 if (request.status == 200) {
3240f75b
MG
192 this.connected = true;
193 var response = eval('(' + request.responseText + ')');
7460295f
MG
194 if (response.data) {
195 this.vt100(response.data);
196 }
197
198 if (!response.session ||
199 this.session && this.session != response.session) {
200 this.sessionClosed();
201 } else {
202 this.session = response.session;
203 this.sendRequest(request);
204 }
205 } else if (request.status == 0) {
206 // Time Out
207 this.sendRequest(request);
208 } else {
209 this.sessionClosed();
210 }
211 }
212};
213
214ShellInABox.prototype.sendKeys = function(keys) {
3240f75b
MG
215 if (!this.connected) {
216 return;
217 }
7460295f
MG
218 if (this.keysInFlight || this.session == undefined) {
219 this.pendingKeys += keys;
220 } else {
221 this.keysInFlight = true;
222 keys = this.pendingKeys + keys;
223 this.pendingKeys = '';
224 var request = new XMLHttpRequest();
11cd1451
MG
225 request.open('POST', this.url + '?', true);
226 request.setRequestHeader('Cache-Control', 'no-cache');
7460295f
MG
227 request.setRequestHeader('Content-Type',
228 'application/x-www-form-urlencoded; charset=utf-8');
11cd1451
MG
229 var content = 'width=' + this.terminalWidth +
230 '&height=' + this.terminalHeight +
231 '&session=' +encodeURIComponent(this.session)+
232 '&keys=' + encodeURIComponent(keys);
233 request.setRequestHeader('Content-Length', content.length);
7460295f
MG
234 request.onreadystatechange = function(shellInABox) {
235 return function() {
236 try {
237 return shellInABox.keyPressReadyStateChange(request);
238 } catch (e) {
239 }
240 }
241 }(this);
11cd1451 242 request.send(content);
7460295f
MG
243 }
244};
245
246ShellInABox.prototype.keyPressReadyStateChange = function(request) {
c27d0db9 247 if (request.readyState == 4 /* XHR_LOADED */) {
7460295f
MG
248 this.keysInFlight = false;
249 if (this.pendingKeys) {
250 this.sendKeys('');
251 }
252 }
253};
254
255ShellInABox.prototype.keysPressed = function(ch) {
256 var hex = '0123456789ABCDEF';
257 var s = '';
258 for (var i = 0; i < ch.length; i++) {
259 var c = ch.charCodeAt(i);
260 if (c < 128) {
261 s += hex.charAt(c >> 4) + hex.charAt(c & 0xF);
262 } else if (c < 0x800) {
263 s += hex.charAt(0xC + (c >> 10) ) +
264 hex.charAt( (c >> 6) & 0xF ) +
265 hex.charAt(0x8 + ((c >> 4) & 0x3)) +
266 hex.charAt( c & 0xF );
267 } else if (c < 0x10000) {
268 s += 'E' +
269 hex.charAt( (c >> 12) ) +
270 hex.charAt(0x8 + (c >> 10) & 0x3 ) +
271 hex.charAt( (c >> 6) & 0xF ) +
272 hex.charAt(0x8 + ((c >> 4) & 0x3)) +
273 hex.charAt( c & 0xF );
274 } else if (c < 0x110000) {
275 s += 'F' +
276 hex.charAt( (c >> 18) ) +
277 hex.charAt(0x8 + (c >> 16) & 0x3 ) +
278 hex.charAt( (c >> 12) & 0xF ) +
279 hex.charAt(0x8 + (c >> 10) & 0x3 ) +
280 hex.charAt( (c >> 6) & 0xF ) +
281 hex.charAt(0x8 + ((c >> 4) & 0x3)) +
282 hex.charAt( c & 0xF );
283 }
284 }
285 this.sendKeys(s);
286};
287
288ShellInABox.prototype.resized = function(w, h) {
289 // Do not send a resize request until we are fully initialized.
290 if (this.session) {
291 // sendKeys() always transmits the current terminal size. So, flush all
292 // pending keys.
293 this.sendKeys('');
294 }
295};
296
297ShellInABox.prototype.toggleSSL = function() {
d1edcc0e
MG
298 if (document.location.hash != '') {
299 if (this.nextUrl.match(/\?plain$/)) {
300 this.nextUrl = this.nextUrl.replace(/\?plain$/, '');
301 } else {
302 this.nextUrl = this.nextUrl.replace(/[?#].*/, '') + '?plain';
303 }
304 if (!this.session) {
305 parent.location = this.nextUrl;
306 }
307 } else {
308 this.nextUrl = this.nextUrl.match(/^https:/)
7460295f
MG
309 ? this.nextUrl.replace(/^https:/, 'http:').replace(/\/*$/, '/plain')
310 : this.nextUrl.replace(/^http/, 'https').replace(/\/*plain$/, '');
d1edcc0e 311 }
7460295f 312 if (this.nextUrl.match(/^[:]*:\/\/[^/]*$/)) {
d1edcc0e 313 this.nextUrl += '/';
7460295f
MG
314 }
315 if (this.session && this.nextUrl != this.url) {
316 alert('This change will take effect the next time you login.');
317 }
318};
319
320ShellInABox.prototype.extendContextMenu = function(entries, actions) {
321 // Modify the entries and actions in place, adding any locally defined
322 // menu entries.
323 var oldActions = [ ];
324 for (var i = 0; i < actions.length; i++) {
325 oldActions[i] = actions[i];
326 }
327 for (var node = entries.firstChild, i = 0, j = 0; node;
328 node = node.nextSibling) {
329 if (node.tagName == 'LI') {
330 actions[i++] = oldActions[j++];
331 if (node.id == "endconfig") {
332 node.id = '';
b624088c
MG
333 if (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL &&
334 !(typeof disableSSLMenu != 'undefined' && disableSSLMenu)) {
7460295f
MG
335 // If the server supports both SSL and plain text connections,
336 // provide a menu entry to switch between the two.
337 var newNode = document.createElement('li');
d1edcc0e 338 var isSecure;
1e1c8024 339 if (document.location.hash != '') {
d1edcc0e
MG
340 isSecure = !this.nextUrl.match(/\?plain$/);
341 } else {
342 isSecure = this.nextUrl.match(/^https:/);
343 }
344 newNode.innerHTML = (isSecure ? '&#10004; ' : '') + 'Secure';
7460295f
MG
345 if (node.nextSibling) {
346 entries.insertBefore(newNode, node.nextSibling);
347 } else {
348 entries.appendChild(newNode);
349 }
350 actions[i++] = this.toggleSSL;
351 node = newNode;
352 }
353 node.id = 'endconfig';
354 }
355 }
356 }
357
358};
359
360ShellInABox.prototype.about = function() {
ac96c090 361 alert("Shell In A Box version " + "2.9 (revision 181)" +
e0bb8a33 362 "\nCopyright 2008-2009 by Markus Gutschke\n" +
7460295f 363 "For more information check http://shellinabox.com" +
46f2036a 364 (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?
7460295f
MG
365 "\n\n" +
366 "This product includes software developed by the OpenSSL Project\n" +
367 "for use in the OpenSSL Toolkit. (http://www.openssl.org/)\n" +
368 "\n" +
369 "This product includes cryptographic software written by " +
370 "Eric Young\n(eay@cryptsoft.com)" :
371 ""));
372};
373
This page took 0.205553 seconds and 5 git commands to generate.