shithub: barrera

Download patch

ref: e1c4261fb2cb095a18d79c3a4374c7eff74bf892
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jan 1 22:09:30 EST 2023

barrera: initial commit

--- /dev/null
+++ b/barrera.c
@@ -1,0 +1,784 @@
+/*
+ * a client for barrier mouse, keyboard and clipboard sharing.
+ */
+#include <u.h>
+#include <libc.h>
+
+/* mouse() ctl */
+enum
+{
+	Mrelative	= (0<<0),
+	Mabsolute	= (1<<0),
+	Mclearbuttons	= (1<<1),
+	Msetbuttons	= (1<<2),
+	Mresetbuttons	= (1<<4),
+};
+
+/* keyboard() ctl */
+enum
+{
+	Kup		= 1,
+	Kdown		= 2,
+	Krepeat		= 3,
+};
+
+/* clipboard type */
+enum
+{
+	Ftext,
+	Fbmp,
+	Fhtml,
+	Fmax,
+};
+
+typedef struct Msg Msg;
+struct Msg
+{
+	uchar		*b;
+	uchar		*p;
+	uchar		*e;
+};
+
+int mouseinfd = -1;
+int mousefd = -1;
+int kbdfd = -1;
+int snarffd = -1;
+Msg snarfbuf;
+
+struct {
+	int	x;
+	int	y;
+	int	buttons;
+} screenmouse;
+
+struct {
+	struct {
+		int	x;
+		int	y;
+	} min, max;
+} screensize;
+
+int packmsg(Msg *msg, char *fmt, ...);
+int packfmtlen(char *fmt, ...);
+int unpackmsg(Msg *msg, char *fmt, ...);
+
+int
+vpackmsglen(char *fmt, va_list arg)
+{
+	int n, q;
+	char *vas;
+	int vai;
+
+	n = 0;
+	while(*fmt){
+		if(*fmt!='%'){
+			n++;
+			fmt++;
+			continue;
+		}
+		fmt++;
+		q = 0;
+		if((*fmt >= '0') && (*fmt <= '9')){
+			q = *(fmt++)-'0';
+		}
+		switch(*fmt){
+		case 'i':
+			vai = va_arg(arg, int);
+			USED(vai);
+			n += q;
+			break;
+		case '*':
+			q = va_arg(arg, int);
+			vas = va_arg(arg, char*);
+			USED(vas);
+			n += 4 + q;
+			break;
+		case 's':
+			vas = va_arg(arg, char*);
+			q = strlen(vas);
+			n += 4 + q;
+			break;
+		}
+		fmt++;
+	}
+	return n;
+}
+
+int
+packmsglen(char *fmt, ...)
+{
+	va_list arg;
+	int n;
+
+	va_start(arg, fmt);
+	n = vpackmsglen(fmt, arg);
+	va_end(arg);
+	return n;
+}
+
+int
+vunpackmsg(Msg *msg, char *fmt, va_list arg)
+{
+	int *vai;
+	char *sval;
+
+	int n, q;
+
+	n = 0;
+	while(*fmt){
+		if(*fmt!='%'){
+			if(msg->p >= msg->e || *msg->p != *fmt)
+				return n;
+			msg->p++;
+			fmt++;
+			continue;
+		}
+		fmt++;
+
+		q = 0;
+		if((*fmt>='0') && (*fmt<='9')){
+			q = *fmt-'0';
+			fmt++;
+		}
+		switch(*fmt){
+		default:
+			return n;
+		case 'i':
+			if(msg->p+q > msg->e)
+				return n;
+			if(vai = va_arg(arg, int*)){
+				switch(q){
+				default:
+					return n;
+				case 1:
+					*vai = 	(unsigned)msg->p[0];
+					break;
+				case 2:
+					*vai = 	(unsigned)msg->p[0]<<8 | (unsigned)msg->p[1];
+					break;
+				case 4:
+					*vai = 	(unsigned)msg->p[0]<<24 | 
+						(unsigned)msg->p[1]<<16 | 
+						(unsigned)msg->p[2]<<8 | 
+						(unsigned)msg->p[3];
+					break;
+				}
+			}
+			msg->p+=q;
+			break;
+		case 's':
+			if(unpackmsg(msg, "%4i", &q) != 1)
+				return n;
+			if(q >= va_arg(arg, int) || msg->p+q > msg->e)
+				return n;
+			sval = va_arg(arg, char*);
+			memmove(sval, msg->p, q);
+			sval[q] = '\0';
+			msg->p+=q;
+			break;
+		case '*':
+			if(unpackmsg(msg, "%4i", &q) != 1)
+				return n;
+			if(q > va_arg(arg, int) || msg->p+q > msg->e)
+				return n;
+			sval = va_arg(arg, char*);
+			memmove(sval, msg->p, q);
+			msg->p+=q;
+			break;
+		}
+
+		n++;
+		fmt++;
+	}
+	return n;
+}
+
+int
+vpackmsg(Msg *msg, char *fmt, va_list arg)
+{
+	int vai;
+	char *vas;
+
+	int n, q;
+
+	n = 0;
+	while(*fmt){
+		if(*fmt!='%'){
+			if(msg->p >= msg->e)
+				return n;
+			*msg->p++ = *fmt++;
+			continue;
+		}
+		fmt++;
+
+		q = 0;
+		if((*fmt >= '0') && (*fmt <= '9')){
+			q = *(fmt++)-'0';
+		}
+		switch(*fmt){
+		default:
+			return n;
+		case 'i':
+			if(msg->p+q > msg->e)
+				return n;
+			vai = va_arg(arg, int);
+			switch(q){
+			default:
+				return n;
+			case 1:
+				msg->p[0] = vai		& 0xff;
+				break;
+			case 2:
+				msg->p[0] = vai>>8	& 0xff;
+				msg->p[1] = vai		& 0xff;
+				break;
+			case 4:
+				msg->p[0] = (vai>>24)	& 0xff;
+				msg->p[1] = (vai>>16)	& 0xff;
+				msg->p[2] = (vai>>8)	& 0xff;
+				msg->p[3] = vai		& 0xff;
+				break;
+			}
+			msg->p += q;
+			break;
+		case '*':
+			q = va_arg(arg, int);
+			vas = va_arg(arg, char*);
+			if(0){
+		case 's':
+				vas = va_arg(arg, char*);
+				q = strlen(vas);
+			}
+			if(msg->p + 4 + q > msg->e)
+				return n;
+			packmsg(msg, "%4i", q);
+			if(q > 0)
+				memcpy(msg->p, vas, q);
+			msg->p += q;
+			break;
+		}
+		n++;
+		fmt++;
+	}
+	return n;
+}
+
+int
+unpackmsg(Msg *msg, char *fmt, ...)
+{
+	va_list arg;
+	int n;
+
+	va_start(arg, fmt);
+	n = vunpackmsg(msg, fmt, arg);
+	va_end(arg);
+	return n;
+}
+
+int
+packmsg(Msg *msg, char *fmt, ...)
+{
+	va_list arg;
+	int n;
+
+	va_start(arg, fmt);
+	n = vpackmsg(msg, fmt, arg);
+	va_end(arg);
+	return n;
+}
+
+void
+sizemsg(Msg *m, int len)
+{
+	int n = m->e - m->p;
+
+	if(len < 0 || len > 1024*1024)
+		sysfatal("bad message size: %d", len);
+	if(len > n){
+		memmove(m->b, m->p, n);
+		m->b = realloc(m->b, len);
+		if(m->b == nil)
+			sysfatal("out of memory: %r");
+		m->p = m->b;
+	}
+	m->e = m->p + len;
+}
+
+int
+writemsg(char *fmt, ...)
+{
+	static Msg m;
+	va_list arg;
+	int n, l;
+
+	va_start(arg, fmt);
+	l = 4 + vpackmsglen(fmt, arg);
+	sizemsg(&m, l);
+	packmsg(&m, "%4i", l-4);
+	n = vpackmsg(&m, fmt, arg);
+	va_end(arg);
+	if(write(1, m.b, l)!=l)
+		return -1;
+	return n;
+}
+
+void
+readscreenmouse(void)
+{
+	char buf[1+4*12+1], *field[4];
+	int n;
+
+	if(mouseinfd < 0)
+		return;
+	n = pread(mouseinfd, buf, sizeof(buf)-1, 0);
+	if(n < 0)
+		return;
+	buf[n] = '\0';
+	if(tokenize(buf+1, field, 4) < 3)
+		return;
+	screenmouse.x = atoi(field[0]);
+	screenmouse.y = atoi(field[1]);
+	screenmouse.buttons = atoi(field[2]);
+}
+
+void
+readscreensize(void)
+{
+	char buf[60+1], *field[5];
+	int fd, n;
+
+	fd = open("/dev/screen", OREAD);
+	if(fd < 0)
+		return;
+	n = read(fd, buf, sizeof(buf)-1);
+	close(fd);
+	if(n < 0)
+		return;
+	buf[n] = '\0';
+	if(tokenize(buf, field, 5) != 5)
+		return;
+	screensize.min.x = atoi(field[1]);
+	screensize.min.y = atoi(field[2]);
+	screensize.max.x = atoi(field[3]);
+	screensize.max.y = atoi(field[4]);
+}
+
+void
+mouse(int ctl, int x, int y, int buttons)
+{
+	if(ctl & Mclearbuttons)
+		screenmouse.buttons = 0;
+	else if(ctl & Msetbuttons)
+		screenmouse.buttons |= buttons;
+	else if(ctl & Mresetbuttons)
+		screenmouse.buttons &= ~buttons;
+	if(ctl & Mabsolute){
+		screenmouse.x = x;
+		screenmouse.y = y;
+	} else {
+		screenmouse.x += x;
+		screenmouse.y += y;
+	}
+	fprint(mousefd, "A%11d %11d %11d %11d",
+		screenmouse.x, screenmouse.y, screenmouse.buttons, 0);
+}
+
+void
+screensaver(int on)
+{
+	if(on){
+		int fd;
+
+		fd = open("/dev/mousectl", OWRITE);
+		if(fd < 0)
+			return;
+		fprint(fd, "blank");
+		close(fd);
+	} else {
+		mouse(Mrelative, 0, 0, 0);
+	}
+}
+
+static int map[][5] = {
+{0xef08,	1,	0x08, 0x00, 0x00},	// del
+{0xef09,	1,	0x09, 0x00, 0x00},	// tab?
+{0xef0d,	1,	0x0a, 0x00, 0x00},	// enter
+{0xef1b,	1,	0x1b, 0x00, 0x00},	// esc
+{0xef50,	3,	0xef, 0x80, 0x8d},	// home
+{0xef51,	3,	0xef, 0x80, 0x91},	// left
+{0xef52,	3,	0xef, 0x80, 0x8e},	// up
+{0xef53,	3,	0xef, 0x80, 0x92},	// right
+{0xef54,	3,	0xef, 0xa0, 0x80},	// down
+{0xef55,	3,	0xef, 0x80, 0x8f},	// page up
+{0xef56,	3,	0xef, 0x80, 0x93},	// page down
+{0xef57,	3,	0xef, 0x80, 0x98},	// end
+{0xef63,	3,	0xef, 0x80, 0x94},	// ins
+{0xefff,	1,	0x7f, 0x00, 0x00},	// del
+{0x0000,	0,	0x00, 0x00, 0x00},
+};
+
+void
+keyboard(int ctl, int key, int mod, int btn, int repeat)
+{
+	uchar b[3];
+	int i, n;
+
+	USED(btn);
+	USED(repeat);
+
+	for(i=0; map[i][0]; i++){
+		if(map[i][0]<key)
+			continue;
+		if(map[i][0]==key){
+			n = map[i][1];
+			switch(n){
+			case 3:
+				b[0] = map[i][2]&0xff;
+				b[1] = map[i][3]&0xff;
+				b[2] = map[i][4]&0xff;
+				break;
+			case 2:
+				b[0] = map[i][2]&0xff;
+				b[1] = map[i][3]&0xff;
+				break;
+			case 1:
+				b[0] = map[i][2]&0xff;
+				break;
+			}
+		} else {
+			if(key&~0x7F)
+				break;
+			n = 1;
+			if(mod == 2) {
+				switch(key) {
+				case 'h':
+					b[0] = 0x08;
+					break;
+				case 'u':
+					b[0] = 0x15;
+					break;
+				case 'w':
+					b[0] = 0x17;
+					break;
+				case 'd':
+					b[0] = 0x04;
+					break;
+				case 'a':
+					b[0] = 0x01;
+					break;
+				case 'e':
+					b[0] = 0x05;
+					break;
+				default:
+					b[0] = key&0x7F;
+				}
+			}else
+				b[0] = key&0x7F;
+		}
+		fprint(kbdfd, "%c%.*s%c", ctl==Kup?'R':'r', n, (char*)b, 0);
+		break;
+	}
+}
+
+int
+readsnarf(void)
+{
+	static Dir *olddir;
+	Dir *d;
+	int n, l;
+
+	if(snarffd < 0)
+		return 0;
+	d = dirfstat(snarffd);
+	if(d == nil)
+		return 0;
+	if(olddir == nil || olddir->qid.vers != d->qid.vers){
+		free(olddir);
+		olddir = d;
+	} else {
+		free(d);
+		return 0;
+	}
+
+	seek(snarffd, 0, 0);
+	for(l = 0;; l+=n){
+		sizemsg(&snarfbuf, 4+4+4 + l + 1024);
+		if((n = read(snarffd, snarfbuf.e - 1024, 1024)) <= 0)
+			break;
+	}
+	if(l <= 0){
+		sizemsg(&snarfbuf, 0);
+		return 0;
+	}
+	packmsg(&snarfbuf, "%4i%4i%4i", 1, Ftext, l);
+	snarfbuf.p -= 4+4+4;
+	return 1;
+}
+
+void
+io(void)
+{
+	static Msg m;
+	char size[32];
+	int clip[2] = {0};
+	int screenchange = 0;
+
+	int l, i, x, y, z, seq, on, key, btn, rep, mod, major, minjor, mark, n, cfmt;
+	uint msgid;
+
+	seq = 0;
+	for(;;){
+		sizemsg(&m, 4);
+		if(readn(0, m.p, 4) != 4)
+			sysfatal("read msg size failed: %r");
+		if(unpackmsg(&m, "%4i", &l) != 1)
+			sysfatal("short msg size");
+		sizemsg(&m, l);
+		if(readn(0, m.p, l) != l)
+			sysfatal("read msg failed: %r");
+		if(unpackmsg(&m, "%4i", &msgid) != 1)
+			sysfatal("short msg id");
+
+#define MSGID(c1,c2,c3,c4)	c1<<24|c2<<16|c3<<8|c4
+		switch(msgid){
+		default:
+		unhandled:
+			fprint(2, "unhandled: %c%c%c%c\n",
+				(char)((msgid>>24)&0xFF),
+				(char)((msgid>>16)&0xFF),
+				(char)((msgid>>8)&0xFF),
+				(char)((msgid>>0)&0xFF));
+			break;
+
+		case MSGID('B','a','r','r'):	/* hello from server */
+			if(unpackmsg(&m, "ier%2i%2i", &major, &minjor)!=2)
+				goto unhandled;
+			if(writemsg("Barrier%2i%2i%s", 1, 6, sysname())!=3)
+				return;
+			break;
+
+		case MSGID('Q','I','N','F'):	/* query info from server */
+			screenchange = 1;
+			break;
+
+		case MSGID('C','I','A','K'):	/* info acknowledge */
+			screenchange = 0;
+			break;
+
+		case MSGID('C','A','L','V'):
+			/* Keep alive ping */
+			if(writemsg("CALV")!=0)
+				return;
+			break;
+
+		case MSGID('C','N','O','P'):	/* nop */
+			break;
+
+		case MSGID('C','B','Y','E'):
+			return;
+
+		case MSGID('C','I','N','N'):	/* enter */
+			if(unpackmsg(&m, "%2i%2i%4i%2i", &x, &y, &seq, &mod)!=4)
+				goto unhandled;
+			mouse(Mabsolute | Mclearbuttons, x, y, 0);
+			screenchange = 1;
+			break;
+
+		case MSGID('C','C','L','P'):	/* grab clipboard */
+			if(unpackmsg(&m, "%1i", &i)!=1 || i < 0 || i >= nelem(clip))
+				goto unhandled;
+			clip[i] = 0;
+			break;
+		case MSGID('C','O','U','T'):	/* leave */
+			z = snarfbuf.e - snarfbuf.p;
+			if(z <= 0)
+				break;
+			for(i = 0; i < nelem(clip); i++){
+				if(!clip[i])
+					continue;
+				snprint(size, sizeof(size), "%d", z);
+				if(writemsg("DCLP%1i%4i%1i%s", i, seq, 1, size) != 4)
+					return;
+				for(l = 0; l < z; l += n){
+					n = z - l;
+					if(n > 1024)
+						n = 1024;
+					if(writemsg("DCLP%1i%4i%1i%*", i, seq, 2, n, snarfbuf.p+l) != 4)
+						return;
+				}
+				if(writemsg("DCLP%1i%4i%1i%s", i, seq, 3, "") != 4)
+					return;
+				clip[i] = 0;
+			}
+			sizemsg(&snarfbuf, 0);
+			break;
+
+		case MSGID('C','R','O','P'):	/* reset options */
+			break;
+
+		case MSGID('C','S','E','C'):	/* screensaver */
+			if(unpackmsg(&m, "%1i", &on)!=1)
+				goto unhandled;
+			screensaver(on);
+			break;
+
+		case MSGID('D','C','L','P'):	/* clipboard data */
+			if(unpackmsg(&m, "%1i%4i%1i", nil, nil, &mark)!=3)
+				goto unhandled;
+
+			switch(mark){
+			default:
+				goto unhandled;
+			case 1:
+				sizemsg(&snarfbuf, 0);
+				break;
+			case 2:
+				if(unpackmsg(&m, "%4i", &l) != 1 || m.e - m.p != l)
+					goto unhandled;
+				sizemsg(&snarfbuf, (snarfbuf.e - snarfbuf.p) + l);
+				memmove(snarfbuf.e - l, m.p, l);
+				break;
+			case 3:
+				if(unpackmsg(&snarfbuf, "%4i", nil) != 1)
+					break;
+				while(unpackmsg(&snarfbuf, "%4i%4i", &cfmt, &l) == 2){
+					if(snarfbuf.e - snarfbuf.p < l)
+						break;
+					if(cfmt != Ftext || l == 0){
+						m.p += l;
+						continue;
+					}
+					if(snarffd >= 0)
+						close(snarffd);
+					snarffd = create("/dev/snarf", ORDWR, 0600);
+					if(snarffd >= 0)
+						write(snarffd, snarfbuf.p, l);
+					break;
+				}
+				sizemsg(&snarfbuf, 0);
+				break;
+			}
+			/* skip readsnarf() */
+			continue;
+
+		case MSGID('D','K','D','N'):	/* keydown */
+			if(unpackmsg(&m, "%2i%2i%2i", &key, &mod, &btn)!=3)
+				goto unhandled;
+			keyboard(Kdown, key, mod, btn, 0);
+			break;
+
+		case MSGID('D','K','U','P'):	/* keyup */
+			if(unpackmsg(&m, "%2i%2i%2i", &key, &mod, &btn)!=3)
+				goto unhandled;
+			keyboard(Kup, key, mod, btn, 1);
+			break;
+
+		case MSGID('D','K','R','P'):	/* keyrepeat */
+			if(unpackmsg(&m, "%2i%2i%2i%2i", &key, &mod, &rep, &btn)!=4)
+				goto unhandled;
+			keyboard(Krepeat, key, mod, btn, rep);
+			break;
+
+		case MSGID('D','M','D','N'):	/* mousedown */
+			if(unpackmsg(&m, "%1i", &btn)!=1)
+				goto unhandled;
+			mouse(Msetbuttons, 0, 0, 1<<(btn-1));
+			screenchange = 1;
+			break;
+
+		case MSGID('D','M','U','P'):	/* mouseup */
+			if(unpackmsg(&m, "%1i", &btn)!=1)
+				goto unhandled;
+			mouse(Mresetbuttons, 0, 0, 1<<(btn-1));
+			screenchange = 1;
+			break;
+
+		case MSGID('D','M','M','V'):	/* mousemove */
+			if(unpackmsg(&m, "%2i%2i", &x, &y)!=2)
+				goto unhandled;
+			if(!screenchange)
+				mouse(Mabsolute, x, y, 0);
+			break;
+
+		case MSGID('D','M','R','M'):	/* mousemove relative */
+			if(unpackmsg(&m, "%2i%2i", &x, &y)!=2)
+				goto unhandled;
+			if(!screenchange)
+				mouse(Mrelative, x, y, 0);
+			break;
+
+		case MSGID('D', 'M', 'W', 'M'): /* mouse wheel */
+			if(unpackmsg(&m, "%2i%2i", &x, &y) != 2)
+				goto unhandled;
+			x = (x<<16)>>16;
+			y = (y<<16)>>16;
+			mouse(Msetbuttons, 0, 0, y>0? 1<<3: 1<<4);
+			mouse(Mresetbuttons, 0, 0, y>0? 1<<3: 1<<4);
+			break;
+
+		case MSGID('D','S','O','P'):	/* ??? */
+			break;
+		}
+
+		if(screenchange == 1){
+			screenchange = 2;
+
+			/* debounce */
+			sleep(50);
+
+			readscreensize();
+			readscreenmouse();
+			if(writemsg("DINF%2i%2i%2i%2i%2i%2i%2i", 
+				screensize.min.x,
+				screensize.min.y,
+				screensize.max.x,
+				screensize.max.y,
+				0,			/* size of warp zone (obsolete) */
+				screenmouse.x, 
+				screenmouse.y)!=7)	/* current mouse position */
+				return;
+		}
+
+		if(readsnarf()){
+			for(i=0; i<2; i++){
+				if(writemsg("CCLP%1i%4i", i, seq)!=2)
+					return;
+				clip[i] = 1;
+			}
+		}
+	}
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: tlsclient tcp!server!24800 %s\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char** argv)
+{
+	ARGBEGIN{
+	default:
+		usage();
+	}ARGEND
+
+	if(argc)
+		usage();
+
+	if((kbdfd = open("/dev/kbdin", OWRITE)) < 0)
+		sysfatal("open: %r");
+
+	if((mousefd = open("/dev/mousein", OWRITE)) < 0)
+		sysfatal("open: %r");
+
+	/* optional */
+	mouseinfd = open("/dev/mousein", OREAD);
+	snarffd = open("/dev/snarf", ORDWR);
+	readsnarf();
+
+	io();
+
+	exits(nil);
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,7 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=barrera
+OFILES=barrera.$O
+
+</sys/src/cmd/mkone