RfbProto.java 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  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. class RfbProto {
  43. final String versionMsg = "RFB 003.003\n";
  44. final static int ConnFailed = 0, NoAuth = 1, VncAuth = 2, MsLogon = 0xfffffffa;
  45. final static int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2;
  46. final static int FramebufferUpdate = 0,
  47. SetColourMapEntries = 1,
  48. Bell = 2,
  49. ServerCutText = 3,
  50. rfbFileTransfer = 7;
  51. final int SetPixelFormat = 0,
  52. FixColourMapEntries = 1,
  53. SetEncodings = 2,
  54. FramebufferUpdateRequest = 3,
  55. KeyboardEvent = 4,
  56. PointerEvent = 5,
  57. ClientCutText = 6;
  58. final static int EncodingRaw = 0,
  59. EncodingCopyRect = 1,
  60. EncodingRRE = 2,
  61. EncodingCoRRE = 4,
  62. EncodingHextile = 5,
  63. EncodingZlib = 6,
  64. EncodingTight = 7,
  65. EncodingCompressLevel0 = 0xFFFFFF00,
  66. EncodingQualityLevel0 = 0xFFFFFFE0,
  67. EncodingXCursor = 0xFFFFFF10,
  68. EncodingRichCursor = 0xFFFFFF11,
  69. EncodingPointerPos = 0xFFFFFF18, // marscha - PointerPos
  70. EncodingLastRect = 0xFFFFFF20,
  71. EncodingNewFBSize = 0xFFFFFF21;
  72. final int HextileRaw = (1 << 0);
  73. final int HextileBackgroundSpecified = (1 << 1);
  74. final int HextileForegroundSpecified = (1 << 2);
  75. final int HextileAnySubrects = (1 << 3);
  76. final int HextileSubrectsColoured = (1 << 4);
  77. final static int TightExplicitFilter = 0x04;
  78. final static int TightFill = 0x08;
  79. final static int TightJpeg = 0x09;
  80. final static int TightMaxSubencoding = 0x09;
  81. final static int TightFilterCopy = 0x00;
  82. final static int TightFilterPalette = 0x01;
  83. final static int TightFilterGradient = 0x02;
  84. final static int TightMinToCompress = 12;
  85. // sf@2004 - FileTransfer part
  86. ArrayList remoteDirsList;
  87. ArrayList remoteFilesList;
  88. ArrayList a;
  89. boolean fFTInit = true; // sf@2004
  90. boolean fFTAllowed = true;
  91. boolean fAbort = false;
  92. boolean fFileReceptionError = false;
  93. boolean fFileReceptionRunning = false;
  94. boolean inDirectory2;
  95. FileOutputStream fos;
  96. FileInputStream fis;
  97. String sendFileSource;
  98. String receivePath;
  99. long fileSize;
  100. long receiveFileSize;
  101. long fileChunkCounter;
  102. final static int sz_rfbFileTransferMsg = 12,
  103. // FileTransfer Content types and Params defines
  104. rfbDirContentRequest = 1,
  105. // Client asks for the content of a given Server directory
  106. rfbDirPacket = 2, // Full directory name or full file name.
  107. // Null content means end of Directory
  108. rfbFileTransferRequest = 3,
  109. // Client asks the server for the tranfer of a given file
  110. rfbFileHeader = 4,
  111. // First packet of a file transfer, containing file's features
  112. rfbFilePacket = 5, // One slice of the file
  113. rfbEndOfFile = 6,
  114. // End of file transfer (the file has been received or error)
  115. rfbAbortFileTransfer = 7,
  116. // The file transfer must be aborted, whatever the state
  117. rfbFileTransferOffer = 8,
  118. // The client offers to send a file to the server
  119. rfbFileAcceptHeader = 9, // The server accepts or rejects the file
  120. rfbCommand = 10,
  121. // The Client sends a simple command (File Delete, Dir create etc...)
  122. rfbCommandReturn = 11,
  123. // New FT Protocole (V2) The zipped checksums of the destination file (Delta Transfer)
  124. rfbFileChecksums = 12,
  125. // The Client receives the server's answer about a simple command
  126. // rfbDirContentRequest client Request - content params
  127. rfbRDirContent = 1, // Request a Server Directory contents
  128. rfbRDrivesList = 2, // Request the server's drives list
  129. // rfbDirPacket & rfbCommandReturn server Answer - content params
  130. rfbADirectory = 1, // Reception of a directory name
  131. rfbAFile = 2, // Reception of a file name
  132. rfbADrivesList = 3, // Reception of a list of drives
  133. rfbADirCreate = 4, // Response to a create dir command
  134. rfbADirDelete = 5, // Response to a delete dir command
  135. rfbAFileCreate = 6, // Response to a create file command
  136. rfbAFileDelete = 7, // Response to a delete file command
  137. // rfbCommand Command - content params
  138. rfbCDirCreate = 1, // Request the server to create the given directory
  139. rfbCDirDelete = 2, // Request the server to delete the given directory
  140. rfbCFileCreate = 3, // Request the server to create the given file
  141. rfbCFileDelete = 4, // Request the server to delete the given file
  142. // Errors - content params or "size" field
  143. rfbRErrorUnknownCmd = 1, // Unknown FileTransfer command.
  144. rfbRErrorCmd = 0xFFFFFFFF,
  145. // Error when a command fails on remote side (ret in "size" field)
  146. sz_rfbBlockSize = 8192, // new FT protocole (v2)
  147. // Size of a File Transfer packet (before compression)
  148. sz_rfbZipDirectoryPrefix = 9;
  149. String rfbZipDirectoryPrefix = "!UVNCDIR-\0";
  150. // Transfered directory are zipped in a file with this prefix. Must end with "-"
  151. // End of FileTransfer part
  152. String host;
  153. int port;
  154. Socket sock;
  155. DataInputStream is;
  156. OutputStream os;
  157. OutputStreamWriter osw;
  158. SessionRecorder rec;
  159. boolean inNormalProtocol = false;
  160. VncViewer viewer;
  161. // Java on UNIX does not call keyPressed() on some keys, for example
  162. // swedish keys To prevent our workaround to produce duplicate
  163. // keypresses on JVMs that actually works, keep track of if
  164. // keyPressed() for a "broken" key was called or not.
  165. boolean brokenKeyPressed = false;
  166. // This will be set to true on the first framebuffer update
  167. // containing Zlib- or Tight-encoded data.
  168. boolean wereZlibUpdates = false;
  169. // This will be set to false if the startSession() was called after
  170. // we have received at least one Zlib- or Tight-encoded framebuffer
  171. // update.
  172. boolean recordFromBeginning = true;
  173. // This fields are needed to show warnings about inefficiently saved
  174. // sessions only once per each saved session file.
  175. boolean zlibWarningShown;
  176. boolean tightWarningShown;
  177. // Before starting to record each saved session, we set this field
  178. // to 0, and increment on each framebuffer update. We don't flush
  179. // the SessionRecorder data into the file before the second update.
  180. // This allows us to write initial framebuffer update with zero
  181. // timestamp, to let the player show initial desktop before
  182. // playback.
  183. int numUpdatesInSession;
  184. /* added for noctis relay
  185. *
  186. */
  187. private void sendRelayCommand(OutputStream out, String serverID) throws IOException {
  188. out.write(IProtocolCommand.CLIENT_CONNECTION);
  189. byte[] serverIDData = serverID.getBytes();
  190. out.write(serverIDData.length);
  191. out.write(serverIDData);
  192. out.flush();
  193. }
  194. //
  195. // Constructor. Make TCP connection to RFB server.
  196. //
  197. RfbProto(String h, int p, VncViewer v, String serverID) throws IOException {
  198. viewer = v;
  199. host = h;
  200. port = p;
  201. sock = new Socket(host, port);
  202. is =
  203. new DataInputStream(
  204. new BufferedInputStream(sock.getInputStream(), 16384));
  205. os = sock.getOutputStream();
  206. osw = new OutputStreamWriter(sock.getOutputStream());
  207. // send a command to relay for create a new connection to the specific server.
  208. sendRelayCommand(os, serverID);
  209. inDirectory2 = false;
  210. a = new ArrayList();
  211. // sf@2004
  212. remoteDirsList = new ArrayList();
  213. remoteFilesList = new ArrayList();
  214. sendFileSource = "";
  215. }
  216. void close() {
  217. try {
  218. sock.close();
  219. if (rec != null) {
  220. rec.close();
  221. rec = null;
  222. }
  223. } catch (Exception e) {
  224. e.printStackTrace();
  225. }
  226. }
  227. //
  228. // Read server's protocol version message
  229. //
  230. int serverMajor, serverMinor;
  231. void readVersionMsg() throws Exception {
  232. byte[] b = new byte[12];
  233. is.readFully(b);
  234. if ((b[0] != 'R')
  235. || (b[1] != 'F')
  236. || (b[2] != 'B')
  237. || (b[3] != ' ')
  238. || (b[4] < '0')
  239. || (b[4] > '9')
  240. || (b[5] < '0')
  241. || (b[5] > '9')
  242. || (b[6] < '0')
  243. || (b[6] > '9')
  244. || (b[7] != '.')
  245. || (b[8] < '0')
  246. || (b[8] > '9')
  247. || (b[9] < '0')
  248. || (b[9] > '9')
  249. || (b[10] < '0')
  250. || (b[10] > '9')
  251. || (b[11] != '\n')) {
  252. throw new Exception(
  253. "Host " + host + " port " + port + " is not an RFB server");
  254. }
  255. serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
  256. serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
  257. }
  258. //
  259. // Write our protocol version message
  260. //
  261. void writeVersionMsg() throws IOException {
  262. os.write(versionMsg.getBytes());
  263. }
  264. //
  265. // Find out the authentication scheme.
  266. //
  267. int readAuthScheme() throws Exception {
  268. int authScheme = is.readInt();
  269. switch (authScheme) {
  270. case ConnFailed :
  271. int reasonLen = is.readInt();
  272. byte[] reason = new byte[reasonLen];
  273. is.readFully(reason);
  274. throw new Exception(new String(reason));
  275. case NoAuth :
  276. case VncAuth :
  277. case MsLogon:
  278. return authScheme;
  279. default :
  280. throw new Exception(
  281. "Unknown authentication scheme from RFB server: "
  282. + authScheme);
  283. }
  284. }
  285. //
  286. // Write the client initialisation message
  287. //
  288. void writeClientInit() throws IOException {
  289. if (viewer.options.shareDesktop) {
  290. os.write(1);
  291. } else {
  292. os.write(0);
  293. }
  294. viewer.options.disableShareDesktop();
  295. }
  296. //
  297. // Read the server initialisation message
  298. //
  299. String desktopName;
  300. int framebufferWidth, framebufferHeight;
  301. int bitsPerPixel, depth;
  302. boolean bigEndian, trueColour;
  303. int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
  304. void readServerInit() throws IOException {
  305. framebufferWidth = is.readUnsignedShort();
  306. framebufferHeight = is.readUnsignedShort();
  307. bitsPerPixel = is.readUnsignedByte();
  308. depth = is.readUnsignedByte();
  309. bigEndian = (is.readUnsignedByte() != 0);
  310. trueColour = (is.readUnsignedByte() != 0);
  311. redMax = is.readUnsignedShort();
  312. greenMax = is.readUnsignedShort();
  313. blueMax = is.readUnsignedShort();
  314. redShift = is.readUnsignedByte();
  315. greenShift = is.readUnsignedByte();
  316. blueShift = is.readUnsignedByte();
  317. byte[] pad = new byte[3];
  318. is.readFully(pad);
  319. int nameLength = is.readInt();
  320. byte[] name = new byte[nameLength];
  321. is.readFully(name);
  322. desktopName = new String(name);
  323. inNormalProtocol = true;
  324. }
  325. //
  326. // Create session file and write initial protocol messages into it.
  327. //
  328. void startSession(String fname) throws IOException {
  329. rec = new SessionRecorder(fname);
  330. rec.writeHeader();
  331. rec.write(versionMsg.getBytes());
  332. rec.writeIntBE(NoAuth);
  333. rec.writeShortBE(framebufferWidth);
  334. rec.writeShortBE(framebufferHeight);
  335. byte[] fbsServerInitMsg =
  336. {
  337. 32,
  338. 24,
  339. 0,
  340. 1,
  341. 0,
  342. (byte) 0xFF,
  343. 0,
  344. (byte) 0xFF,
  345. 0,
  346. (byte) 0xFF,
  347. 16,
  348. 8,
  349. 0,
  350. 0,
  351. 0,
  352. 0 };
  353. rec.write(fbsServerInitMsg);
  354. rec.writeIntBE(desktopName.length());
  355. rec.write(desktopName.getBytes());
  356. numUpdatesInSession = 0;
  357. if (wereZlibUpdates)
  358. recordFromBeginning = false;
  359. zlibWarningShown = false;
  360. tightWarningShown = false;
  361. }
  362. //
  363. // Close session file.
  364. //
  365. void closeSession() throws IOException {
  366. if (rec != null) {
  367. rec.close();
  368. rec = null;
  369. }
  370. }
  371. //
  372. // Set new framebuffer size
  373. //
  374. void setFramebufferSize(int width, int height) {
  375. framebufferWidth = width;
  376. framebufferHeight = height;
  377. }
  378. //
  379. // Read the server message type
  380. //
  381. int readServerMessageType() throws IOException {
  382. int msgType = is.readUnsignedByte();
  383. // If the session is being recorded:
  384. if (rec != null) {
  385. if (msgType == Bell) { // Save Bell messages in session files.
  386. rec.writeByte(msgType);
  387. if (numUpdatesInSession > 0)
  388. rec.flush();
  389. }
  390. }
  391. return msgType;
  392. }
  393. //
  394. // Read a FramebufferUpdate message
  395. //
  396. int updateNRects;
  397. void readFramebufferUpdate() throws IOException {
  398. is.readByte();
  399. updateNRects = is.readUnsignedShort();
  400. // If the session is being recorded:
  401. if (rec != null) {
  402. rec.writeByte(FramebufferUpdate);
  403. rec.writeByte(0);
  404. rec.writeShortBE(updateNRects);
  405. }
  406. numUpdatesInSession++;
  407. }
  408. // Read a FramebufferUpdate rectangle header
  409. int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
  410. void readFramebufferUpdateRectHdr() throws Exception {
  411. updateRectX = is.readUnsignedShort();
  412. updateRectY = is.readUnsignedShort();
  413. updateRectW = is.readUnsignedShort();
  414. updateRectH = is.readUnsignedShort();
  415. updateRectEncoding = is.readInt();
  416. if (updateRectEncoding == EncodingZlib
  417. || updateRectEncoding == EncodingTight)
  418. wereZlibUpdates = true;
  419. // If the session is being recorded:
  420. if (rec != null) {
  421. if (numUpdatesInSession > 1)
  422. rec.flush(); // Flush the output on each rectangle.
  423. rec.writeShortBE(updateRectX);
  424. rec.writeShortBE(updateRectY);
  425. rec.writeShortBE(updateRectW);
  426. rec.writeShortBE(updateRectH);
  427. if (updateRectEncoding == EncodingZlib && !recordFromBeginning) {
  428. // Here we cannot write Zlib-encoded rectangles because the
  429. // decoder won't be able to reproduce zlib stream state.
  430. if (!zlibWarningShown) {
  431. System.out.println(
  432. "Warning: Raw encoding will be used "
  433. + "instead of Zlib in recorded session.");
  434. zlibWarningShown = true;
  435. }
  436. rec.writeIntBE(EncodingRaw);
  437. } else {
  438. rec.writeIntBE(updateRectEncoding);
  439. if (updateRectEncoding == EncodingTight
  440. && !recordFromBeginning
  441. && !tightWarningShown) {
  442. System.out.println(
  443. "Warning: Re-compressing Tight-encoded "
  444. + "updates for session recording.");
  445. tightWarningShown = true;
  446. }
  447. }
  448. }
  449. if (updateRectEncoding == EncodingLastRect
  450. || updateRectEncoding == EncodingNewFBSize)
  451. return;
  452. if (updateRectX + updateRectW > framebufferWidth
  453. || updateRectY + updateRectH > framebufferHeight) {
  454. throw new Exception(
  455. "Framebuffer update rectangle too large: "
  456. + updateRectW
  457. + "x"
  458. + updateRectH
  459. + " at ("
  460. + updateRectX
  461. + ","
  462. + updateRectY
  463. + ")");
  464. }
  465. }
  466. // Read CopyRect source X and Y.
  467. int copyRectSrcX, copyRectSrcY;
  468. void readCopyRect() throws IOException {
  469. copyRectSrcX = is.readUnsignedShort();
  470. copyRectSrcY = is.readUnsignedShort();
  471. // If the session is being recorded:
  472. if (rec != null) {
  473. rec.writeShortBE(copyRectSrcX);
  474. rec.writeShortBE(copyRectSrcY);
  475. }
  476. }
  477. //
  478. // Read a ServerCutText message
  479. //
  480. String readServerCutText() throws IOException {
  481. byte[] pad = new byte[3];
  482. is.readFully(pad);
  483. int len = is.readInt();
  484. byte[] text = new byte[len];
  485. is.readFully(text);
  486. return new String(text);
  487. }
  488. //
  489. // Read an integer in compact representation (1..3 bytes).
  490. // Such format is used as a part of the Tight encoding.
  491. // Also, this method records data if session recording is active and
  492. // the viewer's recordFromBeginning variable is set to true.
  493. //
  494. int readCompactLen() throws IOException {
  495. int[] portion = new int[3];
  496. portion[0] = is.readUnsignedByte();
  497. int byteCount = 1;
  498. int len = portion[0] & 0x7F;
  499. if ((portion[0] & 0x80) != 0) {
  500. portion[1] = is.readUnsignedByte();
  501. byteCount++;
  502. len |= (portion[1] & 0x7F) << 7;
  503. if ((portion[1] & 0x80) != 0) {
  504. portion[2] = is.readUnsignedByte();
  505. byteCount++;
  506. len |= (portion[2] & 0xFF) << 14;
  507. }
  508. }
  509. if (rec != null && recordFromBeginning)
  510. for (int i = 0; i < byteCount; i++)
  511. rec.writeByte(portion[i]);
  512. return len;
  513. }
  514. //Author: Kenn Min Chong/////////////////////////////////////////////
  515. //Read/Write a rfbFileTransferMsg
  516. /*typedef struct _rfbFileTransferMsg {
  517. CARD8 type; // always rfbFileTransfer
  518. CARD8 contentType; // See defines below
  519. CARD16 contentParam;// Other possible content classification (Dir or File name, etc..)
  520. CARD32 size; // FileSize or packet index or error or other
  521. CARD32 length;
  522. // followed by data char text[length]
  523. } rfbFileTransferMsg;
  524. */
  525. // Parsing Rfb message to see what type
  526. void readRfbFileTransferMsg() throws IOException
  527. {
  528. int contentType = is.readUnsignedByte();
  529. int contentParamT = is.readUnsignedByte();
  530. int contentParam = contentParamT;
  531. contentParamT = is.readUnsignedByte();
  532. contentParamT = contentParamT << 8;
  533. contentParam = contentParam | contentParamT;
  534. if (contentType == rfbRDrivesList || contentType == rfbDirPacket)
  535. {
  536. readDriveOrDirectory(contentParam);
  537. }
  538. else if (contentType == rfbFileHeader)
  539. {
  540. receiveFileHeader();
  541. }
  542. else if (contentType == rfbFilePacket)
  543. {
  544. receiveFileChunk();
  545. }
  546. else if (contentType == rfbEndOfFile)
  547. {
  548. endOfReceiveFile(true); // Ok
  549. }
  550. else if (contentType == rfbAbortFileTransfer)
  551. {
  552. if (fFileReceptionRunning)
  553. {
  554. endOfReceiveFile(false); // Error
  555. }
  556. else
  557. {
  558. // sf@2004 - Todo: Add TestPermission
  559. // System.out.println("File Transfer Aborted!");
  560. }
  561. }
  562. else if (contentType == rfbCommandReturn)
  563. {
  564. createDirectoryorDeleteFile(contentParam);
  565. }
  566. else if (contentType == rfbFileAcceptHeader)
  567. {
  568. sendFile();
  569. }
  570. else if (contentType == rfbFileChecksums)
  571. {
  572. ReceiveDestinationFileChecksums();
  573. }
  574. else
  575. {
  576. System.out.println("ContentType: " + contentType);
  577. }
  578. }
  579. //Refactored from readRfbFileTransferMsg()
  580. public void createDirectoryorDeleteFile(int contentParam)
  581. throws IOException {
  582. if (contentParam == rfbADirCreate)
  583. {
  584. createRemoteDirectoryFeedback();
  585. }
  586. else if (contentParam == rfbAFileDelete)
  587. {
  588. deleteRemoteFileFeedback();
  589. }
  590. }
  591. //Refactored from readRfbFileTransferMsg()
  592. public void readDriveOrDirectory(int contentParam) throws IOException {
  593. if (contentParam == rfbADrivesList)
  594. {
  595. readFTPMsgDriveList();
  596. }
  597. else if (contentParam == rfbADirectory && !inDirectory2)
  598. {
  599. inDirectory2 = true;
  600. readFTPMsgDirectoryList();
  601. }
  602. else if (contentParam == rfbADirectory && inDirectory2)
  603. {
  604. readFTPMsgDirectoryListContent();
  605. }
  606. else if (contentParam == 0)
  607. {
  608. readFTPMsgDirectoryListEndContent();
  609. inDirectory2 = false;
  610. }
  611. else
  612. {
  613. System.out.println("ContentParam: " + contentParam);
  614. }
  615. }
  616. // Internally used. Write an Rfb message to the server
  617. void writeRfbFileTransferMsg(
  618. int contentType,
  619. int contentParam,
  620. long size, // 0 : compression not supported - 1 : compression supported
  621. long length,
  622. String text) throws IOException
  623. {
  624. byte b[] = new byte[12];
  625. b[0] = (byte) rfbFileTransfer;
  626. b[1] = (byte) contentType;
  627. b[2] = (byte) contentParam;
  628. byte by = 0;
  629. long c = 0;
  630. length++;
  631. c = size & 0xFF000000;
  632. by = (byte) (c >>> 24);
  633. b[4] = by;
  634. c = size & 0xFF0000;
  635. by = (byte) (c >>> 16);
  636. b[5] = by;
  637. c = size & 0xFF00;
  638. by = (byte) (c >>> 8);
  639. b[6] = by;
  640. c = size & 0xFF;
  641. by = (byte) c;
  642. b[7] = by;
  643. c = length & 0xFF000000;
  644. by = (byte) (c >>> 24);
  645. b[8] = by;
  646. c = length & 0xFF0000;
  647. by = (byte) (c >>> 16);
  648. b[9] = by;
  649. c = length & 0xFF00;
  650. by = (byte) (c >>> 8);
  651. b[10] = by;
  652. c = length & 0xFF;
  653. by = (byte) c;
  654. b[11] = by;
  655. os.write(b);
  656. if (text != null)
  657. {
  658. byte byteArray[] = text.getBytes();
  659. byte byteArray2[] = new byte[byteArray.length + 1];
  660. for (int i = 0; i < byteArray.length; i++) {
  661. byteArray2[i] = byteArray[i];
  662. }
  663. byteArray2[byteArray2.length - 1] = 0;
  664. os.write(byteArray2);
  665. }
  666. }
  667. //Internally used. Write an rfb message to the server for sending files ONLY
  668. int writeRfbFileTransferMsgForSendFile(
  669. int contentType,
  670. int contentParam,
  671. long size,
  672. long length,
  673. String source
  674. ) throws IOException
  675. {
  676. File f = new File(source);
  677. fis = new FileInputStream(f);
  678. byte byteBuffer[] = new byte[sz_rfbBlockSize];
  679. int bytesRead = fis.read(byteBuffer);
  680. long counter=0;
  681. boolean fError = false;
  682. // sf@ - Manage compression
  683. boolean fCompress = true;
  684. Deflater myDeflater = new Deflater();
  685. byte[] CompressionBuffer = new byte[sz_rfbBlockSize + 1024];
  686. int compressedSize = 0;
  687. while (bytesRead!=-1)
  688. {
  689. counter += bytesRead;
  690. myDeflater.setInput(byteBuffer, 0, bytesRead);
  691. myDeflater.finish();
  692. compressedSize = myDeflater.deflate(CompressionBuffer);
  693. myDeflater.reset();
  694. // If the compressed data is larger than the original one, we're dealing with
  695. // already compressed data
  696. if (compressedSize > bytesRead)
  697. fCompress = false;
  698. this.writeRfbFileTransferMsg(
  699. contentType,
  700. contentParam,
  701. (fCompress ? 1 : 0),
  702. (fCompress ? compressedSize-1 : bytesRead-1),
  703. null
  704. );
  705. // Todo: Test write error !
  706. os.write(
  707. fCompress ? CompressionBuffer : byteBuffer,
  708. 0,
  709. fCompress ? compressedSize : bytesRead
  710. );
  711. // Todo: test read error !
  712. bytesRead = fis.read(byteBuffer);
  713. // viewer.ftp.connectionStatus.setText("Sent: "+ counter + " bytes of "+ f.length() + " bytes");
  714. viewer.ftp.jProgressBar.setValue((int)((counter * 100) / f.length()));
  715. viewer.ftp.connectionStatus.setText(">>> Sending File: " + source + " - Size: " + f.length() + " bytes - Progress: " + ((counter * 100) / f.length()) + "%");
  716. if (fAbort == true)
  717. {
  718. fAbort = false;
  719. fError = true;
  720. break;
  721. }
  722. try
  723. {
  724. Thread.sleep(5);
  725. }
  726. catch(InterruptedException e)
  727. {
  728. System.err.println("Interrupted");
  729. }
  730. }
  731. writeRfbFileTransferMsg(fError ? rfbAbortFileTransfer : rfbEndOfFile, 0, 0, 0, null);
  732. fis.close();
  733. return (fError ? -1 : 1);
  734. }
  735. //This method is internally used to send the file to the server once the server is ready
  736. void sendFile()
  737. {
  738. try
  739. {
  740. viewer.ftp.disableButtons();
  741. int size = is.readInt();
  742. int length = is.readInt();
  743. for (int i = 0; i < length; i++)
  744. {
  745. System.out.print((char) is.readUnsignedByte());
  746. }
  747. int ret = writeRfbFileTransferMsgForSendFile(
  748. rfbFilePacket,
  749. 0,
  750. 0,
  751. 0,
  752. sendFileSource);
  753. viewer.ftp.refreshRemoteLocation();
  754. if (ret != 1)
  755. {
  756. viewer.ftp.connectionStatus.setText(" > Error - File NOT sent");
  757. viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - File: <" + sendFileSource) + "> was not correctly sent (aborted by user or error)",0);
  758. }
  759. else
  760. {
  761. viewer.ftp.connectionStatus.setText(" > File sent");
  762. viewer.ftp.historyComboBox.insertItemAt(new String(" > File: <" + sendFileSource) + "> was sent to Remote Machine",0);
  763. }
  764. viewer.ftp.historyComboBox.setSelectedIndex(0);
  765. viewer.ftp.enableButtons();
  766. }
  767. catch (IOException e)
  768. {
  769. System.err.println(e);
  770. }
  771. }
  772. //Call this method to send a file from local pc to server
  773. void offerLocalFile(String source, String destinationPath)
  774. {
  775. try
  776. {
  777. sendFileSource = source;
  778. File f = new File(source);
  779. // sf@2004 - Add support for huge files
  780. long lSize = f.length();
  781. int iLowSize = (int)(lSize & 0x00000000FFFFFFFF);
  782. int iHighSize = (int)(lSize >> 32);
  783. String temp = destinationPath + f.getName();
  784. writeRfbFileTransferMsg(
  785. rfbFileTransferOffer,
  786. 0,
  787. iLowSize, // f.length(),
  788. temp.length(),
  789. temp);
  790. // sf@2004 - Send the high part of the size
  791. byte b[] = new byte[4];
  792. byte by = 0;
  793. long c = 0;
  794. c = iHighSize & 0xFF000000;
  795. by = (byte) (c >>> 24);
  796. b[0] = by;
  797. c = iHighSize & 0xFF0000;
  798. by = (byte) (c >>> 16);
  799. b[1] = by;
  800. c = iHighSize & 0xFF00;
  801. by = (byte) (c >>> 8);
  802. b[2] = by;
  803. c = iHighSize & 0xFF;
  804. by = (byte) c;
  805. b[3] = by;
  806. os.write(b);
  807. }
  808. catch (IOException e)
  809. {
  810. System.err.println(e);
  811. }
  812. }
  813. //Internally used.
  814. //Handles acknowledgement that the file has been deleted on the server
  815. void deleteRemoteFileFeedback() throws IOException
  816. {
  817. is.readInt();
  818. int length = is.readInt();
  819. String f = "";
  820. for (int i = 0; i < length; i++)
  821. {
  822. f += (char)is.readUnsignedByte();
  823. }
  824. viewer.ftp.refreshRemoteLocation();
  825. viewer.ftp.historyComboBox.insertItemAt(new String(" > Deleted File On Remote Machine: " + f.substring(0, f.length()-1)),0);
  826. viewer.ftp.historyComboBox.setSelectedIndex(0);
  827. }
  828. //Call this method to delete a file at server
  829. void deleteRemoteFile(String text)
  830. {
  831. try
  832. {
  833. String temp = text;
  834. writeRfbFileTransferMsg(
  835. rfbCommand,
  836. rfbCFileDelete,
  837. 0,
  838. temp.length(),
  839. temp);
  840. }
  841. catch (IOException e)
  842. {
  843. System.err.println(e);
  844. }
  845. }
  846. //Internally used.
  847. // Handles acknowledgement that the directory has been created on the server
  848. void createRemoteDirectoryFeedback() throws IOException
  849. {
  850. is.readInt();
  851. int length = is.readInt();
  852. String f="";
  853. for (int i = 0; i < length; i++)
  854. {
  855. f += (char)is.readUnsignedByte();
  856. }
  857. viewer.ftp.refreshRemoteLocation();
  858. viewer.ftp.historyComboBox.insertItemAt(new String(" > Created Directory on Remote Machine: " + f.substring(0, f.length()-1)),0);
  859. viewer.ftp.historyComboBox.setSelectedIndex(0);
  860. }
  861. //Call this method to create a directory at server
  862. void createRemoteDirectory(String text)
  863. {
  864. try
  865. {
  866. String temp = text;
  867. writeRfbFileTransferMsg(
  868. rfbCommand,
  869. rfbCDirCreate,
  870. 0,
  871. temp.length(),
  872. temp);
  873. }
  874. catch (IOException e)
  875. {
  876. System.err.println(e);
  877. }
  878. }
  879. //Call this method to get a file from the server
  880. void requestRemoteFile(String text, String localPath)
  881. {
  882. try
  883. {
  884. String temp = text;
  885. receivePath = localPath;
  886. writeRfbFileTransferMsg(
  887. rfbFileTransferRequest,
  888. 0,
  889. 1, // 0 : compression not supported - 1 : compression supported
  890. temp.length(),
  891. temp);
  892. }
  893. catch (IOException e)
  894. {
  895. System.err.println(e);
  896. }
  897. }
  898. //Internally used when transferring file from server. Here, the server sends
  899. //a rfb packet signalling that it is ready to send the file requested
  900. void receiveFileHeader() throws IOException
  901. {
  902. fFileReceptionRunning = true;
  903. fFileReceptionError = false;
  904. viewer.ftp.disableButtons();
  905. int size = is.readInt();
  906. int length = is.readInt();
  907. String tempName = "";
  908. for (int i = 0; i < length; i++)
  909. {
  910. tempName += (char) is.readUnsignedByte();
  911. }
  912. // sf@2004 - Read the high part of file size (not yet in rfbFileTransferMsg for
  913. // backward compatibility reasons...)
  914. int sizeH = is.readInt();
  915. long lSize = ((long)(sizeH) << 32) + size;
  916. receiveFileSize = lSize;
  917. viewer.ftp.connectionStatus.setText("Received: 0 bytes of " + lSize + " bytes");
  918. fileSize=0;
  919. fileChunkCounter = 0;
  920. String fileName = receivePath;
  921. fos = new FileOutputStream(fileName);
  922. writeRfbFileTransferMsg(rfbFileHeader, 0, 0, 0, null);
  923. }
  924. //Internally used when transferring file from server. This method receives one chunk
  925. //of the file
  926. void receiveFileChunk() throws IOException
  927. {
  928. // sf@2004 - Size = 0 means file chunck not compressed
  929. int size = is.readInt();
  930. boolean fCompressed = (size != 0);
  931. int length = is.readInt();
  932. fileChunkCounter++;
  933. // sf@2004 - allocates buffers for file chunck reception and decompression
  934. byte[] ReceptionBuffer = new byte[length + 32];
  935. // Read the incoming file data
  936. // Todo: check error !
  937. is.readFully(ReceptionBuffer,0, length);
  938. if (fCompressed)
  939. {
  940. int bufSize = sz_rfbBlockSize + 1024; // Todo: set a more accurate value here
  941. int decompressedSize = 0;
  942. byte[] DecompressionBuffer = new byte[bufSize];
  943. Inflater myInflater = new Inflater();
  944. myInflater.setInput(ReceptionBuffer);
  945. try
  946. {
  947. decompressedSize = myInflater.inflate(DecompressionBuffer);
  948. }
  949. catch (DataFormatException e)
  950. {
  951. System.err.println(e);
  952. }
  953. // Todo: check error !
  954. fos.write(DecompressionBuffer, 0, decompressedSize);
  955. fileSize += decompressedSize;
  956. }
  957. else
  958. {
  959. // Todo: check error !
  960. fos.write(ReceptionBuffer, 0, length);
  961. fileSize += length;
  962. }
  963. /*
  964. for (int i = 0; i < length; i++)
  965. {
  966. fos.write(is.readUnsignedByte());
  967. fileSize++;
  968. }
  969. */
  970. // viewer.ftp.connectionStatus.setText("Received: " + fileSize + " bytes of "+ receiveFileSize+ " bytes" );
  971. viewer.ftp.jProgressBar.setValue((int)((fileSize * 100) / receiveFileSize));
  972. viewer.ftp.connectionStatus.setText(">>> Receiving File: " + receivePath + " - Size: " + receiveFileSize + " bytes - Progress: " + ((fileSize * 100) / receiveFileSize) + "%");
  973. if (fAbort == true)
  974. {
  975. fAbort = false;
  976. fFileReceptionError = true;
  977. writeRfbFileTransferMsg(rfbAbortFileTransfer, 0, 0, 0, null);
  978. }
  979. // sf@2004 - For old FT protocole only
  980. /*
  981. if(fileChunkCounter==10)
  982. {
  983. writeRfbFileTransferMsg(rfbFileHeader,0,0,0,null);
  984. fileChunkCounter=0;
  985. }
  986. */
  987. }
  988. //Internally used when transferring file from server. Server signals end of file.
  989. void endOfReceiveFile(boolean fReceptionOk) throws IOException
  990. {
  991. int size = is.readInt();
  992. int length = is.readInt();
  993. fileSize=0;
  994. fos.close();
  995. viewer.ftp.refreshLocalLocation();
  996. if (fReceptionOk && !fFileReceptionError)
  997. {
  998. viewer.ftp.connectionStatus.setText(" > File successfully received");
  999. viewer.ftp.historyComboBox.insertItemAt(new String(" > File: <" + receivePath + "> received from Remote Machine" ),0);
  1000. }
  1001. else
  1002. {
  1003. // sf@2004 - Delete the incomplete receieved file for now (until we use Delta Transfer)
  1004. File f = new File(receivePath);
  1005. f.delete();
  1006. viewer.ftp.connectionStatus.setText(" > Error - File NOT received");
  1007. viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - File: <" + receivePath + "> not correctly received from Remote Machine (aborted by user or error)") ,0);
  1008. }
  1009. fFileReceptionError = false;
  1010. fFileReceptionRunning = false;
  1011. viewer.ftp.historyComboBox.setSelectedIndex(0);
  1012. viewer.ftp.enableButtons();
  1013. }
  1014. //Call this method to read the contents of the server directory
  1015. void readServerDirectory(String text)
  1016. {
  1017. try
  1018. {
  1019. String temp = text;
  1020. writeRfbFileTransferMsg(
  1021. rfbDirContentRequest,
  1022. rfbRDirContent,
  1023. 0,
  1024. temp.length(),
  1025. temp);
  1026. }
  1027. catch (IOException e)
  1028. {
  1029. System.err.println(e);
  1030. }
  1031. }
  1032. //Internally used to receive list of drives available on the server
  1033. void readFTPMsgDriveList() throws IOException
  1034. {
  1035. String str = "";
  1036. for (int i = 0; i < 4; i++)
  1037. {
  1038. is.readUnsignedByte();
  1039. }
  1040. int length = is.readInt();
  1041. for (int i = 0; i < length; i++)
  1042. {
  1043. char temp = (char) is.readUnsignedByte();
  1044. if (temp != '\0')
  1045. {
  1046. str += temp;
  1047. }
  1048. }
  1049. viewer.ftp.printDrives(str);
  1050. // sf@2004
  1051. // Finds the first readable drive and populates the local directory
  1052. viewer.ftp.changeLocalDirectory(viewer.ftp.getFirstReadableLocalDrive());
  1053. // Populate the remote directory
  1054. viewer.ftp.changeRemoteDrive();
  1055. viewer.ftp.refreshRemoteLocation();
  1056. }
  1057. //Internally used to receive directory content from server
  1058. //Here, the server marks the start of the directory listing
  1059. void readFTPMsgDirectoryList() throws IOException
  1060. {
  1061. is.readInt();
  1062. int length = is.readInt();
  1063. if (length == 0)
  1064. {
  1065. readFTPMsgDirectorydriveNotReady();
  1066. inDirectory2 = false;
  1067. }
  1068. else
  1069. {
  1070. // sf@2004 - New FT protocole sends remote directory name
  1071. String str = "";
  1072. for (int i = 0; i < length; i++)
  1073. {
  1074. char temp = (char) is.readUnsignedByte();
  1075. if (temp != '\0')
  1076. {
  1077. str += temp;
  1078. }
  1079. }
  1080. // viewer.ftp.changeRemoteDirectory(str);
  1081. }
  1082. }
  1083. //Internally used to receive directory content from server
  1084. //Here, the server sends one file/directory with it's attributes
  1085. void readFTPMsgDirectoryListContent() throws IOException
  1086. {
  1087. String fileName = "", alternateFileName = "";
  1088. byte contentType = 0;
  1089. int contentParamT = 0;
  1090. int contentParam = 0;
  1091. byte temp = 0;
  1092. int dwFileAttributes,
  1093. nFileSizeHigh,
  1094. nFileSizeLow,
  1095. dwReserved0,
  1096. dwReserved1;
  1097. long ftCreationTime, ftLastAccessTime, ftLastWriteTime;
  1098. char cFileName, cAlternateFileName;
  1099. int length = 0;
  1100. is.readInt();
  1101. length = is.readInt();
  1102. dwFileAttributes = is.readInt();
  1103. length -= 4;
  1104. ftCreationTime = is.readLong();
  1105. length -= 8;
  1106. ftLastAccessTime = is.readLong();
  1107. length -= 8;
  1108. ftLastWriteTime = is.readLong();
  1109. length -= 8;
  1110. nFileSizeHigh = is.readInt();
  1111. length -= 4;
  1112. nFileSizeLow = is.readInt();
  1113. length -= 4;
  1114. dwReserved0 = is.readInt();
  1115. length -= 4;
  1116. dwReserved1 = is.readInt();
  1117. length -= 4;
  1118. cFileName = (char) is.readUnsignedByte();
  1119. length--;
  1120. while (cFileName != '\0')
  1121. {
  1122. fileName += cFileName;
  1123. cFileName = (char) is.readUnsignedByte();
  1124. length--;
  1125. }
  1126. cAlternateFileName = (char) is.readByte();
  1127. length--;
  1128. while (length != 0)
  1129. {
  1130. alternateFileName += cAlternateFileName;
  1131. cAlternateFileName = (char) is.readUnsignedByte();
  1132. length--;
  1133. }
  1134. if (dwFileAttributes == 268435456
  1135. || dwFileAttributes == 369098752
  1136. || dwFileAttributes == 285212672
  1137. || dwFileAttributes == 271056896
  1138. || dwFileAttributes == 824705024
  1139. || dwFileAttributes == 807927808
  1140. || dwFileAttributes == 371720192
  1141. || dwFileAttributes == 369623040)
  1142. {
  1143. fileName = " [" + fileName + "]";
  1144. remoteDirsList.add(fileName); // sf@2004
  1145. }
  1146. else
  1147. {
  1148. remoteFilesList.add(" " + fileName); // sf@2004
  1149. }
  1150. // a.add(fileName);
  1151. }
  1152. //Internally used to read directory content of server.
  1153. //Here, server signals end of directory.
  1154. void readFTPMsgDirectoryListEndContent() throws IOException
  1155. {
  1156. is.readInt();
  1157. int length = is.readInt();
  1158. // sf@2004
  1159. a.clear();
  1160. for (int i = 0; i < remoteDirsList.size(); i++)
  1161. a.add(remoteDirsList.get(i));
  1162. for (int i = 0; i < remoteFilesList.size(); i++)
  1163. a.add(remoteFilesList.get(i));
  1164. remoteDirsList.clear();
  1165. remoteFilesList.clear();
  1166. viewer.ftp.printDirectory(a);
  1167. }
  1168. //Internally used to signify the drive requested is not ready
  1169. void readFTPMsgDirectorydriveNotReady() throws IOException
  1170. {
  1171. System.out.println("Remote Drive unavailable");
  1172. viewer.ftp.connectionStatus.setText(" > WARNING - Remote Drive unavailable (possibly restricted access or media not present)");
  1173. viewer.ftp.remoteStatus.setText("WARNING: Remote Drive unavailable");
  1174. }
  1175. //Call this method to request the list of drives on the server.
  1176. void readServerDriveList()
  1177. {
  1178. try
  1179. {
  1180. viewer.rfb.writeRfbFileTransferMsg(
  1181. RfbProto.rfbDirContentRequest,
  1182. RfbProto.rfbRDrivesList,
  1183. 0,
  1184. 0,
  1185. null);
  1186. }
  1187. catch (IOException e)
  1188. {
  1189. System.err.println(e);
  1190. }
  1191. }
  1192. // sf@2004 - Read the destination file checksums data
  1193. // We don't use it for now
  1194. void ReceiveDestinationFileChecksums() throws IOException
  1195. {
  1196. int size = is.readInt();
  1197. int length = is.readInt();
  1198. byte[] ReceptionBuffer = new byte[length + 32];
  1199. // Read the incoming file data
  1200. is.readFully(ReceptionBuffer,0, length);
  1201. /*
  1202. String csData = "";
  1203. for (int i = 0; i < length; i++)
  1204. {
  1205. csData += (char) is.readUnsignedByte();
  1206. }
  1207. */
  1208. // viewer.ftp.connectionStatus.setText("Received: 0 bytes of " + size + " bytes");
  1209. }
  1210. ///////////////////////////////////////////////////////////////////////////////////////////////
  1211. //////////////////////////////////////////////////////////////////////////
  1212. //
  1213. // Write a FramebufferUpdateRequest message
  1214. //
  1215. void writeFramebufferUpdateRequest(
  1216. int x,
  1217. int y,
  1218. int w,
  1219. int h,
  1220. boolean incremental)
  1221. throws IOException {
  1222. if (!viewer.ftp.isVisible()) {
  1223. byte[] b = new byte[10];
  1224. b[0] = (byte) FramebufferUpdateRequest;
  1225. b[1] = (byte) (incremental ? 1 : 0);
  1226. b[2] = (byte) ((x >> 8) & 0xff);
  1227. b[3] = (byte) (x & 0xff);
  1228. b[4] = (byte) ((y >> 8) & 0xff);
  1229. b[5] = (byte) (y & 0xff);
  1230. b[6] = (byte) ((w >> 8) & 0xff);
  1231. b[7] = (byte) (w & 0xff);
  1232. b[8] = (byte) ((h >> 8) & 0xff);
  1233. b[9] = (byte) (h & 0xff);
  1234. os.write(b);
  1235. }
  1236. }
  1237. //
  1238. // Write a SetPixelFormat message
  1239. //
  1240. void writeSetPixelFormat(
  1241. int bitsPerPixel,
  1242. int depth,
  1243. boolean bigEndian,
  1244. boolean trueColour,
  1245. int redMax,
  1246. int greenMax,
  1247. int blueMax,
  1248. int redShift,
  1249. int greenShift,
  1250. int blueShift,
  1251. boolean fGreyScale) // sf@2005
  1252. throws IOException {
  1253. byte[] b = new byte[20];
  1254. b[0] = (byte) SetPixelFormat;
  1255. b[4] = (byte) bitsPerPixel;
  1256. b[5] = (byte) depth;
  1257. b[6] = (byte) (bigEndian ? 1 : 0);
  1258. b[7] = (byte) (trueColour ? 1 : 0);
  1259. b[8] = (byte) ((redMax >> 8) & 0xff);
  1260. b[9] = (byte) (redMax & 0xff);
  1261. b[10] = (byte) ((greenMax >> 8) & 0xff);
  1262. b[11] = (byte) (greenMax & 0xff);
  1263. b[12] = (byte) ((blueMax >> 8) & 0xff);
  1264. b[13] = (byte) (blueMax & 0xff);
  1265. b[14] = (byte) redShift;
  1266. b[15] = (byte) greenShift;
  1267. b[16] = (byte) blueShift;
  1268. b[17] = (byte) (fGreyScale ? 1 : 0); // sf@2005
  1269. os.write(b);
  1270. }
  1271. //
  1272. // Write a FixColourMapEntries message. The values in the red, green and
  1273. // blue arrays are from 0 to 65535.
  1274. //
  1275. void writeFixColourMapEntries(
  1276. int firstColour,
  1277. int nColours,
  1278. int[] red,
  1279. int[] green,
  1280. int[] blue)
  1281. throws IOException {
  1282. byte[] b = new byte[6 + nColours * 6];
  1283. b[0] = (byte) FixColourMapEntries;
  1284. b[2] = (byte) ((firstColour >> 8) & 0xff);
  1285. b[3] = (byte) (firstColour & 0xff);
  1286. b[4] = (byte) ((nColours >> 8) & 0xff);
  1287. b[5] = (byte) (nColours & 0xff);
  1288. for (int i = 0; i < nColours; i++) {
  1289. b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff);
  1290. b[6 + i * 6 + 1] = (byte) (red[i] & 0xff);
  1291. b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff);
  1292. b[6 + i * 6 + 3] = (byte) (green[i] & 0xff);
  1293. b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff);
  1294. b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff);
  1295. }
  1296. os.write(b);
  1297. }
  1298. //
  1299. // Write a SetEncodings message
  1300. //
  1301. void writeSetEncodings(int[] encs, int len) throws IOException {
  1302. byte[] b = new byte[4 + 4 * len];
  1303. b[0] = (byte) SetEncodings;
  1304. b[2] = (byte) ((len >> 8) & 0xff);
  1305. b[3] = (byte) (len & 0xff);
  1306. for (int i = 0; i < len; i++) {
  1307. b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff);
  1308. b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff);
  1309. b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff);
  1310. b[7 + 4 * i] = (byte) (encs[i] & 0xff);
  1311. }
  1312. os.write(b);
  1313. }
  1314. //
  1315. // Write a ClientCutText message
  1316. //
  1317. void writeClientCutText(String text) throws IOException {
  1318. // if (!viewer.ftp.isVisible()) {
  1319. byte[] b = new byte[8 + text.length()];
  1320. b[0] = (byte) ClientCutText;
  1321. b[4] = (byte) ((text.length() >> 24) & 0xff);
  1322. b[5] = (byte) ((text.length() >> 16) & 0xff);
  1323. b[6] = (byte) ((text.length() >> 8) & 0xff);
  1324. b[7] = (byte) (text.length() & 0xff);
  1325. System.arraycopy(text.getBytes(), 0, b, 8, text.length());
  1326. os.write(b);
  1327. // }
  1328. }
  1329. //
  1330. // A buffer for putting pointer and keyboard events before being sent. This
  1331. // is to ensure that multiple RFB events generated from a single Java Event
  1332. // will all be sent in a single network packet. The maximum possible
  1333. // length is 4 modifier down events, a single key event followed by 4
  1334. // modifier up events i.e. 9 key events or 72 bytes.
  1335. //
  1336. byte[] eventBuf = new byte[72];
  1337. int eventBufLen;
  1338. // Useful shortcuts for modifier masks.
  1339. final static int CTRL_MASK = InputEvent.CTRL_MASK;
  1340. final static int SHIFT_MASK = InputEvent.SHIFT_MASK;
  1341. final static int META_MASK = InputEvent.META_MASK;
  1342. final static int ALT_MASK = InputEvent.ALT_MASK;
  1343. //
  1344. // Write a pointer event message. We may need to send modifier key events
  1345. // around it to set the correct modifier state.
  1346. //
  1347. int pointerMask = 0;
  1348. void writePointerEvent(MouseEvent evt) throws IOException {
  1349. if (!viewer.ftp.isVisible()) {
  1350. int modifiers = evt.getModifiers();
  1351. int mask2 = 2;
  1352. int mask3 = 4;
  1353. if (viewer.options.reverseMouseButtons2And3) {
  1354. mask2 = 4;
  1355. mask3 = 2;
  1356. }
  1357. // Note: For some reason, AWT does not set BUTTON1_MASK on left
  1358. // button presses. Here we think that it was the left button if
  1359. // modifiers do not include BUTTON2_MASK or BUTTON3_MASK.
  1360. if (evt.getID() == MouseEvent.MOUSE_PRESSED) {
  1361. if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
  1362. pointerMask = mask2;
  1363. modifiers &= ~ALT_MASK;
  1364. } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
  1365. pointerMask = mask3;
  1366. modifiers &= ~META_MASK;
  1367. } else {
  1368. pointerMask = 1;
  1369. }
  1370. } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) {
  1371. pointerMask = 0;
  1372. if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
  1373. modifiers &= ~ALT_MASK;
  1374. } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
  1375. modifiers &= ~META_MASK;
  1376. }
  1377. }
  1378. eventBufLen = 0;
  1379. writeModifierKeyEvents(modifiers);
  1380. int x = evt.getX();
  1381. int y = evt.getY();
  1382. if (x < 0)
  1383. x = 0;
  1384. if (y < 0)
  1385. y = 0;
  1386. eventBuf[eventBufLen++] = (byte) PointerEvent;
  1387. eventBuf[eventBufLen++] = (byte) pointerMask;
  1388. eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff);
  1389. eventBuf[eventBufLen++] = (byte) (x & 0xff);
  1390. eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff);
  1391. eventBuf[eventBufLen++] = (byte) (y & 0xff);
  1392. //
  1393. // Always release all modifiers after an "up" event
  1394. //
  1395. if (pointerMask == 0) {
  1396. writeModifierKeyEvents(0);
  1397. }
  1398. os.write(eventBuf, 0, eventBufLen);
  1399. }
  1400. }
  1401. //
  1402. // Write a key event message. We may need to send modifier key events
  1403. // around it to set the correct modifier state. Also we need to translate
  1404. // from the Java key values to the X keysym values used by the RFB protocol.
  1405. //
  1406. void writeKeyEvent(KeyEvent evt) throws IOException {
  1407. if (!viewer.ftp.isVisible()) {
  1408. int keyChar = evt.getKeyChar();
  1409. //
  1410. // Ignore event if only modifiers were pressed.
  1411. //
  1412. // Some JVMs return 0 instead of CHAR_UNDEFINED in getKeyChar().
  1413. if (keyChar == 0)
  1414. keyChar = KeyEvent.CHAR_UNDEFINED;
  1415. if (keyChar == KeyEvent.CHAR_UNDEFINED) {
  1416. int code = evt.getKeyCode();
  1417. if (code == KeyEvent.VK_CONTROL
  1418. || code == KeyEvent.VK_SHIFT
  1419. || code == KeyEvent.VK_META
  1420. || code == KeyEvent.VK_ALT)
  1421. return;
  1422. }
  1423. //
  1424. // Key press or key release?
  1425. //
  1426. boolean down = (evt.getID() == KeyEvent.KEY_PRESSED);
  1427. int key;
  1428. if (evt.isActionKey()) {
  1429. //
  1430. // An action key should be one of the following.
  1431. // If not then just ignore the event.
  1432. //
  1433. switch (evt.getKeyCode()) {
  1434. case KeyEvent.VK_HOME :
  1435. key = 0xff50;
  1436. break;
  1437. case KeyEvent.VK_LEFT :
  1438. key = 0xff51;
  1439. break;
  1440. case KeyEvent.VK_UP :
  1441. key = 0xff52;
  1442. break;
  1443. case KeyEvent.VK_RIGHT :
  1444. key = 0xff53;
  1445. break;
  1446. case KeyEvent.VK_DOWN :
  1447. key = 0xff54;
  1448. break;
  1449. case KeyEvent.VK_PAGE_UP :
  1450. key = 0xff55;
  1451. break;
  1452. case KeyEvent.VK_PAGE_DOWN :
  1453. key = 0xff56;
  1454. break;
  1455. case KeyEvent.VK_END :
  1456. key = 0xff57;
  1457. break;
  1458. case KeyEvent.VK_INSERT :
  1459. key = 0xff63;
  1460. break;
  1461. case KeyEvent.VK_F1 :
  1462. key = 0xffbe;
  1463. break;
  1464. case KeyEvent.VK_F2 :
  1465. key = 0xffbf;
  1466. break;
  1467. case KeyEvent.VK_F3 :
  1468. key = 0xffc0;
  1469. break;
  1470. case KeyEvent.VK_F4 :
  1471. key = 0xffc1;
  1472. break;
  1473. case KeyEvent.VK_F5 :
  1474. key = 0xffc2;
  1475. break;
  1476. case KeyEvent.VK_F6 :
  1477. key = 0xffc3;
  1478. break;
  1479. case KeyEvent.VK_F7 :
  1480. key = 0xffc4;
  1481. break;
  1482. case KeyEvent.VK_F8 :
  1483. key = 0xffc5;
  1484. break;
  1485. case KeyEvent.VK_F9 :
  1486. key = 0xffc6;
  1487. break;
  1488. case KeyEvent.VK_F10 :
  1489. key = 0xffc7;
  1490. break;
  1491. case KeyEvent.VK_F11 :
  1492. key = 0xffc8;
  1493. break;
  1494. case KeyEvent.VK_F12 :
  1495. key = 0xffc9;
  1496. break;
  1497. default :
  1498. return;
  1499. }
  1500. } else {
  1501. //
  1502. // A "normal" key press. Ordinary ASCII characters go straight through.
  1503. // For CTRL-<letter>, CTRL is sent separately so just send <letter>.
  1504. // Backspace, tab, return, escape and delete have special keysyms.
  1505. // Anything else we ignore.
  1506. //
  1507. key = keyChar;
  1508. if (key < 0x20) {
  1509. if (evt.isControlDown()) {
  1510. key += 0x60;
  1511. } else {
  1512. switch (key) {
  1513. case KeyEvent.VK_BACK_SPACE :
  1514. key = 0xff08;
  1515. break;
  1516. case KeyEvent.VK_TAB :
  1517. key = 0xff09;
  1518. break;
  1519. case KeyEvent.VK_ENTER :
  1520. key = 0xff0d;
  1521. break;
  1522. case KeyEvent.VK_ESCAPE :
  1523. key = 0xff1b;
  1524. break;
  1525. }
  1526. }
  1527. } else if (key == 0x7f) {
  1528. // Delete
  1529. key = 0xffff;
  1530. } else if (key > 0xff) {
  1531. // JDK1.1 on X incorrectly passes some keysyms straight through,
  1532. // so we do too. JDK1.1.4 seems to have fixed this.
  1533. // The keysyms passed are 0xff00 .. XK_BackSpace .. XK_Delete
  1534. if ((key < 0xff00) || (key > 0xffff))
  1535. return;
  1536. }
  1537. }
  1538. // Fake keyPresses for keys that only generates keyRelease events
  1539. if ((key == 0xe5)
  1540. || (key == 0xc5)
  1541. || // XK_aring / XK_Aring
  1542. (key == 0xe4)
  1543. || (key == 0xc4)
  1544. || // XK_adiaeresis / XK_Adiaeresis
  1545. (key == 0xf6)
  1546. || (key == 0xd6)
  1547. || // XK_odiaeresis / XK_Odiaeresis
  1548. (key == 0xa7)
  1549. || (key == 0xbd)
  1550. || // XK_section / XK_onehalf
  1551. (key == 0xa3)) { // XK_sterling
  1552. // Make sure we do not send keypress events twice on platforms
  1553. // with correct JVMs (those that actually report KeyPress for all
  1554. // keys)
  1555. if (down)
  1556. brokenKeyPressed = true;
  1557. if (!down && !brokenKeyPressed) {
  1558. // We've got a release event for this key, but haven't received
  1559. // a press. Fake it.
  1560. eventBufLen = 0;
  1561. writeModifierKeyEvents(evt.getModifiers());
  1562. writeKeyEvent(key, true);
  1563. os.write(eventBuf, 0, eventBufLen);
  1564. }
  1565. if (!down)
  1566. brokenKeyPressed = false;
  1567. }
  1568. eventBufLen = 0;
  1569. writeModifierKeyEvents(evt.getModifiers());
  1570. writeKeyEvent(key, down);
  1571. // Always release all modifiers after an "up" event
  1572. if (!down)
  1573. writeModifierKeyEvents(0);
  1574. os.write(eventBuf, 0, eventBufLen);
  1575. }
  1576. }
  1577. //
  1578. // Add a raw key event with the given X keysym to eventBuf.
  1579. //
  1580. void writeKeyEvent(int keysym, boolean down) {
  1581. eventBuf[eventBufLen++] = (byte) KeyboardEvent;
  1582. eventBuf[eventBufLen++] = (byte) (down ? 1 : 0);
  1583. eventBuf[eventBufLen++] = (byte) 0;
  1584. eventBuf[eventBufLen++] = (byte) 0;
  1585. eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff);
  1586. eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff);
  1587. eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff);
  1588. eventBuf[eventBufLen++] = (byte) (keysym & 0xff);
  1589. }
  1590. //
  1591. // Write key events to set the correct modifier state.
  1592. //
  1593. int oldModifiers = 0;
  1594. void writeModifierKeyEvents(int newModifiers) {
  1595. if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK))
  1596. writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0);
  1597. if ((newModifiers & SHIFT_MASK) != (oldModifiers & SHIFT_MASK))
  1598. writeKeyEvent(0xffe1, (newModifiers & SHIFT_MASK) != 0);
  1599. if ((newModifiers & META_MASK) != (oldModifiers & META_MASK))
  1600. writeKeyEvent(0xffe7, (newModifiers & META_MASK) != 0);
  1601. if ((newModifiers & ALT_MASK) != (oldModifiers & ALT_MASK))
  1602. writeKeyEvent(0xffe9, (newModifiers & ALT_MASK) != 0);
  1603. oldModifiers = newModifiers;
  1604. }
  1605. //
  1606. // Compress and write the data into the recorded session file. This
  1607. // method assumes the recording is on (rec != null).
  1608. //
  1609. void recordCompressedData(byte[] data, int off, int len)
  1610. throws IOException {
  1611. Deflater deflater = new Deflater();
  1612. deflater.setInput(data, off, len);
  1613. int bufSize = len + len / 100 + 12;
  1614. byte[] buf = new byte[bufSize];
  1615. deflater.finish();
  1616. int compressedSize = deflater.deflate(buf);
  1617. recordCompactLen(compressedSize);
  1618. rec.write(buf, 0, compressedSize);
  1619. }
  1620. void recordCompressedData(byte[] data) throws IOException {
  1621. recordCompressedData(data, 0, data.length);
  1622. }
  1623. //
  1624. // Write an integer in compact representation (1..3 bytes) into the
  1625. // recorded session file. This method assumes the recording is on
  1626. // (rec != null).
  1627. //
  1628. void recordCompactLen(int len) throws IOException {
  1629. byte[] buf = new byte[3];
  1630. int bytes = 0;
  1631. buf[bytes++] = (byte) (len & 0x7F);
  1632. if (len > 0x7F) {
  1633. buf[bytes - 1] |= 0x80;
  1634. buf[bytes++] = (byte) (len >> 7 & 0x7F);
  1635. if (len > 0x3FFF) {
  1636. buf[bytes - 1] |= 0x80;
  1637. buf[bytes++] = (byte) (len >> 14 & 0xFF);
  1638. }
  1639. }
  1640. rec.write(buf, 0, bytes);
  1641. }
  1642. }