]> git.proxmox.com Git - spiceterm.git/blob - spiceterm.c
22bde657628028c279c9db647668976fad821056
[spiceterm.git] / spiceterm.c
1 /*
2
3 Copyright (C) 2007-2011 Proxmox Server Solutions GmbH
4
5 Copyright: spiceterm 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 <dietmar@proxmox.com>
22
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32 #include <pty.h> /* for openpty and forkpty */
33 #include <string.h>
34 #include <errno.h>
35 #include <sys/ioctl.h>
36 #include <sys/wait.h>
37 #include <signal.h>
38 #include <locale.h>
39
40 #include "spiceterm.h"
41 #include "glyphs.h"
42
43 #include <spice.h>
44 #include <spice/enums.h>
45 #include <spice/macros.h>
46 #include <spice/qxl_dev.h>
47
48 #include "test_display_base.h"
49
50 /* define this for debugging */
51 //#define DEBUG
52
53 #define TERM "xterm"
54
55 #define TERMIDCODE "[?1;2c" // vt100 ID
56
57 #define CHECK_ARGC(argc,argv,i) if (i >= argc-1) { \
58 fprintf (stderr, "ERROR: not enough arguments for: %s\n", argv[i]); \
59 print_usage (NULL); \
60 exit(1); \
61 }
62
63 /* these colours are from linux kernel drivers/char/vt.c */
64
65 static int idle_timeout = 1;
66
67 unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
68 8,12,10,14, 9,13,11,15 };
69
70
71 static void
72 print_usage (const char *msg)
73 {
74 if (msg) { fprintf (stderr, "ERROR: %s\n", msg); }
75 fprintf (stderr, "USAGE: vncterm [vncopts] [-c command [args]]\n");
76 }
77
78 /* Convert UCS2 to UTF8 sequence, trailing zero */
79 static int
80 ucs2_to_utf8 (unicode c, char *out)
81 {
82 if (c < 0x80) {
83 out[0] = c; // 0*******
84 out[1] = 0;
85 return 1;
86 } else if (c < 0x800) {
87 out[0] = 0xc0 | (c >> 6); // 110***** 10******
88 out[1] = 0x80 | (c & 0x3f);
89 out[2] = 0;
90 return 2;
91 } else {
92 out[0] = 0xe0 | (c >> 12); // 1110**** 10****** 10******
93 out[1] = 0x80 | ((c >> 6) & 0x3f);
94 out[2] = 0x80 | (c & 0x3f);
95 out[3] = 0;
96 return 3;
97 }
98
99 return 0;
100 }
101
102
103 static void
104 draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib)
105 {
106 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) {
107 return;
108 }
109
110
111 int ec = vt_fontmap[ch];
112
113 test_draw_update_char(vt->screen, x, y, ec, attrib);
114 }
115
116 static void
117 vncterm_update_xy (vncTerm *vt, int x, int y)
118 {
119 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
120
121 int y1 = (vt->y_base + y) % vt->total_height;
122 int y2 = y1 - vt->y_displ;
123 if (y2 < 0) {
124 y2 += vt->total_height;
125 }
126 if (y2 < vt->height) {
127 TextCell *c = &vt->cells[y1 * vt->width + x];
128 draw_char_at (vt, x, y2, c->ch, c->attrib);
129 }
130 }
131
132 static void
133 vncterm_clear_xy (vncTerm *vt, int x, int y)
134 {
135 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
136
137 int y1 = (vt->y_base + y) % vt->total_height;
138 int y2 = y1 - vt->y_displ;
139 if (y2 < 0) {
140 y2 += vt->total_height;
141 }
142 if (y2 < vt->height) {
143 TextCell *c = &vt->cells[y1 * vt->width + x];
144 c->ch = ' ';
145 c->attrib = vt->default_attrib;
146 c->attrib.fgcol = vt->cur_attrib.fgcol;
147 c->attrib.bgcol = vt->cur_attrib.bgcol;
148
149 draw_char_at (vt, x, y, c->ch, c->attrib);
150 }
151 }
152
153 static void
154 vncterm_show_cursor (vncTerm *vt, int show)
155 {
156 int x = vt->cx;
157 if (x >= vt->width) {
158 x = vt->width - 1;
159 }
160
161 int y1 = (vt->y_base + vt->cy) % vt->total_height;
162 int y = y1 - vt->y_displ;
163 if (y < 0) {
164 y += vt->total_height;
165 }
166
167 if (y < vt->height) {
168
169 TextCell *c = &vt->cells[y1 * vt->width + x];
170
171 if (show) {
172 TextAttributes attrib = vt->default_attrib;
173 attrib.invers = !(attrib.invers); /* invert fg and bg */
174 draw_char_at (vt, x, y, c->ch, attrib);
175 } else {
176 draw_char_at (vt, x, y, c->ch, c->attrib);
177 }
178 }
179 }
180
181 static void
182 vncterm_refresh (vncTerm *vt)
183 {
184 int x, y, y1;
185
186 // rfbFillRect (vt->screen, 0, 0, vt->maxx, vt->maxy, vt->default_attrib.bgcol);
187
188 y1 = vt->y_displ;
189 for(y = 0; y < vt->height; y++) {
190 TextCell *c = vt->cells + y1 * vt->width;
191 for(x = 0; x < vt->width; x++) {
192 draw_char_at (vt, x, y, c->ch, c->attrib);
193 c++;
194 }
195 if (++y1 == vt->total_height)
196 y1 = 0;
197 }
198 //rfbMarkRectAsModified (vt->screen, 0, 0, vt->maxx, vt->maxy);
199
200 vncterm_show_cursor (vt, 1);
201 }
202
203 static void
204 vncterm_scroll_down (vncTerm *vt, int top, int bottom, int lines)
205 {
206 if ((top + lines) >= bottom) {
207 lines = bottom - top -1;
208 }
209
210 if (top < 0 || bottom > vt->height || top >= bottom || lines < 1) {
211 return;
212 }
213
214 g_error("vncterm_scroll_down not implemented");
215
216 /*
217 int h = lines * 16;
218 int y0 = top*16;
219 int y1 = y0 + h;
220 int y2 = bottom*16;
221 int rowstride = vt->screen->paddedWidthInBytes;
222 int rows = (bottom - top - lines)*16;
223
224 char *in = vt->screen->frameBuffer+y0*rowstride;
225 char *out = vt->screen->frameBuffer+y1*rowstride;
226 memmove(out,in, rowstride*rows);
227
228 memset(vt->screen->frameBuffer+y0*rowstride, 0, h*rowstride);
229 rfbMarkRectAsModified (vt->screen, 0, y0, vt->screen->width, y2);
230
231 int i;
232 for(i = bottom - top - lines - 1; i >= 0; i--) {
233 int src = ((vt->y_base + top + i) % vt->total_height)*vt->width;
234 int dst = ((vt->y_base + top + lines + i) % vt->total_height)*vt->width;
235
236 memmove(vt->cells + dst, vt->cells + src, vt->width*sizeof (TextCell));
237 }
238
239 for (i = 0; i < lines; i++) {
240 int j;
241 TextCell *c = vt->cells + ((vt->y_base + top + i) % vt->total_height)*vt->width;
242 for(j = 0; j < vt->width; j++) {
243 c->attrib = vt->default_attrib;
244 c->ch = ' ';
245 c++;
246 }
247 }
248 */
249 }
250
251 static void
252 vncterm_scroll_up (vncTerm *vt, int top, int bottom, int lines, int moveattr)
253 {
254 if ((top + lines) >= bottom) {
255 lines = bottom - top - 1;
256 }
257
258 if (top < 0 || bottom > vt->height || top >= bottom || lines < 1) {
259 return;
260 }
261
262 g_error("vncterm_scroll_down not implemented");
263
264 /*
265 int h = lines * 16;
266 int y0 = top*16;
267 int y1 = (top + lines)*16;
268 int y2 = bottom*16;
269 int rowstride = vt->screen->paddedWidthInBytes;
270 int rows = (bottom - top - lines)*16;
271
272 char *in = vt->screen->frameBuffer+y1*rowstride;
273 char *out = vt->screen->frameBuffer+y0*rowstride;
274 memmove(out,in, rowstride*rows);
275
276 memset(vt->screen->frameBuffer+(y2-h)*rowstride, 0, h*rowstride);
277
278 rfbMarkRectAsModified (vt->screen, 0, y0, vt->screen->width, y2);
279
280 if (!moveattr) return;
281
282 // move attributes
283
284 int i;
285 for(i = 0; i < (bottom - top - lines); i++) {
286 int dst = ((vt->y_base + top + i) % vt->total_height)*vt->width;
287 int src = ((vt->y_base + top + lines + i) % vt->total_height)*vt->width;
288
289 memmove(vt->cells + dst, vt->cells + src, vt->width*sizeof (TextCell));
290 }
291
292 for (i = 1; i <= lines; i++) {
293 int j;
294 TextCell *c = vt->cells + ((vt->y_base + bottom - i) % vt->total_height)*vt->width;
295 for(j = 0; j < vt->width; j++) {
296 c->attrib = vt->default_attrib;
297 c->ch = ' ';
298 c++;
299 }
300 }
301 */
302 }
303
304 static void
305 vncterm_virtual_scroll (vncTerm *vt, int lines)
306 {
307 if (vt->altbuf || lines == 0) return;
308
309 if (lines < 0) {
310 lines = -lines;
311 int i = vt->scroll_height;
312 if (i > vt->total_height - vt->height)
313 i = vt->total_height - vt->height;
314 int y1 = vt->y_base - i;
315 if (y1 < 0)
316 y1 += vt->total_height;
317 for(i = 0; i < lines; i++) {
318 if (vt->y_displ == y1) break;
319 if (--vt->y_displ < 0) {
320 vt->y_displ = vt->total_height - 1;
321 }
322 }
323 } else {
324 int i;
325 for(i = 0; i < lines; i++) {
326 if (vt->y_displ == vt->y_base) break;
327 if (++vt->y_displ == vt->total_height) {
328 vt->y_displ = 0;
329 }
330 }
331
332 }
333
334 vncterm_refresh (vt);
335 }
336 static void
337 vncterm_respond_esc (vncTerm *vt, const char *esc)
338 {
339 int len = strlen (esc);
340 int i;
341
342 if (vt->ibuf_count < (IBUFSIZE - 1 - len)) {
343 vt->ibuf[vt->ibuf_count++] = 27;
344 for (i = 0; i < len; i++) {
345 vt->ibuf[vt->ibuf_count++] = esc[i];
346 }
347 }
348 }
349
350 static void
351 vncterm_put_lf (vncTerm *vt)
352 {
353 if (vt->cy + 1 == vt->region_bottom) {
354
355 if (vt->altbuf || vt->region_top != 0 || vt->region_bottom != vt->height) {
356 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, 1, 1);
357 return;
358 }
359
360 if (vt->y_displ == vt->y_base) {
361 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, 1, 0);
362 }
363
364 if (vt->y_displ == vt->y_base) {
365 if (++vt->y_displ == vt->total_height) {
366 vt->y_displ = 0;
367 }
368 }
369
370 if (++vt->y_base == vt->total_height) {
371 vt->y_base = 0;
372 }
373
374 if (vt->scroll_height < vt->total_height) {
375 vt->scroll_height++;
376 }
377
378 int y1 = (vt->y_base + vt->height - 1) % vt->total_height;
379 TextCell *c = &vt->cells[y1 * vt->width];
380 int x;
381 for (x = 0; x < vt->width; x++) {
382 c->ch = ' ';
383 c->attrib = vt->default_attrib;
384 c++;
385 }
386
387 // fprintf (stderr, "BASE: %d DISPLAY %d\n", vt->y_base, vt->y_displ);
388
389 } else if (vt->cy < vt->height - 1) {
390 vt->cy += 1;
391 }
392 }
393
394
395 static void
396 vncterm_csi_m (vncTerm *vt)
397 {
398 int i;
399
400 for (i = 0; i < vt->esc_count; i++) {
401 switch (vt->esc_buf[i]) {
402 case 0: /* reset all console attributes to default */
403 vt->cur_attrib = vt->default_attrib;
404 break;
405 case 1:
406 vt->cur_attrib.bold = 1;
407 break;
408 case 4:
409 vt->cur_attrib.uline = 1;
410 break;
411 case 5:
412 vt->cur_attrib.blink = 1;
413 break;
414 case 7:
415 vt->cur_attrib.invers = 1;
416 break;
417 case 8:
418 vt->cur_attrib.unvisible = 1;
419 break;
420 case 10:
421 vt->cur_enc = LAT1_MAP;
422 // fixme: dispaly controls = 0 ?
423 // fixme: toggle meta = 0 ?
424 break;
425 case 11:
426 vt->cur_enc = IBMPC_MAP;
427 // fixme: dispaly controls = 1 ?
428 // fixme: toggle meta = 0 ?
429 break;
430 case 12:
431 vt->cur_enc = IBMPC_MAP;
432 // fixme: dispaly controls = 1 ?
433 // fixme: toggle meta = 1 ?
434 break;
435 case 22:
436 vt->cur_attrib.bold = 0;
437 break;
438 case 24:
439 vt->cur_attrib.uline = 0;
440 break;
441 case 25:
442 vt->cur_attrib.blink = 0;
443 break;
444 case 27:
445 vt->cur_attrib.invers = 0;
446 break;
447 case 28:
448 vt->cur_attrib.unvisible = 0;
449 break;
450 case 30:
451 case 31:
452 case 32:
453 case 33:
454 case 34:
455 case 35:
456 case 36:
457 case 37:
458 /* set foreground color */
459 vt->cur_attrib.fgcol = color_table [vt->esc_buf[i] - 30];
460 break;
461 case 38:
462 /* reset color to default, enable underline */
463 vt->cur_attrib.fgcol = vt->default_attrib.fgcol;
464 vt->cur_attrib.uline = 1;
465 break;
466 case 39:
467 /* reset color to default, disable underline */
468 vt->cur_attrib.fgcol = vt->default_attrib.fgcol;
469 vt->cur_attrib.uline = 0;
470 break;
471 case 40:
472 case 41:
473 case 42:
474 case 43:
475 case 44:
476 case 45:
477 case 46:
478 case 47:
479 /* set background color */
480 vt->cur_attrib.bgcol = color_table [vt->esc_buf[i] - 40];
481 break;
482 case 49:
483 /* reset background color */
484 vt->cur_attrib.bgcol = vt->default_attrib.bgcol;
485 break;
486 default:
487 fprintf (stderr, "unhandled ESC[%d m code\n",vt->esc_buf[i]);
488 //fixme: implement
489 }
490 }
491 }
492
493 static void
494 vncterm_save_cursor (vncTerm *vt)
495 {
496 vt->cx_saved = vt->cx;
497 vt->cy_saved = vt->cy;
498 vt->cur_attrib_saved = vt->cur_attrib;
499 vt->charset_saved = vt->charset;
500 vt->g0enc_saved = vt->g0enc;
501 vt->g1enc_saved = vt->g1enc;
502 vt->cur_enc_saved = vt->cur_enc;
503 }
504
505 static void
506 vncterm_restore_cursor (vncTerm *vt)
507 {
508 vt->cx = vt->cx_saved;
509 vt->cy = vt->cy_saved;
510 vt->cur_attrib = vt->cur_attrib_saved;
511 vt->charset = vt->charset_saved;
512 vt->g0enc = vt->g0enc_saved;
513 vt->g1enc = vt->g1enc_saved;
514 vt->cur_enc = vt->cur_enc_saved;
515 }
516
517 static void
518 vncterm_set_alternate_buffer (vncTerm *vt, int on_off)
519 {
520 int x, y;
521
522 vt->y_displ = vt->y_base;
523
524 if (on_off) {
525
526 if (vt->altbuf) return;
527
528 vt->altbuf = 1;
529
530 /* alternate buffer & cursor */
531
532 vncterm_save_cursor (vt);
533 /* save screen to altcels */
534 for (y = 0; y < vt->height; y++) {
535 int y1 = (vt->y_base + y) % vt->total_height;
536 for (x = 0; x < vt->width; x++) {
537 vt->altcells[y*vt->width + x] = vt->cells[y1*vt->width + x];
538 }
539 }
540
541 /* clear screen */
542 for (y = 0; y <= vt->height; y++) {
543 for (x = 0; x < vt->width; x++) {
544 vncterm_clear_xy (vt, x, y);
545 }
546 }
547
548 } else {
549
550 if (vt->altbuf == 0) return;
551
552 vt->altbuf = 0;
553
554 /* restore saved data */
555 for (y = 0; y < vt->height; y++) {
556 int y1 = (vt->y_base + y) % vt->total_height;
557 for (x = 0; x < vt->width; x++) {
558 vt->cells[y1*vt->width + x] = vt->altcells[y*vt->width + x];
559 }
560 }
561
562 vncterm_restore_cursor (vt);
563 }
564
565 vncterm_refresh (vt);
566 }
567
568 static void
569 vncterm_set_mode (vncTerm *vt, int on_off)
570 {
571 int i;
572
573 for (i = 0; i <= vt->esc_count; i++) {
574 if (vt->esc_ques) { /* DEC private modes set/reset */
575 switch(vt->esc_buf[i]) {
576 case 10: /* X11 mouse reporting on/off */
577 case 1000:
578 vt->report_mouse = on_off;
579 break;
580 case 1049: /* start/end special app mode (smcup/rmcup) */
581 vncterm_set_alternate_buffer (vt, on_off);
582 break;
583 case 25: /* Cursor on/off */
584 case 9: /* X10 mouse reporting on/off */
585 case 6: /* Origin relative/absolute */
586 case 1: /* Cursor keys in appl mode*/
587 case 5: /* Inverted screen on/off */
588 case 7: /* Autowrap on/off */
589 case 8: /* Autorepeat on/off */
590 break;
591 }
592 } else { /* ANSI modes set/reset */
593 /* fixme: implement me */
594 }
595 }
596 }
597
598 static void
599 vncterm_gotoxy (vncTerm *vt, int x, int y)
600 {
601 /* verify all boundaries */
602
603 if (x < 0) {
604 x = 0;
605 }
606
607 if (x >= vt->width) {
608 x = vt->width - 1;
609 }
610
611 vt->cx = x;
612
613 if (y < 0) {
614 y = 0;
615 }
616
617 if (y >= vt->height) {
618 y = vt->height - 1;
619 }
620
621 vt->cy = y;
622 }
623
624 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
625 EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
626 ESpalette, ESidquery, ESosc1, ESosc2};
627
628 static void
629 vncterm_putchar (vncTerm *vt, unicode ch)
630 {
631 int x, y, i, c;
632
633 #ifdef DEBUG
634 if (!vt->tty_state)
635 fprintf (stderr, "CHAR:%2d: %4x '%c' (cur_enc %d) %d %d\n", vt->tty_state, ch, ch, vt->cur_enc, vt->cx, vt->cy);
636 #endif
637
638 switch(vt->tty_state) {
639 case ESesc:
640 vt->tty_state = ESnormal;
641 switch (ch) {
642 case '[':
643 vt->tty_state = ESsquare;
644 break;
645 case ']':
646 vt->tty_state = ESnonstd;
647 break;
648 case '%':
649 vt->tty_state = ESpercent;
650 break;
651 case '7':
652 vncterm_save_cursor (vt);
653 break;
654 case '8':
655 vncterm_restore_cursor (vt);
656 break;
657 case '(':
658 vt->tty_state = ESsetG0; // SET G0
659 break;
660 case ')':
661 vt->tty_state = ESsetG1; // SET G1
662 break;
663 case 'M':
664 /* cursor up (ri) */
665 if (vt->cy == vt->region_top)
666 vncterm_scroll_down (vt, vt->region_top, vt->region_bottom, 1);
667 else if (vt->cy > 0) {
668 vt->cy--;
669 }
670 break;
671 case '>':
672 /* numeric keypad - ignored */
673 break;
674 case '=':
675 /* appl. keypad - ignored */
676 break;
677 default:
678 #ifdef DEBUG
679 fprintf(stderr, "got unhandled ESC%c %d\n", ch, ch);
680 #endif
681 break;
682 }
683 break;
684 case ESnonstd: /* Operating System Controls */
685 vt->tty_state = ESnormal;
686
687 switch (ch) {
688 case 'P': /* palette escape sequence */
689 for(i = 0; i < MAX_ESC_PARAMS; i++) {
690 vt->esc_buf[i] = 0;
691 }
692
693 vt->esc_count = 0;
694 vt->tty_state = ESpalette;
695 break;
696 case 'R': /* reset palette */
697 // fixme: reset_palette(vc);
698 break;
699 case '0':
700 case '1':
701 case '2':
702 case '4':
703 vt->osc_cmd = ch;
704 vt->osc_textbuf[0] = 0;
705 vt->tty_state = ESosc1;
706 break;
707 default:
708 #ifdef DEBUG
709 fprintf (stderr, "unhandled OSC %c\n", ch);
710 #endif
711 vt->tty_state = ESnormal;
712 break;
713 }
714 break;
715 case ESosc1:
716 vt->tty_state = ESnormal;
717 if (ch == ';') {
718 vt->tty_state = ESosc2;
719 } else {
720 #ifdef DEBUG
721 fprintf (stderr, "got illegal OSC sequence\n");
722 #endif
723 }
724 break;
725 case ESosc2:
726 if (ch != 0x9c && ch != 7) {
727 int i = 0;
728 while (vt->osc_textbuf[i]) i++;
729 vt->osc_textbuf[i++] = ch;
730 vt->osc_textbuf[i] = 0;
731 } else {
732 #ifdef DEBUG
733 fprintf (stderr, "OSC:%c:%s\n", vt->osc_cmd, vt->osc_textbuf);
734 #endif
735 vt->tty_state = ESnormal;
736 }
737 break;
738 case ESpalette:
739 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')
740 || (ch >= 'a' && ch <= 'f')) {
741 vt->esc_buf[vt->esc_count++] = (ch > '9' ? (ch & 0xDF) - 'A' + 10 : ch - '0');
742 if (vt->esc_count == 7) {
743 // fixme: this does not work - please test
744 /*
745 rfbColourMap *cmap =&vt->screen->colourMap;
746
747 int i = color_table[vt->esc_buf[0]] * 3, j = 1;
748 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
749 cmap->data.bytes[i++] += vt->esc_buf[j++];
750 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
751 cmap->data.bytes[i++] += vt->esc_buf[j++];
752 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
753 cmap->data.bytes[i] += vt->esc_buf[j];
754 */
755 //set_palette(vc); ?
756
757 vt->tty_state = ESnormal;
758 }
759 } else
760 vt->tty_state = ESnormal;
761 break;
762 case ESsquare:
763 for(i = 0; i < MAX_ESC_PARAMS; i++) {
764 vt->esc_buf[i] = 0;
765 }
766
767 vt->esc_count = 0;
768 vt->esc_has_par = 0;
769 vt->tty_state = ESgetpars;
770
771 if (ch == '>') {
772 vt->tty_state = ESidquery;
773 break;
774 }
775
776 if ((vt->esc_ques = (ch == '?'))) {
777 break;
778 }
779 case ESgetpars:
780 if (ch >= '0' && ch <= '9') {
781 vt->esc_has_par = 1;
782 if (vt->esc_count < MAX_ESC_PARAMS) {
783 vt->esc_buf[vt->esc_count] = vt->esc_buf[vt->esc_count] * 10 + ch - '0';
784 }
785 break;
786 } else if (ch == ';') {
787 vt->esc_count++;
788 break;
789 } else {
790 if (vt->esc_has_par) {
791 vt->esc_count++;
792 }
793 vt->tty_state = ESgotpars;
794 }
795 case ESgotpars:
796
797 vt->tty_state = ESnormal;
798
799 #ifdef DEBUG
800 char *qes = vt->esc_ques ? "?" : "";
801 if (vt->esc_count == 0) {
802 fprintf(stderr, "ESC[%s%c\n", qes, ch);
803 } else if (vt->esc_count == 1) {
804 fprintf(stderr, "ESC[%s%d%c\n", qes, vt->esc_buf[0], ch);
805 } else {
806 int i;
807 fprintf(stderr, "ESC[%s%d", qes, vt->esc_buf[0]);
808 for (i = 1; i < vt->esc_count; i++) {
809 fprintf(stderr, ";%d", vt->esc_buf[i]);
810 }
811 fprintf (stderr, "%c\n", ch);
812 }
813 #endif
814
815 switch (ch) {
816 case 'h':
817 vncterm_set_mode (vt, 1);
818 break;
819 case 'l':
820 vncterm_set_mode (vt, 0);
821 break;
822 case 'm':
823 if (!vt->esc_count) {
824 vt->esc_count++; // default parameter 0
825 }
826 vncterm_csi_m (vt);
827 break;
828 case 'n':
829 /* report cursor position */
830 /* TODO: send ESC[row;colR */
831 break;
832 case 'A':
833 /* move cursor up */
834 if (vt->esc_buf[0] == 0) {
835 vt->esc_buf[0] = 1;
836 }
837 vt->cy -= vt->esc_buf[0];
838 if (vt->cy < 0) {
839 vt->cy = 0;
840 }
841 break;
842 case 'B':
843 case 'e':
844 /* move cursor down */
845 if (vt->esc_buf[0] == 0) {
846 vt->esc_buf[0] = 1;
847 }
848 vt->cy += vt->esc_buf[0];
849 if (vt->cy >= vt->height) {
850 vt->cy = vt->height - 1;
851 }
852 break;
853 case 'C':
854 case 'a':
855 /* move cursor right */
856 if (vt->esc_buf[0] == 0) {
857 vt->esc_buf[0] = 1;
858 }
859 vt->cx += vt->esc_buf[0];
860 if (vt->cx >= vt->width) {
861 vt->cx = vt->width - 1;
862 }
863 break;
864 case 'D':
865 /* move cursor left */
866 if (vt->esc_buf[0] == 0) {
867 vt->esc_buf[0] = 1;
868 }
869 vt->cx -= vt->esc_buf[0];
870 if (vt->cx < 0) {
871 vt->cx = 0;
872 }
873 break;
874 case 'G':
875 case '`':
876 /* move cursor to column */
877 vncterm_gotoxy (vt, vt->esc_buf[0] - 1, vt->cy);
878 break;
879 case 'd':
880 /* move cursor to row */
881 vncterm_gotoxy (vt, vt->cx , vt->esc_buf[0] - 1);
882 break;
883 case 'f':
884 case 'H':
885 /* move cursor to row, column */
886 vncterm_gotoxy (vt, vt->esc_buf[1] - 1, vt->esc_buf[0] - 1);
887 break;
888 case 'J':
889 switch (vt->esc_buf[0]) {
890 case 0:
891 /* clear to end of screen */
892 for (y = vt->cy; y < vt->height; y++) {
893 for (x = 0; x < vt->width; x++) {
894 if (y == vt->cy && x < vt->cx) {
895 continue;
896 }
897 vncterm_clear_xy (vt, x, y);
898 }
899 }
900 break;
901 case 1:
902 /* clear from beginning of screen */
903 for (y = 0; y <= vt->cy; y++) {
904 for (x = 0; x < vt->width; x++) {
905 if (y == vt->cy && x > vt->cx) {
906 break;
907 }
908 vncterm_clear_xy (vt, x, y);
909 }
910 }
911 break;
912 case 2:
913 /* clear entire screen */
914 for (y = 0; y <= vt->height; y++) {
915 for (x = 0; x < vt->width; x++) {
916 vncterm_clear_xy (vt, x, y);
917 }
918 }
919 break;
920 }
921 break;
922 case 'K':
923 switch (vt->esc_buf[0]) {
924 case 0:
925 /* clear to eol */
926 for(x = vt->cx; x < vt->width; x++) {
927 vncterm_clear_xy (vt, x, vt->cy);
928 }
929 break;
930 case 1:
931 /* clear from beginning of line */
932 for (x = 0; x <= vt->cx; x++) {
933 vncterm_clear_xy (vt, x, vt->cy);
934 }
935 break;
936 case 2:
937 /* clear entire line */
938 for(x = 0; x < vt->width; x++) {
939 vncterm_clear_xy (vt, x, vt->cy);
940 }
941 break;
942 }
943 break;
944 case 'L':
945 /* insert line */
946 c = vt->esc_buf[0];
947
948 if (c > vt->height - vt->cy)
949 c = vt->height - vt->cy;
950 else if (!c)
951 c = 1;
952
953 vncterm_scroll_down (vt, vt->cy, vt->region_bottom, c);
954 break;
955 case 'M':
956 /* delete line */
957 c = vt->esc_buf[0];
958
959 if (c > vt->height - vt->cy)
960 c = vt->height - vt->cy;
961 else if (!c)
962 c = 1;
963
964 vncterm_scroll_up (vt, vt->cy, vt->region_bottom, c, 1);
965 break;
966 case 'T':
967 /* scroll down */
968 c = vt->esc_buf[0];
969 if (!c) c = 1;
970 vncterm_scroll_down (vt, vt->region_top, vt->region_bottom, c);
971 break;
972 case 'S':
973 /* scroll up */
974 c = vt->esc_buf[0];
975 if (!c) c = 1;
976 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, c, 1);
977 break;
978 case 'P':
979 /* delete c character */
980 c = vt->esc_buf[0];
981
982 if (c > vt->width - vt->cx)
983 c = vt->width - vt->cx;
984 else if (!c)
985 c = 1;
986
987 for (x = vt->cx; x < vt->width - c; x++) {
988 int y1 = (vt->y_base + vt->cy) % vt->total_height;
989 TextCell *dst = &vt->cells[y1 * vt->width + x];
990 TextCell *src = dst + c;
991 *dst = *src;
992 vncterm_update_xy (vt, x + c, vt->cy);
993 src->ch = ' ';
994 src->attrib = vt->default_attrib;
995 vncterm_update_xy (vt, x, vt->cy);
996 }
997 break;
998 case 's':
999 /* save cursor position */
1000 vncterm_save_cursor (vt);
1001 break;
1002 case 'u':
1003 /* restore cursor position */
1004 vncterm_restore_cursor (vt);
1005 break;
1006 case 'X':
1007 /* erase c characters */
1008 c = vt->esc_buf[0];
1009 if (!c) c = 1;
1010
1011 if (c > (vt->width - vt->cx)) c = vt->width - vt->cx;
1012
1013 for(i = 0; i < c; i++) {
1014 vncterm_clear_xy (vt, vt->cx + i, vt->cy);
1015 }
1016 break;
1017 case '@':
1018 /* insert c character */
1019 c = vt->esc_buf[0];
1020 if (c > (vt->width - vt->cx)) {
1021 c = vt->width - vt->cx;
1022 }
1023 if (!c) c = 1;
1024
1025 for (x = vt->width - c; x >= vt->cx; x--) {
1026 int y1 = (vt->y_base + vt->cy) % vt->total_height;
1027 TextCell *src = &vt->cells[y1 * vt->width + x];
1028 TextCell *dst = src + c;
1029 *dst = *src;
1030 vncterm_update_xy (vt, x + c, vt->cy);
1031 src->ch = ' ';
1032 src->attrib = vt->cur_attrib;
1033 vncterm_update_xy (vt, x, vt->cy);
1034 }
1035
1036 break;
1037 case 'r':
1038 /* set region */
1039 if (!vt->esc_buf[0])
1040 vt->esc_buf[0]++;
1041 if (!vt->esc_buf[1])
1042 vt->esc_buf[1] = vt->height;
1043 /* Minimum allowed region is 2 lines */
1044 if (vt->esc_buf[0] < vt->esc_buf[1] &&
1045 vt->esc_buf[1] <= vt->height) {
1046 vt->region_top = vt->esc_buf[0] - 1;
1047 vt->region_bottom = vt->esc_buf[1];
1048 vt->cx = 0;
1049 vt->cy = vt->region_top;
1050 #ifdef DEBUG
1051 fprintf (stderr, "set region %d %d\n", vt->region_top, vt->region_bottom);
1052 #endif
1053 }
1054
1055 break;
1056 default:
1057 #ifdef DEBUG
1058 if (vt->esc_count == 0) {
1059 fprintf(stderr, "unhandled escape ESC[%s%c\n", qes, ch);
1060 } else if (vt->esc_count == 1) {
1061 fprintf(stderr, "unhandled escape ESC[%s%d%c\n", qes, vt->esc_buf[0], ch);
1062 } else {
1063 int i;
1064 fprintf(stderr, "unhandled escape ESC[%s%d", qes, vt->esc_buf[0]);
1065 for (i = 1; i < vt->esc_count; i++) {
1066 fprintf(stderr, ";%d", vt->esc_buf[i]);
1067 }
1068 fprintf (stderr, "%c\n", ch);
1069 }
1070 #endif
1071 break;
1072 }
1073 vt->esc_ques = 0;
1074 break;
1075 case ESsetG0: // Set G0
1076 vt->tty_state = ESnormal;
1077
1078 if (ch == '0')
1079 vt->g0enc = GRAF_MAP;
1080 else if (ch == 'B')
1081 vt->g0enc = LAT1_MAP;
1082 else if (ch == 'U')
1083 vt->g0enc = IBMPC_MAP;
1084 else if (ch == 'K')
1085 vt->g0enc = USER_MAP;
1086
1087 if (vt->charset == 0)
1088 vt->cur_enc = vt->g0enc;
1089
1090 break;
1091 case ESsetG1: // Set G1
1092 vt->tty_state = ESnormal;
1093
1094 if (ch == '0')
1095 vt->g1enc = GRAF_MAP;
1096 else if (ch == 'B')
1097 vt->g1enc = LAT1_MAP;
1098 else if (ch == 'U')
1099 vt->g1enc = IBMPC_MAP;
1100 else if (ch == 'K')
1101 vt->g1enc = USER_MAP;
1102
1103 if (vt->charset == 1)
1104 vt->cur_enc = vt->g1enc;
1105
1106 break;
1107 case ESidquery: // vt100 query id
1108 vt->tty_state = ESnormal;
1109
1110 if (ch == 'c') {
1111 #ifdef DEBUG
1112 fprintf (stderr, "ESC[>c Query term ID\n");
1113 #endif
1114 vncterm_respond_esc (vt, TERMIDCODE);
1115 }
1116 break;
1117 case ESpercent:
1118 vt->tty_state = ESnormal;
1119 switch (ch) {
1120 case '@': /* defined in ISO 2022 */
1121 vt->utf8 = 0;
1122 break;
1123 case 'G': /* prelim official escape code */
1124 case '8': /* retained for compatibility */
1125 vt->utf8 = 1;
1126 break;
1127 }
1128 break;
1129 default: // ESnormal
1130 vt->tty_state = ESnormal;
1131
1132 switch(ch) {
1133 case 0:
1134 break;
1135 case 7: /* alert aka. bell */
1136 // fixme:
1137 //rfbSendBell(vt->screen);
1138 break;
1139 case 8: /* backspace */
1140 if (vt->cx > 0)
1141 vt->cx--;
1142 break;
1143 case 9: /* tabspace */
1144 if (vt->cx + (8 - (vt->cx % 8)) > vt->width) {
1145 vt->cx = 0;
1146 vncterm_put_lf (vt);
1147 } else {
1148 vt->cx = vt->cx + (8 - (vt->cx % 8));
1149 }
1150 break;
1151 case 10: /* LF,*/
1152 case 11: /* VT */
1153 case 12: /* FF */
1154 vncterm_put_lf (vt);
1155 break;
1156 case 13: /* carriage return */
1157 vt->cx = 0;
1158 break;
1159 case 14:
1160 /* SI (shift in), select character set 1 */
1161 vt->charset = 1;
1162 vt->cur_enc = vt->g1enc;
1163 /* fixme: display controls = 1 */
1164 break;
1165 case 15:
1166 /* SO (shift out), select character set 0 */
1167 vt->charset = 0;
1168 vt->cur_enc = vt->g0enc;
1169 /* fixme: display controls = 0 */
1170 break;
1171 case 27: /* esc */
1172 vt->tty_state = ESesc;
1173 break;
1174 case 127: /* delete */
1175 /* ignore */
1176 break;
1177 case 128+27: /* csi */
1178 vt->tty_state = ESsquare;
1179 break;
1180 default:
1181 if (vt->cx >= vt->width) {
1182 /* line wrap */
1183 vt->cx = 0;
1184 vncterm_put_lf (vt);
1185 }
1186
1187 int y1 = (vt->y_base + vt->cy) % vt->total_height;
1188 TextCell *c = &vt->cells[y1*vt->width + vt->cx];
1189 c->attrib = vt->cur_attrib;
1190 c->ch = ch;
1191 vncterm_update_xy (vt, vt->cx, vt->cy);
1192 vt->cx++;
1193 break;
1194 }
1195 break;
1196 }
1197 }
1198
1199 static int
1200 vncterm_puts (vncTerm *vt, const char *buf, int len)
1201 {
1202 unicode tc;
1203
1204 vncterm_show_cursor (vt, 0);
1205
1206 while (len) {
1207 unsigned char c = *buf;
1208 len--;
1209 buf++;
1210
1211 if (vt->tty_state != ESnormal) {
1212 // never translate escape sequence
1213 tc = c;
1214 } else if (vt->utf8 && !vt->cur_enc) {
1215
1216 if(c & 0x80) { // utf8 multi-byte sequence
1217
1218 if (vt->utf_count > 0 && (c & 0xc0) == 0x80) {
1219 // inside UTF8 sequence
1220 vt->utf_char = (vt->utf_char << 6) | (c & 0x3f);
1221 vt->utf_count--;
1222 if (vt->utf_count == 0) {
1223 tc = vt->utf_char;
1224 } else {
1225 continue;
1226 }
1227 } else {
1228 // first char of a UTF8 sequence
1229 if ((c & 0xe0) == 0xc0) {
1230 vt->utf_count = 1;
1231 vt->utf_char = (c & 0x1f);
1232 } else if ((c & 0xf0) == 0xe0) {
1233 vt->utf_count = 2;
1234 vt->utf_char = (c & 0x0f);
1235 } else if ((c & 0xf8) == 0xf0) {
1236 vt->utf_count = 3;
1237 vt->utf_char = (c & 0x07);
1238 } else if ((c & 0xfc) == 0xf8) {
1239 vt->utf_count = 4;
1240 vt->utf_char = (c & 0x03);
1241 } else if ((c & 0xfe) == 0xfc) {
1242 vt->utf_count = 5;
1243 vt->utf_char = (c & 0x01);
1244 } else
1245 vt->utf_count = 0;
1246
1247 continue;
1248 }
1249 } else {
1250 // utf8 single byte
1251 tc = c;
1252 vt->utf_count = 0;
1253 }
1254
1255 } else {
1256 // never translate controls
1257 if (c >= 32 && c != 127 && c != (128+27)) {
1258 tc = translations[vt->cur_enc][c & 0x0ff];
1259 } else {
1260 tc = c;
1261 }
1262 }
1263
1264 vncterm_putchar (vt, tc);
1265 }
1266
1267 vncterm_show_cursor (vt, 1);
1268
1269 return len;
1270 }
1271
1272 /* fixme:
1273 void
1274 vncterm_set_xcut_text (char* str, int len, struct _rfbClientRec* cl)
1275 {
1276 vncTerm *vt =(vncTerm *)cl->screen->screenData;
1277
1278 // seems str is Latin-1 encoded
1279 if (vt->selection) free (vt->selection);
1280 vt->selection = (unicode *)malloc (len*sizeof (unicode));
1281 int i;
1282 for (i = 0; i < len; i++) {
1283 vt->selection[i] = str[i] & 0xff;
1284 }
1285 vt->selection_len = len;
1286 }
1287 */
1288 static void
1289 mouse_report (vncTerm *vt, int butt, int mrx, int mry)
1290 {
1291 char buf[8];
1292
1293 sprintf (buf, "[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
1294 (char)('!' + mry));
1295
1296 vncterm_respond_esc (vt, buf);
1297 }
1298
1299 void
1300 vncterm_toggle_marked_cell (vncTerm *vt, int pos)
1301 {
1302 int x= (pos%vt->width)*8;
1303 int y= (pos/vt->width)*16;
1304
1305 /* fixme:
1306
1307 int i,j;
1308 rfbScreenInfoPtr s=vt->screen;
1309
1310 char *b = s->frameBuffer+y*s->width+x;
1311
1312 for (j=0; j < 16; j++) {
1313 for(i=0; i < 8; i++) {
1314 b[j*s->width+i] ^= 0x0f;
1315 rfbMarkRectAsModified (s, x, y, x+8, y+16);
1316 }
1317 }
1318 */
1319 }
1320
1321 /* fixme:
1322
1323 void
1324 vncterm_pointer_event (int buttonMask, int x, int y, rfbClientPtr cl)
1325 {
1326
1327 vncTerm *vt =(vncTerm *)cl->screen->screenData;
1328 static int button2_released = 1;
1329 static int last_mask = 0;
1330 static int sel_start_pos = 0;
1331 static int sel_end_pos = 0;
1332 int i;
1333
1334 int cx = x/8;
1335 int cy = y/16;
1336
1337 if (cx < 0) cx = 0;
1338 if (cx >= vt->width) cx = vt->width - 1;
1339 if (cy < 0) cy = 0;
1340 if (cy >= vt->height) cy = vt->height - 1;
1341
1342 if (vt->report_mouse && buttonMask != last_mask) {
1343 last_mask = buttonMask;
1344 if (buttonMask & 1) {
1345 mouse_report (vt, 0, cx, cy);
1346 }
1347 if (buttonMask & 2) {
1348 mouse_report (vt, 1, cx, cy);
1349 }
1350 if (buttonMask & 4) {
1351 mouse_report (vt, 2, cx, cy);
1352 }
1353 if (!buttonMask) {
1354 mouse_report (vt, 3, cx, cy);
1355 }
1356 }
1357
1358 if (buttonMask & 2) {
1359 if(button2_released && vt->selection) {
1360 int i;
1361 for(i = 0; i < vt->selection_len; i++) {
1362 if (vt->ibuf_count < IBUFSIZE - 6) { // uft8 is max 6 characters wide
1363 if (vt->utf8) {
1364 vt->ibuf_count += ucs2_to_utf8 (vt->selection[i], &vt->ibuf[vt->ibuf_count]);
1365 } else {
1366 vt->ibuf[vt->ibuf_count++] = vt->selection[i];
1367 }
1368 }
1369 }
1370 if (vt->y_displ != vt->y_base) {
1371 vt->y_displ = vt->y_base;
1372 vncterm_refresh (vt);
1373 }
1374 }
1375 button2_released = 0;
1376 } else {
1377 button2_released = 1;
1378 }
1379
1380 if (buttonMask & 1) {
1381 int pos = cy*vt->width + cx;
1382
1383 // code borrowed from libvncserver (VNConsole.c)
1384
1385 if (!vt->mark_active) {
1386
1387 vt->mark_active = 1;
1388 sel_start_pos = sel_end_pos = pos;
1389 vncterm_toggle_marked_cell (vt, pos);
1390
1391 } else {
1392
1393 if (pos != sel_end_pos) {
1394
1395 if (pos > sel_end_pos) {
1396 cx = sel_end_pos; cy=pos;
1397 } else {
1398 cx=pos; cy=sel_end_pos;
1399 }
1400
1401 if (cx < sel_start_pos) {
1402 if (cy < sel_start_pos) cy--;
1403 } else {
1404 cx++;
1405 }
1406
1407 while (cx <= cy) {
1408 vncterm_toggle_marked_cell (vt, cx);
1409 cx++;
1410 }
1411
1412 sel_end_pos = pos;
1413 }
1414 }
1415
1416 } else if (vt->mark_active) {
1417 vt->mark_active = 0;
1418
1419 if (sel_start_pos > sel_end_pos) {
1420 int tmp = sel_start_pos - 1;
1421 sel_start_pos = sel_end_pos;
1422 sel_end_pos = tmp;
1423 }
1424
1425 int len = sel_end_pos - sel_start_pos + 1;
1426
1427 if (vt->selection) free (vt->selection);
1428 vt->selection = (unicode *)malloc (len*sizeof (unicode));
1429 vt->selection_len = len;
1430 char *sel_latin1 = (char *)malloc (len + 1);
1431
1432 for (i = 0; i < len; i++) {
1433 int pos = sel_start_pos + i;
1434 int x = pos % vt->width;
1435 int y1 = ((pos / vt->width) + vt->y_displ) % vt->total_height;
1436 TextCell *c = &vt->cells[y1*vt->width + x];
1437 vt->selection[i] = c->ch;
1438 sel_latin1[i] = (char)c->ch;
1439 c++;
1440 }
1441 sel_latin1[len] = 0;
1442 rfbGotXCutText (vt->screen, sel_latin1, len);
1443 free (sel_latin1);
1444
1445 while (sel_start_pos <= sel_end_pos) {
1446 vncterm_toggle_marked_cell (vt, sel_start_pos++);
1447 }
1448
1449 }
1450
1451 rfbDefaultPtrAddEvent (buttonMask, x, y, cl);
1452
1453 }
1454 */
1455
1456 static int client_count = 0;
1457 static int client_connected = 0;
1458 static int last_client = 1;
1459 static time_t last_time = 0;
1460
1461 static void my_kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
1462 {
1463 vncTerm *vt = SPICE_CONTAINEROF(sin, vncTerm, keyboard_sin);
1464
1465 return;
1466 printf("MYKEYCODE %x\n", frag);
1467
1468 if (vt->ibuf_count < (IBUFSIZE - 32)) {
1469
1470 char keySym = 'A'; // fixme;
1471 vt->ibuf[vt->ibuf_count++] = keySym;
1472
1473 vt->screen->core->watch_update_mask(vt->screen->mwatch, SPICE_WATCH_EVENT_READ|SPICE_WATCH_EVENT_WRITE);
1474 }
1475 }
1476
1477 static void my_kbd_push_unicode(SpiceKbdInstance *sin, uint32_t uc)
1478 {
1479 vncTerm *vt = SPICE_CONTAINEROF(sin, vncTerm, keyboard_sin);
1480
1481 printf("MYKEYVAL %x\n", uc);
1482
1483 if (vt->ibuf_count < (IBUFSIZE - 32)) {
1484 gchar buf[10];
1485 gint len = g_unichar_to_utf8(uc, buf);
1486
1487 if (len > 0) {
1488 int i;
1489 for (i = 0; i < len; i++) {
1490 vt->ibuf[vt->ibuf_count++] = buf[i];
1491 }
1492 }
1493 vt->screen->core->watch_update_mask(vt->screen->mwatch, SPICE_WATCH_EVENT_READ|SPICE_WATCH_EVENT_WRITE);
1494 }
1495 }
1496
1497 static uint8_t my_kbd_get_leds(SpiceKbdInstance *sin)
1498 {
1499 return 0;
1500 }
1501
1502 static SpiceKbdInterface my_keyboard_sif = {
1503 .base.type = SPICE_INTERFACE_KEYBOARD ,
1504 .base.description = "spiceterm keyboard device",
1505 .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
1506 .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
1507 .push_unicode = my_kbd_push_unicode,
1508 .push_scan_freg = my_kbd_push_key,
1509 .get_leds = my_kbd_get_leds,
1510 };
1511
1512 vncTerm *
1513 create_vncterm (int argc, char** argv, int maxx, int maxy)
1514 {
1515 int i;
1516
1517 Test *test;
1518
1519 SpiceCoreInterface *core = basic_event_loop_init();
1520 test = test_new(core);
1521 //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF);
1522 test_add_display_interface(test);
1523 test_add_agent_interface(test->server);
1524
1525 vncTerm *vt = (vncTerm *)calloc (sizeof(vncTerm), 1);
1526
1527 vt->keyboard_sin.base.sif = &my_keyboard_sif.base;
1528 spice_server_add_interface(test->server, &vt->keyboard_sin.base);
1529
1530 /*
1531 rfbColourMap *cmap =&screen->colourMap;
1532 cmap->data.bytes = malloc (16*3);
1533 for(i=0;i<16;i++) {
1534 cmap->data.bytes[i*3 + 0] = default_red[color_table[i]];
1535 cmap->data.bytes[i*3 + 1] = default_grn[color_table[i]];
1536 cmap->data.bytes[i*3 + 2] = default_blu[color_table[i]];
1537 }
1538 cmap->count = 16;
1539 cmap->is16 = FALSE;
1540 screen->serverFormat.trueColour = FALSE;
1541
1542 screen->kbdAddEvent = vncterm_kbd_event;
1543
1544 screen->setXCutText = vncterm_set_xcut_text;
1545
1546 screen->ptrAddEvent = vncterm_pointer_event;
1547
1548 screen->desktopName = "VNC Command Terminal";
1549
1550 screen->newClientHook = new_client;
1551
1552 */
1553
1554 vt->maxx = test->width;
1555 vt->maxy = test->height;
1556
1557 vt->width = vt->maxx / 8;
1558 vt->height = vt->maxy / 16;
1559
1560 vt->total_height = vt->height * 20;
1561 vt->scroll_height = 0;
1562 vt->y_base = 0;
1563 vt->y_displ = 0;
1564
1565 vt->region_top = 0;
1566 vt->region_bottom = vt->height;
1567
1568 vt->g0enc = LAT1_MAP;
1569 vt->g1enc = GRAF_MAP;
1570 vt->cur_enc = vt->g0enc;
1571 vt->charset = 0;
1572
1573 /* default text attributes */
1574 vt->default_attrib.bold = 0;
1575 vt->default_attrib.uline = 0;
1576 vt->default_attrib.blink = 0;
1577 vt->default_attrib.invers = 0;
1578 vt->default_attrib.unvisible = 0;
1579 vt->default_attrib.fgcol = 7;
1580 vt->default_attrib.bgcol = 0;
1581
1582 vt->cur_attrib = vt->default_attrib;
1583
1584 vt->cells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->total_height);
1585
1586 for (i = 0; i < vt->width*vt->total_height; i++) {
1587 vt->cells[i].ch = ' ';
1588 vt->cells[i].attrib = vt->default_attrib;
1589 }
1590
1591 vt->altcells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->height);
1592
1593 vt->screen = test;
1594
1595 return vt;
1596 }
1597
1598 static void master_watch(int master, int event, void *opaque)
1599 {
1600 vncTerm *vt = (vncTerm *)opaque;
1601
1602 printf("CHANNEL EVENT %d\n", event);
1603
1604 // fixme: if (!vt->mark_active) {
1605
1606 if (event == SPICE_WATCH_EVENT_READ) {
1607 char buffer[1024];
1608 int c;
1609 while ((c = read(master, buffer, 1024)) == -1) {
1610 if (errno != EAGAIN) break;
1611 }
1612 if (c == -1) {
1613 g_error("got read error"); // fixme
1614 }
1615 vncterm_puts (vt, buffer, c);
1616 } else {
1617 if (vt->ibuf_count > 0) {
1618 printf ("DEBUG: WRITE %x %d\n", vt->ibuf[0], vt->ibuf_count);
1619 write (master, vt->ibuf, vt->ibuf_count);
1620 vt->ibuf_count = 0; // fixme: what if not all data written
1621 }
1622 vt->screen->core->watch_update_mask(vt->screen->mwatch, SPICE_WATCH_EVENT_READ);
1623 }
1624 }
1625
1626 int
1627 main (int argc, char** argv)
1628 {
1629 int i;
1630 char **cmdargv = NULL;
1631 char *command = "/bin/bash"; // execute normal shell as default
1632 int pid;
1633 int master;
1634 char ptyname[1024];
1635 fd_set fs, fs1;
1636 struct timeval tv, tv1;
1637 time_t elapsed, cur_time;
1638 struct winsize dimensions;
1639
1640 for (i = 1; i < argc; i++) {
1641 if (!strcmp (argv[i], "-c")) {
1642 command = argv[i+1];
1643 cmdargv = &argv[i+1];
1644 argc = i;
1645 argv[i] = NULL;
1646 break;
1647 }
1648 }
1649
1650 vncTerm *vt = create_vncterm (argc, argv, 745, 400);
1651
1652 setlocale(LC_ALL, ""); // set from environment
1653
1654 char *ctype = setlocale (LC_CTYPE, NULL); // query LC_CTYPE
1655
1656 // fixme: ist there a standard way to detect utf8 mode ?
1657 if (strcasestr (ctype, ".utf-8")||strcasestr (ctype, ".utf8")) {
1658 vt->utf8 = 1;
1659 }
1660
1661 dimensions.ws_col = vt->width;
1662 dimensions.ws_row = vt->height;
1663
1664 setenv ("TERM", TERM, 1);
1665
1666 printf("EXEC: %s\n", command);
1667
1668 pid = forkpty (&master, ptyname, NULL, &dimensions);
1669 if(!pid) {
1670
1671 // install default signal handlers
1672 signal (SIGQUIT, SIG_DFL);
1673 signal (SIGTERM, SIG_DFL);
1674 signal (SIGINT, SIG_DFL);
1675
1676 if (cmdargv) {
1677 execvp (command, cmdargv);
1678 } else {
1679 execlp (command, command, NULL);
1680 }
1681 perror ("Error: exec failed\n");
1682 exit (-1); // should not be reached
1683 } else if (pid == -1) {
1684 perror ("Error: fork failed\n");
1685 exit (-1);
1686 }
1687
1688
1689 vt->screen->mwatch = vt->screen->core->watch_add(
1690 master, SPICE_WATCH_EVENT_READ /* |SPICE_WATCH_EVENT_WRITE */,
1691 master_watch, vt);
1692
1693 basic_event_loop_mainloop();
1694
1695 //rfbProcessEvents (vt->screen, 40000); /* 40 ms */
1696
1697 /*
1698 if (vt->ibuf_count > 0) {
1699 printf ("DEBUG: WRITE %d %d\n", vt->ibuf[0], vt->ibuf_count);
1700 write (master, vt->ibuf, vt->ibuf_count);
1701 vt->ibuf_count = 0;
1702 last_time = time (NULL);
1703 }
1704 */
1705
1706 kill (pid, 9);
1707 int status;
1708 waitpid(pid, &status, 0);
1709
1710 exit (0);
1711 }