diff --git a/Makefile.am b/Makefile.am index e72456d..31a9c43 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,6 +37,8 @@ EXTRA_DIST = demo/beep.wav \ shellinabox/shell_in_a_box.js \ shellinabox/vt100.js \ debian/README \ + debian/README.available \ + debian/README.enabled \ debian/changelog \ debian/compat \ debian/control \ diff --git a/Makefile.in b/Makefile.in index d56aa88..9602b5b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -277,6 +277,8 @@ EXTRA_DIST = demo/beep.wav \ shellinabox/shell_in_a_box.js \ shellinabox/vt100.js \ debian/README \ + debian/README.available \ + debian/README.enabled \ debian/changelog \ debian/compat \ debian/control \ diff --git a/config.h b/config.h index 951299d..27d1e4d 100644 --- a/config.h +++ b/config.h @@ -138,7 +138,7 @@ #define STDC_HEADERS 1 /* Most recent revision number in the version control system */ -#define VCS_REVISION "169" +#define VCS_REVISION "170" /* Version number of package */ #define VERSION "2.9" diff --git a/configure b/configure index 1f353a4..4df3799 100755 --- a/configure +++ b/configure @@ -2317,7 +2317,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -VCS_REVISION=169 +VCS_REVISION=170 cat >>confdefs.h <<_ACEOF diff --git a/configure.ac b/configure.ac index 9e54461..88792b2 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.57) dnl This is the one location where the authoritative version number is stored AC_INIT(shellinabox, 2.9, markus@shellinabox.com) -VCS_REVISION=169 +VCS_REVISION=170 AC_SUBST(VCS_REVISION) AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}", [Most recent revision number in the version control system]) diff --git a/debian/README.available b/debian/README.available new file mode 100644 index 0000000..f438e40 --- /dev/null +++ b/debian/README.available @@ -0,0 +1,21 @@ +This directory contains all of the available user CSS style sheets. + +These options will show up in the right click context menu. + +In order to en-/disable the availability of options, add/remove the +appropriate symbolic link in "/etc/shellinabox/options-enabled" and +restart the daemon with "sudo /etc/init.d/shellinabox restart". + +All options are of the form "ID_Name of Option.css". Any options with +identical IDs will be put into the same option group. They are +mutually exclusive and only one such option can selected at any given +time. + +Please note that ':', ',', and ';' are all invalid characters in +option names. + +Options that should be turned on by default have the "_" character +replaced with a "+" character. + +In any group of mutually exclusive options, there must be exactly one +option that is turned on. diff --git a/debian/README.enabled b/debian/README.enabled new file mode 100644 index 0000000..c9ed645 --- /dev/null +++ b/debian/README.enabled @@ -0,0 +1,3 @@ +This directory contains links to "/etc/shellinabox/options-available". See +that directory for more details on how to enable or disable options that +show up in the right-click context menu. diff --git a/debian/compat b/debian/compat index b8626c4..7f8f011 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -4 +7 diff --git a/debian/docs b/debian/docs index 34380ab..885f1b8 100644 --- a/debian/docs +++ b/debian/docs @@ -5,7 +5,3 @@ INSTALL NEWS README TODO -shellinabox/white-on-black.css -shellinabox/black-on-white.css -shellinabox/monochrome.css -shellinabox/color.css diff --git a/debian/rules b/debian/rules index f7841ff..a082552 100755 --- a/debian/rules +++ b/debian/rules @@ -72,8 +72,23 @@ install: build dh_clean -k dh_installdirs @# Add here commands to install the package into debian/tmp - $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp - + $(MAKE) install DESTDIR="$(CURDIR)/debian/tmp" + # Set up system-wide user CSS style options + mkdir -p "$(CURDIR)/debian/tmp/etc/shellinabox/options-available" \ + "$(CURDIR)/debian/tmp/etc/shellinabox/options-enabled" + for i in "00+Black on White" "00_White On Black" \ + "01_Monochrome" "01+Color Terminal"; do \ + ln "$(CURDIR)/debian/tmp/usr/share/doc/shellinabox/$$(echo "$$i"| \ + sed -e 's/[0-9]*[_+]\([^ ]*\).*/\1/'| \ + tr A-Z a-z)"*.css \ + "$(CURDIR)/debian/tmp/etc/shellinabox/options-available/$$i.css";\ + done + cd "$(CURDIR)/debian/tmp/etc/shellinabox/options-enabled" && \ + ln -s ../options-available/*.css . + cp "$(CURDIR)/debian/README.available" \ + "$(CURDIR)/debian/tmp/etc/shellinabox/options-available/README" + cp "$(CURDIR)/debian/README.enabled" \ + "$(CURDIR)/debian/tmp/etc/shellinabox/options-enabled/README" # Build architecture-independent files here. binary-indep: build install @@ -86,7 +101,7 @@ binary-arch: build install dh_installchangelogs ChangeLog dh_installdocs --exclude COPYING --exclude INSTALL --exclude ChangeLog dh_installexamples - dh_install --sourcedir=debian/tmp + dh_install # dh_installmenu # dh_installdebconf # dh_installlogrotate diff --git a/debian/shellinabox.init b/debian/shellinabox.init index 4b7eaa5..db22f81 100755 --- a/debian/shellinabox.init +++ b/debian/shellinabox.init @@ -44,6 +44,20 @@ d_start() { --exec "'$DAEMON'" -- -q --background="'$PIDFILE'" \ -c "'${SHELLINABOX_DATADIR}'" -p "'${SHELLINABOX_PORT}'" \ -u "'${SHELLINABOX_USER}'" -g "'${SHELLINABOX_GROUP}'" \ + $(for i in $(ls /etc/shellinabox/options-enabled/*.css | + sed -e \ + 's/.*[/]\([0-9]*\)[-_+][^/:,;]*[.]css/\1/'| + sort -u); do + for j in /etc/shellinabox/options-enabled/"$i"*.css; do + echo -n "$j" | + sed -e 's/\(.*[/]\)\([0-9]*\)\([-_+]\)\([^/:,;]*\)[.]css/\4:\3\1\2\3\4.css,/ + s/:_/:-/' + done | + sed -e 's/,$/;/' + done | + sed -e 's/;$// + //b + s/.*/--user-css "\0"/') \ "${SHELLINABOX_ARGS}" } diff --git a/debian/shellinabox.install b/debian/shellinabox.install index e53389d..673dad3 100644 --- a/debian/shellinabox.install +++ b/debian/shellinabox.install @@ -1,4 +1,4 @@ -usr/bin/* -usr/share/man/man1/* -debian/tmp/usr/bin/* -debian/tmp/usr/share/man/man1/* +etc/shellinabox/options-available +etc/shellinabox/options-enabled +usr/bin +usr/share/man/man1 diff --git a/demo/vt100.js b/demo/vt100.js index 9dccb5e..0107364 100644 --- a/demo/vt100.js +++ b/demo/vt100.js @@ -173,6 +173,7 @@ function VT100(container) { // Optional arguments '(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?'); } + this.getUserSettings(); this.initializeElements(container); this.maxScrollbackLines = 500; this.npar = 0; @@ -203,10 +204,7 @@ VT100.prototype.reset = function(clearHistory) { this.crLfMode = false; this.offsetMode = false; this.mouseReporting = false; - this.utfEnabled = true; - this.visualBell = typeof suppressAllAudio != - 'undefined' && - suppressAllAudio; + this.utfEnabled = this.utfPreferred; this.utfCount = 0; this.utfChar = 0; this.color = 'ansi0 bgAnsi15'; @@ -248,6 +246,66 @@ VT100.prototype.addListener = function(elem, event, listener) { } }; +VT100.prototype.getUserSettings = function() { + // Compute hash signature to identify the entries in the userCSS menu. + // If the menu is unchanged from last time, default values can be + // looked up in a cookie associated with this page. + this.signature = 0; + this.utfPreferred = true; + this.visualBell = typeof suppressAllAudio != 'undefined' && + suppressAllAudio; + if (this.visualBell) { + this.signature = Math.floor(16807*this.signature + 1) % + ((1 << 31) - 1); + } + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + var label = userCSSList[i][0]; + for (var j = 0; j < label.length; ++j) { + this.signature = Math.floor(16807*this.signature+ + label.charCodeAt(j)) % + ((1 << 31) - 1); + } + if (userCSSList[i][1]) { + this.signature = Math.floor(16807*this.signature + 1) % + ((1 << 31) - 1); + } + } + } + + var key = 'shellInABox=' + this.signature + ':'; + var settings = document.cookie.indexOf(key); + if (settings >= 0) { + settings = document.cookie.substr(settings + key.length). + replace(/([0-1]*).*/, "$1"); + if (settings.length == 2 + (typeof userCSSList == 'undefined' ? + 0 : userCSSList.length)) { + this.utfPreferred = settings.charAt(0) != '0'; + this.visualBell = settings.charAt(1) != '0'; + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + userCSSList[i][2] = settings.charAt(i + 2) != '0'; + } + } + } + } + this.utfEnabled = this.utfPreferred; +}; + +VT100.prototype.storeUserSettings = function() { + var settings = 'shellInABox=' + this.signature + ':' + + (this.utfEnabled ? '1' : '0') + + (this.visualBell ? '1' : '0'); + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + settings += userCSSList[i][2] ? '1' : '0'; + } + } + var d = new Date(); + d.setDate(d.getDate() + 3653); + document.cookie = settings + ';expires=' + d.toGMTString(); +}; + VT100.prototype.initializeUserCSSStyles = function() { this.usercssActions = []; if (typeof userCSSList != 'undefined') { @@ -334,6 +392,7 @@ VT100.prototype.initializeUserCSSStyles = function() { } else { sheet.disabled = true; } + userCSSList[i][2] = !sheet.disabled; } } entry = entry.nextSibling; @@ -1821,7 +1880,11 @@ VT100.prototype.pasteFnc = function() { }; VT100.prototype.toggleUTF = function() { - this.utfEnabled = !this.utfEnabled; + this.utfEnabled = !this.utfEnabled; + + // We always persist the last value that the user selected. Not necessarily + // the last value that a random program requested. + this.utfPreferred = this.utfEnabled; }; VT100.prototype.toggleBell = function() { @@ -1829,7 +1892,7 @@ VT100.prototype.toggleBell = function() { }; VT100.prototype.about = function() { - alert("VT100 Terminal Emulator " + "2.9 (revision 169)" + + alert("VT100 Terminal Emulator " + "2.9 (revision 170)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com"); }; @@ -1922,6 +1985,7 @@ VT100.prototype.showContextMenu = function(x, y) { return function(event) { vt100.hideContextMenu(); action.call(vt100); + vt100.storeUserSettings(); return vt100.cancelEvent(event || window.event); } }(this, actions[i])); diff --git a/shellinabox/shell_in_a_box.js b/shellinabox/shell_in_a_box.js index 6807414..12d2bed 100644 --- a/shellinabox/shell_in_a_box.js +++ b/shellinabox/shell_in_a_box.js @@ -355,7 +355,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) { }; ShellInABox.prototype.about = function() { - alert("Shell In A Box version " + "2.9 (revision 169)" + + alert("Shell In A Box version " + "2.9 (revision 170)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com" + (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ? diff --git a/shellinabox/vt100.js b/shellinabox/vt100.js index 9dccb5e..0107364 100644 --- a/shellinabox/vt100.js +++ b/shellinabox/vt100.js @@ -173,6 +173,7 @@ function VT100(container) { // Optional arguments '(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?'); } + this.getUserSettings(); this.initializeElements(container); this.maxScrollbackLines = 500; this.npar = 0; @@ -203,10 +204,7 @@ VT100.prototype.reset = function(clearHistory) { this.crLfMode = false; this.offsetMode = false; this.mouseReporting = false; - this.utfEnabled = true; - this.visualBell = typeof suppressAllAudio != - 'undefined' && - suppressAllAudio; + this.utfEnabled = this.utfPreferred; this.utfCount = 0; this.utfChar = 0; this.color = 'ansi0 bgAnsi15'; @@ -248,6 +246,66 @@ VT100.prototype.addListener = function(elem, event, listener) { } }; +VT100.prototype.getUserSettings = function() { + // Compute hash signature to identify the entries in the userCSS menu. + // If the menu is unchanged from last time, default values can be + // looked up in a cookie associated with this page. + this.signature = 0; + this.utfPreferred = true; + this.visualBell = typeof suppressAllAudio != 'undefined' && + suppressAllAudio; + if (this.visualBell) { + this.signature = Math.floor(16807*this.signature + 1) % + ((1 << 31) - 1); + } + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + var label = userCSSList[i][0]; + for (var j = 0; j < label.length; ++j) { + this.signature = Math.floor(16807*this.signature+ + label.charCodeAt(j)) % + ((1 << 31) - 1); + } + if (userCSSList[i][1]) { + this.signature = Math.floor(16807*this.signature + 1) % + ((1 << 31) - 1); + } + } + } + + var key = 'shellInABox=' + this.signature + ':'; + var settings = document.cookie.indexOf(key); + if (settings >= 0) { + settings = document.cookie.substr(settings + key.length). + replace(/([0-1]*).*/, "$1"); + if (settings.length == 2 + (typeof userCSSList == 'undefined' ? + 0 : userCSSList.length)) { + this.utfPreferred = settings.charAt(0) != '0'; + this.visualBell = settings.charAt(1) != '0'; + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + userCSSList[i][2] = settings.charAt(i + 2) != '0'; + } + } + } + } + this.utfEnabled = this.utfPreferred; +}; + +VT100.prototype.storeUserSettings = function() { + var settings = 'shellInABox=' + this.signature + ':' + + (this.utfEnabled ? '1' : '0') + + (this.visualBell ? '1' : '0'); + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + settings += userCSSList[i][2] ? '1' : '0'; + } + } + var d = new Date(); + d.setDate(d.getDate() + 3653); + document.cookie = settings + ';expires=' + d.toGMTString(); +}; + VT100.prototype.initializeUserCSSStyles = function() { this.usercssActions = []; if (typeof userCSSList != 'undefined') { @@ -334,6 +392,7 @@ VT100.prototype.initializeUserCSSStyles = function() { } else { sheet.disabled = true; } + userCSSList[i][2] = !sheet.disabled; } } entry = entry.nextSibling; @@ -1821,7 +1880,11 @@ VT100.prototype.pasteFnc = function() { }; VT100.prototype.toggleUTF = function() { - this.utfEnabled = !this.utfEnabled; + this.utfEnabled = !this.utfEnabled; + + // We always persist the last value that the user selected. Not necessarily + // the last value that a random program requested. + this.utfPreferred = this.utfEnabled; }; VT100.prototype.toggleBell = function() { @@ -1829,7 +1892,7 @@ VT100.prototype.toggleBell = function() { }; VT100.prototype.about = function() { - alert("VT100 Terminal Emulator " + "2.9 (revision 169)" + + alert("VT100 Terminal Emulator " + "2.9 (revision 170)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com"); }; @@ -1922,6 +1985,7 @@ VT100.prototype.showContextMenu = function(x, y) { return function(event) { vt100.hideContextMenu(); action.call(vt100); + vt100.storeUserSettings(); return vt100.cancelEvent(event || window.event); } }(this, actions[i])); diff --git a/shellinabox/vt100.jspp b/shellinabox/vt100.jspp index 925ea44..03fec0b 100644 --- a/shellinabox/vt100.jspp +++ b/shellinabox/vt100.jspp @@ -173,6 +173,7 @@ function VT100(container) { // Optional arguments '(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?'); } + this.getUserSettings(); this.initializeElements(container); this.maxScrollbackLines = 500; this.npar = 0; @@ -203,10 +204,7 @@ VT100.prototype.reset = function(clearHistory) { this.crLfMode = false; this.offsetMode = false; this.mouseReporting = false; - this.utfEnabled = true; - this.visualBell = typeof suppressAllAudio != - 'undefined' && - suppressAllAudio; + this.utfEnabled = this.utfPreferred; this.utfCount = 0; this.utfChar = 0; this.color = 'ansi0 bgAnsi15'; @@ -248,6 +246,66 @@ VT100.prototype.addListener = function(elem, event, listener) { } }; +VT100.prototype.getUserSettings = function() { + // Compute hash signature to identify the entries in the userCSS menu. + // If the menu is unchanged from last time, default values can be + // looked up in a cookie associated with this page. + this.signature = 0; + this.utfPreferred = true; + this.visualBell = typeof suppressAllAudio != 'undefined' && + suppressAllAudio; + if (this.visualBell) { + this.signature = Math.floor(16807*this.signature + 1) % + ((1 << 31) - 1); + } + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + var label = userCSSList[i][0]; + for (var j = 0; j < label.length; ++j) { + this.signature = Math.floor(16807*this.signature+ + label.charCodeAt(j)) % + ((1 << 31) - 1); + } + if (userCSSList[i][1]) { + this.signature = Math.floor(16807*this.signature + 1) % + ((1 << 31) - 1); + } + } + } + + var key = 'shellInABox=' + this.signature + ':'; + var settings = document.cookie.indexOf(key); + if (settings >= 0) { + settings = document.cookie.substr(settings + key.length). + replace(/([0-1]*).*/, "$1"); + if (settings.length == 2 + (typeof userCSSList == 'undefined' ? + 0 : userCSSList.length)) { + this.utfPreferred = settings.charAt(0) != '0'; + this.visualBell = settings.charAt(1) != '0'; + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + userCSSList[i][2] = settings.charAt(i + 2) != '0'; + } + } + } + } + this.utfEnabled = this.utfPreferred; +}; + +VT100.prototype.storeUserSettings = function() { + var settings = 'shellInABox=' + this.signature + ':' + + (this.utfEnabled ? '1' : '0') + + (this.visualBell ? '1' : '0'); + if (typeof userCSSList != 'undefined') { + for (var i = 0; i < userCSSList.length; ++i) { + settings += userCSSList[i][2] ? '1' : '0'; + } + } + var d = new Date(); + d.setDate(d.getDate() + 3653); + document.cookie = settings + ';expires=' + d.toGMTString(); +}; + VT100.prototype.initializeUserCSSStyles = function() { this.usercssActions = []; if (typeof userCSSList != 'undefined') { @@ -334,6 +392,7 @@ VT100.prototype.initializeUserCSSStyles = function() { } else { sheet.disabled = true; } + userCSSList[i][2] = !sheet.disabled; } } entry = entry.nextSibling; @@ -1821,7 +1880,11 @@ VT100.prototype.pasteFnc = function() { }; VT100.prototype.toggleUTF = function() { - this.utfEnabled = !this.utfEnabled; + this.utfEnabled = !this.utfEnabled; + + // We always persist the last value that the user selected. Not necessarily + // the last value that a random program requested. + this.utfPreferred = this.utfEnabled; }; VT100.prototype.toggleBell = function() { @@ -1922,6 +1985,7 @@ VT100.prototype.showContextMenu = function(x, y) { return function(event) { vt100.hideContextMenu(); action.call(vt100); + vt100.storeUserSettings(); return vt100.cancelEvent(event || window.event); } }(this, actions[i]));