vncproto: handle control-letter and backspace
[fbvnc.git] / vncproto.c
blob9c4a505aa5dcf2ae4b2c61f9579a25aedf31e18e
1 #include <arpa/inet.h>
2 #include <ctype.h>
3 #include <fcntl.h>
4 #include <netdb.h>
5 #include <netinet/in.h>
6 #include <pwd.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/socket.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
15 #include "config.h"
16 #include "draw.h"
17 #include "fbvnc.h"
19 #define MAXRESOL (1 << 21)
21 /* vnc part */
22 static CARD16 cols = 0;
23 static CARD16 rows = 0;
25 /* and buffer for screen updates */
26 static CARD8 updates[MAXRESOL];
27 static int redraw;
29 int vncproto_init(char * addr, int port)
31 struct sockaddr_in si;
32 rfbProtocolVersionMsg vmsg;
33 rfbClientInitMsg clientinit;
34 rfbServerInitMsg serverinit;
35 rfbSetPixelFormatMsg pixformmsg;
36 struct hostent * he;
37 int servsock, i;
38 CARD32 i32;
39 CARD8 x;
40 #if 0
41 CARD8 passwd[128];
42 #endif
43 rfbSetEncodingsMsg * encodingsmsgp;
45 encodingsmsgp = (rfbSetEncodingsMsg *)malloc(sizeof(rfbSetEncodingsMsg)+sizeof(CARD32));
46 if (encodingsmsgp == NULL) {
47 perror("malloc: Cannot initiate communication");
48 return -1;
51 si.sin_family = AF_INET;
52 si.sin_port = htons(port);
53 he = gethostbyname(addr);
54 if (he)
55 si.sin_addr.s_addr = *((unsigned long *)(he->h_addr));
56 else if (inet_aton(addr, &(si.sin_addr)) < 0) {
57 fprintf(stderr, "Cannot resolve hostname");
58 return -1;
61 servsock = socket(PF_INET, SOCK_STREAM, 0);
62 if (servsock == -1) {
63 perror("Cannot create socket");
64 return -1;
66 if (connect(servsock, (struct sockaddr *)&si, sizeof(si)) < 0) {
67 perror("Cannot connect");
68 close(servsock);
69 return -1;
71 sprintf(vmsg, rfbProtocolVersionFormat, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
72 write(servsock, vmsg, sz_rfbProtocolVersionMsg);
73 read(servsock, vmsg, sz_rfbProtocolVersionMsg);
75 i32 = rfbConnFailed;
76 read(servsock, &i32, sizeof(i32));
77 i32 = ntohl(i32);
79 switch(i32) {
80 case rfbConnFailed: /* conn failed */
81 puts("Remote server says: Connection failed");
82 i32 = 0;
83 read(servsock, &i32, sizeof(i32));
84 while (i32-- && (read(servsock, &x, sizeof(x))==sizeof(x)))
85 printf ("%c", x);
86 puts("");
87 close(servsock);
88 return -1;
89 case rfbNoAuth:
90 break;
91 case rfbVncAuth:
92 puts ("We don't support DES yet");
93 close(servsock);
94 return -1;
95 #if 0
96 p = getpass("Enter password: ");
97 if (!p) {
98 close(servsock);
99 return -1;
101 #endif
104 /* ClientInitialisation */
105 clientinit.shared = 1; /* share */
106 write(servsock, &clientinit, sizeof(clientinit));
108 read(servsock, &serverinit, sizeof(serverinit));
110 fb_init();
111 cols = ntohs(serverinit.framebufferWidth);
112 if (cols > fb_cols())
113 cols = fb_cols();
114 rows = ntohs(serverinit.framebufferHeight);
115 if (rows > fb_rows())
116 rows = fb_rows();
118 i32 = ntohl(serverinit.nameLength);
119 for (i=0; i<i32; i++)
120 read(servsock, &x, 1);
122 pixformmsg.type = rfbSetPixelFormat;
123 pixformmsg.format.bitsPerPixel = 8;
124 pixformmsg.format.depth = 8;
125 pixformmsg.format.bigEndian = 0; /* don't care */
126 pixformmsg.format.trueColour = 1;
128 pixformmsg.format.redMax = htons(3);
129 pixformmsg.format.greenMax = htons(7);
130 pixformmsg.format.blueMax = htons(7);
132 pixformmsg.format.redShift = 0;
133 pixformmsg.format.greenShift = 2;
134 pixformmsg.format.blueShift = 5;
136 write(servsock, &pixformmsg, sizeof(pixformmsg));
138 encodingsmsgp->type = rfbSetEncodings;
139 encodingsmsgp->nEncodings = htons(1);
140 *((CARD32 *)((char *) encodingsmsgp +
141 sizeof(rfbSetEncodingsMsg))) = htonl(rfbEncodingRaw);
142 write(servsock, encodingsmsgp, sizeof(*encodingsmsgp)+sizeof(CARD32));
143 return servsock;
146 int vncproto_free(void)
148 fb_free();
149 return 0;
152 int request_vnc_refresh(int fd, int inc)
154 rfbFramebufferUpdateRequestMsg updreq;
155 updreq.type = rfbFramebufferUpdateRequest;
156 updreq.incremental = inc;
157 updreq.x = htons(0);
158 updreq.y = htons(0);
159 updreq.w = htons(cols);
160 updreq.h = htons(rows);
161 write(fd, &updreq, sizeof(updreq));
162 return 0;
165 static void update_fb(CARD8 *buffer, rfbRectangle r)
167 fbval_t slice[1 << 14];
168 int i, j;
169 for (i = 0; i < r.h; i++) {
170 for (j = 0; j < r.w; j++) {
171 unsigned char *p = &buffer[i * r.w + j];
172 slice[j] = fb_color(*p, *p, *p);
174 fb_set(r.y + i, r.x, slice, r.w);
178 int must_redraw(void)
180 int ret = redraw;
181 redraw = 0;
182 return ret;
185 int parse_vnc_in(int fd)
187 rfbFramebufferUpdateRectHeader uprect;
188 rfbServerToClientMsg msg;
189 rfbServerToClientMsg * vomsgp = &msg;
190 int i, j, k;
192 i = read (fd, vomsgp, sizeof(CARD8));
193 if (i != sizeof(CARD8))
194 return -1;
195 switch (vomsgp->type) {
196 case rfbFramebufferUpdate:
197 i = read(fd, (char *) vomsgp + sizeof(CARD8),
198 sizeof(rfbFramebufferUpdateMsg) - sizeof(CARD8));
199 break;
200 case rfbBell:
201 i = read(fd, (char *) vomsgp + sizeof(CARD8),
202 sizeof(rfbBellMsg) - sizeof(CARD8));
203 break;
204 case rfbServerCutText:
205 i = read(fd, (char *) vomsgp + sizeof(CARD8),
206 sizeof(rfbServerCutTextMsg) - sizeof(CARD8));
207 break;
208 default:
209 return -1;
211 switch (vomsgp->type) {
212 case rfbBell:
213 break;
215 case rfbFramebufferUpdate:
216 vomsgp->fu.nRects = ntohs(vomsgp->fu.nRects);
217 for (k=0; k<vomsgp->fu.nRects; k++) {
218 i = read(fd, &uprect, sizeof(uprect));
219 if (i != sizeof(uprect))
220 return -1;
221 uprect.r.x = ntohs(uprect.r.x);
222 uprect.r.y = ntohs(uprect.r.y);
223 uprect.r.w = ntohs(uprect.r.w);
224 uprect.r.h = ntohs(uprect.r.h);
225 if (uprect.r.x >= cols)
226 return -1;
227 if (uprect.r.x + uprect.r.w > cols)
228 return -1;
229 if (uprect.r.y >= rows)
230 return -1;
231 if (uprect.r.y + uprect.r.h > rows)
232 return -1;
233 for (i=0; i < uprect.r.w * uprect.r.h;) {
234 j = read(fd, updates + i,
235 uprect.r.w * uprect.r.h - i);
236 if (j == -1)
237 return 0;
238 i+=j;
240 update_fb(updates, uprect.r);
242 break;
244 return 0;
247 static int mr, mc; /* mouse position */
248 static int cmd; /* command mode */
249 static char mk[] = MOUSEKEYS;
251 static void handle_mouse(int fd, int c)
253 rfbPointerEventMsg me = {rfbPointerEvent, 0, 0, 0};
254 CARD8 mask = 0;
255 switch (strchr(mk, c) - mk) {
256 case 0:
257 mc -= MOUSESPEED;
258 break;
259 case 1:
260 mr += MOUSESPEED;
261 break;
262 case 2:
263 mr -= MOUSESPEED;
264 break;
265 case 3:
266 mc += MOUSESPEED;
267 break;
268 case 4:
269 mask = rfbButton1Mask;
270 break;
271 case 5:
272 mask = rfbButton2Mask;
273 break;
274 case 6:
275 mask = rfbButton3Mask;
276 break;
278 me.y = htons(MAX(0, MIN(rows - 1, mr)));
279 me.x = htons(MAX(0, MIN(cols - 1, mc)));
280 write(fd, &me, sizeof(me));
281 if (mask) {
282 me.buttonMask = mask;
283 write(fd, &me, sizeof(me));
284 me.buttonMask = 0;
285 write(fd, &me, sizeof(me));
289 static int press(int fd, int key, int down)
291 rfbKeyEventMsg ke = {rfbKeyEvent};
292 ke.key = htonl(key);
293 ke.down = down;
294 return write(fd, &ke, sizeof(ke));
297 int parse_kbd_in(int kbdfd, int fd)
299 char buf[1024];
300 int i, j;
301 int mod = 0;
303 if ((j = read(kbdfd, buf, sizeof(buf))) <= 0 )
304 return -1;
305 for (i = 0; i < j; i++) {
306 int k = -1;
307 if (!cmd) {
308 switch (buf[i]) {
309 case '\x08':
310 case '\x7f':
311 k = 0xff08;
312 break;
313 case '\x09':
314 k = 0xff09;
315 break;
316 case '\x1b':
317 k = 0xff1b;
318 break;
319 case '\x0d':
320 k = 0xff0d;
321 break;
322 case CMDKEY:
323 cmd = 1;
324 break;
325 default:
326 k = (unsigned char) buf[i];
328 } else {
329 if (strchr(mk, buf[i])) {
330 handle_mouse(fd, buf[i]);
331 continue;
333 switch(buf[i]) {
334 case CMDKEY:
335 k = (unsigned char) buf[i];
336 break;
337 case 'q':
338 case 'i':
339 cmd = 0;
340 break;
341 case '\x03': /* cmd ^c */
342 return -1;
343 case 'r':
344 case 'L':
345 redraw = 1;
346 break;
349 if (isupper(k) || strchr(":\"<>?{}|+_()*&^%$#@!~", k))
350 mod = 0xffe1;
351 if (k >= 1 && k <= 26) {
352 k = 'a' + k - 1;
353 mod = 0xffe3;
355 if (k > 0) {
356 if (mod)
357 press(fd, mod, 1);
358 press(fd, k, 1);
359 press(fd, k, 0);
360 if (mod)
361 press(fd, mod, 0);
364 return 0;