├── .gitignore ├── LibVNCServer-0.9.14.tar.gz ├── Makefile ├── README ├── TODO ├── debian ├── changelog ├── control ├── copyright ├── docs ├── rules └── source │ └── format ├── genfont.c ├── genfont2.c ├── glyphs.h ├── vncpatches ├── series └── tls-auth-pluging.patch ├── vncterm.c ├── vncterm.h └── vncterm.pod /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | vncterm 3 | libvncserver-LibVNCServer-0.9.11/ 4 | # wchardata.c is copied from unifont (/usr/share/unifont/wchardata.c) 5 | wchardata.c 6 | *.deb 7 | *.buildinfo 8 | *.changes 9 | -------------------------------------------------------------------------------- /LibVNCServer-0.9.14.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proxmox/vncterm/8112a4cf9d16ce672edcd8445e3180911ba33f25/LibVNCServer-0.9.14.tar.gz -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include /usr/share/dpkg/pkg-info.mk 2 | include /usr/share/dpkg/architecture.mk 3 | 4 | PACKAGE=vncterm 5 | BUILDDIR ?= $(PACKAGE)-$(DEB_VERSION_UPSTREAM) 6 | 7 | VNCVER=0.9.14 8 | VNCREL=LibVNCServer-$(VNCVER) 9 | VNCDIR=libvncserver-$(VNCREL) 10 | VNCSRC=$(VNCREL).tar.gz 11 | VNCLIB=$(VNCDIR)/libvncserver.a 12 | 13 | DSC = $(PACKAGE)_$(DEB_VERSION).dsc 14 | 15 | DEB=$(PACKAGE)_$(DEB_VERSION)_$(DEB_HOST_ARCH).deb 16 | DBG_DEB=$(PACKAGE)-dbgsym_$(DEB_VERSION)_$(DEB_HOST_ARCH).deb 17 | 18 | CPPFLAGS += -O2 -g -Wall -Wno-deprecated-declarations -D_GNU_SOURCE -I $(VNCDIR) 19 | 20 | VNC_LIBS := -lnsl -lpthread -lz -ljpeg -lutil -lgnutls -lpng 21 | 22 | all: vncterm 23 | 24 | font.data: genfont2 25 | ./genfont2 -o font.data.tmp -i /usr/share/unifont/unifont.hex 26 | mv font.data.tmp font.data 27 | 28 | genfont2: genfont2.c 29 | gcc -g -O2 -o $@ genfont2.c -Wall -Wextra -D_GNU_SOURCE -lz 30 | 31 | .PHONY: vnc 32 | vnc: $(VNCLIB) 33 | $(VNCLIB): $(VNCSRC) 34 | rm -rf $(VNCDIR) 35 | tar xf $(VNCSRC) 36 | ln -s ../vncpatches $(VNCDIR)/patches 37 | cd $(VNCDIR); quilt push -a 38 | cd $(VNCDIR); cmake -D WITH_GNUTLS=OFF -D WITH_OPENSSL=OFF -D WITH_WEBSOCKETS=OFF -D WITH_SYSTEMD=OFF -D WITH_TIGHTVNC_FILETRANSFER=OFF -D WITH_GCRYPT=OFF -D WITH_LZO=OFF -D BUILD_SHARED_LIBS=OFF .; cmake --build . 39 | 40 | vncterm: vncterm.c wchardata.c $(VNCLIB) 41 | $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(VNC_LIBS) 42 | 43 | wchardata.c: 44 | cp /usr/share/unifont/$@ $@ 45 | 46 | .PHONY: install 47 | install: vncterm vncterm.1 font.data 48 | mkdir -p $(DESTDIR)/usr/share/$(PACKAGE) 49 | install -m 0644 font.data $(DESTDIR)/usr/share/$(PACKAGE) 50 | mkdir -p $(DESTDIR)/usr/share/man/man1 51 | install -m 0644 vncterm.1 $(DESTDIR)/usr/share/man/man1 52 | mkdir -p $(DESTDIR)/usr/bin 53 | install -m 0755 vncterm $(DESTDIR)/usr/bin 54 | 55 | .PHONY: dinstall 56 | dinstall: $(DEB) 57 | dpkg -i $(DEB) 58 | 59 | vncterm.1: vncterm.pod 60 | rm -f $@ 61 | pod2man -n $< -s 1 -r $(DEB_VERSION_UPSTREAM) <$< >$@ 62 | 63 | $(BUILDDIR): 64 | rm -rf $@ $@.tmp 65 | rsync -a . $@.tmp 66 | echo "git clone git://git.proxmox.com/git/vncterm.git\\ngit checkout $$(git rev-parse HEAD)" > $@.tmp/debian/SOURCE 67 | mv $@.tmp $@ 68 | 69 | .PHONY: deb 70 | deb: $(DEB) 71 | $(DEB): $(BUILDDIR) 72 | cd $(BUILDDIR); dpkg-buildpackage -rfakeroot -b -us -uc 73 | lintian $(DEB) 74 | 75 | .PHONY: dsc 76 | dsc: $(DSC) 77 | rm -rf $(BUILDDIR) $(DSC) 78 | $(MAKE) $(DSC) 79 | lintian $(DSC) 80 | 81 | $(DSC): $(BUILDDIR) 82 | cd $(BUILDDIR); dpkg-buildpackage -S -us -uc 83 | 84 | sbuild: $(DSC) 85 | sbuild $< 86 | 87 | .PHONY: upload 88 | upload: UPLOAD_DIST ?= $(DEB_DISTRIBUTION) 89 | upload: $(DEB) 90 | tar cf - $(DEB) $(DBG_DEB) | ssh -X repoman@repo.proxmox.com -- upload --product pve --dist $(UPLOAD_DIST) 91 | 92 | .PHONY: clean 93 | clean: 94 | rm -f *.dsc *.deb $(PACKAGE)*.tar* *.changes *.build *.buildinfo 95 | rm -f vncterm vncterm.1 genfont genfont2 *~ *.tmp wchardata.c font.data 96 | rm -rf $(VNCDIR) $(PACKAGE)-[0-9]*/ 97 | 98 | .PHONY: distclean 99 | distclean: clean 100 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Simple VNC terminal emulator (inspired by VncCommand) 2 | 3 | We try to simulate a 'xterm', because we want to support: 4 | 5 | - unicode 6 | - mouse 7 | 8 | and xterm seems to be the best solution for that. 9 | 10 | some code is inspired by: qemu, VncCommand, xterm, linux kernel, ... 11 | 12 | libvncserver 13 | ============ 14 | 15 | LibVNCServer does not suppurt TLS currently. So we staically link to a 16 | patched versions on that library instead of using the debian shared 17 | libraries. 18 | 19 | VNC Java Applet (for use in web based applications): 20 | ==================================================== 21 | 22 | We use patched VncViewer files (TigerVNC 1.1.0 sources): 23 | 24 | http://www.tigervnc.com/ 25 | 26 | We sign the applet to make clipboard working. 27 | 28 | Note: Newer tigervnc 1.2.0 always use a toplevel window, which 29 | make it basically useless as applet. 30 | 31 | http://sourceforge.net/tracker/?func=detail&aid=3488166&group_id=254363&atid=1126849 32 | 33 | I put patches for 1.2.0 to newtigerpatches subdir. 34 | 35 | Note: javascript-events.patch requires JSObject, which is inside plugin.jar 36 | previously provided by sun-java-jdk. For wheezy/openjdk, we need to install 37 | package "icedtea-netx-common" which contains that file. 38 | 39 | TODO: 40 | ===== 41 | 42 | Useful sources for terminal emulation: 43 | 44 | xterm source: ctlseqs.txt 45 | http://vt100.net/docs/vt220-rm 46 | man 5 terminfo 47 | infocmp xterm 48 | man console_codes 49 | 50 | Fonts: 51 | 52 | we currently use fonts provided by the debian console-data package: 53 | see /usr/share/consolefonts/* 54 | 55 | Only 8x16 fonts are supported 56 | 57 | TODO contains a list of unimplemented things. 58 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | TODO: 3 | better command line parser - print usage infos 4 | implement some kind of regression testing 5 | cleanup the TLS patch and try to merge into upstream 6 | scroll/history support? 7 | more ESC sequences (see xterm source ctlseqs.txt) 8 | disp_ctrl 9 | add arabic font glyphs 10 | add japanese font glyphs 11 | add other font glyphs (maybe http://openlab.jp/efont/unicode/)? 12 | 13 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | vncterm (1.8.0) bookworm; urgency=medium 2 | 3 | * re-build for Debian 12 Bookworm based releases 4 | 5 | * update libvncserver to 0.9.14 6 | 7 | -- Proxmox Support Team Mon, 29 May 2023 17:10:38 +0200 8 | 9 | vncterm (1.7-1) bullseye; urgency=medium 10 | 11 | * rebuild for Debian 11 Bullseye based releases 12 | 13 | -- Proxmox Support Team Sun, 16 May 2021 19:06:09 +0200 14 | 15 | vncterm (1.6-2) pve pmg; urgency=medium 16 | 17 | * import libvncserver 0.9.13 upstream release 18 | 19 | -- Proxmox Support Team Wed, 15 Jul 2020 07:05:12 +0200 20 | 21 | vncterm (1.6-1) pve pmg; urgency=medium 22 | 23 | * rebuild for Debian Buster 24 | 25 | -- Proxmox Support Team Wed, 22 May 2019 19:42:26 +0200 26 | 27 | vncterm (1.5-3) unstable; urgency=medium 28 | 29 | * depend on libjpeg62-turbo instead of libjpeg62 30 | 31 | -- Proxmox Support Team Wed, 15 Nov 2017 12:46:19 +0100 32 | 33 | vncterm (1.5-2) unstable; urgency=medium 34 | 35 | * replaced pure plack cursor with a more visible pointer with white edges 36 | 37 | -- Proxmox Support Team Wed, 07 Jun 2017 13:53:17 +0200 38 | 39 | vncterm (1.5-1) unstable; urgency=medium 40 | 41 | * use unifont to support more glyphs (range 0x0000..0xFFFF) 42 | 43 | * support wide characters 44 | 45 | * support combining glyphs 46 | 47 | -- Proxmox Support Team Wed, 24 May 2017 13:12:55 +0200 48 | 49 | vncterm (1.4-2) unstable; urgency=medium 50 | 51 | * fix bound checking on cursor move 52 | 53 | -- Proxmox Support Team Sat, 06 May 2017 08:09:29 +0200 54 | 55 | vncterm (1.4-1) unstable; urgency=medium 56 | 57 | * recompile for Debian Stretch / PVE 5 58 | 59 | -- Proxmox Support Team Fri, 10 Mar 2017 10:19:48 +0100 60 | 61 | vncterm (1.3-2) unstable; urgency=medium 62 | 63 | * bound check utf8 characters 64 | 65 | * detect empty first parameter of escape codes 66 | 67 | -- Proxmox Support Team Fri, 10 Mar 2017 10:11:00 +0100 68 | 69 | vncterm (1.3-1) unstable; urgency=low 70 | 71 | * update cipher suites to GnuTLS's NORMAL 72 | 73 | * allow building with GnuTLS 3.5 74 | 75 | * update LibVNCServer to 0.9.11 76 | 77 | -- Proxmox Support Team Fri, 3 Feb 2017 08:52:31 +0100 78 | 79 | vncterm (1.2-1) unstable; urgency=low 80 | 81 | * recompile for Debian Jessie / PVE 4 82 | 83 | -- Proxmox Support Team Fri, 27 Feb 2015 20:00:46 +0100 84 | 85 | vncterm (1.1-8) unstable; urgency=low 86 | 87 | * update applet signature (new code signing cert) 88 | 89 | -- Proxmox Support Team Fri, 25 Jul 2014 06:57:46 +0200 90 | 91 | vncterm (1.1-7) unstable; urgency=low 92 | 93 | * new option -notls (for novnc) 94 | 95 | -- Proxmox Support Team Mon, 23 Jun 2014 13:30:50 +0200 96 | 97 | vncterm (1.1-6) unstable; urgency=low 98 | 99 | * set Caller-Allowable-Codebase and remove Trusted-Library. This avoids 100 | security popups with latest Java 7u45. Also see: 101 | 102 | http://stackoverflow.com/questions/19393826/java-applet-manifest-allow-all-caller-allowable-codebase 103 | 104 | -- Proxmox Support Team Fri, 08 Nov 2013 11:27:08 +0100 105 | 106 | vncterm (1.1-5) unstable; urgency=low 107 | 108 | * use Comodo code sign cert for applet signature 109 | 110 | -- Proxmox Support Team Fri, 08 Nov 2013 08:35:10 +0100 111 | 112 | vncterm (1.1-4) unstable; urgency=low 113 | 114 | * Allow to add intermediate certificates to /etc/pve/local/pve-ssl.pem 115 | (users previously used apache option SSLCertificateChainFile for that). 116 | 117 | -- Proxmox Support Team Mon, 03 Jun 2013 08:26:59 +0200 118 | 119 | vncterm (1.1-3) unstable; urgency=low 120 | 121 | * re-enable javascript-events.patch (used for migrate/reload) 122 | 123 | -- Proxmox Support Team Fri, 10 May 2013 07:56:35 +0200 124 | 125 | vncterm (1.1-2) unstable; urgency=low 126 | 127 | * recompile VnCViewer.jar with openJDK 128 | 129 | * set trusted-lib to avoid security popup 130 | 131 | * disable unused javascript-events.patch 132 | 133 | -- Proxmox Support Team Sat, 20 Apr 2013 16:05:41 +0200 134 | 135 | vncterm (1.1-1) unstable; urgency=low 136 | 137 | * recompile for wheezy 138 | 139 | -- Proxmox Support Team Fri, 15 Mar 2013 08:26:04 +0100 140 | 141 | vncterm (1.0-3) unstable; urgency=low 142 | 143 | * fix focus traversal 144 | 145 | -- Proxmox Support Team Tue, 21 Aug 2012 09:14:04 +0200 146 | 147 | vncterm (1.0-2) unstable; urgency=low 148 | 149 | * do not create a new process group (with setsid), so 150 | we can kill the whole pve task if used inside fork_worker(). 151 | 152 | -- Proxmox Support Team Tue, 13 Sep 2011 10:49:32 +0200 153 | 154 | vncterm (1.0-1) unstable; urgency=low 155 | 156 | * use TigerVNC java sources 157 | 158 | * implement TLS encryption and vencrypt password auth 159 | 160 | * removed support for -passwdfile option 161 | 162 | -- root Mon, 24 Jan 2011 10:46:25 +0100 163 | 164 | vncterm (0.9-2) unstable; urgency=low 165 | 166 | * compiled for debian etch 167 | 168 | * use memmove instead of rfbDoCopyRect (avoid SIGSEGV when 169 | called with negative dy) 170 | 171 | -- Proxmox Support Team Wed, 22 Apr 2009 10:02:08 +0200 172 | 173 | vncterm (0.9-1) stable; urgency=low 174 | 175 | * initial import 176 | 177 | -- Proxmox Support Team Thu, 27 Dec 2007 05:57:17 +0100 178 | 179 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: vncterm 2 | Section: admin 3 | Priority: optional 4 | Maintainer: Proxmox Support Team 5 | Build-Depends: cmake, 6 | debhelper-compat (= 12), 7 | libglib2.0-dev, 8 | libgnutls28-dev, 9 | libjpeg62-turbo-dev, 10 | libpng-dev, 11 | quilt, 12 | unifont, 13 | zlib1g-dev, 14 | Standards-Version: 4.6.1 15 | 16 | Package: vncterm 17 | Architecture: any 18 | Section: x11 19 | Priority: optional 20 | Depends: libgnutls-deb0-28 | libgnutls30, 21 | libjpeg62-turbo, 22 | libpng16-16, 23 | zlib1g (>= 1:1.2.1), 24 | ${misc:Depends}, 25 | ${shlibs:Depends}, 26 | Description: VNC Terminal Emulator 27 | With vncterm you can start commands and export its standard input and 28 | output to any VNC client (simulating a xterm Terminal). 29 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Source: git://git.proxmox.com/git/vncterm.git 3 | 4 | Files: 5 | * 6 | Copyright: 2007 - 2023, Proxmox Support Team 7 | License: AGPL-3.0-or-later 8 | This program is free software: you can redistribute it and/or modify it under 9 | the terms of the GNU Affero General Public License as published by the Free 10 | Software Foundation, either version 3 of the License, or (at your option) any 11 | later version. 12 | . 13 | This program is distributed in the hope that it will be useful, but WITHOUT 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more 16 | details. 17 | . 18 | You should have received a copy of the GNU Affero General Public License along 19 | with this program. If not, see . 20 | Comment: 21 | The authors take the provided option to use the LibVNC as GPL 2 *or later*, 22 | and use it as GPL 3, allowing combination with our AGPLv3 code. 23 | 24 | Files: 25 | LibVNCServer-*.tar* 26 | Copyright: 2001-2003, Johannes E. Schindelin 27 | 2001 - 2022, The LibVNC Authors 28 | License: GPL-2+ 29 | This program is free software; you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation; either version 2 of the License, or 32 | (at your option) any later version. 33 | . 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | . 39 | You should have received a copy of the GNU General Public License 40 | along with this package; if not, see <https://www.gnu.org/licenses/>. 41 | Comment: 42 | On Debian systems, the full text of the GNU General Public License 43 | version 2 can be found in the file '/usr/share/common-licenses/GPL-2'. 44 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | debian/SOURCE 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | %: 4 | dh $@ 5 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /genfont.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2007 Proxmox Server Solutions GmbH 4 | 5 | Copyright: vzdump is under GNU GPL, the GNU General Public License. 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; version 2 dated June, 1991. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 | 02111-1307, USA. 20 | 21 | Author: Dietmar Maurer 22 | 23 | */ 24 | 25 | #include 26 | #include 27 | #include /* read compressed console fonts */ 28 | #include 29 | #include 30 | 31 | /* map unicode to font */ 32 | static unsigned short vt_fontmap[65536]; 33 | 34 | /* font glyph storage */ 35 | static unsigned char *vt_font_data = NULL; 36 | static int vt_font_size = 0; 37 | static int vt_font_maxsize = 0; 38 | 39 | /* PSF stuff */ 40 | 41 | 42 | #define PSF_MAGIC1 0x36 43 | #define PSF_MAGIC2 0x04 44 | 45 | #define PSF_MODE256NOSFM 0 46 | #define PSF_MODE512NOSFM 1 47 | #define PSF_MODE256SFM 2 48 | #define PSF_MODE512SFM 3 49 | 50 | #define PSF_SEPARATOR 0xFFFF 51 | 52 | struct psf_header 53 | { 54 | unsigned char magic1, magic2; /* Magic number */ 55 | unsigned char mode; /* PSF font mode */ 56 | unsigned char charheight; /* Character size */ 57 | }; 58 | 59 | #define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2) 60 | #define PSF_MODE_VALID(x) ((x) <= PSF_MODE512SFM) 61 | #define PSF_MODE_HAS512(x) (((x) == 1) || ((x) == 3)) 62 | #define PSF_MODE_HASSFM(x) (((x) == 2) || ((x) == 3)) 63 | 64 | typedef unsigned short unicode; 65 | 66 | static int 67 | font_add_glyph (const char *data) 68 | { 69 | 70 | if (vt_font_size >= vt_font_maxsize) { 71 | vt_font_maxsize += 256; 72 | vt_font_data = realloc (vt_font_data, vt_font_maxsize*16); 73 | } 74 | 75 | memcpy (vt_font_data + vt_font_size*16, data, 16); 76 | 77 | vt_font_size += 1; 78 | 79 | return vt_font_size - 1; 80 | } 81 | 82 | static int 83 | load_psf_font (const char *filename, int is_default) 84 | { 85 | struct psf_header psfhdr; 86 | 87 | gzFile f = gzopen(filename, "rb"); 88 | if (f == NULL) { 89 | fprintf (stderr, "unable to read file %s\n", filename); 90 | exit(-1); 91 | } 92 | 93 | // read psf header 94 | if (gzread(f, &psfhdr, sizeof(struct psf_header)) != sizeof(struct psf_header)) { 95 | fprintf (stderr, "unable to read psf font header (%s)\n", filename); 96 | gzclose (f); 97 | return -1; 98 | } 99 | 100 | if (!PSF_MAGIC_OK(psfhdr) || !PSF_MODE_VALID(psfhdr.mode) || 101 | !PSF_MODE_HASSFM(psfhdr.mode) || (psfhdr.charheight != 16)) { 102 | fprintf (stderr, "no valid 8*16 psf font (%s)\n", filename); 103 | gzclose (f); 104 | return -1; 105 | } 106 | 107 | int charcount = ((PSF_MODE_HAS512(psfhdr.mode)) ? 512 : 256); 108 | 109 | int size = 16*charcount; 110 | 111 | char *chardata = (char *)malloc (size); 112 | 113 | if (size != gzread(f, chardata, size)) { 114 | fprintf (stderr, "unable to read font character data (%s)\n", filename); 115 | gzclose (f); 116 | return -1; 117 | } 118 | 119 | unicode unichar; 120 | int glyph; 121 | 122 | for (glyph = 0 ;glyph < charcount ;glyph++) { 123 | int fi = 0; 124 | while (gzread (f, &unichar, sizeof(unicode)) == sizeof(unicode) && 125 | (unichar != PSF_SEPARATOR)) { 126 | if (!vt_fontmap[unichar]) { 127 | if (!fi) { 128 | fi = font_add_glyph (chardata + glyph*16); 129 | } 130 | vt_fontmap[unichar] = fi; 131 | } 132 | } 133 | 134 | if (is_default && fi && glyph < 256) { 135 | vt_fontmap[0xf000 + glyph] = fi; 136 | } 137 | } 138 | 139 | free (chardata); 140 | gzclose (f); 141 | 142 | return 0; 143 | } 144 | 145 | void 146 | print_glyphs () 147 | { 148 | int i, j; 149 | 150 | printf ("static int vt_font_size = %d;\n\n", vt_font_size); 151 | 152 | printf ("static unsigned char vt_font_data[] = {\n"); 153 | for (i = 0; i < vt_font_size; i++) { 154 | printf ("\t/* %d 0x%02x */\n", i, i); 155 | for (j = 0; j < 16; j++) { 156 | unsigned char d = vt_font_data[i*16+j]; 157 | printf ("\t0x%02X, /* ", d); 158 | int k; 159 | for (k = 128; k > 0; k = k>>1) { 160 | printf ("%c", (d & k) ? '1': '0'); 161 | } 162 | printf (" */\n"); 163 | } 164 | printf ("\n"); 165 | } 166 | printf ("};\n\n"); 167 | 168 | printf ("static unsigned short vt_fontmap[65536] = {\n"); 169 | for (i = 0; i < 0x0ffff; i++) { 170 | printf ("\t/* 0x%04X => */ %d,\n", i, vt_fontmap[i]); 171 | } 172 | printf ("};\n\n"); 173 | 174 | } 175 | 176 | int 177 | main (int argc, char** argv) 178 | { 179 | char empty[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; 180 | glob_t globbuf; 181 | 182 | font_add_glyph (empty); 183 | 184 | /* font load order is only important if glyphs are redefined */ 185 | load_psf_font ("/usr/share/consolefonts/default8x16.psf.gz", 1); /* vga default */ 186 | load_psf_font ("/usr/share/consolefonts/lat1u-16.psf.gz", 0); /* Latin-1 */ 187 | load_psf_font ("/usr/share/consolefonts/lat2u-16.psf.gz", 0); /* Latin-2 */ 188 | load_psf_font ("/usr/share/consolefonts/lat4u-16.psf.gz", 0); /* Baltic */ 189 | 190 | load_psf_font ("/usr/share/consolefonts/iso07.f16.psf.gz", 0); /* Greek */ 191 | load_psf_font ("/usr/share/consolefonts/Goha-16.psf.gz", 0); /* Ethiopic */ 192 | 193 | /* fixme: Arabic, Japanese letters ? */ 194 | 195 | if (0) { 196 | glob("/usr/share/consolefonts/*", GLOB_ERR, NULL, &globbuf); 197 | 198 | int i; 199 | for (i = 0; i < globbuf.gl_pathc; i++) { 200 | int pc = vt_font_size; 201 | load_psf_font (globbuf.gl_pathv[i], 0); 202 | if (vt_font_size > pc) { 203 | printf ("TEST: %s %d\n", globbuf.gl_pathv[i], vt_font_size - pc); 204 | } 205 | } 206 | } else { 207 | 208 | print_glyphs (); 209 | 210 | } 211 | 212 | exit (0); 213 | } 214 | -------------------------------------------------------------------------------- /genfont2.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2017 Proxmox Server Solutions GmbH 4 | 5 | Copyright: vncterm is under GNU GPL, the GNU General Public License. 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; version 2 dated June, 1991. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 | 02111-1307, USA. 20 | 21 | Author: Dominik Csapak 22 | 23 | This tool converts the unifont.hex file format into 24 | a binary format used in vncterm to render glyphs. 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #define NUMCODEPOINTS 0xFFFF 35 | #define GLYPHLINES 16 36 | #define INDEXLENGTH 4 37 | 38 | /* parses strings like 00F0 to the integer */ 39 | long 40 | parsehex(char *val, size_t length) 41 | { 42 | unsigned int value = 0; 43 | 44 | for (size_t i = 0; i < length; i++) { 45 | value *= 16; 46 | if (val[i] >= '0' && val[i] <= '9') { 47 | value += (val[i] - '0'); 48 | } else if (val[i] >= 'A' && val[i] <= 'F') { 49 | value += (val[i] - 'A' + 10); 50 | } else if (val[i] >= 'a' && val[i] <= 'f') { 51 | value += (val[i] - 'a' + 10); 52 | } else { 53 | return -1; 54 | } 55 | } 56 | 57 | return value; 58 | } 59 | 60 | void usage(char **argv) { 61 | printf("Usage: %s [OPTION]...\n", argv[0]); 62 | printf("Converts font data from hex format into binary format used by vncterm.\n"); 63 | 64 | printf("\n"); 65 | printf(" -o, --output file for output, if omitted, write to STDOUT\n"); 66 | printf(" -i, --input file for input, if omitted read from STDIN\n"); 67 | printf(" -h, --help display this help\n"); 68 | 69 | printf("\nThe input has to be formatted in the hex format of unifont.\n"); 70 | } 71 | 72 | int 73 | main (int argc, char** argv) 74 | { 75 | FILE *fd; 76 | FILE *outfd; 77 | char *line = NULL; 78 | char *tmp = NULL; 79 | char *fontfile = NULL; 80 | char *outfile = NULL; 81 | size_t linesize = 0; 82 | uint8_t emptyglyph[GLYPHLINES*2] = { 0 }; 83 | uint8_t glyph[GLYPHLINES*2] = { 0 }; 84 | int nextcodepoint = 0; 85 | int codepoint = 0; 86 | int c; 87 | 88 | static struct option long_options[] = { 89 | {"help", no_argument, 0, 'h'}, 90 | {"output", required_argument, 0, 'o'}, 91 | {"input", required_argument, 0, 'i'}, 92 | { 0 , 0, 0, 0} 93 | }; 94 | int option_index = 0; 95 | 96 | while((c = getopt_long(argc, argv, "hi:o:", long_options, &option_index)) != -1) { 97 | switch (c) { 98 | case 'h': 99 | usage(argv); 100 | exit(0); 101 | break; 102 | case 'o': 103 | outfile = optarg; 104 | break; 105 | case 'i': 106 | fontfile = optarg; 107 | break; 108 | default: 109 | usage(argv); 110 | exit(1); 111 | } 112 | } 113 | 114 | if (fontfile != NULL){ 115 | fd = fopen(fontfile, "r"); 116 | if (fd == NULL) { 117 | fprintf(stderr, "Error opening '%s'\n", fontfile); 118 | perror(NULL); 119 | exit(2); 120 | } 121 | } else { 122 | fd = stdin; 123 | } 124 | 125 | if (outfile != NULL) { 126 | outfd = fopen(outfile, "w"); 127 | if (outfd == NULL) { 128 | fprintf(stderr, "Error opening '%s'\n", outfile); 129 | perror(NULL); 130 | exit(2); 131 | } 132 | } else { 133 | outfd = stdout; 134 | } 135 | 136 | 137 | while (getline(&line, &linesize, fd) != -1) { 138 | codepoint = parsehex(line, INDEXLENGTH); 139 | if (codepoint == -1) { 140 | fprintf(stderr, "Cannot parse codepoint index: '%s'\n", line); 141 | free(line); 142 | exit(4); 143 | } 144 | 145 | /* fill in missing codepoints with empty glyphs */ 146 | while (nextcodepoint++ < codepoint) { 147 | fwrite(emptyglyph, sizeof(emptyglyph), 1, outfd); 148 | } 149 | 150 | tmp = line + INDEXLENGTH + 1; 151 | size_t i = 0; 152 | 153 | /* parse until end of line */ 154 | while (*(tmp+i*2) != '\n' && i < sizeof(glyph)) { 155 | int value = parsehex(tmp+i*2, 2); 156 | 157 | if (value == -1) { 158 | fprintf(stderr, "Cannot parse glyph from line: '%s' at position %ld ('%s')\n", line, i*2, tmp+i*2); 159 | free(line); 160 | exit(4); 161 | } 162 | 163 | glyph[i++] = (uint8_t)value; 164 | } 165 | 166 | /* if we have a 1width glyph, fill the rest with zeroes */ 167 | while (i < sizeof(glyph)) { 168 | glyph[i++] = 0; 169 | } 170 | 171 | fwrite(glyph, sizeof(glyph), 1, outfd); 172 | } 173 | 174 | if(errno) { 175 | perror("Cannot not read line from file"); 176 | } 177 | 178 | while (nextcodepoint++ <= NUMCODEPOINTS) { 179 | fwrite(emptyglyph, sizeof(emptyglyph), 1, outfd); 180 | } 181 | 182 | free(line); 183 | exit(0); 184 | } 185 | -------------------------------------------------------------------------------- /vncpatches/series: -------------------------------------------------------------------------------- 1 | tls-auth-pluging.patch 2 | -------------------------------------------------------------------------------- /vncpatches/tls-auth-pluging.patch: -------------------------------------------------------------------------------- 1 | Index: libvncserver-LibVNCServer-0.9.13/libvncserver/auth.c 2 | =================================================================== 3 | --- libvncserver-LibVNCServer-0.9.13.orig/libvncserver/auth.c 4 | +++ libvncserver-LibVNCServer-0.9.13/libvncserver/auth.c 5 | @@ -301,7 +301,8 @@ rfbAuthNewClient(rfbClientPtr cl) 6 | 7 | if (!cl->screen->authPasswdData || cl->reverseConnection) { 8 | /* chk if this condition is valid or not. */ 9 | - securityType = rfbSecTypeNone; 10 | + /* we disable anonymous auth */ 11 | + // securityType = rfbSecTypeNone; 12 | } else if (cl->screen->authPasswdData) { 13 | securityType = rfbSecTypeVncAuth; 14 | } 15 | Index: libvncserver-LibVNCServer-0.9.13/libvncserver/sockets.c 16 | =================================================================== 17 | --- libvncserver-LibVNCServer-0.9.13.orig/libvncserver/sockets.c 18 | +++ libvncserver-LibVNCServer-0.9.13/libvncserver/sockets.c 19 | @@ -638,7 +638,11 @@ rfbReadExactTimeout(rfbClientPtr cl, cha 20 | n = read(sock, buf, len); 21 | } 22 | #else 23 | - n = read(sock, buf, len); 24 | + if (cl->sock_read_fn) { 25 | + n = cl->sock_read_fn(cl, buf, len); 26 | + } else { 27 | + n = read(sock, buf, len); 28 | + } 29 | #endif 30 | 31 | if (n > 0) { 32 | @@ -826,7 +830,11 @@ rfbWriteExact(rfbClientPtr cl, 33 | n = rfbssl_write(cl, buf, len); 34 | else 35 | #endif 36 | + if (cl->sock_write_fn) { 37 | + n = cl->sock_write_fn(cl, buf, len); 38 | + } else { 39 | n = write(sock, buf, len); 40 | + } 41 | 42 | if (n > 0) { 43 | 44 | Index: libvncserver-LibVNCServer-0.9.13/rfb/rfb.h 45 | =================================================================== 46 | --- libvncserver-LibVNCServer-0.9.13.orig/rfb/rfb.h 47 | +++ libvncserver-LibVNCServer-0.9.13/rfb/rfb.h 48 | @@ -411,6 +411,9 @@ typedef struct _rfbStatList { 49 | typedef struct _rfbSslCtx rfbSslCtx; 50 | typedef struct _wsCtx wsCtx; 51 | 52 | +typedef ssize_t (*sock_read_fn_t)(struct _rfbClientRec *cl, void *buf, size_t count); 53 | +typedef ssize_t (*sock_write_fn_t)(struct _rfbClientRec *cl, const void *buf, size_t count); 54 | + 55 | typedef struct _rfbClientRec { 56 | 57 | /** back pointer to the screen */ 58 | @@ -431,6 +434,10 @@ typedef struct _rfbClientRec { 59 | void* clientData; 60 | ClientGoneHookPtr clientGoneHook; 61 | 62 | + /* use to hook up TLS read/write */ 63 | + sock_read_fn_t sock_read_fn; 64 | + sock_read_fn_t sock_write_fn; 65 | + 66 | rfbSocket sock; 67 | char *host; 68 | 69 | -------------------------------------------------------------------------------- /vncterm.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2007-2011 Proxmox Server Solutions GmbH 4 | 5 | Copyright: vzdump is under GNU GPL, the GNU General Public License. 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; version 2 dated June, 1991. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 | 02111-1307, USA. 20 | 21 | Author: Dietmar Maurer 22 | 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include /* for openpty and forkpty */ 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "vncterm.h" 45 | 46 | #include 47 | #include 48 | 49 | /* define this for debugging */ 50 | //#define DEBUG 51 | 52 | char *auth_path = "/"; 53 | char *auth_perm = "Sys.Console"; 54 | 55 | uint16_t screen_width = 744; 56 | uint16_t screen_height = 400; 57 | 58 | int use_x509 = 1; 59 | 60 | extern int wcwidth (wchar_t wc); 61 | unsigned char *fontdata; 62 | 63 | #define FONTFILE "/usr/share/vncterm/font.data" 64 | #define GLYPHLINES 16 65 | 66 | static char * 67 | urlencode(char *buf, const char *value) 68 | { 69 | static const char *hexchar = "0123456789abcdef"; 70 | char *p = buf; 71 | int i; 72 | int l = strlen(value); 73 | for (i = 0; i < l; i++) { 74 | char c = value[i]; 75 | if (('a' <= c && c <= 'z') || 76 | ('A' <= c && c <= 'Z') || 77 | ('0' <= c && c <= '9')) { 78 | *p++ = c; 79 | } else if (c == 32) { 80 | *p++ = '+'; 81 | } else { 82 | *p++ = '%'; 83 | *p++ = hexchar[c >> 4]; 84 | *p++ = hexchar[c & 15]; 85 | } 86 | } 87 | *p = 0; 88 | 89 | return p; 90 | } 91 | 92 | static int 93 | pve_auth_verify(const char *clientip, const char *username, const char *passwd) 94 | { 95 | struct sockaddr_in server; 96 | 97 | int sfd = socket(AF_INET, SOCK_STREAM, 0); 98 | if (sfd == -1) { 99 | perror("pve_auth_verify: socket failed"); 100 | return -1; 101 | } 102 | 103 | struct hostent *he; 104 | if ((he = gethostbyname("localhost")) == NULL) { 105 | fprintf(stderr, "pve_auth_verify: error resolving hostname\n"); 106 | goto err; 107 | } 108 | 109 | memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length); 110 | server.sin_family = AF_INET; 111 | server.sin_port = htons(85); 112 | 113 | if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) { 114 | perror("pve_auth_verify: error connecting to server"); 115 | goto err; 116 | } 117 | 118 | char buf[8192]; 119 | char form[8192]; 120 | 121 | char *p = form; 122 | p = urlencode(p, "username"); 123 | *p++ = '='; 124 | p = urlencode(p, username); 125 | 126 | *p++ = '&'; 127 | p = urlencode(p, "password"); 128 | *p++ = '='; 129 | p = urlencode(p, passwd); 130 | 131 | *p++ = '&'; 132 | p = urlencode(p, "path"); 133 | *p++ = '='; 134 | p = urlencode(p, auth_path); 135 | 136 | *p++ = '&'; 137 | p = urlencode(p, "privs"); 138 | *p++ = '='; 139 | p = urlencode(p, auth_perm); 140 | 141 | sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n" 142 | "Host: localhost:85\n" 143 | "Connection: close\n" 144 | "PVEClientIP: %s\n" 145 | "Content-Type: application/x-www-form-urlencoded\n" 146 | "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form); 147 | ssize_t len = strlen(buf); 148 | ssize_t sb = send(sfd, buf, len, 0); 149 | if (sb < 0) { 150 | perror("pve_auth_verify: send failed"); 151 | goto err; 152 | } 153 | if (sb != len) { 154 | fprintf(stderr, "pve_auth_verify: partial send error\n"); 155 | goto err; 156 | } 157 | 158 | len = recv(sfd, buf, sizeof(buf) - 1, 0); 159 | if (len < 0) { 160 | perror("pve_auth_verify: recv failed"); 161 | goto err; 162 | } 163 | 164 | buf[len] = 0; 165 | 166 | //printf("DATA:%s\n", buf); 167 | 168 | shutdown(sfd, SHUT_RDWR); 169 | 170 | return strncmp(buf, "HTTP/1.1 200 OK", 15); 171 | 172 | err: 173 | shutdown(sfd, SHUT_RDWR); 174 | return -1; 175 | } 176 | 177 | #ifdef DEBUG 178 | static void vnc_debug_gnutls_log(int level, const char* str) { 179 | fprintf(stderr, "%d %s", level, str); 180 | } 181 | #endif 182 | 183 | #define DH_BITS 2048 184 | static gnutls_dh_params_t dh_params; 185 | 186 | typedef struct { 187 | gnutls_session_t session; 188 | } tls_client_t; 189 | 190 | static ssize_t 191 | vnc_tls_push( 192 | gnutls_transport_ptr_t transport, 193 | const void *data, 194 | size_t len) 195 | { 196 | rfbClientPtr cl = (rfbClientPtr)transport; 197 | int n; 198 | 199 | retry: 200 | n = send(cl->sock, data, len, 0); 201 | if (n < 0) { 202 | if (errno == EINTR) 203 | goto retry; 204 | return -1; 205 | } 206 | return n; 207 | } 208 | 209 | static ssize_t 210 | vnc_tls_pull( 211 | gnutls_transport_ptr_t transport, 212 | void *data, 213 | size_t len) 214 | { 215 | rfbClientPtr cl = (rfbClientPtr)transport; 216 | int n; 217 | 218 | retry: 219 | n = recv(cl->sock, data, len, 0); 220 | if (n < 0) { 221 | if (errno == EINTR) 222 | goto retry; 223 | return -1; 224 | } 225 | return n; 226 | } 227 | 228 | ssize_t vnc_tls_read(rfbClientPtr cl, void *buf, size_t count) 229 | { 230 | tls_client_t *sd = (tls_client_t *)cl->clientData; 231 | 232 | int ret = gnutls_read(sd->session, buf, count); 233 | if (ret < 0) { 234 | if (ret == GNUTLS_E_AGAIN) 235 | errno = EAGAIN; 236 | else 237 | errno = EIO; 238 | ret = -1; 239 | } 240 | 241 | return ret; 242 | } 243 | ssize_t vnc_tls_write(rfbClientPtr cl, void *buf, size_t count) 244 | { 245 | tls_client_t *sd = (tls_client_t *)cl->clientData; 246 | 247 | int ret = gnutls_write(sd->session, buf, count); 248 | if (ret < 0) { 249 | if (ret == GNUTLS_E_AGAIN) 250 | errno = EAGAIN; 251 | else 252 | errno = EIO; 253 | ret = -1; 254 | } 255 | 256 | return ret; 257 | } 258 | 259 | static gnutls_anon_server_credentials 260 | tls_initialize_anon_cred(void) 261 | { 262 | gnutls_anon_server_credentials anon_cred; 263 | int ret; 264 | 265 | if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) { 266 | rfbLog("can't allocate credentials: %s\n", gnutls_strerror(ret)); 267 | return NULL; 268 | } 269 | 270 | #if GNUTLS_VERSION_NUMBER >= 0x030506 271 | gnutls_anon_set_server_known_dh_params(anon_cred, GNUTLS_SEC_PARAM_MEDIUM); 272 | #else 273 | gnutls_anon_set_server_dh_params(anon_cred, dh_params); 274 | #endif 275 | 276 | return anon_cred; 277 | } 278 | 279 | static gnutls_certificate_credentials_t 280 | tls_initialize_x509_cred(void) 281 | { 282 | gnutls_certificate_credentials_t x509_cred; 283 | int ret; 284 | 285 | /* Paths to x509 certs/keys */ 286 | char *x509cacert = "/etc/pve/pve-root-ca.pem"; 287 | char *x509cert = "/etc/pve/local/pve-ssl.pem"; 288 | char *x509key = "/etc/pve/local/pve-ssl.key"; 289 | 290 | if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { 291 | rfbLog("can't allocate credentials: %s\n", gnutls_strerror(ret)); 292 | return NULL; 293 | } 294 | 295 | if ((ret = gnutls_certificate_set_x509_trust_file 296 | (x509_cred, x509cacert, GNUTLS_X509_FMT_PEM)) < 0) { 297 | rfbLog("can't load CA certificate: %s\n", gnutls_strerror(ret)); 298 | gnutls_certificate_free_credentials(x509_cred); 299 | return NULL; 300 | } 301 | 302 | if ((ret = gnutls_certificate_set_x509_key_file 303 | (x509_cred, x509cert, x509key, GNUTLS_X509_FMT_PEM)) < 0) { 304 | rfbLog("can't load certificate & key: %s\n", gnutls_strerror(ret)); 305 | gnutls_certificate_free_credentials(x509_cred); 306 | return NULL; 307 | } 308 | #if GNUTLS_VERSION_NUMBER >= 0x030506 309 | /* only available since GnuTLS 3.5.6, on previous versions see 310 | * gnutls_certificate_set_dh_params(). */ 311 | gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_MEDIUM); 312 | #else 313 | gnutls_certificate_set_dh_params (x509_cred, dh_params); 314 | #endif 315 | 316 | return x509_cred; 317 | } 318 | 319 | /* rfb tls security handler */ 320 | 321 | #define rfbSecTypeVencrypt 19 322 | #define rfbVencryptTlsPlain 259 323 | #define rfbVencryptX509Plain 262 324 | 325 | void rfbEncodeU32(char *buf, uint32_t value) 326 | { 327 | buf[0] = (value >> 24) & 0xFF; 328 | buf[1] = (value >> 16) & 0xFF; 329 | buf[2] = (value >> 8) & 0xFF; 330 | buf[3] = value & 0xFF; 331 | } 332 | 333 | uint32_t rfbDecodeU32(char *data, size_t offset) 334 | { 335 | return ((data[offset] << 24) | (data[offset + 1] << 16) | 336 | (data[offset + 2] << 8) | data[offset + 3]); 337 | } 338 | 339 | static void 340 | vencrypt_subauth_plain(rfbClientPtr cl) 341 | { 342 | const char *err = NULL; 343 | char buf[4096]; 344 | int n; 345 | 346 | char clientip[INET6_ADDRSTRLEN]; 347 | clientip[0] = 0; 348 | struct sockaddr_in client; 349 | socklen_t addrlen = sizeof(client); 350 | if (getpeername(cl->sock, &client, &addrlen) == 0) { 351 | inet_ntop(client.sin_family, &client.sin_addr, 352 | clientip, sizeof(clientip)); 353 | } 354 | 355 | if ((n = rfbReadExact(cl, buf, 8)) <= 0) { 356 | err = n ? "read failed" : "client gone"; 357 | goto err; 358 | } 359 | 360 | uint32_t ulen = rfbDecodeU32(buf, 0); 361 | uint32_t pwlen = rfbDecodeU32(buf, 4); 362 | 363 | if (!ulen) { 364 | err = "No User name."; 365 | goto err; 366 | } 367 | if (ulen >= 255) { 368 | err = "User name too long."; 369 | goto err; 370 | } 371 | if (!pwlen) { 372 | err = "Password too short"; 373 | goto err; 374 | } 375 | if (pwlen >= 511) { 376 | err = "Password too long."; 377 | goto err; 378 | } 379 | 380 | if ((n = rfbReadExact(cl, buf, ulen)) <= 0) { 381 | err = n ? "read failed" : "client gone"; 382 | goto err; 383 | } 384 | buf[ulen] = 0; 385 | char *username = buf; 386 | char *passwd = buf + ulen + 1; 387 | if ((n = rfbReadExact(cl, passwd, pwlen)) <= 0) { 388 | err = n ? "read failed" : "client gone"; 389 | goto err; 390 | } 391 | passwd[pwlen] = 0; 392 | 393 | rfbLog("VencryptPlain: username: %s pw: %s\n", username, passwd); 394 | 395 | if (pve_auth_verify(clientip, username, passwd) == 0) { 396 | rfbEncodeU32(buf, 0); /* Accept auth completion */ 397 | rfbWriteExact(cl, buf, 4); 398 | cl->state = RFB_INITIALISATION; 399 | return; 400 | } 401 | 402 | err = "Authentication failed"; 403 | err: 404 | rfbLog("VencryptPlain: %s\n", err ? err : "no reason specified"); 405 | if (err) { 406 | rfbEncodeU32(buf, 1); /* Reject auth */ 407 | rfbWriteExact(cl, buf, 4); 408 | if (cl->protocolMinorVersion >= 8) { 409 | int elen = strlen(err); 410 | rfbEncodeU32(buf, elen); 411 | rfbWriteExact(cl, buf, 4); 412 | rfbWriteExact(cl, err, elen); 413 | } 414 | } 415 | rfbCloseClient(cl); 416 | return; 417 | } 418 | 419 | static void 420 | rfbVncAuthVencrypt(rfbClientPtr cl) 421 | { 422 | int ret; 423 | 424 | /* Send VeNCrypt version 0.2 */ 425 | char buf[256]; 426 | buf[0] = 0; 427 | buf[1] = 2; 428 | 429 | if (rfbWriteExact(cl, buf, 2) < 0) { 430 | rfbLogPerror("rfbVncAuthVencrypt: write"); 431 | rfbCloseClient(cl); 432 | return; 433 | } 434 | 435 | int n = rfbReadExact(cl, buf, 2); 436 | if (n <= 0) { 437 | if (n == 0) 438 | rfbLog("rfbVncAuthVencrypt: client gone\n"); 439 | else 440 | rfbLogPerror("rfbVncAuthVencrypt: read"); 441 | rfbCloseClient(cl); 442 | return; 443 | } 444 | 445 | if (buf[0] != 0 || buf[1] != 2) { 446 | rfbLog("Unsupported VeNCrypt protocol %d.%d\n", 447 | (int)buf[0], (int)buf[1]); 448 | buf[0] = 1; /* Reject version */ 449 | rfbWriteExact(cl, buf, 1); 450 | rfbCloseClient(cl); 451 | return; 452 | } 453 | 454 | /* Sending allowed auth */ 455 | int req_auth = use_x509 ? rfbVencryptX509Plain : rfbVencryptTlsPlain; 456 | 457 | buf[0] = 0; /* Accept version */ 458 | buf[1] = 1; /* number of sub auths */ 459 | rfbEncodeU32(buf+2, req_auth); 460 | if (rfbWriteExact(cl, buf, 6) < 0) { 461 | rfbLogPerror("rfbVncAuthVencrypt: write"); 462 | rfbCloseClient(cl); 463 | return; 464 | } 465 | 466 | n = rfbReadExact(cl, buf, 4); 467 | if (n <= 0) { 468 | if (n == 0) 469 | rfbLog("rfbVncAuthVencrypt: client gone\n"); 470 | else 471 | rfbLogPerror("rfbVncAuthVencrypt: read"); 472 | rfbCloseClient(cl); 473 | return; 474 | } 475 | 476 | int auth = rfbDecodeU32(buf, 0); 477 | if (auth != req_auth) { 478 | buf[0] = 1; /* Reject auth*/ 479 | rfbWriteExact(cl, buf, 1); 480 | rfbCloseClient(cl); 481 | return; 482 | } 483 | 484 | buf[0] = 1; /* Accept auth */ 485 | if (rfbWriteExact(cl, buf, 1) < 0) { 486 | rfbLogPerror("rfbVncAuthVencrypt: write"); 487 | rfbCloseClient(cl); 488 | return; 489 | } 490 | 491 | tls_client_t *sd = calloc(1, sizeof(tls_client_t)); 492 | 493 | if (sd->session == NULL) { 494 | if (gnutls_init(&sd->session, GNUTLS_SERVER) < 0) { 495 | rfbLog("gnutls_init failed\n"); 496 | rfbCloseClient(cl); 497 | return; 498 | 499 | } 500 | 501 | if ((ret = gnutls_set_default_priority(sd->session)) < 0) { 502 | rfbLog("gnutls_set_default_priority failed: %s\n", gnutls_strerror(ret)); 503 | sd->session = NULL; 504 | rfbCloseClient(cl); 505 | return; 506 | } 507 | 508 | static const char *priority_str_x509 = "NORMAL"; 509 | static const char *priority_str_anon = "NORMAL:+ANON-ECDH:+ANON-DH"; 510 | if ((ret = gnutls_priority_set_direct(sd->session, use_x509 ? priority_str_x509 : priority_str_anon, NULL)) < 0) { 511 | rfbLog("gnutls_priority_set_direct failed: %s\n", gnutls_strerror(ret)); 512 | sd->session = NULL; 513 | rfbCloseClient(cl); 514 | return; 515 | } 516 | 517 | if (use_x509) { 518 | gnutls_certificate_server_credentials x509_cred; 519 | 520 | if (!(x509_cred = tls_initialize_x509_cred())) { 521 | sd->session = NULL; 522 | rfbCloseClient(cl); 523 | return; 524 | } 525 | 526 | if (gnutls_credentials_set(sd->session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) { 527 | sd->session = NULL; 528 | gnutls_certificate_free_credentials(x509_cred); 529 | rfbCloseClient(cl); 530 | return; 531 | } 532 | 533 | } else { 534 | gnutls_anon_server_credentials anon_cred; 535 | 536 | if (!(anon_cred = tls_initialize_anon_cred())) { 537 | sd->session = NULL; 538 | rfbCloseClient(cl); 539 | return; 540 | } 541 | 542 | if ((ret = gnutls_credentials_set(sd->session, GNUTLS_CRD_ANON, anon_cred)) < 0) { 543 | rfbLog("gnutls_credentials_set failed: %s\n", gnutls_strerror(ret)); 544 | gnutls_anon_free_server_credentials(anon_cred); 545 | sd->session = NULL; 546 | rfbCloseClient(cl); 547 | return; 548 | } 549 | } 550 | 551 | gnutls_transport_set_ptr(sd->session, (gnutls_transport_ptr_t)cl); 552 | gnutls_transport_set_push_function(sd->session, vnc_tls_push); 553 | gnutls_transport_set_pull_function(sd->session, vnc_tls_pull); 554 | } 555 | 556 | 557 | retry: 558 | if ((ret = gnutls_handshake(sd->session)) < 0) { 559 | if (!gnutls_error_is_fatal(ret)) { 560 | usleep(100000); 561 | goto retry; 562 | } 563 | rfbLog("rfbVncAuthVencrypt: handshake failed\n"); 564 | rfbCloseClient(cl); 565 | return; 566 | } 567 | 568 | /* set up TLS read/write hooks */ 569 | cl->clientData = sd; 570 | cl->sock_read_fn = &vnc_tls_read; 571 | cl->sock_write_fn = &vnc_tls_write; 572 | 573 | vencrypt_subauth_plain(cl); 574 | } 575 | 576 | static rfbSecurityHandler VncSecurityHandlerVencrypt = { 577 | rfbSecTypeVencrypt, 578 | rfbVncAuthVencrypt, 579 | NULL 580 | }; 581 | 582 | #define TERM "xterm" 583 | 584 | #define TERMIDCODE "[?1;2c" // vt100 ID 585 | 586 | #define CHECK_ARGC(argc,argv,i) if (i >= argc-1) { \ 587 | fprintf (stderr, "ERROR: not enough arguments for: %s\n", argv[i]); \ 588 | print_usage (NULL); \ 589 | exit(1); \ 590 | } 591 | 592 | /* these colours are from linux kernel drivers/char/vt.c */ 593 | 594 | static int idle_timeout = 1; 595 | 596 | unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, 597 | 8,12,10,14, 9,13,11,15 }; 598 | 599 | /* the default colour table, for VGA+ colour systems */ 600 | int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, 601 | 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; 602 | int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, 603 | 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; 604 | int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, 605 | 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; 606 | 607 | static void 608 | print_usage (const char *msg) 609 | { 610 | if (msg) { fprintf (stderr, "ERROR: %s\n", msg); } 611 | fprintf (stderr, "USAGE: vncterm [vncopts] [-c command [args]]\n"); 612 | } 613 | 614 | /* Convert UCS2 to UTF8 sequence, trailing zero */ 615 | static int 616 | ucs2_to_utf8 (unicode c, char *out) 617 | { 618 | if (c < 0x80) { 619 | out[0] = c; // 0******* 620 | out[1] = 0; 621 | return 1; 622 | } else if (c < 0x800) { 623 | out[0] = 0xc0 | (c >> 6); // 110***** 10****** 624 | out[1] = 0x80 | (c & 0x3f); 625 | out[2] = 0; 626 | return 2; 627 | } else { 628 | out[0] = 0xe0 | (c >> 12); // 1110**** 10****** 10****** 629 | out[1] = 0x80 | ((c >> 6) & 0x3f); 630 | out[2] = 0x80 | (c & 0x3f); 631 | out[3] = 0; 632 | return 3; 633 | } 634 | 635 | return 0; 636 | } 637 | 638 | static void 639 | rfb_draw_char (rfbScreenInfoPtr rfbScreen, int x, int y, 640 | unicode c, rfbPixel col, short width) 641 | { 642 | int i,j; 643 | unsigned char *data= fontdata + c*(GLYPHLINES*2); 644 | unsigned char d=*data; 645 | int rowstride=rfbScreen->paddedWidthInBytes; 646 | char *colour=(char*)&col; 647 | 648 | for(j = 0; j < GLYPHLINES; j++) { 649 | for(i = 0; i < 8*width; i++) { 650 | if ((i&7) == 0) { 651 | d=*data; 652 | data++; 653 | } 654 | if (d&0x80) 655 | *(rfbScreen->frameBuffer+(y+j)*rowstride+(x+i)) = *colour; 656 | d<<=1; 657 | } 658 | } 659 | } 660 | 661 | static void 662 | draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib, short width, unicode combiningglyph) 663 | { 664 | if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; } 665 | 666 | // non printable character 667 | if (width < 1) return; 668 | 669 | int rx = x*8; 670 | int ry = y*16; 671 | int rxe = x*8+8*width; 672 | int rye = y*16+16; 673 | 674 | int fg, bg; 675 | 676 | if (attrib.invers) { 677 | bg = attrib.fgcol; 678 | fg = attrib.bgcol; 679 | } else { 680 | bg = attrib.bgcol; 681 | fg = attrib.fgcol; 682 | } 683 | 684 | rfbFillRect (vt->screen, rx, ry, rxe, rye, bg); 685 | 686 | if (attrib.bold) { 687 | fg += 8; 688 | } 689 | 690 | // unsuported attributes = (attrib.blink || attrib.unvisible) 691 | 692 | rfb_draw_char (vt->screen, rx, ry, ch, fg, width); 693 | 694 | if (combiningglyph) { 695 | rfb_draw_char (vt->screen, rx, ry, combiningglyph, fg, 1); 696 | } 697 | 698 | if (attrib.uline) { 699 | rfbDrawLine (vt->screen, rx, ry + 14, rxe, ry + 14, fg); 700 | } 701 | 702 | rfbMarkRectAsModified (vt->screen, rx, ry, rxe, rye); 703 | 704 | } 705 | 706 | static void 707 | vncterm_update_xy (vncTerm *vt, int x, int y) 708 | { 709 | if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; } 710 | 711 | int y1 = (vt->y_base + y) % vt->total_height; 712 | int y2 = y1 - vt->y_displ; 713 | if (y2 < 0) { 714 | y2 += vt->total_height; 715 | } 716 | if (y2 < vt->height) { 717 | TextCell *c = &vt->cells[y1 * vt->width + x]; 718 | draw_char_at (vt, x, y2, c->ch, c->attrib, c->width, c->combiningglyph); 719 | } 720 | } 721 | 722 | static void 723 | vncterm_clear_xy (vncTerm *vt, int x, int y) 724 | { 725 | if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; } 726 | 727 | int y1 = (vt->y_base + y) % vt->total_height; 728 | int y2 = y1 - vt->y_displ; 729 | if (y2 < 0) { 730 | y2 += vt->total_height; 731 | } 732 | if (y2 < vt->height) { 733 | TextCell *c = &vt->cells[y1 * vt->width + x]; 734 | c->ch = ' '; 735 | c->attrib = vt->default_attrib; 736 | c->attrib.fgcol = vt->cur_attrib.fgcol; 737 | c->attrib.bgcol = vt->cur_attrib.bgcol; 738 | c->width = 1; 739 | c->combiningglyph = 0; 740 | 741 | draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->combiningglyph); 742 | } 743 | } 744 | 745 | static void 746 | vncterm_show_cursor (vncTerm *vt, int show) 747 | { 748 | int x = vt->cx; 749 | if (x >= vt->width) { 750 | x = vt->width - 1; 751 | } 752 | 753 | int y1 = (vt->y_base + vt->cy) % vt->total_height; 754 | int y = y1 - vt->y_displ; 755 | if (y < 0) { 756 | y += vt->total_height; 757 | } 758 | 759 | if (y < vt->height) { 760 | 761 | TextCell *c = &vt->cells[y1 * vt->width + x]; 762 | 763 | if (show) { 764 | TextAttributes attrib = vt->default_attrib; 765 | attrib.invers = !(attrib.invers); /* invert fg and bg */ 766 | draw_char_at (vt, x, y, c->ch, attrib, c->width, c->combiningglyph); 767 | } else { 768 | draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->combiningglyph); 769 | } 770 | } 771 | } 772 | 773 | static void 774 | vncterm_refresh (vncTerm *vt) 775 | { 776 | int x, y, y1; 777 | 778 | rfbFillRect (vt->screen, 0, 0, vt->maxx, vt->maxy, vt->default_attrib.bgcol); 779 | 780 | y1 = vt->y_displ; 781 | for(y = 0; y < vt->height; y++) { 782 | TextCell *c = vt->cells + y1 * vt->width; 783 | for(x = 0; x < vt->width; x++) { 784 | draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->combiningglyph); 785 | c += c->width; 786 | } 787 | if (++y1 == vt->total_height) 788 | y1 = 0; 789 | } 790 | rfbMarkRectAsModified (vt->screen, 0, 0, vt->maxx, vt->maxy); 791 | 792 | vncterm_show_cursor (vt, 1); 793 | } 794 | 795 | static void 796 | vncterm_scroll_down (vncTerm *vt, int top, int bottom, int lines) 797 | { 798 | if ((top + lines) >= bottom) { 799 | lines = bottom - top -1; 800 | } 801 | 802 | if (top < 0 || bottom > vt->height || top >= bottom || lines < 1) { 803 | return; 804 | } 805 | 806 | int h = lines * 16; 807 | int y0 = top*16; 808 | int y1 = y0 + h; 809 | int y2 = bottom*16; 810 | int rowstride = vt->screen->paddedWidthInBytes; 811 | int rows = (bottom - top - lines)*16; 812 | 813 | char *in = vt->screen->frameBuffer+y0*rowstride; 814 | char *out = vt->screen->frameBuffer+y1*rowstride; 815 | memmove(out,in, rowstride*rows); 816 | 817 | memset(vt->screen->frameBuffer+y0*rowstride, 0, h*rowstride); 818 | rfbMarkRectAsModified (vt->screen, 0, y0, vt->screen->width, y2); 819 | 820 | int i; 821 | for(i = bottom - top - lines - 1; i >= 0; i--) { 822 | int src = ((vt->y_base + top + i) % vt->total_height)*vt->width; 823 | int dst = ((vt->y_base + top + lines + i) % vt->total_height)*vt->width; 824 | 825 | memmove(vt->cells + dst, vt->cells + src, vt->width*sizeof (TextCell)); 826 | } 827 | 828 | for (i = 0; i < lines; i++) { 829 | int j; 830 | TextCell *c = vt->cells + ((vt->y_base + top + i) % vt->total_height)*vt->width; 831 | for(j = 0; j < vt->width; j++) { 832 | c->attrib = vt->default_attrib; 833 | c->ch = ' '; 834 | c->width = 1; 835 | c->combiningglyph = 0; 836 | c++; 837 | } 838 | } 839 | } 840 | 841 | static void 842 | vncterm_scroll_up (vncTerm *vt, int top, int bottom, int lines, int moveattr) 843 | { 844 | if ((top + lines) >= bottom) { 845 | lines = bottom - top - 1; 846 | } 847 | 848 | if (top < 0 || bottom > vt->height || top >= bottom || lines < 1) { 849 | return; 850 | } 851 | 852 | int h = lines * 16; 853 | int y0 = top*16; 854 | int y1 = (top + lines)*16; 855 | int y2 = bottom*16; 856 | int rowstride = vt->screen->paddedWidthInBytes; 857 | int rows = (bottom - top - lines)*16; 858 | 859 | char *in = vt->screen->frameBuffer+y1*rowstride; 860 | char *out = vt->screen->frameBuffer+y0*rowstride; 861 | memmove(out,in, rowstride*rows); 862 | 863 | memset(vt->screen->frameBuffer+(y2-h)*rowstride, 0, h*rowstride); 864 | 865 | rfbMarkRectAsModified (vt->screen, 0, y0, vt->screen->width, y2); 866 | 867 | if (!moveattr) return; 868 | 869 | // move attributes 870 | 871 | int i; 872 | for(i = 0; i < (bottom - top - lines); i++) { 873 | int dst = ((vt->y_base + top + i) % vt->total_height)*vt->width; 874 | int src = ((vt->y_base + top + lines + i) % vt->total_height)*vt->width; 875 | 876 | memmove(vt->cells + dst, vt->cells + src, vt->width*sizeof (TextCell)); 877 | } 878 | 879 | for (i = 1; i <= lines; i++) { 880 | int j; 881 | TextCell *c = vt->cells + ((vt->y_base + bottom - i) % vt->total_height)*vt->width; 882 | for(j = 0; j < vt->width; j++) { 883 | c->attrib = vt->default_attrib; 884 | c->ch = ' '; 885 | c->width = 1; 886 | c->combiningglyph = 0; 887 | c++; 888 | } 889 | } 890 | } 891 | 892 | static void 893 | vncterm_virtual_scroll (vncTerm *vt, int lines) 894 | { 895 | if (vt->altbuf || lines == 0) return; 896 | 897 | if (lines < 0) { 898 | lines = -lines; 899 | int i = vt->scroll_height; 900 | if (i > vt->total_height - vt->height) 901 | i = vt->total_height - vt->height; 902 | int y1 = vt->y_base - i; 903 | if (y1 < 0) 904 | y1 += vt->total_height; 905 | for(i = 0; i < lines; i++) { 906 | if (vt->y_displ == y1) break; 907 | if (--vt->y_displ < 0) { 908 | vt->y_displ = vt->total_height - 1; 909 | } 910 | } 911 | } else { 912 | int i; 913 | for(i = 0; i < lines; i++) { 914 | if (vt->y_displ == vt->y_base) break; 915 | if (++vt->y_displ == vt->total_height) { 916 | vt->y_displ = 0; 917 | } 918 | } 919 | 920 | } 921 | 922 | vncterm_refresh (vt); 923 | } 924 | static void 925 | vncterm_respond_esc (vncTerm *vt, const char *esc) 926 | { 927 | int len = strlen (esc); 928 | int i; 929 | 930 | if (vt->ibuf_count < (IBUFSIZE - 1 - len)) { 931 | vt->ibuf[vt->ibuf_count++] = 27; 932 | for (i = 0; i < len; i++) { 933 | vt->ibuf[vt->ibuf_count++] = esc[i]; 934 | } 935 | } 936 | } 937 | 938 | static void 939 | vncterm_put_lf (vncTerm *vt) 940 | { 941 | if (vt->cy + 1 == vt->region_bottom) { 942 | 943 | if (vt->altbuf || vt->region_top != 0 || vt->region_bottom != vt->height) { 944 | vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, 1, 1); 945 | return; 946 | } 947 | 948 | if (vt->y_displ == vt->y_base) { 949 | vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, 1, 0); 950 | } 951 | 952 | if (vt->y_displ == vt->y_base) { 953 | if (++vt->y_displ == vt->total_height) { 954 | vt->y_displ = 0; 955 | } 956 | } 957 | 958 | if (++vt->y_base == vt->total_height) { 959 | vt->y_base = 0; 960 | } 961 | 962 | if (vt->scroll_height < vt->total_height) { 963 | vt->scroll_height++; 964 | } 965 | 966 | int y1 = (vt->y_base + vt->height - 1) % vt->total_height; 967 | TextCell *c = &vt->cells[y1 * vt->width]; 968 | int x; 969 | for (x = 0; x < vt->width; x++) { 970 | c->ch = ' '; 971 | c->width = 1; 972 | c->combiningglyph = 0; 973 | c->attrib = vt->default_attrib; 974 | c++; 975 | } 976 | 977 | // fprintf (stderr, "BASE: %d DISPLAY %d\n", vt->y_base, vt->y_displ); 978 | 979 | } else if (vt->cy < vt->height - 1) { 980 | vt->cy += 1; 981 | } 982 | } 983 | 984 | 985 | static void 986 | vncterm_csi_m (vncTerm *vt) 987 | { 988 | int i; 989 | 990 | for (i = 0; i < vt->esc_count; i++) { 991 | switch (vt->esc_buf[i]) { 992 | case 0: /* reset all console attributes to default */ 993 | vt->cur_attrib = vt->default_attrib; 994 | break; 995 | case 1: 996 | vt->cur_attrib.bold = 1; 997 | break; 998 | case 4: 999 | vt->cur_attrib.uline = 1; 1000 | break; 1001 | case 5: 1002 | vt->cur_attrib.blink = 1; 1003 | break; 1004 | case 7: 1005 | vt->cur_attrib.invers = 1; 1006 | break; 1007 | case 8: 1008 | vt->cur_attrib.unvisible = 1; 1009 | break; 1010 | case 10: 1011 | vt->cur_enc = LAT1_MAP; 1012 | // fixme: dispaly controls = 0 ? 1013 | // fixme: toggle meta = 0 ? 1014 | break; 1015 | case 11: 1016 | vt->cur_enc = IBMPC_MAP; 1017 | // fixme: dispaly controls = 1 ? 1018 | // fixme: toggle meta = 0 ? 1019 | break; 1020 | case 12: 1021 | vt->cur_enc = IBMPC_MAP; 1022 | // fixme: dispaly controls = 1 ? 1023 | // fixme: toggle meta = 1 ? 1024 | break; 1025 | case 22: 1026 | vt->cur_attrib.bold = 0; 1027 | break; 1028 | case 24: 1029 | vt->cur_attrib.uline = 0; 1030 | break; 1031 | case 25: 1032 | vt->cur_attrib.blink = 0; 1033 | break; 1034 | case 27: 1035 | vt->cur_attrib.invers = 0; 1036 | break; 1037 | case 28: 1038 | vt->cur_attrib.unvisible = 0; 1039 | break; 1040 | case 30: 1041 | case 31: 1042 | case 32: 1043 | case 33: 1044 | case 34: 1045 | case 35: 1046 | case 36: 1047 | case 37: 1048 | /* set foreground color */ 1049 | vt->cur_attrib.fgcol = color_table [vt->esc_buf[i] - 30]; 1050 | break; 1051 | case 38: 1052 | /* reset color to default, enable underline */ 1053 | vt->cur_attrib.fgcol = vt->default_attrib.fgcol; 1054 | vt->cur_attrib.uline = 1; 1055 | break; 1056 | case 39: 1057 | /* reset color to default, disable underline */ 1058 | vt->cur_attrib.fgcol = vt->default_attrib.fgcol; 1059 | vt->cur_attrib.uline = 0; 1060 | break; 1061 | case 40: 1062 | case 41: 1063 | case 42: 1064 | case 43: 1065 | case 44: 1066 | case 45: 1067 | case 46: 1068 | case 47: 1069 | /* set background color */ 1070 | vt->cur_attrib.bgcol = color_table [vt->esc_buf[i] - 40]; 1071 | break; 1072 | case 49: 1073 | /* reset background color */ 1074 | vt->cur_attrib.bgcol = vt->default_attrib.bgcol; 1075 | break; 1076 | default: 1077 | fprintf (stderr, "unhandled ESC[%d m code\n",vt->esc_buf[i]); 1078 | //fixme: implement 1079 | } 1080 | } 1081 | } 1082 | 1083 | static void 1084 | vncterm_save_cursor (vncTerm *vt) 1085 | { 1086 | vt->cx_saved = vt->cx; 1087 | vt->cy_saved = vt->cy; 1088 | vt->cur_attrib_saved = vt->cur_attrib; 1089 | vt->charset_saved = vt->charset; 1090 | vt->g0enc_saved = vt->g0enc; 1091 | vt->g1enc_saved = vt->g1enc; 1092 | vt->cur_enc_saved = vt->cur_enc; 1093 | } 1094 | 1095 | static void 1096 | vncterm_restore_cursor (vncTerm *vt) 1097 | { 1098 | vt->cx = vt->cx_saved; 1099 | vt->cy = vt->cy_saved; 1100 | vt->cur_attrib = vt->cur_attrib_saved; 1101 | vt->charset = vt->charset_saved; 1102 | vt->g0enc = vt->g0enc_saved; 1103 | vt->g1enc = vt->g1enc_saved; 1104 | vt->cur_enc = vt->cur_enc_saved; 1105 | } 1106 | 1107 | static void 1108 | vncterm_set_alternate_buffer (vncTerm *vt, int on_off) 1109 | { 1110 | int x, y; 1111 | 1112 | vt->y_displ = vt->y_base; 1113 | 1114 | if (on_off) { 1115 | 1116 | if (vt->altbuf) return; 1117 | 1118 | vt->altbuf = 1; 1119 | 1120 | /* alternate buffer & cursor */ 1121 | 1122 | vncterm_save_cursor (vt); 1123 | /* save screen to altcels */ 1124 | for (y = 0; y < vt->height; y++) { 1125 | int y1 = (vt->y_base + y) % vt->total_height; 1126 | for (x = 0; x < vt->width; x++) { 1127 | vt->altcells[y*vt->width + x] = vt->cells[y1*vt->width + x]; 1128 | } 1129 | } 1130 | 1131 | /* clear screen */ 1132 | for (y = 0; y <= vt->height; y++) { 1133 | for (x = 0; x < vt->width; x++) { 1134 | vncterm_clear_xy (vt, x, y); 1135 | } 1136 | } 1137 | 1138 | } else { 1139 | 1140 | if (vt->altbuf == 0) return; 1141 | 1142 | vt->altbuf = 0; 1143 | 1144 | /* restore saved data */ 1145 | for (y = 0; y < vt->height; y++) { 1146 | int y1 = (vt->y_base + y) % vt->total_height; 1147 | for (x = 0; x < vt->width; x++) { 1148 | vt->cells[y1*vt->width + x] = vt->altcells[y*vt->width + x]; 1149 | } 1150 | } 1151 | 1152 | vncterm_restore_cursor (vt); 1153 | } 1154 | 1155 | vncterm_refresh (vt); 1156 | } 1157 | 1158 | static void 1159 | vncterm_set_mode (vncTerm *vt, int on_off) 1160 | { 1161 | int i; 1162 | 1163 | for (i = 0; i <= vt->esc_count; i++) { 1164 | if (vt->esc_ques) { /* DEC private modes set/reset */ 1165 | switch(vt->esc_buf[i]) { 1166 | case 10: /* X11 mouse reporting on/off */ 1167 | case 1000: 1168 | vt->report_mouse = on_off; 1169 | break; 1170 | case 1049: /* start/end special app mode (smcup/rmcup) */ 1171 | vncterm_set_alternate_buffer (vt, on_off); 1172 | break; 1173 | case 25: /* Cursor on/off */ 1174 | case 9: /* X10 mouse reporting on/off */ 1175 | case 6: /* Origin relative/absolute */ 1176 | case 1: /* Cursor keys in appl mode*/ 1177 | case 5: /* Inverted screen on/off */ 1178 | case 7: /* Autowrap on/off */ 1179 | case 8: /* Autorepeat on/off */ 1180 | break; 1181 | } 1182 | } else { /* ANSI modes set/reset */ 1183 | /* fixme: implement me */ 1184 | } 1185 | } 1186 | } 1187 | 1188 | static void 1189 | vncterm_gotoxy (vncTerm *vt, int x, int y) 1190 | { 1191 | /* verify all boundaries */ 1192 | 1193 | if (x < 0) { 1194 | x = 0; 1195 | } else if (x >= vt->width) { 1196 | x = vt->width - 1; 1197 | } 1198 | 1199 | vt->cx = x; 1200 | 1201 | if (y < 0) { 1202 | y = 0; 1203 | } else if (y >= vt->height) { 1204 | y = vt->height - 1; 1205 | } 1206 | 1207 | vt->cy = y; 1208 | } 1209 | 1210 | enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, 1211 | EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, 1212 | ESpalette, ESidquery, ESosc1, ESosc2}; 1213 | 1214 | static void 1215 | vncterm_putchar (vncTerm *vt, unicode ch) 1216 | { 1217 | int x, y, i, c; 1218 | 1219 | #ifdef DEBUG 1220 | if (!vt->tty_state) 1221 | fprintf (stderr, "CHAR:%2d: %4x '%c' (cur_enc %d) %d %d\n", vt->tty_state, ch, ch, vt->cur_enc, vt->cx, vt->cy); 1222 | #endif 1223 | 1224 | switch(vt->tty_state) { 1225 | case ESesc: 1226 | vt->tty_state = ESnormal; 1227 | switch (ch) { 1228 | case '[': 1229 | vt->tty_state = ESsquare; 1230 | break; 1231 | case ']': 1232 | vt->tty_state = ESnonstd; 1233 | break; 1234 | case '%': 1235 | vt->tty_state = ESpercent; 1236 | break; 1237 | case '7': 1238 | vncterm_save_cursor (vt); 1239 | break; 1240 | case '8': 1241 | vncterm_restore_cursor (vt); 1242 | break; 1243 | case '(': 1244 | vt->tty_state = ESsetG0; // SET G0 1245 | break; 1246 | case ')': 1247 | vt->tty_state = ESsetG1; // SET G1 1248 | break; 1249 | case 'M': 1250 | /* cursor up (ri) */ 1251 | if (vt->cy == vt->region_top) 1252 | vncterm_scroll_down (vt, vt->region_top, vt->region_bottom, 1); 1253 | else if (vt->cy > 0) { 1254 | vt->cy--; 1255 | } 1256 | break; 1257 | case '>': 1258 | /* numeric keypad - ignored */ 1259 | break; 1260 | case '=': 1261 | /* appl. keypad - ignored */ 1262 | break; 1263 | default: 1264 | #ifdef DEBUG 1265 | fprintf(stderr, "got unhandled ESC%c %d\n", ch, ch); 1266 | #endif 1267 | break; 1268 | } 1269 | break; 1270 | case ESnonstd: /* Operating System Controls */ 1271 | vt->tty_state = ESnormal; 1272 | 1273 | switch (ch) { 1274 | case 'P': /* palette escape sequence */ 1275 | for(i = 0; i < MAX_ESC_PARAMS; i++) { 1276 | vt->esc_buf[i] = 0; 1277 | } 1278 | 1279 | vt->esc_count = 0; 1280 | vt->tty_state = ESpalette; 1281 | break; 1282 | case 'R': /* reset palette */ 1283 | // fixme: reset_palette(vc); 1284 | break; 1285 | case '0': 1286 | case '1': 1287 | case '2': 1288 | case '4': 1289 | vt->osc_cmd = ch; 1290 | vt->osc_textbuf[0] = 0; 1291 | vt->tty_state = ESosc1; 1292 | break; 1293 | default: 1294 | #ifdef DEBUG 1295 | fprintf (stderr, "unhandled OSC %c\n", ch); 1296 | #endif 1297 | vt->tty_state = ESnormal; 1298 | break; 1299 | } 1300 | break; 1301 | case ESosc1: 1302 | vt->tty_state = ESnormal; 1303 | if (ch == ';') { 1304 | vt->tty_state = ESosc2; 1305 | } else { 1306 | #ifdef DEBUG 1307 | fprintf (stderr, "got illegal OSC sequence\n"); 1308 | #endif 1309 | } 1310 | break; 1311 | case ESosc2: 1312 | if (ch != 0x9c && ch != 7) { 1313 | int i = 0; 1314 | while (vt->osc_textbuf[i]) i++; 1315 | vt->osc_textbuf[i++] = ch; 1316 | vt->osc_textbuf[i] = 0; 1317 | } else { 1318 | #ifdef DEBUG 1319 | fprintf (stderr, "OSC:%c:%s\n", vt->osc_cmd, vt->osc_textbuf); 1320 | #endif 1321 | vt->tty_state = ESnormal; 1322 | } 1323 | break; 1324 | case ESpalette: 1325 | if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') 1326 | || (ch >= 'a' && ch <= 'f')) { 1327 | vt->esc_buf[vt->esc_count++] = (ch > '9' ? (ch & 0xDF) - 'A' + 10 : ch - '0'); 1328 | if (vt->esc_count == 7) { 1329 | // fixme: this does not work - please test 1330 | rfbColourMap *cmap =&vt->screen->colourMap; 1331 | 1332 | int i = color_table[vt->esc_buf[0]] * 3, j = 1; 1333 | cmap->data.bytes[i] = 16 * vt->esc_buf[j++]; 1334 | cmap->data.bytes[i++] += vt->esc_buf[j++]; 1335 | cmap->data.bytes[i] = 16 * vt->esc_buf[j++]; 1336 | cmap->data.bytes[i++] += vt->esc_buf[j++]; 1337 | cmap->data.bytes[i] = 16 * vt->esc_buf[j++]; 1338 | cmap->data.bytes[i] += vt->esc_buf[j]; 1339 | 1340 | //set_palette(vc); ? 1341 | 1342 | vt->tty_state = ESnormal; 1343 | } 1344 | } else 1345 | vt->tty_state = ESnormal; 1346 | break; 1347 | case ESsquare: 1348 | for(i = 0; i < MAX_ESC_PARAMS; i++) { 1349 | vt->esc_buf[i] = 0; 1350 | } 1351 | 1352 | vt->esc_count = 0; 1353 | vt->esc_has_par = 0; 1354 | vt->tty_state = ESgetpars; 1355 | 1356 | if (ch == '>') { 1357 | vt->tty_state = ESidquery; 1358 | break; 1359 | } 1360 | 1361 | if ((vt->esc_ques = (ch == '?'))) { 1362 | break; 1363 | } 1364 | case ESgetpars: 1365 | if (ch >= '0' && ch <= '9') { 1366 | vt->esc_has_par = 1; 1367 | if (vt->esc_count < MAX_ESC_PARAMS) { 1368 | vt->esc_buf[vt->esc_count] = vt->esc_buf[vt->esc_count] * 10 + ch - '0'; 1369 | } 1370 | break; 1371 | } else if (ch == ';') { 1372 | vt->esc_has_par = 1; 1373 | vt->esc_count++; 1374 | break; 1375 | } else { 1376 | if (vt->esc_has_par) { 1377 | vt->esc_count++; 1378 | } 1379 | vt->tty_state = ESgotpars; 1380 | } 1381 | case ESgotpars: 1382 | 1383 | vt->tty_state = ESnormal; 1384 | 1385 | #ifdef DEBUG 1386 | char *qes = vt->esc_ques ? "?" : ""; 1387 | if (vt->esc_count == 0) { 1388 | fprintf(stderr, "ESC[%s%c\n", qes, ch); 1389 | } else if (vt->esc_count == 1) { 1390 | fprintf(stderr, "ESC[%s%d%c\n", qes, vt->esc_buf[0], ch); 1391 | } else { 1392 | int i; 1393 | fprintf(stderr, "ESC[%s%d", qes, vt->esc_buf[0]); 1394 | for (i = 1; i < vt->esc_count; i++) { 1395 | fprintf(stderr, ";%d", vt->esc_buf[i]); 1396 | } 1397 | fprintf (stderr, "%c\n", ch); 1398 | } 1399 | #endif 1400 | 1401 | switch (ch) { 1402 | case 'h': 1403 | vncterm_set_mode (vt, 1); 1404 | break; 1405 | case 'l': 1406 | vncterm_set_mode (vt, 0); 1407 | break; 1408 | case 'm': 1409 | if (!vt->esc_count) { 1410 | vt->esc_count++; // default parameter 0 1411 | } 1412 | vncterm_csi_m (vt); 1413 | break; 1414 | case 'n': 1415 | /* report cursor position */ 1416 | /* TODO: send ESC[row;colR */ 1417 | break; 1418 | case 'A': 1419 | /* move cursor up */ 1420 | if (vt->esc_buf[0] == 0) { 1421 | vt->esc_buf[0] = 1; 1422 | } 1423 | vncterm_gotoxy (vt, vt->cx, vt->cy - vt->esc_buf[0]); 1424 | break; 1425 | case 'B': 1426 | case 'e': 1427 | /* move cursor down */ 1428 | if (vt->esc_buf[0] == 0) { 1429 | vt->esc_buf[0] = 1; 1430 | } 1431 | vncterm_gotoxy (vt, vt->cx, vt->cy + vt->esc_buf[0]); 1432 | break; 1433 | case 'C': 1434 | case 'a': 1435 | /* move cursor right */ 1436 | if (vt->esc_buf[0] == 0) { 1437 | vt->esc_buf[0] = 1; 1438 | } 1439 | vncterm_gotoxy (vt, vt->cx + vt->esc_buf[0], vt->cy); 1440 | break; 1441 | case 'D': 1442 | /* move cursor left */ 1443 | if (vt->esc_buf[0] == 0) { 1444 | vt->esc_buf[0] = 1; 1445 | } 1446 | vncterm_gotoxy (vt, vt->cx - vt->esc_buf[0], vt->cy); 1447 | break; 1448 | case 'G': 1449 | case '`': 1450 | /* move cursor to column */ 1451 | vncterm_gotoxy (vt, vt->esc_buf[0] - 1, vt->cy); 1452 | break; 1453 | case 'd': 1454 | /* move cursor to row */ 1455 | vncterm_gotoxy (vt, vt->cx , vt->esc_buf[0] - 1); 1456 | break; 1457 | case 'f': 1458 | case 'H': 1459 | /* move cursor to row, column */ 1460 | vncterm_gotoxy (vt, vt->esc_buf[1] - 1, vt->esc_buf[0] - 1); 1461 | break; 1462 | case 'J': 1463 | switch (vt->esc_buf[0]) { 1464 | case 0: 1465 | /* clear to end of screen */ 1466 | for (y = vt->cy; y < vt->height; y++) { 1467 | for (x = 0; x < vt->width; x++) { 1468 | if (y == vt->cy && x < vt->cx) { 1469 | continue; 1470 | } 1471 | vncterm_clear_xy (vt, x, y); 1472 | } 1473 | } 1474 | break; 1475 | case 1: 1476 | /* clear from beginning of screen */ 1477 | for (y = 0; y <= vt->cy; y++) { 1478 | for (x = 0; x < vt->width; x++) { 1479 | if (y == vt->cy && x > vt->cx) { 1480 | break; 1481 | } 1482 | vncterm_clear_xy (vt, x, y); 1483 | } 1484 | } 1485 | break; 1486 | case 2: 1487 | /* clear entire screen */ 1488 | for (y = 0; y <= vt->height; y++) { 1489 | for (x = 0; x < vt->width; x++) { 1490 | vncterm_clear_xy (vt, x, y); 1491 | } 1492 | } 1493 | break; 1494 | } 1495 | break; 1496 | case 'K': 1497 | switch (vt->esc_buf[0]) { 1498 | case 0: 1499 | /* clear to eol */ 1500 | for(x = vt->cx; x < vt->width; x++) { 1501 | vncterm_clear_xy (vt, x, vt->cy); 1502 | } 1503 | break; 1504 | case 1: 1505 | /* clear from beginning of line */ 1506 | for (x = 0; x <= vt->cx; x++) { 1507 | vncterm_clear_xy (vt, x, vt->cy); 1508 | } 1509 | break; 1510 | case 2: 1511 | /* clear entire line */ 1512 | for(x = 0; x < vt->width; x++) { 1513 | vncterm_clear_xy (vt, x, vt->cy); 1514 | } 1515 | break; 1516 | } 1517 | break; 1518 | case 'L': 1519 | /* insert line */ 1520 | c = vt->esc_buf[0]; 1521 | 1522 | if (c > vt->height - vt->cy) 1523 | c = vt->height - vt->cy; 1524 | else if (!c) 1525 | c = 1; 1526 | 1527 | vncterm_scroll_down (vt, vt->cy, vt->region_bottom, c); 1528 | break; 1529 | case 'M': 1530 | /* delete line */ 1531 | c = vt->esc_buf[0]; 1532 | 1533 | if (c > vt->height - vt->cy) 1534 | c = vt->height - vt->cy; 1535 | else if (!c) 1536 | c = 1; 1537 | 1538 | vncterm_scroll_up (vt, vt->cy, vt->region_bottom, c, 1); 1539 | break; 1540 | case 'T': 1541 | /* scroll down */ 1542 | c = vt->esc_buf[0]; 1543 | if (!c) c = 1; 1544 | vncterm_scroll_down (vt, vt->region_top, vt->region_bottom, c); 1545 | break; 1546 | case 'S': 1547 | /* scroll up */ 1548 | c = vt->esc_buf[0]; 1549 | if (!c) c = 1; 1550 | vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, c, 1); 1551 | break; 1552 | case 'P': 1553 | /* delete c character */ 1554 | c = vt->esc_buf[0]; 1555 | 1556 | if (c > vt->width - vt->cx) 1557 | c = vt->width - vt->cx; 1558 | else if (!c) 1559 | c = 1; 1560 | 1561 | for (x = vt->cx; x < vt->width - c; x++) { 1562 | int y1 = (vt->y_base + vt->cy) % vt->total_height; 1563 | TextCell *dst = &vt->cells[y1 * vt->width + x]; 1564 | TextCell *src = dst + c; 1565 | *dst = *src; 1566 | vncterm_update_xy (vt, x + c, vt->cy); 1567 | src->ch = ' '; 1568 | src->width = 1; 1569 | src->combiningglyph = 0; 1570 | src->attrib = vt->default_attrib; 1571 | vncterm_update_xy (vt, x, vt->cy); 1572 | } 1573 | break; 1574 | case 's': 1575 | /* save cursor position */ 1576 | vncterm_save_cursor (vt); 1577 | break; 1578 | case 'u': 1579 | /* restore cursor position */ 1580 | vncterm_restore_cursor (vt); 1581 | break; 1582 | case 'X': 1583 | /* erase c characters */ 1584 | c = vt->esc_buf[0]; 1585 | if (!c) c = 1; 1586 | 1587 | if (c > (vt->width - vt->cx)) c = vt->width - vt->cx; 1588 | 1589 | for(i = 0; i < c; i++) { 1590 | vncterm_clear_xy (vt, vt->cx + i, vt->cy); 1591 | } 1592 | break; 1593 | case '@': 1594 | /* insert c character */ 1595 | c = vt->esc_buf[0]; 1596 | if (c > (vt->width - vt->cx)) { 1597 | c = vt->width - vt->cx; 1598 | } 1599 | if (!c) c = 1; 1600 | 1601 | for (x = vt->width - c; x >= vt->cx; x--) { 1602 | int y1 = (vt->y_base + vt->cy) % vt->total_height; 1603 | TextCell *src = &vt->cells[y1 * vt->width + x]; 1604 | TextCell *dst = src + c; 1605 | *dst = *src; 1606 | vncterm_update_xy (vt, x + c, vt->cy); 1607 | src->ch = ' '; 1608 | src->width = 1; 1609 | src->combiningglyph = 0; 1610 | src->attrib = vt->cur_attrib; 1611 | vncterm_update_xy (vt, x, vt->cy); 1612 | } 1613 | 1614 | break; 1615 | case 'r': 1616 | /* set region */ 1617 | if (!vt->esc_buf[0]) 1618 | vt->esc_buf[0]++; 1619 | if (!vt->esc_buf[1]) 1620 | vt->esc_buf[1] = vt->height; 1621 | /* Minimum allowed region is 2 lines */ 1622 | if (vt->esc_buf[0] < vt->esc_buf[1] && 1623 | vt->esc_buf[1] <= vt->height) { 1624 | vt->region_top = vt->esc_buf[0] - 1; 1625 | vt->region_bottom = vt->esc_buf[1]; 1626 | vt->cx = 0; 1627 | vt->cy = vt->region_top; 1628 | #ifdef DEBUG 1629 | fprintf (stderr, "set region %d %d\n", vt->region_top, vt->region_bottom); 1630 | #endif 1631 | } 1632 | 1633 | break; 1634 | default: 1635 | #ifdef DEBUG 1636 | if (vt->esc_count == 0) { 1637 | fprintf(stderr, "unhandled escape ESC[%s%c\n", qes, ch); 1638 | } else if (vt->esc_count == 1) { 1639 | fprintf(stderr, "unhandled escape ESC[%s%d%c\n", qes, vt->esc_buf[0], ch); 1640 | } else { 1641 | int i; 1642 | fprintf(stderr, "unhandled escape ESC[%s%d", qes, vt->esc_buf[0]); 1643 | for (i = 1; i < vt->esc_count; i++) { 1644 | fprintf(stderr, ";%d", vt->esc_buf[i]); 1645 | } 1646 | fprintf (stderr, "%c\n", ch); 1647 | } 1648 | #endif 1649 | break; 1650 | } 1651 | vt->esc_ques = 0; 1652 | break; 1653 | case ESsetG0: // Set G0 1654 | vt->tty_state = ESnormal; 1655 | 1656 | if (ch == '0') 1657 | vt->g0enc = GRAF_MAP; 1658 | else if (ch == 'B') 1659 | vt->g0enc = LAT1_MAP; 1660 | else if (ch == 'U') 1661 | vt->g0enc = IBMPC_MAP; 1662 | else if (ch == 'K') 1663 | vt->g0enc = USER_MAP; 1664 | 1665 | if (vt->charset == 0) 1666 | vt->cur_enc = vt->g0enc; 1667 | 1668 | break; 1669 | case ESsetG1: // Set G1 1670 | vt->tty_state = ESnormal; 1671 | 1672 | if (ch == '0') 1673 | vt->g1enc = GRAF_MAP; 1674 | else if (ch == 'B') 1675 | vt->g1enc = LAT1_MAP; 1676 | else if (ch == 'U') 1677 | vt->g1enc = IBMPC_MAP; 1678 | else if (ch == 'K') 1679 | vt->g1enc = USER_MAP; 1680 | 1681 | if (vt->charset == 1) 1682 | vt->cur_enc = vt->g1enc; 1683 | 1684 | break; 1685 | case ESidquery: // vt100 query id 1686 | vt->tty_state = ESnormal; 1687 | 1688 | if (ch == 'c') { 1689 | #ifdef DEBUG 1690 | fprintf (stderr, "ESC[>c Query term ID\n"); 1691 | #endif 1692 | vncterm_respond_esc (vt, TERMIDCODE); 1693 | } 1694 | break; 1695 | case ESpercent: 1696 | vt->tty_state = ESnormal; 1697 | switch (ch) { 1698 | case '@': /* defined in ISO 2022 */ 1699 | vt->utf8 = 0; 1700 | break; 1701 | case 'G': /* prelim official escape code */ 1702 | case '8': /* retained for compatibility */ 1703 | vt->utf8 = 1; 1704 | break; 1705 | } 1706 | break; 1707 | default: // ESnormal 1708 | vt->tty_state = ESnormal; 1709 | 1710 | switch(ch) { 1711 | case 0: 1712 | break; 1713 | case 7: /* alert aka. bell */ 1714 | rfbSendBell(vt->screen); 1715 | break; 1716 | case 8: /* backspace */ 1717 | if (vt->cx > 0) 1718 | vt->cx--; 1719 | break; 1720 | case 9: /* tabspace */ 1721 | if (vt->cx + (8 - (vt->cx % 8)) > vt->width) { 1722 | vt->cx = 0; 1723 | vncterm_put_lf (vt); 1724 | } else { 1725 | vt->cx = vt->cx + (8 - (vt->cx % 8)); 1726 | } 1727 | break; 1728 | case 10: /* LF,*/ 1729 | case 11: /* VT */ 1730 | case 12: /* FF */ 1731 | vncterm_put_lf (vt); 1732 | break; 1733 | case 13: /* carriage return */ 1734 | vt->cx = 0; 1735 | break; 1736 | case 14: 1737 | /* SI (shift in), select character set 1 */ 1738 | vt->charset = 1; 1739 | vt->cur_enc = vt->g1enc; 1740 | /* fixme: display controls = 1 */ 1741 | break; 1742 | case 15: 1743 | /* SO (shift out), select character set 0 */ 1744 | vt->charset = 0; 1745 | vt->cur_enc = vt->g0enc; 1746 | /* fixme: display controls = 0 */ 1747 | break; 1748 | case 27: /* esc */ 1749 | vt->tty_state = ESesc; 1750 | break; 1751 | case 127: /* delete */ 1752 | /* ignore */ 1753 | break; 1754 | case 128+27: /* csi */ 1755 | vt->tty_state = ESsquare; 1756 | break; 1757 | default: 1758 | if (vt->cx >= vt->width) { 1759 | /* line wrap */ 1760 | vt->cx = 0; 1761 | vncterm_put_lf (vt); 1762 | } 1763 | 1764 | int y1 = (vt->y_base + vt->cy) % vt->total_height; 1765 | int width = wcwidth(ch); 1766 | if (width > 0) { 1767 | // normal/wide character 1768 | TextCell *c = &vt->cells[y1*vt->width + vt->cx]; 1769 | c->attrib = vt->cur_attrib; 1770 | c->ch = ch; 1771 | c->width = width; 1772 | c->combiningglyph = 0; 1773 | vncterm_update_xy (vt, vt->cx, vt->cy); 1774 | vt->cx += width; 1775 | } else if (width == 0) { 1776 | // combiningglyph 1777 | TextCell *c = &vt->cells[y1*vt->width + vt->cx - 1]; 1778 | c->attrib = vt->cur_attrib; 1779 | c->combiningglyph = ch; 1780 | vncterm_update_xy (vt, vt->cx - 1, vt->cy); 1781 | } else { 1782 | // non printable character, so we do not save them 1783 | } 1784 | break; 1785 | } 1786 | break; 1787 | } 1788 | } 1789 | 1790 | static int 1791 | vncterm_puts (vncTerm *vt, const char *buf, int len) 1792 | { 1793 | unicode tc; 1794 | 1795 | vncterm_show_cursor (vt, 0); 1796 | 1797 | while (len) { 1798 | unsigned char c = *buf; 1799 | len--; 1800 | buf++; 1801 | 1802 | if (vt->tty_state != ESnormal) { 1803 | // never translate escape sequence 1804 | tc = c; 1805 | } else if (vt->utf8 && !vt->cur_enc) { 1806 | 1807 | if(c & 0x80) { // utf8 multi-byte sequence 1808 | 1809 | if (vt->utf_count > 0 && (c & 0xc0) == 0x80) { 1810 | // inside UTF8 sequence 1811 | vt->utf_char = (vt->utf_char << 6) | (c & 0x3f); 1812 | vt->utf_count--; 1813 | if (vt->utf_count == 0) { 1814 | if (vt->utf_char <= USHRT_MAX) { 1815 | tc = vt->utf_char; 1816 | } else { 1817 | tc = 0; 1818 | } 1819 | } else { 1820 | continue; 1821 | } 1822 | } else { 1823 | // first char of a UTF8 sequence 1824 | if ((c & 0xe0) == 0xc0) { 1825 | vt->utf_count = 1; 1826 | vt->utf_char = (c & 0x1f); 1827 | } else if ((c & 0xf0) == 0xe0) { 1828 | vt->utf_count = 2; 1829 | vt->utf_char = (c & 0x0f); 1830 | } else if ((c & 0xf8) == 0xf0) { 1831 | vt->utf_count = 3; 1832 | vt->utf_char = (c & 0x07); 1833 | } else if ((c & 0xfc) == 0xf8) { 1834 | vt->utf_count = 4; 1835 | vt->utf_char = (c & 0x03); 1836 | } else if ((c & 0xfe) == 0xfc) { 1837 | vt->utf_count = 5; 1838 | vt->utf_char = (c & 0x01); 1839 | } else 1840 | vt->utf_count = 0; 1841 | 1842 | continue; 1843 | } 1844 | } else { 1845 | // utf8 single byte 1846 | tc = c; 1847 | vt->utf_count = 0; 1848 | } 1849 | 1850 | } else { 1851 | // never translate controls 1852 | if (c >= 32 && c != 127 && c != (128+27)) { 1853 | tc = translations[vt->cur_enc][c & 0x0ff]; 1854 | } else { 1855 | tc = c; 1856 | } 1857 | } 1858 | 1859 | vncterm_putchar (vt, tc); 1860 | } 1861 | 1862 | vncterm_show_cursor (vt, 1); 1863 | return len; 1864 | } 1865 | 1866 | void 1867 | vncterm_kbd_event (rfbBool down, rfbKeySym keySym, rfbClientPtr cl) 1868 | { 1869 | vncTerm *vt =(vncTerm *)cl->screen->screenData; 1870 | static int control = 0; 1871 | static int shift = 0; 1872 | char *esc = NULL; 1873 | 1874 | //fprintf (stderr, "KEYEVENT:%d: %08x\n", down == 0, keySym);fflush (stderr); 1875 | if (down) { 1876 | //fprintf (stderr, "KEYPRESS: %d\n", keySym);fflush (stderr); 1877 | 1878 | if (keySym == XK_Shift_L || keySym == XK_Shift_R) { 1879 | shift = 1; 1880 | } if (keySym == XK_Control_L || keySym == XK_Control_R) { 1881 | control = 1; 1882 | } else if (vt->ibuf_count < (IBUFSIZE - 32)) { 1883 | 1884 | if (control) { 1885 | if(keySym >= 'a' && keySym <= 'z') 1886 | keySym -= 'a' -1; 1887 | else if (keySym >= 'A' && keySym <= 'Z') 1888 | keySym -= 'A'-1; 1889 | else 1890 | keySym=0xffff; 1891 | } else { 1892 | switch (keySym) { 1893 | case XK_Escape: 1894 | keySym=27; break; 1895 | case XK_Return: 1896 | keySym='\r'; break; 1897 | case XK_BackSpace: 1898 | keySym=8; break; 1899 | case XK_Tab: 1900 | keySym='\t'; break; 1901 | case XK_Delete: /* kdch1 */ 1902 | case XK_KP_Delete: 1903 | esc = "[3~";break; 1904 | case XK_Home: /* khome */ 1905 | case XK_KP_Home: 1906 | esc = "OH";break; 1907 | case XK_End: 1908 | case XK_KP_End: /* kend */ 1909 | esc = "OF";break; 1910 | case XK_Insert: /* kich1 */ 1911 | case XK_KP_Insert: 1912 | esc = "[2~";break; 1913 | case XK_Up: 1914 | case XK_KP_Up: /* kcuu1 */ 1915 | esc = "OA";break; 1916 | case XK_Down: /* kcud1 */ 1917 | case XK_KP_Down: 1918 | esc = "OB";break; 1919 | case XK_Right: 1920 | case XK_KP_Right: /* kcuf1 */ 1921 | esc = "OC";break; 1922 | case XK_Left: 1923 | case XK_KP_Left: /* kcub1 */ 1924 | esc = "OD";break; 1925 | case XK_Page_Up: 1926 | if (shift) { 1927 | vncterm_virtual_scroll (vt, -vt->height/2); 1928 | return; 1929 | } 1930 | esc = "[5~";break; 1931 | case XK_Page_Down: 1932 | if (shift) { 1933 | vncterm_virtual_scroll (vt, vt->height/2); 1934 | return; 1935 | } 1936 | esc = "[6~";break; 1937 | case XK_F1: 1938 | esc = "OP";break; 1939 | case XK_F2: 1940 | esc = "OQ";break; 1941 | case XK_F3: 1942 | esc = "OR";break; 1943 | case XK_F4: 1944 | esc = "OS";break; 1945 | case XK_F5: 1946 | esc = "[15~";break; 1947 | case XK_F6: 1948 | esc = "[17~";break; 1949 | case XK_F7: 1950 | esc = "[18~";break; 1951 | case XK_F8: 1952 | esc = "[19~";break; 1953 | case XK_F9: 1954 | esc = "[20~";break; 1955 | case XK_F10: 1956 | esc = "[21~";break; 1957 | case XK_F11: 1958 | esc = "[23~";break; 1959 | case XK_F12: 1960 | esc = "[24~";break; 1961 | default: 1962 | break; 1963 | } 1964 | } 1965 | 1966 | #ifdef DEBUG 1967 | fprintf (stderr, "KEYPRESS OUT:%s: %d\n", esc, keySym); fflush (stderr); 1968 | #endif 1969 | 1970 | if (vt->y_displ != vt->y_base) { 1971 | vt->y_displ = vt->y_base; 1972 | vncterm_refresh (vt); 1973 | } 1974 | 1975 | if (esc) { 1976 | vncterm_respond_esc (vt, esc); 1977 | } else if(keySym<0x100) { 1978 | if (vt->utf8) { 1979 | int len = ucs2_to_utf8 (keySym & 0x0fff, &vt->ibuf[vt->ibuf_count]); 1980 | vt->ibuf_count += len; 1981 | } else { 1982 | vt->ibuf[vt->ibuf_count++] = (char)keySym; 1983 | } 1984 | } 1985 | } 1986 | } else { 1987 | if (keySym == XK_Shift_L || keySym == XK_Shift_R) { 1988 | shift = 0; 1989 | } else if (keySym == XK_Control_L || keySym == XK_Control_R) { 1990 | control = 0; 1991 | } 1992 | } 1993 | } 1994 | 1995 | void 1996 | vncterm_set_xcut_text (char* str, int len, struct _rfbClientRec* cl) 1997 | { 1998 | vncTerm *vt =(vncTerm *)cl->screen->screenData; 1999 | 2000 | // seems str is Latin-1 encoded 2001 | if (vt->selection) free (vt->selection); 2002 | vt->selection = (unicode *)malloc (len*sizeof (unicode)); 2003 | int i; 2004 | for (i = 0; i < len; i++) { 2005 | vt->selection[i] = str[i] & 0xff; 2006 | } 2007 | vt->selection_len = len; 2008 | } 2009 | 2010 | static void 2011 | mouse_report (vncTerm *vt, int butt, int mrx, int mry) 2012 | { 2013 | char buf[8]; 2014 | 2015 | sprintf (buf, "[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), 2016 | (char)('!' + mry)); 2017 | 2018 | vncterm_respond_esc (vt, buf); 2019 | } 2020 | 2021 | void 2022 | vncterm_toggle_marked_cell (vncTerm *vt, int pos) 2023 | { 2024 | int x= (pos%vt->width)*8; 2025 | int y= (pos/vt->width)*16; 2026 | 2027 | int i,j; 2028 | rfbScreenInfoPtr s=vt->screen; 2029 | 2030 | char *b = s->frameBuffer+y*s->width+x; 2031 | 2032 | for (j=0; j < 16; j++) { 2033 | for(i=0; i < 8; i++) { 2034 | b[j*s->width+i] ^= 0x0f; 2035 | rfbMarkRectAsModified (s, x, y, x+8, y+16); 2036 | } 2037 | } 2038 | } 2039 | 2040 | void 2041 | vncterm_pointer_event (int buttonMask, int x, int y, rfbClientPtr cl) 2042 | { 2043 | vncTerm *vt =(vncTerm *)cl->screen->screenData; 2044 | static int button2_released = 1; 2045 | static int last_mask = 0; 2046 | static int sel_start_pos = 0; 2047 | static int sel_end_pos = 0; 2048 | int i; 2049 | 2050 | int cx = x/8; 2051 | int cy = y/16; 2052 | 2053 | if (cx < 0) cx = 0; 2054 | if (cx >= vt->width) cx = vt->width - 1; 2055 | if (cy < 0) cy = 0; 2056 | if (cy >= vt->height) cy = vt->height - 1; 2057 | 2058 | if (vt->report_mouse && buttonMask != last_mask) { 2059 | last_mask = buttonMask; 2060 | if (buttonMask & 1) { 2061 | mouse_report (vt, 0, cx, cy); 2062 | } 2063 | if (buttonMask & 2) { 2064 | mouse_report (vt, 1, cx, cy); 2065 | } 2066 | if (buttonMask & 4) { 2067 | mouse_report (vt, 2, cx, cy); 2068 | } 2069 | if (!buttonMask) { 2070 | mouse_report (vt, 3, cx, cy); 2071 | } 2072 | } 2073 | 2074 | if (buttonMask & 2) { 2075 | if(button2_released && vt->selection) { 2076 | int i; 2077 | for(i = 0; i < vt->selection_len; i++) { 2078 | if (vt->ibuf_count < IBUFSIZE - 6) { // uft8 is max 6 characters wide 2079 | if (vt->utf8) { 2080 | vt->ibuf_count += ucs2_to_utf8 (vt->selection[i], &vt->ibuf[vt->ibuf_count]); 2081 | } else { 2082 | vt->ibuf[vt->ibuf_count++] = vt->selection[i]; 2083 | } 2084 | } 2085 | } 2086 | if (vt->y_displ != vt->y_base) { 2087 | vt->y_displ = vt->y_base; 2088 | vncterm_refresh (vt); 2089 | } 2090 | } 2091 | button2_released = 0; 2092 | } else { 2093 | button2_released = 1; 2094 | } 2095 | 2096 | if (buttonMask & 1) { 2097 | int pos = cy*vt->width + cx; 2098 | 2099 | // code borrowed from libvncserver (VNConsole.c) 2100 | 2101 | if (!vt->mark_active) { 2102 | 2103 | vt->mark_active = 1; 2104 | sel_start_pos = sel_end_pos = pos; 2105 | vncterm_toggle_marked_cell (vt, pos); 2106 | 2107 | } else { 2108 | 2109 | if (pos != sel_end_pos) { 2110 | 2111 | if (pos > sel_end_pos) { 2112 | cx = sel_end_pos; cy=pos; 2113 | } else { 2114 | cx=pos; cy=sel_end_pos; 2115 | } 2116 | 2117 | if (cx < sel_start_pos) { 2118 | if (cy < sel_start_pos) cy--; 2119 | } else { 2120 | cx++; 2121 | } 2122 | 2123 | while (cx <= cy) { 2124 | vncterm_toggle_marked_cell (vt, cx); 2125 | cx++; 2126 | } 2127 | 2128 | sel_end_pos = pos; 2129 | } 2130 | } 2131 | 2132 | } else if (vt->mark_active) { 2133 | vt->mark_active = 0; 2134 | 2135 | if (sel_start_pos > sel_end_pos) { 2136 | int tmp = sel_start_pos - 1; 2137 | sel_start_pos = sel_end_pos; 2138 | sel_end_pos = tmp; 2139 | } 2140 | 2141 | int len = sel_end_pos - sel_start_pos + 1; 2142 | 2143 | if (vt->selection) free (vt->selection); 2144 | vt->selection = (unicode *)malloc (len*sizeof (unicode)); 2145 | vt->selection_len = len; 2146 | char *sel_latin1 = (char *)malloc (len + 1); 2147 | 2148 | for (i = 0; i < len; i++) { 2149 | int pos = sel_start_pos + i; 2150 | int x = pos % vt->width; 2151 | int y1 = ((pos / vt->width) + vt->y_displ) % vt->total_height; 2152 | TextCell *c = &vt->cells[y1*vt->width + x]; 2153 | vt->selection[i] = c->ch; 2154 | sel_latin1[i] = (char)c->ch; 2155 | c++; 2156 | } 2157 | sel_latin1[len] = 0; 2158 | rfbGotXCutText (vt->screen, sel_latin1, len); 2159 | free (sel_latin1); 2160 | 2161 | while (sel_start_pos <= sel_end_pos) { 2162 | vncterm_toggle_marked_cell (vt, sel_start_pos++); 2163 | } 2164 | 2165 | } 2166 | 2167 | rfbDefaultPtrAddEvent (buttonMask, x, y, cl); 2168 | } 2169 | 2170 | static int client_count = 0; 2171 | static int client_connected = 0; 2172 | static int last_client = 1; 2173 | static time_t last_time = 0; 2174 | 2175 | void 2176 | client_gone (rfbClientPtr client) 2177 | { 2178 | client_count--; 2179 | 2180 | last_time = time (NULL); 2181 | 2182 | if (client_count <= 0) { 2183 | last_client = 1; 2184 | } 2185 | } 2186 | 2187 | /* libvncserver callback for when a new client connects */ 2188 | enum rfbNewClientAction 2189 | new_client (rfbClientPtr client) 2190 | { 2191 | client->clientGoneHook = client_gone; 2192 | client_count++; 2193 | 2194 | last_time = time (NULL); 2195 | 2196 | last_client = 0; 2197 | client_connected = 1; 2198 | 2199 | return RFB_CLIENT_ACCEPT; 2200 | } 2201 | 2202 | static char *vncticket = NULL; 2203 | 2204 | static void 2205 | MakeRichCursor(rfbScreenInfoPtr rfbScreen) 2206 | { 2207 | int w = 16, 2208 | h = 16; 2209 | rfbCursorPtr c = rfbScreen->cursor; 2210 | char bitmap[] = 2211 | " " 2212 | " x " 2213 | " xx " 2214 | " xxx " 2215 | " xxxx " 2216 | " xxxxx " 2217 | " xxxxxx " 2218 | " xxxxxxx " 2219 | " xxxxxxxx " 2220 | " xxxxxxxxx " 2221 | " xxxxxxxxxx " 2222 | " xxxx " 2223 | " xxx " 2224 | " xx " 2225 | " x " 2226 | " "; 2227 | char edge[] = 2228 | " " 2229 | " x " 2230 | " xx " 2231 | " x x " 2232 | " x x " 2233 | " x x " 2234 | " x x " 2235 | " x x " 2236 | " x x " 2237 | " x x " 2238 | " x xxxxxx " 2239 | " x x " 2240 | " x x " 2241 | " xx " 2242 | " x " 2243 | " "; 2244 | 2245 | c = rfbScreen->cursor = rfbMakeXCursor(w,h,bitmap,bitmap); 2246 | c->richSource = (unsigned char*)calloc(w*h, 1); 2247 | c->cleanupRichSource = TRUE; 2248 | 2249 | for(int j=0;jrichSource[pos] = 15; // white 2254 | } else { 2255 | c->richSource[pos] = 0; // black 2256 | } 2257 | } 2258 | } 2259 | } 2260 | 2261 | vncTerm * 2262 | create_vncterm (int argc, char** argv, int maxx, int maxy) 2263 | { 2264 | int i; 2265 | 2266 | rfbScreenInfoPtr screen = rfbGetScreen (&argc, argv, maxx, maxy, 8, 1, 1); 2267 | screen->frameBuffer=(char*)calloc(maxx*maxy, 1); 2268 | MakeRichCursor(screen); 2269 | 2270 | char **passwds = calloc(sizeof(char**), 2); 2271 | 2272 | vncTerm *vt = (vncTerm *)calloc (sizeof(vncTerm), 1); 2273 | 2274 | rfbColourMap *cmap =&screen->colourMap; 2275 | cmap->data.bytes = malloc (16*3); 2276 | for(i=0;i<16;i++) { 2277 | cmap->data.bytes[i*3 + 0] = default_red[color_table[i]]; 2278 | cmap->data.bytes[i*3 + 1] = default_grn[color_table[i]]; 2279 | cmap->data.bytes[i*3 + 2] = default_blu[color_table[i]]; 2280 | } 2281 | cmap->count = 16; 2282 | cmap->is16 = FALSE; 2283 | screen->serverFormat.trueColour = FALSE; 2284 | 2285 | screen->kbdAddEvent = vncterm_kbd_event; 2286 | 2287 | screen->setXCutText = vncterm_set_xcut_text; 2288 | 2289 | screen->ptrAddEvent = vncterm_pointer_event; 2290 | 2291 | screen->desktopName = "VNC Command Terminal"; 2292 | 2293 | screen->newClientHook = new_client; 2294 | 2295 | vt->maxx = screen->width; 2296 | vt->maxy = screen->height; 2297 | 2298 | vt->width = vt->maxx / 8; 2299 | vt->height = vt->maxy / 16; 2300 | 2301 | vt->total_height = vt->height * 20; 2302 | vt->scroll_height = 0; 2303 | vt->y_base = 0; 2304 | vt->y_displ = 0; 2305 | 2306 | vt->region_top = 0; 2307 | vt->region_bottom = vt->height; 2308 | 2309 | vt->g0enc = LAT1_MAP; 2310 | vt->g1enc = GRAF_MAP; 2311 | vt->cur_enc = vt->g0enc; 2312 | vt->charset = 0; 2313 | 2314 | /* default text attributes */ 2315 | vt->default_attrib.bold = 0; 2316 | vt->default_attrib.uline = 0; 2317 | vt->default_attrib.blink = 0; 2318 | vt->default_attrib.invers = 0; 2319 | vt->default_attrib.unvisible = 0; 2320 | vt->default_attrib.fgcol = 7; 2321 | vt->default_attrib.bgcol = 0; 2322 | 2323 | vt->cur_attrib = vt->default_attrib; 2324 | 2325 | vt->cells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->total_height); 2326 | 2327 | for (i = 0; i < vt->width*vt->total_height; i++) { 2328 | vt->cells[i].ch = ' '; 2329 | vt->cells[i].attrib = vt->default_attrib; 2330 | } 2331 | 2332 | vt->altcells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->height); 2333 | 2334 | vt->screen = screen; 2335 | 2336 | screen->screenData = (void*)vt; 2337 | 2338 | //screen->autoPort = 1; 2339 | 2340 | if (vncticket) { 2341 | passwds[0] = vncticket; 2342 | passwds[1] = NULL; 2343 | 2344 | screen->authPasswdData = (void *)passwds; 2345 | screen->passwordCheck = rfbCheckPasswordByList; 2346 | } else { 2347 | rfbRegisterSecurityHandler(&VncSecurityHandlerVencrypt); 2348 | } 2349 | 2350 | rfbInitServer(screen); 2351 | 2352 | return vt; 2353 | } 2354 | 2355 | int 2356 | main (int argc, char** argv) 2357 | { 2358 | int i; 2359 | char **cmdargv = NULL; 2360 | char *command = "/bin/bash"; // execute normal shell as default 2361 | int fontfd; 2362 | struct stat sb; 2363 | int pid; 2364 | int master; 2365 | char ptyname[1024]; 2366 | fd_set fs, fs1; 2367 | struct timeval tv, tv1; 2368 | time_t elapsed, cur_time; 2369 | struct winsize dimensions; 2370 | unsigned long width = 0; 2371 | unsigned long height = 0; 2372 | 2373 | if (gnutls_global_init () < 0) { 2374 | fprintf(stderr, "gnutls_global_init failed\n"); 2375 | exit(-1); 2376 | } 2377 | 2378 | if (gnutls_dh_params_init (&dh_params) < 0) { 2379 | fprintf(stderr, "gnutls_dh_params_init failed\n"); 2380 | exit(-1); 2381 | } 2382 | 2383 | if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) { 2384 | fprintf(stderr, "gnutls_dh_params_init failed\n"); 2385 | exit(-1); 2386 | } 2387 | 2388 | for (i = 1; i < argc; i++) { 2389 | if (!strcmp (argv[i], "-c")) { 2390 | command = argv[i+1]; 2391 | cmdargv = &argv[i+1]; 2392 | argc = i; 2393 | argv[i] = NULL; 2394 | break; 2395 | } 2396 | } 2397 | 2398 | for (i = 1; i < argc; i++) { 2399 | if (!strcmp (argv[i], "-timeout")) { 2400 | CHECK_ARGC (argc, argv, i); 2401 | idle_timeout = atoi(argv[i+1]); 2402 | rfbPurgeArguments(&argc, &i, 2, argv); i--; 2403 | } else if (!strcmp (argv[i], "-authpath")) { 2404 | CHECK_ARGC (argc, argv, i); 2405 | auth_path = argv[i+1]; 2406 | rfbPurgeArguments(&argc, &i, 2, argv); i--; 2407 | } else if (!strcmp (argv[i], "-perm")) { 2408 | CHECK_ARGC (argc, argv, i); 2409 | auth_perm = argv[i+1]; 2410 | rfbPurgeArguments(&argc, &i, 2, argv); i--; 2411 | } else if (!strcmp (argv[i], "-width")) { 2412 | CHECK_ARGC (argc, argv, i); 2413 | errno = 0; 2414 | width = strtoul(argv[i+1], NULL, 10); 2415 | if (errno == 0 && width >= 16 && width < 0xFFFF) { 2416 | screen_width = width; 2417 | } 2418 | rfbPurgeArguments(&argc, &i, 2, argv); i--; 2419 | } else if (!strcmp (argv[i], "-height")) { 2420 | CHECK_ARGC (argc, argv, i); 2421 | errno = 0; 2422 | height = strtoul(argv[i+1], NULL, 10); 2423 | if (errno == 0 && height >= 32 && height < 0xFFFF) { 2424 | screen_height = height; 2425 | } 2426 | rfbPurgeArguments(&argc, &i, 2, argv); i--; 2427 | } else if (!strcmp (argv[i], "-notls")) { 2428 | rfbPurgeArguments(&argc, &i, 1, argv); i--; 2429 | if ((vncticket = getenv("PVE_VNC_TICKET")) == NULL) { 2430 | fprintf(stderr, "missing env PVE_VNC_TICKET (-notls)\n"); 2431 | exit(-1); 2432 | } 2433 | } 2434 | } 2435 | 2436 | unsetenv("PVE_VNC_TICKET"); // do not expose this to child 2437 | 2438 | #ifdef DEBUG 2439 | rfbLogEnable (1); 2440 | gnutls_global_set_log_level(10); 2441 | gnutls_global_set_log_function(vnc_debug_gnutls_log); 2442 | #else 2443 | rfbLogEnable (0); 2444 | #endif 2445 | 2446 | // mmap font file 2447 | fontfd = open(FONTFILE, O_RDONLY); 2448 | if (fontfd == -1) { 2449 | perror("Error opening Fontfile 'FONTFILE'"); 2450 | exit (-1); 2451 | } 2452 | if (fstat(fontfd, &sb) == -1) { 2453 | perror("Stat on 'FONTFILE' failed"); 2454 | exit (-1); 2455 | } 2456 | fontdata = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fontfd, 0); 2457 | if (fontdata == MAP_FAILED) { 2458 | perror("Could not mmap 'FONTFILE'"); 2459 | exit (-1); 2460 | } 2461 | 2462 | close(fontfd); 2463 | vncTerm *vt = create_vncterm (argc, argv, screen_width, screen_height); 2464 | 2465 | setlocale(LC_ALL, ""); // set from environment 2466 | 2467 | char *ctype = setlocale (LC_CTYPE, NULL); // query LC_CTYPE 2468 | 2469 | // fixme: ist there a standard way to detect utf8 mode ? 2470 | if (strcasestr (ctype, ".utf-8")||strcasestr (ctype, ".utf8")) { 2471 | vt->utf8 = 1; 2472 | } 2473 | 2474 | dimensions.ws_col = vt->width; 2475 | dimensions.ws_row = vt->height; 2476 | 2477 | setenv ("TERM", TERM, 1); 2478 | 2479 | pid = forkpty (&master, ptyname, NULL, &dimensions); 2480 | if(!pid) { 2481 | 2482 | // install default signal handlers 2483 | signal (SIGQUIT, SIG_DFL); 2484 | signal (SIGTERM, SIG_DFL); 2485 | signal (SIGINT, SIG_DFL); 2486 | 2487 | if (cmdargv) { 2488 | execvp (command, cmdargv); 2489 | } else { 2490 | execlp (command, command, NULL); 2491 | } 2492 | perror ("Error: exec failed\n"); 2493 | exit (-1); // should not be reached 2494 | } else if (pid == -1) { 2495 | perror ("Error: fork failed\n"); 2496 | exit (-1); 2497 | } 2498 | 2499 | FD_ZERO (&fs); 2500 | FD_SET (master, &fs); 2501 | tv.tv_sec = 0; 2502 | tv.tv_usec = 5000; /* 5 ms */ 2503 | 2504 | last_time = time (NULL); 2505 | 2506 | int count = 0; 2507 | while (1) { 2508 | count ++; 2509 | tv1 = tv; 2510 | fs1 = fs; 2511 | 2512 | cur_time = time (NULL); 2513 | 2514 | elapsed = cur_time - last_time; 2515 | //printf ("Elapsed %ld\n", elapsed); 2516 | 2517 | if (last_client) { 2518 | if (client_connected) { 2519 | if (idle_timeout && (elapsed >= idle_timeout)) { 2520 | break; 2521 | } 2522 | } else { 2523 | // wait at least 20 seconds for initial connect 2524 | if (idle_timeout && (elapsed >= (idle_timeout > 20 ? idle_timeout : 20))) { 2525 | break; 2526 | } 2527 | } 2528 | } else { 2529 | // exit after 30 minutes idle time 2530 | if (elapsed >= 30*60) { 2531 | break; 2532 | } 2533 | } 2534 | 2535 | rfbProcessEvents (vt->screen, 40000); /* 40 ms */ 2536 | 2537 | if (vt->ibuf_count > 0) { 2538 | //printf ("DEBUG: WRITE %d %d\n", vt->ibuf[0], vt->ibuf_count); 2539 | write (master, vt->ibuf, vt->ibuf_count); 2540 | vt->ibuf_count = 0; 2541 | last_time = time (NULL); 2542 | } 2543 | 2544 | if (!vt->mark_active) { 2545 | 2546 | int num_fds = select (master+1, &fs1, NULL, NULL, &tv1); 2547 | if (num_fds >= 0) { 2548 | if (FD_ISSET (master, &fs1)) { 2549 | char buffer[1024]; 2550 | int c; 2551 | while ((c = read (master, buffer, 1024)) == -1) { 2552 | if (errno != EAGAIN) break; 2553 | } 2554 | if (c == -1) break; 2555 | vncterm_puts (vt, buffer, c); 2556 | } 2557 | } else { 2558 | break; 2559 | } 2560 | } 2561 | } 2562 | 2563 | rfbScreenCleanup(vt->screen); 2564 | 2565 | kill (pid, 9); 2566 | int status; 2567 | waitpid(pid, &status, 0); 2568 | 2569 | munmap(fontdata, sb.st_size); 2570 | exit (0); 2571 | } 2572 | -------------------------------------------------------------------------------- /vncterm.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define IBUFSIZE 1024 4 | #define MAX_ESC_PARAMS 16 5 | 6 | typedef unsigned short unicode; 7 | 8 | typedef struct TextAttributes { 9 | unsigned int fgcol:4; 10 | unsigned int bgcol:4; 11 | unsigned int bold:1; 12 | unsigned int uline:1; 13 | unsigned int blink:1; 14 | unsigned int invers:1; 15 | unsigned int unvisible:1; 16 | } TextAttributes; 17 | 18 | typedef struct TextCell { 19 | unicode ch; 20 | unicode combiningglyph; 21 | short width; 22 | TextAttributes attrib; 23 | } TextCell; 24 | 25 | typedef struct vncTerm { 26 | int maxx; 27 | int maxy; 28 | 29 | int width; 30 | int height; 31 | 32 | int total_height; 33 | int scroll_height; 34 | int y_base; 35 | int y_displ; 36 | int altbuf:1; 37 | 38 | unsigned int utf8:1; // utf8 mode 39 | long utf_char; // used by utf8 parser 40 | int utf_count; // used by utf8 parser 41 | 42 | 43 | TextAttributes default_attrib; 44 | 45 | TextCell *cells; 46 | TextCell *altcells; 47 | 48 | rfbScreenInfoPtr screen; 49 | 50 | // cursor 51 | TextAttributes cur_attrib; 52 | TextAttributes cur_attrib_saved; 53 | unsigned int tty_state; // 0 - normal, 1 - ESC, 2 - CSI 54 | int cx; // cursor x position 55 | int cy; // cursor y position 56 | int cx_saved; // saved cursor x position 57 | int cy_saved; // saved cursor y position 58 | unsigned int esc_buf[MAX_ESC_PARAMS]; 59 | unsigned int esc_count; 60 | unsigned int esc_ques; 61 | unsigned int esc_has_par; 62 | char osc_textbuf[4096]; 63 | char osc_cmd; 64 | unsigned int region_top; 65 | unsigned int region_bottom; 66 | 67 | unsigned int charset:1; // G0 or G1 68 | unsigned int charset_saved:1; // G0 or G1 69 | unsigned int g0enc:2; 70 | unsigned int g0enc_saved:2; 71 | unsigned int g1enc:2; 72 | unsigned int g1enc_saved:2; 73 | unsigned int cur_enc:2; 74 | unsigned int cur_enc_saved:2; 75 | 76 | // input buffer 77 | char ibuf[IBUFSIZE]; 78 | int ibuf_count; 79 | 80 | unicode *selection; 81 | int selection_len; 82 | 83 | unsigned int mark_active:1; 84 | 85 | unsigned int report_mouse:1; 86 | 87 | } vncTerm; 88 | 89 | /* Unicode translations copied from kernel source consolemap.c */ 90 | 91 | #define LAT1_MAP 0 92 | #define GRAF_MAP 1 93 | #define IBMPC_MAP 2 94 | #define USER_MAP 3 95 | 96 | static unsigned short translations[][256] = { 97 | /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ 98 | { 99 | 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 100 | 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 101 | 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 102 | 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 103 | 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 104 | 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 105 | 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 106 | 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 107 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 108 | 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 109 | 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 110 | 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 111 | 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 112 | 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 113 | 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 114 | 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 115 | 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 116 | 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 117 | 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 118 | 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 119 | 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 120 | 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 121 | 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 122 | 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 123 | 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 124 | 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 125 | 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 126 | 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 127 | 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 128 | 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 129 | 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 130 | 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff 131 | }, 132 | /* VT100 graphics mapped to Unicode */ 133 | { 134 | 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 135 | 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 136 | 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 137 | 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 138 | 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 139 | 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f, 140 | 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 141 | 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 142 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 143 | 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 144 | 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 145 | 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0, 146 | 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, 147 | 0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, 148 | 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, 149 | 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f, 150 | 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 151 | 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 152 | 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 153 | 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 154 | 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 155 | 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 156 | 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 157 | 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 158 | 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 159 | 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 160 | 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 161 | 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 162 | 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 163 | 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 164 | 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 165 | 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff 166 | }, 167 | /* IBM Codepage 437 mapped to Unicode */ 168 | { 169 | 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 170 | 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, 171 | 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, 172 | 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc, 173 | 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 174 | 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 175 | 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 176 | 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 177 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 178 | 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 179 | 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 180 | 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 181 | 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 182 | 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 183 | 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 184 | 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, 185 | 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 186 | 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 187 | 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 188 | 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 189 | 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 190 | 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 191 | 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 192 | 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 193 | 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 194 | 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 195 | 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 196 | 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 197 | 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 198 | 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 199 | 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 200 | 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 201 | }, 202 | /* User mapping -- default to codes for direct font mapping */ 203 | { 204 | 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007, 205 | 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f, 206 | 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017, 207 | 0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 208 | 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027, 209 | 0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f, 210 | 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 211 | 0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f, 212 | 0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047, 213 | 0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f, 214 | 0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057, 215 | 0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f, 216 | 0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067, 217 | 0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f, 218 | 0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077, 219 | 0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f, 220 | 0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087, 221 | 0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f, 222 | 0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097, 223 | 0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f, 224 | 0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7, 225 | 0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af, 226 | 0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7, 227 | 0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf, 228 | 0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7, 229 | 0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf, 230 | 0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7, 231 | 0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df, 232 | 0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7, 233 | 0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef, 234 | 0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7, 235 | 0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff 236 | } 237 | }; 238 | -------------------------------------------------------------------------------- /vncterm.pod: -------------------------------------------------------------------------------- 1 | =head1 NAME 2 | 3 | vncterm - VNC Terminal Emulator 4 | 5 | =head1 SYNOPSIS 6 | 7 | vncterm [VNCOPTS] [-c command [ARGS]] 8 | 9 | =head1 DESCRIPTION 10 | 11 | Executes redirecting stdin from a vncviewer and stdout & stderr 12 | to the VNC clients. Implements a 'xterm' compatible terminal. 13 | 14 | =head1 SEE ALSO 15 | 16 | x11vnc(1). 17 | 18 | =head1 AUTHOR 19 | 20 | Dietmar Maurer 21 | 22 | Many thanks to Proxmox Server Solutions (www.proxmox.com) for sponsoring 23 | this work. 24 | 25 | =head1 COPYRIGHT AND DISCLAIMER 26 | 27 | Copyright (C) 2007 Proxmox Server Solutions GmbH 28 | 29 | Copyright: vncterm is under GNU GPL, the GNU General Public License. 30 | 31 | This program is free software; you can redistribute it and/or modify 32 | it under the terms of the GNU General Public License as published by 33 | the Free Software Foundation; either version 2 of the License, or 34 | (at your option) any later version. 35 | 36 | This program is distributed in the hope that it will be useful, 37 | but WITHOUT ANY WARRANTY; without even the implied warranty of 38 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 39 | GNU General Public License for more details. 40 | 41 | You should have received a copy of the GNU General Public License along 42 | with this program; if not, write to the Free Software Foundation, Inc., 43 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 44 | --------------------------------------------------------------------------------