#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <rfb/rfb.h>
#include <locale.h>
#include "vncterm.h"
-#include "glyphs.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
char *auth_path = "/";
char *auth_perm = "Sys.Console";
+uint16_t screen_width = 744;
+uint16_t screen_height = 400;
+
int use_x509 = 1;
+extern int wcwidth (wchar_t wc);
+unsigned char *fontdata;
+
+#define FONTFILE "/usr/share/vncterm/font.data"
+#define GLYPHLINES 16
+
static char *
urlencode(char *buf, const char *value)
{
return;
}
- /* optimize for speed */
- static const int cipher_priority_performance[] = {
- GNUTLS_CIPHER_ARCFOUR_128,
- GNUTLS_CIPHER_AES_128_CBC,
- GNUTLS_CIPHER_3DES_CBC, 0
- };
-
- if ((ret = gnutls_cipher_set_priority(sd->session, cipher_priority_performance)) < 0) {
- rfbLog("gnutls_cipher_set_priority failed: %s\n", gnutls_strerror(ret));
- sd->session = NULL;
- rfbCloseClient(cl);
- return;
- }
-
- static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
- static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
- if ((ret = gnutls_kx_set_priority(sd->session, use_x509 ? kx_x509 : kx_anon)) < 0) {
- rfbLog("gnutls_kx_set_priority failed: %s\n", gnutls_strerror(ret));
- sd->session = NULL;
- rfbCloseClient(cl);
- return;
- }
-
- static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
- if ((ret = gnutls_certificate_type_set_priority(sd->session, cert_type_priority)) < 0) {
- rfbLog("gnutls_certificate_type_set_priority failed: %s\n",
- gnutls_strerror(ret));
- sd->session = NULL;
- rfbCloseClient(cl);
- return;
- }
-
- static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
- if ((ret = gnutls_protocol_set_priority(sd->session, protocol_priority)) < 0) {
- rfbLog("gnutls_protocol_set_priority failed: %s\n",
- gnutls_strerror(ret));
+ static const char *priority_str_x509 = "NORMAL";
+ static const char *priority_str_anon = "NORMAL:+ANON-ECDH:+ANON-DH";
+ if ((ret = gnutls_priority_set_direct(sd->session, use_x509 ? priority_str_x509 : priority_str_anon, NULL)) < 0) {
+ rfbLog("gnutls_priority_set_direct failed: %s\n", gnutls_strerror(ret));
sd->session = NULL;
rfbCloseClient(cl);
return;
static void
rfb_draw_char (rfbScreenInfoPtr rfbScreen, int x, int y,
- unsigned short c, rfbPixel col)
+ unicode c, rfbPixel col, short width)
{
- if (c > vt_font_size) {
- rfbLog ("undefined font glyph %d\n", c);
- return;
- }
-
int i,j;
- unsigned char *data= vt_font_data + c*16;
+ unsigned char *data= fontdata + c*(GLYPHLINES*2);
unsigned char d=*data;
int rowstride=rfbScreen->paddedWidthInBytes;
char *colour=(char*)&col;
- for(j = 0; j < 16; j++) {
- for(i = 0; i < 8; i++) {
+ for(j = 0; j < GLYPHLINES; j++) {
+ for(i = 0; i < 8*width; i++) {
if ((i&7) == 0) {
d=*data;
data++;
}
static void
-draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib)
+draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib, short width, unicode combiningglyph)
{
if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
+ // non printable character
+ if (width < 1) return;
+
int rx = x*8;
int ry = y*16;
- int rxe = x*8+8;
+ int rxe = x*8+8*width;
int rye = y*16+16;
int fg, bg;
fg = attrib.fgcol;
}
- int ec = vt_fontmap[ch];
-
rfbFillRect (vt->screen, rx, ry, rxe, rye, bg);
if (attrib.bold) {
// unsuported attributes = (attrib.blink || attrib.unvisible)
- rfb_draw_char (vt->screen, rx, ry, ec, fg);
+ rfb_draw_char (vt->screen, rx, ry, ch, fg, width);
+
+ if (combiningglyph) {
+ rfb_draw_char (vt->screen, rx, ry, combiningglyph, fg, 1);
+ }
if (attrib.uline) {
rfbDrawLine (vt->screen, rx, ry + 14, rxe, ry + 14, fg);
}
if (y2 < vt->height) {
TextCell *c = &vt->cells[y1 * vt->width + x];
- draw_char_at (vt, x, y2, c->ch, c->attrib);
+ draw_char_at (vt, x, y2, c->ch, c->attrib, c->width, c->combiningglyph);
}
}
c->attrib = vt->default_attrib;
c->attrib.fgcol = vt->cur_attrib.fgcol;
c->attrib.bgcol = vt->cur_attrib.bgcol;
+ c->width = 1;
+ c->combiningglyph = 0;
- draw_char_at (vt, x, y, c->ch, c->attrib);
+ draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->combiningglyph);
}
}
if (show) {
TextAttributes attrib = vt->default_attrib;
attrib.invers = !(attrib.invers); /* invert fg and bg */
- draw_char_at (vt, x, y, c->ch, attrib);
+ draw_char_at (vt, x, y, c->ch, attrib, c->width, c->combiningglyph);
} else {
- draw_char_at (vt, x, y, c->ch, c->attrib);
+ draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->combiningglyph);
}
}
}
for(y = 0; y < vt->height; y++) {
TextCell *c = vt->cells + y1 * vt->width;
for(x = 0; x < vt->width; x++) {
- draw_char_at (vt, x, y, c->ch, c->attrib);
- c++;
+ draw_char_at (vt, x, y, c->ch, c->attrib, c->width, c->combiningglyph);
+ c += c->width;
}
if (++y1 == vt->total_height)
y1 = 0;
for(j = 0; j < vt->width; j++) {
c->attrib = vt->default_attrib;
c->ch = ' ';
+ c->width = 1;
+ c->combiningglyph = 0;
c++;
}
}
for(j = 0; j < vt->width; j++) {
c->attrib = vt->default_attrib;
c->ch = ' ';
+ c->width = 1;
+ c->combiningglyph = 0;
c++;
}
}
int x;
for (x = 0; x < vt->width; x++) {
c->ch = ' ';
+ c->width = 1;
+ c->combiningglyph = 0;
c->attrib = vt->default_attrib;
c++;
}
if (x < 0) {
x = 0;
- }
-
- if (x >= vt->width) {
+ } else if (x >= vt->width) {
x = vt->width - 1;
}
if (y < 0) {
y = 0;
- }
-
- if (y >= vt->height) {
+ } else if (y >= vt->height) {
y = vt->height - 1;
}
}
break;
} else if (ch == ';') {
+ vt->esc_has_par = 1;
vt->esc_count++;
break;
} else {
if (vt->esc_buf[0] == 0) {
vt->esc_buf[0] = 1;
}
- vt->cy -= vt->esc_buf[0];
- if (vt->cy < 0) {
- vt->cy = 0;
- }
+ vncterm_gotoxy (vt, vt->cx, vt->cy - vt->esc_buf[0]);
break;
case 'B':
case 'e':
if (vt->esc_buf[0] == 0) {
vt->esc_buf[0] = 1;
}
- vt->cy += vt->esc_buf[0];
- if (vt->cy >= vt->height) {
- vt->cy = vt->height - 1;
- }
+ vncterm_gotoxy (vt, vt->cx, vt->cy + vt->esc_buf[0]);
break;
case 'C':
case 'a':
if (vt->esc_buf[0] == 0) {
vt->esc_buf[0] = 1;
}
- vt->cx += vt->esc_buf[0];
- if (vt->cx >= vt->width) {
- vt->cx = vt->width - 1;
- }
+ vncterm_gotoxy (vt, vt->cx + vt->esc_buf[0], vt->cy);
break;
case 'D':
/* move cursor left */
if (vt->esc_buf[0] == 0) {
vt->esc_buf[0] = 1;
}
- vt->cx -= vt->esc_buf[0];
- if (vt->cx < 0) {
- vt->cx = 0;
- }
+ vncterm_gotoxy (vt, vt->cx - vt->esc_buf[0], vt->cy);
break;
case 'G':
case '`':
*dst = *src;
vncterm_update_xy (vt, x + c, vt->cy);
src->ch = ' ';
+ src->width = 1;
+ src->combiningglyph = 0;
src->attrib = vt->default_attrib;
vncterm_update_xy (vt, x, vt->cy);
}
*dst = *src;
vncterm_update_xy (vt, x + c, vt->cy);
src->ch = ' ';
+ src->width = 1;
+ src->combiningglyph = 0;
src->attrib = vt->cur_attrib;
vncterm_update_xy (vt, x, vt->cy);
}
}
int y1 = (vt->y_base + vt->cy) % vt->total_height;
- TextCell *c = &vt->cells[y1*vt->width + vt->cx];
- c->attrib = vt->cur_attrib;
- c->ch = ch;
- vncterm_update_xy (vt, vt->cx, vt->cy);
- vt->cx++;
+ int width = wcwidth(ch);
+ if (width > 0) {
+ // normal/wide character
+ TextCell *c = &vt->cells[y1*vt->width + vt->cx];
+ c->attrib = vt->cur_attrib;
+ c->ch = ch;
+ c->width = width;
+ c->combiningglyph = 0;
+ vncterm_update_xy (vt, vt->cx, vt->cy);
+ vt->cx += width;
+ } else if (width == 0) {
+ // combiningglyph
+ TextCell *c = &vt->cells[y1*vt->width + vt->cx - 1];
+ c->attrib = vt->cur_attrib;
+ c->combiningglyph = ch;
+ vncterm_update_xy (vt, vt->cx - 1, vt->cy);
+ } else {
+ // non printable character, so we do not save them
+ }
break;
}
break;
vt->utf_char = (vt->utf_char << 6) | (c & 0x3f);
vt->utf_count--;
if (vt->utf_count == 0) {
- tc = vt->utf_char;
+ if (vt->utf_char <= USHRT_MAX) {
+ tc = vt->utf_char;
+ } else {
+ tc = 0;
+ }
} else {
continue;
}
static char *vncticket = NULL;
+static void
+MakeRichCursor(rfbScreenInfoPtr rfbScreen)
+{
+ int w = 16,
+ h = 16;
+ rfbCursorPtr c = rfbScreen->cursor;
+ char bitmap[] =
+ " "
+ " x "
+ " xx "
+ " xxx "
+ " xxxx "
+ " xxxxx "
+ " xxxxxx "
+ " xxxxxxx "
+ " xxxxxxxx "
+ " xxxxxxxxx "
+ " xxxxxxxxxx "
+ " xxxx "
+ " xxx "
+ " xx "
+ " x "
+ " ";
+ char edge[] =
+ " "
+ " x "
+ " xx "
+ " x x "
+ " x x "
+ " x x "
+ " x x "
+ " x x "
+ " x x "
+ " x x "
+ " x xxxxxx "
+ " x x "
+ " x x "
+ " xx "
+ " x "
+ " ";
+
+ c = rfbScreen->cursor = rfbMakeXCursor(w,h,bitmap,bitmap);
+ c->richSource = (unsigned char*)calloc(w*h, 1);
+ c->cleanupRichSource = TRUE;
+
+ for(int j=0;j<h;j++) {
+ for(int i=0;i<w;i++) {
+ unsigned int pos = j*w+i;
+ if (edge[pos] == 'x') {
+ c->richSource[pos] = 15; // white
+ } else {
+ c->richSource[pos] = 0; // black
+ }
+ }
+ }
+}
+
vncTerm *
create_vncterm (int argc, char** argv, int maxx, int maxy)
{
rfbScreenInfoPtr screen = rfbGetScreen (&argc, argv, maxx, maxy, 8, 1, 1);
screen->frameBuffer=(char*)calloc(maxx*maxy, 1);
+ MakeRichCursor(screen);
char **passwds = calloc(sizeof(char**), 2);
int i;
char **cmdargv = NULL;
char *command = "/bin/bash"; // execute normal shell as default
+ int fontfd;
+ struct stat sb;
int pid;
int master;
char ptyname[1024];
struct timeval tv, tv1;
time_t elapsed, cur_time;
struct winsize dimensions;
+ unsigned long width = 0;
+ unsigned long height = 0;
if (gnutls_global_init () < 0) {
fprintf(stderr, "gnutls_global_init failed\n");
CHECK_ARGC (argc, argv, i);
auth_perm = argv[i+1];
rfbPurgeArguments(&argc, &i, 2, argv); i--;
+ } else if (!strcmp (argv[i], "-width")) {
+ CHECK_ARGC (argc, argv, i);
+ errno = 0;
+ width = strtoul(argv[i+1], NULL, 10);
+ if (errno == 0 && width >= 16 && width < 0xFFFF) {
+ screen_width = width;
+ }
+ rfbPurgeArguments(&argc, &i, 2, argv); i--;
+ } else if (!strcmp (argv[i], "-height")) {
+ CHECK_ARGC (argc, argv, i);
+ errno = 0;
+ height = strtoul(argv[i+1], NULL, 10);
+ if (errno == 0 && height >= 32 && height < 0xFFFF) {
+ screen_height = height;
+ }
+ rfbPurgeArguments(&argc, &i, 2, argv); i--;
} else if (!strcmp (argv[i], "-notls")) {
rfbPurgeArguments(&argc, &i, 1, argv); i--;
if ((vncticket = getenv("PVE_VNC_TICKET")) == NULL) {
rfbLogEnable (0);
#endif
- vncTerm *vt = create_vncterm (argc, argv, 745, 400);
+ // mmap font file
+ fontfd = open(FONTFILE, O_RDONLY);
+ if (fontfd == -1) {
+ perror("Error opening Fontfile 'FONTFILE'");
+ exit (-1);
+ }
+ if (fstat(fontfd, &sb) == -1) {
+ perror("Stat on 'FONTFILE' failed");
+ exit (-1);
+ }
+ fontdata = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fontfd, 0);
+ if (fontdata == MAP_FAILED) {
+ perror("Could not mmap 'FONTFILE'");
+ exit (-1);
+ }
+
+ close(fontfd);
+ vncTerm *vt = create_vncterm (argc, argv, screen_width, screen_height);
setlocale(LC_ALL, ""); // set from environment
}
}
+ rfbScreenCleanup(vt->screen);
+
kill (pid, 9);
int status;
waitpid(pid, &status, 0);
+ munmap(fontdata, sb.st_size);
exit (0);
}