VNC.Mod 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE VNC; (** AUTHOR "pjm/jkreienb"; PURPOSE "VNC client"; *)
  3. (*
  4. VNC viewer for Aos - based on Oberon VNC viewer by Jörg Kreienbühl.
  5. This version is based on the window manager.
  6. References:
  7. 1. Tristan Richardson and Kenneth R. Wood, "The RFB Protocol: Version 3.3", ORL, Cambridge, January 1998
  8. *)
  9. IMPORT SYSTEM, Streams, KernelLog, Objects, Commands, Network, IP, TCP, DNS, DES,
  10. Inputs, Raster, WMWindowManager, Rect := WMRectangles, Dialogs := WMDialogs, Beep, Files;
  11. CONST
  12. OpenTimeout = 10000;
  13. CloseTimeout = 2000;
  14. PollTimeout = 0; (* set to 0 for old-style polling on every received event *)
  15. Shared = TRUE;
  16. AlphaCursor = 128;
  17. InBufSize = 8192; (* network input buffer *)
  18. OutBufSize = 4096; (* network output buffer *)
  19. ImgBufSize = 8192; (* image buffer for ReceiveRaw *)
  20. BellDelay = 20; (* ms *)
  21. BellFreq = 550; (* Hz *)
  22. Trace = FALSE;
  23. TraceVisual = TRUE;
  24. TraceAudio = FALSE;
  25. Ok = TCP.Ok;
  26. TYPE
  27. Connection* = POINTER TO RECORD
  28. next: Connection; (* link in connection pool *)
  29. pcb: TCP.Connection;
  30. w: Window;
  31. res: WORD;
  32. id: LONGINT;
  33. receiver: Receiver;
  34. sender: Sender;
  35. nb: Raster.Image;
  36. fmt: Raster.Format; (* network transfer format *)
  37. mode: Raster.Mode;
  38. bytesPerPixel: LONGINT; (* network transfer format size *)
  39. rcvbuf, imgbuf: POINTER TO ARRAY OF CHAR;
  40. rcvbufpos, rcvbuflen: LONGINT;
  41. fip: IP.Adr
  42. END;
  43. TYPE
  44. EnumProc = PROCEDURE (c: Connection; out : Streams.Writer);
  45. ConnectionPool = OBJECT
  46. VAR head, tail: Connection; id: LONGINT;
  47. PROCEDURE Empty(): BOOLEAN;
  48. BEGIN (* read head pointer atomically *)
  49. RETURN head = NIL
  50. END Empty;
  51. PROCEDURE Add(c: Connection);
  52. BEGIN {EXCLUSIVE}
  53. c.next := NIL; c.id := id; INC(id);
  54. IF head = NIL THEN head := c ELSE tail.next := c END;
  55. tail := c
  56. END Add;
  57. PROCEDURE Remove(c: Connection);
  58. VAR p, q: Connection;
  59. BEGIN {EXCLUSIVE}
  60. p := NIL; q := head;
  61. WHILE (q # NIL) & (q # c) DO p := q; q := q.next END;
  62. IF q = c THEN (* found *)
  63. IF p # NIL THEN p.next := q.next ELSE head := NIL; tail := NIL END
  64. END
  65. END Remove;
  66. PROCEDURE Enumerate(p: EnumProc; out : Streams.Writer);
  67. VAR c: Connection;
  68. BEGIN (* may traverse list concurrently with Add and Remove *)
  69. c := head; WHILE c # NIL DO p(c, out); c := c.next END
  70. END Enumerate;
  71. PROCEDURE Find(id: LONGINT): Connection;
  72. VAR c: Connection;
  73. BEGIN (* may traverse list concurrently with Add and Remove *)
  74. c := head; WHILE (c # NIL) & (c.id # id) DO c := c.next END;
  75. RETURN c
  76. END Find;
  77. PROCEDURE &Init*;
  78. BEGIN
  79. head := NIL; tail := NIL; id := 0
  80. END Init;
  81. END ConnectionPool;
  82. TYPE
  83. Window = OBJECT (WMWindowManager.BufferWindow)
  84. VAR sender: Sender;
  85. PROCEDURE PointerDown*(x, y: LONGINT; keys: SET);
  86. BEGIN
  87. IF sender # NIL THEN sender.Pointer(x, y, keys) END
  88. END PointerDown;
  89. PROCEDURE PointerMove*(x, y: LONGINT; keys: SET);
  90. BEGIN
  91. IF sender # NIL THEN sender.Pointer(x, y, keys) END
  92. END PointerMove;
  93. PROCEDURE WheelMove*(dz : LONGINT);
  94. BEGIN
  95. IF sender # NIL THEN sender.Wheel(dz) END
  96. END WheelMove;
  97. PROCEDURE PointerUp*(x, y: LONGINT; keys: SET);
  98. BEGIN
  99. IF sender # NIL THEN sender.Pointer(x, y, keys) END
  100. END PointerUp;
  101. PROCEDURE KeyEvent*(ucs : LONGINT; flags: SET; keysym: LONGINT);
  102. BEGIN
  103. IF (keysym # Inputs.KsNil) & (sender # NIL) THEN sender.Key(keysym, flags) END
  104. END KeyEvent;
  105. PROCEDURE Close*;
  106. BEGIN
  107. IF sender # NIL THEN CloseVNC(sender.c) END
  108. END Close;
  109. END Window;
  110. TYPE
  111. Receiver = OBJECT
  112. VAR c: Connection; exception, double: BOOLEAN;
  113. PROCEDURE &Init*(c: Connection);
  114. BEGIN
  115. SELF.c := c; exception := FALSE; double := FALSE
  116. END Init;
  117. BEGIN {ACTIVE, SAFE}
  118. IF exception THEN
  119. IF TRUE OR Trace THEN KernelLog.Enter; KernelLog.String("Receiver exception"); KernelLog.Exit END;
  120. IF double THEN RETURN END;
  121. double := TRUE
  122. ELSE
  123. exception := TRUE;
  124. IF Trace THEN KernelLog.Enter; KernelLog.String("Receiver enter"); KernelLog.Exit END;
  125. REPEAT
  126. IF (PollTimeout = 0) & (c.sender # NIL) THEN c.sender.HandleTimeout END;
  127. AwaitResponse(c)
  128. UNTIL c.res # Ok;
  129. IF Trace THEN KernelLog.Enter; KernelLog.String("Receiver exit"); KernelLog.Exit END
  130. END;
  131. IF c.sender # NIL THEN c.sender.Terminate END;
  132. IF c.w # NIL THEN
  133. c.w.manager.Remove(c.w);
  134. c.w := NIL
  135. END
  136. END Receiver;
  137. TYPE
  138. Sender = OBJECT
  139. VAR
  140. c: Connection;
  141. head, middle, tail, lx, ly: LONGINT;
  142. res: WORD;
  143. lkeys : SET;
  144. buf: ARRAY OutBufSize OF CHAR;
  145. done, poll: BOOLEAN;
  146. timer: Objects.Timer;
  147. PROCEDURE Available(): LONGINT;
  148. BEGIN
  149. RETURN (head - tail - 1) MOD LEN(buf)
  150. END Available;
  151. PROCEDURE Put(x: CHAR);
  152. BEGIN
  153. ASSERT((tail+1) MOD LEN(buf) # head);
  154. buf[tail] := x; tail := (tail+1) MOD LEN(buf)
  155. END Put;
  156. PROCEDURE PutInt(x: LONGINT);
  157. BEGIN
  158. Put(CHR(x DIV 100H)); Put(CHR(x MOD 100H))
  159. END PutInt;
  160. PROCEDURE Pointer(x, y: LONGINT; keys: SET);
  161. BEGIN {EXCLUSIVE}
  162. IF (x >= 0) & (x < c.w.img.width) & (y >= 0) & (y < c.w.img.height) & (Available() >= 6) THEN
  163. IF Trace THEN
  164. KernelLog.Enter; KernelLog.String("Ptr "); KernelLog.Int(x, 5); KernelLog.Int(y, 5); KernelLog.Exit
  165. END;
  166. Put(5X); (* PointerEvent (sec. 5.2.6) *)
  167. Put(CHR(SYSTEM.VAL(LONGINT, keys)));
  168. PutInt(x); PutInt(y);
  169. lx := x; ly := y; lkeys := keys
  170. END
  171. END Pointer;
  172. PROCEDURE Wheel(dz : LONGINT);
  173. VAR keys : SET;
  174. BEGIN {EXCLUSIVE}
  175. IF (Available() >= 6) THEN
  176. IF Trace THEN
  177. KernelLog.Enter; KernelLog.String("Wheel "); KernelLog.Int(dz, 5); KernelLog.Exit
  178. END;
  179. Put(5X); (* PointerEvent (sec. 5.2.6) *)
  180. keys := lkeys;
  181. IF dz < 0 THEN INCL(keys, 3) END;
  182. IF dz > 0 THEN INCL(keys, 4) END;
  183. Put(CHR(SYSTEM.VAL(LONGINT, keys)));
  184. PutInt(lx); PutInt(ly)
  185. END
  186. END Wheel;
  187. PROCEDURE Key(keysym: LONGINT; flags: SET);
  188. BEGIN {EXCLUSIVE}
  189. IF Available() >= 8 THEN
  190. Put(4X); (* KeyEvent (sec. 5.2.5) *)
  191. IF Inputs.Release IN flags THEN Put(0X) ELSE Put(1X) END;
  192. PutInt(0); PutInt(0); PutInt(keysym)
  193. END
  194. END Key;
  195. PROCEDURE Paste(r: Streams.Reader);
  196. VAR key: LONGINT;
  197. BEGIN {EXCLUSIVE}
  198. LOOP
  199. key := ORD(r.Get());
  200. IF r.res # 0 THEN EXIT END;
  201. AWAIT(Available() >= 16);
  202. (* down key *)
  203. Put(4X); (* KeyEvent (sec. 5.2.5) *)
  204. Put(1X); PutInt(0); PutInt(0); PutInt(key);
  205. (* up key *)
  206. Put(4X); (* KeyEvent (sec. 5.2.5) *)
  207. Put(0X); PutInt(0); PutInt(0); PutInt(key)
  208. END
  209. END Paste;
  210. PROCEDURE AwaitEvent;
  211. BEGIN {EXCLUSIVE}
  212. AWAIT((head # tail) OR poll OR done);
  213. IF ~done & (Available() >= 10) THEN
  214. Put(3X); (* FramebufferUpdateRequest (sec. 5.2.4) *)
  215. Put(1X); (* incremental *)
  216. PutInt(0); PutInt(0); PutInt(c.w.img.width); PutInt(c.w.img.height)
  217. END;
  218. middle := tail; poll := FALSE
  219. END AwaitEvent;
  220. PROCEDURE SendEvents;
  221. BEGIN
  222. IF middle >= head THEN
  223. c.pcb.Send(buf, head, middle-head, FALSE, res)
  224. ELSE (* split buffer *)
  225. c.pcb.Send(buf, head, LEN(buf)-head, FALSE, res);
  226. IF res = Ok THEN c.pcb.Send(buf, 0, middle, FALSE, res) END
  227. END;
  228. head := middle
  229. END SendEvents;
  230. PROCEDURE Terminate;
  231. BEGIN {EXCLUSIVE}
  232. done := TRUE
  233. END Terminate;
  234. PROCEDURE HandleTimeout;
  235. BEGIN {EXCLUSIVE}
  236. poll := TRUE;
  237. IF (PollTimeout > 0) & ~done THEN
  238. Objects.SetTimeout(timer, SELF.HandleTimeout, PollTimeout)
  239. END
  240. END HandleTimeout;
  241. PROCEDURE &Init*(c: Connection);
  242. BEGIN
  243. NEW(timer);
  244. SELF.c := c; head := 0; middle := 0; tail := 0; res := Ok; done := FALSE
  245. END Init;
  246. BEGIN {ACTIVE}
  247. IF Trace THEN KernelLog.Enter; KernelLog.String("Sender enter"); KernelLog.Exit END;
  248. LOOP
  249. AwaitEvent;
  250. IF done THEN EXIT END;
  251. IF TraceAudio THEN Beep.Beep(BellFreq) END;
  252. IF Trace THEN
  253. KernelLog.Enter; KernelLog.String("Events "); KernelLog.Int(head, 5); KernelLog.Int(middle, 5); KernelLog.Exit
  254. END;
  255. SendEvents;
  256. IF TraceAudio THEN Beep.Beep(0) END;
  257. IF res # Ok THEN EXIT END
  258. END;
  259. Objects.CancelTimeout(timer);
  260. IF Trace THEN KernelLog.Enter; KernelLog.String("Sender exit"); KernelLog.Exit END
  261. END Sender;
  262. TYPE
  263. Bell = OBJECT
  264. VAR timer: Objects.Timer;
  265. PROCEDURE Ring;
  266. BEGIN {EXCLUSIVE}
  267. IF timer = NIL THEN NEW(timer) END;
  268. Objects.SetTimeout(timer, SELF.HandleTimeout, BellDelay); (* ignore race with expired, but unscheduled timer *)
  269. Beep.Beep(BellFreq)
  270. END Ring;
  271. PROCEDURE HandleTimeout;
  272. BEGIN {EXCLUSIVE}
  273. Beep.Beep(0)
  274. END HandleTimeout;
  275. END Bell;
  276. VAR
  277. pool: ConnectionPool;
  278. bell: Bell;
  279. PROCEDURE ReceiveBytes(c: Connection; VAR buf: ARRAY OF CHAR; size: LONGINT; VAR len: LONGINT);
  280. VAR dst, n: LONGINT;
  281. BEGIN
  282. IF c.res = Ok THEN
  283. dst := 0; len := 0;
  284. LOOP
  285. IF size <= 0 THEN EXIT END;
  286. n := MIN(c.rcvbuflen, size); (* n is number of bytes to copy from buffer now *)
  287. IF n = 0 THEN (* buffer empty *)
  288. (* attempt to read at least size bytes, but at most a full buffer *)
  289. c.pcb.Receive(c.rcvbuf^, 0, LEN(c.rcvbuf), size, n, c.res);
  290. IF c.res # Ok THEN EXIT END;
  291. c.rcvbufpos := 0; c.rcvbuflen := n;
  292. n := MIN(n, size) (* n is number of bytes to copy from buffer now *)
  293. END;
  294. ASSERT(dst+n <= LEN(buf)); (* index check *)
  295. SYSTEM.MOVE(ADDRESSOF(c.rcvbuf[c.rcvbufpos]), ADDRESSOF(buf[dst]), n);
  296. INC(c.rcvbufpos, n); DEC(c.rcvbuflen, n);
  297. INC(dst, n); DEC(size, n); INC(len, n)
  298. END
  299. ELSE
  300. buf[0] := 0X; len := 0
  301. END
  302. END ReceiveBytes;
  303. PROCEDURE Receive(c: Connection; VAR ch: CHAR);
  304. VAR len: LONGINT; buf: ARRAY 1 OF CHAR;
  305. BEGIN
  306. IF c.rcvbuflen > 0 THEN
  307. ch := c.rcvbuf[c.rcvbufpos]; INC(c.rcvbufpos); DEC(c.rcvbuflen)
  308. ELSE
  309. ReceiveBytes(c, buf, 1, len);
  310. ch := buf[0]
  311. END
  312. END Receive;
  313. PROCEDURE ReceiveInt(c: Connection; VAR x: LONGINT);
  314. VAR len: LONGINT; buf: ARRAY 2 OF CHAR;
  315. BEGIN
  316. ReceiveBytes(c, buf, 2, len);
  317. x := Network.GetNet2(buf, 0)
  318. END ReceiveInt;
  319. PROCEDURE ReceiveLInt(c: Connection; VAR x: LONGINT);
  320. VAR len: LONGINT; buf: ARRAY 4 OF CHAR;
  321. BEGIN
  322. ReceiveBytes(c, buf, 4, len);
  323. x := Network.GetNet4(buf, 0)
  324. END ReceiveLInt;
  325. PROCEDURE ReceiveIgnore(c: Connection; len: LONGINT);
  326. VAR ch: CHAR;
  327. BEGIN
  328. WHILE (len > 0) & (c.res = Ok) DO Receive(c, ch); DEC(len) END
  329. END ReceiveIgnore;
  330. PROCEDURE Send(c: Connection; x: CHAR);
  331. VAR buf: ARRAY 1 OF CHAR;
  332. BEGIN
  333. buf[0] := x; c.pcb.Send(buf, 0, 1, FALSE, c.res)
  334. END Send;
  335. (* Get the server's version number and send our version number. *)
  336. PROCEDURE DoVersion(c: Connection): BOOLEAN;
  337. VAR buf: ARRAY 16 OF CHAR; len: LONGINT;
  338. BEGIN
  339. ReceiveBytes(c, buf, 12, len);
  340. IF c.res = Ok THEN
  341. IF Trace THEN
  342. buf[11] := 0X;
  343. KernelLog.Enter; KernelLog.String("Version="); KernelLog.String(buf); KernelLog.Exit
  344. END;
  345. buf := "RFB 003.003"; buf[11] := 0AX;
  346. c.pcb.Send(buf, 0, 12, FALSE, c.res)
  347. END;
  348. RETURN c.res = Ok
  349. END DoVersion;
  350. (* Authenticate ourself with the server. *)
  351. PROCEDURE DoAuthentication(c: Connection; VAR pwd: ARRAY OF CHAR): BOOLEAN;
  352. VAR x, len, len0: LONGINT; buf: ARRAY 64 OF CHAR; cipher: ARRAY 16 OF CHAR; d: DES.DES;
  353. BEGIN
  354. ReceiveLInt(c, x);
  355. IF c.res = Ok THEN
  356. IF Trace THEN
  357. KernelLog.Enter; KernelLog.String("Scheme="); KernelLog.Int(x, 1); KernelLog.Exit
  358. END;
  359. IF x = 0 THEN (* failed *)
  360. ReceiveLInt(c, len); (* read reason *)
  361. WHILE (len > 0) & (c.res = Ok) DO
  362. len0 := MIN(len, LEN(buf));
  363. ReceiveBytes(c, buf, len0, len0);
  364. DEC(len, len0)
  365. END;
  366. IF Trace & (c.res = Ok) THEN (* write last part of reason (typically only one part) *)
  367. IF len0 = LEN(buf) THEN DEC(len0) END;
  368. buf[len0] := 0X;
  369. KernelLog.Enter; KernelLog.String("Reason="); KernelLog.String(buf); KernelLog.Exit
  370. END
  371. ELSIF x = 2 THEN (* VNC authentication *)
  372. ReceiveBytes(c, buf, 16, len); (* challenge *)
  373. IF c.res = Ok THEN
  374. NEW(d);
  375. d.SetKey(pwd);
  376. d.Encrypt(buf, 0, cipher, 0); (* Two 8-Byte-Blocks *)
  377. d.Encrypt(buf, 8, cipher, 8);
  378. c.pcb.Send(cipher, 0, 16, FALSE, c.res);
  379. IF c.res = Ok THEN
  380. ReceiveLInt(c, x);
  381. IF c.res = Ok THEN
  382. c.res := x (* 0=Ok, 1=failed, 2=too-many *)
  383. END
  384. END
  385. END
  386. ELSE (* no or unknown authentication *)
  387. (* skip *)
  388. END
  389. END;
  390. RETURN c.res = Ok
  391. END DoAuthentication;
  392. (* Set up an RFB encodings message. "code" contains the codes in preferred order. "len" returns the message length. *)
  393. PROCEDURE PutEncodings(VAR buf: ARRAY OF CHAR; ofs: LONGINT; code: ARRAY OF CHAR; VAR len: LONGINT);
  394. VAR i: LONGINT;
  395. BEGIN
  396. buf[ofs] := 2X; (* SetEncodings (sec. 5.2.3) *)
  397. buf[ofs+1] := 0X; (* padding *)
  398. i := 0;
  399. WHILE code[i] # 0X DO
  400. Network.PutNet4(buf, ofs + 4*(i+1), ORD(code[i])-ORD("0"));
  401. INC(i)
  402. END;
  403. Network.PutNet2(buf, ofs+2, i); (* number-of-encodings *)
  404. len := 4*(i+1)
  405. END PutEncodings;
  406. (* Initialise the transfer format. *)
  407. PROCEDURE DoInit(c: Connection): BOOLEAN;
  408. VAR len, len0, w, h: LONGINT; buf: ARRAY 64 OF CHAR; pixel: Raster.Pixel; ptr: WMWindowManager.PointerInfo;
  409. BEGIN
  410. IF Shared THEN Send(c, 1X) ELSE Send(c, 0X) END;
  411. IF c.res = Ok THEN
  412. ReceiveBytes(c, buf, 24, len); (* initialization message *)
  413. IF c.res = Ok THEN
  414. w := Network.GetNet2(buf, 0); h := Network.GetNet2(buf, 2);
  415. len := Network.GetNet4(buf, 20);
  416. IF Trace THEN
  417. KernelLog.Enter;
  418. KernelLog.String("Server: width="); KernelLog.Int(w, 1);
  419. KernelLog.String(" height="); KernelLog.Int(h, 1);
  420. KernelLog.String(" bpp="); KernelLog.Int(ORD(buf[4]), 1);
  421. KernelLog.String(" depth="); KernelLog.Int(ORD(buf[5]), 1);
  422. KernelLog.String(" bigendian="); KernelLog.Int(ORD(buf[6]), 1);
  423. KernelLog.String(" truecolor="); KernelLog.Int(ORD(buf[7]), 1); KernelLog.Ln;
  424. KernelLog.String(" redmax="); KernelLog.Int(Network.GetNet2(buf, 8), 1);
  425. KernelLog.String(" greenmax="); KernelLog.Int(Network.GetNet2(buf, 10), 1);
  426. KernelLog.String(" bluemax="); KernelLog.Int(Network.GetNet2(buf, 12), 1);
  427. KernelLog.String(" redshift="); KernelLog.Int(ORD(buf[14]), 1);
  428. KernelLog.String(" greenshift="); KernelLog.Int(ORD(buf[15]), 1);
  429. KernelLog.String(" blueshift="); KernelLog.Int(ORD(buf[16]), 1);
  430. KernelLog.String(" len="); KernelLog.Int(len, 1);
  431. KernelLog.Exit
  432. END;
  433. WHILE (len > 0) & (c.res = Ok) DO
  434. len0 := MIN(len, LEN(buf));
  435. ReceiveBytes(c, buf, len0, len0);
  436. DEC(len, len0)
  437. END;
  438. IF c.res = Ok THEN
  439. IF Trace THEN (* write last part of name (typically only one part) *)
  440. IF len0 = LEN(buf) THEN DEC(len0) END;
  441. buf[len0] := 0X;
  442. KernelLog.Enter; KernelLog.String("Name="); KernelLog.String(buf); KernelLog.Exit
  443. END;
  444. (* choose our preferred format *)
  445. Raster.InitMode(c.mode, Raster.srcCopy);
  446. NEW(c.w, w, h, FALSE);
  447. NEW(ptr); ptr.hotX := 2; ptr.hotY := 2;
  448. NEW(ptr.img); Raster.Create(ptr.img, 4, 4, Raster.BGRA8888);
  449. Raster.SetRGBA(pixel, 255, 255, 255, AlphaCursor);
  450. Raster.Fill(ptr.img, 0, 0, 4, 4, pixel, c.mode);
  451. Raster.SetRGBA(pixel, 0, 0, 0, AlphaCursor);
  452. Raster.Fill(ptr.img, 1, 1, 3, 3, pixel, c.mode);
  453. c.w.SetPointerInfo(ptr);
  454. WMWindowManager.DefaultAddWindow(c.w);
  455. Raster.SetRGB(pixel, 0, 0, 0);
  456. Raster.Fill(c.w.img, 0, 0, c.w.img.width, c.w.img.height, pixel, c.mode);
  457. c.w.Invalidate(Rect.MakeRect(0, 0, c.w.img.width, c.w.img.height));
  458. NEW(c.nb);
  459. IF c.w.img.fmt.code IN {Raster.bgr888, Raster.bgra8888} THEN
  460. c.fmt := Raster.BGRA8888
  461. ELSE
  462. c.fmt := Raster.BGR565
  463. END;
  464. c.bytesPerPixel := c.fmt.bpp DIV 8;
  465. ASSERT(ImgBufSize >= w*c.bytesPerPixel); (* at least one full line will fit buffer *)
  466. NEW(c.imgbuf, ImgBufSize);
  467. (* set up client format message *)
  468. buf[0] := 0X; (* SetPixelFormat message (sec. 5.2.1) *)
  469. buf[1] := 0X; buf[2] := 0X; buf[3] := 0X; (* padding *)
  470. buf[4] := CHR(c.bytesPerPixel*8); (* bits-per-pixel (8, 16 or 32) on wire *)
  471. buf[5] := CHR(c.fmt.bpp); (* depth (8, 16, 24 or 32) *)
  472. buf[6] := 0X; (* big-endian-flag *)
  473. buf[7] := 1X; (* true-colour-flag *)
  474. CASE c.fmt.code OF
  475. Raster.bgr565:
  476. Network.PutNet2(buf, 8, 31); (* red-max *)
  477. Network.PutNet2(buf, 10, 63); (* green-max *)
  478. Network.PutNet2(buf, 12, 31); (* blue-max *)
  479. buf[14] := CHR(11); (* red-shift *)
  480. buf[15] := CHR(5); (* green-shift *)
  481. buf[16] := CHR(0) (* blue-shift *)
  482. |Raster.bgra8888:
  483. Network.PutNet2(buf, 8, 255); (* red-max *)
  484. Network.PutNet2(buf, 10, 255); (* green-max *)
  485. Network.PutNet2(buf, 12, 255); (* blue-max *)
  486. buf[14] := CHR(16); (* red-shift *)
  487. buf[15] := CHR(8); (* green-shift *)
  488. buf[16] := CHR(0) (* blue-shift *)
  489. END;
  490. PutEncodings(buf, 20, "15420", len); (* 0=raw, 1=copy rectangle, 2=RRE, 4=CoRRE, 5=hextile *)
  491. IF Trace THEN
  492. KernelLog.Enter; KernelLog.String("Client:"); KernelLog.Ln;
  493. KernelLog.Buffer(buf, 0, 20+len); KernelLog.Exit
  494. END;
  495. c.pcb.Send(buf, 0, 20+len, FALSE, c.res)
  496. END
  497. END
  498. END;
  499. RETURN c.res = Ok
  500. END DoInit;
  501. (* Send a framebuffer update request. *)
  502. PROCEDURE SendRequest(c: Connection; inc: BOOLEAN; x, y, w, h: LONGINT);
  503. VAR buf: ARRAY 10 OF CHAR;
  504. BEGIN
  505. IF Trace THEN
  506. KernelLog.Enter; KernelLog.String("Req"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  507. KernelLog.Int(w, 5); KernelLog.Int(h, 5);
  508. IF inc THEN KernelLog.String(" inc") END;
  509. KernelLog.Exit
  510. END;
  511. buf[0] := 3X; (* FramebufferUpdateRequest (sec. 5.2.4) *)
  512. IF inc THEN buf[1] := 1X ELSE buf[1] := 0X END;
  513. Network.PutNet2(buf, 2, x); Network.PutNet2(buf, 4, y);
  514. Network.PutNet2(buf, 6, w); Network.PutNet2(buf, 8, h);
  515. c.pcb.Send(buf, 0, 10, FALSE, c.res)
  516. END SendRequest;
  517. (* Update an area of the display. *)
  518. PROCEDURE UpdateDisplay(c: Connection; x, y, w, h: LONGINT);
  519. (*VAR pixel: Raster.Pixel; mode: Raster.Mode;*)
  520. BEGIN
  521. (*
  522. Raster.SetRGB(pixel, 255, 255, 255);
  523. Raster.InitMode(mode, Raster.InvDst);
  524. Raster.Fill(c.w.img, 0, 0, 5, 5, pixel, mode);
  525. IF (x # 0) OR (y # 0) THEN c.w.AddDirty(0, 0, 10, 10) END;
  526. *)
  527. c.w.Invalidate(Rect.MakeRect(x, y, x + w, y + h))
  528. END UpdateDisplay;
  529. (* Receive a raw rectangle. *)
  530. PROCEDURE ReceiveRaw(c: Connection; x, y, w, h: LONGINT);
  531. VAR bh, h0, len, i: LONGINT;
  532. BEGIN
  533. IF Trace THEN
  534. KernelLog.Enter; KernelLog.String("Raw"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  535. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Exit
  536. END;
  537. bh := LEN(c.imgbuf^) DIV (w*c.bytesPerPixel); (* number of lines that will fit in buffer *)
  538. Raster.Init(c.nb, w, bh, c.fmt, w*c.bytesPerPixel, ADDRESSOF(c.imgbuf[0]));
  539. WHILE h > 0 DO
  540. IF h >= bh THEN h0 := bh ELSE h0 := h END;
  541. len := h0*w*c.bytesPerPixel;
  542. ReceiveBytes(c, c.imgbuf^, len, len);
  543. IF c.res # Ok THEN RETURN END;
  544. IF c.bytesPerPixel = 4 THEN (* fix alpha values *)
  545. FOR i := 0 TO len-1 BY 4 DO c.imgbuf[i+Raster.a] := 0FFX END
  546. END;
  547. Raster.Copy(c.nb, c.w.img, 0, 0, w, h0, x, y, c.mode);
  548. DEC(h, h0); INC(y, h0)
  549. END
  550. END ReceiveRaw;
  551. (* Receive a copy rectangle message. *)
  552. PROCEDURE ReceiveCopyRect(c: Connection; x, y, w, h: LONGINT);
  553. VAR sx, sy: LONGINT;
  554. BEGIN
  555. ReceiveInt(c, sx); (* src-x-position *)
  556. IF c.res = Ok THEN
  557. ReceiveInt(c, sy); (* src-y-position *)
  558. IF c.res = Ok THEN
  559. IF Trace THEN
  560. KernelLog.Enter; KernelLog.String("Copy"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  561. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Int(sx, 5); KernelLog.Int(sy, 5); KernelLog.Exit
  562. END;
  563. Raster.Copy(c.w.img, c.w.img, sx, sy, sx+w, sy+h, x, y, c.mode)
  564. END
  565. END
  566. END ReceiveCopyRect;
  567. (* Receive a pixel. *)
  568. PROCEDURE ReceivePixel(c: Connection; VAR pixel: Raster.Pixel);
  569. VAR len: LONGINT; buf: ARRAY 4 OF CHAR;
  570. BEGIN
  571. ReceiveBytes(c, buf, c.bytesPerPixel, len);
  572. c.fmt.unpack(c.fmt, ADDRESSOF(buf[0]), 0, pixel);
  573. pixel[Raster.a] := 0FFX
  574. END ReceivePixel;
  575. (* Receive an RRE rectangle message. *)
  576. PROCEDURE ReceiveRRE(c: Connection; x, y, w, h: LONGINT);
  577. VAR n, len, sx, sy: LONGINT; pixel: Raster.Pixel; buf: ARRAY 8 OF CHAR;
  578. BEGIN
  579. IF Trace THEN
  580. KernelLog.Enter; KernelLog.String("RRE"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  581. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Exit
  582. END;
  583. ReceiveLInt(c, n); (* number-of-subrectangles *)
  584. IF c.res = Ok THEN
  585. ReceivePixel(c, pixel);
  586. IF c.res = Ok THEN
  587. Raster.Fill(c.w.img, x, y, x+w, y+h, pixel, c.mode);
  588. WHILE n > 0 DO
  589. ReceivePixel(c, pixel);
  590. IF c.res # Ok THEN RETURN END;
  591. ReceiveBytes(c, buf, 8, len);
  592. IF c.res # Ok THEN RETURN END;
  593. sx := x+Network.GetNet2(buf, 0); sy := y+Network.GetNet2(buf, 2);
  594. Raster.Fill(c.w.img, sx, sy, sx+Network.GetNet2(buf, 4), sy+Network.GetNet2(buf, 6), pixel, c.mode);
  595. DEC(n)
  596. END
  597. END
  598. END
  599. END ReceiveRRE;
  600. (* Receive a CoRRE rectangle message. *)
  601. PROCEDURE ReceiveCoRRE(c: Connection; x, y, w, h: LONGINT);
  602. VAR n, len, sx, sy: LONGINT; pixel: Raster.Pixel; buf: ARRAY 4 OF CHAR;
  603. BEGIN
  604. IF Trace THEN
  605. KernelLog.Enter; KernelLog.String("CoRRE"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  606. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Exit
  607. END;
  608. ReceiveLInt(c, n); (* number-of-subrectangles *)
  609. IF c.res = Ok THEN
  610. ReceivePixel(c, pixel);
  611. IF c.res = Ok THEN
  612. Raster.Fill(c.w.img, x, y, x+w, y+h, pixel, c.mode);
  613. WHILE n > 0 DO
  614. ReceivePixel(c, pixel);
  615. IF c.res # Ok THEN RETURN END;
  616. ReceiveBytes(c, buf, 4, len);
  617. IF c.res # Ok THEN RETURN END;
  618. sx := x+ORD(buf[0]); sy := y+ORD(buf[1]);
  619. Raster.Fill(c.w.img, sx, sy, sx+ORD(buf[2]), sy+ORD(buf[3]), pixel, c.mode);
  620. DEC(n)
  621. END
  622. END
  623. END
  624. END ReceiveCoRRE;
  625. (* Receive a hextile rectangle message. *)
  626. PROCEDURE ReceiveHextile(c: Connection; x, y, w, h: LONGINT);
  627. CONST
  628. Raw = 0; BackgroundSpecified = 1; ForegroundSpecified = 2; AnySubrects = 3; SubrectsColoured = 4;
  629. VAR
  630. row, col, i, tw, th, wmin, hmin, sx, sy, sw, sh: LONGINT;
  631. bg, fg, pixel: Raster.Pixel; sub: SET; ch: CHAR;
  632. BEGIN
  633. IF Trace THEN
  634. KernelLog.Enter; KernelLog.String("Hex"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  635. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Exit
  636. END;
  637. wmin := (w-1) MOD 16 + 1; hmin := (h-1) MOD 16 + 1;
  638. FOR row := 0 TO (h-1) DIV 16 DO
  639. IF row < (h-1) DIV 16 THEN th := 16 ELSE th := hmin END;
  640. FOR col := 0 TO (w-1) DIV 16 DO
  641. IF col < (w-1) DIV 16 THEN tw := 16 ELSE tw := wmin END;
  642. Receive(c, ch);
  643. IF c.res # Ok THEN RETURN END;
  644. sub := SYSTEM.VAL(SET, LONG(ORD(ch)));
  645. IF Raw IN sub THEN
  646. ReceiveRaw(c, x + 16*col, y + 16*row, tw, th)
  647. ELSE
  648. IF BackgroundSpecified IN sub THEN ReceivePixel(c, bg) END;
  649. IF ForegroundSpecified IN sub THEN ReceivePixel(c, fg) END;
  650. Raster.Fill(c.w.img, x + 16*col, y + 16*row, x + 16*col + tw, y + 16*row + th, bg, c.mode);
  651. IF AnySubrects IN sub THEN
  652. Receive(c, ch);
  653. IF c.res # Ok THEN RETURN END;
  654. FOR i := 1 TO ORD(ch) DO
  655. IF SubrectsColoured IN sub THEN ReceivePixel(c, pixel) ELSE pixel := fg END;
  656. Receive(c, ch);
  657. IF c.res # Ok THEN RETURN END;
  658. sx := ORD(ch) DIV 16; sy := ORD(ch) MOD 16;
  659. Receive(c, ch);
  660. IF c.res # Ok THEN RETURN END;
  661. sw := ORD(ch) DIV 16 + 1; sh := ORD(ch) MOD 16 + 1;
  662. Raster.Fill(c.w.img, x + 16*col + sx, y + 16*row + sy, x + 16*col + sx + sw,
  663. y + 16*row + sy + sh, pixel, c.mode)
  664. END
  665. END
  666. END
  667. END;
  668. IF TraceVisual THEN UpdateDisplay(c, x, y + 16*row, w, th) END
  669. END
  670. END ReceiveHextile;
  671. (* Receive a rectangle message. *)
  672. PROCEDURE ReceiveRectangle(c: Connection);
  673. VAR len, x, y, w, h: LONGINT; buf: ARRAY 12 OF CHAR;
  674. BEGIN
  675. ReceiveBytes(c, buf, 12, len);
  676. x := Network.GetNet2(buf, 0); y := Network.GetNet2(buf, 2);
  677. w := Network.GetNet2(buf, 4); h := Network.GetNet2(buf, 6);
  678. CASE Network.GetNet4(buf, 8) OF (* encoding-type *)
  679. 0: ReceiveRaw(c, x, y, w, h)
  680. |1: ReceiveCopyRect(c, x, y, w, h)
  681. |2: ReceiveRRE(c, x, y, w, h)
  682. |4: ReceiveCoRRE(c, x, y, w, h)
  683. |5: ReceiveHextile(c, x, y, w, h)
  684. END;
  685. UpdateDisplay(c, x, y, w, h)
  686. END ReceiveRectangle;
  687. (* Receive and react on one message from the server. *)
  688. PROCEDURE AwaitResponse(c: Connection);
  689. VAR len: LONGINT; ch: CHAR;
  690. BEGIN
  691. Receive(c, ch);
  692. IF c.res = Ok THEN
  693. CASE ORD(ch) OF
  694. 0: (* FramebufferUpdate (sec. 5.3.1) *)
  695. Receive(c, ch); (* padding *)
  696. IF c.res = Ok THEN ReceiveInt(c, len) END; (* number-of-rectangles *)
  697. WHILE (c.res = Ok) & (len > 0) DO
  698. ReceiveRectangle(c); DEC(len)
  699. END
  700. |1: (* SetColourMapEntries (sec. 5.3.2) *)
  701. Receive(c, ch); (* padding *)
  702. IF c.res = Ok THEN ReceiveInt(c, len) END; (* first-colour *)
  703. IF c.res = Ok THEN ReceiveInt(c, len) END; (* number-of-colours *)
  704. IF (c.res = Ok) & (len > 0) THEN ReceiveIgnore(c, len*6) END
  705. |2: (* Bell (sec. 5.3.3) *)
  706. bell.Ring
  707. |3: (* ServerCutText (sec. 5.3.4) *)
  708. ReceiveIgnore(c, 3); (* padding *)
  709. ReceiveLInt(c, len);
  710. IF (c.res = Ok) & (len > 0) THEN ReceiveIgnore(c, len) END
  711. END
  712. END
  713. END AwaitResponse;
  714. (* Open a VNC connection to the specified server and port. *)
  715. PROCEDURE OpenVNC*(c: Connection; server: IP.Adr; port: LONGINT; pwd: ARRAY OF CHAR);
  716. BEGIN
  717. NEW(c.pcb); c.fip := server;
  718. c.pcb.Open(TCP.NilPort, server, port, c.res);
  719. c.pcb.DelaySend(FALSE);
  720. IF c.res = Ok THEN
  721. c.pcb.AwaitState(TCP.OpenStates, TCP.ClosedStates, OpenTimeout, c.res)
  722. END;
  723. IF c.res = Ok THEN
  724. NEW(c.rcvbuf, InBufSize); c.rcvbufpos := 0; c.rcvbuflen := 0;
  725. IF DoVersion(c) & DoAuthentication(c, pwd) & DoInit(c) THEN
  726. SendRequest(c, FALSE, 0, 0, c.w.img.width, c.w.img.height);
  727. IF c.res = Ok THEN
  728. NEW(c.receiver, c);
  729. NEW(c.sender, c);
  730. c.w.sender := c.sender;
  731. IF PollTimeout # 0 THEN c.sender.HandleTimeout END (* start the timer *)
  732. ELSE
  733. CloseVNC(c)
  734. END
  735. ELSE
  736. CloseVNC(c)
  737. END
  738. END;
  739. IF Trace & (c # NIL) THEN
  740. KernelLog.Enter; KernelLog.String("OpenVNC="); KernelLog.Int(c.res, 1); KernelLog.Exit
  741. END
  742. END OpenVNC;
  743. (* Close a VNC connection. *)
  744. PROCEDURE CloseVNC*(VAR c: Connection);
  745. VAR res: WORD;
  746. BEGIN
  747. pool.Remove(c);
  748. c.pcb.Close();
  749. c.pcb.AwaitState(TCP.ClosedStates, {}, CloseTimeout, res);
  750. IF Trace THEN
  751. KernelLog.Enter; KernelLog.String("CloseVNC="); KernelLog.Int(res, 1); KernelLog.Exit
  752. END;
  753. (*c.pcb := NIL*)
  754. END CloseVNC;
  755. PROCEDURE PrintConnection(c: Connection; out : Streams.Writer);
  756. VAR res: WORD; name: ARRAY 128 OF CHAR;
  757. BEGIN
  758. out.Int(c.id, 1);
  759. CASE c.fmt.code OF
  760. Raster.bgr565:
  761. out.String(" 16-bit")
  762. |Raster.bgra8888:
  763. out.String(" 32-bit")
  764. END;
  765. IF (c.w # NIL) & (c.w.img # NIL) THEN
  766. out.Char(" "); out.Int(c.w.img.width, 1);
  767. out.Char("x"); out.Int(c.w.img.height, 1)
  768. END;
  769. DNS.HostByNumber(c.fip, name, res);
  770. out.Char(" "); out.String(name);
  771. out.Ln
  772. END PrintConnection;
  773. PROCEDURE Show*(context : Commands.Context);
  774. BEGIN
  775. IF ~pool.Empty() THEN
  776. context.out.String("VNC connections"); context.out.Ln;
  777. pool.Enumerate(PrintConnection, context.out);
  778. ELSE
  779. context.out.String("No open connections"); context.out.Ln
  780. END;
  781. END Show;
  782. PROCEDURE ReadString(r: Streams.Reader; VAR s: ARRAY OF CHAR);
  783. VAR i: LONGINT;
  784. BEGIN
  785. i := 0; WHILE (r.res = 0) & (r.Peek() # " ") DO r.Char(s[i]); INC(i) END;
  786. s[i] := 0X; r.SkipBytes(1)
  787. END ReadString;
  788. PROCEDURE Open*(context : Commands.Context); (** server[pwd|?] port *)
  789. VAR
  790. server: IP.Adr; res: WORD; port: LONGINT;
  791. c: Connection; pwd: ARRAY 32 OF CHAR; svr, title: ARRAY 128 OF CHAR;
  792. BEGIN
  793. context.arg.SkipWhitespace; context.arg.String(svr); context.arg.SkipWhitespace;
  794. IF (context.arg.Peek() < "0") OR (context.arg.Peek() > "9") THEN context.arg.String(pwd) END;
  795. context.arg.SkipWhitespace; context.arg.Int(port, FALSE);
  796. IF (context.arg.res = Streams.Ok) OR (context.arg.res = Streams.EOF) THEN
  797. DNS.HostByName(svr, server, res);
  798. IF (res = Ok) & (port # 0) THEN
  799. IF pwd = "?" THEN
  800. IF Dialogs.QueryPassword("Enter VNC Password", pwd) # Dialogs.ResOk THEN RETURN END
  801. END;
  802. NEW(c);
  803. OpenVNC(c, server, port, pwd);
  804. IF c.res = Ok THEN
  805. pool.Add(c);
  806. COPY(svr, title); Files.AppendStr(" Port ", title); Files.AppendInt(port, title); Files.AppendStr(" - VNC ", title); Files.AppendInt(c.id, title);
  807. c.w.SetTitle(WMWindowManager.NewString(title));
  808. Show(context)
  809. ELSE
  810. context.error.String("Error "); context.error.Int(c.res, 1); context.error.Ln
  811. END
  812. ELSE
  813. context.error.String("Error: not found"); context.error.Ln
  814. END
  815. ELSE
  816. context.error.String("Error: expected server[ pwd] port"); context.error.Ln
  817. END;
  818. END Open;
  819. PROCEDURE Paste*(context : Commands.Context); (** connection text *)
  820. VAR i: LONGINT; c: Connection;
  821. BEGIN
  822. context.arg.SkipWhitespace; context.arg.Int(i, FALSE);
  823. c := pool.Find(i);
  824. IF (c # NIL) & (c.sender # NIL) THEN
  825. IF context.arg.Peek() = " " THEN context.arg.SkipBytes(1) END;
  826. c.sender.Paste(context.arg);
  827. END;
  828. END Paste;
  829. BEGIN
  830. NEW(bell); NEW(pool)
  831. END VNC.
  832. VNC.Open portnoy.ethz.ch 5901 ~
  833. VNC.Show
  834. VNC.Paste 0 Hello world~
  835. System.Free VNC ~