VNC.Mod 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  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. PROCEDURE Min(x, y: LONGINT): LONGINT;
  336. BEGIN
  337. IF x <= y THEN RETURN x ELSE RETURN y END
  338. END Min;
  339. (* Get the server's version number and send our version number. *)
  340. PROCEDURE DoVersion(c: Connection): BOOLEAN;
  341. VAR buf: ARRAY 16 OF CHAR; len: LONGINT;
  342. BEGIN
  343. ReceiveBytes(c, buf, 12, len);
  344. IF c.res = Ok THEN
  345. IF Trace THEN
  346. buf[11] := 0X;
  347. KernelLog.Enter; KernelLog.String("Version="); KernelLog.String(buf); KernelLog.Exit
  348. END;
  349. buf := "RFB 003.003"; buf[11] := 0AX;
  350. c.pcb.Send(buf, 0, 12, FALSE, c.res)
  351. END;
  352. RETURN c.res = Ok
  353. END DoVersion;
  354. (* Authenticate ourself with the server. *)
  355. PROCEDURE DoAuthentication(c: Connection; VAR pwd: ARRAY OF CHAR): BOOLEAN;
  356. VAR x, len, len0: LONGINT; buf: ARRAY 64 OF CHAR; cipher: ARRAY 16 OF CHAR; d: DES.DES;
  357. BEGIN
  358. ReceiveLInt(c, x);
  359. IF c.res = Ok THEN
  360. IF Trace THEN
  361. KernelLog.Enter; KernelLog.String("Scheme="); KernelLog.Int(x, 1); KernelLog.Exit
  362. END;
  363. IF x = 0 THEN (* failed *)
  364. ReceiveLInt(c, len); (* read reason *)
  365. WHILE (len > 0) & (c.res = Ok) DO
  366. len0 := Min(len, LEN(buf));
  367. ReceiveBytes(c, buf, len0, len0);
  368. DEC(len, len0)
  369. END;
  370. IF Trace & (c.res = Ok) THEN (* write last part of reason (typically only one part) *)
  371. IF len0 = LEN(buf) THEN DEC(len0) END;
  372. buf[len0] := 0X;
  373. KernelLog.Enter; KernelLog.String("Reason="); KernelLog.String(buf); KernelLog.Exit
  374. END
  375. ELSIF x = 2 THEN (* VNC authentication *)
  376. ReceiveBytes(c, buf, 16, len); (* challenge *)
  377. IF c.res = Ok THEN
  378. NEW(d);
  379. d.SetKey(pwd);
  380. d.Encrypt(buf, 0, cipher, 0); (* Two 8-Byte-Blocks *)
  381. d.Encrypt(buf, 8, cipher, 8);
  382. c.pcb.Send(cipher, 0, 16, FALSE, c.res);
  383. IF c.res = Ok THEN
  384. ReceiveLInt(c, x);
  385. IF c.res = Ok THEN
  386. c.res := x (* 0=Ok, 1=failed, 2=too-many *)
  387. END
  388. END
  389. END
  390. ELSE (* no or unknown authentication *)
  391. (* skip *)
  392. END
  393. END;
  394. RETURN c.res = Ok
  395. END DoAuthentication;
  396. (* Set up an RFB encodings message. "code" contains the codes in preferred order. "len" returns the message length. *)
  397. PROCEDURE PutEncodings(VAR buf: ARRAY OF CHAR; ofs: LONGINT; code: ARRAY OF CHAR; VAR len: LONGINT);
  398. VAR i: LONGINT;
  399. BEGIN
  400. buf[ofs] := 2X; (* SetEncodings (sec. 5.2.3) *)
  401. buf[ofs+1] := 0X; (* padding *)
  402. i := 0;
  403. WHILE code[i] # 0X DO
  404. Network.PutNet4(buf, ofs + 4*(i+1), ORD(code[i])-ORD("0"));
  405. INC(i)
  406. END;
  407. Network.PutNet2(buf, ofs+2, i); (* number-of-encodings *)
  408. len := 4*(i+1)
  409. END PutEncodings;
  410. (* Initialise the transfer format. *)
  411. PROCEDURE DoInit(c: Connection): BOOLEAN;
  412. VAR len, len0, w, h: LONGINT; buf: ARRAY 64 OF CHAR; pixel: Raster.Pixel; ptr: WMWindowManager.PointerInfo;
  413. BEGIN
  414. IF Shared THEN Send(c, 1X) ELSE Send(c, 0X) END;
  415. IF c.res = Ok THEN
  416. ReceiveBytes(c, buf, 24, len); (* initialization message *)
  417. IF c.res = Ok THEN
  418. w := Network.GetNet2(buf, 0); h := Network.GetNet2(buf, 2);
  419. len := Network.GetNet4(buf, 20);
  420. IF Trace THEN
  421. KernelLog.Enter;
  422. KernelLog.String("Server: width="); KernelLog.Int(w, 1);
  423. KernelLog.String(" height="); KernelLog.Int(h, 1);
  424. KernelLog.String(" bpp="); KernelLog.Int(ORD(buf[4]), 1);
  425. KernelLog.String(" depth="); KernelLog.Int(ORD(buf[5]), 1);
  426. KernelLog.String(" bigendian="); KernelLog.Int(ORD(buf[6]), 1);
  427. KernelLog.String(" truecolor="); KernelLog.Int(ORD(buf[7]), 1); KernelLog.Ln;
  428. KernelLog.String(" redmax="); KernelLog.Int(Network.GetNet2(buf, 8), 1);
  429. KernelLog.String(" greenmax="); KernelLog.Int(Network.GetNet2(buf, 10), 1);
  430. KernelLog.String(" bluemax="); KernelLog.Int(Network.GetNet2(buf, 12), 1);
  431. KernelLog.String(" redshift="); KernelLog.Int(ORD(buf[14]), 1);
  432. KernelLog.String(" greenshift="); KernelLog.Int(ORD(buf[15]), 1);
  433. KernelLog.String(" blueshift="); KernelLog.Int(ORD(buf[16]), 1);
  434. KernelLog.String(" len="); KernelLog.Int(len, 1);
  435. KernelLog.Exit
  436. END;
  437. WHILE (len > 0) & (c.res = Ok) DO
  438. len0 := Min(len, LEN(buf));
  439. ReceiveBytes(c, buf, len0, len0);
  440. DEC(len, len0)
  441. END;
  442. IF c.res = Ok THEN
  443. IF Trace THEN (* write last part of name (typically only one part) *)
  444. IF len0 = LEN(buf) THEN DEC(len0) END;
  445. buf[len0] := 0X;
  446. KernelLog.Enter; KernelLog.String("Name="); KernelLog.String(buf); KernelLog.Exit
  447. END;
  448. (* choose our preferred format *)
  449. Raster.InitMode(c.mode, Raster.srcCopy);
  450. NEW(c.w, w, h, FALSE);
  451. NEW(ptr); ptr.hotX := 2; ptr.hotY := 2;
  452. NEW(ptr.img); Raster.Create(ptr.img, 4, 4, Raster.BGRA8888);
  453. Raster.SetRGBA(pixel, 255, 255, 255, AlphaCursor);
  454. Raster.Fill(ptr.img, 0, 0, 4, 4, pixel, c.mode);
  455. Raster.SetRGBA(pixel, 0, 0, 0, AlphaCursor);
  456. Raster.Fill(ptr.img, 1, 1, 3, 3, pixel, c.mode);
  457. c.w.SetPointerInfo(ptr);
  458. WMWindowManager.DefaultAddWindow(c.w);
  459. Raster.SetRGB(pixel, 0, 0, 0);
  460. Raster.Fill(c.w.img, 0, 0, c.w.img.width, c.w.img.height, pixel, c.mode);
  461. c.w.Invalidate(Rect.MakeRect(0, 0, c.w.img.width, c.w.img.height));
  462. NEW(c.nb);
  463. IF c.w.img.fmt.code IN {Raster.bgr888, Raster.bgra8888} THEN
  464. c.fmt := Raster.BGRA8888
  465. ELSE
  466. c.fmt := Raster.BGR565
  467. END;
  468. c.bytesPerPixel := c.fmt.bpp DIV 8;
  469. ASSERT(ImgBufSize >= w*c.bytesPerPixel); (* at least one full line will fit buffer *)
  470. NEW(c.imgbuf, ImgBufSize);
  471. (* set up client format message *)
  472. buf[0] := 0X; (* SetPixelFormat message (sec. 5.2.1) *)
  473. buf[1] := 0X; buf[2] := 0X; buf[3] := 0X; (* padding *)
  474. buf[4] := CHR(c.bytesPerPixel*8); (* bits-per-pixel (8, 16 or 32) on wire *)
  475. buf[5] := CHR(c.fmt.bpp); (* depth (8, 16, 24 or 32) *)
  476. buf[6] := 0X; (* big-endian-flag *)
  477. buf[7] := 1X; (* true-colour-flag *)
  478. CASE c.fmt.code OF
  479. Raster.bgr565:
  480. Network.PutNet2(buf, 8, 31); (* red-max *)
  481. Network.PutNet2(buf, 10, 63); (* green-max *)
  482. Network.PutNet2(buf, 12, 31); (* blue-max *)
  483. buf[14] := CHR(11); (* red-shift *)
  484. buf[15] := CHR(5); (* green-shift *)
  485. buf[16] := CHR(0) (* blue-shift *)
  486. |Raster.bgra8888:
  487. Network.PutNet2(buf, 8, 255); (* red-max *)
  488. Network.PutNet2(buf, 10, 255); (* green-max *)
  489. Network.PutNet2(buf, 12, 255); (* blue-max *)
  490. buf[14] := CHR(16); (* red-shift *)
  491. buf[15] := CHR(8); (* green-shift *)
  492. buf[16] := CHR(0) (* blue-shift *)
  493. END;
  494. PutEncodings(buf, 20, "15420", len); (* 0=raw, 1=copy rectangle, 2=RRE, 4=CoRRE, 5=hextile *)
  495. IF Trace THEN
  496. KernelLog.Enter; KernelLog.String("Client:"); KernelLog.Ln;
  497. KernelLog.Buffer(buf, 0, 20+len); KernelLog.Exit
  498. END;
  499. c.pcb.Send(buf, 0, 20+len, FALSE, c.res)
  500. END
  501. END
  502. END;
  503. RETURN c.res = Ok
  504. END DoInit;
  505. (* Send a framebuffer update request. *)
  506. PROCEDURE SendRequest(c: Connection; inc: BOOLEAN; x, y, w, h: LONGINT);
  507. VAR buf: ARRAY 10 OF CHAR;
  508. BEGIN
  509. IF Trace THEN
  510. KernelLog.Enter; KernelLog.String("Req"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  511. KernelLog.Int(w, 5); KernelLog.Int(h, 5);
  512. IF inc THEN KernelLog.String(" inc") END;
  513. KernelLog.Exit
  514. END;
  515. buf[0] := 3X; (* FramebufferUpdateRequest (sec. 5.2.4) *)
  516. IF inc THEN buf[1] := 1X ELSE buf[1] := 0X END;
  517. Network.PutNet2(buf, 2, x); Network.PutNet2(buf, 4, y);
  518. Network.PutNet2(buf, 6, w); Network.PutNet2(buf, 8, h);
  519. c.pcb.Send(buf, 0, 10, FALSE, c.res)
  520. END SendRequest;
  521. (* Update an area of the display. *)
  522. PROCEDURE UpdateDisplay(c: Connection; x, y, w, h: LONGINT);
  523. (*VAR pixel: Raster.Pixel; mode: Raster.Mode;*)
  524. BEGIN
  525. (*
  526. Raster.SetRGB(pixel, 255, 255, 255);
  527. Raster.InitMode(mode, Raster.InvDst);
  528. Raster.Fill(c.w.img, 0, 0, 5, 5, pixel, mode);
  529. IF (x # 0) OR (y # 0) THEN c.w.AddDirty(0, 0, 10, 10) END;
  530. *)
  531. c.w.Invalidate(Rect.MakeRect(x, y, x + w, y + h))
  532. END UpdateDisplay;
  533. (* Receive a raw rectangle. *)
  534. PROCEDURE ReceiveRaw(c: Connection; x, y, w, h: LONGINT);
  535. VAR bh, h0, len, i: LONGINT;
  536. BEGIN
  537. IF Trace THEN
  538. KernelLog.Enter; KernelLog.String("Raw"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  539. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Exit
  540. END;
  541. bh := LEN(c.imgbuf^) DIV (w*c.bytesPerPixel); (* number of lines that will fit in buffer *)
  542. Raster.Init(c.nb, w, bh, c.fmt, w*c.bytesPerPixel, ADDRESSOF(c.imgbuf[0]));
  543. WHILE h > 0 DO
  544. IF h >= bh THEN h0 := bh ELSE h0 := h END;
  545. len := h0*w*c.bytesPerPixel;
  546. ReceiveBytes(c, c.imgbuf^, len, len);
  547. IF c.res # Ok THEN RETURN END;
  548. IF c.bytesPerPixel = 4 THEN (* fix alpha values *)
  549. FOR i := 0 TO len-1 BY 4 DO c.imgbuf[i+Raster.a] := 0FFX END
  550. END;
  551. Raster.Copy(c.nb, c.w.img, 0, 0, w, h0, x, y, c.mode);
  552. DEC(h, h0); INC(y, h0)
  553. END
  554. END ReceiveRaw;
  555. (* Receive a copy rectangle message. *)
  556. PROCEDURE ReceiveCopyRect(c: Connection; x, y, w, h: LONGINT);
  557. VAR sx, sy: LONGINT;
  558. BEGIN
  559. ReceiveInt(c, sx); (* src-x-position *)
  560. IF c.res = Ok THEN
  561. ReceiveInt(c, sy); (* src-y-position *)
  562. IF c.res = Ok THEN
  563. IF Trace THEN
  564. KernelLog.Enter; KernelLog.String("Copy"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  565. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Int(sx, 5); KernelLog.Int(sy, 5); KernelLog.Exit
  566. END;
  567. Raster.Copy(c.w.img, c.w.img, sx, sy, sx+w, sy+h, x, y, c.mode)
  568. END
  569. END
  570. END ReceiveCopyRect;
  571. (* Receive a pixel. *)
  572. PROCEDURE ReceivePixel(c: Connection; VAR pixel: Raster.Pixel);
  573. VAR len: LONGINT; buf: ARRAY 4 OF CHAR;
  574. BEGIN
  575. ReceiveBytes(c, buf, c.bytesPerPixel, len);
  576. c.fmt.unpack(c.fmt, ADDRESSOF(buf[0]), 0, pixel);
  577. pixel[Raster.a] := 0FFX
  578. END ReceivePixel;
  579. (* Receive an RRE rectangle message. *)
  580. PROCEDURE ReceiveRRE(c: Connection; x, y, w, h: LONGINT);
  581. VAR n, len, sx, sy: LONGINT; pixel: Raster.Pixel; buf: ARRAY 8 OF CHAR;
  582. BEGIN
  583. IF Trace THEN
  584. KernelLog.Enter; KernelLog.String("RRE"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  585. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Exit
  586. END;
  587. ReceiveLInt(c, n); (* number-of-subrectangles *)
  588. IF c.res = Ok THEN
  589. ReceivePixel(c, pixel);
  590. IF c.res = Ok THEN
  591. Raster.Fill(c.w.img, x, y, x+w, y+h, pixel, c.mode);
  592. WHILE n > 0 DO
  593. ReceivePixel(c, pixel);
  594. IF c.res # Ok THEN RETURN END;
  595. ReceiveBytes(c, buf, 8, len);
  596. IF c.res # Ok THEN RETURN END;
  597. sx := x+Network.GetNet2(buf, 0); sy := y+Network.GetNet2(buf, 2);
  598. Raster.Fill(c.w.img, sx, sy, sx+Network.GetNet2(buf, 4), sy+Network.GetNet2(buf, 6), pixel, c.mode);
  599. DEC(n)
  600. END
  601. END
  602. END
  603. END ReceiveRRE;
  604. (* Receive a CoRRE rectangle message. *)
  605. PROCEDURE ReceiveCoRRE(c: Connection; x, y, w, h: LONGINT);
  606. VAR n, len, sx, sy: LONGINT; pixel: Raster.Pixel; buf: ARRAY 4 OF CHAR;
  607. BEGIN
  608. IF Trace THEN
  609. KernelLog.Enter; KernelLog.String("CoRRE"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  610. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Exit
  611. END;
  612. ReceiveLInt(c, n); (* number-of-subrectangles *)
  613. IF c.res = Ok THEN
  614. ReceivePixel(c, pixel);
  615. IF c.res = Ok THEN
  616. Raster.Fill(c.w.img, x, y, x+w, y+h, pixel, c.mode);
  617. WHILE n > 0 DO
  618. ReceivePixel(c, pixel);
  619. IF c.res # Ok THEN RETURN END;
  620. ReceiveBytes(c, buf, 4, len);
  621. IF c.res # Ok THEN RETURN END;
  622. sx := x+ORD(buf[0]); sy := y+ORD(buf[1]);
  623. Raster.Fill(c.w.img, sx, sy, sx+ORD(buf[2]), sy+ORD(buf[3]), pixel, c.mode);
  624. DEC(n)
  625. END
  626. END
  627. END
  628. END ReceiveCoRRE;
  629. (* Receive a hextile rectangle message. *)
  630. PROCEDURE ReceiveHextile(c: Connection; x, y, w, h: LONGINT);
  631. CONST
  632. Raw = 0; BackgroundSpecified = 1; ForegroundSpecified = 2; AnySubrects = 3; SubrectsColoured = 4;
  633. VAR
  634. row, col, i, tw, th, wmin, hmin, sx, sy, sw, sh: LONGINT;
  635. bg, fg, pixel: Raster.Pixel; sub: SET; ch: CHAR;
  636. BEGIN
  637. IF Trace THEN
  638. KernelLog.Enter; KernelLog.String("Hex"); KernelLog.Int(x, 5); KernelLog.Int(y, 5);
  639. KernelLog.Int(w, 5); KernelLog.Int(h, 5); KernelLog.Exit
  640. END;
  641. wmin := (w-1) MOD 16 + 1; hmin := (h-1) MOD 16 + 1;
  642. FOR row := 0 TO (h-1) DIV 16 DO
  643. IF row < (h-1) DIV 16 THEN th := 16 ELSE th := hmin END;
  644. FOR col := 0 TO (w-1) DIV 16 DO
  645. IF col < (w-1) DIV 16 THEN tw := 16 ELSE tw := wmin END;
  646. Receive(c, ch);
  647. IF c.res # Ok THEN RETURN END;
  648. sub := SYSTEM.VAL(SET, LONG(ORD(ch)));
  649. IF Raw IN sub THEN
  650. ReceiveRaw(c, x + 16*col, y + 16*row, tw, th)
  651. ELSE
  652. IF BackgroundSpecified IN sub THEN ReceivePixel(c, bg) END;
  653. IF ForegroundSpecified IN sub THEN ReceivePixel(c, fg) END;
  654. Raster.Fill(c.w.img, x + 16*col, y + 16*row, x + 16*col + tw, y + 16*row + th, bg, c.mode);
  655. IF AnySubrects IN sub THEN
  656. Receive(c, ch);
  657. IF c.res # Ok THEN RETURN END;
  658. FOR i := 1 TO ORD(ch) DO
  659. IF SubrectsColoured IN sub THEN ReceivePixel(c, pixel) ELSE pixel := fg END;
  660. Receive(c, ch);
  661. IF c.res # Ok THEN RETURN END;
  662. sx := ORD(ch) DIV 16; sy := ORD(ch) MOD 16;
  663. Receive(c, ch);
  664. IF c.res # Ok THEN RETURN END;
  665. sw := ORD(ch) DIV 16 + 1; sh := ORD(ch) MOD 16 + 1;
  666. Raster.Fill(c.w.img, x + 16*col + sx, y + 16*row + sy, x + 16*col + sx + sw,
  667. y + 16*row + sy + sh, pixel, c.mode)
  668. END
  669. END
  670. END
  671. END;
  672. IF TraceVisual THEN UpdateDisplay(c, x, y + 16*row, w, th) END
  673. END
  674. END ReceiveHextile;
  675. (* Receive a rectangle message. *)
  676. PROCEDURE ReceiveRectangle(c: Connection);
  677. VAR len, x, y, w, h: LONGINT; buf: ARRAY 12 OF CHAR;
  678. BEGIN
  679. ReceiveBytes(c, buf, 12, len);
  680. x := Network.GetNet2(buf, 0); y := Network.GetNet2(buf, 2);
  681. w := Network.GetNet2(buf, 4); h := Network.GetNet2(buf, 6);
  682. CASE Network.GetNet4(buf, 8) OF (* encoding-type *)
  683. 0: ReceiveRaw(c, x, y, w, h)
  684. |1: ReceiveCopyRect(c, x, y, w, h)
  685. |2: ReceiveRRE(c, x, y, w, h)
  686. |4: ReceiveCoRRE(c, x, y, w, h)
  687. |5: ReceiveHextile(c, x, y, w, h)
  688. END;
  689. UpdateDisplay(c, x, y, w, h)
  690. END ReceiveRectangle;
  691. (* Receive and react on one message from the server. *)
  692. PROCEDURE AwaitResponse(c: Connection);
  693. VAR len: LONGINT; ch: CHAR;
  694. BEGIN
  695. Receive(c, ch);
  696. IF c.res = Ok THEN
  697. CASE ORD(ch) OF
  698. 0: (* FramebufferUpdate (sec. 5.3.1) *)
  699. Receive(c, ch); (* padding *)
  700. IF c.res = Ok THEN ReceiveInt(c, len) END; (* number-of-rectangles *)
  701. WHILE (c.res = Ok) & (len > 0) DO
  702. ReceiveRectangle(c); DEC(len)
  703. END
  704. |1: (* SetColourMapEntries (sec. 5.3.2) *)
  705. Receive(c, ch); (* padding *)
  706. IF c.res = Ok THEN ReceiveInt(c, len) END; (* first-colour *)
  707. IF c.res = Ok THEN ReceiveInt(c, len) END; (* number-of-colours *)
  708. IF (c.res = Ok) & (len > 0) THEN ReceiveIgnore(c, len*6) END
  709. |2: (* Bell (sec. 5.3.3) *)
  710. bell.Ring
  711. |3: (* ServerCutText (sec. 5.3.4) *)
  712. ReceiveIgnore(c, 3); (* padding *)
  713. ReceiveLInt(c, len);
  714. IF (c.res = Ok) & (len > 0) THEN ReceiveIgnore(c, len) END
  715. END
  716. END
  717. END AwaitResponse;
  718. (* Open a VNC connection to the specified server and port. *)
  719. PROCEDURE OpenVNC*(c: Connection; server: IP.Adr; port: LONGINT; pwd: ARRAY OF CHAR);
  720. BEGIN
  721. NEW(c.pcb); c.fip := server;
  722. c.pcb.Open(TCP.NilPort, server, port, c.res);
  723. c.pcb.DelaySend(FALSE);
  724. IF c.res = Ok THEN
  725. c.pcb.AwaitState(TCP.OpenStates, TCP.ClosedStates, OpenTimeout, c.res)
  726. END;
  727. IF c.res = Ok THEN
  728. NEW(c.rcvbuf, InBufSize); c.rcvbufpos := 0; c.rcvbuflen := 0;
  729. IF DoVersion(c) & DoAuthentication(c, pwd) & DoInit(c) THEN
  730. SendRequest(c, FALSE, 0, 0, c.w.img.width, c.w.img.height);
  731. IF c.res = Ok THEN
  732. NEW(c.receiver, c);
  733. NEW(c.sender, c);
  734. c.w.sender := c.sender;
  735. IF PollTimeout # 0 THEN c.sender.HandleTimeout END (* start the timer *)
  736. ELSE
  737. CloseVNC(c)
  738. END
  739. ELSE
  740. CloseVNC(c)
  741. END
  742. END;
  743. IF Trace & (c # NIL) THEN
  744. KernelLog.Enter; KernelLog.String("OpenVNC="); KernelLog.Int(c.res, 1); KernelLog.Exit
  745. END
  746. END OpenVNC;
  747. (* Close a VNC connection. *)
  748. PROCEDURE CloseVNC*(VAR c: Connection);
  749. VAR res: WORD;
  750. BEGIN
  751. pool.Remove(c);
  752. c.pcb.Close();
  753. c.pcb.AwaitState(TCP.ClosedStates, {}, CloseTimeout, res);
  754. IF Trace THEN
  755. KernelLog.Enter; KernelLog.String("CloseVNC="); KernelLog.Int(res, 1); KernelLog.Exit
  756. END;
  757. (*c.pcb := NIL*)
  758. END CloseVNC;
  759. PROCEDURE PrintConnection(c: Connection; out : Streams.Writer);
  760. VAR res: WORD; name: ARRAY 128 OF CHAR;
  761. BEGIN
  762. out.Int(c.id, 1);
  763. CASE c.fmt.code OF
  764. Raster.bgr565:
  765. out.String(" 16-bit")
  766. |Raster.bgra8888:
  767. out.String(" 32-bit")
  768. END;
  769. IF (c.w # NIL) & (c.w.img # NIL) THEN
  770. out.Char(" "); out.Int(c.w.img.width, 1);
  771. out.Char("x"); out.Int(c.w.img.height, 1)
  772. END;
  773. DNS.HostByNumber(c.fip, name, res);
  774. out.Char(" "); out.String(name);
  775. out.Ln
  776. END PrintConnection;
  777. PROCEDURE Show*(context : Commands.Context);
  778. BEGIN
  779. IF ~pool.Empty() THEN
  780. context.out.String("VNC connections"); context.out.Ln;
  781. pool.Enumerate(PrintConnection, context.out);
  782. ELSE
  783. context.out.String("No open connections"); context.out.Ln
  784. END;
  785. END Show;
  786. PROCEDURE ReadString(r: Streams.Reader; VAR s: ARRAY OF CHAR);
  787. VAR i: LONGINT;
  788. BEGIN
  789. i := 0; WHILE (r.res = 0) & (r.Peek() # " ") DO r.Char(s[i]); INC(i) END;
  790. s[i] := 0X; r.SkipBytes(1)
  791. END ReadString;
  792. PROCEDURE Open*(context : Commands.Context); (** server[pwd|?] port *)
  793. VAR
  794. server: IP.Adr; res: WORD; port: LONGINT;
  795. c: Connection; pwd: ARRAY 32 OF CHAR; svr, title: ARRAY 128 OF CHAR;
  796. BEGIN
  797. context.arg.SkipWhitespace; context.arg.String(svr); context.arg.SkipWhitespace;
  798. IF (context.arg.Peek() < "0") OR (context.arg.Peek() > "9") THEN context.arg.String(pwd) END;
  799. context.arg.SkipWhitespace; context.arg.Int(port, FALSE);
  800. IF (context.arg.res = Streams.Ok) OR (context.arg.res = Streams.EOF) THEN
  801. DNS.HostByName(svr, server, res);
  802. IF (res = Ok) & (port # 0) THEN
  803. IF pwd = "?" THEN
  804. IF Dialogs.QueryPassword("Enter VNC Password", pwd) # Dialogs.ResOk THEN RETURN END
  805. END;
  806. NEW(c);
  807. OpenVNC(c, server, port, pwd);
  808. IF c.res = Ok THEN
  809. pool.Add(c);
  810. COPY(svr, title); Files.AppendStr(" Port ", title); Files.AppendInt(port, title); Files.AppendStr(" - VNC ", title); Files.AppendInt(c.id, title);
  811. c.w.SetTitle(WMWindowManager.NewString(title));
  812. Show(context)
  813. ELSE
  814. context.error.String("Error "); context.error.Int(c.res, 1); context.error.Ln
  815. END
  816. ELSE
  817. context.error.String("Error: not found"); context.error.Ln
  818. END
  819. ELSE
  820. context.error.String("Error: expected server[ pwd] port"); context.error.Ln
  821. END;
  822. END Open;
  823. PROCEDURE Paste*(context : Commands.Context); (** connection text *)
  824. VAR i: LONGINT; c: Connection;
  825. BEGIN
  826. context.arg.SkipWhitespace; context.arg.Int(i, FALSE);
  827. c := pool.Find(i);
  828. IF (c # NIL) & (c.sender # NIL) THEN
  829. IF context.arg.Peek() = " " THEN context.arg.SkipBytes(1) END;
  830. c.sender.Paste(context.arg);
  831. END;
  832. END Paste;
  833. BEGIN
  834. NEW(bell); NEW(pool)
  835. END VNC.
  836. VNC.Open portnoy.ethz.ch 5901 ~
  837. VNC.Show
  838. VNC.Paste 0 Hello world~
  839. System.Free VNC ~