NoctisRfbProto.java 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247
  1. // Copyright (C) 2002-2004 Ultr@VNC Team. All Rights Reserved.
  2. // Copyright (C) 2004 Kenn Min Chong, John Witchel. All Rights Reserved.
  3. // Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
  4. // Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
  5. // Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
  6. // Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
  7. //
  8. // This is free software; you can redistribute it and/or modify
  9. // it under the terms of the GNU General Public License as published by
  10. // the Free Software Foundation; either version 2 of the License, or
  11. // (at your option) any later version.
  12. //
  13. // This software is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU General Public License
  19. // along with this software; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  21. // USA.
  22. //
  23. //
  24. // RfbProto.java
  25. //4/19/04
  26. import java.awt.event.InputEvent;
  27. import java.awt.event.KeyEvent;
  28. import java.awt.event.MouseEvent;
  29. import java.io.BufferedInputStream;
  30. import java.io.DataInputStream;
  31. import java.io.File;
  32. import java.io.FileInputStream;
  33. import java.io.FileOutputStream;
  34. import java.io.IOException;
  35. import java.io.OutputStream;
  36. import java.io.OutputStreamWriter;
  37. import java.net.Socket;
  38. import java.util.ArrayList;
  39. import java.util.zip.DataFormatException;
  40. import java.util.zip.Deflater;
  41. import java.util.zip.Inflater;
  42. import javax.swing.JOptionPane;
  43. class NoctisRfbProto {
  44. final String versionMsg = "RFB 003.003\n";
  45. final static int ConnFailed = 0, NoAuth = 1, VncAuth = 2, MsLogon = 0xfffffffa;
  46. final static int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2;
  47. final static int FramebufferUpdate = 0, SetColourMapEntries = 1, Bell = 2, ServerCutText = 3, rfbFileTransfer = 7;
  48. final int SetPixelFormat = 0, FixColourMapEntries = 1, SetEncodings = 2, FramebufferUpdateRequest = 3, KeyboardEvent = 4, PointerEvent = 5, ClientCutText = 6;
  49. final static int EncodingRaw = 0, EncodingCopyRect = 1, EncodingRRE = 2, EncodingCoRRE = 4, EncodingHextile = 5, EncodingZlib = 6, EncodingTight = 7, EncodingCompressLevel0 = 0xFFFFFF00,
  50. EncodingQualityLevel0 = 0xFFFFFFE0, EncodingXCursor = 0xFFFFFF10, EncodingRichCursor = 0xFFFFFF11, EncodingPointerPos = 0xFFFFFF18, // marscha - PointerPos
  51. EncodingLastRect = 0xFFFFFF20, EncodingNewFBSize = 0xFFFFFF21;
  52. final int HextileRaw = (1 << 0);
  53. final int HextileBackgroundSpecified = (1 << 1);
  54. final int HextileForegroundSpecified = (1 << 2);
  55. final int HextileAnySubrects = (1 << 3);
  56. final int HextileSubrectsColoured = (1 << 4);
  57. final static int TightExplicitFilter = 0x04;
  58. final static int TightFill = 0x08;
  59. final static int TightJpeg = 0x09;
  60. final static int TightMaxSubencoding = 0x09;
  61. final static int TightFilterCopy = 0x00;
  62. final static int TightFilterPalette = 0x01;
  63. final static int TightFilterGradient = 0x02;
  64. final static int TightMinToCompress = 12;
  65. // sf@2004 - FileTransfer part
  66. ArrayList remoteDirsList;
  67. ArrayList remoteFilesList;
  68. ArrayList a;
  69. boolean fFTInit = true; // sf@2004
  70. boolean fFTAllowed = true;
  71. boolean fAbort = false;
  72. boolean fFileReceptionError = false;
  73. boolean fFileReceptionRunning = false;
  74. boolean inDirectory2;
  75. FileOutputStream fos;
  76. FileInputStream fis;
  77. String sendFileSource;
  78. String receivePath;
  79. long fileSize;
  80. long receiveFileSize;
  81. long fileChunkCounter;
  82. final static int sz_rfbFileTransferMsg = 12,
  83. // FileTransfer Content types and Params defines
  84. rfbDirContentRequest = 1,
  85. // Client asks for the content of a given Server directory
  86. rfbDirPacket = 2, // Full directory name or full file name.
  87. // Null content means end of Directory
  88. rfbFileTransferRequest = 3,
  89. // Client asks the server for the tranfer of a given file
  90. rfbFileHeader = 4,
  91. // First packet of a file transfer, containing file's features
  92. rfbFilePacket = 5, // One slice of the file
  93. rfbEndOfFile = 6,
  94. // End of file transfer (the file has been received or error)
  95. rfbAbortFileTransfer = 7,
  96. // The file transfer must be aborted, whatever the state
  97. rfbFileTransferOffer = 8,
  98. // The client offers to send a file to the server
  99. rfbFileAcceptHeader = 9, // The server accepts or rejects the file
  100. rfbCommand = 10,
  101. // The Client sends a simple command (File Delete, Dir create etc...)
  102. rfbCommandReturn = 11,
  103. // New FT Protocole (V2) The zipped checksums of the destination file (Delta Transfer)
  104. rfbFileChecksums = 12,
  105. // The Client receives the server's answer about a simple command
  106. // rfbDirContentRequest client Request - content params
  107. rfbRDirContent = 1, // Request a Server Directory contents
  108. rfbRDrivesList = 2, // Request the server's drives list
  109. // rfbDirPacket & rfbCommandReturn server Answer - content params
  110. rfbADirectory = 1, // Reception of a directory name
  111. rfbAFile = 2, // Reception of a file name
  112. rfbADrivesList = 3, // Reception of a list of drives
  113. rfbADirCreate = 4, // Response to a create dir command
  114. rfbADirDelete = 5, // Response to a delete dir command
  115. rfbAFileCreate = 6, // Response to a create file command
  116. rfbAFileDelete = 7, // Response to a delete file command
  117. // rfbCommand Command - content params
  118. rfbCDirCreate = 1, // Request the server to create the given directory
  119. rfbCDirDelete = 2, // Request the server to delete the given directory
  120. rfbCFileCreate = 3, // Request the server to create the given file
  121. rfbCFileDelete = 4, // Request the server to delete the given file
  122. // Errors - content params or "size" field
  123. rfbRErrorUnknownCmd = 1, // Unknown FileTransfer command.
  124. rfbRErrorCmd = 0xFFFFFFFF,
  125. // Error when a command fails on remote side (ret in "size" field)
  126. sz_rfbBlockSize = 8192, // new FT protocole (v2)
  127. // Size of a File Transfer packet (before compression)
  128. sz_rfbZipDirectoryPrefix = 9;
  129. String rfbZipDirectoryPrefix = "!UVNCDIR-\0";
  130. // Transfered directory are zipped in a file with this prefix. Must end with "-"
  131. // End of FileTransfer part
  132. String host;
  133. int port;
  134. Socket sock;
  135. DataInputStream is;
  136. OutputStream os;
  137. OutputStreamWriter osw;
  138. SessionRecorder rec;
  139. boolean inNormalProtocol = false;
  140. // VncViewer viewer;
  141. ConfigClientBean config;
  142. // Java on UNIX does not call keyPressed() on some keys, for example
  143. // swedish keys To prevent our workaround to produce duplicate
  144. // keypresses on JVMs that actually works, keep track of if
  145. // keyPressed() for a "broken" key was called or not.
  146. boolean brokenKeyPressed = false;
  147. // This will be set to true on the first framebuffer update
  148. // containing Zlib- or Tight-encoded data.
  149. boolean wereZlibUpdates = false;
  150. // This will be set to false if the startSession() was called after
  151. // we have received at least one Zlib- or Tight-encoded framebuffer
  152. // update.
  153. boolean recordFromBeginning = true;
  154. // This fields are needed to show warnings about inefficiently saved
  155. // sessions only once per each saved session file.
  156. boolean zlibWarningShown;
  157. boolean tightWarningShown;
  158. // Before starting to record each saved session, we set this field
  159. // to 0, and increment on each framebuffer update. We don't flush
  160. // the SessionRecorder data into the file before the second update.
  161. // This allows us to write initial framebuffer update with zero
  162. // timestamp, to let the player show initial desktop before
  163. // playback.
  164. int numUpdatesInSession;
  165. //
  166. // Constructor. Make TCP connection to RFB server.
  167. //
  168. NoctisRfbProto(String h, int p, ConfigClientBean c) throws IOException {
  169. config = c;
  170. host = h;
  171. port = p;
  172. sock = new Socket(host, port);
  173. is = new DataInputStream(new BufferedInputStream(sock.getInputStream(), 16384));
  174. os = sock.getOutputStream();
  175. osw = new OutputStreamWriter(sock.getOutputStream());
  176. inDirectory2 = false;
  177. a = new ArrayList();
  178. // sf@2004
  179. remoteDirsList = new ArrayList();
  180. remoteFilesList = new ArrayList();
  181. sendFileSource = "";
  182. }
  183. void close() {
  184. try {
  185. sock.close();
  186. if (rec != null) {
  187. rec.close();
  188. rec = null;
  189. }
  190. } catch (Exception e) {
  191. e.printStackTrace();
  192. }
  193. }
  194. //
  195. // Read server's protocol version message
  196. //
  197. int serverMajor, serverMinor;
  198. void readVersionMsg() throws Exception {
  199. byte[] b = new byte[12];
  200. is.readFully(b);
  201. if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ') || (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9') || (b[6] < '0') || (b[6] > '9') || (b[7] != '.')
  202. || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9') || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n')) {
  203. throw new Exception("Host " + host + " port " + port + " is not an RFB server");
  204. }
  205. serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
  206. serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
  207. }
  208. //
  209. // Write our protocol version message
  210. //
  211. void writeVersionMsg() throws IOException {
  212. os.write(versionMsg.getBytes());
  213. }
  214. //
  215. // Find out the authentication scheme.
  216. //
  217. int readAuthScheme() throws Exception {
  218. int authScheme = is.readInt();
  219. switch (authScheme) {
  220. case ConnFailed:
  221. int reasonLen = is.readInt();
  222. byte[] reason = new byte[reasonLen];
  223. is.readFully(reason);
  224. throw new Exception(new String(reason));
  225. case NoAuth:
  226. case VncAuth:
  227. case MsLogon:
  228. return authScheme;
  229. default:
  230. throw new Exception("Unknown authentication scheme from RFB server: " + authScheme);
  231. }
  232. }
  233. //
  234. // Write the client initialisation message
  235. //
  236. void writeClientInit() throws IOException {
  237. if (config.isShareDesktop()) {
  238. os.write(1);
  239. } else {
  240. os.write(0);
  241. }
  242. config.setShareDesktop(false);
  243. }
  244. //
  245. // Read the server initialisation message
  246. //
  247. String desktopName;
  248. int framebufferWidth, framebufferHeight;
  249. int bitsPerPixel, depth;
  250. boolean bigEndian, trueColour;
  251. int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
  252. void readServerInit() throws IOException {
  253. framebufferWidth = is.readUnsignedShort();
  254. framebufferHeight = is.readUnsignedShort();
  255. bitsPerPixel = is.readUnsignedByte();
  256. depth = is.readUnsignedByte();
  257. bigEndian = (is.readUnsignedByte() != 0);
  258. trueColour = (is.readUnsignedByte() != 0);
  259. redMax = is.readUnsignedShort();
  260. greenMax = is.readUnsignedShort();
  261. blueMax = is.readUnsignedShort();
  262. redShift = is.readUnsignedByte();
  263. greenShift = is.readUnsignedByte();
  264. blueShift = is.readUnsignedByte();
  265. byte[] pad = new byte[3];
  266. is.readFully(pad);
  267. int nameLength = is.readInt();
  268. byte[] name = new byte[nameLength];
  269. is.readFully(name);
  270. desktopName = new String(name);
  271. inNormalProtocol = true;
  272. }
  273. //
  274. // Create session file and write initial protocol messages into it.
  275. //
  276. void startSession(String fname) throws IOException {
  277. rec = new SessionRecorder(fname);
  278. rec.writeHeader();
  279. rec.write(versionMsg.getBytes());
  280. rec.writeIntBE(NoAuth);
  281. rec.writeShortBE(framebufferWidth);
  282. rec.writeShortBE(framebufferHeight);
  283. byte[] fbsServerInitMsg = { 32, 24, 0, 1, 0, (byte) 0xFF, 0, (byte) 0xFF, 0, (byte) 0xFF, 16, 8, 0, 0, 0, 0 };
  284. rec.write(fbsServerInitMsg);
  285. rec.writeIntBE(desktopName.length());
  286. rec.write(desktopName.getBytes());
  287. numUpdatesInSession = 0;
  288. if (wereZlibUpdates)
  289. recordFromBeginning = false;
  290. zlibWarningShown = false;
  291. tightWarningShown = false;
  292. }
  293. //
  294. // Close session file.
  295. //
  296. void closeSession() throws IOException {
  297. if (rec != null) {
  298. rec.close();
  299. rec = null;
  300. }
  301. }
  302. //
  303. // Set new framebuffer size
  304. //
  305. void setFramebufferSize(int width, int height) {
  306. framebufferWidth = width;
  307. framebufferHeight = height;
  308. }
  309. //
  310. // Read the server message type
  311. //
  312. int readServerMessageType() throws IOException {
  313. int msgType = is.readUnsignedByte();
  314. // If the session is being recorded:
  315. if (rec != null) {
  316. if (msgType == Bell) { // Save Bell messages in session files.
  317. rec.writeByte(msgType);
  318. if (numUpdatesInSession > 0)
  319. rec.flush();
  320. }
  321. }
  322. return msgType;
  323. }
  324. //
  325. // Read a FramebufferUpdate message
  326. //
  327. int updateNRects;
  328. void readFramebufferUpdate() throws IOException {
  329. is.readByte();
  330. updateNRects = is.readUnsignedShort();
  331. // If the session is being recorded:
  332. if (rec != null) {
  333. rec.writeByte(FramebufferUpdate);
  334. rec.writeByte(0);
  335. rec.writeShortBE(updateNRects);
  336. }
  337. numUpdatesInSession++;
  338. }
  339. // Read a FramebufferUpdate rectangle header
  340. int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
  341. void readFramebufferUpdateRectHdr() throws Exception {
  342. updateRectX = is.readUnsignedShort();
  343. updateRectY = is.readUnsignedShort();
  344. updateRectW = is.readUnsignedShort();
  345. updateRectH = is.readUnsignedShort();
  346. updateRectEncoding = is.readInt();
  347. if (updateRectEncoding == EncodingZlib || updateRectEncoding == EncodingTight)
  348. wereZlibUpdates = true;
  349. // If the session is being recorded:
  350. if (rec != null) {
  351. if (numUpdatesInSession > 1)
  352. rec.flush(); // Flush the output on each rectangle.
  353. rec.writeShortBE(updateRectX);
  354. rec.writeShortBE(updateRectY);
  355. rec.writeShortBE(updateRectW);
  356. rec.writeShortBE(updateRectH);
  357. if (updateRectEncoding == EncodingZlib && !recordFromBeginning) {
  358. // Here we cannot write Zlib-encoded rectangles because the
  359. // decoder won't be able to reproduce zlib stream state.
  360. if (!zlibWarningShown) {
  361. System.out.println("Warning: Raw encoding will be used " + "instead of Zlib in recorded session.");
  362. zlibWarningShown = true;
  363. }
  364. rec.writeIntBE(EncodingRaw);
  365. } else {
  366. rec.writeIntBE(updateRectEncoding);
  367. if (updateRectEncoding == EncodingTight && !recordFromBeginning && !tightWarningShown) {
  368. System.out.println("Warning: Re-compressing Tight-encoded " + "updates for session recording.");
  369. tightWarningShown = true;
  370. }
  371. }
  372. }
  373. if (updateRectEncoding == EncodingLastRect || updateRectEncoding == EncodingNewFBSize)
  374. return;
  375. if (updateRectX + updateRectW > framebufferWidth || updateRectY + updateRectH > framebufferHeight) {
  376. throw new Exception("Framebuffer update rectangle too large: " + updateRectW + "x" + updateRectH + " at (" + updateRectX + "," + updateRectY + ")");
  377. }
  378. }
  379. // Read CopyRect source X and Y.
  380. int copyRectSrcX, copyRectSrcY;
  381. void readCopyRect() throws IOException {
  382. copyRectSrcX = is.readUnsignedShort();
  383. copyRectSrcY = is.readUnsignedShort();
  384. // If the session is being recorded:
  385. if (rec != null) {
  386. rec.writeShortBE(copyRectSrcX);
  387. rec.writeShortBE(copyRectSrcY);
  388. }
  389. }
  390. //
  391. // Read a ServerCutText message
  392. //
  393. String readServerCutText() throws IOException {
  394. byte[] pad = new byte[3];
  395. is.readFully(pad);
  396. int len = is.readInt();
  397. byte[] text = new byte[len];
  398. is.readFully(text);
  399. return new String(text);
  400. }
  401. //
  402. // Read an integer in compact representation (1..3 bytes).
  403. // Such format is used as a part of the Tight encoding.
  404. // Also, this method records data if session recording is active and
  405. // the viewer's recordFromBeginning variable is set to true.
  406. //
  407. int readCompactLen() throws IOException {
  408. int[] portion = new int[3];
  409. portion[0] = is.readUnsignedByte();
  410. int byteCount = 1;
  411. int len = portion[0] & 0x7F;
  412. if ((portion[0] & 0x80) != 0) {
  413. portion[1] = is.readUnsignedByte();
  414. byteCount++;
  415. len |= (portion[1] & 0x7F) << 7;
  416. if ((portion[1] & 0x80) != 0) {
  417. portion[2] = is.readUnsignedByte();
  418. byteCount++;
  419. len |= (portion[2] & 0xFF) << 14;
  420. }
  421. }
  422. if (rec != null && recordFromBeginning)
  423. for (int i = 0; i < byteCount; i++)
  424. rec.writeByte(portion[i]);
  425. return len;
  426. }
  427. // Author: Kenn Min Chong/////////////////////////////////////////////
  428. // Read/Write a rfbFileTransferMsg
  429. /*
  430. * typedef struct _rfbFileTransferMsg { CARD8 type; // always rfbFileTransfer CARD8 contentType; // See defines below CARD16 contentParam;// Other possible content classification (Dir or File
  431. * name, etc..) CARD32 size; // FileSize or packet index or error or other CARD32 length; // followed by data char text[length] } rfbFileTransferMsg;
  432. */
  433. // Parsing Rfb message to see what type
  434. void readRfbFileTransferMsg() throws IOException {
  435. int contentType = is.readUnsignedByte();
  436. int contentParamT = is.readUnsignedByte();
  437. int contentParam = contentParamT;
  438. contentParamT = is.readUnsignedByte();
  439. contentParamT = contentParamT << 8;
  440. contentParam = contentParam | contentParamT;
  441. if (contentType == rfbRDrivesList || contentType == rfbDirPacket) {
  442. readDriveOrDirectory(contentParam);
  443. } else if (contentType == rfbFileHeader) {
  444. receiveFileHeader();
  445. } else if (contentType == rfbFilePacket) {
  446. receiveFileChunk();
  447. } else if (contentType == rfbEndOfFile) {
  448. endOfReceiveFile(true); // Ok
  449. } else if (contentType == rfbAbortFileTransfer) {
  450. if (fFileReceptionRunning) {
  451. endOfReceiveFile(false); // Error
  452. } else {
  453. // sf@2004 - Todo: Add TestPermission
  454. // System.out.println("File Transfer Aborted!");
  455. }
  456. } else if (contentType == rfbFileChecksums) {
  457. ReceiveDestinationFileChecksums();
  458. } else {
  459. System.out.println("ContentType: " + contentType);
  460. }
  461. }
  462. // Refactored from readRfbFileTransferMsg()
  463. public void readDriveOrDirectory(int contentParam) throws IOException {
  464. if (contentParam == rfbADrivesList) {
  465. readFTPMsgDriveList();
  466. } else if (contentParam == rfbADirectory && !inDirectory2) {
  467. inDirectory2 = true;
  468. readFTPMsgDirectoryList();
  469. } else if (contentParam == rfbADirectory && inDirectory2) {
  470. readFTPMsgDirectoryListContent();
  471. } else if (contentParam == 0) {
  472. readFTPMsgDirectoryListEndContent();
  473. inDirectory2 = false;
  474. } else {
  475. System.out.println("ContentParam: " + contentParam);
  476. }
  477. }
  478. // Internally used. Write an Rfb message to the server
  479. void writeRfbFileTransferMsg(int contentType, int contentParam, long size, // 0 : compression not supported - 1 : compression supported
  480. long length, String text) throws IOException {
  481. byte b[] = new byte[12];
  482. b[0] = (byte) rfbFileTransfer;
  483. b[1] = (byte) contentType;
  484. b[2] = (byte) contentParam;
  485. byte by = 0;
  486. long c = 0;
  487. length++;
  488. c = size & 0xFF000000;
  489. by = (byte) (c >>> 24);
  490. b[4] = by;
  491. c = size & 0xFF0000;
  492. by = (byte) (c >>> 16);
  493. b[5] = by;
  494. c = size & 0xFF00;
  495. by = (byte) (c >>> 8);
  496. b[6] = by;
  497. c = size & 0xFF;
  498. by = (byte) c;
  499. b[7] = by;
  500. c = length & 0xFF000000;
  501. by = (byte) (c >>> 24);
  502. b[8] = by;
  503. c = length & 0xFF0000;
  504. by = (byte) (c >>> 16);
  505. b[9] = by;
  506. c = length & 0xFF00;
  507. by = (byte) (c >>> 8);
  508. b[10] = by;
  509. c = length & 0xFF;
  510. by = (byte) c;
  511. b[11] = by;
  512. os.write(b);
  513. if (text != null) {
  514. byte byteArray[] = text.getBytes();
  515. byte byteArray2[] = new byte[byteArray.length + 1];
  516. for (int i = 0; i < byteArray.length; i++) {
  517. byteArray2[i] = byteArray[i];
  518. }
  519. byteArray2[byteArray2.length - 1] = 0;
  520. os.write(byteArray2);
  521. }
  522. }
  523. // Call this method to send a file from local pc to server
  524. void offerLocalFile(String source, String destinationPath) {
  525. try {
  526. sendFileSource = source;
  527. File f = new File(source);
  528. // sf@2004 - Add support for huge files
  529. long lSize = f.length();
  530. int iLowSize = (int) (lSize & 0x00000000FFFFFFFF);
  531. int iHighSize = (int) (lSize >> 32);
  532. String temp = destinationPath + f.getName();
  533. writeRfbFileTransferMsg(rfbFileTransferOffer, 0, iLowSize, // f.length(),
  534. temp.length(), temp);
  535. // sf@2004 - Send the high part of the size
  536. byte b[] = new byte[4];
  537. byte by = 0;
  538. long c = 0;
  539. c = iHighSize & 0xFF000000;
  540. by = (byte) (c >>> 24);
  541. b[0] = by;
  542. c = iHighSize & 0xFF0000;
  543. by = (byte) (c >>> 16);
  544. b[1] = by;
  545. c = iHighSize & 0xFF00;
  546. by = (byte) (c >>> 8);
  547. b[2] = by;
  548. c = iHighSize & 0xFF;
  549. by = (byte) c;
  550. b[3] = by;
  551. os.write(b);
  552. } catch (IOException e) {
  553. System.err.println(e);
  554. }
  555. }
  556. // Call this method to delete a file at server
  557. void deleteRemoteFile(String text) {
  558. try {
  559. String temp = text;
  560. writeRfbFileTransferMsg(rfbCommand, rfbCFileDelete, 0, temp.length(), temp);
  561. } catch (IOException e) {
  562. System.err.println(e);
  563. }
  564. }
  565. // Call this method to create a directory at server
  566. void createRemoteDirectory(String text) {
  567. try {
  568. String temp = text;
  569. writeRfbFileTransferMsg(rfbCommand, rfbCDirCreate, 0, temp.length(), temp);
  570. } catch (IOException e) {
  571. System.err.println(e);
  572. }
  573. }
  574. // Call this method to get a file from the server
  575. void requestRemoteFile(String text, String localPath) {
  576. try {
  577. String temp = text;
  578. receivePath = localPath;
  579. writeRfbFileTransferMsg(rfbFileTransferRequest, 0, 1, // 0 : compression not supported - 1 : compression supported
  580. temp.length(), temp);
  581. } catch (IOException e) {
  582. System.err.println(e);
  583. }
  584. }
  585. // Internally used when transferring file from server. Here, the server sends
  586. // a rfb packet signalling that it is ready to send the file requested
  587. void receiveFileHeader() throws IOException {
  588. fFileReceptionRunning = true;
  589. fFileReceptionError = false;
  590. int size = is.readInt();
  591. int length = is.readInt();
  592. String tempName = "";
  593. for (int i = 0; i < length; i++) {
  594. tempName += (char) is.readUnsignedByte();
  595. }
  596. // sf@2004 - Read the high part of file size (not yet in rfbFileTransferMsg for
  597. // backward compatibility reasons...)
  598. int sizeH = is.readInt();
  599. long lSize = ((long) (sizeH) << 32) + size;
  600. receiveFileSize = lSize;
  601. fileSize = 0;
  602. fileChunkCounter = 0;
  603. String fileName = receivePath;
  604. fos = new FileOutputStream(fileName);
  605. writeRfbFileTransferMsg(rfbFileHeader, 0, 0, 0, null);
  606. }
  607. // Internally used when transferring file from server. This method receives one chunk
  608. // of the file
  609. void receiveFileChunk() throws IOException {
  610. // sf@2004 - Size = 0 means file chunck not compressed
  611. int size = is.readInt();
  612. boolean fCompressed = (size != 0);
  613. int length = is.readInt();
  614. fileChunkCounter++;
  615. // sf@2004 - allocates buffers for file chunck reception and decompression
  616. byte[] ReceptionBuffer = new byte[length + 32];
  617. // Read the incoming file data
  618. // Todo: check error !
  619. is.readFully(ReceptionBuffer, 0, length);
  620. if (fCompressed) {
  621. int bufSize = sz_rfbBlockSize + 1024; // Todo: set a more accurate value here
  622. int decompressedSize = 0;
  623. byte[] DecompressionBuffer = new byte[bufSize];
  624. Inflater myInflater = new Inflater();
  625. myInflater.setInput(ReceptionBuffer);
  626. try {
  627. decompressedSize = myInflater.inflate(DecompressionBuffer);
  628. } catch (DataFormatException e) {
  629. System.err.println(e);
  630. }
  631. // Todo: check error !
  632. fos.write(DecompressionBuffer, 0, decompressedSize);
  633. fileSize += decompressedSize;
  634. } else {
  635. // Todo: check error !
  636. fos.write(ReceptionBuffer, 0, length);
  637. fileSize += length;
  638. }
  639. /*
  640. * for (int i = 0; i < length; i++) { fos.write(is.readUnsignedByte()); fileSize++; }
  641. */
  642. if (fAbort == true) {
  643. fAbort = false;
  644. fFileReceptionError = true;
  645. writeRfbFileTransferMsg(rfbAbortFileTransfer, 0, 0, 0, null);
  646. }
  647. // sf@2004 - For old FT protocole only
  648. /*
  649. * if(fileChunkCounter==10) { writeRfbFileTransferMsg(rfbFileHeader,0,0,0,null); fileChunkCounter=0; }
  650. */
  651. }
  652. // Internally used when transferring file from server. Server signals end of file.
  653. void endOfReceiveFile(boolean fReceptionOk) throws IOException {
  654. int size = is.readInt();
  655. int length = is.readInt();
  656. fileSize = 0;
  657. fos.close();
  658. if (fReceptionOk && !fFileReceptionError) {
  659. } else {
  660. // sf@2004 - Delete the incomplete receieved file for now (until we use Delta Transfer)
  661. File f = new File(receivePath);
  662. f.delete();
  663. }
  664. fFileReceptionError = false;
  665. fFileReceptionRunning = false;
  666. }
  667. // Call this method to read the contents of the server directory
  668. void readServerDirectory(String text) {
  669. try {
  670. String temp = text;
  671. writeRfbFileTransferMsg(rfbDirContentRequest, rfbRDirContent, 0, temp.length(), temp);
  672. } catch (IOException e) {
  673. System.err.println(e);
  674. }
  675. }
  676. // Internally used to receive list of drives available on the server
  677. void readFTPMsgDriveList() throws IOException {
  678. String str = "";
  679. for (int i = 0; i < 4; i++) {
  680. is.readUnsignedByte();
  681. }
  682. int length = is.readInt();
  683. for (int i = 0; i < length; i++) {
  684. char temp = (char) is.readUnsignedByte();
  685. if (temp != '\0') {
  686. str += temp;
  687. }
  688. }
  689. }
  690. // Internally used to receive directory content from server
  691. // Here, the server marks the start of the directory listing
  692. void readFTPMsgDirectoryList() throws IOException {
  693. is.readInt();
  694. int length = is.readInt();
  695. if (length == 0) {
  696. inDirectory2 = false;
  697. } else {
  698. // sf@2004 - New FT protocole sends remote directory name
  699. String str = "";
  700. for (int i = 0; i < length; i++) {
  701. char temp = (char) is.readUnsignedByte();
  702. if (temp != '\0') {
  703. str += temp;
  704. }
  705. }
  706. // viewer.ftp.changeRemoteDirectory(str);
  707. }
  708. }
  709. // Internally used to receive directory content from server
  710. // Here, the server sends one file/directory with it's attributes
  711. void readFTPMsgDirectoryListContent() throws IOException {
  712. String fileName = "", alternateFileName = "";
  713. byte contentType = 0;
  714. int contentParamT = 0;
  715. int contentParam = 0;
  716. byte temp = 0;
  717. int dwFileAttributes, nFileSizeHigh, nFileSizeLow, dwReserved0, dwReserved1;
  718. long ftCreationTime, ftLastAccessTime, ftLastWriteTime;
  719. char cFileName, cAlternateFileName;
  720. int length = 0;
  721. is.readInt();
  722. length = is.readInt();
  723. dwFileAttributes = is.readInt();
  724. length -= 4;
  725. ftCreationTime = is.readLong();
  726. length -= 8;
  727. ftLastAccessTime = is.readLong();
  728. length -= 8;
  729. ftLastWriteTime = is.readLong();
  730. length -= 8;
  731. nFileSizeHigh = is.readInt();
  732. length -= 4;
  733. nFileSizeLow = is.readInt();
  734. length -= 4;
  735. dwReserved0 = is.readInt();
  736. length -= 4;
  737. dwReserved1 = is.readInt();
  738. length -= 4;
  739. cFileName = (char) is.readUnsignedByte();
  740. length--;
  741. while (cFileName != '\0') {
  742. fileName += cFileName;
  743. cFileName = (char) is.readUnsignedByte();
  744. length--;
  745. }
  746. cAlternateFileName = (char) is.readByte();
  747. length--;
  748. while (length != 0) {
  749. alternateFileName += cAlternateFileName;
  750. cAlternateFileName = (char) is.readUnsignedByte();
  751. length--;
  752. }
  753. if (dwFileAttributes == 268435456 || dwFileAttributes == 369098752 || dwFileAttributes == 285212672 || dwFileAttributes == 271056896 || dwFileAttributes == 824705024
  754. || dwFileAttributes == 807927808 || dwFileAttributes == 371720192 || dwFileAttributes == 369623040) {
  755. fileName = " [" + fileName + "]";
  756. remoteDirsList.add(fileName); // sf@2004
  757. } else {
  758. remoteFilesList.add(" " + fileName); // sf@2004
  759. }
  760. // a.add(fileName);
  761. }
  762. // Internally used to read directory content of server.
  763. // Here, server signals end of directory.
  764. void readFTPMsgDirectoryListEndContent() throws IOException {
  765. is.readInt();
  766. int length = is.readInt();
  767. // sf@2004
  768. a.clear();
  769. for (int i = 0; i < remoteDirsList.size(); i++)
  770. a.add(remoteDirsList.get(i));
  771. for (int i = 0; i < remoteFilesList.size(); i++)
  772. a.add(remoteFilesList.get(i));
  773. remoteDirsList.clear();
  774. remoteFilesList.clear();
  775. }
  776. // sf@2004 - Read the destination file checksums data
  777. // We don't use it for now
  778. void ReceiveDestinationFileChecksums() throws IOException {
  779. int size = is.readInt();
  780. int length = is.readInt();
  781. byte[] ReceptionBuffer = new byte[length + 32];
  782. // Read the incoming file data
  783. is.readFully(ReceptionBuffer, 0, length);
  784. /*
  785. * String csData = ""; for (int i = 0; i < length; i++) { csData += (char) is.readUnsignedByte(); }
  786. */
  787. // viewer.ftp.connectionStatus.setText("Received: 0 bytes of " + size + " bytes");
  788. }
  789. //
  790. // Write a SetPixelFormat message
  791. //
  792. void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian, boolean trueColour, int redMax, int greenMax, int blueMax, int redShift, int greenShift, int blueShift, boolean fGreyScale) // sf@2005
  793. throws IOException {
  794. byte[] b = new byte[20];
  795. b[0] = (byte) SetPixelFormat;
  796. b[4] = (byte) bitsPerPixel;
  797. b[5] = (byte) depth;
  798. b[6] = (byte) (bigEndian ? 1 : 0);
  799. b[7] = (byte) (trueColour ? 1 : 0);
  800. b[8] = (byte) ((redMax >> 8) & 0xff);
  801. b[9] = (byte) (redMax & 0xff);
  802. b[10] = (byte) ((greenMax >> 8) & 0xff);
  803. b[11] = (byte) (greenMax & 0xff);
  804. b[12] = (byte) ((blueMax >> 8) & 0xff);
  805. b[13] = (byte) (blueMax & 0xff);
  806. b[14] = (byte) redShift;
  807. b[15] = (byte) greenShift;
  808. b[16] = (byte) blueShift;
  809. b[17] = (byte) (fGreyScale ? 1 : 0); // sf@2005
  810. os.write(b);
  811. }
  812. //
  813. // Write a FixColourMapEntries message. The values in the red, green and
  814. // blue arrays are from 0 to 65535.
  815. //
  816. void writeFixColourMapEntries(int firstColour, int nColours, int[] red, int[] green, int[] blue) throws IOException {
  817. byte[] b = new byte[6 + nColours * 6];
  818. b[0] = (byte) FixColourMapEntries;
  819. b[2] = (byte) ((firstColour >> 8) & 0xff);
  820. b[3] = (byte) (firstColour & 0xff);
  821. b[4] = (byte) ((nColours >> 8) & 0xff);
  822. b[5] = (byte) (nColours & 0xff);
  823. for (int i = 0; i < nColours; i++) {
  824. b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff);
  825. b[6 + i * 6 + 1] = (byte) (red[i] & 0xff);
  826. b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff);
  827. b[6 + i * 6 + 3] = (byte) (green[i] & 0xff);
  828. b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff);
  829. b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff);
  830. }
  831. os.write(b);
  832. }
  833. //
  834. // Write a SetEncodings message
  835. //
  836. void writeSetEncodings(int[] encs, int len) throws IOException {
  837. byte[] b = new byte[4 + 4 * len];
  838. b[0] = (byte) SetEncodings;
  839. b[2] = (byte) ((len >> 8) & 0xff);
  840. b[3] = (byte) (len & 0xff);
  841. for (int i = 0; i < len; i++) {
  842. b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff);
  843. b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff);
  844. b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff);
  845. b[7 + 4 * i] = (byte) (encs[i] & 0xff);
  846. }
  847. os.write(b);
  848. }
  849. //
  850. // Write a ClientCutText message
  851. //
  852. void writeClientCutText(String text) throws IOException {
  853. // if (!viewer.ftp.isVisible()) {
  854. byte[] b = new byte[8 + text.length()];
  855. b[0] = (byte) ClientCutText;
  856. b[4] = (byte) ((text.length() >> 24) & 0xff);
  857. b[5] = (byte) ((text.length() >> 16) & 0xff);
  858. b[6] = (byte) ((text.length() >> 8) & 0xff);
  859. b[7] = (byte) (text.length() & 0xff);
  860. System.arraycopy(text.getBytes(), 0, b, 8, text.length());
  861. os.write(b);
  862. // }
  863. }
  864. //
  865. // A buffer for putting pointer and keyboard events before being sent. This
  866. // is to ensure that multiple RFB events generated from a single Java Event
  867. // will all be sent in a single network packet. The maximum possible
  868. // length is 4 modifier down events, a single key event followed by 4
  869. // modifier up events i.e. 9 key events or 72 bytes.
  870. //
  871. byte[] eventBuf = new byte[72];
  872. int eventBufLen;
  873. // Useful shortcuts for modifier masks.
  874. final static int CTRL_MASK = InputEvent.CTRL_MASK;
  875. final static int SHIFT_MASK = InputEvent.SHIFT_MASK;
  876. final static int META_MASK = InputEvent.META_MASK;
  877. final static int ALT_MASK = InputEvent.ALT_MASK;
  878. //
  879. // Write a pointer event message. We may need to send modifier key events
  880. // around it to set the correct modifier state.
  881. //
  882. int pointerMask = 0;
  883. //
  884. // Add a raw key event with the given X keysym to eventBuf.
  885. //
  886. void writeKeyEvent(int keysym, boolean down) {
  887. eventBuf[eventBufLen++] = (byte) KeyboardEvent;
  888. eventBuf[eventBufLen++] = (byte) (down ? 1 : 0);
  889. eventBuf[eventBufLen++] = (byte) 0;
  890. eventBuf[eventBufLen++] = (byte) 0;
  891. eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff);
  892. eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff);
  893. eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff);
  894. eventBuf[eventBufLen++] = (byte) (keysym & 0xff);
  895. }
  896. //
  897. // Write key events to set the correct modifier state.
  898. //
  899. int oldModifiers = 0;
  900. void writeModifierKeyEvents(int newModifiers) {
  901. if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK))
  902. writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0);
  903. if ((newModifiers & SHIFT_MASK) != (oldModifiers & SHIFT_MASK))
  904. writeKeyEvent(0xffe1, (newModifiers & SHIFT_MASK) != 0);
  905. if ((newModifiers & META_MASK) != (oldModifiers & META_MASK))
  906. writeKeyEvent(0xffe7, (newModifiers & META_MASK) != 0);
  907. if ((newModifiers & ALT_MASK) != (oldModifiers & ALT_MASK))
  908. writeKeyEvent(0xffe9, (newModifiers & ALT_MASK) != 0);
  909. oldModifiers = newModifiers;
  910. }
  911. //
  912. // Compress and write the data into the recorded session file. This
  913. // method assumes the recording is on (rec != null).
  914. //
  915. void recordCompressedData(byte[] data, int off, int len) throws IOException {
  916. Deflater deflater = new Deflater();
  917. deflater.setInput(data, off, len);
  918. int bufSize = len + len / 100 + 12;
  919. byte[] buf = new byte[bufSize];
  920. deflater.finish();
  921. int compressedSize = deflater.deflate(buf);
  922. recordCompactLen(compressedSize);
  923. rec.write(buf, 0, compressedSize);
  924. }
  925. void recordCompressedData(byte[] data) throws IOException {
  926. recordCompressedData(data, 0, data.length);
  927. }
  928. //
  929. // Write an integer in compact representation (1..3 bytes) into the
  930. // recorded session file. This method assumes the recording is on
  931. // (rec != null).
  932. //
  933. void recordCompactLen(int len) throws IOException {
  934. byte[] buf = new byte[3];
  935. int bytes = 0;
  936. buf[bytes++] = (byte) (len & 0x7F);
  937. if (len > 0x7F) {
  938. buf[bytes - 1] |= 0x80;
  939. buf[bytes++] = (byte) (len >> 7 & 0x7F);
  940. if (len > 0x3FFF) {
  941. buf[bytes - 1] |= 0x80;
  942. buf[bytes++] = (byte) (len >> 14 & 0xFF);
  943. }
  944. }
  945. rec.write(buf, 0, bytes);
  946. }
  947. // added by noctis
  948. public boolean tryAuthenticate(String us, String pw) throws Exception {
  949. readVersionMsg();
  950. System.out.println("RFB server supports protocol version " + serverMajor + "." + serverMinor);
  951. writeVersionMsg();
  952. int authScheme = readAuthScheme();
  953. switch (authScheme) {
  954. case RfbProto.NoAuth:
  955. System.out.println("No authentication needed");
  956. return true;
  957. case RfbProto.VncAuth:
  958. byte[] challenge = new byte[16];
  959. is.readFully(challenge);
  960. if (pw.length() > 8)
  961. pw = pw.substring(0, 8); // Truncate to 8 chars
  962. // vncEncryptBytes in the UNIX libvncauth truncates password
  963. // after the first zero byte. We do to.
  964. int firstZero = pw.indexOf(0);
  965. if (firstZero != -1) {
  966. pw = pw.substring(0, firstZero);
  967. }
  968. byte[] key = { 0, 0, 0, 0, 0, 0, 0, 0 };
  969. System.arraycopy(pw.getBytes(), 0, key, 0, pw.length());
  970. DesCipher des = new DesCipher(key);
  971. des.encrypt(challenge, 0, challenge, 0);
  972. des.encrypt(challenge, 8, challenge, 8);
  973. os.write(challenge);
  974. int authResult = is.readInt();
  975. switch (authResult) {
  976. case RfbProto.VncAuthOK:
  977. System.out.println("VNC authentication succeeded");
  978. return true;
  979. case RfbProto.VncAuthFailed:
  980. System.out.println("VNC authentication failed");
  981. break;
  982. case RfbProto.VncAuthTooMany:
  983. throw new Exception("VNC authentication failed - too many tries");
  984. default:
  985. throw new Exception("Unknown VNC authentication result " + authResult);
  986. }
  987. break;
  988. case RfbProto.MsLogon:
  989. System.out.println("MS-Logon (DH) detected");
  990. break;
  991. default:
  992. throw new Exception("Unknown VNC authentication scheme " + authScheme);
  993. }
  994. return false;
  995. }
  996. void doProtocolInitialisation() throws IOException {
  997. writeClientInit();
  998. readServerInit();
  999. System.out.println("Desktop name is " + desktopName);
  1000. System.out.println("Desktop size is " + framebufferWidth + " x " + framebufferHeight);
  1001. }
  1002. }