From d4b95f3ed4b8a0f47dab35a2560d76bb66117277 Mon Sep 17 00:00:00 2001 From: Ruben <ruben@rubenkerkhof.com> Date: Sun, 17 Oct 2010 17:50:39 +0200 Subject: [PATCH 12/14] 30_utf8-support.diff from Debian --- README.txt | 240 ++++++++++++++++++++++++++-------------------------- ajaxterm.1 | 2 + ajaxterm.html | 1 + ajaxterm.js | 13 +++- ajaxterm.py | 81 ++++++++---------- configure.makefile | 2 +- utf8-escape.js | 80 +++++++++++++++++ 7 files changed, 251 insertions(+), 168 deletions(-) create mode 100644 utf8-escape.js diff --git a/README.txt b/README.txt index 4b0ae99..05ae97f 100644 --- a/README.txt +++ b/README.txt @@ -1,120 +1,120 @@ -= [http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Ajaxterm] = - -Ajaxterm is a web based terminal. It was totally inspired and works almost -exactly like http://anyterm.org/ except it's much easier to install (see -comparaison with anyterm below). - -Ajaxterm written in python (and some AJAX javascript for client side) and depends only on python2.3 or better.[[BR]] -Ajaxterm is '''very simple to install''' on Linux, MacOS X, FreeBSD, Solaris, cygwin and any Unix that runs python2.3.[[BR]] -Ajaxterm was written by Antony Lesuisse (email: al AT udev.org), License Public Domain. - -Use the [/qweb/forum/viewforum.php?id=2 Forum], if you have any question or remark. - -== News == - - * 2006-10-29: v0.10 allow space in login, cgi launch fix, redhat init - * 2006-07-12: v0.9 change uid, daemon fix (Daniel Fischer) - * 2006-07-04: v0.8 add login support to ssh (Sven Geggus), change max width to 256 - * 2006-05-31: v0.7 minor fixes, daemon option - * 2006-05-23: v0.6 Applied debian and gentoo patches, renamed to Ajaxterm, default port 8022 - -== Download and Install == - - * Release: [/qweb/files/Ajaxterm-0.10.tar.gz Ajaxterm-0.10.tar.gz] - * Browse src: [/qweb/trac/browser/trunk/ajaxterm/ ajaxterm/] - -To install Ajaxterm issue the following commands: -{{{ -wget http://antony.lesuisse.org/qweb/files/Ajaxterm-0.10.tar.gz -tar zxvf Ajaxterm-0.10.tar.gz -cd Ajaxterm-0.10 -./ajaxterm.py -}}} -Then point your browser to this URL : http://localhost:8022/ - -== Screenshot == - -{{{ -#!html -<center><img src="/qweb/trac/attachment/wiki/AjaxTerm/scr.png?format=raw" alt="ajaxterm screenshot" style=""/></center> -}}} - -== Documentation and Caveats == - - * Ajaxterm only support latin1, if you use Ubuntu or any LANG==en_US.UTF-8 distribution don't forget to "unset LANG". - - * If run as root ajaxterm will run /bin/login, otherwise it will run ssh - localhost. To use an other command use the -c option. - - * By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is - strongly recommended to use '''https SSL/TLS''', and that is simple to - configure if you use the apache web server using mod_proxy.[[BR]][[BR]] - Using ssl will also speed up ajaxterm (probably because of keepalive).[[BR]][[BR]] - Here is an configuration example: - -{{{ - Listen 443 - NameVirtualHost *:443 - - <VirtualHost *:443> - ServerName localhost - SSLEngine On - SSLCertificateKeyFile ssl/apache.pem - SSLCertificateFile ssl/apache.pem - - ProxyRequests Off - <Proxy *> - Order deny,allow - Allow from all - </Proxy> - ProxyPass /ajaxterm/ http://localhost:8022/ - ProxyPassReverse /ajaxterm/ http://localhost:8022/ - </VirtualHost> -}}} - - * Using GET HTTP request seems to speed up ajaxterm, just click on GET in the - interface, but be warned that your keystrokes might be loggued (by apache or - any proxy). I usually enable it after the login. - - * Ajaxterm commandline usage: - -{{{ -usage: ajaxterm.py [options] - -options: - -h, --help show this help message and exit - -pPORT, --port=PORT Set the TCP port (default: 8022) - -cCMD, --command=CMD set the command (default: /bin/login or ssh localhost) - -l, --log log requests to stderr (default: quiet mode) - -d, --daemon run as daemon in the background - -PPIDFILE, --pidfile=PIDFILE - set the pidfile (default: /var/run/ajaxterm.pid) - -iINDEX_FILE, --index=INDEX_FILE - default index file (default: ajaxterm.html) - -uUID, --uid=UID Set the daemon's user id -}}} - - * Ajaxterm was first written as a demo for qweb (my web framework), but - actually doesn't use many features of qweb. - - * Compared to anyterm: - * There are no partial updates, ajaxterm updates either all the screen or - nothing. That make the code simpler and I also think it's faster. HTTP - replies are always gzencoded. When used in 80x25 mode, almost all of - them are below the 1500 bytes (size of an ethernet frame) and we just - replace the screen with the reply (no javascript string handling). - * Ajaxterm polls the server for updates with an exponentially growing - timeout when the screen hasn't changed. The timeout is also resetted as - soon as a key is pressed. Anyterm blocks on a pending request and use a - parallel connection for keypresses. The anyterm approch is better - when there aren't any keypress. - - * Ajaxterm files are released in the Public Domain, (except [http://sarissa.sourceforge.net/doc/ sarissa*] which are LGPL). - -== TODO == - - * insert mode ESC [ 4 h - * change size x,y from gui (sending signal) - * vt102 graphic codepage - * use innerHTML or prototype instead of sarissa - += [http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Ajaxterm] = + +Ajaxterm is a web based terminal. It was totally inspired and works almost +exactly like http://anyterm.org/ except it's much easier to install (see +comparaison with anyterm below). + +Ajaxterm written in python (and some AJAX javascript for client side) and depends only on python2.3 or better.[[BR]] +Ajaxterm is '''very simple to install''' on Linux, MacOS X, FreeBSD, Solaris, cygwin and any Unix that runs python2.3.[[BR]] +Ajaxterm was written by Antony Lesuisse (email: al AT udev.org), License Public Domain. + +Use the [/qweb/forum/viewforum.php?id=2 Forum], if you have any question or remark. + +== News == + + * 2006-10-29: v0.10 allow space in login, cgi launch fix, redhat init + * 2006-07-12: v0.9 change uid, daemon fix (Daniel Fischer) + * 2006-07-04: v0.8 add login support to ssh (Sven Geggus), change max width to 256 + * 2006-05-31: v0.7 minor fixes, daemon option + * 2006-05-23: v0.6 Applied debian and gentoo patches, renamed to Ajaxterm, default port 8022 + +== Download and Install == + + * Release: [/qweb/files/Ajaxterm-0.10.tar.gz Ajaxterm-0.10.tar.gz] + * Browse src: [/qweb/trac/browser/trunk/ajaxterm/ ajaxterm/] + +To install Ajaxterm issue the following commands: +{{{ +wget http://antony.lesuisse.org/qweb/files/Ajaxterm-0.10.tar.gz +tar zxvf Ajaxterm-0.10.tar.gz +cd Ajaxterm-0.10 +./ajaxterm.py +}}} +Then point your browser to this URL : http://localhost:8022/ + +== Screenshot == + +{{{ +#!html +<center><img src="/qweb/trac/attachment/wiki/AjaxTerm/scr.png?format=raw" alt="ajaxterm screenshot" style=""/></center> +}}} + +== Documentation and Caveats == + + * Ajaxterm only support utf8. + + * If run as root ajaxterm will run /bin/login, otherwise it will run ssh + localhost. To use an other command use the -c option. + + * By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is + strongly recommended to use '''https SSL/TLS''', and that is simple to + configure if you use the apache web server using mod_proxy.[[BR]][[BR]] + Using ssl will also speed up ajaxterm (probably because of keepalive).[[BR]][[BR]] + Here is an configuration example: + +{{{ + Listen 443 + NameVirtualHost *:443 + + <VirtualHost *:443> + ServerName localhost + SSLEngine On + SSLCertificateKeyFile ssl/apache.pem + SSLCertificateFile ssl/apache.pem + + ProxyRequests Off + <Proxy *> + Order deny,allow + Allow from all + </Proxy> + ProxyPass /ajaxterm/ http://localhost:8022/ + ProxyPassReverse /ajaxterm/ http://localhost:8022/ + </VirtualHost> +}}} + + * Using GET HTTP request seems to speed up ajaxterm, just click on GET in the + interface, but be warned that your keystrokes might be loggued (by apache or + any proxy). I usually enable it after the login. + + * Ajaxterm commandline usage: + +{{{ +usage: ajaxterm.py [options] + +options: + -h, --help show this help message and exit + -pPORT, --port=PORT Set the TCP port (default: 8022) + -cCMD, --command=CMD set the command (default: /bin/login or ssh localhost) + -l, --log log requests to stderr (default: quiet mode) + -d, --daemon run as daemon in the background + -PPIDFILE, --pidfile=PIDFILE + set the pidfile (default: /var/run/ajaxterm.pid) + -iINDEX_FILE, --index=INDEX_FILE + default index file (default: ajaxterm.html) + -uUID, --uid=UID Set the daemon's user id +}}} + + * Ajaxterm was first written as a demo for qweb (my web framework), but + actually doesn't use many features of qweb. + + * Compared to anyterm: + * There are no partial updates, ajaxterm updates either all the screen or + nothing. That make the code simpler and I also think it's faster. HTTP + replies are always gzencoded. When used in 80x25 mode, almost all of + them are below the 1500 bytes (size of an ethernet frame) and we just + replace the screen with the reply (no javascript string handling). + * Ajaxterm polls the server for updates with an exponentially growing + timeout when the screen hasn't changed. The timeout is also resetted as + soon as a key is pressed. Anyterm blocks on a pending request and use a + parallel connection for keypresses. The anyterm approch is better + when there aren't any keypress. + + * Ajaxterm files are released in the Public Domain, (except [http://sarissa.sourceforge.net/doc/ sarissa*] which are LGPL). + +== TODO == + + * insert mode ESC [ 4 h + * change size x,y from gui (sending signal) + * vt102 graphic codepage + * use innerHTML or prototype instead of sarissa + diff --git a/ajaxterm.1 b/ajaxterm.1 index 8d0a942..29d8250 100644 --- a/ajaxterm.1 +++ b/ajaxterm.1 @@ -20,6 +20,8 @@ A summary of the options supported by \fBajaxterm\fR is included below. .SH AUTHOR Antony Lesuisse <al@udev.org> +Adopted to UTF-8 by Sergej Pupykin <ps@lx-ltd.ru> + This manual page was written for the Debian system by Julien Valroff <julien@kirya.net> (but may be used by others). diff --git a/ajaxterm.html b/ajaxterm.html index 095e7d6..2cc48ef 100644 --- a/ajaxterm.html +++ b/ajaxterm.html @@ -8,6 +8,7 @@ <script type="text/javascript" src="sarissa_dhtml.js"></script> <script type="text/javascript" src="ajaxterm.js"></script> <script type="text/javascript" src="ajaxterm_config.js"></script> + <script type="text/javascript" src="utf8-escape.js"></script> <script type="text/javascript"> window.onload=function() { t=ajaxterm.Terminal("term",width,height); diff --git a/ajaxterm.js b/ajaxterm.js index 2579a8f..b976a96 100644 --- a/ajaxterm.js +++ b/ajaxterm.js @@ -142,7 +142,16 @@ ajaxterm.Terminal_ctor=function(id,width,height) { if (r.readyState==4) { if(r.status==200) { window.clearTimeout(error_timeout); - de=r.responseXML.documentElement; + if(ie) + { + var responseXMLdoc = new ActiveXObject("Microsoft.XMLDOM"); + responseXMLdoc.loadXML(r.responseText); + de = responseXMLdoc.documentElement; + } + else + { + de=r.responseXML.documentElement; + } if(de.tagName=="pre") { if(ie) { Sarissa.updateContentFromNode(de, dterm); @@ -250,7 +259,7 @@ ajaxterm.Terminal_ctor=function(id,width,height) { if(k=="+") { queue("%2B"); } else { - queue(escape(k)); + queue(utf8Escape(k)); } } ev.cancelBubble=true; diff --git a/ajaxterm.py b/ajaxterm.py index 8695590..92bf67e 100755 --- a/ajaxterm.py +++ b/ajaxterm.py @@ -21,7 +21,9 @@ os.chdir(os.path.normpath(os.path.dirname(__file__))) # Optional: Add QWeb in sys path sys.path[0:0]=glob.glob('../../python') -import qweb +import qweb, codecs +utf8decoder = codecs.getincrementaldecoder('utf8')() + from socket import gethostname @@ -92,31 +94,14 @@ class Terminal: for i in [i[4] for i in dir(self) if i.startswith('csi_') and len(i)==5]: if not self.csi_seq.has_key(i): self.csi_seq[i]=(getattr(self,'csi_'+i),[1]) - # Init 0-256 to latin1 and html translation table - self.trl1="" - for i in range(256): - if i<32: - self.trl1+=" " - elif i<127 or i>160: - self.trl1+=chr(i) - else: - self.trl1+="?" - self.trhtml="" - for i in range(256): - if i==0x0a or (i>32 and i<127) or i>160: - self.trhtml+=chr(i) - elif i<=32: - self.trhtml+="\xa0" - else: - self.trhtml+="?" - def reset(self,s=""): - self.scr=array.array('i',[0x000700]*(self.width*self.height)) + def reset(self,s=u""): + self.scr=array.array('l',[0x07000000]*(self.width*self.height)) self.st=0 self.sb=self.height-1 self.cx_bak=self.cx=0 self.cy_bak=self.cy=0 self.cl=0 - self.sgr=0x000700 + self.sgr=0x07000000 self.buf="" self.outbuf="" self.last_html="" @@ -127,7 +112,7 @@ class Terminal: self.scr[pos:pos+len(s)]=s def zero(self,y1,x1,y2,x2): w=self.width*(y2-y1)+x2-x1+1 - z=array.array('i',[0x000700]*w) + z=array.array('l',[0x07000000]*w) self.scr[self.width*y1+x1:self.width*y2+x2+1]=z def scroll_up(self,y1,y2): self.poke(y1,0,self.peek(y1+1,0,y2,self.width)) @@ -280,17 +265,17 @@ class Terminal: def csi_m(self,l): for i in l: if i==0 or i==39 or i==49 or i==27: - self.sgr=0x000700 + self.sgr=0x07000000 elif i==1: - self.sgr=(self.sgr|0x000800) + self.sgr=(self.sgr|0x08000000) elif i==7: - self.sgr=0x070000 + self.sgr=0x70000000 elif i>=30 and i<=37: c=i-30 - self.sgr=(self.sgr&0xff08ff)|(c<<8) + self.sgr=(self.sgr&0xf8ffffff)|(c<<24) elif i>=40 and i<=47: c=i-40 - self.sgr=(self.sgr&0x00ffff)|(c<<16) + self.sgr=(self.sgr&0x0fffffff)|(c<<28) # else: # print "CSI sgr ignore",l,i # print 'sgr: %r %x'%(l,self.sgr) @@ -320,12 +305,12 @@ class Terminal: break # if self.buf=='': print "ESC %r\n"%e def write(self,s): - for i in s: + for i in utf8decoder.decode(s): if len(self.buf) or (i in self.esc_seq): - self.buf+=i + self.buf+=chr(ord(i)&255) self.escape() elif i == '\x1b': - self.buf+=i + self.buf+=chr(ord(i)&255) else: self.echo(i) def read(self): @@ -333,35 +318,41 @@ class Terminal: self.outbuf="" return b def dump(self): - r='' + r=u'' for i in self.scr: - r+=chr(i&255) + r+=unichr(i&0xFFFFFF) return r - def dumplatin1(self): - return self.dump().translate(self.trl1) + def dumputf8(self): + return self.dump().encode('utf8') def dumphtml(self,color=1): h=self.height w=self.width r="" - span="" + span=u"" span_bg,span_fg=-1,-1 for i in range(h*w): - q,c=divmod(self.scr[i],256) + q,c=divmod(self.scr[i],256*256*256) if color: - bg,fg=divmod(q,256) + bg,fg=divmod(q,16) + bg &= 0x7 else: bg,fg=0,7 if i==self.cy*w+self.cx: bg,fg=1,7 if (bg!=span_bg or fg!=span_fg or i==h*w-1): if len(span): - r+='<span class="f%d b%d">%s</span>'%(span_fg,span_bg,cgi.escape(span.translate(self.trhtml))) - span="" + r+='<span class="f%d b%d">%s</span>'%(span_fg,span_bg,cgi.escape(span.replace(u' ',u'\xa0').encode('utf8'))) + span=u"" span_bg,span_fg=bg,fg - span+=chr(c) + if c == 0: + span+=u' ' + elif c > 0x10000: + span+=u'?' + else: + span+=unichr(c&0xFFFF) if i%w==w-1: - span+='\n' - r='<?xml version="1.0" encoding="ISO-8859-1"?><pre class="term">%s</pre>'%r + span+=u'\n' + r='<?xml version="1.0" encoding="utf8"?><pre class="term">%s</pre>'%r if self.last_html==r: return '<?xml version="1.0"?><idem></idem>' else: @@ -369,8 +360,8 @@ class Terminal: # print self return r def __repr__(self): - d=self.dumplatin1() - r="" + d=self.dumputf8() + r=u"" for i in range(self.height): r+="|%s|\n"%d[self.width*i:self.width*(i+1)] return r @@ -432,7 +423,7 @@ class Multiplex: elif os.getuid()==0: cmd=['/bin/login'] else: - sys.stdout.write(gethostname() + " login: ") + sys.stdout.write(gethostname() + u" login: ") login=sys.stdin.readline().strip() if re.match('^[0-9A-Za-z-_. ]+$',login): cmd=['ssh'] diff --git a/configure.makefile b/configure.makefile index a30dc23..c866804 100644 --- a/configure.makefile +++ b/configure.makefile @@ -5,7 +5,7 @@ install: install -d "%(bin)s" install -d "%(lib)s" install ajaxterm.bin "%(bin)s/ajaxterm" - install -m 644 ajaxterm.css ajaxterm.html ajaxterm.js qweb.py sarissa.js sarissa_dhtml.js "%(lib)s" + install -m 644 ajaxterm.css ajaxterm.html ajaxterm.js qweb.py sarissa.js sarissa_dhtml.js utf8-escape.js "%(lib)s" install -m 644 ajaxterm.conf "%(etc)s" install -m 755 ajaxterm.py "%(lib)s" ln -s /etc/ajaxterm.conf "%(lib)s"/ajaxterm_config.js diff --git a/utf8-escape.js b/utf8-escape.js new file mode 100644 index 0000000..dfb8cb3 --- /dev/null +++ b/utf8-escape.js @@ -0,0 +1,80 @@ +var char2hex = new Array( + "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", + "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", + "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", + "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f", + "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", + "%28", "%29", "%2a", "%2b", "%2c", "%2d", "%2e", "%2f", + "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37", + "%38", "%39", "%3a", "%3b", "%3c", "%3d", "%3e", "%3f", + "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47", + "%48", "%49", "%4a", "%4b", "%4c", "%4d", "%4e", "%4f", + "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57", + "%58", "%59", "%5a", "%5b", "%5c", "%5d", "%5e", "%5f", + "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67", + "%68", "%69", "%6a", "%6b", "%6c", "%6d", "%6e", "%6f", + "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77", + "%78", "%79", "%7a", "%7b", "%7c", "%7d", "%7e", "%7f", + "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", + "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f", + "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", + "%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", + "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af", + "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", + "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", + "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", + "%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf", + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df", + "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7", + "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef", + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff" + ); + +function utf8Escape(s) +{ + var sbuf = ""; + var i; + + var len = s.length; + for (i = 0; i < len; i++) + { + var ch = s.charCodeAt(i); + if( (65 <= ch && ch <= 90) || + (97 <= ch && ch <= 122) || + (48 <= ch && ch <= 57) ) + { + sbuf += String.fromCharCode(ch); + } + else if (ch == 32) + { + sbuf += '+'; + } + else if (ch == 45 || ch == 95 + || ch == 46 || ch == 33 + || ch == 126 || ch == 42 + || ch == 39 || ch == 40 + || ch == 41) + { + sbuf += char2hex[ch]; + } + else if (ch <= 0x007F) + { + sbuf += char2hex[ch]; + } + else if (ch <= 0x07FF) + { + sbuf += char2hex[0xc0 | (ch >> 6)]; + sbuf += char2hex[0x80 | (ch & 0x3F)]; + } + else + { + sbuf += char2hex[0xe0 | (ch >> 12)]; + sbuf += char2hex[0x80 | ((ch >> 6) & 0x3F)]; + sbuf += char2hex[0x80 | (ch & 0x3F)]; + } + } + return sbuf; +} -- 1.7.3.1