--- /dev/null
+package com.tightvnc.decoder;
+
+import com.tightvnc.vncviewer.RfbInputStream;
+import java.awt.Graphics;
+import java.awt.Color;
+import java.io.IOException;
+
+//
+// Class that used for decoding CoRRE encoded data.
+//
+
+public class CoRREDecoder extends RawDecoder {
+
+ final static int EncodingCoRRE = 4;
+
+ public CoRREDecoder(Graphics g, RfbInputStream is) {
+ super(g, is);
+ }
+
+ public CoRREDecoder(Graphics g, RfbInputStream is, int frameBufferW,
+ int frameBufferH) {
+ super(g, is, frameBufferW, frameBufferH);
+ }
+
+ //
+ // Override handleRect method to decode CoRRE encoded data insted of
+ // raw pixel data.
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws IOException {
+
+ //
+ // Write encoding ID to record output stream
+ //
+
+ if (dos != null) {
+ dos.writeInt(CoRREDecoder.EncodingCoRRE);
+ }
+
+ int nSubrects = rfbis.readU32();
+
+ byte[] bg_buf = new byte[bytesPerPixel];
+ rfbis.readFully(bg_buf);
+ Color pixel;
+ if (bytesPerPixel == 1) {
+ pixel = getColor256()[bg_buf[0] & 0xFF];
+ } else {
+ pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
+ }
+ graphics.setColor(pixel);
+ graphics.fillRect(x, y, w, h);
+
+ byte[] buf = new byte[nSubrects * (bytesPerPixel + 4)];
+ rfbis.readFully(buf);
+
+ //
+ // Save decoded data to data output stream
+ //
+
+ if (dos != null) {
+ dos.writeInt(nSubrects);
+ dos.write(bg_buf);
+ dos.write(buf);
+ }
+
+ int sx, sy, sw, sh;
+ int i = 0;
+
+ for (int j = 0; j < nSubrects; j++) {
+ if (bytesPerPixel == 1) {
+ pixel = getColor256()[buf[i++] & 0xFF];
+ } else {
+ pixel = new Color(buf[i+2] & 0xFF, buf[i+1] & 0xFF, buf[i] & 0xFF);
+ i += 4;
+ }
+ sx = x + (buf[i++] & 0xFF);
+ sy = y + (buf[i++] & 0xFF);
+ sw = buf[i++] & 0xFF;
+ sh = buf[i++] & 0xFF;
+
+ graphics.setColor(pixel);
+ graphics.fillRect(sx, sy, sw, sh);
+ }
+ }
+}
--- /dev/null
+package com.tightvnc.decoder;
+
+import com.tightvnc.vncviewer.RfbInputStream;
+import java.awt.Graphics;
+import java.io.IOException;
+
+//
+// Class that used for decoding CopyRect encoded data.
+//
+
+public class CopyRectDecoder extends RawDecoder {
+
+ final static int EncodingCopyRect = 1;
+
+ public CopyRectDecoder(Graphics g, RfbInputStream is) {
+ super(g, is);
+ }
+
+ public CopyRectDecoder(Graphics g, RfbInputStream is, int frameBufferW,
+ int frameBufferH) {
+ super(g, is, frameBufferW, frameBufferH);
+ }
+
+ //
+ // Override handleRect method handle CopyRect
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws IOException {
+
+ //
+ // Write encoding ID to record output stream
+ //
+
+ if (dos != null) {
+ dos.writeInt(CopyRectDecoder.EncodingCopyRect);
+ }
+
+ int copyRectSrcX = rfbis.readU16();
+ int copyRectSrcY = rfbis.readU16();
+
+ // If the session is being recorded:
+ if (dos != null) {
+ dos.writeShort(copyRectSrcX);
+ dos.writeShort(copyRectSrcY);
+ }
+
+ graphics.copyArea(copyRectSrcX, copyRectSrcY, w, h,
+ x - copyRectSrcX, y - copyRectSrcY);
+ }
+}
--- /dev/null
+package com.tightvnc.decoder;
+
+import com.tightvnc.decoder.common.Repaintable;
+import com.tightvnc.vncviewer.RfbInputStream;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.io.IOException;
+
+//
+// Class that used for decoding hextile encoded data.
+//
+
+public class HextileDecoder extends RawDecoder {
+
+ final static int EncodingHextile = 5;
+
+ // Contstants used in the Hextile decoder
+ final static int
+ HextileRaw = 1,
+ HextileBackgroundSpecified = 2,
+ HextileForegroundSpecified = 4,
+ HextileAnySubrects = 8,
+ HextileSubrectsColoured = 16;
+
+ public HextileDecoder(Graphics g, RfbInputStream is) {
+ super(g, is);
+ }
+
+ public HextileDecoder(Graphics g, RfbInputStream is, int frameBufferW,
+ int frameBufferH) {
+ super(g, is, frameBufferW, frameBufferH);
+ }
+
+ //
+ // Set private members methods
+ //
+
+ public void setRepainableControl(Repaintable r) {
+ repainableControl = r;
+ }
+
+ //
+ // Override handleRect method to decode Hextile encoded data insted of
+ // raw pixel data.
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws IOException,
+ Exception {
+
+ //
+ // Write encoding ID to record output stream
+ //
+
+ if (dos != null) {
+ dos.writeInt(HextileDecoder.EncodingHextile);
+ }
+
+ hextile_bg = new Color(0);
+ hextile_fg = new Color(0);
+
+ for (int ty = y; ty < y + h; ty += 16) {
+ int th = 16;
+ if (y + h - ty < 16)
+ th = y + h - ty;
+
+ for (int tx = x; tx < x + w; tx += 16) {
+ int tw = 16;
+ if (x + w - tx < 16)
+ tw = x + w - tx;
+
+ handleHextileSubrect(tx, ty, tw, th);
+ }
+ if (repainableControl != null)
+ repainableControl.scheduleRepaint(x, y, w, h);
+ }
+ if (repainableControl != null)
+ repainableControl.scheduleRepaint(x, y, w, h);
+ }
+
+ //
+ // Handle one tile in the Hextile-encoded data.
+ //
+
+ private void handleHextileSubrect(int tx, int ty, int tw, int th)
+ throws IOException, Exception {
+
+ int subencoding = rfbis.readU8();
+
+ //
+ // Save decoded data to data output stream
+ //
+
+ if (dos != null) {
+ dos.writeByte((byte)subencoding);
+ }
+
+ // Is it a raw-encoded sub-rectangle?
+ if ((subencoding & HextileRaw) != 0) {
+ //
+ // Disable encoding id writting to record stream
+ // in super (RawDecoder) class, cause we write subencoding ID
+ // in this class (see code above).
+ //
+
+ super.enableEncodingRecordWritting(false);
+ super.handleRect(tx, ty, tw, th);
+ super.handleUpdatedPixels(tx, ty, tw, th);
+ super.enableEncodingRecordWritting(true);
+ return;
+ }
+
+ // Read and draw the background if specified.
+ byte[] cbuf = new byte[bytesPerPixel];
+ if ((subencoding & HextileBackgroundSpecified) != 0) {
+ rfbis.readFully(cbuf);
+ if (bytesPerPixel == 1) {
+ hextile_bg = getColor256()[cbuf[0] & 0xFF];
+ } else {
+ hextile_bg = new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
+ }
+
+ //
+ // Save decoded data to data output stream
+ //
+
+ if (dos != null) {
+ dos.write(cbuf);
+ }
+ }
+ graphics.setColor(hextile_bg);
+ graphics.fillRect(tx, ty, tw, th);
+
+ // Read the foreground color if specified.
+ if ((subencoding & HextileForegroundSpecified) != 0) {
+ rfbis.readFully(cbuf);
+ if (bytesPerPixel == 1) {
+ hextile_fg = getColor256()[cbuf[0] & 0xFF];
+ } else {
+ hextile_fg = new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
+ }
+
+ //
+ // Save decoded data to data output stream
+ //
+
+ if (dos != null) {
+ dos.write(cbuf);
+ }
+ }
+
+ // Done with this tile if there is no sub-rectangles.
+ if ((subencoding & HextileAnySubrects) == 0)
+ return;
+
+ int nSubrects = rfbis.readU8();
+ int bufsize = nSubrects * 2;
+ if ((subencoding & HextileSubrectsColoured) != 0) {
+ bufsize += nSubrects * bytesPerPixel;
+ }
+ byte[] buf = new byte[bufsize];
+ rfbis.readFully(buf);
+
+ //
+ // Save decoded data to data output stream
+ //
+
+ if (dos != null) {
+ dos.writeByte((byte)nSubrects);
+ dos.write(buf);
+ }
+
+ int b1, b2, sx, sy, sw, sh;
+ int i = 0;
+
+ if ((subencoding & HextileSubrectsColoured) == 0) {
+
+ // Sub-rectangles are all of the same color.
+ graphics.setColor(hextile_fg);
+ for (int j = 0; j < nSubrects; j++) {
+ b1 = buf[i++] & 0xFF;
+ b2 = buf[i++] & 0xFF;
+ sx = tx + (b1 >> 4);
+ sy = ty + (b1 & 0xf);
+ sw = (b2 >> 4) + 1;
+ sh = (b2 & 0xf) + 1;
+ graphics.fillRect(sx, sy, sw, sh);
+ }
+ } else if (bytesPerPixel == 1) {
+
+ // BGR233 (8-bit color) version for colored sub-rectangles.
+ for (int j = 0; j < nSubrects; j++) {
+ hextile_fg = getColor256()[buf[i++] & 0xFF];
+ b1 = buf[i++] & 0xFF;
+ b2 = buf[i++] & 0xFF;
+ sx = tx + (b1 >> 4);
+ sy = ty + (b1 & 0xf);
+ sw = (b2 >> 4) + 1;
+ sh = (b2 & 0xf) + 1;
+ graphics.setColor(hextile_fg);
+ graphics.fillRect(sx, sy, sw, sh);
+ }
+
+ } else {
+
+ // Full-color (24-bit) version for colored sub-rectangles.
+ for (int j = 0; j < nSubrects; j++) {
+ hextile_fg = new Color(buf[i+2] & 0xFF,
+ buf[i+1] & 0xFF,
+ buf[i] & 0xFF);
+ i += 4;
+ b1 = buf[i++] & 0xFF;
+ b2 = buf[i++] & 0xFF;
+ sx = tx + (b1 >> 4);
+ sy = ty + (b1 & 0xf);
+ sw = (b2 >> 4) + 1;
+ sh = (b2 & 0xf) + 1;
+ graphics.setColor(hextile_fg);
+ graphics.fillRect(sx, sy, sw, sh);
+ }
+
+ }
+ }
+
+ // These colors should be kept between handleHextileSubrect() calls.
+ private Color hextile_bg, hextile_fg;
+ // Repaitable object
+ private Repaintable repainableControl = null;
+}
--- /dev/null
+package com.tightvnc.decoder;
+
+import com.tightvnc.vncviewer.RfbInputStream;
+import java.awt.Graphics;
+import java.awt.Color;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+//
+// Class that used for decoding RRE encoded data.
+//
+
+public class RREDecoder extends RawDecoder {
+
+ final static int EncodingRRE = 2;
+
+ public RREDecoder(Graphics g, RfbInputStream is) {
+ super(g, is);
+ }
+
+ public RREDecoder(Graphics g, RfbInputStream is, int frameBufferW,
+ int frameBufferH) {
+ super(g, is, frameBufferW, frameBufferH);
+ }
+
+ //
+ // Override handleRect method to decode RRE encoded data insted of
+ // raw pixel data.
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws IOException {
+
+ //
+ // Write encoding ID to record output stream
+ //
+
+ if (dos != null) {
+ dos.writeInt(RREDecoder.EncodingRRE);
+ }
+
+ int nSubrects = rfbis.readU32();
+ byte[] bg_buf = new byte[bytesPerPixel];
+ rfbis.readFully(bg_buf);
+ Color pixel;
+ if (bytesPerPixel == 1) {
+ pixel = getColor256()[bg_buf[0] & 0xFF];
+ } else {
+ pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
+ }
+ graphics.setColor(pixel);
+ graphics.fillRect(x, y, w, h);
+ byte[] buf = new byte[nSubrects * (bytesPerPixel + 8)];
+ rfbis.readFully(buf);
+ DataInputStream ds = new DataInputStream(new ByteArrayInputStream(buf));
+
+ //
+ // Save decoded data to data output stream
+ //
+ if (dos != null) {
+ dos.writeInt(nSubrects);
+ dos.write(bg_buf);
+ dos.write(buf);
+ }
+
+ int sx, sy, sw, sh;
+ for (int j = 0; j < nSubrects; j++) {
+ if (bytesPerPixel == 1) {
+ pixel = getColor256()[ds.readUnsignedByte()];
+ } else {
+ ds.skip(4);
+ pixel = new Color(buf[j*12+2] & 0xFF,
+ buf[j*12+1] & 0xFF,
+ buf[j*12] & 0xFF);
+ }
+ sx = x + ds.readUnsignedShort();
+ sy = y + ds.readUnsignedShort();
+ sw = ds.readUnsignedShort();
+ sh = ds.readUnsignedShort();
+
+ graphics.setColor(pixel);
+ graphics.fillRect(sx, sy, sw, sh);
+ }
+ }
+}
--- /dev/null
+package com.tightvnc.decoder;
+
+import com.tightvnc.vncviewer.RfbInputStream;
+import java.io.IOException;
+import java.io.DataOutput;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.ColorModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.MemoryImageSource;
+import java.awt.Color;
+import java.awt.Toolkit;
+
+//
+// This is base decoder class.
+// Other classes will be childs of RawDecoder.
+//
+
+public class RawDecoder {
+ final static int EncodingRaw = 0;
+
+ public RawDecoder(Graphics g, RfbInputStream is) {
+ setGraphics(g);
+ setRfbInputStream(is);
+ }
+
+ public RawDecoder(Graphics g, RfbInputStream is, int frameBufferW,
+ int frameBufferH) {
+ setGraphics(g);
+ setRfbInputStream(is);
+ setFrameBufferSize(frameBufferW, frameBufferH);
+ // FIXME: cm24 created in getColorModel24.
+ // Remove if no bugs
+ cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
+ }
+
+ //
+ // Set methods to set value of non-static protected members of class
+ //
+
+ public void setRfbInputStream(RfbInputStream is) {
+ rfbis = is;
+ }
+
+ public void setGraphics(Graphics g) {
+ graphics = g;
+ }
+
+ public void setBPP(int bpp) {
+ bytesPerPixel = bpp;
+ }
+
+ public void setFrameBufferSize(int w, int h) {
+ framebufferWidth = w;
+ framebufferHeight = h;
+ }
+
+ //
+ // FIXME: Rename this method after we don't need RecordInterface
+ // in RawDecoder class to record session
+ //
+
+ public void setDataOutputStream(DataOutput os) {
+ dos = os;
+ }
+
+ //
+ // Decodes Raw Pixels data and draw it into graphics
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
+
+ //
+ // Write encoding ID to record output stream
+ //
+
+ if ((dos != null) && (enableEncodingRecordWritting)) {
+ dos.writeInt(RawDecoder.EncodingRaw);
+ }
+
+ if (bytesPerPixel == 1) {
+ for (int dy = y; dy < y + h; dy++) {
+ if (pixels8 != null) {
+ rfbis.readFully(pixels8, dy * framebufferWidth + x, w);
+ }
+ //
+ // Save decoded data to record output stream
+ //
+ if (dos != null) {
+ dos.write(pixels8, dy * framebufferWidth + x, w);
+ }
+ }
+ } else {
+ byte[] buf = new byte[w * 4];
+ int i, offset;
+ for (int dy = y; dy < y + h; dy++) {
+ rfbis.readFully(buf);
+ //
+ // Save decoded data to record output stream
+ //
+ if (dos != null) {
+ dos.write(buf);
+ }
+ offset = dy * framebufferWidth + x;
+ if (pixels24 != null) {
+ for (i = 0; i < w; i++) {
+ pixels24[offset + i] =
+ (buf[i * 4 + 2] & 0xFF) << 16 |
+ (buf[i * 4 + 1] & 0xFF) << 8 |
+ (buf[i * 4] & 0xFF);
+ } //for
+ } // if
+ } // for
+ } // else
+ handleUpdatedPixels(x, y, w, h);
+ } // void
+
+ //
+ // Display newly updated area of pixels.
+ //
+
+ protected void handleUpdatedPixels(int x, int y, int w, int h) {
+ // Draw updated pixels of the off-screen image.
+ pixelsSource.newPixels(x, y, w, h);
+ graphics.setClip(x, y, w, h);
+ graphics.drawImage(rawPixelsImage, 0, 0, null);
+ graphics.setClip(0, 0, framebufferWidth, framebufferHeight);
+ }
+
+ //
+ // Updates pixels data.
+ // This method must be called when framebuffer is resized
+ // or BPP is changed.
+ //
+
+ public void update() {
+ // Images with raw pixels should be re-allocated on every change
+ // of geometry or pixel format.
+ int fbWidth = framebufferWidth;
+ int fbHeight = framebufferHeight;
+
+ if (bytesPerPixel == 1) {
+ pixels24 = null;
+ pixels8 = new byte[fbWidth * fbHeight];
+ pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(),
+ pixels8, 0, fbWidth);
+ } else {
+ pixels8 = null;
+ pixels24 = new int[fbWidth * fbHeight];
+ pixelsSource =
+ new MemoryImageSource(fbWidth, fbHeight, cm24, pixels24, 0, fbWidth);
+ }
+ pixelsSource.setAnimated(true);
+ rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
+ }
+
+ //
+ // Private static members access methods
+ //
+
+ protected ColorModel getColorModel8() {
+ if (cm8 == null) {
+ cm8 = cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
+ }
+ return cm8;
+ }
+
+ protected ColorModel getColorModel24() {
+ if (cm24 == null) {
+ cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
+ }
+ return cm24;
+ }
+
+ protected Color[]getColor256() {
+ if (color256 == null) {
+ color256 = new Color[256];
+ for (int i = 0; i < 256; i++)
+ color256[i] = new Color(cm8.getRGB(i));
+ }
+ return color256;
+ }
+
+ //
+ // This method will be used by HextileDecoder to disable
+ // double writting encoding id to record stream.
+ //
+ // FIXME: Try to find better solution than this.
+ //
+
+ protected void enableEncodingRecordWritting(boolean enable) {
+ enableEncodingRecordWritting = enable;
+ }
+
+ //
+ // Unique data for every decoder (? maybe not ?)
+ //
+
+ protected int bytesPerPixel = 4;
+ protected int framebufferWidth = 0;
+ protected int framebufferHeight = 0;
+ protected RfbInputStream rfbis = null;
+ protected Graphics graphics = null;
+ protected DataOutput dos = null;
+ protected boolean enableEncodingRecordWritting = true;
+
+ //
+ // This data must be shared between decoders
+ //
+
+ protected static byte []pixels8 = null;
+ protected static int []pixels24 = null;
+ protected static MemoryImageSource pixelsSource = null;
+ protected static Image rawPixelsImage = null;
+
+ //
+ // Access to this static members only though protected methods
+ //
+
+ private static ColorModel cm8 = null;
+ private static ColorModel cm24 = null;
+ private static Color []color256 = null;
+}
--- /dev/null
+package com.tightvnc.decoder;
+
+import com.tightvnc.decoder.common.Repaintable;
+import com.tightvnc.vncviewer.RfbInputStream;
+import java.awt.Graphics;
+import java.awt.Color;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.image.ImageObserver;
+import java.io.IOException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+//
+// Class that used for decoding Tight encoded data.
+//
+
+public class TightDecoder extends RawDecoder implements ImageObserver {
+
+ final static int EncodingTight = 7;
+
+ //
+ // Tight decoder constants
+ //
+
+ final static int TightExplicitFilter = 0x04;
+ final static int TightFill = 0x08;
+ final static int TightJpeg = 0x09;
+ final static int TightMaxSubencoding = 0x09;
+ final static int TightFilterCopy = 0x00;
+ final static int TightFilterPalette = 0x01;
+ final static int TightFilterGradient = 0x02;
+ final static int TightMinToCompress = 12;
+
+ // Tight encoder's data.
+ final static int tightZlibBufferSize = 512;
+
+ public TightDecoder(Graphics g, RfbInputStream is) {
+ super(g, is);
+ tightInflaters = new Inflater[4];
+ }
+
+ public TightDecoder(Graphics g, RfbInputStream is, int frameBufferW,
+ int frameBufferH) {
+ super(g, is, frameBufferW, frameBufferH);
+ tightInflaters = new Inflater[4];
+ }
+
+ //
+ // Set and get methods for private TightDecoder
+ //
+
+ public void setRepainableControl(Repaintable r) {
+ repainatableControl = r;
+ }
+
+ //
+ // JPEG processing statistic methods
+ //
+
+ public long getNumJPEGRects() {
+ return statNumRectsTightJPEG;
+ }
+
+ public void setNumJPEGRects(int v) {
+ statNumRectsTightJPEG = v;
+ }
+
+ //
+ // Tight processing statistic methods
+ //
+
+ public long getNumTightRects() {
+ return statNumRectsTight;
+ }
+
+ public void setNumTightRects(int v) {
+ statNumRectsTight = v;
+ }
+
+ //
+ // Handle a Tight-encoded rectangle.
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws Exception {
+
+ //
+ // Write encoding ID to record output stream
+ //
+
+ if (dos != null) {
+ dos.writeInt(TightDecoder.EncodingTight);
+ }
+
+ int comp_ctl = rfbis.readU8();
+
+ if (dos != null) {
+ // Tell the decoder to flush each of the four zlib streams.
+ dos.writeByte(comp_ctl | 0x0F);
+ }
+
+ // Flush zlib streams if we are told by the server to do so.
+ for (int stream_id = 0; stream_id < 4; stream_id++) {
+ if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) {
+ tightInflaters[stream_id] = null;
+ }
+ comp_ctl >>= 1;
+ }
+
+ // Check correctness of subencoding value.
+ if (comp_ctl > TightDecoder.TightMaxSubencoding) {
+ throw new Exception("Incorrect tight subencoding: " + comp_ctl);
+ }
+
+ // Handle solid-color rectangles.
+ if (comp_ctl == TightDecoder.TightFill) {
+
+ if (bytesPerPixel == 1) {
+ int idx = rfbis.readU8();
+ graphics.setColor(getColor256()[idx]);
+ if (dos != null) {
+ dos.writeByte(idx);
+ }
+ } else {
+ byte[] buf = new byte[3];
+ rfbis.readFully(buf);
+ if (dos != null) {
+ dos.write(buf);
+ }
+ Color bg = new Color(0xFF000000 | (buf[0] & 0xFF) << 16 |
+ (buf[1] & 0xFF) << 8 | (buf[2] & 0xFF));
+ graphics.setColor(bg);
+ }
+ graphics.fillRect(x, y, w, h);
+ repainatableControl.scheduleRepaint(x, y, w, h);
+ return;
+
+ }
+
+ if (comp_ctl == TightDecoder.TightJpeg) {
+
+ statNumRectsTightJPEG++;
+
+ // Read JPEG data.
+ byte[] jpegData = new byte[rfbis.readCompactLen()];
+ rfbis.readFully(jpegData);
+ if (dos != null) {
+ recordCompactLen(jpegData.length);
+ dos.write(jpegData);
+ }
+
+ // Create an Image object from the JPEG data.
+ Image jpegImage = Toolkit.getDefaultToolkit().createImage(jpegData);
+
+ // Remember the rectangle where the image should be drawn.
+ jpegRect = new Rectangle(x, y, w, h);
+
+ // Let the imageUpdate() method do the actual drawing, here just
+ // wait until the image is fully loaded and drawn.
+ synchronized(jpegRect) {
+ Toolkit.getDefaultToolkit().prepareImage(jpegImage, -1, -1, this);
+ try {
+ // Wait no longer than three seconds.
+ jpegRect.wait(3000);
+ } catch (InterruptedException e) {
+ throw new Exception("Interrupted while decoding JPEG image");
+ }
+ }
+
+ // Done, jpegRect is not needed any more.
+ jpegRect = null;
+ return;
+
+ } else {
+ statNumRectsTight++;
+ }
+
+ // Read filter id and parameters.
+ int numColors = 0, rowSize = w;
+ byte[] palette8 = new byte[2];
+ int[] palette24 = new int[256];
+ boolean useGradient = false;
+ if ((comp_ctl & TightDecoder.TightExplicitFilter) != 0) {
+ int filter_id = rfbis.readU8();
+ if (dos != null) {
+ dos.writeByte(filter_id);
+ }
+ if (filter_id == TightDecoder.TightFilterPalette) {
+ numColors = rfbis.readU8() + 1;
+ if (dos != null) {
+ dos.writeByte((numColors - 1));
+ }
+ if (bytesPerPixel == 1) {
+ if (numColors != 2) {
+ throw new Exception("Incorrect tight palette size: " + numColors);
+ }
+ rfbis.readFully(palette8);
+ if (dos != null) {
+ dos.write(palette8);
+ }
+ } else {
+ byte[] buf = new byte[numColors * 3];
+ rfbis.readFully(buf);
+ if (dos != null) {
+ dos.write(buf);
+ }
+ for (int i = 0; i < numColors; i++) {
+ palette24[i] = ((buf[i * 3] & 0xFF) << 16 |
+ (buf[i * 3 + 1] & 0xFF) << 8 |
+ (buf[i * 3 + 2] & 0xFF));
+ }
+ }
+ if (numColors == 2) {
+ rowSize = (w + 7) / 8;
+ }
+ } else if (filter_id == TightDecoder.TightFilterGradient) {
+ useGradient = true;
+ } else if (filter_id != TightDecoder.TightFilterCopy) {
+ throw new Exception("Incorrect tight filter id: " + filter_id);
+ }
+ }
+ if (numColors == 0 && bytesPerPixel == 4)
+ rowSize *= 3;
+
+ // Read, optionally uncompress and decode data.
+ int dataSize = h * rowSize;
+ if (dataSize < TightDecoder.TightMinToCompress) {
+ // Data size is small - not compressed with zlib.
+ if (numColors != 0) {
+ // Indexed colors.
+ byte[] indexedData = new byte[dataSize];
+ rfbis.readFully(indexedData);
+ if (dos != null) {
+ dos.write(indexedData);
+ }
+ if (numColors == 2) {
+ // Two colors.
+ if (bytesPerPixel == 1) {
+ decodeMonoData(x, y, w, h, indexedData, palette8);
+ } else {
+ decodeMonoData(x, y, w, h, indexedData, palette24);
+ }
+ } else {
+ // 3..255 colors (assuming bytesPixel == 4).
+ int i = 0;
+ for (int dy = y; dy < y + h; dy++) {
+ for (int dx = x; dx < x + w; dx++) {
+ pixels24[dy * framebufferWidth + dx] =
+ palette24[indexedData[i++] & 0xFF];
+ }
+ }
+ }
+ } else if (useGradient) {
+ // "Gradient"-processed data
+ byte[] buf = new byte[w * h * 3];
+ rfbis.readFully(buf);
+ if (dos != null) {
+ dos.write(buf);
+ }
+ decodeGradientData(x, y, w, h, buf);
+ } else {
+ // Raw truecolor data.
+ if (bytesPerPixel == 1) {
+ for (int dy = y; dy < y + h; dy++) {
+ rfbis.readFully(pixels8, dy * framebufferWidth + x, w);
+ if (dos != null) {
+ dos.write(pixels8, dy * framebufferWidth + x, w);
+ }
+ }
+ } else {
+ byte[] buf = new byte[w * 3];
+ int i, offset;
+ for (int dy = y; dy < y + h; dy++) {
+ rfbis.readFully(buf);
+ if (dos != null) {
+ dos.write(buf);
+ }
+ offset = dy * framebufferWidth + x;
+ for (i = 0; i < w; i++) {
+ pixels24[offset + i] =
+ (buf[i * 3] & 0xFF) << 16 |
+ (buf[i * 3 + 1] & 0xFF) << 8 |
+ (buf[i * 3 + 2] & 0xFF);
+ }
+ }
+ }
+ }
+ } else {
+ // Data was compressed with zlib.
+ int zlibDataLen = rfbis.readCompactLen();
+ byte[] zlibData = new byte[zlibDataLen];
+ rfbis.readFully(zlibData);
+ int stream_id = comp_ctl & 0x03;
+ if (tightInflaters[stream_id] == null) {
+ tightInflaters[stream_id] = new Inflater();
+ }
+ Inflater myInflater = tightInflaters[stream_id];
+ myInflater.setInput(zlibData);
+ byte[] buf = new byte[dataSize];
+ myInflater.inflate(buf);
+ if (dos != null) {
+ recordCompressedData(buf);
+ }
+
+ if (numColors != 0) {
+ // Indexed colors.
+ if (numColors == 2) {
+ // Two colors.
+ if (bytesPerPixel == 1) {
+ decodeMonoData(x, y, w, h, buf, palette8);
+ } else {
+ decodeMonoData(x, y, w, h, buf, palette24);
+ }
+ } else {
+ // More than two colors (assuming bytesPixel == 4).
+ int i = 0;
+ for (int dy = y; dy < y + h; dy++) {
+ for (int dx = x; dx < x + w; dx++) {
+ pixels24[dy * framebufferWidth + dx] =
+ palette24[buf[i++] & 0xFF];
+ }
+ }
+ }
+ } else if (useGradient) {
+ // Compressed "Gradient"-filtered data (assuming bytesPixel == 4).
+ decodeGradientData(x, y, w, h, buf);
+ } else {
+ // Compressed truecolor data.
+ if (bytesPerPixel == 1) {
+ int destOffset = y * framebufferWidth + x;
+ for (int dy = 0; dy < h; dy++) {
+ System.arraycopy(buf, dy * w, pixels8, destOffset, w);
+ destOffset += framebufferWidth;
+ }
+ } else {
+ int srcOffset = 0;
+ int destOffset, i;
+ for (int dy = 0; dy < h; dy++) {
+ myInflater.inflate(buf);
+ destOffset = (y + dy) * framebufferWidth + x;
+ for (i = 0; i < w; i++) {
+ RawDecoder.pixels24[destOffset + i] =
+ (buf[srcOffset] & 0xFF) << 16 |
+ (buf[srcOffset + 1] & 0xFF) << 8 |
+ (buf[srcOffset + 2] & 0xFF);
+ srcOffset += 3;
+ }
+ }
+ }
+ }
+ }
+ handleUpdatedPixels(x, y, w, h);
+ }
+
+ //
+ // Decode 1bpp-encoded bi-color rectangle (8-bit and 24-bit versions).
+ //
+
+ private void decodeMonoData(int x, int y, int w, int h, byte[] src, byte[] palette) {
+
+ int dx, dy, n;
+ int i = y * framebufferWidth + x;
+ int rowBytes = (w + 7) / 8;
+ byte b;
+
+ for (dy = 0; dy < h; dy++) {
+ for (dx = 0; dx < w / 8; dx++) {
+ b = src[dy*rowBytes+dx];
+ for (n = 7; n >= 0; n--)
+ pixels8[i++] = palette[b >> n & 1];
+ }
+ for (n = 7; n >= 8 - w % 8; n--) {
+ pixels8[i++] = palette[src[dy*rowBytes+dx] >> n & 1];
+ }
+ i += (framebufferWidth - w);
+ }
+ }
+
+ private void decodeMonoData(int x, int y, int w, int h, byte[] src, int[] palette) {
+
+ int dx, dy, n;
+ int i = y * framebufferWidth + x;
+ int rowBytes = (w + 7) / 8;
+ byte b;
+
+ for (dy = 0; dy < h; dy++) {
+ for (dx = 0; dx < w / 8; dx++) {
+ b = src[dy*rowBytes+dx];
+ for (n = 7; n >= 0; n--)
+ pixels24[i++] = palette[b >> n & 1];
+ }
+ for (n = 7; n >= 8 - w % 8; n--) {
+ pixels24[i++] = palette[src[dy*rowBytes+dx] >> n & 1];
+ }
+ i += (framebufferWidth - w);
+ }
+ }
+
+ //
+ // Decode data processed with the "Gradient" filter.
+ //
+
+ private void decodeGradientData (int x, int y, int w, int h, byte[] buf) {
+
+ int dx, dy, c;
+ byte[] prevRow = new byte[w * 3];
+ byte[] thisRow = new byte[w * 3];
+ byte[] pix = new byte[3];
+ int[] est = new int[3];
+
+ int offset = y * framebufferWidth + x;
+
+ for (dy = 0; dy < h; dy++) {
+
+ /* First pixel in a row */
+ for (c = 0; c < 3; c++) {
+ pix[c] = (byte)(prevRow[c] + buf[dy * w * 3 + c]);
+ thisRow[c] = pix[c];
+ }
+ pixels24[offset++] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
+
+ /* Remaining pixels of a row */
+ for (dx = 1; dx < w; dx++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = ((prevRow[dx * 3 + c] & 0xFF) + (pix[c] & 0xFF) -
+ (prevRow[(dx-1) * 3 + c] & 0xFF));
+ if (est[c] > 0xFF) {
+ est[c] = 0xFF;
+ } else if (est[c] < 0x00) {
+ est[c] = 0x00;
+ }
+ pix[c] = (byte)(est[c] + buf[(dy * w + dx) * 3 + c]);
+ thisRow[dx * 3 + c] = pix[c];
+ }
+ pixels24[offset++] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
+ }
+
+ System.arraycopy(thisRow, 0, prevRow, 0, w * 3);
+ offset += (framebufferWidth - w);
+ }
+ }
+
+ //
+ // Override the ImageObserver interface method to handle drawing of
+ // JPEG-encoded data.
+ //
+
+ public boolean imageUpdate(Image img, int infoflags,
+ int x, int y, int width, int height) {
+ if ((infoflags & (ALLBITS | ABORT)) == 0) {
+ return true; // We need more image data.
+ } else {
+ // If the whole image is available, draw it now.
+ if ((infoflags & ALLBITS) != 0) {
+ if (jpegRect != null) {
+ synchronized(jpegRect) {
+ graphics.drawImage(img, jpegRect.x, jpegRect.y, null);
+ repainatableControl.scheduleRepaint(jpegRect.x, jpegRect.y,
+ jpegRect.width, jpegRect.height);
+ jpegRect.notify();
+ }
+ }
+ }
+ return false; // All image data was processed.
+ }
+ }
+
+ //
+ // Write an integer in compact representation (1..3 bytes) into the
+ // recorded session file.
+ //
+
+ void recordCompactLen(int len) throws IOException {
+ byte[] buf = new byte[3];
+ int bytes = 0;
+ buf[bytes++] = (byte)(len & 0x7F);
+ if (len > 0x7F) {
+ buf[bytes-1] |= 0x80;
+ buf[bytes++] = (byte)(len >> 7 & 0x7F);
+ if (len > 0x3FFF) {
+ buf[bytes-1] |= 0x80;
+ buf[bytes++] = (byte)(len >> 14 & 0xFF);
+ }
+ }
+ if (dos != null) dos.write(buf, 0, bytes);
+ }
+
+ //
+ // Compress and write the data into the recorded session file.
+ //
+
+ void recordCompressedData(byte[] data, int off, int len) throws IOException {
+ Deflater deflater = new Deflater();
+ deflater.setInput(data, off, len);
+ int bufSize = len + len / 100 + 12;
+ byte[] buf = new byte[bufSize];
+ deflater.finish();
+ int compressedSize = deflater.deflate(buf);
+ recordCompactLen(compressedSize);
+ if (dos != null) dos.write(buf, 0, compressedSize);
+ }
+
+ void recordCompressedData(byte[] data) throws IOException {
+ recordCompressedData(data, 0, data.length);
+ }
+
+ //
+ // Private members
+ //
+
+ private Inflater[] tightInflaters;
+ // Since JPEG images are loaded asynchronously, we have to remember
+ // their position in the framebuffer. Also, this jpegRect object is
+ // used for synchronization between the rfbThread and a JVM's thread
+ // which decodes and loads JPEG images.
+ private Rectangle jpegRect;
+ private Repaintable repainatableControl = null;
+ // Jpeg decoding statistics
+ private long statNumRectsTightJPEG = 0;
+ // Tight decoding statistics
+ private long statNumRectsTight = 0;
+}
--- /dev/null
+package com.tightvnc.decoder;
+
+import com.tightvnc.vncviewer.InStream;
+import com.tightvnc.vncviewer.RfbInputStream;
+import com.tightvnc.vncviewer.ZlibInStream;
+import java.awt.Graphics;
+import com.tightvnc.vncviewer.MemInStream;
+import java.awt.Color;
+import java.awt.Toolkit;
+import java.awt.image.MemoryImageSource;
+import java.io.IOException;
+
+//
+// Class that used for decoding ZRLE encoded data.
+//
+
+public class ZRLEDecoder extends RawDecoder {
+
+ final static int EncodingZRLE = 16;
+
+ public ZRLEDecoder(Graphics g, RfbInputStream is) {
+ super(g, is);
+ }
+
+ public ZRLEDecoder(Graphics g, RfbInputStream is, int frameBufferW,
+ int frameBufferH) {
+ super(g, is, frameBufferW, frameBufferH);
+ }
+
+ //
+ // Handle a ZRLE-encoded rectangle.
+ //
+ // FIXME: Currently, session recording is not fully supported for ZRLE.
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
+
+ //
+ // Write encoding ID to record output stream
+ //
+
+ if (dos != null) {
+ dos.writeInt(ZRLEDecoder.EncodingZRLE);
+ }
+
+ if (zrleInStream == null)
+ zrleInStream = new ZlibInStream();
+
+ int nBytes = rfbis.readU32();
+ if (nBytes > 64 * 1024 * 1024)
+ throw new Exception("ZRLE decoder: illegal compressed data size");
+
+ if (zrleBuf == null || zrleBufLen < nBytes) {
+ zrleBufLen = nBytes + 4096;
+ zrleBuf = new byte[zrleBufLen];
+ }
+
+ // FIXME: Do not wait for all the data before decompression.
+ rfbis.readFully(zrleBuf, 0, nBytes);
+
+ //
+ // Override handleRect method to decode RRE encoded data insted of
+ // raw pixel data.
+ //
+
+ if (dos != null) {
+ if (!zrleRecWarningShown) {
+ System.out.println("Warning: ZRLE session can be recorded" +
+ " only from the beginning");
+ System.out.println("Warning: Recorded file may be corrupted");
+ zrleRecWarningShown = true;
+ }
+ }
+
+ zrleInStream.setUnderlying(new MemInStream(zrleBuf, 0, nBytes), nBytes);
+
+ for (int ty = y; ty < y+h; ty += 64) {
+
+ int th = Math.min(y+h-ty, 64);
+
+ for (int tx = x; tx < x+w; tx += 64) {
+
+ int tw = Math.min(x+w-tx, 64);
+
+ int mode = zrleInStream.readU8();
+ boolean rle = (mode & 128) != 0;
+ int palSize = mode & 127;
+ int[] palette = new int[128];
+
+ readZrlePalette(palette, palSize);
+
+ if (palSize == 1) {
+ int pix = palette[0];
+ Color c = (bytesPerPixel == 1) ?
+ getColor256()[pix] : new Color(0xFF000000 | pix);
+ graphics.setColor(c);
+ graphics.fillRect(tx, ty, tw, th);
+ continue;
+ }
+
+ if (!rle) {
+ if (palSize == 0) {
+ readZrleRawPixels(tw, th);
+ } else {
+ readZrlePackedPixels(tw, th, palette, palSize);
+ }
+ } else {
+ if (palSize == 0) {
+ readZrlePlainRLEPixels(tw, th);
+ } else {
+ readZrlePackedRLEPixels(tw, th, palette);
+ }
+ }
+ handleUpdatedZrleTile(tx, ty, tw, th);
+ }
+ }
+ zrleInStream.reset();
+ }
+
+ //
+ // Override update() method cause we have own data that
+ // must be updated when framebuffer is resized or BPP is changed
+ //
+
+ public void update() {
+ // Images with raw pixels should be re-allocated on every change
+ // of geometry or pixel format.
+ int fbWidth = framebufferWidth;
+ int fbHeight = framebufferHeight;
+
+ if (bytesPerPixel == 1) {
+ RawDecoder.pixels24 = null;
+ RawDecoder.pixels8 = new byte[fbWidth * fbHeight];
+ RawDecoder.pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(), pixels8, 0, fbWidth);
+ zrleTilePixels24 = null;
+ zrleTilePixels8 = new byte[64 * 64];
+ } else {
+ RawDecoder.pixels8 = null;
+ RawDecoder.pixels24 = new int[fbWidth * fbHeight];
+ RawDecoder.pixelsSource =
+ new MemoryImageSource(fbWidth, fbHeight, getColorModel24(), pixels24, 0, fbWidth);
+ zrleTilePixels8 = null;
+ zrleTilePixels24 = new int[64 * 64];
+ }
+ RawDecoder.pixelsSource.setAnimated(true);
+ RawDecoder.rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
+ }
+
+ //
+ // Copy pixels from zrleTilePixels8 or zrleTilePixels24, then update.
+ //
+
+ private void handleUpdatedZrleTile(int x, int y, int w, int h) {
+ Object src, dst;
+ if (bytesPerPixel == 1) {
+ src = zrleTilePixels8; dst = pixels8;
+ } else {
+ src = zrleTilePixels24; dst = pixels24;
+ }
+ int offsetSrc = 0;
+ int offsetDst = (y * framebufferWidth + x);
+ for (int j = 0; j < h; j++) {
+ System.arraycopy(src, offsetSrc, dst, offsetDst, w);
+ offsetSrc += w;
+ offsetDst += framebufferWidth;
+ }
+ handleUpdatedPixels(x, y, w, h);
+ }
+
+ //
+ // Private methods for reading ZRLE data
+ //
+
+ private int readPixel(InStream is) throws Exception {
+ int pix;
+ if (bytesPerPixel == 1) {
+ pix = is.readU8();
+ } else {
+ int p1 = is.readU8();
+ int p2 = is.readU8();
+ int p3 = is.readU8();
+ pix = (p3 & 0xFF) << 16 | (p2 & 0xFF) << 8 | (p1 & 0xFF);
+ }
+ return pix;
+ }
+
+ private void readPixels(InStream is, int[] dst, int count) throws Exception {
+ if (bytesPerPixel == 1) {
+ byte[] buf = new byte[count];
+ is.readBytes(buf, 0, count);
+ for (int i = 0; i < count; i++) {
+ dst[i] = (int)buf[i] & 0xFF;
+ }
+ } else {
+ byte[] buf = new byte[count * 3];
+ is.readBytes(buf, 0, count * 3);
+ for (int i = 0; i < count; i++) {
+ dst[i] = ((buf[i*3+2] & 0xFF) << 16 |
+ (buf[i*3+1] & 0xFF) << 8 |
+ (buf[i*3] & 0xFF));
+ }
+ }
+ }
+
+ private void readZrlePalette(int[] palette, int palSize) throws Exception {
+ readPixels(zrleInStream, palette, palSize);
+ }
+
+ private void readZrleRawPixels(int tw, int th) throws Exception {
+ if (bytesPerPixel == 1) {
+ zrleInStream.readBytes(zrleTilePixels8, 0, tw * th);
+ } else {
+ readPixels(zrleInStream, zrleTilePixels24, tw * th); ///
+ }
+ }
+
+ private void readZrlePackedPixels(int tw, int th, int[] palette, int palSize)
+ throws Exception {
+
+ int bppp = ((palSize > 16) ? 8 :
+ ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
+ int ptr = 0;
+
+ for (int i = 0; i < th; i++) {
+ int eol = ptr + tw;
+ int b = 0;
+ int nbits = 0;
+
+ while (ptr < eol) {
+ if (nbits == 0) {
+ b = zrleInStream.readU8();
+ nbits = 8;
+ }
+ nbits -= bppp;
+ int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
+ if (bytesPerPixel == 1) {
+ zrleTilePixels8[ptr++] = (byte)palette[index];
+ } else {
+ zrleTilePixels24[ptr++] = palette[index];
+ }
+ }
+ }
+ }
+
+ private void readZrlePlainRLEPixels(int tw, int th) throws Exception {
+ int ptr = 0;
+ int end = ptr + tw * th;
+ while (ptr < end) {
+ int pix = readPixel(zrleInStream);
+ int len = 1;
+ int b;
+ do {
+ b = zrleInStream.readU8();
+ len += b;
+ } while (b == 255);
+
+ if (!(len <= end - ptr))
+ throw new Exception("ZRLE decoder: assertion failed" +
+ " (len <= end-ptr)");
+
+ if (bytesPerPixel == 1) {
+ while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
+ } else {
+ while (len-- > 0) zrleTilePixels24[ptr++] = pix;
+ }
+ }
+ }
+
+ private void readZrlePackedRLEPixels(int tw, int th, int[] palette)
+ throws Exception {
+
+ int ptr = 0;
+ int end = ptr + tw * th;
+ while (ptr < end) {
+ int index = zrleInStream.readU8();
+ int len = 1;
+ if ((index & 128) != 0) {
+ int b;
+ do {
+ b = zrleInStream.readU8();
+ len += b;
+ } while (b == 255);
+
+ if (!(len <= end - ptr))
+ throw new Exception("ZRLE decoder: assertion failed" +
+ " (len <= end - ptr)");
+ }
+
+ index &= 127;
+ int pix = palette[index];
+
+ if (bytesPerPixel == 1) {
+ while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
+ } else {
+ while (len-- > 0) zrleTilePixels24[ptr++] = pix;
+ }
+ }
+ }
+
+ //
+ // ZRLE encoder's data.
+ //
+
+ private byte[] zrleBuf;
+ private int zrleBufLen = 0;
+ private byte[] zrleTilePixels8;
+ private int[] zrleTilePixels24;
+ private ZlibInStream zrleInStream;
+ private boolean zrleRecWarningShown = false;
+}
--- /dev/null
+package com.tightvnc.decoder;
+
+import com.tightvnc.vncviewer.RfbInputStream;
+import java.awt.Graphics;
+import java.io.IOException;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+//
+// Class that used for decoding ZLib encoded data.
+//
+
+public class ZlibDecoder extends RawDecoder {
+
+ final static int EncodingZlib = 6;
+
+ public ZlibDecoder(Graphics g, RfbInputStream is) {
+ super(g, is);
+ }
+
+ public ZlibDecoder(Graphics g, RfbInputStream is, int frameBufferW,
+ int frameBufferH) {
+ super(g, is, frameBufferW, frameBufferH);
+ }
+
+ //
+ // Override handleRect method to decode ZLib encoded data insted of
+ // raw pixel data.
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws IOException {
+
+ //
+ // Write encoding ID to record output stream.
+ // Remark: we forced changed encoding from zlib to raw
+ // cause at this moment we cannot save data in zlib encoding.
+ //
+
+ if (dos != null) {
+ dos.writeInt(RawDecoder.EncodingRaw);
+ }
+
+ int nBytes = rfbis.readU32();
+
+ if (zlibBuf == null || zlibBufLen < nBytes) {
+ zlibBufLen = nBytes * 2;
+ zlibBuf = new byte[zlibBufLen];
+ }
+
+ rfbis.readFully(zlibBuf, 0, nBytes);
+
+ if (zlibInflater == null) {
+ zlibInflater = new Inflater();
+ }
+ zlibInflater.setInput(zlibBuf, 0, nBytes);
+
+ try {
+ if (bytesPerPixel == 1) {
+ for (int dy = y; dy < y + h; dy++) {
+ zlibInflater.inflate(pixels8, dy * framebufferWidth + x, w);
+
+ //
+ // Save decoded raw data to data output stream
+ //
+
+ if (dos != null)
+ dos.write(pixels8, dy * framebufferWidth + x, w);
+ }
+ } else {
+ byte[] buf = new byte[w * 4];
+ int i, offset;
+ for (int dy = y; dy < y + h; dy++) {
+ zlibInflater.inflate(buf);
+ offset = dy * framebufferWidth + x;
+ for (i = 0; i < w; i++) {
+ RawDecoder.pixels24[offset + i] =
+ (buf[i * 4 + 2] & 0xFF) << 16 |
+ (buf[i * 4 + 1] & 0xFF) << 8 |
+ (buf[i * 4] & 0xFF);
+ }
+
+ //
+ // Save decoded raw data to data output stream
+ //
+
+ if (dos != null)
+ dos.write(buf);
+ }
+ }
+ } catch (DataFormatException ex) {
+ ex.printStackTrace();
+ }
+ handleUpdatedPixels(x, y, w, h);
+ }
+
+ //
+ // Zlib encoder's data.
+ //
+
+ protected byte[] zlibBuf;
+ protected int zlibBufLen = 0;
+ protected Inflater zlibInflater;
+}
--- /dev/null
+package com.tightvnc.decoder.common;
+
+public interface Repaintable {
+
+ public void scheduleRepaint(int x, int y, int w, int h);
+
+}
--- /dev/null
+//
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+// Copyright (C) 2002-2006 Constantin Kaplinsky. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+
+//
+// The panel which implements the user authentication scheme
+//
+
+class AuthPanel extends Panel implements ActionListener {
+
+ TextField passwordField;
+ Button okButton;
+
+ //
+ // Constructor.
+ //
+
+ public AuthPanel(VncViewer viewer)
+ {
+ Label titleLabel = new Label("VNC Authentication", Label.CENTER);
+ titleLabel.setFont(new Font("Helvetica", Font.BOLD, 18));
+
+ Label promptLabel = new Label("Password:", Label.CENTER);
+
+ passwordField = new TextField(10);
+ passwordField.setForeground(Color.black);
+ passwordField.setBackground(Color.white);
+ passwordField.setEchoChar('*');
+
+ okButton = new Button("OK");
+
+ GridBagLayout gridbag = new GridBagLayout();
+ GridBagConstraints gbc = new GridBagConstraints();
+
+ setLayout(gridbag);
+
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.insets = new Insets(0,0,20,0);
+ gridbag.setConstraints(titleLabel,gbc);
+ add(titleLabel);
+
+ gbc.fill = GridBagConstraints.NONE;
+ gbc.gridwidth = 1;
+ gbc.insets = new Insets(0,0,0,0);
+ gridbag.setConstraints(promptLabel,gbc);
+ add(promptLabel);
+
+ gridbag.setConstraints(passwordField,gbc);
+ add(passwordField);
+ passwordField.addActionListener(this);
+
+ // gbc.ipady = 10;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.fill = GridBagConstraints.BOTH;
+ gbc.insets = new Insets(0,20,0,0);
+ gbc.ipadx = 30;
+ gridbag.setConstraints(okButton,gbc);
+ add(okButton);
+ okButton.addActionListener(this);
+ }
+
+ //
+ // Move keyboard focus to the default object, that is, the password
+ // text field.
+ //
+
+ public void moveFocusToDefaultField()
+ {
+ passwordField.requestFocus();
+ }
+
+ //
+ // This method is called when a button is pressed or return is
+ // pressed in the password text field.
+ //
+
+ public synchronized void actionPerformed(ActionEvent evt)
+ {
+ if (evt.getSource() == passwordField || evt.getSource() == okButton) {
+ passwordField.setEnabled(false);
+ notify();
+ }
+ }
+
+ //
+ // Wait for user entering a password, and return it as String.
+ //
+
+ public synchronized String getPassword() throws Exception
+ {
+ try {
+ wait();
+ } catch (InterruptedException e) { }
+ return passwordField.getText();
+ }
+
+}
--- /dev/null
+//
+// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// ButtonPanel class implements panel with four buttons in the
+// VNCViewer desktop window.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+
+class ButtonPanel extends Panel implements ActionListener {
+
+ VncViewer viewer;
+ Button disconnectButton;
+ Button optionsButton;
+ Button recordButton;
+ Button clipboardButton;
+ Button ctrlAltDelButton;
+ Button refreshButton;
+ Button selectButton;
+ Button videoFreezeButton;
+
+ final String enableVideoFreezeLabel = "Ignore Video";
+ final String disableVideoFreezeLabel = "Enable Video";
+ final String selectEnterLabel = "Select Video Area";
+ final String selectLeaveLabel = "Hide Selection";
+
+ ButtonPanel(VncViewer v) {
+ viewer = v;
+
+ setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
+ disconnectButton = new Button("Disconnect");
+ disconnectButton.setEnabled(false);
+ add(disconnectButton);
+ disconnectButton.addActionListener(this);
+ optionsButton = new Button("Options");
+ add(optionsButton);
+ optionsButton.addActionListener(this);
+ clipboardButton = new Button("Clipboard");
+ clipboardButton.setEnabled(false);
+ add(clipboardButton);
+ clipboardButton.addActionListener(this);
+ if (viewer.rec != null) {
+ recordButton = new Button("Record");
+ add(recordButton);
+ recordButton.addActionListener(this);
+ }
+ ctrlAltDelButton = new Button("Send Ctrl-Alt-Del");
+ ctrlAltDelButton.setEnabled(false);
+ add(ctrlAltDelButton);
+ ctrlAltDelButton.addActionListener(this);
+ refreshButton = new Button("Refresh");
+ refreshButton.setEnabled(false);
+ add(refreshButton);
+ refreshButton.addActionListener(this);
+ }
+
+ /**
+ * Add video selection button to the ButtonPanel.
+ */
+ public void addSelectButton() {
+ selectButton = new Button(selectEnterLabel);
+ selectButton.setEnabled(false);
+ add(selectButton);
+ selectButton.addActionListener(this);
+ }
+
+ /**
+ * Add video ignore button to the ButtonPanel.
+ */
+ public void addVideoFreezeButton() {
+ videoFreezeButton = new Button(enableVideoFreezeLabel);
+ add(videoFreezeButton);
+ videoFreezeButton.addActionListener(this);
+ }
+
+ //
+ // Enable buttons on successful connection.
+ //
+
+ public void enableButtons() {
+ disconnectButton.setEnabled(true);
+ clipboardButton.setEnabled(true);
+ refreshButton.setEnabled(true);
+ if (selectButton != null) {
+ selectButton.setEnabled(true);
+ }
+ }
+
+ //
+ // Disable all buttons on disconnect.
+ //
+
+ public void disableButtonsOnDisconnect() {
+ remove(disconnectButton);
+ disconnectButton = new Button("Hide desktop");
+ disconnectButton.setEnabled(true);
+ add(disconnectButton, 0);
+ disconnectButton.addActionListener(this);
+
+ optionsButton.setEnabled(false);
+ clipboardButton.setEnabled(false);
+ ctrlAltDelButton.setEnabled(false);
+ refreshButton.setEnabled(false);
+ if (selectButton != null) {
+ selectButton.setEnabled(false);
+ }
+ }
+
+ //
+ // Enable/disable controls that should not be available in view-only
+ // mode.
+ //
+
+ public void enableRemoteAccessControls(boolean enable) {
+ ctrlAltDelButton.setEnabled(enable);
+ }
+
+ //
+ // Event processing.
+ //
+
+ public void actionPerformed(ActionEvent evt) {
+
+ viewer.moveFocusToDesktop();
+
+ if (evt.getSource() == disconnectButton) {
+ viewer.disconnect();
+
+ } else if (evt.getSource() == optionsButton) {
+ viewer.options.setVisible(!viewer.options.isVisible());
+
+ } else if (evt.getSource() == recordButton) {
+ viewer.rec.setVisible(!viewer.rec.isVisible());
+
+ } else if (evt.getSource() == clipboardButton) {
+ viewer.clipboard.setVisible(!viewer.clipboard.isVisible());
+ } else if (evt.getSource() == videoFreezeButton) {
+
+ //
+ // Send video freeze message to server and change caption of button
+ //
+
+ //
+ // TODO: Move this code to another place.
+ //
+
+ boolean sendOk = true;
+ boolean currentFreezeState =
+ videoFreezeButton.getLabel().equals(disableVideoFreezeLabel);
+ try {
+ viewer.rfb.trySendVideoFreeze(!currentFreezeState);
+ } catch (IOException ex) {
+ sendOk = false;
+ ex.printStackTrace();
+ }
+ if (sendOk) {
+ if (!currentFreezeState) {
+ videoFreezeButton.setLabel(disableVideoFreezeLabel);
+ } else {
+ videoFreezeButton.setLabel(enableVideoFreezeLabel);
+ }
+ }
+ } else if (evt.getSource() == ctrlAltDelButton) {
+ try {
+ final int modifiers = InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
+
+ KeyEvent ctrlAltDelEvent =
+ new KeyEvent(this, KeyEvent.KEY_PRESSED, 0, modifiers, 127);
+ viewer.rfb.writeKeyEvent(ctrlAltDelEvent);
+
+ ctrlAltDelEvent =
+ new KeyEvent(this, KeyEvent.KEY_RELEASED, 0, modifiers, 127);
+ viewer.rfb.writeKeyEvent(ctrlAltDelEvent);
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else if (evt.getSource() == refreshButton) {
+ try {
+ RfbProto rfb = viewer.rfb;
+ rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
+ rfb.framebufferHeight, false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else if (selectButton != null && evt.getSource() == selectButton) {
+ if (viewer.vc != null) {
+ boolean isSelecting = viewer.vc.isInSelectionMode();
+ if (!isSelecting) {
+ selectButton.setLabel(selectLeaveLabel);
+ viewer.vc.enableSelection(true);
+ } else {
+ selectButton.setLabel(selectEnterLabel);
+ viewer.vc.enableSelection(false);
+ }
+ }
+ }
+ }
+}
+
--- /dev/null
+//
+// Copyright (C) 2003 Constantin Kaplinsky. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// CapabilityInfo.java - A class to hold information about a
+// particular capability as used in the RFB protocol 3.130.
+//
+
+package com.tightvnc.vncviewer;
+
+class CapabilityInfo {
+
+ // Public methods
+
+ public CapabilityInfo(int code,
+ String vendorSignature,
+ String nameSignature,
+ String description) {
+ this.code = code;
+ this.vendorSignature = vendorSignature;
+ this.nameSignature = nameSignature;
+ this.description = description;
+ enabled = false;
+ }
+
+ public CapabilityInfo(int code,
+ byte[] vendorSignature,
+ byte[] nameSignature) {
+ this.code = code;
+ this.vendorSignature = new String(vendorSignature);
+ this.nameSignature = new String(nameSignature);
+ this.description = null;
+ enabled = false;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void enable() {
+ enabled = true;
+ }
+
+ public boolean equals(CapabilityInfo other) {
+ return (other != null && this.code == other.code &&
+ this.vendorSignature.equals(other.vendorSignature) &&
+ this.nameSignature.equals(other.nameSignature));
+ }
+
+ public boolean enableIfEquals(CapabilityInfo other) {
+ if (this.equals(other))
+ enable();
+
+ return isEnabled();
+ }
+
+ // Protected data
+
+ protected int code;
+ protected String vendorSignature;
+ protected String nameSignature;
+
+ protected String description;
+ protected boolean enabled;
+}
--- /dev/null
+//
+// Copyright (C) 2003 Constantin Kaplinsky. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// CapsContainer.java - A container of capabilities as used in the RFB
+// protocol 3.130
+//
+
+package com.tightvnc.vncviewer;
+
+import java.util.Vector;
+import java.util.Hashtable;
+
+class CapsContainer {
+
+ // Public methods
+
+ public CapsContainer() {
+ infoMap = new Hashtable(64, (float)0.25);
+ orderedList = new Vector(32, 8);
+ }
+
+ public void add(CapabilityInfo capinfo) {
+ Integer key = new Integer(capinfo.getCode());
+ infoMap.put(key, capinfo);
+ }
+
+ public void add(int code, String vendor, String name, String desc) {
+ Integer key = new Integer(code);
+ infoMap.put(key, new CapabilityInfo(code, vendor, name, desc));
+ }
+
+ public boolean isKnown(int code) {
+ return infoMap.containsKey(new Integer(code));
+ }
+
+ public CapabilityInfo getInfo(int code) {
+ return (CapabilityInfo)infoMap.get(new Integer(code));
+ }
+
+ public String getDescription(int code) {
+ CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(new Integer(code));
+ if (capinfo == null)
+ return null;
+
+ return capinfo.getDescription();
+ }
+
+ public boolean enable(CapabilityInfo other) {
+ Integer key = new Integer(other.getCode());
+ CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(key);
+ if (capinfo == null)
+ return false;
+
+ boolean enabled = capinfo.enableIfEquals(other);
+ if (enabled)
+ orderedList.addElement(key);
+
+ return enabled;
+ }
+
+ public boolean isEnabled(int code) {
+ CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(new Integer(code));
+ if (capinfo == null)
+ return false;
+
+ return capinfo.isEnabled();
+ }
+
+ public int numEnabled() {
+ return orderedList.size();
+ }
+
+ public int getByOrder(int idx) {
+ int code;
+ try {
+ code = ((Integer)orderedList.elementAt(idx)).intValue();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ code = 0;
+ }
+ return code;
+ }
+
+ // Protected data
+
+ protected Hashtable infoMap;
+ protected Vector orderedList;
+}
+
--- /dev/null
+//
+// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved.
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// Clipboard frame.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+
+class ClipboardFrame extends Frame
+ implements WindowListener, ActionListener {
+
+ TextArea textArea;
+ Button clearButton, closeButton;
+ String selection;
+ VncViewer viewer;
+
+ //
+ // Constructor.
+ //
+
+ ClipboardFrame(VncViewer v) {
+ super("TigerVNC Clipboard");
+
+ viewer = v;
+
+ GridBagLayout gridbag = new GridBagLayout();
+ setLayout(gridbag);
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.fill = GridBagConstraints.BOTH;
+ gbc.weighty = 1.0;
+
+ textArea = new TextArea(5, 40);
+ gridbag.setConstraints(textArea, gbc);
+ add(textArea);
+
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.weightx = 1.0;
+ gbc.weighty = 0.0;
+ gbc.gridwidth = 1;
+
+ clearButton = new Button("Clear");
+ gridbag.setConstraints(clearButton, gbc);
+ add(clearButton);
+ clearButton.addActionListener(this);
+
+ closeButton = new Button("Close");
+ gridbag.setConstraints(closeButton, gbc);
+ add(closeButton);
+ closeButton.addActionListener(this);
+
+ pack();
+
+ addWindowListener(this);
+ }
+
+
+ //
+ // Set the cut text from the RFB server.
+ //
+
+ void setCutText(String text) {
+ selection = text;
+ textArea.setText(text);
+ if (isVisible()) {
+ textArea.selectAll();
+ }
+ }
+
+
+ //
+ // When the focus leaves the window, see if we have new cut text and
+ // if so send it to the RFB server.
+ //
+
+ public void windowDeactivated (WindowEvent evt) {
+ if (selection != null && !selection.equals(textArea.getText())) {
+ selection = textArea.getText();
+ viewer.setCutText(selection);
+ }
+ }
+
+ //
+ // Close our window properly.
+ //
+
+ public void windowClosing(WindowEvent evt) {
+ setVisible(false);
+ }
+
+ //
+ // Ignore window events we're not interested in.
+ //
+
+ public void windowActivated(WindowEvent evt) {}
+ public void windowOpened(WindowEvent evt) {}
+ public void windowClosed(WindowEvent evt) {}
+ public void windowIconified(WindowEvent evt) {}
+ public void windowDeiconified(WindowEvent evt) {}
+
+
+ //
+ // Respond to button presses
+ //
+
+ public void actionPerformed(ActionEvent evt) {
+ if (evt.getSource() == clearButton) {
+ textArea.setText("");
+ } else if (evt.getSource() == closeButton) {
+ setVisible(false);
+ }
+ }
+}
--- /dev/null
+//
+// This DES class has been extracted from package Acme.Crypto for use in VNC.
+// The bytebit[] array has been reversed so that the most significant bit
+// in each byte of the key is ignored, not the least significant. Also the
+// unnecessary odd parity code has been removed.
+//
+// These changes are:
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//
+
+// DesCipher - the DES encryption method
+//
+// The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is:
+//
+// Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
+//
+// Permission to use, copy, modify, and distribute this software
+// and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
+// without fee is hereby granted, provided that this copyright notice is kept
+// intact.
+//
+// WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
+// OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
+// FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+// DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
+//
+// THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
+// CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
+// PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
+// NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
+// SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+// SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
+// PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
+// SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
+// HIGH RISK ACTIVITIES.
+//
+//
+// The rest is:
+//
+// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// Visit the ACME Labs Java page for up-to-date versions of this and other
+// fine Java utilities: http://www.acme.com/java/
+
+
+package com.tightvnc.vncviewer;
+
+import java.io.*;
+
+/// The DES encryption method.
+// <P>
+// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped
+// in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream,
+// it does around 7000 bytes/second.
+// <P>
+// Most of this code is by Dave Zimmerman <dzimm@widget.com>, and is
+// Copyright (c) 1996 Widget Workshop, Inc. See the source file for details.
+// <P>
+// <A HREF="/resources/classes/Acme/Crypto/DesCipher.java">Fetch the software.</A><BR>
+// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
+// <P>
+// @see Des3Cipher
+// @see EncryptedOutputStream
+// @see EncryptedInputStream
+
+public class DesCipher
+ {
+
+ // Constructor, byte-array key.
+ public DesCipher( byte[] key )
+ {
+ setKey( key );
+ }
+
+ // Key routines.
+
+ private int[] encryptKeys = new int[32];
+ private int[] decryptKeys = new int[32];
+
+ /// Set the key.
+ public void setKey( byte[] key )
+ {
+ deskey( key, true, encryptKeys );
+ deskey( key, false, decryptKeys );
+ }
+
+ // Turn an 8-byte key into internal keys.
+ private void deskey( byte[] keyBlock, boolean encrypting, int[] KnL )
+ {
+ int i, j, l, m, n;
+ int[] pc1m = new int[56];
+ int[] pcr = new int[56];
+ int[] kn = new int[32];
+
+ for ( j = 0; j < 56; ++j )
+ {
+ l = pc1[j];
+ m = l & 07;
+ pc1m[j] = ( (keyBlock[l >>> 3] & bytebit[m]) != 0 )? 1: 0;
+ }
+
+ for ( i = 0; i < 16; ++i )
+ {
+ if ( encrypting )
+ m = i << 1;
+ else
+ m = (15-i) << 1;
+ n = m+1;
+ kn[m] = kn[n] = 0;
+ for ( j = 0; j < 28; ++j )
+ {
+ l = j+totrot[i];
+ if ( l < 28 )
+ pcr[j] = pc1m[l];
+ else
+ pcr[j] = pc1m[l-28];
+ }
+ for ( j=28; j < 56; ++j )
+ {
+ l = j+totrot[i];
+ if ( l < 56 )
+ pcr[j] = pc1m[l];
+ else
+ pcr[j] = pc1m[l-28];
+ }
+ for ( j = 0; j < 24; ++j )
+ {
+ if ( pcr[pc2[j]] != 0 )
+ kn[m] |= bigbyte[j];
+ if ( pcr[pc2[j+24]] != 0 )
+ kn[n] |= bigbyte[j];
+ }
+ }
+ cookey( kn, KnL );
+ }
+
+ private void cookey( int[] raw, int KnL[] )
+ {
+ int raw0, raw1;
+ int rawi, KnLi;
+ int i;
+
+ for ( i = 0, rawi = 0, KnLi = 0; i < 16; ++i )
+ {
+ raw0 = raw[rawi++];
+ raw1 = raw[rawi++];
+ KnL[KnLi] = (raw0 & 0x00fc0000) << 6;
+ KnL[KnLi] |= (raw0 & 0x00000fc0) << 10;
+ KnL[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
+ KnL[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
+ ++KnLi;
+ KnL[KnLi] = (raw0 & 0x0003f000) << 12;
+ KnL[KnLi] |= (raw0 & 0x0000003f) << 16;
+ KnL[KnLi] |= (raw1 & 0x0003f000) >>> 4;
+ KnL[KnLi] |= (raw1 & 0x0000003f);
+ ++KnLi;
+ }
+ }
+
+
+ // Block encryption routines.
+
+ private int[] tempInts = new int[2];
+
+ /// Encrypt a block of eight bytes.
+ public void encrypt( byte[] clearText, int clearOff, byte[] cipherText, int cipherOff )
+ {
+ squashBytesToInts( clearText, clearOff, tempInts, 0, 2 );
+ des( tempInts, tempInts, encryptKeys );
+ spreadIntsToBytes( tempInts, 0, cipherText, cipherOff, 2 );
+ }
+
+ /// Decrypt a block of eight bytes.
+ public void decrypt( byte[] cipherText, int cipherOff, byte[] clearText, int clearOff )
+ {
+ squashBytesToInts( cipherText, cipherOff, tempInts, 0, 2 );
+ des( tempInts, tempInts, decryptKeys );
+ spreadIntsToBytes( tempInts, 0, clearText, clearOff, 2 );
+ }
+
+ // The DES function.
+ private void des( int[] inInts, int[] outInts, int[] keys )
+ {
+ int fval, work, right, leftt;
+ int round;
+ int keysi = 0;
+
+ leftt = inInts[0];
+ right = inInts[1];
+
+ work = ((leftt >>> 4) ^ right) & 0x0f0f0f0f;
+ right ^= work;
+ leftt ^= (work << 4);
+
+ work = ((leftt >>> 16) ^ right) & 0x0000ffff;
+ right ^= work;
+ leftt ^= (work << 16);
+
+ work = ((right >>> 2) ^ leftt) & 0x33333333;
+ leftt ^= work;
+ right ^= (work << 2);
+
+ work = ((right >>> 8) ^ leftt) & 0x00ff00ff;
+ leftt ^= work;
+ right ^= (work << 8);
+ right = (right << 1) | ((right >>> 31) & 1);
+
+ work = (leftt ^ right) & 0xaaaaaaaa;
+ leftt ^= work;
+ right ^= work;
+ leftt = (leftt << 1) | ((leftt >>> 31) & 1);
+
+ for ( round = 0; round < 8; ++round )
+ {
+ work = (right << 28) | (right >>> 4);
+ work ^= keys[keysi++];
+ fval = SP7[ work & 0x0000003f ];
+ fval |= SP5[(work >>> 8) & 0x0000003f ];
+ fval |= SP3[(work >>> 16) & 0x0000003f ];
+ fval |= SP1[(work >>> 24) & 0x0000003f ];
+ work = right ^ keys[keysi++];
+ fval |= SP8[ work & 0x0000003f ];
+ fval |= SP6[(work >>> 8) & 0x0000003f ];
+ fval |= SP4[(work >>> 16) & 0x0000003f ];
+ fval |= SP2[(work >>> 24) & 0x0000003f ];
+ leftt ^= fval;
+ work = (leftt << 28) | (leftt >>> 4);
+ work ^= keys[keysi++];
+ fval = SP7[ work & 0x0000003f ];
+ fval |= SP5[(work >>> 8) & 0x0000003f ];
+ fval |= SP3[(work >>> 16) & 0x0000003f ];
+ fval |= SP1[(work >>> 24) & 0x0000003f ];
+ work = leftt ^ keys[keysi++];
+ fval |= SP8[ work & 0x0000003f ];
+ fval |= SP6[(work >>> 8) & 0x0000003f ];
+ fval |= SP4[(work >>> 16) & 0x0000003f ];
+ fval |= SP2[(work >>> 24) & 0x0000003f ];
+ right ^= fval;
+ }
+
+ right = (right << 31) | (right >>> 1);
+ work = (leftt ^ right) & 0xaaaaaaaa;
+ leftt ^= work;
+ right ^= work;
+ leftt = (leftt << 31) | (leftt >>> 1);
+ work = ((leftt >>> 8) ^ right) & 0x00ff00ff;
+ right ^= work;
+ leftt ^= (work << 8);
+ work = ((leftt >>> 2) ^ right) & 0x33333333;
+ right ^= work;
+ leftt ^= (work << 2);
+ work = ((right >>> 16) ^ leftt) & 0x0000ffff;
+ leftt ^= work;
+ right ^= (work << 16);
+ work = ((right >>> 4) ^ leftt) & 0x0f0f0f0f;
+ leftt ^= work;
+ right ^= (work << 4);
+ outInts[0] = right;
+ outInts[1] = leftt;
+ }
+
+
+ // Tables, permutations, S-boxes, etc.
+
+ private static byte[] bytebit = {
+ (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x08,
+ (byte)0x10, (byte)0x20, (byte)0x40, (byte)0x80
+ };
+ private static int[] bigbyte = {
+ 0x800000, 0x400000, 0x200000, 0x100000,
+ 0x080000, 0x040000, 0x020000, 0x010000,
+ 0x008000, 0x004000, 0x002000, 0x001000,
+ 0x000800, 0x000400, 0x000200, 0x000100,
+ 0x000080, 0x000040, 0x000020, 0x000010,
+ 0x000008, 0x000004, 0x000002, 0x000001
+ };
+ private static byte[] pc1 = {
+ (byte)56, (byte)48, (byte)40, (byte)32, (byte)24, (byte)16, (byte) 8,
+ (byte) 0, (byte)57, (byte)49, (byte)41, (byte)33, (byte)25, (byte)17,
+ (byte) 9, (byte) 1, (byte)58, (byte)50, (byte)42, (byte)34, (byte)26,
+ (byte)18, (byte)10, (byte) 2, (byte)59, (byte)51, (byte)43, (byte)35,
+ (byte)62, (byte)54, (byte)46, (byte)38, (byte)30, (byte)22, (byte)14,
+ (byte) 6, (byte)61, (byte)53, (byte)45, (byte)37, (byte)29, (byte)21,
+ (byte)13, (byte) 5, (byte)60, (byte)52, (byte)44, (byte)36, (byte)28,
+ (byte)20, (byte)12, (byte) 4, (byte)27, (byte)19, (byte)11, (byte)3
+ };
+ private static int[] totrot = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
+ };
+
+ private static byte[] pc2 = {
+ (byte)13, (byte)16, (byte)10, (byte)23, (byte) 0, (byte) 4,
+ (byte) 2, (byte)27, (byte)14, (byte) 5, (byte)20, (byte) 9,
+ (byte)22, (byte)18, (byte)11, (byte)3 , (byte)25, (byte) 7,
+ (byte)15, (byte) 6, (byte)26, (byte)19, (byte)12, (byte) 1,
+ (byte)40, (byte)51, (byte)30, (byte)36, (byte)46, (byte)54,
+ (byte)29, (byte)39, (byte)50, (byte)44, (byte)32, (byte)47,
+ (byte)43, (byte)48, (byte)38, (byte)55, (byte)33, (byte)52,
+ (byte)45, (byte)41, (byte)49, (byte)35, (byte)28, (byte)31,
+ };
+
+ private static int[] SP1 = {
+ 0x01010400, 0x00000000, 0x00010000, 0x01010404,
+ 0x01010004, 0x00010404, 0x00000004, 0x00010000,
+ 0x00000400, 0x01010400, 0x01010404, 0x00000400,
+ 0x01000404, 0x01010004, 0x01000000, 0x00000004,
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400,
+ 0x00010400, 0x01010000, 0x01010000, 0x01000404,
+ 0x00010004, 0x01000004, 0x01000004, 0x00010004,
+ 0x00000000, 0x00000404, 0x00010404, 0x01000000,
+ 0x00010000, 0x01010404, 0x00000004, 0x01010000,
+ 0x01010400, 0x01000000, 0x01000000, 0x00000400,
+ 0x01010004, 0x00010000, 0x00010400, 0x01000004,
+ 0x00000400, 0x00000004, 0x01000404, 0x00010404,
+ 0x01010404, 0x00010004, 0x01010000, 0x01000404,
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400,
+ 0x00000404, 0x01000400, 0x01000400, 0x00000000,
+ 0x00010004, 0x00010400, 0x00000000, 0x01010004
+ };
+ private static int[] SP2 = {
+ 0x80108020, 0x80008000, 0x00008000, 0x00108020,
+ 0x00100000, 0x00000020, 0x80100020, 0x80008020,
+ 0x80000020, 0x80108020, 0x80108000, 0x80000000,
+ 0x80008000, 0x00100000, 0x00000020, 0x80100020,
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000,
+ 0x80000000, 0x00008000, 0x00108020, 0x80100000,
+ 0x00100020, 0x80000020, 0x00000000, 0x00108000,
+ 0x00008020, 0x80108000, 0x80100000, 0x00008020,
+ 0x00000000, 0x00108020, 0x80100020, 0x00100000,
+ 0x80008020, 0x80100000, 0x80108000, 0x00008000,
+ 0x80100000, 0x80008000, 0x00000020, 0x80108020,
+ 0x00108020, 0x00000020, 0x00008000, 0x80000000,
+ 0x00008020, 0x80108000, 0x00100000, 0x80000020,
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020,
+ 0x00108000, 0x00000000, 0x80008000, 0x00008020,
+ 0x80000000, 0x80100020, 0x80108020, 0x00108000
+ };
+ private static int[] SP3 = {
+ 0x00000208, 0x08020200, 0x00000000, 0x08020008,
+ 0x08000200, 0x00000000, 0x00020208, 0x08000200,
+ 0x00020008, 0x08000008, 0x08000008, 0x00020000,
+ 0x08020208, 0x00020008, 0x08020000, 0x00000208,
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200,
+ 0x00020200, 0x08020000, 0x08020008, 0x00020208,
+ 0x08000208, 0x00020200, 0x00020000, 0x08000208,
+ 0x00000008, 0x08020208, 0x00000200, 0x08000000,
+ 0x08020200, 0x08000000, 0x00020008, 0x00000208,
+ 0x00020000, 0x08020200, 0x08000200, 0x00000000,
+ 0x00000200, 0x00020008, 0x08020208, 0x08000200,
+ 0x08000008, 0x00000200, 0x00000000, 0x08020008,
+ 0x08000208, 0x00020000, 0x08000000, 0x08020208,
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008,
+ 0x08020000, 0x08000208, 0x00000208, 0x08020000,
+ 0x00020208, 0x00000008, 0x08020008, 0x00020200
+ };
+ private static int[] SP4 = {
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802080, 0x00800081, 0x00800001, 0x00002001,
+ 0x00000000, 0x00802000, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00800080, 0x00800001,
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002001, 0x00002080,
+ 0x00800081, 0x00000001, 0x00002080, 0x00800080,
+ 0x00002000, 0x00802080, 0x00802081, 0x00000081,
+ 0x00800080, 0x00800001, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00000000, 0x00802000,
+ 0x00002080, 0x00800080, 0x00800081, 0x00000001,
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802081, 0x00000081, 0x00000001, 0x00002000,
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081,
+ 0x00002001, 0x00002080, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002000, 0x00802080
+ };
+ private static int[] SP5 = {
+ 0x00000100, 0x02080100, 0x02080000, 0x42000100,
+ 0x00080000, 0x00000100, 0x40000000, 0x02080000,
+ 0x40080100, 0x00080000, 0x02000100, 0x40080100,
+ 0x42000100, 0x42080000, 0x00080100, 0x40000000,
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000,
+ 0x40000100, 0x42080100, 0x42080100, 0x02000100,
+ 0x42080000, 0x40000100, 0x00000000, 0x42000000,
+ 0x02080100, 0x02000000, 0x42000000, 0x00080100,
+ 0x00080000, 0x42000100, 0x00000100, 0x02000000,
+ 0x40000000, 0x02080000, 0x42000100, 0x40080100,
+ 0x02000100, 0x40000000, 0x42080000, 0x02080100,
+ 0x40080100, 0x00000100, 0x02000000, 0x42080000,
+ 0x42080100, 0x00080100, 0x42000000, 0x42080100,
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000,
+ 0x00080100, 0x02000100, 0x40000100, 0x00080000,
+ 0x00000000, 0x40080000, 0x02080100, 0x40000100
+ };
+ private static int[] SP6 = {
+ 0x20000010, 0x20400000, 0x00004000, 0x20404010,
+ 0x20400000, 0x00000010, 0x20404010, 0x00400000,
+ 0x20004000, 0x00404010, 0x00400000, 0x20000010,
+ 0x00400010, 0x20004000, 0x20000000, 0x00004010,
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000,
+ 0x00404000, 0x20004010, 0x00000010, 0x20400010,
+ 0x20400010, 0x00000000, 0x00404010, 0x20404000,
+ 0x00004010, 0x00404000, 0x20404000, 0x20000000,
+ 0x20004000, 0x00000010, 0x20400010, 0x00404000,
+ 0x20404010, 0x00400000, 0x00004010, 0x20000010,
+ 0x00400000, 0x20004000, 0x20000000, 0x00004010,
+ 0x20000010, 0x20404010, 0x00404000, 0x20400000,
+ 0x00404010, 0x20404000, 0x00000000, 0x20400010,
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010,
+ 0x00004000, 0x00400010, 0x20004010, 0x00000000,
+ 0x20404000, 0x20000000, 0x00400010, 0x20004010
+ };
+ private static int[] SP7 = {
+ 0x00200000, 0x04200002, 0x04000802, 0x00000000,
+ 0x00000800, 0x04000802, 0x00200802, 0x04200800,
+ 0x04200802, 0x00200000, 0x00000000, 0x04000002,
+ 0x00000002, 0x04000000, 0x04200002, 0x00000802,
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800,
+ 0x04000002, 0x04200000, 0x04200800, 0x00200002,
+ 0x04200000, 0x00000800, 0x00000802, 0x04200802,
+ 0x00200800, 0x00000002, 0x04000000, 0x00200800,
+ 0x04000000, 0x00200800, 0x00200000, 0x04000802,
+ 0x04000802, 0x04200002, 0x04200002, 0x00000002,
+ 0x00200002, 0x04000000, 0x04000800, 0x00200000,
+ 0x04200800, 0x00000802, 0x00200802, 0x04200800,
+ 0x00000802, 0x04000002, 0x04200802, 0x04200000,
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802,
+ 0x00000000, 0x00200802, 0x04200000, 0x00000800,
+ 0x04000002, 0x04000800, 0x00000800, 0x00200002
+ };
+ private static int[] SP8 = {
+ 0x10001040, 0x00001000, 0x00040000, 0x10041040,
+ 0x10000000, 0x10001040, 0x00000040, 0x10000000,
+ 0x00040040, 0x10040000, 0x10041040, 0x00041000,
+ 0x10041000, 0x00041040, 0x00001000, 0x00000040,
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040,
+ 0x00041000, 0x00040040, 0x10040040, 0x10041000,
+ 0x00001040, 0x00000000, 0x00000000, 0x10040040,
+ 0x10000040, 0x10001000, 0x00041040, 0x00040000,
+ 0x00041040, 0x00040000, 0x10041000, 0x00001000,
+ 0x00000040, 0x10040040, 0x00001000, 0x00041040,
+ 0x10001000, 0x00000040, 0x10000040, 0x10040000,
+ 0x10040040, 0x10000000, 0x00040000, 0x10001040,
+ 0x00000000, 0x10041040, 0x00040040, 0x10000040,
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000,
+ 0x10041040, 0x00041000, 0x00041000, 0x00001040,
+ 0x00001040, 0x00040040, 0x10000000, 0x10041000
+ };
+
+ // Routines taken from other parts of the Acme utilities.
+
+ /// Squash bytes down to ints.
+ public static void squashBytesToInts( byte[] inBytes, int inOff, int[] outInts, int outOff, int intLen )
+ {
+ for ( int i = 0; i < intLen; ++i )
+ outInts[outOff + i] =
+ ( ( inBytes[inOff + i * 4 ] & 0xff ) << 24 ) |
+ ( ( inBytes[inOff + i * 4 + 1] & 0xff ) << 16 ) |
+ ( ( inBytes[inOff + i * 4 + 2] & 0xff ) << 8 ) |
+ ( inBytes[inOff + i * 4 + 3] & 0xff );
+ }
+
+ /// Spread ints into bytes.
+ public static void spreadIntsToBytes( int[] inInts, int inOff, byte[] outBytes, int outOff, int intLen )
+ {
+ for ( int i = 0; i < intLen; ++i )
+ {
+ outBytes[outOff + i * 4 ] = (byte) ( inInts[inOff + i] >>> 24 );
+ outBytes[outOff + i * 4 + 1] = (byte) ( inInts[inOff + i] >>> 16 );
+ outBytes[outOff + i * 4 + 2] = (byte) ( inInts[inOff + i] >>> 8 );
+ outBytes[outOff + i * 4 + 3] = (byte) inInts[inOff + i];
+ }
+ }
+ }
--- /dev/null
+//
+// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// HTTPConnectSocket.java together with HTTPConnectSocketFactory.java
+// implement an alternate way to connect to VNC servers via one or two
+// HTTP proxies supporting the HTTP CONNECT method.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.net.*;
+import java.io.*;
+
+class HTTPConnectSocket extends Socket {
+
+ public HTTPConnectSocket(String host, int port,
+ String proxyHost, int proxyPort)
+ throws IOException {
+
+ // Connect to the specified HTTP proxy
+ super(proxyHost, proxyPort);
+
+ // Send the CONNECT request
+ getOutputStream().write(("CONNECT " + host + ":" + port +
+ " HTTP/1.0\r\n\r\n").getBytes());
+
+ // Read the first line of the response
+ DataInputStream is = new DataInputStream(getInputStream());
+ String str = is.readLine();
+
+ // Check the HTTP error code -- it should be "200" on success
+ if (!str.startsWith("HTTP/1.0 200 ")) {
+ if (str.startsWith("HTTP/1.0 "))
+ str = str.substring(9);
+ throw new IOException("Proxy reports \"" + str + "\"");
+ }
+
+ // Success -- skip remaining HTTP headers
+ do {
+ str = is.readLine();
+ } while (str.length() != 0);
+ }
+}
+
--- /dev/null
+//
+// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// HTTPConnectSocketFactory.java together with HTTPConnectSocket.java
+// implement an alternate way to connect to VNC servers via one or two
+// HTTP proxies supporting the HTTP CONNECT method.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.applet.*;
+import java.net.*;
+import java.io.*;
+
+class HTTPConnectSocketFactory implements SocketFactory {
+
+ public Socket createSocket(String host, int port, Applet applet)
+ throws IOException {
+
+ return createSocket(host, port,
+ applet.getParameter("PROXYHOST1"),
+ applet.getParameter("PROXYPORT1"));
+ }
+
+ public Socket createSocket(String host, int port, String[] args)
+ throws IOException {
+
+ return createSocket(host, port,
+ readArg(args, "PROXYHOST1"),
+ readArg(args, "PROXYPORT1"));
+ }
+
+ public Socket createSocket(String host, int port,
+ String proxyHost, String proxyPortStr)
+ throws IOException {
+
+ int proxyPort = 0;
+ if (proxyPortStr != null) {
+ try {
+ proxyPort = Integer.parseInt(proxyPortStr);
+ } catch (NumberFormatException e) { }
+ }
+
+ if (proxyHost == null || proxyPort == 0) {
+ System.out.println("Incomplete parameter list for HTTPConnectSocket");
+ return new Socket(host, port);
+ }
+
+ System.out.println("HTTP CONNECT via proxy " + proxyHost +
+ " port " + proxyPort);
+ HTTPConnectSocket s =
+ new HTTPConnectSocket(host, port, proxyHost, proxyPort);
+
+ return (Socket)s;
+ }
+
+ private String readArg(String[] args, String name) {
+
+ for (int i = 0; i < args.length; i += 2) {
+ if (args[i].equalsIgnoreCase(name)) {
+ try {
+ return args[i+1];
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+}
+
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// rdr::InStream marshalls data from a buffer stored in RDR (RFB Data
+// Representation).
+//
+
+package com.tightvnc.vncviewer;
+
+abstract public class InStream {
+
+ // check() ensures there is buffer data for at least one item of size
+ // itemSize bytes. Returns the number of items in the buffer (up to a
+ // maximum of nItems).
+
+ public final int check(int itemSize, int nItems) throws Exception {
+ if (ptr + itemSize * nItems > end) {
+ if (ptr + itemSize > end)
+ return overrun(itemSize, nItems);
+
+ nItems = (end - ptr) / itemSize;
+ }
+ return nItems;
+ }
+
+ public final void check(int itemSize) throws Exception {
+ if (ptr + itemSize > end)
+ overrun(itemSize, 1);
+ }
+
+ // readU/SN() methods read unsigned and signed N-bit integers.
+
+ public final int readS8() throws Exception {
+ check(1); return b[ptr++];
+ }
+
+ public final int readS16() throws Exception {
+ check(2); int b0 = b[ptr++];
+ int b1 = b[ptr++] & 0xff; return b0 << 8 | b1;
+ }
+
+ public final int readS32() throws Exception {
+ check(4); int b0 = b[ptr++];
+ int b1 = b[ptr++] & 0xff;
+ int b2 = b[ptr++] & 0xff;
+ int b3 = b[ptr++] & 0xff;
+ return b0 << 24 | b1 << 16 | b2 << 8 | b3;
+ }
+
+ public final int readU8() throws Exception {
+ return readS8() & 0xff;
+ }
+
+ public final int readU16() throws Exception {
+ return readS16() & 0xffff;
+ }
+
+ public final int readU32() throws Exception {
+ return readS32() & 0xffffffff;
+ }
+
+ // readString() reads a string - a U32 length followed by the data.
+
+ public final String readString() throws Exception {
+ int len = readU32();
+ if (len > maxStringLength)
+ throw new Exception("InStream max string length exceeded");
+
+ char[] str = new char[len];
+ int i = 0;
+ while (i < len) {
+ int j = i + check(1, len - i);
+ while (i < j) {
+ str[i++] = (char)b[ptr++];
+ }
+ }
+
+ return new String(str);
+ }
+
+ // maxStringLength protects against allocating a huge buffer. Set it
+ // higher if you need longer strings.
+
+ public static int maxStringLength = 65535;
+
+ public final void skip(int bytes) throws Exception {
+ while (bytes > 0) {
+ int n = check(1, bytes);
+ ptr += n;
+ bytes -= n;
+ }
+ }
+
+ // readBytes() reads an exact number of bytes into an array at an offset.
+
+ public void readBytes(byte[] data, int offset, int length) throws Exception {
+ int offsetEnd = offset + length;
+ while (offset < offsetEnd) {
+ int n = check(1, offsetEnd - offset);
+ System.arraycopy(b, ptr, data, offset, n);
+ ptr += n;
+ offset += n;
+ }
+ }
+
+ // readOpaqueN() reads a quantity "without byte-swapping". Because java has
+ // no byte-ordering, we just use big-endian.
+
+ public final int readOpaque8() throws Exception {
+ return readU8();
+ }
+
+ public final int readOpaque16() throws Exception {
+ return readU16();
+ }
+
+ public final int readOpaque32() throws Exception {
+ return readU32();
+ }
+
+ public final int readOpaque24A() throws Exception {
+ check(3); int b0 = b[ptr++];
+ int b1 = b[ptr++]; int b2 = b[ptr++];
+ return b0 << 24 | b1 << 16 | b2 << 8;
+ }
+
+ public final int readOpaque24B() throws Exception {
+ check(3); int b0 = b[ptr++];
+ int b1 = b[ptr++]; int b2 = b[ptr++];
+ return b0 << 16 | b1 << 8 | b2;
+ }
+
+ // pos() returns the position in the stream.
+
+ abstract public int pos();
+
+ // bytesAvailable() returns true if at least one byte can be read from the
+ // stream without blocking. i.e. if false is returned then readU8() would
+ // block.
+
+ public boolean bytesAvailable() { return end != ptr; }
+
+ // getbuf(), getptr(), getend() and setptr() are "dirty" methods which allow
+ // you to manipulate the buffer directly. This is useful for a stream which
+ // is a wrapper around an underlying stream.
+
+ public final byte[] getbuf() { return b; }
+ public final int getptr() { return ptr; }
+ public final int getend() { return end; }
+ public final void setptr(int p) { ptr = p; }
+
+ // overrun() is implemented by a derived class to cope with buffer overrun.
+ // It ensures there are at least itemSize bytes of buffer data. Returns
+ // the number of items in the buffer (up to a maximum of nItems). itemSize
+ // is supposed to be "small" (a few bytes).
+
+ abstract protected int overrun(int itemSize, int nItems) throws Exception;
+
+ protected InStream() {}
+ protected byte[] b;
+ protected int ptr;
+ protected int end;
+}
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+Manifest-Version: 1.0
+Main-Class: VncViewer
--- /dev/null
+#
+# Making the VNC applet.
+#
+
+CP = cp
+JC = javac
+JCFLAGS = -target 1.1
+JAR = jar
+ARCHIVE = VncViewer.jar
+MANIFEST = MANIFEST.MF
+PAGES = index.vnc
+INSTALL_DIR = /usr/local/vnc/classes
+
+CLASSES = VncViewer.class RfbProto.class AuthPanel.class VncCanvas.class \
+ VncCanvas2.class \
+ OptionsFrame.class ClipboardFrame.class ButtonPanel.class \
+ DesCipher.class CapabilityInfo.class CapsContainer.class \
+ RecordingFrame.class SessionRecorder.class \
+ SocketFactory.class HTTPConnectSocketFactory.class \
+ HTTPConnectSocket.class ReloginPanel.class \
+ InStream.class MemInStream.class ZlibInStream.class
+
+SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \
+ VncCanvas2.java \
+ OptionsFrame.java ClipboardFrame.java ButtonPanel.java \
+ DesCipher.java CapabilityInfo.java CapsContainer.java \
+ RecordingFrame.java SessionRecorder.java \
+ SocketFactory.java HTTPConnectSocketFactory.java \
+ HTTPConnectSocket.java ReloginPanel.java \
+ InStream.java MemInStream.java ZlibInStream.java
+
+all: $(CLASSES) $(ARCHIVE)
+
+$(CLASSES): $(SOURCES)
+ $(JC) $(JCFLAGS) -O $(SOURCES)
+
+$(ARCHIVE): $(CLASSES) $(MANIFEST)
+ $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES)
+
+install: $(CLASSES) $(ARCHIVE)
+ $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR)
+
+export:: $(CLASSES) $(ARCHIVE) $(PAGES)
+ @$(ExportJavaClasses)
+
+clean::
+ $(RM) *.class *.jar
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tightvnc.vncviewer;
+
+public class MemInStream extends InStream {
+
+ public MemInStream(byte[] data, int offset, int len) {
+ b = data;
+ ptr = offset;
+ end = offset + len;
+ }
+
+ public int pos() { return ptr; }
+
+ protected int overrun(int itemSize, int nItems) throws Exception {
+ throw new Exception("MemInStream overrun: end of stream");
+ }
+}
--- /dev/null
+//
+// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved.
+// Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved.
+// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// Options frame.
+//
+// This deals with all the options the user can play with.
+// It sets the encodings array and some booleans.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+
+class OptionsFrame extends Frame
+ implements WindowListener, ActionListener, ItemListener {
+
+ static String[] names = {
+ "Encoding",
+ "Compression level",
+ "JPEG image quality",
+ "Cursor shape updates",
+ "Use CopyRect",
+ "Continuous updates",
+ "Restricted colors",
+ "Mouse buttons 2 and 3",
+ "View only",
+ "Scaling factor",
+ "Scale remote cursor",
+ "Share desktop"
+ };
+
+ static String[][] values = {
+ { "Auto", "Raw", "RRE", "CoRRE", "Hextile", "Zlib", "Tight", "ZRLE" },
+ { "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9" },
+ { "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" },
+ { "Enable", "Ignore", "Disable" },
+ { "Yes", "No" },
+ { "Yes", "No" },
+ { "Yes", "No" },
+ { "Normal", "Reversed" },
+ { "Yes", "No" },
+ { "Auto", "1%", "5%", "10%", "20%", "25%", "50%", "75%", "100%"},
+ { "No", "50%", "75%", "125%", "150%" },
+ { "Yes", "No" }
+ };
+
+ final int
+ encodingIndex = 0,
+ compressLevelIndex = 1,
+ jpegQualityIndex = 2,
+ cursorUpdatesIndex = 3,
+ useCopyRectIndex = 4,
+ contUpdatesIndex = 5,
+ eightBitColorsIndex = 6,
+ mouseButtonIndex = 7,
+ viewOnlyIndex = 8,
+ scalingFactorIndex = 9,
+ scaleCursorIndex = 10,
+ shareDesktopIndex = 11;
+
+ Label[] labels = new Label[names.length];
+ Choice[] choices = new Choice[names.length];
+ Button closeButton;
+ VncViewer viewer;
+
+
+ //
+ // The actual data which other classes look at:
+ //
+
+ int preferredEncoding;
+ int compressLevel;
+ int jpegQuality;
+ boolean useCopyRect;
+ boolean continuousUpdates;
+ boolean requestCursorUpdates;
+ boolean ignoreCursorUpdates;
+
+ boolean eightBitColors;
+
+ boolean reverseMouseButtons2And3;
+ boolean shareDesktop;
+ boolean viewOnly;
+ int scaleCursor;
+
+ boolean autoScale;
+ int scalingFactor;
+
+ //
+ // Constructor. Set up the labels and choices from the names and values
+ // arrays.
+ //
+
+ OptionsFrame(VncViewer v) {
+ super("TigerVNC Options");
+
+ viewer = v;
+
+ GridBagLayout gridbag = new GridBagLayout();
+ setLayout(gridbag);
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.fill = GridBagConstraints.BOTH;
+
+ for (int i = 0; i < names.length; i++) {
+ labels[i] = new Label(names[i]);
+ gbc.gridwidth = 1;
+ gridbag.setConstraints(labels[i],gbc);
+ add(labels[i]);
+
+ choices[i] = new Choice();
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gridbag.setConstraints(choices[i],gbc);
+ add(choices[i]);
+ choices[i].addItemListener(this);
+
+ for (int j = 0; j < values[i].length; j++) {
+ choices[i].addItem(values[i][j]);
+ }
+ }
+
+ closeButton = new Button("Close");
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gridbag.setConstraints(closeButton, gbc);
+ add(closeButton);
+ closeButton.addActionListener(this);
+
+ pack();
+
+ addWindowListener(this);
+
+ // Set up defaults
+
+ choices[encodingIndex].select("Auto");
+ choices[compressLevelIndex].select("Default");
+ choices[jpegQualityIndex].select("6");
+ choices[cursorUpdatesIndex].select("Enable");
+ choices[useCopyRectIndex].select("Yes");
+ choices[contUpdatesIndex].select("No");
+ choices[eightBitColorsIndex].select("No");
+ choices[mouseButtonIndex].select("Normal");
+ choices[viewOnlyIndex].select("No");
+ choices[scaleCursorIndex].select("No");
+ choices[shareDesktopIndex].select("Yes");
+
+ // But let them be overridden by parameters
+
+ for (int i = 0; i < names.length; i++) {
+ String s = viewer.readParameter(names[i], false);
+ if (s != null) {
+ for (int j = 0; j < values[i].length; j++) {
+ if (s.equalsIgnoreCase(values[i][j])) {
+ choices[i].select(j);
+ }
+ }
+ }
+ }
+
+ // Get scaling factor from parameters and set it
+ // to gui and class member scalingFactor
+
+ String s = viewer.readParameter("Scaling Factor", false);
+ if (s == null) s = "100%";
+ setScalingFactor(s);
+ if (autoScale) {
+ choices[scalingFactorIndex].select("Auto");
+ } else {
+ choices[scalingFactorIndex].select(s);
+ }
+
+ // Make the booleans and encodings array correspond to the state of the GUI
+
+ setEncodings();
+ setColorFormat();
+ setContinuousUpdates();
+ setOtherOptions();
+ }
+
+ //
+ // Set scaling factor class member value
+ //
+
+ void setScalingFactor(int sf) {
+ setScalingFactor(((Integer)sf).toString());
+ }
+
+ void setScalingFactor(String s) {
+ autoScale = false;
+ scalingFactor = 100;
+ if (s != null) {
+ if (s.equalsIgnoreCase("Auto")) {
+ autoScale = true;
+ } else {
+ // Remove the '%' char at the end of string if present.
+ if (s.charAt(s.length() - 1) == '%') {
+ s = s.substring(0, s.length() - 1);
+ }
+ // Convert to an integer.
+ try {
+ scalingFactor = Integer.parseInt(s);
+ }
+ catch (NumberFormatException e) {
+ scalingFactor = 100;
+ }
+ // Make sure scalingFactor is in the range of [1..1000].
+ if (scalingFactor < 1) {
+ scalingFactor = 1;
+ } else if (scalingFactor > 1000) {
+ scalingFactor = 1000;
+ }
+ }
+ }
+ }
+
+
+ //
+ // Disable the shareDesktop option
+ //
+
+ void disableShareDesktop() {
+ labels[shareDesktopIndex].setEnabled(false);
+ choices[shareDesktopIndex].setEnabled(false);
+ }
+
+
+ //
+ // Disable the "Continuous updates" option. This method is called
+ // when we figure out that the server does not support corresponding
+ // protocol extensions.
+ //
+
+ void disableContUpdates() {
+ labels[contUpdatesIndex].setEnabled(false);
+ choices[contUpdatesIndex].setEnabled(false);
+ choices[contUpdatesIndex].select("No");
+ continuousUpdates = false;
+ }
+
+
+ //
+ // setEncodings looks at the encoding, compression level, JPEG
+ // quality level, cursor shape updates and copyRect choices and sets
+ // corresponding variables properly. Then it calls the VncViewer's
+ // setEncodings method to send a SetEncodings message to the RFB
+ // server.
+ //
+
+ void setEncodings() {
+ useCopyRect = choices[useCopyRectIndex].getSelectedItem().equals("Yes");
+
+ preferredEncoding = RfbProto.EncodingRaw;
+ boolean enableCompressLevel = false;
+ boolean enableQualityLevel = false;
+
+ if (choices[encodingIndex].getSelectedItem().equals("RRE")) {
+ preferredEncoding = RfbProto.EncodingRRE;
+ } else if (choices[encodingIndex].getSelectedItem().equals("CoRRE")) {
+ preferredEncoding = RfbProto.EncodingCoRRE;
+ } else if (choices[encodingIndex].getSelectedItem().equals("Hextile")) {
+ preferredEncoding = RfbProto.EncodingHextile;
+ } else if (choices[encodingIndex].getSelectedItem().equals("ZRLE")) {
+ preferredEncoding = RfbProto.EncodingZRLE;
+ } else if (choices[encodingIndex].getSelectedItem().equals("Zlib")) {
+ preferredEncoding = RfbProto.EncodingZlib;
+ enableCompressLevel = true;
+ } else if (choices[encodingIndex].getSelectedItem().equals("Tight")) {
+ preferredEncoding = RfbProto.EncodingTight;
+ enableCompressLevel = true;
+ enableQualityLevel = !eightBitColors;
+ } else if (choices[encodingIndex].getSelectedItem().equals("Auto")) {
+ preferredEncoding = -1;
+ enableQualityLevel = !eightBitColors;
+ }
+
+ // Handle compression level setting.
+
+ try {
+ compressLevel =
+ Integer.parseInt(choices[compressLevelIndex].getSelectedItem());
+ }
+ catch (NumberFormatException e) {
+ compressLevel = -1;
+ }
+ if (compressLevel < 1 || compressLevel > 9) {
+ compressLevel = -1;
+ }
+ labels[compressLevelIndex].setEnabled(enableCompressLevel);
+ choices[compressLevelIndex].setEnabled(enableCompressLevel);
+
+ // Handle JPEG quality setting.
+
+ try {
+ jpegQuality =
+ Integer.parseInt(choices[jpegQualityIndex].getSelectedItem());
+ }
+ catch (NumberFormatException e) {
+ jpegQuality = -1;
+ }
+ if (jpegQuality < 0 || jpegQuality > 9) {
+ jpegQuality = -1;
+ }
+ labels[jpegQualityIndex].setEnabled(enableQualityLevel);
+ choices[jpegQualityIndex].setEnabled(enableQualityLevel);
+
+ // Request cursor shape updates if necessary.
+
+ requestCursorUpdates =
+ !choices[cursorUpdatesIndex].getSelectedItem().equals("Disable");
+
+ if (requestCursorUpdates) {
+ ignoreCursorUpdates =
+ choices[cursorUpdatesIndex].getSelectedItem().equals("Ignore");
+ }
+
+ viewer.setEncodings();
+ }
+
+ //
+ // setColorFormat sets eightBitColors variable depending on the GUI
+ // setting, causing switches between 8-bit and 24-bit colors mode if
+ // necessary.
+ //
+
+ void setColorFormat() {
+
+ eightBitColors =
+ choices[eightBitColorsIndex].getSelectedItem().equals("Yes");
+
+ boolean enableJPEG = !eightBitColors &&
+ (choices[encodingIndex].getSelectedItem().equals("Tight") ||
+ choices[encodingIndex].getSelectedItem().equals("Auto"));
+
+ labels[jpegQualityIndex].setEnabled(enableJPEG);
+ choices[jpegQualityIndex].setEnabled(enableJPEG);
+ }
+
+ //
+ // setContinuousUpdates sets continuousUpdates variable depending on
+ // the GUI setting. VncViewer monitors the state of this variable and
+ // send corresponding protocol messages to the server when necessary.
+ //
+
+ void setContinuousUpdates() {
+
+ continuousUpdates =
+ choices[contUpdatesIndex].getSelectedItem().equals("Yes");
+ }
+
+ //
+ // setOtherOptions looks at the "other" choices (ones that do not
+ // cause sending any protocol messages) and sets the boolean flags
+ // appropriately.
+ //
+
+ void setOtherOptions() {
+
+ reverseMouseButtons2And3
+ = choices[mouseButtonIndex].getSelectedItem().equals("Reversed");
+
+ viewOnly
+ = choices[viewOnlyIndex].getSelectedItem().equals("Yes");
+ if (viewer.vc != null)
+ viewer.vc.enableInput(!viewOnly);
+
+ shareDesktop
+ = choices[shareDesktopIndex].getSelectedItem().equals("Yes");
+
+ String scaleString = choices[scaleCursorIndex].getSelectedItem();
+ if (scaleString.endsWith("%"))
+ scaleString = scaleString.substring(0, scaleString.length() - 1);
+ try {
+ scaleCursor = Integer.parseInt(scaleString);
+ }
+ catch (NumberFormatException e) {
+ scaleCursor = 0;
+ }
+ if (scaleCursor < 10 || scaleCursor > 500) {
+ scaleCursor = 0;
+ }
+ if (requestCursorUpdates && !ignoreCursorUpdates && !viewOnly) {
+ labels[scaleCursorIndex].setEnabled(true);
+ choices[scaleCursorIndex].setEnabled(true);
+ } else {
+ labels[scaleCursorIndex].setEnabled(false);
+ choices[scaleCursorIndex].setEnabled(false);
+ }
+ if (viewer.vc != null)
+ viewer.vc.createSoftCursor(); // update cursor scaling
+ }
+
+
+ //
+ // Respond to actions on Choice controls
+ //
+
+ public void itemStateChanged(ItemEvent evt) {
+ Object source = evt.getSource();
+
+ if (source == choices[encodingIndex] ||
+ source == choices[compressLevelIndex] ||
+ source == choices[jpegQualityIndex] ||
+ source == choices[cursorUpdatesIndex] ||
+ source == choices[useCopyRectIndex]) {
+
+ setEncodings();
+
+ if (source == choices[cursorUpdatesIndex]) {
+ setOtherOptions(); // update scaleCursor state
+ }
+
+ } else if (source == choices[eightBitColorsIndex]) {
+
+ setColorFormat();
+
+ } else if (source == choices[contUpdatesIndex]) {
+
+ setContinuousUpdates();
+
+ } else if (source == choices[mouseButtonIndex] ||
+ source == choices[shareDesktopIndex] ||
+ source == choices[viewOnlyIndex] ||
+ source == choices[scaleCursorIndex]) {
+
+ setOtherOptions();
+
+ } else if (source == choices[scalingFactorIndex]){
+ // Tell VNC canvas that scaling factor has changed
+ setScalingFactor(choices[scalingFactorIndex].getSelectedItem());
+ if (viewer.vc != null)
+ viewer.vc.setScalingFactor(scalingFactor);
+ }
+ }
+
+ //
+ // Respond to button press
+ //
+
+ public void actionPerformed(ActionEvent evt) {
+ if (evt.getSource() == closeButton)
+ setVisible(false);
+ }
+
+ //
+ // Respond to window events
+ //
+
+ public void windowClosing(WindowEvent evt) {
+ setVisible(false);
+ }
+
+ public void windowActivated(WindowEvent evt) {}
+ public void windowDeactivated(WindowEvent evt) {}
+ public void windowOpened(WindowEvent evt) {}
+ public void windowClosed(WindowEvent evt) {}
+ public void windowIconified(WindowEvent evt) {}
+ public void windowDeiconified(WindowEvent evt) {}
+}
--- /dev/null
+
+ TigerVNC Java Viewer version 1.3.9
+
+======================================================================
+
+This distribution is based on the standard VNC source and includes new
+TightVNC-specific features and fixes, such as additional low-bandwidth
+optimizations, major GUI improvements, and more.
+
+ Copyright (C) 1999 AT&T Laboratories Cambridge.
+ Copyright (C) 2000 Tridia Corp.
+ Copyright (C) 2002-2003 RealVNC Ltd.
+ Copyright (C) 2001-2004 HorizonLive.com, Inc.
+ Copyright (C) 2000-2007 Constantin Kaplinsky
+ Copyright (C) 2000-2007 TightVNC Group
+ All rights reserved.
+
+This software is distributed under the GNU General Public Licence as
+published by the Free Software Foundation. See the file LICENCE.TXT for the
+conditions under which this software is made available. TigerVNC also
+contains code from other sources. See the Acknowledgements section below, and
+the individual files for details of the conditions under which they are made
+available.
+
+
+Compiling from the sources
+==========================
+
+To compile all the .java files to .class files, simply do:
+
+ % make all
+
+This will also generate a JAR (Java archive) file containing all the classes.
+Most JVM (Java Virtual Machine) implementations are able to use either a set
+of .class files, or the JAR archive.
+
+
+Installation
+============
+
+There are three basic ways to use TigerVNC Java viewer:
+
+ 1. Running applet as part of TigerVNC server installation.
+
+ Both the Unix and Windows versions of TigerVNC servers include small
+ built-in HTTP server which can serve Java viewer to Web clients. This
+ enables easy Web access to the shared desktop without need to install
+ any software on the client computer. Unix and Windows versions of
+ TigerVNC servers are different in the way they store the .class and .jar
+ files: the Unix server (Xvnc) is able to serve any set of files present
+ in a particular directory, while the Windows server (WinVNC) has all the
+ .class and .jar files inside the WinVNC executable file. Therefore, for
+ Xvnc, it's enough to copy the files into a correct directory, but for
+ WinVNC, the server binaries should be rebuild if the built-in Java
+ viewer should be updated.
+
+ To install the Java viewer under Xvnc, copy all the .class files, the
+ .jar file and the .vnc files to an installation directory (e.g.
+ /usr/local/vnc/classes):
+
+ cp *.class *.jar *.vnc /usr/local/vnc/classes
+
+ Also, make sure that the vncserver script is configured to point to the
+ installation directory (see the Xvnc manual page for the description of
+ the -httpd command-line option).
+
+ 2. Running applet hosted on a standalone Web server.
+
+ Another possibility to use the Java viewer is to install it under a
+ fully-functional HTTP server such as Apache or IIS. Obviously, this
+ method requires running an HTTP server, and due to the Java security
+ restrictions, it's also required that the server should be installed on
+ the same machine which is running the TigerVNC server. In this case,
+ installation is simply copying the .class and .jar files into a
+ directory that is under control of the HTTP server. Also, an HTML page
+ should be created which will act as a the base document for the viewer
+ applet (see an example named index.html in this distribution).
+
+ NOTE: Provided index.html page is an example only. Before using that
+ file, edit it with a text editor. See more information inside
+ index.html.
+
+ 3. Running the viewer as a standalone application.
+
+ Finally, the Java viewer can be executed locally on the client machine,
+ but this method requires installation of either JRE (Java Runtime
+ Environment) or JDK (Java Development Kit). If all the .class files are
+ in the current directory, the Java viewer can be executed like this,
+ from the command line:
+
+ java VncViewer HOST vnchost PORT 5900
+
+ The HOST parameter is required, PORT defaults to 5900 if omitted, and
+ there is a number of other optional parameters, see the Parameters
+ section below.
+
+
+Parameters
+==========
+
+TigerVNC Java viewer supports a number of parameters allowing you to
+customize its behavior. Most parameters directly correspond to the settings
+found in the Options window. However, there are parameters that do not
+correspond to those settings. For such parameters, you can see a note "no GUI
+equivalent", in the documentation below.
+
+Parameters can be specified in one of the two ways, depending on how the Java
+viewer is used:
+
+ 1. When the Java viewer is run as an applet (embedded within an HTML
+ document), parameters should be specified in the <PARAM> HTML tags,
+ within the appropriate <APPLET> section. Here is an example:
+
+ <APPLET CODE=VncViewer.class ARCHIVE=VncViewer.jar WIDTH=400 HEIGHT=300>
+ <PARAM NAME="PORT" VALUE=5901>
+ <PARAM NAME="Scaling factor" VALUE=50>
+ </APPLET>
+
+ 2. When run as a standalone application, the Java viewer reads parameters
+ from the command line. Command-line arguments should be specified in
+ pairs -- first goes parameter name, then parameter value. Here is a
+ command line example:
+
+ java VncViewer HOST vnchost PORT 5901 "Scaling factor" 50
+
+Both parameter names and their values are case-insensitive. The only
+exception is the "PASSWORD" parameter, as VNC passwords are case-sensitive.
+
+Here is the complete list of parameters supported in TigerVNC Java viewer:
+
+--> "HOST" (no GUI equivalent)
+
+ Value: host name or IP address of the VNC server.
+ Default: in applet mode, the host from which the applet was loaded.
+
+ This parameter tells the viewer which server to connect to. It's not
+ needed in the applet mode, because default Java security policy allow
+ connections from applets to the only one host anyway, and that is the
+ host from which the applet was loaded. However, this parameter is
+ required if the viewer is used as a standalone application.
+
+--> "PORT" (no GUI equivalent)
+
+ Value: TCP port number on the VNC server.
+ Default: 5900.
+
+ This parameter specifies TCP port number for outgoing VNC connection.
+ Note that this port is not the one used for HTTP connection from the
+ browser, it is the port used for VNC/RFB connection. Usually, VNC servers
+ use ports 58xx for HTTP connections, and ports 59xx for RFB connections.
+ Thus, most likely, this parameter should be set to something like 5900,
+ 5901 etc.
+
+--> "PASSWORD"
+
+ Value: session password in plain text.
+ Default: none, ask user.
+
+ DO NOT EVER USE THIS PARAMETER, unless you really know what you are
+ doing. It's extremely dangerous from the security point of view. When
+ this parameter is set, the viewer won't ever ask for a password.
+
+--> "ENCPASSWORD"
+
+ Value: encrypted session password in hex-ascii.
+ Default: none, ask user.
+
+ The same as the "PASSWORD" parameter but DES-encrypted using a fixed key.
+ Its value should be represented in hex-ascii e.g. "494015f9a35e8b22".
+ This parameter has higher priority over the "PASSWORD" parameter. DO NOT
+ EVER USE THIS PARAMETER, unless you really know what you are doing. It's
+ extremely dangerous from the security point of view, and encryption does
+ not actually help here since the decryption key is always known.
+
+--> "Encoding"
+
+ Values: "Auto", "Raw", "RRE", "CoRRE", "Hextile", "ZRLE", "Zlib", "Tight".
+ Default: "Auto".
+
+ The preferred encoding. If the value is "Auto", then the viewer will
+ continuously estimate average network throughput and request encodings
+ that are appropriate for current connection speed. "Hextile" is an
+ encoding that was designed for fast networks, while "Tight" is better
+ suited for low-bandwidth connections. From the other side, "Tight"
+ decoder in the TigerVNC Java viewer seems to be more efficient than
+ "Hextile" decoder so it may be ok for fast networks too. "ZRLE" encoding
+ is similar to "Tight", but it does not support JPEG compression and
+ compression levels. Unlike "Tight" encoding, "ZRLE" is supported in
+ recent versions of RealVNC products. Other encodings are not efficient
+ and provided for compatibility reasons.
+
+--> "Compression level"
+
+ Values: "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9".
+ Default: "Default". ;-)
+
+ Use specified compression level for "Tight" and "Zlib" encodings. Level 1
+ uses minimum of CPU time on the server but achieves weak compression
+ ratios. Level 9 offers best compression but may be slow in terms of CPU
+ time consumption on the server side. Use high levels with very slow
+ network connections, and low levels when working over higher-speed
+ networks. The "Default" value means that the server's default compression
+ level should be used.
+
+--> "JPEG image quality"
+
+ Values: "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9".
+ Default: "6".
+
+ Use the specified image quality level in "Tight" encoding. Quality level
+ 0 denotes bad image quality but very impressive compression ratios, while
+ level 9 offers very good image quality at lower compression ratios. If
+ the value is "JPEG off", the server will not use lossy JPEG compression
+ in "Tight" encoding.
+
+--> "Cursor shape updates"
+
+ Values: "Enable", "Ignore", "Disable".
+ Default: "Enable".
+
+ Cursor shape updates is a protocol extension used to handle remote cursor
+ movements locally on the client side, saving bandwidth and eliminating
+ delays in mouse pointer movement. Note that current implementation of
+ cursor shape updates does not allow a client to track mouse cursor
+ position at the server side. This means that clients would not see mouse
+ cursor movements if mouse was moved either locally on the server, or by
+ another remote VNC client. Set this parameter to "Disable" if you always
+ want to see real cursor position on the remote side. Setting this option
+ to "Ignore" is similar to "Enable" but the remote cursor will not be
+ visible at all. This can be a reasonable setting if you don't care about
+ cursor shape and don't want to see two mouse cursors, one above another.
+
+--> "Use CopyRect"
+
+ Values: "Yes", "No".
+ Default: "Yes".
+
+ The "CopyRect" encoding saves bandwidth and drawing time when parts of
+ the remote screen are moving around. Most likely, you don't want to
+ change this setting.
+
+--> "Restricted colors"
+
+ Values: "Yes", "No".
+ Default: "No".
+
+ If set to "No", then 24-bit color format is used to represent pixel data.
+ If set to "Yes", then only 8 bits are used to represent each pixel. 8-bit
+ color format can save bandwidth, but colors may look very inaccurate.
+
+--> "Mouse buttons 2 and 3"
+
+ Values: "Normal", "Reversed".
+ Default: "Normal".
+
+ If set to "Reversed", then right mouse button (button 2) will act as it
+ was middle mouse button (button 3), and vice versa.
+
+--> "View only"
+
+ Values: "Yes", "No".
+ Default: "No".
+
+ If set to "Yes", then all keyboard and mouse events in the desktop window
+ will be silently ignored and will not be passed to the remote side.
+
+--> "Scale remote cursor"
+
+ Values: "No", "50%", "75%", "125%", "150%".
+ Default: "No".
+
+ If a percentage value is specified, the remote cursor is reduced
+ or enlarged accordingly. Scaling takes place only when "View only"
+ is set to "No", and "Cursor shape updates" is set to "Enable".
+
+--> "Share desktop"
+
+ Values: "Yes", "No".
+ Default: "Yes".
+
+ Share the connection with other clients on the same VNC server. The exact
+ behaviour in each case depends on the server configuration.
+
+--> "Open new window" (no GUI equivalent, applicable only in the applet mode)
+
+ Values: "Yes", "No".
+ Default: "No".
+
+ Operate in a separate window. This makes possible resizing the desktop,
+ and adds scroll bars when necessary. If the server supports variable
+ desktop size, the window will resize automatically when remote desktop
+ size changes.
+
+--> "Scaling factor" (no GUI equivalent)
+
+ Value: an integer in the range of [1..1000], or the string "auto".
+ Default: "100".
+
+ Scale local representation of the remote desktop. The value is
+ interpreted as scaling factor in percents. The default value of 100%
+ corresponds to the original framebuffer size. Values below 100 reduce
+ image size, values above 100 enlarge the image proportionally. If the
+ parameter is set to "auto", automatic scaling is performed. Auto-scaling
+ tries to choose scaling factor such way that the whole remote framebuffer
+ will fit on the local screen. Currently, auto-scaling is supported only
+ when the remote desktop is shown in a separate frame (always true in the
+ application mode, and also in the applet mode with "Open new window"
+ parameter set to "yes").
+
+--> "Show controls" (no GUI equivalent)
+
+ Values: "Yes", "No".
+ Default: "Yes".
+
+ Set to "No" if you want to get rid of that button panel at the top.
+
+--> "Offer relogin" (no GUI equivalent, applicable only in the applet mode)
+
+ Values: "Yes", "No".
+ Default: "Yes".
+
+ If set to "No", the buttons "Login again" and "Close window" won't be
+ shown on disconnects or after an error has occured.
+
+--> "Show offline desktop" (no GUI equivalent)
+
+ Values: "Yes", "No".
+ Default: "No".
+
+ If set to "Yes", the viewer would continue to display desktop even
+ if the remote side has closed the connection. In this case, if the
+ button panel is enabled, then the "Disconnect" button would be
+ changed to "Hide desktop" after the connection is lost.
+
+--> "Defer screen updates" (no GUI equivalent)
+
+ Value: time in milliseconds.
+ Default: "20".
+
+ When updating the desktop contents after receiving an update from server,
+ schedule repaint within the specified number of milliseconds. Small delay
+ helps to coalesce several small updates into one drawing operation,
+ improving CPU usage. Set this parameter to 0 to disable deferred updates.
+
+--> "Defer cursor updates" (no GUI equivalent)
+
+ Value: time in milliseconds.
+ Default: "10".
+
+ When updating the desktop after moving the mouse, schedule repaint within
+ the specified number of milliseconds. This setting makes sense only when
+ "Cursor shape updates" parameter is set to "Enable". Small delay helps to
+ coalesce several small updates into one drawing operation, improving CPU
+ usage. Set this parameter to 0 to disable deferred cursor updates.
+
+--> "Defer update requests" (no GUI equivalent)
+
+ Value: time in milliseconds.
+ Default: "0".
+
+ After processing an update received from server, wait for the specified
+ number of milliseconds before requesting next screen update. Such delay
+ will end immediately on every mouse or keyboard event if not in the "view
+ only" mode. Small delay helps the server to coalesce several small
+ updates into one framebuffer update, improving both bandwidth and CPU
+ usage. Increasing the parameter value does not affect responsiveness on
+ mouse and keyboard events, but causes delays in updating the screen when
+ there is no mouse and keyboard activity on the client side.
+
+--> "SocketFactory" (no GUI equivalent)
+
+ Value: name of the class.
+ Default: none.
+
+ This option provides the way to define an alternate I/O implementation.
+ The dynamically referenced class must implement a SocketFactory
+ interface, and create a Socket, as configured by this parameter. See the
+ source in SocketFactory.java.
+
+--> "DEBUG_XU" (no GUI equivalent)
+
+ Value: non-negative integer.
+ Default: 0.
+
+ Debugging option that causes update statistics reset after the specified
+ number of first framebuffer updates. This option was added to measure the
+ performance of a VNC server. First few updates (especially the very first
+ one) may be notably slower than others, and the viewer can exclude such
+ updates from statistics.
+
+--> "DEBUG_CU" (no GUI equivalent)
+
+ Value: non-negative integer.
+ Default: 0.
+
+ Debugging option that causes the viewer disconnect after the specified
+ number of framebuffer updates. When used with the "DEBUG_XU" parameter,
+ the number of updates specified in "DEBUG_XU" is not counted as part of
+ this parameter's value. E.g. if "DEBUG_XU"=2 and "DEBUG_CU"=10, then the
+ viewer will disconnect after 12 framebuffer updates: update statistics
+ will be reset after first two updates, then collected for next 10
+ updates, then the viewer will disconnect automatically. If the value is
+ 0, the viewer will not disconnect automatically. This option was added to
+ measure the performance of a VNC server.
+
+
+RECORDING VNC SESSIONS
+======================
+
+Current version of the TigerVNC Java viewer is able to record VNC (RFB)
+sessions in files for later playback. The data format in saved session files
+is compatible with the rfbproxy program written by Tim Waugh. Most important
+thing about session recording is that it's supported only if Java security
+manager allows access to local filesystem. Typically, it would not work for
+unsigned applets. To use this feature, either use TigerVNC Java viewer as a
+standalone application (Java Runtime Environment or Java Development Kit
+should be installed), or as a signed applet. The code checks if it's possible
+to support session recording, and if everything's fine, the new "Record"
+button should appear in the button panel. Pressing this button opens new
+window which controls session recording. The GUI is pretty self-explained.
+
+Other important facts about session recording:
+
+--> All sessions are recorded in the 24-bit color format. If you use
+ restricted colors (8-bit format), it will be temporarly switched to
+ 24-bit mode during session recording.
+
+--> All sessions are recorded with cursor shape updates turned off. This is
+ necessary to represent remote cursor movements in recorded sessions.
+
+--> Closing and re-opening the recording control window does not affect the
+ recording. It's not necessary to keep that window open during recording a
+ session.
+
+--> Avoid using Zlib and ZRLE encodings when recording sessions. If you have
+ started recording BEFORE opening a VNC session, then you are ok. But
+ otherwise, all Zlib-encoded updates will be saved Raw-encoded (that is,
+ without compression at all). The case with ZRLE is even worse -- ZRLE
+ updates will not be saved at all, so the resulting session file may be
+ corrupted. Zlib decoding depends on the pixel data received earlier, thus
+ saving the data received from the server at an arbitrary moment is not
+ sufficient to decompress it correctly. And there is no way to tell Zlib
+ or ZRLE decoder to reset decompressor's state -- that's a limitation of
+ these encoders. The viewer could re-compress raw pixel data again before
+ saving Zlib-encoded sessions, but unfortunately Java API does not allow
+ to flush zlib data streams making it impossible to save Zlib-encoded RFB
+ pixel data without using native code.
+
+--> Usually, Tight encoding is the most suitable one for session recording,
+ but some of the issues described above for the Zlib encoding affect the
+ Tight encoding as well. Unlike Zlib sessions, Tight-encoded sessions are
+ always saved Tight-encoded, but the viewer has to re-compress parts of
+ data to synchronize encoder's and decoder's zlib streams. And, due to
+ Java zlib API limitations, zlib streams' states have to be reset on each
+ compressed rectangle, causing compression ratios to be lower than in the
+ original VNC session. If you want to achieve the best possible
+ performance, turn recording on BEFORE connecting to the VNC server,
+ otherwise CPU usage and compression ratios may be notably less efficient.
+
+
+HINTS
+=====
+
+--> To refresh remote desktop in the view-only mode, press "r" or "R"
+ on the keyboard.
+
+
+ACKNOWLEDGEMENTS
+================
+
+This distribution contains Java DES software by Dave Zimmerman
+<dzimm@widget.com> and Jef Poskanzer <jef@acme.com>. This is:
+
+ Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee
+ is hereby granted, provided that this copyright notice is kept intact.
+
+ WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
+ SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE
+ LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
+ MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
+
+ THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
+ CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
+ PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
+ NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
+ SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+ SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
+ PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET
+ WORKSHOP SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF
+ FITNESS FOR HIGH RISK ACTIVITIES.
+
+ Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights
+ reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Visit the ACME Labs Java page for up-to-date versions of this and other
+ fine Java utilities: http://www.acme.com/java/
--- /dev/null
+package com.tightvnc.vncviewer;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+public class RecordOutputStream implements DataOutput {
+
+ public RecordOutputStream(RfbProto rfbproto) {
+ rfb = rfbproto;
+ }
+
+ private boolean canWrite() {
+ return ((rfb != null) && (rfb.rec != null));
+ }
+
+ public void write(byte[] b) throws IOException {
+ if (canWrite())
+ rfb.rec.write(b);
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (canWrite())
+ rfb.rec.write(b, off, len);
+ }
+
+ public void write(int b) throws IOException {
+ if (canWrite())
+ rfb.rec.writeIntBE(b);
+ }
+
+ public void writeBoolean(boolean v) { }
+
+ public void writeByte(int v) throws IOException {
+ if (canWrite()) {
+ rfb.rec.writeByte(v);
+ }
+ }
+
+ public void writeBytes(String s) { }
+ public void writeChar(int v) { }
+ public void writeChars(String s) { }
+ public void writeDouble(double v) { }
+ public void writeFloat(float v) { }
+
+ public void writeInt(int v) throws IOException {
+ if (canWrite())
+ rfb.rec.writeIntBE(v);
+ }
+
+ public void writeLong(long v) { }
+
+ public void writeShort(int v) throws IOException {
+ if (canWrite())
+ rfb.rec.writeShortBE(v);
+ }
+
+ public void writeUTF(String str) { }
+
+ private RfbProto rfb = null;
+}
--- /dev/null
+//
+// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// Recording frame. It allows to control recording RFB sessions into
+// FBS (FrameBuffer Stream) files.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.io.*;
+import java.awt.*;
+import java.awt.event.*;
+
+class RecordingFrame extends Frame
+ implements WindowListener, ActionListener {
+
+ boolean recording;
+
+ TextField fnameField;
+ Button browseButton;
+
+ Label statusLabel;
+
+ Button recordButton, nextButton, closeButton;
+ VncViewer viewer;
+
+ //
+ // Check if current security manager allows to create a
+ // RecordingFrame object.
+ //
+
+ public static boolean checkSecurity() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ try {
+ security.checkPropertyAccess("user.dir");
+ security.checkPropertyAccess("file.separator");
+ // Work around (rare) checkPropertyAccess bug
+ System.getProperty("user.dir");
+ } catch (SecurityException e) {
+ System.out.println("SecurityManager restricts session recording.");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ //
+ // Constructor.
+ //
+
+ RecordingFrame(VncViewer v) {
+ super("TigerVNC Session Recording");
+
+ viewer = v;
+
+ // Determine initial filename for next saved session.
+ // FIXME: Check SecurityManager.
+
+ String fname = nextNewFilename(System.getProperty("user.dir") +
+ System.getProperty("file.separator") +
+ "vncsession.fbs");
+
+ // Construct new panel with file name field and "Browse" button.
+
+ Panel fnamePanel = new Panel();
+ GridBagLayout fnameGridbag = new GridBagLayout();
+ fnamePanel.setLayout(fnameGridbag);
+
+ GridBagConstraints fnameConstraints = new GridBagConstraints();
+ fnameConstraints.gridwidth = GridBagConstraints.RELATIVE;
+ fnameConstraints.fill = GridBagConstraints.BOTH;
+ fnameConstraints.weightx = 4.0;
+
+ fnameField = new TextField(fname, 64);
+ fnameGridbag.setConstraints(fnameField, fnameConstraints);
+ fnamePanel.add(fnameField);
+ fnameField.addActionListener(this);
+
+ fnameConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ fnameConstraints.weightx = 1.0;
+
+ browseButton = new Button("Browse");
+ fnameGridbag.setConstraints(browseButton, fnameConstraints);
+ fnamePanel.add(browseButton);
+ browseButton.addActionListener(this);
+
+ // Construct the frame.
+
+ GridBagLayout gridbag = new GridBagLayout();
+ setLayout(gridbag);
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.fill = GridBagConstraints.BOTH;
+ gbc.weighty = 1.0;
+ gbc.insets = new Insets(10, 0, 0, 0);
+
+ Label helpLabel =
+ new Label("File name to save next recorded session in:", Label.CENTER);
+ gridbag.setConstraints(helpLabel, gbc);
+ add(helpLabel);
+
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.weighty = 0.0;
+ gbc.insets = new Insets(0, 0, 0, 0);
+
+ gridbag.setConstraints(fnamePanel, gbc);
+ add(fnamePanel);
+
+ gbc.fill = GridBagConstraints.BOTH;
+ gbc.weighty = 1.0;
+ gbc.insets = new Insets(10, 0, 10, 0);
+
+ statusLabel = new Label("", Label.CENTER);
+ gridbag.setConstraints(statusLabel, gbc);
+ add(statusLabel);
+
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.weightx = 1.0;
+ gbc.weighty = 0.0;
+ gbc.gridwidth = 1;
+ gbc.insets = new Insets(0, 0, 0, 0);
+
+ recordButton = new Button("Record");
+ gridbag.setConstraints(recordButton, gbc);
+ add(recordButton);
+ recordButton.addActionListener(this);
+
+ nextButton = new Button("Next file");
+ gridbag.setConstraints(nextButton, gbc);
+ add(nextButton);
+ nextButton.addActionListener(this);
+
+ closeButton = new Button("Close");
+ gridbag.setConstraints(closeButton, gbc);
+ add(closeButton);
+ closeButton.addActionListener(this);
+
+ // Set correct text, font and color for the statusLabel.
+ stopRecording();
+
+ pack();
+
+ addWindowListener(this);
+ }
+
+ //
+ // If the given string ends with ".NNN" where NNN is a decimal
+ // number, increase this number by one. Otherwise, append ".001"
+ // to the given string.
+ //
+
+ protected String nextFilename(String fname) {
+ int len = fname.length();
+ int suffixPos = len;
+ int suffixNum = 1;
+
+ if (len > 4 && fname.charAt(len - 4) == '.') {
+ try {
+ suffixNum = Integer.parseInt(fname.substring(len - 3, len)) + 1;
+ suffixPos = len - 4;
+ } catch (NumberFormatException e) { }
+ }
+
+ char[] zeroes = {'0', '0', '0'};
+ String suffix = String.valueOf(suffixNum);
+ if (suffix.length() < 3) {
+ suffix = new String(zeroes, 0, 3 - suffix.length()) + suffix;
+ }
+
+ return fname.substring(0, suffixPos) + '.' + suffix;
+ }
+
+ //
+ // Find next name of a file which does not exist yet.
+ //
+
+ protected String nextNewFilename(String fname) {
+ String newName = fname;
+ File f;
+ try {
+ do {
+ newName = nextFilename(newName);
+ f = new File(newName);
+ } while (f.exists());
+ } catch (SecurityException e) { }
+
+ return newName;
+ }
+
+ //
+ // Let the user choose a file name showing a FileDialog.
+ //
+
+ protected boolean browseFile() {
+ File currentFile = new File(fnameField.getText());
+
+ FileDialog fd =
+ new FileDialog(this, "Save next session as...", FileDialog.SAVE);
+ fd.setDirectory(currentFile.getParent());
+ fd.setVisible(true);
+ if (fd.getFile() != null) {
+ String newDir = fd.getDirectory();
+ String sep = System.getProperty("file.separator");
+ if (newDir.length() > 0) {
+ if (!sep.equals(newDir.substring(newDir.length() - sep.length())))
+ newDir += sep;
+ }
+ String newFname = newDir + fd.getFile();
+ if (newFname.equals(fnameField.getText())) {
+ fnameField.setText(newFname);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //
+ // Start recording.
+ //
+
+ public void startRecording() {
+ statusLabel.setText("Status: Recording...");
+ statusLabel.setFont(new Font("Helvetica", Font.BOLD, 12));
+ statusLabel.setForeground(Color.red);
+ recordButton.setLabel("Stop recording");
+
+ recording = true;
+
+ viewer.setRecordingStatus(fnameField.getText());
+ }
+
+ //
+ // Stop recording.
+ //
+
+ public void stopRecording() {
+ statusLabel.setText("Status: Not recording.");
+ statusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
+ statusLabel.setForeground(Color.black);
+ recordButton.setLabel("Record");
+
+ recording = false;
+
+ viewer.setRecordingStatus(null);
+ }
+
+ //
+ // Close our window properly.
+ //
+
+ public void windowClosing(WindowEvent evt) {
+ setVisible(false);
+ }
+
+ //
+ // Ignore window events we're not interested in.
+ //
+
+ public void windowActivated(WindowEvent evt) {}
+ public void windowDeactivated (WindowEvent evt) {}
+ public void windowOpened(WindowEvent evt) {}
+ public void windowClosed(WindowEvent evt) {}
+ public void windowIconified(WindowEvent evt) {}
+ public void windowDeiconified(WindowEvent evt) {}
+
+
+ //
+ // Respond to button presses
+ //
+
+ public void actionPerformed(ActionEvent evt) {
+ if (evt.getSource() == browseButton) {
+ if (browseFile() && recording)
+ startRecording();
+
+ } else if (evt.getSource() == recordButton) {
+ if (!recording) {
+ startRecording();
+ } else {
+ stopRecording();
+ fnameField.setText(nextNewFilename(fnameField.getText()));
+ }
+
+ } else if (evt.getSource() == nextButton) {
+ fnameField.setText(nextNewFilename(fnameField.getText()));
+ if (recording)
+ startRecording();
+
+ } else if (evt.getSource() == closeButton) {
+ setVisible(false);
+
+ }
+ }
+}
--- /dev/null
+//
+// Copyright (C) 2002 Cendio Systems. All Rights Reserved.
+// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// ReloginPanel class implements panel with a button for logging in again,
+// after fatal errors or disconnect
+//
+
+package com.tightvnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.applet.*;
+
+//
+// The panel which implements the Relogin button
+//
+
+class ReloginPanel extends Panel implements ActionListener {
+ Button reloginButton;
+ Button closeButton;
+ VncViewer viewer;
+
+ //
+ // Constructor.
+ //
+ public ReloginPanel(VncViewer v) {
+ viewer = v;
+ setLayout(new FlowLayout(FlowLayout.CENTER));
+ reloginButton = new Button("Login again");
+ add(reloginButton);
+ reloginButton.addActionListener(this);
+ if (viewer.inSeparateFrame) {
+ closeButton = new Button("Close window");
+ add(closeButton);
+ closeButton.addActionListener(this);
+ }
+ }
+
+ //
+ // This method is called when a button is pressed.
+ //
+ public synchronized void actionPerformed(ActionEvent evt) {
+ if (viewer.inSeparateFrame)
+ viewer.vncFrame.dispose();
+ if (evt.getSource() == reloginButton)
+ viewer.getAppletContext().showDocument(viewer.getDocumentBase());
+ }
+}
--- /dev/null
+package com.tightvnc.vncviewer;
+
+import java.io.IOException;
+
+//
+// This class is layer between data of private RfbProto class
+// and classes in other packages.
+//
+// For now this class is used by com.tightvnc.decoder.RawDecoder
+//
+public class RfbInputStream {
+ RfbInputStream(RfbProto rfbProto) {
+ rfb = rfbProto;
+ }
+
+ //
+ // Read data methods
+ //
+
+ public void readFully(byte b[]) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ public void readFully(byte b[], int off, int len) throws IOException {
+ rfb.readFully(b, off, len);
+ }
+
+ public int readU32() throws IOException {
+ return rfb.readU32();
+ }
+
+ public int readU8() throws IOException {
+ return rfb.readU8();
+ }
+
+ public int readCompactLen() throws IOException {
+ return rfb.readCompactLen();
+ }
+
+ public int readU16() throws IOException {
+ return rfb.readU16();
+ }
+
+ private RfbProto rfb = null;
+}
--- /dev/null
+//
+// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
+// Copyright (C) 2001-2006 Constantin Kaplinsky. All Rights Reserved.
+// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// RfbProto.java
+//
+
+package com.tightvnc.vncviewer;
+
+import java.io.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.net.Socket;
+import java.util.zip.*;
+
+class RfbProto {
+
+ final static String
+ versionMsg_3_3 = "RFB 003.003\n",
+ versionMsg_3_7 = "RFB 003.007\n",
+ versionMsg_3_8 = "RFB 003.008\n";
+
+ // Vendor signatures: standard VNC/RealVNC, TridiaVNC, and TightVNC
+ final static String
+ StandardVendor = "STDV",
+ TridiaVncVendor = "TRDV",
+ TightVncVendor = "TGHT";
+
+ // Security types
+ final static int
+ SecTypeInvalid = 0,
+ SecTypeNone = 1,
+ SecTypeVncAuth = 2,
+ SecTypeTight = 16;
+
+ // Supported tunneling types
+ final static int
+ NoTunneling = 0;
+ final static String
+ SigNoTunneling = "NOTUNNEL";
+
+ // Supported authentication types
+ final static int
+ AuthNone = 1,
+ AuthVNC = 2,
+ AuthUnixLogin = 129;
+ final static String
+ SigAuthNone = "NOAUTH__",
+ SigAuthVNC = "VNCAUTH_",
+ SigAuthUnixLogin = "ULGNAUTH";
+
+ // VNC authentication results
+ final static int
+ VncAuthOK = 0,
+ VncAuthFailed = 1,
+ VncAuthTooMany = 2;
+
+ // Standard server-to-client messages
+ final static int
+ FramebufferUpdate = 0,
+ SetColourMapEntries = 1,
+ Bell = 2,
+ ServerCutText = 3;
+
+ // Non-standard server-to-client messages
+ final static int
+ EndOfContinuousUpdates = 150;
+ final static String
+ SigEndOfContinuousUpdates = "CUS_EOCU";
+
+ // Standard client-to-server messages
+ final static int
+ SetPixelFormat = 0,
+ FixColourMapEntries = 1,
+ SetEncodings = 2,
+ FramebufferUpdateRequest = 3,
+ KeyboardEvent = 4,
+ PointerEvent = 5,
+ ClientCutText = 6;
+
+ // Non-standard client-to-server messages
+ final static int EnableContinuousUpdates = 150;
+ final static int VideoRectangleSelection = 151;
+ final static int VideoFreeze = 152;
+ final static String SigVideoFreeze = "VD_FREEZ";
+ final static String SigEnableContinuousUpdates = "CUC_ENCU";
+ final static String SigVideoRectangleSelection = "VRECTSEL";
+
+ // Supported encodings and pseudo-encodings
+ final static int
+ EncodingRaw = 0,
+ EncodingCopyRect = 1,
+ EncodingRRE = 2,
+ EncodingCoRRE = 4,
+ EncodingHextile = 5,
+ EncodingZlib = 6,
+ EncodingTight = 7,
+ EncodingZRLE = 16,
+ EncodingCompressLevel0 = 0xFFFFFF00,
+ EncodingQualityLevel0 = 0xFFFFFFE0,
+ EncodingXCursor = 0xFFFFFF10,
+ EncodingRichCursor = 0xFFFFFF11,
+ EncodingPointerPos = 0xFFFFFF18,
+ EncodingLastRect = 0xFFFFFF20,
+ EncodingNewFBSize = 0xFFFFFF21;
+ final static String
+ SigEncodingRaw = "RAW_____",
+ SigEncodingCopyRect = "COPYRECT",
+ SigEncodingRRE = "RRE_____",
+ SigEncodingCoRRE = "CORRE___",
+ SigEncodingHextile = "HEXTILE_",
+ SigEncodingZlib = "ZLIB____",
+ SigEncodingTight = "TIGHT___",
+ SigEncodingZRLE = "ZRLE____",
+ SigEncodingCompressLevel0 = "COMPRLVL",
+ SigEncodingQualityLevel0 = "JPEGQLVL",
+ SigEncodingXCursor = "X11CURSR",
+ SigEncodingRichCursor = "RCHCURSR",
+ SigEncodingPointerPos = "POINTPOS",
+ SigEncodingLastRect = "LASTRECT",
+ SigEncodingNewFBSize = "NEWFBSIZ";
+
+ final static int MaxNormalEncoding = 255;
+
+ // Contstants used in the Hextile decoder
+ final static int
+ HextileRaw = 1,
+ HextileBackgroundSpecified = 2,
+ HextileForegroundSpecified = 4,
+ HextileAnySubrects = 8,
+ HextileSubrectsColoured = 16;
+
+ // Contstants used in the Tight decoder
+ final static int TightMinToCompress = 12;
+ final static int
+ TightExplicitFilter = 0x04,
+ TightFill = 0x08,
+ TightJpeg = 0x09,
+ TightMaxSubencoding = 0x09,
+ TightFilterCopy = 0x00,
+ TightFilterPalette = 0x01,
+ TightFilterGradient = 0x02;
+
+
+ String host;
+ int port;
+ Socket sock;
+ OutputStream os;
+ SessionRecorder rec;
+ boolean inNormalProtocol = false;
+ VncViewer viewer;
+
+ // Input stream is declared private to make sure it can be accessed
+ // only via RfbProto methods. We have to do this because we want to
+ // count how many bytes were read.
+ private DataInputStream is;
+ private long numBytesRead = 0;
+ public long getNumBytesRead() { return numBytesRead; }
+
+ // Java on UNIX does not call keyPressed() on some keys, for example
+ // swedish keys To prevent our workaround to produce duplicate
+ // keypresses on JVMs that actually works, keep track of if
+ // keyPressed() for a "broken" key was called or not.
+ boolean brokenKeyPressed = false;
+
+ // This will be set to true on the first framebuffer update
+ // containing Zlib-, ZRLE- or Tight-encoded data.
+ boolean wereZlibUpdates = false;
+
+ // This fields are needed to show warnings about inefficiently saved
+ // sessions only once per each saved session file.
+ boolean zlibWarningShown;
+ boolean tightWarningShown;
+
+ // Before starting to record each saved session, we set this field
+ // to 0, and increment on each framebuffer update. We don't flush
+ // the SessionRecorder data into the file before the second update.
+ // This allows us to write initial framebuffer update with zero
+ // timestamp, to let the player show initial desktop before
+ // playback.
+ int numUpdatesInSession;
+
+ // Measuring network throughput.
+ boolean timing;
+ long timeWaitedIn100us;
+ long timedKbits;
+
+ // Protocol version and TightVNC-specific protocol options.
+ int serverMajor, serverMinor;
+ int clientMajor, clientMinor;
+ boolean protocolTightVNC;
+ CapsContainer tunnelCaps, authCaps;
+ CapsContainer serverMsgCaps, clientMsgCaps;
+ CapsContainer encodingCaps;
+
+ // "Continuous updates" is a TightVNC-specific feature that allows
+ // receiving framebuffer updates continuously, without sending update
+ // requests. The variables below track the state of this feature.
+ // Initially, continuous updates are disabled. They can be enabled
+ // by calling tryEnableContinuousUpdates() method, and only if this
+ // feature is supported by the server. To disable continuous updates,
+ // tryDisableContinuousUpdates() should be called.
+ private boolean continuousUpdatesActive = false;
+ private boolean continuousUpdatesEnding = false;
+
+ // If true, informs that the RFB socket was closed.
+ private boolean closed;
+
+ //
+ // Constructor. Make TCP connection to RFB server.
+ //
+
+ RfbProto(String h, int p, VncViewer v) throws IOException {
+ viewer = v;
+ host = h;
+ port = p;
+
+ if (viewer.socketFactory == null) {
+ sock = new Socket(host, port);
+ sock.setTcpNoDelay(true);
+ } else {
+ try {
+ Class factoryClass = Class.forName(viewer.socketFactory);
+ SocketFactory factory = (SocketFactory)factoryClass.newInstance();
+ if (viewer.inAnApplet)
+ sock = factory.createSocket(host, port, viewer);
+ else
+ sock = factory.createSocket(host, port, viewer.mainArgs);
+ } catch(Exception e) {
+ e.printStackTrace();
+ throw new IOException(e.getMessage());
+ }
+ }
+ is = new DataInputStream(new BufferedInputStream(sock.getInputStream(),
+ 16384));
+ os = sock.getOutputStream();
+
+ timing = false;
+ timeWaitedIn100us = 5;
+ timedKbits = 0;
+ }
+
+
+ synchronized void close() {
+ try {
+ sock.close();
+ closed = true;
+ System.out.println("RFB socket closed");
+ if (rec != null) {
+ rec.close();
+ rec = null;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ synchronized boolean closed() {
+ return closed;
+ }
+
+ //
+ // Read server's protocol version message
+ //
+
+ void readVersionMsg() throws Exception {
+
+ byte[] b = new byte[12];
+
+ readFully(b);
+
+ 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] != '.')
+ || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9')
+ || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n'))
+ {
+ throw new Exception("Host " + host + " port " + port +
+ " is not an RFB server");
+ }
+
+ serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
+ serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
+
+ if (serverMajor < 3) {
+ throw new Exception("RFB server does not support protocol version 3");
+ }
+ }
+
+
+ //
+ // Write our protocol version message
+ //
+
+ void writeVersionMsg() throws IOException {
+ clientMajor = 3;
+ if (serverMajor > 3 || serverMinor >= 8) {
+ clientMinor = 8;
+ os.write(versionMsg_3_8.getBytes());
+ } else if (serverMinor >= 7) {
+ clientMinor = 7;
+ os.write(versionMsg_3_7.getBytes());
+ } else {
+ clientMinor = 3;
+ os.write(versionMsg_3_3.getBytes());
+ }
+ protocolTightVNC = false;
+ initCapabilities();
+ }
+
+
+ //
+ // Negotiate the authentication scheme.
+ //
+
+ int negotiateSecurity() throws Exception {
+ return (clientMinor >= 7) ?
+ selectSecurityType() : readSecurityType();
+ }
+
+ //
+ // Read security type from the server (protocol version 3.3).
+ //
+
+ int readSecurityType() throws Exception {
+ int secType = readU32();
+
+ switch (secType) {
+ case SecTypeInvalid:
+ readConnFailedReason();
+ return SecTypeInvalid; // should never be executed
+ case SecTypeNone:
+ case SecTypeVncAuth:
+ return secType;
+ default:
+ throw new Exception("Unknown security type from RFB server: " + secType);
+ }
+ }
+
+ //
+ // Select security type from the server's list (protocol versions 3.7/3.8).
+ //
+
+ int selectSecurityType() throws Exception {
+ int secType = SecTypeInvalid;
+
+ // Read the list of secutiry types.
+ int nSecTypes = readU8();
+ if (nSecTypes == 0) {
+ readConnFailedReason();
+ return SecTypeInvalid; // should never be executed
+ }
+ byte[] secTypes = new byte[nSecTypes];
+ readFully(secTypes);
+
+ // Find out if the server supports TightVNC protocol extensions
+ for (int i = 0; i < nSecTypes; i++) {
+ if (secTypes[i] == SecTypeTight) {
+ protocolTightVNC = true;
+ os.write(SecTypeTight);
+ return SecTypeTight;
+ }
+ }
+
+ // Find first supported security type.
+ for (int i = 0; i < nSecTypes; i++) {
+ if (secTypes[i] == SecTypeNone || secTypes[i] == SecTypeVncAuth) {
+ secType = secTypes[i];
+ break;
+ }
+ }
+
+ if (secType == SecTypeInvalid) {
+ throw new Exception("Server did not offer supported security type");
+ } else {
+ os.write(secType);
+ }
+
+ return secType;
+ }
+
+ //
+ // Perform "no authentication".
+ //
+
+ void authenticateNone() throws Exception {
+ if (clientMinor >= 8)
+ readSecurityResult("No authentication");
+ }
+
+ //
+ // Perform standard VNC Authentication.
+ //
+
+ void authenticateVNC(String pw) throws Exception {
+ byte[] challenge = new byte[16];
+ readFully(challenge);
+
+ if (pw.length() > 8)
+ pw = pw.substring(0, 8); // Truncate to 8 chars
+
+ // Truncate password on the first zero byte.
+ int firstZero = pw.indexOf(0);
+ if (firstZero != -1)
+ pw = pw.substring(0, firstZero);
+
+ byte[] key = {0, 0, 0, 0, 0, 0, 0, 0};
+ System.arraycopy(pw.getBytes(), 0, key, 0, pw.length());
+
+ DesCipher des = new DesCipher(key);
+
+ des.encrypt(challenge, 0, challenge, 0);
+ des.encrypt(challenge, 8, challenge, 8);
+
+ os.write(challenge);
+
+ readSecurityResult("VNC authentication");
+ }
+
+ //
+ // Read security result.
+ // Throws an exception on authentication failure.
+ //
+
+ void readSecurityResult(String authType) throws Exception {
+ int securityResult = readU32();
+
+ switch (securityResult) {
+ case VncAuthOK:
+ System.out.println(authType + ": success");
+ break;
+ case VncAuthFailed:
+ if (clientMinor >= 8)
+ readConnFailedReason();
+ throw new Exception(authType + ": failed");
+ case VncAuthTooMany:
+ throw new Exception(authType + ": failed, too many tries");
+ default:
+ throw new Exception(authType + ": unknown result " + securityResult);
+ }
+ }
+
+ //
+ // Read the string describing the reason for a connection failure,
+ // and throw an exception.
+ //
+
+ void readConnFailedReason() throws Exception {
+ int reasonLen = readU32();
+ byte[] reason = new byte[reasonLen];
+ readFully(reason);
+ throw new Exception(new String(reason));
+ }
+
+ //
+ // Initialize capability lists (TightVNC protocol extensions).
+ //
+
+ void initCapabilities() {
+ tunnelCaps = new CapsContainer();
+ authCaps = new CapsContainer();
+ serverMsgCaps = new CapsContainer();
+ clientMsgCaps = new CapsContainer();
+ encodingCaps = new CapsContainer();
+
+ // Supported authentication methods
+ authCaps.add(AuthNone, StandardVendor, SigAuthNone,
+ "No authentication");
+ authCaps.add(AuthVNC, StandardVendor, SigAuthVNC,
+ "Standard VNC password authentication");
+
+ // Supported non-standard server-to-client messages
+ serverMsgCaps.add(EndOfContinuousUpdates, TightVncVendor,
+ SigEndOfContinuousUpdates,
+ "End of continuous updates notification");
+
+ // Supported non-standard client-to-server messages
+ clientMsgCaps.add(EnableContinuousUpdates, TightVncVendor,
+ SigEnableContinuousUpdates,
+ "Enable/disable continuous updates");
+ clientMsgCaps.add(VideoRectangleSelection, TightVncVendor,
+ SigVideoRectangleSelection,
+ "Select a rectangle to be treated as video");
+ clientMsgCaps.add(VideoFreeze, TightVncVendor,
+ SigVideoFreeze,
+ "Disable/enable video rectangle");
+
+ // Supported encoding types
+ encodingCaps.add(EncodingCopyRect, StandardVendor,
+ SigEncodingCopyRect, "Standard CopyRect encoding");
+ encodingCaps.add(EncodingRRE, StandardVendor,
+ SigEncodingRRE, "Standard RRE encoding");
+ encodingCaps.add(EncodingCoRRE, StandardVendor,
+ SigEncodingCoRRE, "Standard CoRRE encoding");
+ encodingCaps.add(EncodingHextile, StandardVendor,
+ SigEncodingHextile, "Standard Hextile encoding");
+ encodingCaps.add(EncodingZRLE, StandardVendor,
+ SigEncodingZRLE, "Standard ZRLE encoding");
+ encodingCaps.add(EncodingZlib, TridiaVncVendor,
+ SigEncodingZlib, "Zlib encoding");
+ encodingCaps.add(EncodingTight, TightVncVendor,
+ SigEncodingTight, "Tight encoding");
+
+ // Supported pseudo-encoding types
+ encodingCaps.add(EncodingCompressLevel0, TightVncVendor,
+ SigEncodingCompressLevel0, "Compression level");
+ encodingCaps.add(EncodingQualityLevel0, TightVncVendor,
+ SigEncodingQualityLevel0, "JPEG quality level");
+ encodingCaps.add(EncodingXCursor, TightVncVendor,
+ SigEncodingXCursor, "X-style cursor shape update");
+ encodingCaps.add(EncodingRichCursor, TightVncVendor,
+ SigEncodingRichCursor, "Rich-color cursor shape update");
+ encodingCaps.add(EncodingPointerPos, TightVncVendor,
+ SigEncodingPointerPos, "Pointer position update");
+ encodingCaps.add(EncodingLastRect, TightVncVendor,
+ SigEncodingLastRect, "LastRect protocol extension");
+ encodingCaps.add(EncodingNewFBSize, TightVncVendor,
+ SigEncodingNewFBSize, "Framebuffer size change");
+ }
+
+ //
+ // Setup tunneling (TightVNC protocol extensions)
+ //
+
+ void setupTunneling() throws IOException {
+ int nTunnelTypes = readU32();
+ if (nTunnelTypes != 0) {
+ readCapabilityList(tunnelCaps, nTunnelTypes);
+
+ // We don't support tunneling yet.
+ writeInt(NoTunneling);
+ }
+ }
+
+ //
+ // Negotiate authentication scheme (TightVNC protocol extensions)
+ //
+
+ int negotiateAuthenticationTight() throws Exception {
+ int nAuthTypes = readU32();
+ if (nAuthTypes == 0)
+ return AuthNone;
+
+ readCapabilityList(authCaps, nAuthTypes);
+ for (int i = 0; i < authCaps.numEnabled(); i++) {
+ int authType = authCaps.getByOrder(i);
+ if (authType == AuthNone || authType == AuthVNC) {
+ writeInt(authType);
+ return authType;
+ }
+ }
+ throw new Exception("No suitable authentication scheme found");
+ }
+
+ //
+ // Read a capability list (TightVNC protocol extensions)
+ //
+
+ void readCapabilityList(CapsContainer caps, int count) throws IOException {
+ int code;
+ byte[] vendor = new byte[4];
+ byte[] name = new byte[8];
+ for (int i = 0; i < count; i++) {
+ code = readU32();
+ readFully(vendor);
+ readFully(name);
+ caps.enable(new CapabilityInfo(code, vendor, name));
+ }
+ }
+
+ //
+ // Write a 32-bit integer into the output stream.
+ //
+
+ void writeInt(int value) throws IOException {
+ byte[] b = new byte[4];
+ b[0] = (byte) ((value >> 24) & 0xff);
+ b[1] = (byte) ((value >> 16) & 0xff);
+ b[2] = (byte) ((value >> 8) & 0xff);
+ b[3] = (byte) (value & 0xff);
+ os.write(b);
+ }
+
+ //
+ // Write the client initialisation message
+ //
+
+ void writeClientInit() throws IOException {
+ if (viewer.options.shareDesktop) {
+ os.write(1);
+ } else {
+ os.write(0);
+ }
+ viewer.options.disableShareDesktop();
+ }
+
+
+ //
+ // Read the server initialisation message
+ //
+
+ String desktopName;
+ int framebufferWidth, framebufferHeight;
+ int bitsPerPixel, depth;
+ boolean bigEndian, trueColour;
+ int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
+
+ void readServerInit() throws IOException {
+ framebufferWidth = readU16();
+ framebufferHeight = readU16();
+ bitsPerPixel = readU8();
+ depth = readU8();
+ bigEndian = (readU8() != 0);
+ trueColour = (readU8() != 0);
+ redMax = readU16();
+ greenMax = readU16();
+ blueMax = readU16();
+ redShift = readU8();
+ greenShift = readU8();
+ blueShift = readU8();
+ byte[] pad = new byte[3];
+ readFully(pad);
+ int nameLength = readU32();
+ byte[] name = new byte[nameLength];
+ readFully(name);
+ desktopName = new String(name);
+
+ // Read interaction capabilities (TightVNC protocol extensions)
+ if (protocolTightVNC) {
+ int nServerMessageTypes = readU16();
+ int nClientMessageTypes = readU16();
+ int nEncodingTypes = readU16();
+ readU16();
+ readCapabilityList(serverMsgCaps, nServerMessageTypes);
+ readCapabilityList(clientMsgCaps, nClientMessageTypes);
+ readCapabilityList(encodingCaps, nEncodingTypes);
+ }
+
+ if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
+ viewer.options.disableContUpdates();
+ }
+
+ inNormalProtocol = true;
+ }
+
+
+ //
+ // Create session file and write initial protocol messages into it.
+ //
+
+ void startSession(String fname) throws IOException {
+ rec = new SessionRecorder(fname);
+ rec.writeHeader();
+ rec.write(versionMsg_3_3.getBytes());
+ rec.writeIntBE(SecTypeNone);
+ rec.writeShortBE(framebufferWidth);
+ rec.writeShortBE(framebufferHeight);
+ byte[] fbsServerInitMsg = {
+ 32, 24, 0, 1, 0,
+ (byte)0xFF, 0, (byte)0xFF, 0, (byte)0xFF,
+ 16, 8, 0, 0, 0, 0
+ };
+ rec.write(fbsServerInitMsg);
+ rec.writeIntBE(desktopName.length());
+ rec.write(desktopName.getBytes());
+ numUpdatesInSession = 0;
+
+ // FIXME: If there were e.g. ZRLE updates only, that should not
+ // affect recording of Zlib and Tight updates. So, actually
+ // we should maintain separate flags for Zlib, ZRLE and
+ // Tight, instead of one ``wereZlibUpdates'' variable.
+ //
+
+ zlibWarningShown = false;
+ tightWarningShown = false;
+ }
+
+ //
+ // Close session file.
+ //
+
+ void closeSession() throws IOException {
+ if (rec != null) {
+ rec.close();
+ rec = null;
+ }
+ }
+
+
+ //
+ // Set new framebuffer size
+ //
+
+ void setFramebufferSize(int width, int height) {
+ framebufferWidth = width;
+ framebufferHeight = height;
+ }
+
+
+ //
+ // Read the server message type
+ //
+
+ int readServerMessageType() throws IOException {
+ int msgType = readU8();
+
+ // If the session is being recorded:
+ if (rec != null) {
+ if (msgType == Bell) { // Save Bell messages in session files.
+ rec.writeByte(msgType);
+ if (numUpdatesInSession > 0)
+ rec.flush();
+ }
+ }
+
+ return msgType;
+ }
+
+
+ //
+ // Read a FramebufferUpdate message
+ //
+
+ int updateNRects;
+
+ void readFramebufferUpdate() throws IOException {
+ skipBytes(1);
+ updateNRects = readU16();
+
+ // If the session is being recorded:
+ if (rec != null) {
+ rec.writeByte(FramebufferUpdate);
+ rec.writeByte(0);
+ rec.writeShortBE(updateNRects);
+ }
+
+ numUpdatesInSession++;
+ }
+
+ //
+ // Returns true if encoding is not pseudo
+ //
+ // FIXME: Find better way to differ pseudo and real encodings
+ //
+
+ boolean isRealDecoderEncoding(int encoding) {
+ if ((encoding >= 1) && (encoding <= 16)) {
+ return true;
+ }
+ return false;
+ }
+
+ // Read a FramebufferUpdate rectangle header
+
+ int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
+
+ void readFramebufferUpdateRectHdr() throws Exception {
+ updateRectX = readU16();
+ updateRectY = readU16();
+ updateRectW = readU16();
+ updateRectH = readU16();
+ updateRectEncoding = readU32();
+
+ if (updateRectEncoding == EncodingZlib ||
+ updateRectEncoding == EncodingZRLE ||
+ updateRectEncoding == EncodingTight)
+ wereZlibUpdates = true;
+
+ // If the session is being recorded:
+ if (rec != null) {
+ if (numUpdatesInSession > 1)
+ rec.flush(); // Flush the output on each rectangle.
+ rec.writeShortBE(updateRectX);
+ rec.writeShortBE(updateRectY);
+ rec.writeShortBE(updateRectW);
+ rec.writeShortBE(updateRectH);
+
+ //
+ // If this is pseudo encoding or CopyRect that write encoding ID
+ // in this place. All real encoding ID will be written to record stream
+ // in decoder classes.
+
+ if (((!isRealDecoderEncoding(updateRectEncoding))) && (rec != null)) {
+ rec.writeIntBE(updateRectEncoding);
+ }
+ }
+
+ if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding)
+ return;
+
+ if (updateRectX + updateRectW > framebufferWidth ||
+ updateRectY + updateRectH > framebufferHeight) {
+ throw new Exception("Framebuffer update rectangle too large: " +
+ updateRectW + "x" + updateRectH + " at (" +
+ updateRectX + "," + updateRectY + ")");
+ }
+ }
+
+ //
+ // Read a ServerCutText message
+ //
+
+ String readServerCutText() throws IOException {
+ skipBytes(3);
+ int len = readU32();
+ byte[] text = new byte[len];
+ readFully(text);
+ return new String(text);
+ }
+
+
+ //
+ // Read an integer in compact representation (1..3 bytes).
+ // Such format is used as a part of the Tight encoding.
+ // Also, this method records data if session recording is active and
+ // the viewer's recordFromBeginning variable is set to true.
+ //
+
+ int readCompactLen() throws IOException {
+ int[] portion = new int[3];
+ portion[0] = readU8();
+ int byteCount = 1;
+ int len = portion[0] & 0x7F;
+ if ((portion[0] & 0x80) != 0) {
+ portion[1] = readU8();
+ byteCount++;
+ len |= (portion[1] & 0x7F) << 7;
+ if ((portion[1] & 0x80) != 0) {
+ portion[2] = readU8();
+ byteCount++;
+ len |= (portion[2] & 0xFF) << 14;
+ }
+ }
+
+ return len;
+ }
+
+
+ //
+ // Write a FramebufferUpdateRequest message
+ //
+
+ void writeFramebufferUpdateRequest(int x, int y, int w, int h,
+ boolean incremental)
+ throws IOException
+ {
+ byte[] b = new byte[10];
+
+ b[0] = (byte) FramebufferUpdateRequest;
+ b[1] = (byte) (incremental ? 1 : 0);
+ b[2] = (byte) ((x >> 8) & 0xff);
+ b[3] = (byte) (x & 0xff);
+ b[4] = (byte) ((y >> 8) & 0xff);
+ b[5] = (byte) (y & 0xff);
+ b[6] = (byte) ((w >> 8) & 0xff);
+ b[7] = (byte) (w & 0xff);
+ b[8] = (byte) ((h >> 8) & 0xff);
+ b[9] = (byte) (h & 0xff);
+
+ os.write(b);
+ }
+
+
+ //
+ // Write a SetPixelFormat message
+ //
+
+ void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian,
+ boolean trueColour,
+ int redMax, int greenMax, int blueMax,
+ int redShift, int greenShift, int blueShift)
+ throws IOException
+ {
+ byte[] b = new byte[20];
+
+ b[0] = (byte) SetPixelFormat;
+ b[4] = (byte) bitsPerPixel;
+ b[5] = (byte) depth;
+ b[6] = (byte) (bigEndian ? 1 : 0);
+ b[7] = (byte) (trueColour ? 1 : 0);
+ b[8] = (byte) ((redMax >> 8) & 0xff);
+ b[9] = (byte) (redMax & 0xff);
+ b[10] = (byte) ((greenMax >> 8) & 0xff);
+ b[11] = (byte) (greenMax & 0xff);
+ b[12] = (byte) ((blueMax >> 8) & 0xff);
+ b[13] = (byte) (blueMax & 0xff);
+ b[14] = (byte) redShift;
+ b[15] = (byte) greenShift;
+ b[16] = (byte) blueShift;
+
+ os.write(b);
+ }
+
+
+ //
+ // Write a FixColourMapEntries message. The values in the red, green and
+ // blue arrays are from 0 to 65535.
+ //
+
+ void writeFixColourMapEntries(int firstColour, int nColours,
+ int[] red, int[] green, int[] blue)
+ throws IOException
+ {
+ byte[] b = new byte[6 + nColours * 6];
+
+ b[0] = (byte) FixColourMapEntries;
+ b[2] = (byte) ((firstColour >> 8) & 0xff);
+ b[3] = (byte) (firstColour & 0xff);
+ b[4] = (byte) ((nColours >> 8) & 0xff);
+ b[5] = (byte) (nColours & 0xff);
+
+ for (int i = 0; i < nColours; i++) {
+ b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff);
+ b[6 + i * 6 + 1] = (byte) (red[i] & 0xff);
+ b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff);
+ b[6 + i * 6 + 3] = (byte) (green[i] & 0xff);
+ b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff);
+ b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff);
+ }
+
+ os.write(b);
+ }
+
+
+ //
+ // Write a SetEncodings message
+ //
+
+ void writeSetEncodings(int[] encs, int len) throws IOException {
+ byte[] b = new byte[4 + 4 * len];
+
+ b[0] = (byte) SetEncodings;
+ b[2] = (byte) ((len >> 8) & 0xff);
+ b[3] = (byte) (len & 0xff);
+
+ for (int i = 0; i < len; i++) {
+ b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff);
+ b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff);
+ b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff);
+ b[7 + 4 * i] = (byte) (encs[i] & 0xff);
+ }
+
+ os.write(b);
+ }
+
+
+ //
+ // Write a ClientCutText message
+ //
+
+ void writeClientCutText(String text) throws IOException {
+ byte[] b = new byte[8 + text.length()];
+
+ b[0] = (byte) ClientCutText;
+ b[4] = (byte) ((text.length() >> 24) & 0xff);
+ b[5] = (byte) ((text.length() >> 16) & 0xff);
+ b[6] = (byte) ((text.length() >> 8) & 0xff);
+ b[7] = (byte) (text.length() & 0xff);
+
+ System.arraycopy(text.getBytes(), 0, b, 8, text.length());
+
+ os.write(b);
+ }
+
+
+ //
+ // A buffer for putting pointer and keyboard events before being sent. This
+ // is to ensure that multiple RFB events generated from a single Java Event
+ // will all be sent in a single network packet. The maximum possible
+ // length is 4 modifier down events, a single key event followed by 4
+ // modifier up events i.e. 9 key events or 72 bytes.
+ //
+
+ byte[] eventBuf = new byte[72];
+ int eventBufLen;
+
+
+ // Useful shortcuts for modifier masks.
+
+ final static int CTRL_MASK = InputEvent.CTRL_MASK;
+ final static int SHIFT_MASK = InputEvent.SHIFT_MASK;
+ final static int META_MASK = InputEvent.META_MASK;
+ final static int ALT_MASK = InputEvent.ALT_MASK;
+
+
+ //
+ // Write a pointer event message. We may need to send modifier key events
+ // around it to set the correct modifier state.
+ //
+
+ int pointerMask = 0;
+
+ void writePointerEvent(MouseEvent evt) throws IOException {
+ int modifiers = evt.getModifiers();
+
+ int mask2 = 2;
+ int mask3 = 4;
+ if (viewer.options.reverseMouseButtons2And3) {
+ mask2 = 4;
+ mask3 = 2;
+ }
+
+ // Note: For some reason, AWT does not set BUTTON1_MASK on left
+ // button presses. Here we think that it was the left button if
+ // modifiers do not include BUTTON2_MASK or BUTTON3_MASK.
+
+ if (evt.getID() == MouseEvent.MOUSE_PRESSED) {
+ if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
+ pointerMask = mask2;
+ modifiers &= ~ALT_MASK;
+ } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
+ pointerMask = mask3;
+ modifiers &= ~META_MASK;
+ } else {
+ pointerMask = 1;
+ }
+ } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) {
+ pointerMask = 0;
+ if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
+ modifiers &= ~ALT_MASK;
+ } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
+ modifiers &= ~META_MASK;
+ }
+ }
+
+ eventBufLen = 0;
+ writeModifierKeyEvents(modifiers);
+
+ int x = evt.getX();
+ int y = evt.getY();
+
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+
+ eventBuf[eventBufLen++] = (byte) PointerEvent;
+ eventBuf[eventBufLen++] = (byte) pointerMask;
+ eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff);
+ eventBuf[eventBufLen++] = (byte) (x & 0xff);
+ eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff);
+ eventBuf[eventBufLen++] = (byte) (y & 0xff);
+
+ //
+ // Always release all modifiers after an "up" event
+ //
+
+ if (pointerMask == 0) {
+ writeModifierKeyEvents(0);
+ }
+
+ os.write(eventBuf, 0, eventBufLen);
+ }
+
+
+ //
+ // Write a key event message. We may need to send modifier key events
+ // around it to set the correct modifier state. Also we need to translate
+ // from the Java key values to the X keysym values used by the RFB protocol.
+ //
+
+ void writeKeyEvent(KeyEvent evt) throws IOException {
+
+ int keyChar = evt.getKeyChar();
+
+ //
+ // Ignore event if only modifiers were pressed.
+ //
+
+ // Some JVMs return 0 instead of CHAR_UNDEFINED in getKeyChar().
+ if (keyChar == 0)
+ keyChar = KeyEvent.CHAR_UNDEFINED;
+
+ if (keyChar == KeyEvent.CHAR_UNDEFINED) {
+ int code = evt.getKeyCode();
+ if (code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_SHIFT ||
+ code == KeyEvent.VK_META || code == KeyEvent.VK_ALT)
+ return;
+ }
+
+ //
+ // Key press or key release?
+ //
+
+ boolean down = (evt.getID() == KeyEvent.KEY_PRESSED);
+
+ int key;
+ if (evt.isActionKey()) {
+
+ //
+ // An action key should be one of the following.
+ // If not then just ignore the event.
+ //
+
+ switch(evt.getKeyCode()) {
+ case KeyEvent.VK_HOME: key = 0xff50; break;
+ case KeyEvent.VK_LEFT: key = 0xff51; break;
+ case KeyEvent.VK_UP: key = 0xff52; break;
+ case KeyEvent.VK_RIGHT: key = 0xff53; break;
+ case KeyEvent.VK_DOWN: key = 0xff54; break;
+ case KeyEvent.VK_PAGE_UP: key = 0xff55; break;
+ case KeyEvent.VK_PAGE_DOWN: key = 0xff56; break;
+ case KeyEvent.VK_END: key = 0xff57; break;
+ case KeyEvent.VK_INSERT: key = 0xff63; break;
+ case KeyEvent.VK_F1: key = 0xffbe; break;
+ case KeyEvent.VK_F2: key = 0xffbf; break;
+ case KeyEvent.VK_F3: key = 0xffc0; break;
+ case KeyEvent.VK_F4: key = 0xffc1; break;
+ case KeyEvent.VK_F5: key = 0xffc2; break;
+ case KeyEvent.VK_F6: key = 0xffc3; break;
+ case KeyEvent.VK_F7: key = 0xffc4; break;
+ case KeyEvent.VK_F8: key = 0xffc5; break;
+ case KeyEvent.VK_F9: key = 0xffc6; break;
+ case KeyEvent.VK_F10: key = 0xffc7; break;
+ case KeyEvent.VK_F11: key = 0xffc8; break;
+ case KeyEvent.VK_F12: key = 0xffc9; break;
+ default:
+ return;
+ }
+
+ } else {
+
+ //
+ // A "normal" key press. Ordinary ASCII characters go straight through.
+ // For CTRL-<letter>, CTRL is sent separately so just send <letter>.
+ // Backspace, tab, return, escape and delete have special keysyms.
+ // Anything else we ignore.
+ //
+
+ key = keyChar;
+
+ if (key < 0x20) {
+ if (evt.isControlDown()) {
+ key += 0x60;
+ } else {
+ switch(key) {
+ case KeyEvent.VK_BACK_SPACE: key = 0xff08; break;
+ case KeyEvent.VK_TAB: key = 0xff09; break;
+ case KeyEvent.VK_ENTER: key = 0xff0d; break;
+ case KeyEvent.VK_ESCAPE: key = 0xff1b; break;
+ }
+ }
+ } else if (key == 0x7f) {
+ // Delete
+ key = 0xffff;
+ } else if (key > 0xff) {
+ // JDK1.1 on X incorrectly passes some keysyms straight through,
+ // so we do too. JDK1.1.4 seems to have fixed this.
+ // The keysyms passed are 0xff00 .. XK_BackSpace .. XK_Delete
+ // Also, we pass through foreign currency keysyms (0x20a0..0x20af).
+ if ((key < 0xff00 || key > 0xffff) &&
+ !(key >= 0x20a0 && key <= 0x20af))
+ return;
+ }
+ }
+
+ // Fake keyPresses for keys that only generates keyRelease events
+ if ((key == 0xe5) || (key == 0xc5) || // XK_aring / XK_Aring
+ (key == 0xe4) || (key == 0xc4) || // XK_adiaeresis / XK_Adiaeresis
+ (key == 0xf6) || (key == 0xd6) || // XK_odiaeresis / XK_Odiaeresis
+ (key == 0xa7) || (key == 0xbd) || // XK_section / XK_onehalf
+ (key == 0xa3)) { // XK_sterling
+ // Make sure we do not send keypress events twice on platforms
+ // with correct JVMs (those that actually report KeyPress for all
+ // keys)
+ if (down)
+ brokenKeyPressed = true;
+
+ if (!down && !brokenKeyPressed) {
+ // We've got a release event for this key, but haven't received
+ // a press. Fake it.
+ eventBufLen = 0;
+ writeModifierKeyEvents(evt.getModifiers());
+ writeKeyEvent(key, true);
+ os.write(eventBuf, 0, eventBufLen);
+ }
+
+ if (!down)
+ brokenKeyPressed = false;
+ }
+
+ eventBufLen = 0;
+ writeModifierKeyEvents(evt.getModifiers());
+ writeKeyEvent(key, down);
+
+ // Always release all modifiers after an "up" event
+ if (!down)
+ writeModifierKeyEvents(0);
+
+ os.write(eventBuf, 0, eventBufLen);
+ }
+
+
+ //
+ // Add a raw key event with the given X keysym to eventBuf.
+ //
+
+ void writeKeyEvent(int keysym, boolean down) {
+ eventBuf[eventBufLen++] = (byte) KeyboardEvent;
+ eventBuf[eventBufLen++] = (byte) (down ? 1 : 0);
+ eventBuf[eventBufLen++] = (byte) 0;
+ eventBuf[eventBufLen++] = (byte) 0;
+ eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff);
+ eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff);
+ eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff);
+ eventBuf[eventBufLen++] = (byte) (keysym & 0xff);
+ }
+
+
+ //
+ // Write key events to set the correct modifier state.
+ //
+
+ int oldModifiers = 0;
+
+ void writeModifierKeyEvents(int newModifiers) {
+ if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK))
+ writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0);
+
+ if ((newModifiers & SHIFT_MASK) != (oldModifiers & SHIFT_MASK))
+ writeKeyEvent(0xffe1, (newModifiers & SHIFT_MASK) != 0);
+
+ if ((newModifiers & META_MASK) != (oldModifiers & META_MASK))
+ writeKeyEvent(0xffe7, (newModifiers & META_MASK) != 0);
+
+ if ((newModifiers & ALT_MASK) != (oldModifiers & ALT_MASK))
+ writeKeyEvent(0xffe9, (newModifiers & ALT_MASK) != 0);
+
+ oldModifiers = newModifiers;
+ }
+
+
+ //
+ // Enable continuous updates for the specified area of the screen (but
+ // only if EnableContinuousUpdates message is supported by the server).
+ //
+
+ void tryEnableContinuousUpdates(int x, int y, int w, int h)
+ throws IOException
+ {
+ if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
+ System.out.println("Continuous updates not supported by the server");
+ return;
+ }
+
+ if (continuousUpdatesActive) {
+ System.out.println("Continuous updates already active");
+ return;
+ }
+
+ byte[] b = new byte[10];
+
+ b[0] = (byte) EnableContinuousUpdates;
+ b[1] = (byte) 1; // enable
+ b[2] = (byte) ((x >> 8) & 0xff);
+ b[3] = (byte) (x & 0xff);
+ b[4] = (byte) ((y >> 8) & 0xff);
+ b[5] = (byte) (y & 0xff);
+ b[6] = (byte) ((w >> 8) & 0xff);
+ b[7] = (byte) (w & 0xff);
+ b[8] = (byte) ((h >> 8) & 0xff);
+ b[9] = (byte) (h & 0xff);
+
+ os.write(b);
+
+ continuousUpdatesActive = true;
+ System.out.println("Continuous updates activated");
+ }
+
+
+ //
+ // Disable continuous updates (only if EnableContinuousUpdates message
+ // is supported by the server).
+ //
+
+ void tryDisableContinuousUpdates() throws IOException
+ {
+ if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
+ System.out.println("Continuous updates not supported by the server");
+ return;
+ }
+
+ if (!continuousUpdatesActive) {
+ System.out.println("Continuous updates already disabled");
+ return;
+ }
+
+ if (continuousUpdatesEnding)
+ return;
+
+ byte[] b = { (byte)EnableContinuousUpdates, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ os.write(b);
+
+ if (!serverMsgCaps.isEnabled(EndOfContinuousUpdates)) {
+ // If the server did not advertise support for the
+ // EndOfContinuousUpdates message (should not normally happen
+ // when EnableContinuousUpdates is supported), then we clear
+ // 'continuousUpdatesActive' variable immediately. Normally,
+ // it will be reset on receiving EndOfContinuousUpdates message
+ // from the server.
+ continuousUpdatesActive = false;
+ } else {
+ // Indicate that we are waiting for EndOfContinuousUpdates.
+ continuousUpdatesEnding = true;
+ }
+ }
+
+
+ //
+ // Process EndOfContinuousUpdates message received from the server.
+ //
+
+ void endOfContinuousUpdates()
+ {
+ continuousUpdatesActive = false;
+ continuousUpdatesEnding = false;
+ }
+
+
+ //
+ // Check if continuous updates are in effect.
+ //
+
+ boolean continuousUpdatesAreActive()
+ {
+ return continuousUpdatesActive;
+ }
+
+ /**
+ * Send a rectangle selection to be treated as video by the server (but
+ * only if VideoRectangleSelection message is supported by the server).
+ * @param rect specifies coordinates and size of the rectangule.
+ * @throws java.io.IOException
+ */
+ void trySendVideoSelection(Rectangle rect) throws IOException
+ {
+ if (!clientMsgCaps.isEnabled(VideoRectangleSelection)) {
+ System.out.println("Video area selection is not supported by the server");
+ return;
+ }
+
+ // Send zero coordinates if the rectangle is empty.
+ if (rect.isEmpty()) {
+ rect = new Rectangle();
+ }
+
+ int x = rect.x;
+ int y = rect.y;
+ int w = rect.width;
+ int h = rect.height;
+
+ byte[] b = new byte[10];
+
+ b[0] = (byte) VideoRectangleSelection;
+ b[1] = (byte) 0; // reserved
+ b[2] = (byte) ((x >> 8) & 0xff);
+ b[3] = (byte) (x & 0xff);
+ b[4] = (byte) ((y >> 8) & 0xff);
+ b[5] = (byte) (y & 0xff);
+ b[6] = (byte) ((w >> 8) & 0xff);
+ b[7] = (byte) (w & 0xff);
+ b[8] = (byte) ((h >> 8) & 0xff);
+ b[9] = (byte) (h & 0xff);
+
+ os.write(b);
+
+ System.out.println("Video rectangle selection message sent");
+ }
+
+ void trySendVideoFreeze(boolean freeze) throws IOException
+ {
+ if (!clientMsgCaps.isEnabled(VideoFreeze)) {
+ System.out.println("Video freeze is not supported by the server");
+ return;
+ }
+
+ byte[] b = new byte[2];
+ byte fb = 0;
+ if (freeze) {
+ fb = 1;
+ }
+
+ b[0] = (byte) VideoFreeze;
+ b[1] = (byte) fb;
+
+ os.write(b);
+
+ System.out.println("Video freeze selection message sent");
+ }
+
+ public void startTiming() {
+ timing = true;
+
+ // Carry over up to 1s worth of previous rate for smoothing.
+
+ if (timeWaitedIn100us > 10000) {
+ timedKbits = timedKbits * 10000 / timeWaitedIn100us;
+ timeWaitedIn100us = 10000;
+ }
+ }
+
+ public void stopTiming() {
+ timing = false;
+ if (timeWaitedIn100us < timedKbits/2)
+ timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
+ }
+
+ public long kbitsPerSecond() {
+ return timedKbits * 10000 / timeWaitedIn100us;
+ }
+
+ public long timeWaited() {
+ return timeWaitedIn100us;
+ }
+
+ //
+ // Methods for reading data via our DataInputStream member variable (is).
+ //
+ // In addition to reading data, the readFully() methods updates variables
+ // used to estimate data throughput.
+ //
+
+ public void readFully(byte b[]) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ public void readFully(byte b[], int off, int len) throws IOException {
+ long before = 0;
+ if (timing)
+ before = System.currentTimeMillis();
+
+ is.readFully(b, off, len);
+
+ if (timing) {
+ long after = System.currentTimeMillis();
+ long newTimeWaited = (after - before) * 10;
+ int newKbits = len * 8 / 1000;
+
+ // limit rate to between 10kbit/s and 40Mbit/s
+
+ if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
+ if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
+
+ timeWaitedIn100us += newTimeWaited;
+ timedKbits += newKbits;
+ }
+
+ numBytesRead += len;
+ }
+
+ final int available() throws IOException {
+ return is.available();
+ }
+
+ // FIXME: DataInputStream::skipBytes() is not guaranteed to skip
+ // exactly n bytes. Probably we don't want to use this method.
+ final int skipBytes(int n) throws IOException {
+ int r = is.skipBytes(n);
+ numBytesRead += r;
+ return r;
+ }
+
+ final int readU8() throws IOException {
+ int r = is.readUnsignedByte();
+ numBytesRead++;
+ return r;
+ }
+
+ final int readU16() throws IOException {
+ int r = is.readUnsignedShort();
+ numBytesRead += 2;
+ return r;
+ }
+
+ final int readU32() throws IOException {
+ int r = is.readInt();
+ numBytesRead += 4;
+ return r;
+ }
+}
--- /dev/null
+//
+// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// SessionRecorder is a class to write FBS (FrameBuffer Stream) files.
+// FBS files are used to save RFB sessions for later playback.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.io.*;
+
+class SessionRecorder {
+
+ protected FileOutputStream f;
+ protected DataOutputStream df;
+ protected long startTime, lastTimeOffset;
+
+ protected byte[] buffer;
+ protected int bufferSize;
+ protected int bufferBytes;
+
+ public SessionRecorder(String name, int bufsize) throws IOException {
+ f = new FileOutputStream(name);
+ df = new DataOutputStream(f);
+ startTime = System.currentTimeMillis();
+ lastTimeOffset = 0;
+
+ bufferSize = bufsize;
+ bufferBytes = 0;
+ buffer = new byte[bufferSize];
+ }
+
+ public SessionRecorder(String name) throws IOException {
+ this(name, 65536);
+ }
+
+ //
+ // Close the file, free resources.
+ //
+
+ public void close() throws IOException {
+ try {
+ flush();
+ } catch (IOException e) {
+ }
+
+ df = null;
+ f.close();
+ f = null;
+ buffer = null;
+ }
+
+ //
+ // Write the FBS file header as defined in the rfbproxy utility.
+ //
+
+ public void writeHeader() throws IOException {
+ df.write("FBS 001.000\n".getBytes());
+ }
+
+ //
+ // Write one byte.
+ //
+
+ public void writeByte(int b) throws IOException {
+ prepareWriting();
+ buffer[bufferBytes++] = (byte)b;
+ }
+
+ //
+ // Write 16-bit value, big-endian.
+ //
+
+ public void writeShortBE(int v) throws IOException {
+ prepareWriting();
+ buffer[bufferBytes++] = (byte)(v >> 8);
+ buffer[bufferBytes++] = (byte)v;
+ }
+
+ //
+ // Write 32-bit value, big-endian.
+ //
+
+ public void writeIntBE(int v) throws IOException {
+ prepareWriting();
+ buffer[bufferBytes] = (byte)(v >> 24);
+ buffer[bufferBytes + 1] = (byte)(v >> 16);
+ buffer[bufferBytes + 2] = (byte)(v >> 8);
+ buffer[bufferBytes + 3] = (byte)v;
+ bufferBytes += 4;
+ }
+
+ //
+ // Write 16-bit value, little-endian.
+ //
+
+ public void writeShortLE(int v) throws IOException {
+ prepareWriting();
+ buffer[bufferBytes++] = (byte)v;
+ buffer[bufferBytes++] = (byte)(v >> 8);
+ }
+
+ //
+ // Write 32-bit value, little-endian.
+ //
+
+ public void writeIntLE(int v) throws IOException {
+ prepareWriting();
+ buffer[bufferBytes] = (byte)v;
+ buffer[bufferBytes + 1] = (byte)(v >> 8);
+ buffer[bufferBytes + 2] = (byte)(v >> 16);
+ buffer[bufferBytes + 3] = (byte)(v >> 24);
+ bufferBytes += 4;
+ }
+
+ //
+ // Write byte arrays.
+ //
+
+ public void write(byte b[], int off, int len) throws IOException {
+ prepareWriting();
+ while (len > 0) {
+ if (bufferBytes > bufferSize - 4)
+ flush(false);
+
+ int partLen;
+ if (bufferBytes + len > bufferSize) {
+ partLen = bufferSize - bufferBytes;
+ } else {
+ partLen = len;
+ }
+ System.arraycopy(b, off, buffer, bufferBytes, partLen);
+ bufferBytes += partLen;
+ off += partLen;
+ len -= partLen;
+ }
+ }
+
+ public void write(byte b[]) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ //
+ // Flush the output. This method saves buffered data in the
+ // underlying file object adding data sizes and timestamps. If the
+ // updateTimeOffset is set to false, then the current time offset
+ // will not be changed for next write operation.
+ //
+
+ public void flush(boolean updateTimeOffset) throws IOException {
+ if (bufferBytes > 0) {
+ df.writeInt(bufferBytes);
+ df.write(buffer, 0, (bufferBytes + 3) & 0x7FFFFFFC);
+ df.writeInt((int)lastTimeOffset);
+ bufferBytes = 0;
+ if (updateTimeOffset)
+ lastTimeOffset = -1;
+ }
+ }
+
+ public void flush() throws IOException {
+ flush(true);
+ }
+
+ //
+ // Before writing any data, remember time offset and flush the
+ // buffer before it becomes full.
+ //
+
+ protected void prepareWriting() throws IOException {
+ if (lastTimeOffset == -1)
+ lastTimeOffset = System.currentTimeMillis() - startTime;
+ if (bufferBytes > bufferSize - 4)
+ flush(false);
+ }
+
+}
+
--- /dev/null
+//
+// Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// SocketFactory.java describes an interface used to substitute the
+// standard Socket class by its alternative implementations.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.applet.*;
+import java.net.*;
+import java.io.*;
+
+public interface SocketFactory {
+
+ public Socket createSocket(String host, int port, Applet applet)
+ throws IOException;
+
+ public Socket createSocket(String host, int port, String[] args)
+ throws IOException;
+}
--- /dev/null
+//
+// Copyright (C) 2004 Horizon Wimba. All Rights Reserved.
+// Copyright (C) 2001-2003 HorizonLive.com, Inc. All Rights Reserved.
+// Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
+// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+package com.tightvnc.vncviewer;
+
+import com.tightvnc.decoder.CoRREDecoder;
+import com.tightvnc.decoder.CopyRectDecoder;
+import com.tightvnc.decoder.HextileDecoder;
+import com.tightvnc.decoder.RREDecoder;
+import com.tightvnc.decoder.RawDecoder;
+import com.tightvnc.decoder.TightDecoder;
+import com.tightvnc.decoder.ZRLEDecoder;
+import com.tightvnc.decoder.ZlibDecoder;
+import com.tightvnc.decoder.common.Repaintable;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import java.io.*;
+import java.lang.*;
+import java.util.zip.*;
+
+
+//
+// VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
+//
+
+class VncCanvas extends Canvas
+ implements KeyListener, MouseListener, MouseMotionListener, Repaintable, Runnable {
+
+ VncViewer viewer;
+ RfbProto rfb;
+ ColorModel cm8, cm24;
+ int bytesPixel;
+
+ int maxWidth = 0, maxHeight = 0;
+ int scalingFactor;
+ int scaledWidth, scaledHeight;
+
+ Image memImage;
+ Graphics memGraphics;
+
+ //
+ // Decoders
+ //
+
+ RawDecoder rawDecoder;
+ RREDecoder rreDecoder;
+ CoRREDecoder correDecoder;
+ ZlibDecoder zlibDecoder;
+ HextileDecoder hextileDecoder;
+ ZRLEDecoder zrleDecoder;
+ TightDecoder tightDecoder;
+ CopyRectDecoder copyRectDecoder;
+
+ // Base decoder decoders array
+ RawDecoder []decoders = null;
+
+ // Update statistics.
+ long statStartTime; // time on first framebufferUpdateRequest
+ long statNumUpdates; // counter for FramebufferUpdate messages
+ long statNumTotalRects; // rectangles in FramebufferUpdate messages
+ long statNumPixelRects; // the same, but excluding pseudo-rectangles
+ long statNumRectsTight; // Tight-encoded rectangles (including JPEG)
+ long statNumRectsTightJPEG; // JPEG-compressed Tight-encoded rectangles
+ long statNumRectsZRLE; // ZRLE-encoded rectangles
+ long statNumRectsHextile; // Hextile-encoded rectangles
+ long statNumRectsRaw; // Raw-encoded rectangles
+ long statNumRectsCopy; // CopyRect rectangles
+ long statNumBytesEncoded; // number of bytes in updates, as received
+ long statNumBytesDecoded; // number of bytes, as if Raw encoding was used
+
+ // True if we process keyboard and mouse events.
+ boolean inputEnabled;
+
+ // True if was no one auto resize of canvas
+ boolean isFirstSizeAutoUpdate = true;
+
+ // Members for limiting sending mouse events to server
+ long lastMouseEventSendTime = System.currentTimeMillis();
+ long mouseMaxFreq = 20;
+
+ //
+ // The constructors.
+ //
+
+ public VncCanvas(VncViewer v, int maxWidth_, int maxHeight_)
+ throws IOException {
+
+ viewer = v;
+ maxWidth = maxWidth_;
+ maxHeight = maxHeight_;
+
+ rfb = viewer.rfb;
+ scalingFactor = viewer.options.scalingFactor;
+
+ cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
+ cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
+
+ //
+ // Create decoders
+ //
+
+ // Input stream for decoders
+ RfbInputStream rfbis = new RfbInputStream(rfb);
+ // Create output stream for session recording
+ RecordOutputStream ros = new RecordOutputStream(rfb);
+
+ rawDecoder = new RawDecoder(memGraphics, rfbis);
+ rreDecoder = new RREDecoder(memGraphics, rfbis);
+ correDecoder = new CoRREDecoder(memGraphics, rfbis);
+ hextileDecoder = new HextileDecoder(memGraphics, rfbis);
+ tightDecoder = new TightDecoder(memGraphics, rfbis);
+ zlibDecoder = new ZlibDecoder(memGraphics, rfbis);
+ zrleDecoder = new ZRLEDecoder(memGraphics, rfbis);
+ copyRectDecoder = new CopyRectDecoder(memGraphics, rfbis);
+
+ //
+ // Set data for decoders that needs extra parameters
+ //
+
+ hextileDecoder.setRepainableControl(this);
+ tightDecoder.setRepainableControl(this);
+
+ //
+ // Create array that contains our decoders
+ //
+
+ decoders = new RawDecoder[8];
+ decoders[0] = rawDecoder;
+ decoders[1] = rreDecoder;
+ decoders[2] = correDecoder;
+ decoders[3] = hextileDecoder;
+ decoders[4] = zlibDecoder;
+ decoders[5] = tightDecoder;
+ decoders[6] = zrleDecoder;
+ decoders[7] = copyRectDecoder;
+
+ //
+ // Set session recorder for decoders
+ //
+
+ for (int i = 0; i < decoders.length; i++) {
+ decoders[i].setDataOutputStream(ros);
+ }
+
+ setPixelFormat();
+ resetSelection();
+
+ inputEnabled = false;
+ if (!viewer.options.viewOnly)
+ enableInput(true);
+
+ // Enable mouse and keyboard event listeners.
+ addKeyListener(this);
+ addMouseListener(this);
+ addMouseMotionListener(this);
+
+ // Create thread, that will send mouse movement events
+ // to VNC server.
+ Thread mouseThread = new Thread(this);
+ mouseThread.start();
+ }
+
+ public VncCanvas(VncViewer v) throws IOException {
+ this(v, 0, 0);
+ }
+
+ //
+ // Callback methods to determine geometry of our Component.
+ //
+
+ public Dimension getPreferredSize() {
+ return new Dimension(scaledWidth, scaledHeight);
+ }
+
+ public Dimension getMinimumSize() {
+ return new Dimension(scaledWidth, scaledHeight);
+ }
+
+ public Dimension getMaximumSize() {
+ return new Dimension(scaledWidth, scaledHeight);
+ }
+
+ //
+ // All painting is performed here.
+ //
+
+ public void update(Graphics g) {
+ paint(g);
+ }
+
+ public void paint(Graphics g) {
+ synchronized(memImage) {
+ if (rfb.framebufferWidth == scaledWidth) {
+ g.drawImage(memImage, 0, 0, null);
+ } else {
+ paintScaledFrameBuffer(g);
+ }
+ }
+ if (showSoftCursor) {
+ int x0 = cursorX - hotX, y0 = cursorY - hotY;
+ Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight);
+ if (r.intersects(g.getClipBounds())) {
+ g.drawImage(softCursor, x0, y0, null);
+ }
+ }
+ if (isInSelectionMode()) {
+ Rectangle r = getSelection(true);
+ if (r.width > 0 && r.height > 0) {
+ // Don't forget to correct the coordinates for the right and bottom
+ // borders, so that the borders are the part of the selection.
+ r.width -= 1;
+ r.height -= 1;
+ g.setXORMode(Color.yellow);
+ g.drawRect(r.x, r.y, r.width, r.height);
+ }
+ }
+ }
+
+ public void paintScaledFrameBuffer(Graphics g) {
+ g.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null);
+ }
+
+ //
+ // Start/stop receiving mouse events. Keyboard events are received
+ // even in view-only mode, because we want to map the 'r' key to the
+ // screen refreshing function.
+ //
+
+ public synchronized void enableInput(boolean enable) {
+ if (enable && !inputEnabled) {
+ inputEnabled = true;
+ if (viewer.showControls) {
+ viewer.buttonPanel.enableRemoteAccessControls(true);
+ }
+ createSoftCursor(); // scaled cursor
+ } else if (!enable && inputEnabled) {
+ inputEnabled = false;
+ if (viewer.showControls) {
+ viewer.buttonPanel.enableRemoteAccessControls(false);
+ }
+ createSoftCursor(); // non-scaled cursor
+ }
+ }
+
+ public void setPixelFormat() throws IOException {
+ if (viewer.options.eightBitColors) {
+ rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6);
+ bytesPixel = 1;
+ } else {
+ rfb.writeSetPixelFormat(32, 24, false, true, 255, 255, 255, 16, 8, 0);
+ bytesPixel = 4;
+ }
+ updateFramebufferSize();
+ }
+
+ void setScalingFactor(int sf) {
+ scalingFactor = sf;
+ updateFramebufferSize();
+ invalidate();
+ }
+
+ void updateFramebufferSize() {
+
+ // Useful shortcuts.
+ int fbWidth = rfb.framebufferWidth;
+ int fbHeight = rfb.framebufferHeight;
+
+ // FIXME: This part of code must be in VncViewer i think
+ if (viewer.options.autoScale) {
+ if (viewer.inAnApplet) {
+ maxWidth = viewer.getWidth();
+ maxHeight = viewer.getHeight();
+ } else {
+ if (viewer.vncFrame != null) {
+ if (isFirstSizeAutoUpdate) {
+ isFirstSizeAutoUpdate = false;
+ Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
+ maxWidth = (int)screenSize.getWidth() - 100;
+ maxHeight = (int)screenSize.getHeight() - 100;
+ viewer.vncFrame.setSize(maxWidth, maxHeight);
+ } else {
+ viewer.desktopScrollPane.doLayout();
+ maxWidth = viewer.desktopScrollPane.getWidth();
+ maxHeight = viewer.desktopScrollPane.getHeight();
+ }
+ } else {
+ maxWidth = fbWidth;
+ maxHeight = fbHeight;
+ }
+ }
+ int f1 = maxWidth * 100 / fbWidth;
+ int f2 = maxHeight * 100 / fbHeight;
+ scalingFactor = Math.min(f1, f2);
+ if (scalingFactor > 100)
+ scalingFactor = 100;
+ System.out.println("Scaling desktop at " + scalingFactor + "%");
+ }
+
+ // Update scaled framebuffer geometry.
+ scaledWidth = (fbWidth * scalingFactor + 50) / 100;
+ scaledHeight = (fbHeight * scalingFactor + 50) / 100;
+
+ // Create new off-screen image either if it does not exist, or if
+ // its geometry should be changed. It's not necessary to replace
+ // existing image if only pixel format should be changed.
+ if (memImage == null) {
+ memImage = viewer.vncContainer.createImage(fbWidth, fbHeight);
+ memGraphics = memImage.getGraphics();
+ } else if (memImage.getWidth(null) != fbWidth ||
+ memImage.getHeight(null) != fbHeight) {
+ synchronized(memImage) {
+ memImage = viewer.vncContainer.createImage(fbWidth, fbHeight);
+ memGraphics = memImage.getGraphics();
+ }
+ }
+
+ //
+ // Update decoders
+ //
+
+ //
+ // FIXME: Why decoders can be null here?
+ //
+
+ if (decoders != null) {
+ for (int i = 0; i < decoders.length; i++) {
+ //
+ // Set changes to every decoder that we can use
+ //
+
+ decoders[i].setBPP(bytesPixel);
+ decoders[i].setFrameBufferSize(fbWidth, fbHeight);
+ decoders[i].setGraphics(memGraphics);
+
+ //
+ // Update decoder
+ //
+
+ decoders[i].update();
+ }
+ }
+
+ // FIXME: This part of code must be in VncViewer i think
+ // Update the size of desktop containers.
+ if (viewer.inSeparateFrame) {
+ if (viewer.desktopScrollPane != null) {
+ if (!viewer.options.autoScale) {
+ resizeDesktopFrame();
+ } else {
+ setSize(scaledWidth, scaledHeight);
+ viewer.desktopScrollPane.setSize(maxWidth + 200,
+ maxHeight + 200);
+ }
+ }
+ } else {
+ setSize(scaledWidth, scaledHeight);
+ }
+ viewer.moveFocusToDesktop();
+ }
+
+ void resizeDesktopFrame() {
+ setSize(scaledWidth, scaledHeight);
+
+ // FIXME: Find a better way to determine correct size of a
+ // ScrollPane. -- const
+ Insets insets = viewer.desktopScrollPane.getInsets();
+ viewer.desktopScrollPane.setSize(scaledWidth +
+ 2 * Math.min(insets.left, insets.right),
+ scaledHeight +
+ 2 * Math.min(insets.top, insets.bottom));
+
+ viewer.vncFrame.pack();
+
+ // Try to limit the frame size to the screen size.
+
+ Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
+ Dimension frameSize = viewer.vncFrame.getSize();
+ Dimension newSize = frameSize;
+
+ // Reduce Screen Size by 30 pixels in each direction;
+ // This is a (poor) attempt to account for
+ // 1) Menu bar on Macintosh (should really also account for
+ // Dock on OSX). Usually 22px on top of screen.
+ // 2) Taxkbar on Windows (usually about 28 px on bottom)
+ // 3) Other obstructions.
+
+ screenSize.height -= 30;
+ screenSize.width -= 30;
+
+ boolean needToResizeFrame = false;
+ if (frameSize.height > screenSize.height) {
+ newSize.height = screenSize.height;
+ needToResizeFrame = true;
+ }
+ if (frameSize.width > screenSize.width) {
+ newSize.width = screenSize.width;
+ needToResizeFrame = true;
+ }
+ if (needToResizeFrame) {
+ viewer.vncFrame.setSize(newSize);
+ }
+
+ viewer.desktopScrollPane.doLayout();
+ }
+
+ //
+ // processNormalProtocol() - executed by the rfbThread to deal with the
+ // RFB socket.
+ //
+
+ public void processNormalProtocol() throws Exception {
+
+ // Start/stop session recording if necessary.
+ viewer.checkRecordingStatus();
+
+ rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
+ rfb.framebufferHeight, false);
+
+ if (viewer.options.continuousUpdates) {
+ rfb.tryEnableContinuousUpdates(0, 0, rfb.framebufferWidth,
+ rfb.framebufferHeight);
+ }
+
+ resetStats();
+ boolean statsRestarted = false;
+
+ //
+ // main dispatch loop
+ //
+
+ while (true) {
+
+ // Read message type from the server.
+ int msgType = rfb.readServerMessageType();
+
+ // Process the message depending on its type.
+ switch (msgType) {
+ case RfbProto.FramebufferUpdate:
+
+ if (statNumUpdates == viewer.debugStatsExcludeUpdates &&
+ !statsRestarted) {
+ resetStats();
+ statsRestarted = true;
+ } else if (statNumUpdates == viewer.debugStatsMeasureUpdates &&
+ statsRestarted) {
+ viewer.disconnect();
+ }
+
+ rfb.readFramebufferUpdate();
+ statNumUpdates++;
+
+ boolean cursorPosReceived = false;
+
+ for (int i = 0; i < rfb.updateNRects; i++) {
+
+ rfb.readFramebufferUpdateRectHdr();
+ statNumTotalRects++;
+ int rx = rfb.updateRectX, ry = rfb.updateRectY;
+ int rw = rfb.updateRectW, rh = rfb.updateRectH;
+
+ if (rfb.updateRectEncoding == rfb.EncodingLastRect)
+ break;
+
+ if (rfb.updateRectEncoding == rfb.EncodingNewFBSize) {
+ rfb.setFramebufferSize(rw, rh);
+ updateFramebufferSize();
+ break;
+ }
+
+ if (rfb.updateRectEncoding == rfb.EncodingXCursor ||
+ rfb.updateRectEncoding == rfb.EncodingRichCursor) {
+ handleCursorShapeUpdate(rfb.updateRectEncoding, rx, ry, rw, rh);
+ continue;
+ }
+
+ if (rfb.updateRectEncoding == rfb.EncodingPointerPos) {
+ softCursorMove(rx, ry);
+ cursorPosReceived = true;
+ continue;
+ }
+
+ long numBytesReadBefore = rfb.getNumBytesRead();
+
+ rfb.startTiming();
+
+ switch (rfb.updateRectEncoding) {
+ case RfbProto.EncodingRaw:
+ statNumRectsRaw++;
+ handleRawRect(rx, ry, rw, rh);
+ break;
+ case RfbProto.EncodingCopyRect:
+ statNumRectsCopy++;
+ handleCopyRect(rx, ry, rw, rh);
+ break;
+ case RfbProto.EncodingRRE:
+ handleRRERect(rx, ry, rw, rh);
+ break;
+ case RfbProto.EncodingCoRRE:
+ handleCoRRERect(rx, ry, rw, rh);
+ break;
+ case RfbProto.EncodingHextile:
+ statNumRectsHextile++;
+ handleHextileRect(rx, ry, rw, rh);
+ break;
+ case RfbProto.EncodingZRLE:
+ statNumRectsZRLE++;
+ handleZRLERect(rx, ry, rw, rh);
+ break;
+ case RfbProto.EncodingZlib:
+ handleZlibRect(rx, ry, rw, rh);
+ break;
+ case RfbProto.EncodingTight:
+ if (tightDecoder != null) {
+ statNumRectsTightJPEG = tightDecoder.getNumJPEGRects();
+ //statNumRectsTight = tightDecoder.getNumTightRects();
+ }
+ statNumRectsTight++;
+ handleTightRect(rx, ry, rw, rh);
+ break;
+ default:
+ throw new Exception("Unknown RFB rectangle encoding " +
+ rfb.updateRectEncoding);
+ }
+
+ rfb.stopTiming();
+
+ statNumPixelRects++;
+ statNumBytesDecoded += rw * rh * bytesPixel;
+ statNumBytesEncoded +=
+ (int)(rfb.getNumBytesRead() - numBytesReadBefore);
+ }
+
+ boolean fullUpdateNeeded = false;
+
+ // Start/stop session recording if necessary. Request full
+ // update if a new session file was opened.
+ if (viewer.checkRecordingStatus())
+ fullUpdateNeeded = true;
+
+ // Defer framebuffer update request if necessary. But wake up
+ // immediately on keyboard or mouse event. Also, don't sleep
+ // if there is some data to receive, or if the last update
+ // included a PointerPos message.
+ if (viewer.deferUpdateRequests > 0 &&
+ rfb.available() == 0 && !cursorPosReceived) {
+ synchronized(rfb) {
+ try {
+ rfb.wait(viewer.deferUpdateRequests);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ viewer.autoSelectEncodings();
+
+ // Before requesting framebuffer update, check if the pixel
+ // format should be changed.
+ if (viewer.options.eightBitColors != (bytesPixel == 1)) {
+ // Pixel format should be changed.
+ if (!rfb.continuousUpdatesAreActive()) {
+ // Continuous updates are not used. In this case, we just
+ // set new pixel format and request full update.
+ setPixelFormat();
+ fullUpdateNeeded = true;
+ } else {
+ // Otherwise, disable continuous updates first. Pixel
+ // format will be set later when we are sure that there
+ // will be no unsolicited framebuffer updates.
+ rfb.tryDisableContinuousUpdates();
+ break; // skip the code below
+ }
+ }
+
+ // Enable/disable continuous updates to reflect the GUI setting.
+ boolean enable = viewer.options.continuousUpdates;
+ if (enable != rfb.continuousUpdatesAreActive()) {
+ if (enable) {
+ rfb.tryEnableContinuousUpdates(0, 0, rfb.framebufferWidth,
+ rfb.framebufferHeight);
+ } else {
+ rfb.tryDisableContinuousUpdates();
+ }
+ }
+
+ // Finally, request framebuffer update if needed.
+ if (fullUpdateNeeded) {
+ rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
+ rfb.framebufferHeight, false);
+ } else if (!rfb.continuousUpdatesAreActive()) {
+ rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
+ rfb.framebufferHeight, true);
+ }
+
+ break;
+
+ case RfbProto.SetColourMapEntries:
+ throw new Exception("Can't handle SetColourMapEntries message");
+
+ case RfbProto.Bell:
+ Toolkit.getDefaultToolkit().beep();
+ break;
+
+ case RfbProto.ServerCutText:
+ String s = rfb.readServerCutText();
+ viewer.clipboard.setCutText(s);
+ break;
+
+ case RfbProto.EndOfContinuousUpdates:
+ if (rfb.continuousUpdatesAreActive()) {
+ rfb.endOfContinuousUpdates();
+
+ // Change pixel format if such change was pending. Note that we
+ // could not change pixel format while continuous updates were
+ // in effect.
+ boolean incremental = true;
+ if (viewer.options.eightBitColors != (bytesPixel == 1)) {
+ setPixelFormat();
+ incremental = false;
+ }
+ // From this point, we ask for updates explicitly.
+ rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
+ rfb.framebufferHeight,
+ incremental);
+ }
+ break;
+
+ default:
+ throw new Exception("Unknown RFB message type " + msgType);
+ }
+ }
+ }
+
+ //
+ // Handle a raw rectangle. The second form with paint==false is used
+ // by the Hextile decoder for raw-encoded tiles.
+ //
+
+ void handleRawRect(int x, int y, int w, int h) throws IOException, Exception {
+ handleRawRect(x, y, w, h, true);
+ }
+
+ void handleRawRect(int x, int y, int w, int h, boolean paint)
+ throws IOException , Exception{
+ rawDecoder.handleRect(x, y, w, h);
+ if (paint)
+ scheduleRepaint(x, y, w, h);
+ }
+
+ //
+ // Handle a CopyRect rectangle.
+ //
+
+ void handleCopyRect(int x, int y, int w, int h) throws IOException {
+ copyRectDecoder.handleRect(x, y, w, h);
+ scheduleRepaint(x, y, w, h);
+ }
+
+ //
+ // Handle an RRE-encoded rectangle.
+ //
+
+ void handleRRERect(int x, int y, int w, int h) throws IOException {
+ rreDecoder.handleRect(x, y, w, h);
+ scheduleRepaint(x, y, w, h);
+ }
+
+ //
+ // Handle a CoRRE-encoded rectangle.
+ //
+
+ void handleCoRRERect(int x, int y, int w, int h) throws IOException {
+ correDecoder.handleRect(x, y, w, h);
+ scheduleRepaint(x, y, w, h);
+ }
+
+ //
+ // Handle a Hextile-encoded rectangle.
+ //
+
+ void handleHextileRect(int x, int y, int w, int h) throws IOException,
+ Exception {
+ hextileDecoder.handleRect(x, y, w, h);
+ }
+
+ //
+ // Handle a ZRLE-encoded rectangle.
+ //
+ // FIXME: Currently, session recording is not fully supported for ZRLE.
+ //
+
+ void handleZRLERect(int x, int y, int w, int h) throws Exception {
+ zrleDecoder.handleRect(x, y, w, h);
+ scheduleRepaint(x, y, w, h);
+ }
+
+ //
+ // Handle a Zlib-encoded rectangle.
+ //
+
+ void handleZlibRect(int x, int y, int w, int h) throws Exception {
+ zlibDecoder.handleRect(x, y, w, h);
+ scheduleRepaint(x, y, w, h);
+ }
+
+ //
+ // Handle a Tight-encoded rectangle.
+ //
+
+ void handleTightRect(int x, int y, int w, int h) throws Exception {
+ tightDecoder.handleRect(x, y, w, h);
+ scheduleRepaint(x, y, w, h);
+ }
+
+ //
+ // Tell JVM to repaint specified desktop area.
+ //
+
+ public void scheduleRepaint(int x, int y, int w, int h) {
+ // Request repaint, deferred if necessary.
+ if (rfb.framebufferWidth == scaledWidth) {
+ repaint(viewer.deferScreenUpdates, x, y, w, h);
+ } else {
+ int sx = x * scalingFactor / 100;
+ int sy = y * scalingFactor / 100;
+ int sw = ((x + w) * scalingFactor + 49) / 100 - sx + 1;
+ int sh = ((y + h) * scalingFactor + 49) / 100 - sy + 1;
+ repaint(viewer.deferScreenUpdates, sx, sy, sw, sh);
+ }
+ }
+
+ //
+ // Handle events.
+ //
+
+ public void keyPressed(KeyEvent evt) {
+ processLocalKeyEvent(evt);
+ }
+ public void keyReleased(KeyEvent evt) {
+ processLocalKeyEvent(evt);
+ }
+ public void keyTyped(KeyEvent evt) {
+ evt.consume();
+ }
+
+ public void mousePressed(MouseEvent evt) {
+ processLocalMouseEvent(evt, false);
+ }
+ public void mouseReleased(MouseEvent evt) {
+ processLocalMouseEvent(evt, false);
+ }
+ public void mouseMoved(MouseEvent evt) {
+ processLocalMouseEvent(evt, true);
+ }
+ public void mouseDragged(MouseEvent evt) {
+ processLocalMouseEvent(evt, true);
+ }
+
+ private synchronized void trySendPointerEvent() {
+ if ((needToSendMouseEvent) && (mouseEvent!=null)) {
+ sendMouseEvent(mouseEvent, false);
+ needToSendMouseEvent = false;
+ lastMouseEventSendTime = System.currentTimeMillis();
+ }
+ }
+
+ public void run() {
+ while (true) {
+ // Send mouse movement if we have it
+ trySendPointerEvent();
+ // Sleep for some time
+ try {
+ Thread.sleep(1000 / mouseMaxFreq);
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+
+ //
+ // Ignored events.
+ //
+
+ public void mouseClicked(MouseEvent evt) {}
+ public void mouseEntered(MouseEvent evt) {}
+ public void mouseExited(MouseEvent evt) {}
+
+ //
+ // Actual event processing.
+ //
+
+ private void processLocalKeyEvent(KeyEvent evt) {
+ if (viewer.rfb != null && rfb.inNormalProtocol) {
+ if (!inputEnabled) {
+ if ((evt.getKeyChar() == 'r' || evt.getKeyChar() == 'R') &&
+ evt.getID() == KeyEvent.KEY_PRESSED ) {
+ // Request screen update.
+ try {
+ rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
+ rfb.framebufferHeight, false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ } else {
+ // Input enabled.
+ synchronized(rfb) {
+ try {
+ rfb.writeKeyEvent(evt);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ rfb.notify();
+ }
+ }
+ }
+ // Don't ever pass keyboard events to AWT for default processing.
+ // Otherwise, pressing Tab would switch focus to ButtonPanel etc.
+ evt.consume();
+ }
+
+ private void processLocalMouseEvent(MouseEvent evt, boolean moved) {
+ if (viewer.rfb != null && rfb.inNormalProtocol) {
+ if (!inSelectionMode) {
+ if (inputEnabled) {
+ // If mouse not moved, but it's click event then
+ // send it to server immideanlty.
+ // Else, it's mouse movement - we can send it in
+ // our thread later.
+ if (!moved) {
+ sendMouseEvent(evt, moved);
+ } else {
+ mouseEvent = evt;
+ needToSendMouseEvent = true;
+ }
+ }
+ } else {
+ handleSelectionMouseEvent(evt);
+ }
+ }
+ }
+
+ private void sendMouseEvent(MouseEvent evt, boolean moved) {
+ if (moved) {
+ softCursorMove(evt.getX(), evt.getY());
+ }
+ if (rfb.framebufferWidth != scaledWidth) {
+ int sx = (evt.getX() * 100 + scalingFactor/2) / scalingFactor;
+ int sy = (evt.getY() * 100 + scalingFactor/2) / scalingFactor;
+ evt.translatePoint(sx - evt.getX(), sy - evt.getY());
+ }
+ synchronized(rfb) {
+ try {
+ rfb.writePointerEvent(evt);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ rfb.notify();
+ lastMouseEventSendTime = System.currentTimeMillis();
+ }
+ }
+
+ //
+ // Reset update statistics.
+ //
+
+ void resetStats() {
+ statStartTime = System.currentTimeMillis();
+ statNumUpdates = 0;
+ statNumTotalRects = 0;
+ statNumPixelRects = 0;
+ statNumRectsTight = 0;
+ statNumRectsTightJPEG = 0;
+ statNumRectsZRLE = 0;
+ statNumRectsHextile = 0;
+ statNumRectsRaw = 0;
+ statNumRectsCopy = 0;
+ statNumBytesEncoded = 0;
+ statNumBytesDecoded = 0;
+ if (tightDecoder != null) {
+ tightDecoder.setNumJPEGRects(0);
+ tightDecoder.setNumTightRects(0);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////
+ //
+ // Handle cursor shape updates (XCursor and RichCursor encodings).
+ //
+
+ boolean showSoftCursor = false;
+
+ MemoryImageSource softCursorSource;
+ Image softCursor;
+ MouseEvent mouseEvent = null;
+ boolean needToSendMouseEvent = false;
+ int cursorX = 0, cursorY = 0;
+ int cursorWidth, cursorHeight;
+ int origCursorWidth, origCursorHeight;
+ int hotX, hotY;
+ int origHotX, origHotY;
+
+ //
+ // Handle cursor shape update (XCursor and RichCursor encodings).
+ //
+
+ synchronized void
+ handleCursorShapeUpdate(int encodingType,
+ int xhot, int yhot, int width, int height)
+ throws IOException {
+
+ softCursorFree();
+
+ if (width * height == 0)
+ return;
+
+ // Ignore cursor shape data if requested by user.
+ if (viewer.options.ignoreCursorUpdates) {
+ int bytesPerRow = (width + 7) / 8;
+ int bytesMaskData = bytesPerRow * height;
+
+ if (encodingType == rfb.EncodingXCursor) {
+ rfb.skipBytes(6 + bytesMaskData * 2);
+ } else {
+ // rfb.EncodingRichCursor
+ rfb.skipBytes(width * height + bytesMaskData);
+ }
+ return;
+ }
+
+ // Decode cursor pixel data.
+ softCursorSource = decodeCursorShape(encodingType, width, height);
+
+ // Set original (non-scaled) cursor dimensions.
+ origCursorWidth = width;
+ origCursorHeight = height;
+ origHotX = xhot;
+ origHotY = yhot;
+
+ // Create off-screen cursor image.
+ createSoftCursor();
+
+ // Show the cursor.
+ showSoftCursor = true;
+ repaint(viewer.deferCursorUpdates,
+ cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
+ }
+
+ //
+ // decodeCursorShape(). Decode cursor pixel data and return
+ // corresponding MemoryImageSource instance.
+ //
+
+ synchronized MemoryImageSource
+ decodeCursorShape(int encodingType, int width, int height)
+ throws IOException {
+
+ int bytesPerRow = (width + 7) / 8;
+ int bytesMaskData = bytesPerRow * height;
+
+ int[] softCursorPixels = new int[width * height];
+
+ if (encodingType == rfb.EncodingXCursor) {
+
+ // Read foreground and background colors of the cursor.
+ byte[] rgb = new byte[6];
+ rfb.readFully(rgb);
+ int[] colors = { (0xFF000000 | (rgb[3] & 0xFF) << 16 |
+ (rgb[4] & 0xFF) << 8 | (rgb[5] & 0xFF)),
+ (0xFF000000 | (rgb[0] & 0xFF) << 16 |
+ (rgb[1] & 0xFF) << 8 | (rgb[2] & 0xFF)) };
+
+ // Read pixel and mask data.
+ byte[] pixBuf = new byte[bytesMaskData];
+ rfb.readFully(pixBuf);
+ byte[] maskBuf = new byte[bytesMaskData];
+ rfb.readFully(maskBuf);
+
+ // Decode pixel data into softCursorPixels[].
+ byte pixByte, maskByte;
+ int x, y, n, result;
+ int i = 0;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width / 8; x++) {
+ pixByte = pixBuf[y * bytesPerRow + x];
+ maskByte = maskBuf[y * bytesPerRow + x];
+ for (n = 7; n >= 0; n--) {
+ if ((maskByte >> n & 1) != 0) {
+ result = colors[pixByte >> n & 1];
+ } else {
+ result = 0; // Transparent pixel
+ }
+ softCursorPixels[i++] = result;
+ }
+ }
+ for (n = 7; n >= 8 - width % 8; n--) {
+ if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
+ result = colors[pixBuf[y * bytesPerRow + x] >> n & 1];
+ } else {
+ result = 0; // Transparent pixel
+ }
+ softCursorPixels[i++] = result;
+ }
+ }
+
+ } else {
+ // encodingType == rfb.EncodingRichCursor
+
+ // Read pixel and mask data.
+ byte[] pixBuf = new byte[width * height * bytesPixel];
+ rfb.readFully(pixBuf);
+ byte[] maskBuf = new byte[bytesMaskData];
+ rfb.readFully(maskBuf);
+
+ // Decode pixel data into softCursorPixels[].
+ byte pixByte, maskByte;
+ int x, y, n, result;
+ int i = 0;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width / 8; x++) {
+ maskByte = maskBuf[y * bytesPerRow + x];
+ for (n = 7; n >= 0; n--) {
+ if ((maskByte >> n & 1) != 0) {
+ if (bytesPixel == 1) {
+ result = cm8.getRGB(pixBuf[i]);
+ } else {
+ result = 0xFF000000 |
+ (pixBuf[i * 4 + 2] & 0xFF) << 16 |
+ (pixBuf[i * 4 + 1] & 0xFF) << 8 |
+ (pixBuf[i * 4] & 0xFF);
+ }
+ } else {
+ result = 0; // Transparent pixel
+ }
+ softCursorPixels[i++] = result;
+ }
+ }
+ for (n = 7; n >= 8 - width % 8; n--) {
+ if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
+ if (bytesPixel == 1) {
+ result = cm8.getRGB(pixBuf[i]);
+ } else {
+ result = 0xFF000000 |
+ (pixBuf[i * 4 + 2] & 0xFF) << 16 |
+ (pixBuf[i * 4 + 1] & 0xFF) << 8 |
+ (pixBuf[i * 4] & 0xFF);
+ }
+ } else {
+ result = 0; // Transparent pixel
+ }
+ softCursorPixels[i++] = result;
+ }
+ }
+
+ }
+
+ return new MemoryImageSource(width, height, softCursorPixels, 0, width);
+ }
+
+ //
+ // createSoftCursor(). Assign softCursor new Image (scaled if necessary).
+ // Uses softCursorSource as a source for new cursor image.
+ //
+
+ synchronized void
+ createSoftCursor() {
+
+ if (softCursorSource == null)
+ return;
+
+ int scaleCursor = viewer.options.scaleCursor;
+ if (scaleCursor == 0 || !inputEnabled)
+ scaleCursor = 100;
+
+ // Save original cursor coordinates.
+ int x = cursorX - hotX;
+ int y = cursorY - hotY;
+ int w = cursorWidth;
+ int h = cursorHeight;
+
+ cursorWidth = (origCursorWidth * scaleCursor + 50) / 100;
+ cursorHeight = (origCursorHeight * scaleCursor + 50) / 100;
+ hotX = (origHotX * scaleCursor + 50) / 100;
+ hotY = (origHotY * scaleCursor + 50) / 100;
+ softCursor = Toolkit.getDefaultToolkit().createImage(softCursorSource);
+
+ if (scaleCursor != 100) {
+ softCursor = softCursor.getScaledInstance(cursorWidth, cursorHeight,
+ Image.SCALE_SMOOTH);
+ }
+
+ if (showSoftCursor) {
+ // Compute screen area to update.
+ x = Math.min(x, cursorX - hotX);
+ y = Math.min(y, cursorY - hotY);
+ w = Math.max(w, cursorWidth);
+ h = Math.max(h, cursorHeight);
+
+ repaint(viewer.deferCursorUpdates, x, y, w, h);
+ }
+ }
+
+ //
+ // softCursorMove(). Moves soft cursor into a particular location.
+ //
+
+ synchronized void softCursorMove(int x, int y) {
+ int oldX = cursorX;
+ int oldY = cursorY;
+ cursorX = x;
+ cursorY = y;
+ if (showSoftCursor) {
+ repaint(viewer.deferCursorUpdates,
+ oldX - hotX, oldY - hotY, cursorWidth, cursorHeight);
+ repaint(viewer.deferCursorUpdates,
+ cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
+ }
+ }
+
+ //
+ // softCursorFree(). Remove soft cursor, dispose resources.
+ //
+
+ synchronized void softCursorFree() {
+ if (showSoftCursor) {
+ showSoftCursor = false;
+ softCursor = null;
+ softCursorSource = null;
+
+ repaint(viewer.deferCursorUpdates,
+ cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////
+ //
+ // Support for selecting a rectangular video area.
+ //
+
+ /** This flag is false in normal operation, and true in the selection mode. */
+ private boolean inSelectionMode;
+
+ /** The point where the selection was started. */
+ private Point selectionStart;
+
+ /** The second point of the selection. */
+ private Point selectionEnd;
+
+ /**
+ * We change cursor when enabling the selection mode. In this variable, we
+ * save the original cursor so we can restore it on returning to the normal
+ * mode.
+ */
+ private Cursor savedCursor;
+
+ /**
+ * Initialize selection-related varibles.
+ */
+ private synchronized void resetSelection() {
+ inSelectionMode = false;
+ selectionStart = new Point(0, 0);
+ selectionEnd = new Point(0, 0);
+
+ savedCursor = getCursor();
+ }
+
+ /**
+ * Check current state of the selection mode.
+ * @return true in the selection mode, false otherwise.
+ */
+ public boolean isInSelectionMode() {
+ return inSelectionMode;
+ }
+
+ /**
+ * Get current selection.
+ * @param useScreenCoords use screen coordinates if true, or framebuffer
+ * coordinates if false. This makes difference when scaling factor is not 100.
+ * @return The selection as a {@link Rectangle}.
+ */
+ private synchronized Rectangle getSelection(boolean useScreenCoords) {
+ int x0 = selectionStart.x;
+ int x1 = selectionEnd.x;
+ int y0 = selectionStart.y;
+ int y1 = selectionEnd.y;
+ // Make x and y point to the upper left corner of the selection.
+ if (x1 < x0) {
+ int t = x0; x0 = x1; x1 = t;
+ }
+ if (y1 < y0) {
+ int t = y0; y0 = y1; y1 = t;
+ }
+ // Include the borders in the selection (unless it's empty).
+ if (x0 != x1 && y0 != y1) {
+ x1 += 1;
+ y1 += 1;
+ }
+ // Translate from screen coordinates to framebuffer coordinates.
+ if (rfb.framebufferWidth != scaledWidth) {
+ x0 = (x0 * 100 + scalingFactor/2) / scalingFactor;
+ y0 = (y0 * 100 + scalingFactor/2) / scalingFactor;
+ x1 = (x1 * 100 + scalingFactor/2) / scalingFactor;
+ y1 = (y1 * 100 + scalingFactor/2) / scalingFactor;
+ }
+ // Clip the selection to framebuffer.
+ if (x0 < 0)
+ x0 = 0;
+ if (y0 < 0)
+ y0 = 0;
+ if (x1 > rfb.framebufferWidth)
+ x1 = rfb.framebufferWidth;
+ if (y1 > rfb.framebufferHeight)
+ y1 = rfb.framebufferHeight;
+ // Make width a multiple of 16.
+ int widthBlocks = (x1 - x0 + 8) / 16;
+ if (selectionStart.x <= selectionEnd.x) {
+ x1 = x0 + widthBlocks * 16;
+ if (x1 > rfb.framebufferWidth) {
+ x1 -= 16;
+ }
+ } else {
+ x0 = x1 - widthBlocks * 16;
+ if (x0 < 0) {
+ x0 += 16;
+ }
+ }
+ // Make height a multiple of 8.
+ int heightBlocks = (y1 - y0 + 4) / 8;
+ if (selectionStart.y <= selectionEnd.y) {
+ y1 = y0 + heightBlocks * 8;
+ if (y1 > rfb.framebufferHeight) {
+ y1 -= 8;
+ }
+ } else {
+ y0 = y1 - heightBlocks * 8;
+ if (y0 < 0) {
+ y0 += 8;
+ }
+ }
+ // Translate the selection back to screen coordinates if requested.
+ if (useScreenCoords && rfb.framebufferWidth != scaledWidth) {
+ x0 = (x0 * scalingFactor + 50) / 100;
+ y0 = (y0 * scalingFactor + 50) / 100;
+ x1 = (x1 * scalingFactor + 50) / 100;
+ y1 = (y1 * scalingFactor + 50) / 100;
+ }
+ // Construct and return the result.
+ return new Rectangle(x0, y0, x1 - x0, y1 - y0);
+ }
+
+ /**
+ * Enable or disable the selection mode.
+ * @param enable enables the selection mode if true, disables if fasle.
+ */
+ public synchronized void enableSelection(boolean enable) {
+ if (enable && !inSelectionMode) {
+ // Enter the selection mode.
+ inSelectionMode = true;
+ savedCursor = getCursor();
+ setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ repaint();
+ } else if (!enable && inSelectionMode) {
+ // Leave the selection mode.
+ inSelectionMode = false;
+ setCursor(savedCursor);
+ repaint();
+ }
+ }
+
+ /**
+ * Process mouse events in the selection mode.
+ *
+ * @param evt mouse event that was originally passed to
+ * {@link MouseListener} or {@link MouseMotionListener}.
+ */
+ private synchronized void handleSelectionMouseEvent(MouseEvent evt) {
+ int id = evt.getID();
+ boolean button1 = (evt.getModifiers() & InputEvent.BUTTON1_MASK) != 0;
+
+ if (id == MouseEvent.MOUSE_PRESSED && button1) {
+ selectionStart = selectionEnd = evt.getPoint();
+ repaint();
+ }
+ if (id == MouseEvent.MOUSE_DRAGGED && button1) {
+ selectionEnd = evt.getPoint();
+ repaint();
+ }
+ if (id == MouseEvent.MOUSE_RELEASED && button1) {
+ try {
+ rfb.trySendVideoSelection(getSelection(false));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
--- /dev/null
+//
+// Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.awt.*;
+import java.io.*;
+
+//
+// VncCanvas2 is a special version of VncCanvas which may use Java 2 API.
+//
+
+class VncCanvas2 extends VncCanvas {
+
+ public VncCanvas2(VncViewer v) throws IOException {
+ super(v);
+ disableFocusTraversalKeys();
+ }
+
+ public VncCanvas2(VncViewer v, int maxWidth_, int maxHeight_)
+ throws IOException {
+
+ super(v, maxWidth_, maxHeight_);
+ disableFocusTraversalKeys();
+ }
+
+ public void paintScaledFrameBuffer(Graphics g) {
+ Graphics2D g2d = (Graphics2D)g;
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ g2d.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null);
+ }
+
+ //
+ // Try to disable focus traversal keys (JVMs 1.4 and higher).
+ //
+
+ private void disableFocusTraversalKeys() {
+ try {
+ Class[] argClasses = { Boolean.TYPE };
+ java.lang.reflect.Method method =
+ getClass().getMethod("setFocusTraversalKeysEnabled", argClasses);
+ Object[] argObjects = { new Boolean(false) };
+ method.invoke(this, argObjects);
+ } catch (Exception e) {}
+ }
+
+}
+
--- /dev/null
+//
+// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
+// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// VncViewer.java - the VNC viewer applet. This class mainly just sets up the
+// user interface, leaving it to the VncCanvas to do the actual rendering of
+// a VNC desktop.
+//
+
+package com.tightvnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+
+public class VncViewer extends java.applet.Applet
+ implements java.lang.Runnable, WindowListener, ComponentListener {
+
+ boolean inAnApplet = true;
+ boolean inSeparateFrame = false;
+
+ //
+ // main() is called when run as a java program from the command line.
+ // It simply runs the applet inside a newly-created frame.
+ //
+
+ public static void main(String[] argv) {
+ VncViewer v = new VncViewer();
+ v.mainArgs = argv;
+ v.inAnApplet = false;
+ v.inSeparateFrame = true;
+
+ v.init();
+ v.start();
+ }
+
+ String[] mainArgs;
+
+ RfbProto rfb;
+ Thread rfbThread;
+
+ Frame vncFrame;
+ Container vncContainer;
+ ScrollPane desktopScrollPane;
+ GridBagLayout gridbag;
+ ButtonPanel buttonPanel;
+ Label connStatusLabel;
+ VncCanvas vc;
+ OptionsFrame options;
+ ClipboardFrame clipboard;
+ RecordingFrame rec;
+
+ // Control session recording.
+ Object recordingSync;
+ String sessionFileName;
+ boolean recordingActive;
+ boolean recordingStatusChanged;
+ String cursorUpdatesDef;
+ String eightBitColorsDef;
+
+ // Variables read from parameter values.
+ String socketFactory;
+ String host;
+ int port;
+ String passwordParam;
+ boolean showControls;
+ boolean offerRelogin;
+ boolean showOfflineDesktop;
+ int deferScreenUpdates;
+ int deferCursorUpdates;
+ int deferUpdateRequests;
+ int debugStatsExcludeUpdates;
+ int debugStatsMeasureUpdates;
+
+ // Reference to this applet for inter-applet communication.
+ public static java.applet.Applet refApplet;
+
+ //
+ // init()
+ //
+
+ public void init() {
+
+ readParameters();
+
+ refApplet = this;
+
+ if (inSeparateFrame) {
+ vncFrame = new Frame("TigerVNC");
+ if (!inAnApplet) {
+ vncFrame.add("Center", this);
+ }
+ vncContainer = vncFrame;
+ } else {
+ vncContainer = this;
+ }
+
+ recordingSync = new Object();
+
+ options = new OptionsFrame(this);
+ clipboard = new ClipboardFrame(this);
+ if (RecordingFrame.checkSecurity())
+ rec = new RecordingFrame(this);
+
+ sessionFileName = null;
+ recordingActive = false;
+ recordingStatusChanged = false;
+ cursorUpdatesDef = null;
+ eightBitColorsDef = null;
+
+ if (inSeparateFrame) {
+ vncFrame.addWindowListener(this);
+ vncFrame.addComponentListener(this);
+ }
+
+ rfbThread = new Thread(this);
+ rfbThread.start();
+ }
+
+ public void update(Graphics g) {
+ }
+
+ //
+ // run() - executed by the rfbThread to deal with the RFB socket.
+ //
+
+ public void run() {
+
+ gridbag = new GridBagLayout();
+ vncContainer.setLayout(gridbag);
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.anchor = GridBagConstraints.NORTHWEST;
+
+ if (showControls) {
+ buttonPanel = new ButtonPanel(this);
+ gridbag.setConstraints(buttonPanel, gbc);
+ vncContainer.add(buttonPanel);
+ }
+
+ try {
+ connectAndAuthenticate();
+ doProtocolInitialisation();
+
+ if (showControls &&
+ rfb.clientMsgCaps.isEnabled(RfbProto.VideoRectangleSelection)) {
+ buttonPanel.addSelectButton();
+ }
+
+ if (showControls &&
+ rfb.clientMsgCaps.isEnabled(RfbProto.VideoFreeze)) {
+ buttonPanel.addVideoFreezeButton();
+ }
+
+ // FIXME: Use auto-scaling not only in a separate frame.
+ if (options.autoScale && inSeparateFrame) {
+ Dimension screenSize;
+ try {
+ screenSize = vncContainer.getToolkit().getScreenSize();
+ } catch (Exception e) {
+ screenSize = new Dimension(0, 0);
+ }
+ createCanvas(screenSize.width - 32, screenSize.height - 32);
+ } else {
+ createCanvas(0, 0);
+ }
+
+ gbc.weightx = 1.0;
+ gbc.weighty = 1.0;
+
+ if (inSeparateFrame) {
+
+ // Create a panel which itself is resizeable and can hold
+ // non-resizeable VncCanvas component at the top left corner.
+ Panel canvasPanel = new Panel();
+ canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
+ canvasPanel.add(vc);
+
+ // Create a ScrollPane which will hold a panel with VncCanvas
+ // inside.
+ desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
+ gbc.fill = GridBagConstraints.BOTH;
+ gridbag.setConstraints(desktopScrollPane, gbc);
+ desktopScrollPane.add(canvasPanel);
+ // If auto scale is not enabled we don't need to set first frame
+ // size to fullscreen
+ if (!options.autoScale) {
+ vc.isFirstSizeAutoUpdate = false;
+ }
+
+ // Finally, add our ScrollPane to the Frame window.
+ vncFrame.add(desktopScrollPane);
+ vncFrame.setTitle(rfb.desktopName);
+ vncFrame.pack();
+ vc.resizeDesktopFrame();
+
+ } else {
+ // Just add the VncCanvas component to the Applet.
+ gridbag.setConstraints(vc, gbc);
+ add(vc);
+ validate();
+ }
+
+ if (showControls) {
+ buttonPanel.enableButtons();
+ }
+
+ moveFocusToDesktop();
+ processNormalProtocol();
+
+ } catch (NoRouteToHostException e) {
+ fatalError("Network error: no route to server: " + host, e);
+ } catch (UnknownHostException e) {
+ fatalError("Network error: server name unknown: " + host, e);
+ } catch (ConnectException e) {
+ fatalError("Network error: could not connect to server: " +
+ host + ":" + port, e);
+ } catch (EOFException e) {
+ if (showOfflineDesktop) {
+ e.printStackTrace();
+ System.out.println("Network error: remote side closed connection");
+ if (vc != null) {
+ vc.enableInput(false);
+ }
+ if (inSeparateFrame) {
+ vncFrame.setTitle(rfb.desktopName + " [disconnected]");
+ }
+ if (rfb != null && !rfb.closed())
+ rfb.close();
+ if (showControls && buttonPanel != null) {
+ buttonPanel.disableButtonsOnDisconnect();
+ if (inSeparateFrame) {
+ vncFrame.pack();
+ } else {
+ validate();
+ }
+ }
+ } else {
+ fatalError("Network error: remote side closed connection", e);
+ }
+ } catch (IOException e) {
+ String str = e.getMessage();
+ if (str != null && str.length() != 0) {
+ fatalError("Network Error: " + str, e);
+ } else {
+ fatalError(e.toString(), e);
+ }
+ } catch (Exception e) {
+ String str = e.getMessage();
+ if (str != null && str.length() != 0) {
+ fatalError("Error: " + str, e);
+ } else {
+ fatalError(e.toString(), e);
+ }
+ }
+
+ }
+
+ //
+ // Create a VncCanvas instance.
+ //
+
+ void createCanvas(int maxWidth, int maxHeight) throws IOException {
+ // Determine if Java 2D API is available and use a special
+ // version of VncCanvas if it is present.
+ vc = null;
+ try {
+ // This throws ClassNotFoundException if there is no Java 2D API.
+ Class cl = Class.forName("java.awt.Graphics2D");
+ // If we could load Graphics2D class, then we can use VncCanvas2D.
+ cl = Class.forName("com.tightvnc.vncviewer.VncCanvas2");
+ Class[] argClasses = { this.getClass(), Integer.TYPE, Integer.TYPE };
+ java.lang.reflect.Constructor cstr = cl.getConstructor(argClasses);
+ Object[] argObjects =
+ { this, new Integer(maxWidth), new Integer(maxHeight) };
+ vc = (VncCanvas)cstr.newInstance(argObjects);
+ } catch (Exception e) {
+ System.out.println("Warning: Java 2D API is not available");
+ }
+
+ // If we failed to create VncCanvas2D, use old VncCanvas.
+ if (vc == null)
+ vc = new VncCanvas(this, maxWidth, maxHeight);
+ }
+
+
+ //
+ // Process RFB socket messages.
+ // If the rfbThread is being stopped, ignore any exceptions,
+ // otherwise rethrow the exception so it can be handled.
+ //
+
+ void processNormalProtocol() throws Exception {
+ try {
+ vc.processNormalProtocol();
+ } catch (Exception e) {
+ if (rfbThread == null) {
+ System.out.println("Ignoring RFB socket exceptions" +
+ " because applet is stopping");
+ } else {
+ throw e;
+ }
+ }
+ }
+
+
+ //
+ // Connect to the RFB server and authenticate the user.
+ //
+
+ void connectAndAuthenticate() throws Exception
+ {
+ showConnectionStatus("Initializing...");
+ if (inSeparateFrame) {
+ vncFrame.pack();
+ vncFrame.show();
+ } else {
+ validate();
+ }
+
+ showConnectionStatus("Connecting to " + host + ", port " + port + "...");
+
+ rfb = new RfbProto(host, port, this);
+ showConnectionStatus("Connected to server");
+
+ rfb.readVersionMsg();
+ showConnectionStatus("RFB server supports protocol version " +
+ rfb.serverMajor + "." + rfb.serverMinor);
+
+ rfb.writeVersionMsg();
+ showConnectionStatus("Using RFB protocol version " +
+ rfb.clientMajor + "." + rfb.clientMinor);
+
+ int secType = rfb.negotiateSecurity();
+ int authType;
+ if (secType == RfbProto.SecTypeTight) {
+ showConnectionStatus("Enabling TightVNC protocol extensions");
+ rfb.setupTunneling();
+ authType = rfb.negotiateAuthenticationTight();
+ } else {
+ authType = secType;
+ }
+
+ switch (authType) {
+ case RfbProto.AuthNone:
+ showConnectionStatus("No authentication needed");
+ rfb.authenticateNone();
+ break;
+ case RfbProto.AuthVNC:
+ showConnectionStatus("Performing standard VNC authentication");
+ if (passwordParam != null) {
+ rfb.authenticateVNC(passwordParam);
+ } else {
+ String pw = askPassword();
+ rfb.authenticateVNC(pw);
+ }
+ break;
+ default:
+ throw new Exception("Unknown authentication scheme " + authType);
+ }
+ }
+
+
+ //
+ // Show a message describing the connection status.
+ // To hide the connection status label, use (msg == null).
+ //
+
+ void showConnectionStatus(String msg)
+ {
+ if (msg == null) {
+ if (vncContainer.isAncestorOf(connStatusLabel)) {
+ vncContainer.remove(connStatusLabel);
+ }
+ return;
+ }
+
+ System.out.println(msg);
+
+ if (connStatusLabel == null) {
+ connStatusLabel = new Label("Status: " + msg);
+ connStatusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
+ } else {
+ connStatusLabel.setText("Status: " + msg);
+ }
+
+ if (!vncContainer.isAncestorOf(connStatusLabel)) {
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.anchor = GridBagConstraints.NORTHWEST;
+ gbc.weightx = 1.0;
+ gbc.weighty = 1.0;
+ gbc.insets = new Insets(20, 30, 20, 30);
+ gridbag.setConstraints(connStatusLabel, gbc);
+ vncContainer.add(connStatusLabel);
+ }
+
+ if (inSeparateFrame) {
+ vncFrame.pack();
+ } else {
+ validate();
+ }
+ }
+
+
+ //
+ // Show an authentication panel.
+ //
+
+ String askPassword() throws Exception
+ {
+ showConnectionStatus(null);
+
+ AuthPanel authPanel = new AuthPanel(this);
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.anchor = GridBagConstraints.NORTHWEST;
+ gbc.weightx = 1.0;
+ gbc.weighty = 1.0;
+ gbc.ipadx = 100;
+ gbc.ipady = 50;
+ gridbag.setConstraints(authPanel, gbc);
+ vncContainer.add(authPanel);
+
+ if (inSeparateFrame) {
+ vncFrame.pack();
+ } else {
+ validate();
+ }
+
+ authPanel.moveFocusToDefaultField();
+ String pw = authPanel.getPassword();
+ vncContainer.remove(authPanel);
+
+ return pw;
+ }
+
+
+ //
+ // Do the rest of the protocol initialisation.
+ //
+
+ void doProtocolInitialisation() throws IOException
+ {
+ rfb.writeClientInit();
+ rfb.readServerInit();
+
+ System.out.println("Desktop name is " + rfb.desktopName);
+ System.out.println("Desktop size is " + rfb.framebufferWidth + " x " +
+ rfb.framebufferHeight);
+
+ setEncodings();
+
+ showConnectionStatus(null);
+ }
+
+
+ //
+ // Send current encoding list to the RFB server.
+ //
+
+ int[] encodingsSaved;
+ int nEncodingsSaved;
+
+ void setEncodings() { setEncodings(false); }
+ void autoSelectEncodings() { setEncodings(true); }
+
+ void setEncodings(boolean autoSelectOnly) {
+ if (options == null || rfb == null || !rfb.inNormalProtocol)
+ return;
+
+ int preferredEncoding = options.preferredEncoding;
+ if (preferredEncoding == -1) {
+ long kbitsPerSecond = rfb.kbitsPerSecond();
+ if (nEncodingsSaved < 1) {
+ // Choose Tight or ZRLE encoding for the very first update.
+ System.out.println("Using Tight/ZRLE encodings");
+ preferredEncoding = RfbProto.EncodingTight;
+ } else if (kbitsPerSecond > 2000 &&
+ encodingsSaved[0] != RfbProto.EncodingHextile) {
+ // Switch to Hextile if the connection speed is above 2Mbps.
+ System.out.println("Throughput " + kbitsPerSecond +
+ " kbit/s - changing to Hextile encoding");
+ preferredEncoding = RfbProto.EncodingHextile;
+ } else if (kbitsPerSecond < 1000 &&
+ encodingsSaved[0] != RfbProto.EncodingTight) {
+ // Switch to Tight/ZRLE if the connection speed is below 1Mbps.
+ System.out.println("Throughput " + kbitsPerSecond +
+ " kbit/s - changing to Tight/ZRLE encodings");
+ preferredEncoding = RfbProto.EncodingTight;
+ } else {
+ // Don't change the encoder.
+ if (autoSelectOnly)
+ return;
+ preferredEncoding = encodingsSaved[0];
+ }
+ } else {
+ // Auto encoder selection is not enabled.
+ if (autoSelectOnly)
+ return;
+ }
+
+ int[] encodings = new int[20];
+ int nEncodings = 0;
+
+ encodings[nEncodings++] = preferredEncoding;
+ if (options.useCopyRect) {
+ encodings[nEncodings++] = RfbProto.EncodingCopyRect;
+ }
+
+ if (preferredEncoding != RfbProto.EncodingTight) {
+ encodings[nEncodings++] = RfbProto.EncodingTight;
+ }
+ if (preferredEncoding != RfbProto.EncodingZRLE) {
+ encodings[nEncodings++] = RfbProto.EncodingZRLE;
+ }
+ if (preferredEncoding != RfbProto.EncodingHextile) {
+ encodings[nEncodings++] = RfbProto.EncodingHextile;
+ }
+ if (preferredEncoding != RfbProto.EncodingZlib) {
+ encodings[nEncodings++] = RfbProto.EncodingZlib;
+ }
+ if (preferredEncoding != RfbProto.EncodingCoRRE) {
+ encodings[nEncodings++] = RfbProto.EncodingCoRRE;
+ }
+ if (preferredEncoding != RfbProto.EncodingRRE) {
+ encodings[nEncodings++] = RfbProto.EncodingRRE;
+ }
+
+ if (options.compressLevel >= 0 && options.compressLevel <= 9) {
+ encodings[nEncodings++] =
+ RfbProto.EncodingCompressLevel0 + options.compressLevel;
+ }
+ if (options.jpegQuality >= 0 && options.jpegQuality <= 9) {
+ encodings[nEncodings++] =
+ RfbProto.EncodingQualityLevel0 + options.jpegQuality;
+ }
+
+ if (options.requestCursorUpdates) {
+ encodings[nEncodings++] = RfbProto.EncodingXCursor;
+ encodings[nEncodings++] = RfbProto.EncodingRichCursor;
+ if (!options.ignoreCursorUpdates)
+ encodings[nEncodings++] = RfbProto.EncodingPointerPos;
+ }
+
+ encodings[nEncodings++] = RfbProto.EncodingLastRect;
+ encodings[nEncodings++] = RfbProto.EncodingNewFBSize;
+
+ boolean encodingsWereChanged = false;
+ if (nEncodings != nEncodingsSaved) {
+ encodingsWereChanged = true;
+ } else {
+ for (int i = 0; i < nEncodings; i++) {
+ if (encodings[i] != encodingsSaved[i]) {
+ encodingsWereChanged = true;
+ break;
+ }
+ }
+ }
+
+ if (encodingsWereChanged) {
+ try {
+ rfb.writeSetEncodings(encodings, nEncodings);
+ if (vc != null) {
+ vc.softCursorFree();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ encodingsSaved = encodings;
+ nEncodingsSaved = nEncodings;
+ }
+ }
+
+
+ //
+ // setCutText() - send the given cut text to the RFB server.
+ //
+
+ void setCutText(String text) {
+ try {
+ if (rfb != null && rfb.inNormalProtocol) {
+ rfb.writeClientCutText(text);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ //
+ // Order change in session recording status. To stop recording, pass
+ // null in place of the fname argument.
+ //
+
+ void setRecordingStatus(String fname) {
+ synchronized(recordingSync) {
+ sessionFileName = fname;
+ recordingStatusChanged = true;
+ }
+ }
+
+ //
+ // Start or stop session recording. Returns true if this method call
+ // causes recording of a new session.
+ //
+
+ boolean checkRecordingStatus() throws IOException {
+ synchronized(recordingSync) {
+ if (recordingStatusChanged) {
+ recordingStatusChanged = false;
+ if (sessionFileName != null) {
+ startRecording();
+ return true;
+ } else {
+ stopRecording();
+ }
+ }
+ }
+ return false;
+ }
+
+ //
+ // Start session recording.
+ //
+
+ protected void startRecording() throws IOException {
+ synchronized(recordingSync) {
+ if (!recordingActive) {
+ // Save settings to restore them after recording the session.
+ cursorUpdatesDef =
+ options.choices[options.cursorUpdatesIndex].getSelectedItem();
+ eightBitColorsDef =
+ options.choices[options.eightBitColorsIndex].getSelectedItem();
+ // Set options to values suitable for recording.
+ options.choices[options.cursorUpdatesIndex].select("Disable");
+ options.choices[options.cursorUpdatesIndex].setEnabled(false);
+ options.setEncodings();
+ options.choices[options.eightBitColorsIndex].select("No");
+ options.choices[options.eightBitColorsIndex].setEnabled(false);
+ options.setColorFormat();
+ } else {
+ rfb.closeSession();
+ }
+
+ System.out.println("Recording the session in " + sessionFileName);
+ rfb.startSession(sessionFileName);
+ recordingActive = true;
+ }
+ }
+
+ //
+ // Stop session recording.
+ //
+
+ protected void stopRecording() throws IOException {
+ synchronized(recordingSync) {
+ if (recordingActive) {
+ // Restore options.
+ options.choices[options.cursorUpdatesIndex].select(cursorUpdatesDef);
+ options.choices[options.cursorUpdatesIndex].setEnabled(true);
+ options.setEncodings();
+ options.choices[options.eightBitColorsIndex].select(eightBitColorsDef);
+ options.choices[options.eightBitColorsIndex].setEnabled(true);
+ options.setColorFormat();
+
+ rfb.closeSession();
+ System.out.println("Session recording stopped.");
+ }
+ sessionFileName = null;
+ recordingActive = false;
+ }
+ }
+
+
+ //
+ // readParameters() - read parameters from the html source or from the
+ // command line. On the command line, the arguments are just a sequence of
+ // param_name/param_value pairs where the names and values correspond to
+ // those expected in the html applet tag source.
+ //
+
+ void readParameters() {
+ host = readParameter("HOST", !inAnApplet);
+ if (host == null) {
+ host = getCodeBase().getHost();
+ if (host.equals("")) {
+ fatalError("HOST parameter not specified");
+ }
+ }
+
+ port = readIntParameter("PORT", 5900);
+
+ // Read "ENCPASSWORD" or "PASSWORD" parameter if specified.
+ readPasswordParameters();
+
+ String str;
+ if (inAnApplet) {
+ str = readParameter("Open New Window", false);
+ if (str != null && str.equalsIgnoreCase("Yes"))
+ inSeparateFrame = true;
+ }
+
+ // "Show Controls" set to "No" disables button panel.
+ showControls = true;
+ str = readParameter("Show Controls", false);
+ if (str != null && str.equalsIgnoreCase("No"))
+ showControls = false;
+
+ // "Offer Relogin" set to "No" disables "Login again" and "Close
+ // window" buttons under error messages in applet mode.
+ offerRelogin = true;
+ str = readParameter("Offer Relogin", false);
+ if (str != null && str.equalsIgnoreCase("No"))
+ offerRelogin = false;
+
+ // Do we continue showing desktop on remote disconnect?
+ showOfflineDesktop = false;
+ str = readParameter("Show Offline Desktop", false);
+ if (str != null && str.equalsIgnoreCase("Yes"))
+ showOfflineDesktop = true;
+
+ // Fine tuning options.
+ deferScreenUpdates = readIntParameter("Defer screen updates", 20);
+ deferCursorUpdates = readIntParameter("Defer cursor updates", 10);
+ deferUpdateRequests = readIntParameter("Defer update requests", 0);
+
+ // Debugging options.
+ debugStatsExcludeUpdates = readIntParameter("DEBUG_XU", 0);
+ debugStatsMeasureUpdates = readIntParameter("DEBUG_CU", 0);
+
+ // SocketFactory.
+ socketFactory = readParameter("SocketFactory", false);
+ }
+
+ //
+ // Read password parameters. If an "ENCPASSWORD" parameter is set,
+ // then decrypt the password into the passwordParam string. Otherwise,
+ // try to read the "PASSWORD" parameter directly to passwordParam.
+ //
+
+ private void readPasswordParameters() {
+ String encPasswordParam = readParameter("ENCPASSWORD", false);
+ if (encPasswordParam == null) {
+ passwordParam = readParameter("PASSWORD", false);
+ } else {
+ // ENCPASSWORD is hexascii-encoded. Decode.
+ byte[] pw = {0, 0, 0, 0, 0, 0, 0, 0};
+ int len = encPasswordParam.length() / 2;
+ if (len > 8)
+ len = 8;
+ for (int i = 0; i < len; i++) {
+ String hex = encPasswordParam.substring(i*2, i*2+2);
+ Integer x = new Integer(Integer.parseInt(hex, 16));
+ pw[i] = x.byteValue();
+ }
+ // Decrypt the password.
+ byte[] key = {23, 82, 107, 6, 35, 78, 88, 7};
+ DesCipher des = new DesCipher(key);
+ des.decrypt(pw, 0, pw, 0);
+ passwordParam = new String(pw);
+ }
+ }
+
+ public String readParameter(String name, boolean required) {
+ if (inAnApplet) {
+ String s = getParameter(name);
+ if ((s == null) && required) {
+ fatalError(name + " parameter not specified");
+ }
+ return s;
+ }
+
+ for (int i = 0; i < mainArgs.length; i += 2) {
+ if (mainArgs[i].equalsIgnoreCase(name)) {
+ try {
+ return mainArgs[i+1];
+ } catch (Exception e) {
+ if (required) {
+ fatalError(name + " parameter not specified");
+ }
+ return null;
+ }
+ }
+ }
+ if (required) {
+ fatalError(name + " parameter not specified");
+ }
+ return null;
+ }
+
+ int readIntParameter(String name, int defaultValue) {
+ String str = readParameter(name, false);
+ int result = defaultValue;
+ if (str != null) {
+ try {
+ result = Integer.parseInt(str);
+ } catch (NumberFormatException e) { }
+ }
+ return result;
+ }
+
+ //
+ // moveFocusToDesktop() - move keyboard focus either to VncCanvas.
+ //
+
+ void moveFocusToDesktop() {
+ if (vncContainer != null) {
+ if (vc != null && vncContainer.isAncestorOf(vc))
+ vc.requestFocus();
+ }
+ }
+
+ //
+ // disconnect() - close connection to server.
+ //
+
+ synchronized public void disconnect() {
+ System.out.println("Disconnecting");
+
+ if (vc != null) {
+ double sec = (System.currentTimeMillis() - vc.statStartTime) / 1000.0;
+ double rate = Math.round(vc.statNumUpdates / sec * 100) / 100.0;
+ long nRealRects = vc.statNumPixelRects;
+ long nPseudoRects = vc.statNumTotalRects - vc.statNumPixelRects;
+ System.out.println("Updates received: " + vc.statNumUpdates + " (" +
+ nRealRects + " rectangles + " + nPseudoRects +
+ " pseudo), " + rate + " updates/sec");
+ long numRectsOther = nRealRects - vc.statNumRectsTight
+ - vc.statNumRectsZRLE - vc.statNumRectsHextile
+ - vc.statNumRectsRaw - vc.statNumRectsCopy;
+ System.out.println("Rectangles:" +
+ " Tight=" + vc.statNumRectsTight +
+ "(JPEG=" + vc.statNumRectsTightJPEG +
+ ") ZRLE=" + vc.statNumRectsZRLE +
+ " Hextile=" + vc.statNumRectsHextile +
+ " Raw=" + vc.statNumRectsRaw +
+ " CopyRect=" + vc.statNumRectsCopy +
+ " other=" + numRectsOther);
+
+ long raw = vc.statNumBytesDecoded;
+ long compressed = vc.statNumBytesEncoded;
+ if (compressed > 0) {
+ double ratio = Math.round((double)raw / compressed * 1000) / 1000.0;
+ System.out.println("Pixel data: " + vc.statNumBytesDecoded +
+ " bytes, " + vc.statNumBytesEncoded +
+ " compressed, ratio " + ratio);
+ }
+ }
+
+ if (rfb != null && !rfb.closed())
+ rfb.close();
+ options.dispose();
+ clipboard.dispose();
+ if (rec != null)
+ rec.dispose();
+
+ if (inAnApplet) {
+ showMessage("Disconnected");
+ } else {
+ System.exit(0);
+ }
+ }
+
+ //
+ // fatalError() - print out a fatal error message.
+ // FIXME: Do we really need two versions of the fatalError() method?
+ //
+
+ synchronized public void fatalError(String str) {
+ System.out.println(str);
+
+ if (inAnApplet) {
+ // vncContainer null, applet not inited,
+ // can not present the error to the user.
+ Thread.currentThread().stop();
+ } else {
+ System.exit(1);
+ }
+ }
+
+ synchronized public void fatalError(String str, Exception e) {
+
+ if (rfb != null && rfb.closed()) {
+ // Not necessary to show error message if the error was caused
+ // by I/O problems after the rfb.close() method call.
+ System.out.println("RFB thread finished");
+ return;
+ }
+
+ System.out.println(str);
+ e.printStackTrace();
+
+ if (rfb != null)
+ rfb.close();
+
+ if (inAnApplet) {
+ showMessage(str);
+ } else {
+ System.exit(1);
+ }
+ }
+
+ //
+ // Show message text and optionally "Relogin" and "Close" buttons.
+ //
+
+ void showMessage(String msg) {
+ vncContainer.removeAll();
+
+ Label errLabel = new Label(msg, Label.CENTER);
+ errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
+
+ if (offerRelogin) {
+
+ Panel gridPanel = new Panel(new GridLayout(0, 1));
+ Panel outerPanel = new Panel(new FlowLayout(FlowLayout.LEFT));
+ outerPanel.add(gridPanel);
+ vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 16));
+ vncContainer.add(outerPanel);
+ Panel textPanel = new Panel(new FlowLayout(FlowLayout.CENTER));
+ textPanel.add(errLabel);
+ gridPanel.add(textPanel);
+ gridPanel.add(new ReloginPanel(this));
+
+ } else {
+
+ vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
+ vncContainer.add(errLabel);
+
+ }
+
+ if (inSeparateFrame) {
+ vncFrame.pack();
+ } else {
+ validate();
+ }
+ }
+
+ //
+ // Stop the applet.
+ // Main applet thread will terminate on first exception
+ // after seeing that rfbThread has been set to null.
+ //
+
+ public void stop() {
+ System.out.println("Stopping applet");
+ rfbThread = null;
+ }
+
+ //
+ // This method is called before the applet is destroyed.
+ //
+
+ public void destroy() {
+ System.out.println("Destroying applet");
+
+ vncContainer.removeAll();
+ options.dispose();
+ clipboard.dispose();
+ if (rec != null)
+ rec.dispose();
+ if (rfb != null && !rfb.closed())
+ rfb.close();
+ if (inSeparateFrame)
+ vncFrame.dispose();
+ }
+
+ //
+ // Start/stop receiving mouse events.
+ //
+
+ public void enableInput(boolean enable) {
+ vc.enableInput(enable);
+ }
+
+ //
+ // Resize framebuffer if autoScale is enabled.
+ //
+
+ public void componentResized(ComponentEvent e) {
+ if (e.getComponent() == vncFrame) {
+ if (options.autoScale) {
+ if (vc != null) {
+ if (!vc.isFirstSizeAutoUpdate) {
+ vc.updateFramebufferSize();
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Ignore component events we're not interested in.
+ //
+
+ public void componentShown(ComponentEvent e) { }
+ public void componentMoved(ComponentEvent e) { }
+ public void componentHidden(ComponentEvent e) { }
+
+ //
+ // Close application properly on window close event.
+ //
+
+ public void windowClosing(WindowEvent evt) {
+ System.out.println("Closing window");
+ if (rfb != null)
+ disconnect();
+
+ vncContainer.hide();
+
+ if (!inAnApplet) {
+ System.exit(0);
+ }
+ }
+
+ //
+ // Ignore window events we're not interested in.
+ //
+
+ public void windowActivated(WindowEvent evt) {}
+ public void windowDeactivated (WindowEvent evt) {}
+ public void windowOpened(WindowEvent evt) {}
+ public void windowClosed(WindowEvent evt) {}
+ public void windowIconified(WindowEvent evt) {}
+ public void windowDeiconified(WindowEvent evt) {}
+}
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// A ZlibInStream reads from a zlib.io.InputStream
+//
+
+package com.tightvnc.vncviewer;
+
+public class ZlibInStream extends InStream {
+
+ static final int defaultBufSize = 16384;
+
+ public ZlibInStream(int bufSize_) {
+ bufSize = bufSize_;
+ b = new byte[bufSize];
+ ptr = end = ptrOffset = 0;
+ inflater = new java.util.zip.Inflater();
+ }
+
+ public ZlibInStream() { this(defaultBufSize); }
+
+ public void setUnderlying(InStream is, int bytesIn_) {
+ underlying = is;
+ bytesIn = bytesIn_;
+ ptr = end = 0;
+ }
+
+ public void reset() throws Exception {
+ ptr = end = 0;
+ if (underlying == null) return;
+
+ while (bytesIn > 0) {
+ decompress();
+ end = 0; // throw away any data
+ }
+ underlying = null;
+ }
+
+ public int pos() { return ptrOffset + ptr; }
+
+ protected int overrun(int itemSize, int nItems) throws Exception {
+ if (itemSize > bufSize)
+ throw new Exception("ZlibInStream overrun: max itemSize exceeded");
+ if (underlying == null)
+ throw new Exception("ZlibInStream overrun: no underlying stream");
+
+ if (end - ptr != 0)
+ System.arraycopy(b, ptr, b, 0, end - ptr);
+
+ ptrOffset += ptr;
+ end -= ptr;
+ ptr = 0;
+
+ while (end < itemSize) {
+ decompress();
+ }
+
+ if (itemSize * nItems > end)
+ nItems = end / itemSize;
+
+ return nItems;
+ }
+
+ // decompress() calls the decompressor once. Note that this won't
+ // necessarily generate any output data - it may just consume some input
+ // data. Returns false if wait is false and we would block on the underlying
+ // stream.
+
+ private void decompress() throws Exception {
+ try {
+ underlying.check(1);
+ int avail_in = underlying.getend() - underlying.getptr();
+ if (avail_in > bytesIn)
+ avail_in = bytesIn;
+
+ if (inflater.needsInput()) {
+ inflater.setInput(underlying.getbuf(), underlying.getptr(), avail_in);
+ }
+
+ int n = inflater.inflate(b, end, bufSize - end);
+
+ end += n;
+ if (inflater.needsInput()) {
+ bytesIn -= avail_in;
+ underlying.setptr(underlying.getptr() + avail_in);
+ }
+ } catch (java.util.zip.DataFormatException e) {
+ throw new Exception("ZlibInStream: inflate failed");
+ }
+ }
+
+ private InStream underlying;
+ private int bufSize;
+ private int ptrOffset;
+ private java.util.zip.Inflater inflater;
+ private int bytesIn;
+}
--- /dev/null
+<!--
+ index.html - an example HTML page for TigerVNC Java viewer applet, to be
+ used with a standalone Web server running on the same machine where the
+ TigerVNC server is running. Before using this example, please MAKE SURE
+ to check the following:
+
+ * the value of the PORT parameter should be set correctly (normally, the
+ port number is 5900 + display number);
+
+ * the CODE and ARCHIVE attributes of the <APPLET> tag should point to
+ the correct directory (this example assumes that this page is in the
+ same directory with .jar and .class files);
+
+ * the WIDTH and HEIGHT attributes of the <APPLET> tag correspond to the
+ actual desktop size on the server (height should be increased to leave
+ enough space for the button panel).
+-->
+
+<HTML>
+<TITLE>
+TigerVNC desktop
+</TITLE>
+<APPLET CODE="VncViewer.class" ARCHIVE="VncViewer.jar"
+ WIDTH="800" HEIGHT="632">
+<PARAM NAME="PORT" VALUE="5901">
+</APPLET>
+<BR>
+<A href="http://www.tigervnc.org/">TigerVNC site</A>
+</HTML>
--- /dev/null
+<!--
+ index.vnc - default HTML page for TigerVNC Java viewer applet, to be
+ used with Xvnc. On any file ending in .vnc, the HTTP server embedded in
+ Xvnc will substitute the following variables when preceded by a dollar:
+ USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT,
+ PARAMS. Use two dollar signs ($$) to get a dollar sign in the generated
+ HTML page.
+
+ NOTE: the $PARAMS variable is not supported by the standard VNC, so
+ make sure you have TigerVNC on the server side, if you're using this
+ variable.
+-->
+
+<HTML>
+<TITLE>
+$USER's $DESKTOP desktop ($DISPLAY)
+</TITLE>
+<APPLET CODE=VncViewer.class ARCHIVE=VncViewer.jar
+ WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT>
+<param name=PORT value=$PORT>
+$PARAMS
+</APPLET>
+<BR>
+<A href="http://www.tigervnc.org/">TigerVNC site</A>
+</HTML>
+++ /dev/null
-package com.tightvnc.decoder;
-
-import com.tightvnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.awt.Color;
-import java.io.IOException;
-
-//
-// Class that used for decoding CoRRE encoded data.
-//
-
-public class CoRREDecoder extends RawDecoder {
-
- final static int EncodingCoRRE = 4;
-
- public CoRREDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public CoRREDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Override handleRect method to decode CoRRE encoded data insted of
- // raw pixel data.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(CoRREDecoder.EncodingCoRRE);
- }
-
- int nSubrects = rfbis.readU32();
-
- byte[] bg_buf = new byte[bytesPerPixel];
- rfbis.readFully(bg_buf);
- Color pixel;
- if (bytesPerPixel == 1) {
- pixel = getColor256()[bg_buf[0] & 0xFF];
- } else {
- pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
- }
- graphics.setColor(pixel);
- graphics.fillRect(x, y, w, h);
-
- byte[] buf = new byte[nSubrects * (bytesPerPixel + 4)];
- rfbis.readFully(buf);
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.writeInt(nSubrects);
- dos.write(bg_buf);
- dos.write(buf);
- }
-
- int sx, sy, sw, sh;
- int i = 0;
-
- for (int j = 0; j < nSubrects; j++) {
- if (bytesPerPixel == 1) {
- pixel = getColor256()[buf[i++] & 0xFF];
- } else {
- pixel = new Color(buf[i+2] & 0xFF, buf[i+1] & 0xFF, buf[i] & 0xFF);
- i += 4;
- }
- sx = x + (buf[i++] & 0xFF);
- sy = y + (buf[i++] & 0xFF);
- sw = buf[i++] & 0xFF;
- sh = buf[i++] & 0xFF;
-
- graphics.setColor(pixel);
- graphics.fillRect(sx, sy, sw, sh);
- }
- }
-}
+++ /dev/null
-package com.tightvnc.decoder;
-
-import com.tightvnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.io.IOException;
-
-//
-// Class that used for decoding CopyRect encoded data.
-//
-
-public class CopyRectDecoder extends RawDecoder {
-
- final static int EncodingCopyRect = 1;
-
- public CopyRectDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public CopyRectDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Override handleRect method handle CopyRect
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(CopyRectDecoder.EncodingCopyRect);
- }
-
- int copyRectSrcX = rfbis.readU16();
- int copyRectSrcY = rfbis.readU16();
-
- // If the session is being recorded:
- if (dos != null) {
- dos.writeShort(copyRectSrcX);
- dos.writeShort(copyRectSrcY);
- }
-
- graphics.copyArea(copyRectSrcX, copyRectSrcY, w, h,
- x - copyRectSrcX, y - copyRectSrcY);
- }
-}
+++ /dev/null
-package com.tightvnc.decoder;
-
-import com.tightvnc.decoder.common.Repaintable;
-import com.tightvnc.vncviewer.RfbInputStream;
-import java.awt.Color;
-import java.awt.Graphics;
-import java.io.IOException;
-
-//
-// Class that used for decoding hextile encoded data.
-//
-
-public class HextileDecoder extends RawDecoder {
-
- final static int EncodingHextile = 5;
-
- // Contstants used in the Hextile decoder
- final static int
- HextileRaw = 1,
- HextileBackgroundSpecified = 2,
- HextileForegroundSpecified = 4,
- HextileAnySubrects = 8,
- HextileSubrectsColoured = 16;
-
- public HextileDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public HextileDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Set private members methods
- //
-
- public void setRepainableControl(Repaintable r) {
- repainableControl = r;
- }
-
- //
- // Override handleRect method to decode Hextile encoded data insted of
- // raw pixel data.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException,
- Exception {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(HextileDecoder.EncodingHextile);
- }
-
- hextile_bg = new Color(0);
- hextile_fg = new Color(0);
-
- for (int ty = y; ty < y + h; ty += 16) {
- int th = 16;
- if (y + h - ty < 16)
- th = y + h - ty;
-
- for (int tx = x; tx < x + w; tx += 16) {
- int tw = 16;
- if (x + w - tx < 16)
- tw = x + w - tx;
-
- handleHextileSubrect(tx, ty, tw, th);
- }
- if (repainableControl != null)
- repainableControl.scheduleRepaint(x, y, w, h);
- }
- if (repainableControl != null)
- repainableControl.scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle one tile in the Hextile-encoded data.
- //
-
- private void handleHextileSubrect(int tx, int ty, int tw, int th)
- throws IOException, Exception {
-
- int subencoding = rfbis.readU8();
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.writeByte((byte)subencoding);
- }
-
- // Is it a raw-encoded sub-rectangle?
- if ((subencoding & HextileRaw) != 0) {
- //
- // Disable encoding id writting to record stream
- // in super (RawDecoder) class, cause we write subencoding ID
- // in this class (see code above).
- //
-
- super.enableEncodingRecordWritting(false);
- super.handleRect(tx, ty, tw, th);
- super.handleUpdatedPixels(tx, ty, tw, th);
- super.enableEncodingRecordWritting(true);
- return;
- }
-
- // Read and draw the background if specified.
- byte[] cbuf = new byte[bytesPerPixel];
- if ((subencoding & HextileBackgroundSpecified) != 0) {
- rfbis.readFully(cbuf);
- if (bytesPerPixel == 1) {
- hextile_bg = getColor256()[cbuf[0] & 0xFF];
- } else {
- hextile_bg = new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
- }
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.write(cbuf);
- }
- }
- graphics.setColor(hextile_bg);
- graphics.fillRect(tx, ty, tw, th);
-
- // Read the foreground color if specified.
- if ((subencoding & HextileForegroundSpecified) != 0) {
- rfbis.readFully(cbuf);
- if (bytesPerPixel == 1) {
- hextile_fg = getColor256()[cbuf[0] & 0xFF];
- } else {
- hextile_fg = new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
- }
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.write(cbuf);
- }
- }
-
- // Done with this tile if there is no sub-rectangles.
- if ((subencoding & HextileAnySubrects) == 0)
- return;
-
- int nSubrects = rfbis.readU8();
- int bufsize = nSubrects * 2;
- if ((subencoding & HextileSubrectsColoured) != 0) {
- bufsize += nSubrects * bytesPerPixel;
- }
- byte[] buf = new byte[bufsize];
- rfbis.readFully(buf);
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.writeByte((byte)nSubrects);
- dos.write(buf);
- }
-
- int b1, b2, sx, sy, sw, sh;
- int i = 0;
-
- if ((subencoding & HextileSubrectsColoured) == 0) {
-
- // Sub-rectangles are all of the same color.
- graphics.setColor(hextile_fg);
- for (int j = 0; j < nSubrects; j++) {
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- sx = tx + (b1 >> 4);
- sy = ty + (b1 & 0xf);
- sw = (b2 >> 4) + 1;
- sh = (b2 & 0xf) + 1;
- graphics.fillRect(sx, sy, sw, sh);
- }
- } else if (bytesPerPixel == 1) {
-
- // BGR233 (8-bit color) version for colored sub-rectangles.
- for (int j = 0; j < nSubrects; j++) {
- hextile_fg = getColor256()[buf[i++] & 0xFF];
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- sx = tx + (b1 >> 4);
- sy = ty + (b1 & 0xf);
- sw = (b2 >> 4) + 1;
- sh = (b2 & 0xf) + 1;
- graphics.setColor(hextile_fg);
- graphics.fillRect(sx, sy, sw, sh);
- }
-
- } else {
-
- // Full-color (24-bit) version for colored sub-rectangles.
- for (int j = 0; j < nSubrects; j++) {
- hextile_fg = new Color(buf[i+2] & 0xFF,
- buf[i+1] & 0xFF,
- buf[i] & 0xFF);
- i += 4;
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- sx = tx + (b1 >> 4);
- sy = ty + (b1 & 0xf);
- sw = (b2 >> 4) + 1;
- sh = (b2 & 0xf) + 1;
- graphics.setColor(hextile_fg);
- graphics.fillRect(sx, sy, sw, sh);
- }
-
- }
- }
-
- // These colors should be kept between handleHextileSubrect() calls.
- private Color hextile_bg, hextile_fg;
- // Repaitable object
- private Repaintable repainableControl = null;
-}
+++ /dev/null
-package com.tightvnc.decoder;
-
-import com.tightvnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.awt.Color;
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-
-//
-// Class that used for decoding RRE encoded data.
-//
-
-public class RREDecoder extends RawDecoder {
-
- final static int EncodingRRE = 2;
-
- public RREDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public RREDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Override handleRect method to decode RRE encoded data insted of
- // raw pixel data.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(RREDecoder.EncodingRRE);
- }
-
- int nSubrects = rfbis.readU32();
- byte[] bg_buf = new byte[bytesPerPixel];
- rfbis.readFully(bg_buf);
- Color pixel;
- if (bytesPerPixel == 1) {
- pixel = getColor256()[bg_buf[0] & 0xFF];
- } else {
- pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
- }
- graphics.setColor(pixel);
- graphics.fillRect(x, y, w, h);
- byte[] buf = new byte[nSubrects * (bytesPerPixel + 8)];
- rfbis.readFully(buf);
- DataInputStream ds = new DataInputStream(new ByteArrayInputStream(buf));
-
- //
- // Save decoded data to data output stream
- //
- if (dos != null) {
- dos.writeInt(nSubrects);
- dos.write(bg_buf);
- dos.write(buf);
- }
-
- int sx, sy, sw, sh;
- for (int j = 0; j < nSubrects; j++) {
- if (bytesPerPixel == 1) {
- pixel = getColor256()[ds.readUnsignedByte()];
- } else {
- ds.skip(4);
- pixel = new Color(buf[j*12+2] & 0xFF,
- buf[j*12+1] & 0xFF,
- buf[j*12] & 0xFF);
- }
- sx = x + ds.readUnsignedShort();
- sy = y + ds.readUnsignedShort();
- sw = ds.readUnsignedShort();
- sh = ds.readUnsignedShort();
-
- graphics.setColor(pixel);
- graphics.fillRect(sx, sy, sw, sh);
- }
- }
-}
+++ /dev/null
-package com.tightvnc.decoder;
-
-import com.tightvnc.vncviewer.RfbInputStream;
-import java.io.IOException;
-import java.io.DataOutput;
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.image.ColorModel;
-import java.awt.image.DirectColorModel;
-import java.awt.image.MemoryImageSource;
-import java.awt.Color;
-import java.awt.Toolkit;
-
-//
-// This is base decoder class.
-// Other classes will be childs of RawDecoder.
-//
-
-public class RawDecoder {
- final static int EncodingRaw = 0;
-
- public RawDecoder(Graphics g, RfbInputStream is) {
- setGraphics(g);
- setRfbInputStream(is);
- }
-
- public RawDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- setGraphics(g);
- setRfbInputStream(is);
- setFrameBufferSize(frameBufferW, frameBufferH);
- // FIXME: cm24 created in getColorModel24.
- // Remove if no bugs
- cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
- }
-
- //
- // Set methods to set value of non-static protected members of class
- //
-
- public void setRfbInputStream(RfbInputStream is) {
- rfbis = is;
- }
-
- public void setGraphics(Graphics g) {
- graphics = g;
- }
-
- public void setBPP(int bpp) {
- bytesPerPixel = bpp;
- }
-
- public void setFrameBufferSize(int w, int h) {
- framebufferWidth = w;
- framebufferHeight = h;
- }
-
- //
- // FIXME: Rename this method after we don't need RecordInterface
- // in RawDecoder class to record session
- //
-
- public void setDataOutputStream(DataOutput os) {
- dos = os;
- }
-
- //
- // Decodes Raw Pixels data and draw it into graphics
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
-
- //
- // Write encoding ID to record output stream
- //
-
- if ((dos != null) && (enableEncodingRecordWritting)) {
- dos.writeInt(RawDecoder.EncodingRaw);
- }
-
- if (bytesPerPixel == 1) {
- for (int dy = y; dy < y + h; dy++) {
- if (pixels8 != null) {
- rfbis.readFully(pixels8, dy * framebufferWidth + x, w);
- }
- //
- // Save decoded data to record output stream
- //
- if (dos != null) {
- dos.write(pixels8, dy * framebufferWidth + x, w);
- }
- }
- } else {
- byte[] buf = new byte[w * 4];
- int i, offset;
- for (int dy = y; dy < y + h; dy++) {
- rfbis.readFully(buf);
- //
- // Save decoded data to record output stream
- //
- if (dos != null) {
- dos.write(buf);
- }
- offset = dy * framebufferWidth + x;
- if (pixels24 != null) {
- for (i = 0; i < w; i++) {
- pixels24[offset + i] =
- (buf[i * 4 + 2] & 0xFF) << 16 |
- (buf[i * 4 + 1] & 0xFF) << 8 |
- (buf[i * 4] & 0xFF);
- } //for
- } // if
- } // for
- } // else
- handleUpdatedPixels(x, y, w, h);
- } // void
-
- //
- // Display newly updated area of pixels.
- //
-
- protected void handleUpdatedPixels(int x, int y, int w, int h) {
- // Draw updated pixels of the off-screen image.
- pixelsSource.newPixels(x, y, w, h);
- graphics.setClip(x, y, w, h);
- graphics.drawImage(rawPixelsImage, 0, 0, null);
- graphics.setClip(0, 0, framebufferWidth, framebufferHeight);
- }
-
- //
- // Updates pixels data.
- // This method must be called when framebuffer is resized
- // or BPP is changed.
- //
-
- public void update() {
- // Images with raw pixels should be re-allocated on every change
- // of geometry or pixel format.
- int fbWidth = framebufferWidth;
- int fbHeight = framebufferHeight;
-
- if (bytesPerPixel == 1) {
- pixels24 = null;
- pixels8 = new byte[fbWidth * fbHeight];
- pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(),
- pixels8, 0, fbWidth);
- } else {
- pixels8 = null;
- pixels24 = new int[fbWidth * fbHeight];
- pixelsSource =
- new MemoryImageSource(fbWidth, fbHeight, cm24, pixels24, 0, fbWidth);
- }
- pixelsSource.setAnimated(true);
- rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
- }
-
- //
- // Private static members access methods
- //
-
- protected ColorModel getColorModel8() {
- if (cm8 == null) {
- cm8 = cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
- }
- return cm8;
- }
-
- protected ColorModel getColorModel24() {
- if (cm24 == null) {
- cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
- }
- return cm24;
- }
-
- protected Color[]getColor256() {
- if (color256 == null) {
- color256 = new Color[256];
- for (int i = 0; i < 256; i++)
- color256[i] = new Color(cm8.getRGB(i));
- }
- return color256;
- }
-
- //
- // This method will be used by HextileDecoder to disable
- // double writting encoding id to record stream.
- //
- // FIXME: Try to find better solution than this.
- //
-
- protected void enableEncodingRecordWritting(boolean enable) {
- enableEncodingRecordWritting = enable;
- }
-
- //
- // Unique data for every decoder (? maybe not ?)
- //
-
- protected int bytesPerPixel = 4;
- protected int framebufferWidth = 0;
- protected int framebufferHeight = 0;
- protected RfbInputStream rfbis = null;
- protected Graphics graphics = null;
- protected DataOutput dos = null;
- protected boolean enableEncodingRecordWritting = true;
-
- //
- // This data must be shared between decoders
- //
-
- protected static byte []pixels8 = null;
- protected static int []pixels24 = null;
- protected static MemoryImageSource pixelsSource = null;
- protected static Image rawPixelsImage = null;
-
- //
- // Access to this static members only though protected methods
- //
-
- private static ColorModel cm8 = null;
- private static ColorModel cm24 = null;
- private static Color []color256 = null;
-}
+++ /dev/null
-package com.tightvnc.decoder;
-
-import com.tightvnc.decoder.common.Repaintable;
-import com.tightvnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.awt.Color;
-import java.awt.Image;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.image.ImageObserver;
-import java.io.IOException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
-
-//
-// Class that used for decoding Tight encoded data.
-//
-
-public class TightDecoder extends RawDecoder implements ImageObserver {
-
- final static int EncodingTight = 7;
-
- //
- // Tight decoder constants
- //
-
- final static int TightExplicitFilter = 0x04;
- final static int TightFill = 0x08;
- final static int TightJpeg = 0x09;
- final static int TightMaxSubencoding = 0x09;
- final static int TightFilterCopy = 0x00;
- final static int TightFilterPalette = 0x01;
- final static int TightFilterGradient = 0x02;
- final static int TightMinToCompress = 12;
-
- // Tight encoder's data.
- final static int tightZlibBufferSize = 512;
-
- public TightDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- tightInflaters = new Inflater[4];
- }
-
- public TightDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- tightInflaters = new Inflater[4];
- }
-
- //
- // Set and get methods for private TightDecoder
- //
-
- public void setRepainableControl(Repaintable r) {
- repainatableControl = r;
- }
-
- //
- // JPEG processing statistic methods
- //
-
- public long getNumJPEGRects() {
- return statNumRectsTightJPEG;
- }
-
- public void setNumJPEGRects(int v) {
- statNumRectsTightJPEG = v;
- }
-
- //
- // Tight processing statistic methods
- //
-
- public long getNumTightRects() {
- return statNumRectsTight;
- }
-
- public void setNumTightRects(int v) {
- statNumRectsTight = v;
- }
-
- //
- // Handle a Tight-encoded rectangle.
- //
-
- public void handleRect(int x, int y, int w, int h) throws Exception {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(TightDecoder.EncodingTight);
- }
-
- int comp_ctl = rfbis.readU8();
-
- if (dos != null) {
- // Tell the decoder to flush each of the four zlib streams.
- dos.writeByte(comp_ctl | 0x0F);
- }
-
- // Flush zlib streams if we are told by the server to do so.
- for (int stream_id = 0; stream_id < 4; stream_id++) {
- if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) {
- tightInflaters[stream_id] = null;
- }
- comp_ctl >>= 1;
- }
-
- // Check correctness of subencoding value.
- if (comp_ctl > TightDecoder.TightMaxSubencoding) {
- throw new Exception("Incorrect tight subencoding: " + comp_ctl);
- }
-
- // Handle solid-color rectangles.
- if (comp_ctl == TightDecoder.TightFill) {
-
- if (bytesPerPixel == 1) {
- int idx = rfbis.readU8();
- graphics.setColor(getColor256()[idx]);
- if (dos != null) {
- dos.writeByte(idx);
- }
- } else {
- byte[] buf = new byte[3];
- rfbis.readFully(buf);
- if (dos != null) {
- dos.write(buf);
- }
- Color bg = new Color(0xFF000000 | (buf[0] & 0xFF) << 16 |
- (buf[1] & 0xFF) << 8 | (buf[2] & 0xFF));
- graphics.setColor(bg);
- }
- graphics.fillRect(x, y, w, h);
- repainatableControl.scheduleRepaint(x, y, w, h);
- return;
-
- }
-
- if (comp_ctl == TightDecoder.TightJpeg) {
-
- statNumRectsTightJPEG++;
-
- // Read JPEG data.
- byte[] jpegData = new byte[rfbis.readCompactLen()];
- rfbis.readFully(jpegData);
- if (dos != null) {
- recordCompactLen(jpegData.length);
- dos.write(jpegData);
- }
-
- // Create an Image object from the JPEG data.
- Image jpegImage = Toolkit.getDefaultToolkit().createImage(jpegData);
-
- // Remember the rectangle where the image should be drawn.
- jpegRect = new Rectangle(x, y, w, h);
-
- // Let the imageUpdate() method do the actual drawing, here just
- // wait until the image is fully loaded and drawn.
- synchronized(jpegRect) {
- Toolkit.getDefaultToolkit().prepareImage(jpegImage, -1, -1, this);
- try {
- // Wait no longer than three seconds.
- jpegRect.wait(3000);
- } catch (InterruptedException e) {
- throw new Exception("Interrupted while decoding JPEG image");
- }
- }
-
- // Done, jpegRect is not needed any more.
- jpegRect = null;
- return;
-
- } else {
- statNumRectsTight++;
- }
-
- // Read filter id and parameters.
- int numColors = 0, rowSize = w;
- byte[] palette8 = new byte[2];
- int[] palette24 = new int[256];
- boolean useGradient = false;
- if ((comp_ctl & TightDecoder.TightExplicitFilter) != 0) {
- int filter_id = rfbis.readU8();
- if (dos != null) {
- dos.writeByte(filter_id);
- }
- if (filter_id == TightDecoder.TightFilterPalette) {
- numColors = rfbis.readU8() + 1;
- if (dos != null) {
- dos.writeByte((numColors - 1));
- }
- if (bytesPerPixel == 1) {
- if (numColors != 2) {
- throw new Exception("Incorrect tight palette size: " + numColors);
- }
- rfbis.readFully(palette8);
- if (dos != null) {
- dos.write(palette8);
- }
- } else {
- byte[] buf = new byte[numColors * 3];
- rfbis.readFully(buf);
- if (dos != null) {
- dos.write(buf);
- }
- for (int i = 0; i < numColors; i++) {
- palette24[i] = ((buf[i * 3] & 0xFF) << 16 |
- (buf[i * 3 + 1] & 0xFF) << 8 |
- (buf[i * 3 + 2] & 0xFF));
- }
- }
- if (numColors == 2) {
- rowSize = (w + 7) / 8;
- }
- } else if (filter_id == TightDecoder.TightFilterGradient) {
- useGradient = true;
- } else if (filter_id != TightDecoder.TightFilterCopy) {
- throw new Exception("Incorrect tight filter id: " + filter_id);
- }
- }
- if (numColors == 0 && bytesPerPixel == 4)
- rowSize *= 3;
-
- // Read, optionally uncompress and decode data.
- int dataSize = h * rowSize;
- if (dataSize < TightDecoder.TightMinToCompress) {
- // Data size is small - not compressed with zlib.
- if (numColors != 0) {
- // Indexed colors.
- byte[] indexedData = new byte[dataSize];
- rfbis.readFully(indexedData);
- if (dos != null) {
- dos.write(indexedData);
- }
- if (numColors == 2) {
- // Two colors.
- if (bytesPerPixel == 1) {
- decodeMonoData(x, y, w, h, indexedData, palette8);
- } else {
- decodeMonoData(x, y, w, h, indexedData, palette24);
- }
- } else {
- // 3..255 colors (assuming bytesPixel == 4).
- int i = 0;
- for (int dy = y; dy < y + h; dy++) {
- for (int dx = x; dx < x + w; dx++) {
- pixels24[dy * framebufferWidth + dx] =
- palette24[indexedData[i++] & 0xFF];
- }
- }
- }
- } else if (useGradient) {
- // "Gradient"-processed data
- byte[] buf = new byte[w * h * 3];
- rfbis.readFully(buf);
- if (dos != null) {
- dos.write(buf);
- }
- decodeGradientData(x, y, w, h, buf);
- } else {
- // Raw truecolor data.
- if (bytesPerPixel == 1) {
- for (int dy = y; dy < y + h; dy++) {
- rfbis.readFully(pixels8, dy * framebufferWidth + x, w);
- if (dos != null) {
- dos.write(pixels8, dy * framebufferWidth + x, w);
- }
- }
- } else {
- byte[] buf = new byte[w * 3];
- int i, offset;
- for (int dy = y; dy < y + h; dy++) {
- rfbis.readFully(buf);
- if (dos != null) {
- dos.write(buf);
- }
- offset = dy * framebufferWidth + x;
- for (i = 0; i < w; i++) {
- pixels24[offset + i] =
- (buf[i * 3] & 0xFF) << 16 |
- (buf[i * 3 + 1] & 0xFF) << 8 |
- (buf[i * 3 + 2] & 0xFF);
- }
- }
- }
- }
- } else {
- // Data was compressed with zlib.
- int zlibDataLen = rfbis.readCompactLen();
- byte[] zlibData = new byte[zlibDataLen];
- rfbis.readFully(zlibData);
- int stream_id = comp_ctl & 0x03;
- if (tightInflaters[stream_id] == null) {
- tightInflaters[stream_id] = new Inflater();
- }
- Inflater myInflater = tightInflaters[stream_id];
- myInflater.setInput(zlibData);
- byte[] buf = new byte[dataSize];
- myInflater.inflate(buf);
- if (dos != null) {
- recordCompressedData(buf);
- }
-
- if (numColors != 0) {
- // Indexed colors.
- if (numColors == 2) {
- // Two colors.
- if (bytesPerPixel == 1) {
- decodeMonoData(x, y, w, h, buf, palette8);
- } else {
- decodeMonoData(x, y, w, h, buf, palette24);
- }
- } else {
- // More than two colors (assuming bytesPixel == 4).
- int i = 0;
- for (int dy = y; dy < y + h; dy++) {
- for (int dx = x; dx < x + w; dx++) {
- pixels24[dy * framebufferWidth + dx] =
- palette24[buf[i++] & 0xFF];
- }
- }
- }
- } else if (useGradient) {
- // Compressed "Gradient"-filtered data (assuming bytesPixel == 4).
- decodeGradientData(x, y, w, h, buf);
- } else {
- // Compressed truecolor data.
- if (bytesPerPixel == 1) {
- int destOffset = y * framebufferWidth + x;
- for (int dy = 0; dy < h; dy++) {
- System.arraycopy(buf, dy * w, pixels8, destOffset, w);
- destOffset += framebufferWidth;
- }
- } else {
- int srcOffset = 0;
- int destOffset, i;
- for (int dy = 0; dy < h; dy++) {
- myInflater.inflate(buf);
- destOffset = (y + dy) * framebufferWidth + x;
- for (i = 0; i < w; i++) {
- RawDecoder.pixels24[destOffset + i] =
- (buf[srcOffset] & 0xFF) << 16 |
- (buf[srcOffset + 1] & 0xFF) << 8 |
- (buf[srcOffset + 2] & 0xFF);
- srcOffset += 3;
- }
- }
- }
- }
- }
- handleUpdatedPixels(x, y, w, h);
- }
-
- //
- // Decode 1bpp-encoded bi-color rectangle (8-bit and 24-bit versions).
- //
-
- private void decodeMonoData(int x, int y, int w, int h, byte[] src, byte[] palette) {
-
- int dx, dy, n;
- int i = y * framebufferWidth + x;
- int rowBytes = (w + 7) / 8;
- byte b;
-
- for (dy = 0; dy < h; dy++) {
- for (dx = 0; dx < w / 8; dx++) {
- b = src[dy*rowBytes+dx];
- for (n = 7; n >= 0; n--)
- pixels8[i++] = palette[b >> n & 1];
- }
- for (n = 7; n >= 8 - w % 8; n--) {
- pixels8[i++] = palette[src[dy*rowBytes+dx] >> n & 1];
- }
- i += (framebufferWidth - w);
- }
- }
-
- private void decodeMonoData(int x, int y, int w, int h, byte[] src, int[] palette) {
-
- int dx, dy, n;
- int i = y * framebufferWidth + x;
- int rowBytes = (w + 7) / 8;
- byte b;
-
- for (dy = 0; dy < h; dy++) {
- for (dx = 0; dx < w / 8; dx++) {
- b = src[dy*rowBytes+dx];
- for (n = 7; n >= 0; n--)
- pixels24[i++] = palette[b >> n & 1];
- }
- for (n = 7; n >= 8 - w % 8; n--) {
- pixels24[i++] = palette[src[dy*rowBytes+dx] >> n & 1];
- }
- i += (framebufferWidth - w);
- }
- }
-
- //
- // Decode data processed with the "Gradient" filter.
- //
-
- private void decodeGradientData (int x, int y, int w, int h, byte[] buf) {
-
- int dx, dy, c;
- byte[] prevRow = new byte[w * 3];
- byte[] thisRow = new byte[w * 3];
- byte[] pix = new byte[3];
- int[] est = new int[3];
-
- int offset = y * framebufferWidth + x;
-
- for (dy = 0; dy < h; dy++) {
-
- /* First pixel in a row */
- for (c = 0; c < 3; c++) {
- pix[c] = (byte)(prevRow[c] + buf[dy * w * 3 + c]);
- thisRow[c] = pix[c];
- }
- pixels24[offset++] =
- (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
-
- /* Remaining pixels of a row */
- for (dx = 1; dx < w; dx++) {
- for (c = 0; c < 3; c++) {
- est[c] = ((prevRow[dx * 3 + c] & 0xFF) + (pix[c] & 0xFF) -
- (prevRow[(dx-1) * 3 + c] & 0xFF));
- if (est[c] > 0xFF) {
- est[c] = 0xFF;
- } else if (est[c] < 0x00) {
- est[c] = 0x00;
- }
- pix[c] = (byte)(est[c] + buf[(dy * w + dx) * 3 + c]);
- thisRow[dx * 3 + c] = pix[c];
- }
- pixels24[offset++] =
- (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
- }
-
- System.arraycopy(thisRow, 0, prevRow, 0, w * 3);
- offset += (framebufferWidth - w);
- }
- }
-
- //
- // Override the ImageObserver interface method to handle drawing of
- // JPEG-encoded data.
- //
-
- public boolean imageUpdate(Image img, int infoflags,
- int x, int y, int width, int height) {
- if ((infoflags & (ALLBITS | ABORT)) == 0) {
- return true; // We need more image data.
- } else {
- // If the whole image is available, draw it now.
- if ((infoflags & ALLBITS) != 0) {
- if (jpegRect != null) {
- synchronized(jpegRect) {
- graphics.drawImage(img, jpegRect.x, jpegRect.y, null);
- repainatableControl.scheduleRepaint(jpegRect.x, jpegRect.y,
- jpegRect.width, jpegRect.height);
- jpegRect.notify();
- }
- }
- }
- return false; // All image data was processed.
- }
- }
-
- //
- // Write an integer in compact representation (1..3 bytes) into the
- // recorded session file.
- //
-
- void recordCompactLen(int len) throws IOException {
- byte[] buf = new byte[3];
- int bytes = 0;
- buf[bytes++] = (byte)(len & 0x7F);
- if (len > 0x7F) {
- buf[bytes-1] |= 0x80;
- buf[bytes++] = (byte)(len >> 7 & 0x7F);
- if (len > 0x3FFF) {
- buf[bytes-1] |= 0x80;
- buf[bytes++] = (byte)(len >> 14 & 0xFF);
- }
- }
- if (dos != null) dos.write(buf, 0, bytes);
- }
-
- //
- // Compress and write the data into the recorded session file.
- //
-
- void recordCompressedData(byte[] data, int off, int len) throws IOException {
- Deflater deflater = new Deflater();
- deflater.setInput(data, off, len);
- int bufSize = len + len / 100 + 12;
- byte[] buf = new byte[bufSize];
- deflater.finish();
- int compressedSize = deflater.deflate(buf);
- recordCompactLen(compressedSize);
- if (dos != null) dos.write(buf, 0, compressedSize);
- }
-
- void recordCompressedData(byte[] data) throws IOException {
- recordCompressedData(data, 0, data.length);
- }
-
- //
- // Private members
- //
-
- private Inflater[] tightInflaters;
- // Since JPEG images are loaded asynchronously, we have to remember
- // their position in the framebuffer. Also, this jpegRect object is
- // used for synchronization between the rfbThread and a JVM's thread
- // which decodes and loads JPEG images.
- private Rectangle jpegRect;
- private Repaintable repainatableControl = null;
- // Jpeg decoding statistics
- private long statNumRectsTightJPEG = 0;
- // Tight decoding statistics
- private long statNumRectsTight = 0;
-}
+++ /dev/null
-package com.tightvnc.decoder;
-
-import com.tightvnc.vncviewer.InStream;
-import com.tightvnc.vncviewer.RfbInputStream;
-import com.tightvnc.vncviewer.ZlibInStream;
-import java.awt.Graphics;
-import com.tightvnc.vncviewer.MemInStream;
-import java.awt.Color;
-import java.awt.Toolkit;
-import java.awt.image.MemoryImageSource;
-import java.io.IOException;
-
-//
-// Class that used for decoding ZRLE encoded data.
-//
-
-public class ZRLEDecoder extends RawDecoder {
-
- final static int EncodingZRLE = 16;
-
- public ZRLEDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public ZRLEDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Handle a ZRLE-encoded rectangle.
- //
- // FIXME: Currently, session recording is not fully supported for ZRLE.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(ZRLEDecoder.EncodingZRLE);
- }
-
- if (zrleInStream == null)
- zrleInStream = new ZlibInStream();
-
- int nBytes = rfbis.readU32();
- if (nBytes > 64 * 1024 * 1024)
- throw new Exception("ZRLE decoder: illegal compressed data size");
-
- if (zrleBuf == null || zrleBufLen < nBytes) {
- zrleBufLen = nBytes + 4096;
- zrleBuf = new byte[zrleBufLen];
- }
-
- // FIXME: Do not wait for all the data before decompression.
- rfbis.readFully(zrleBuf, 0, nBytes);
-
- //
- // Override handleRect method to decode RRE encoded data insted of
- // raw pixel data.
- //
-
- if (dos != null) {
- if (!zrleRecWarningShown) {
- System.out.println("Warning: ZRLE session can be recorded" +
- " only from the beginning");
- System.out.println("Warning: Recorded file may be corrupted");
- zrleRecWarningShown = true;
- }
- }
-
- zrleInStream.setUnderlying(new MemInStream(zrleBuf, 0, nBytes), nBytes);
-
- for (int ty = y; ty < y+h; ty += 64) {
-
- int th = Math.min(y+h-ty, 64);
-
- for (int tx = x; tx < x+w; tx += 64) {
-
- int tw = Math.min(x+w-tx, 64);
-
- int mode = zrleInStream.readU8();
- boolean rle = (mode & 128) != 0;
- int palSize = mode & 127;
- int[] palette = new int[128];
-
- readZrlePalette(palette, palSize);
-
- if (palSize == 1) {
- int pix = palette[0];
- Color c = (bytesPerPixel == 1) ?
- getColor256()[pix] : new Color(0xFF000000 | pix);
- graphics.setColor(c);
- graphics.fillRect(tx, ty, tw, th);
- continue;
- }
-
- if (!rle) {
- if (palSize == 0) {
- readZrleRawPixels(tw, th);
- } else {
- readZrlePackedPixels(tw, th, palette, palSize);
- }
- } else {
- if (palSize == 0) {
- readZrlePlainRLEPixels(tw, th);
- } else {
- readZrlePackedRLEPixels(tw, th, palette);
- }
- }
- handleUpdatedZrleTile(tx, ty, tw, th);
- }
- }
- zrleInStream.reset();
- }
-
- //
- // Override update() method cause we have own data that
- // must be updated when framebuffer is resized or BPP is changed
- //
-
- public void update() {
- // Images with raw pixels should be re-allocated on every change
- // of geometry or pixel format.
- int fbWidth = framebufferWidth;
- int fbHeight = framebufferHeight;
-
- if (bytesPerPixel == 1) {
- RawDecoder.pixels24 = null;
- RawDecoder.pixels8 = new byte[fbWidth * fbHeight];
- RawDecoder.pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(), pixels8, 0, fbWidth);
- zrleTilePixels24 = null;
- zrleTilePixels8 = new byte[64 * 64];
- } else {
- RawDecoder.pixels8 = null;
- RawDecoder.pixels24 = new int[fbWidth * fbHeight];
- RawDecoder.pixelsSource =
- new MemoryImageSource(fbWidth, fbHeight, getColorModel24(), pixels24, 0, fbWidth);
- zrleTilePixels8 = null;
- zrleTilePixels24 = new int[64 * 64];
- }
- RawDecoder.pixelsSource.setAnimated(true);
- RawDecoder.rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
- }
-
- //
- // Copy pixels from zrleTilePixels8 or zrleTilePixels24, then update.
- //
-
- private void handleUpdatedZrleTile(int x, int y, int w, int h) {
- Object src, dst;
- if (bytesPerPixel == 1) {
- src = zrleTilePixels8; dst = pixels8;
- } else {
- src = zrleTilePixels24; dst = pixels24;
- }
- int offsetSrc = 0;
- int offsetDst = (y * framebufferWidth + x);
- for (int j = 0; j < h; j++) {
- System.arraycopy(src, offsetSrc, dst, offsetDst, w);
- offsetSrc += w;
- offsetDst += framebufferWidth;
- }
- handleUpdatedPixels(x, y, w, h);
- }
-
- //
- // Private methods for reading ZRLE data
- //
-
- private int readPixel(InStream is) throws Exception {
- int pix;
- if (bytesPerPixel == 1) {
- pix = is.readU8();
- } else {
- int p1 = is.readU8();
- int p2 = is.readU8();
- int p3 = is.readU8();
- pix = (p3 & 0xFF) << 16 | (p2 & 0xFF) << 8 | (p1 & 0xFF);
- }
- return pix;
- }
-
- private void readPixels(InStream is, int[] dst, int count) throws Exception {
- if (bytesPerPixel == 1) {
- byte[] buf = new byte[count];
- is.readBytes(buf, 0, count);
- for (int i = 0; i < count; i++) {
- dst[i] = (int)buf[i] & 0xFF;
- }
- } else {
- byte[] buf = new byte[count * 3];
- is.readBytes(buf, 0, count * 3);
- for (int i = 0; i < count; i++) {
- dst[i] = ((buf[i*3+2] & 0xFF) << 16 |
- (buf[i*3+1] & 0xFF) << 8 |
- (buf[i*3] & 0xFF));
- }
- }
- }
-
- private void readZrlePalette(int[] palette, int palSize) throws Exception {
- readPixels(zrleInStream, palette, palSize);
- }
-
- private void readZrleRawPixels(int tw, int th) throws Exception {
- if (bytesPerPixel == 1) {
- zrleInStream.readBytes(zrleTilePixels8, 0, tw * th);
- } else {
- readPixels(zrleInStream, zrleTilePixels24, tw * th); ///
- }
- }
-
- private void readZrlePackedPixels(int tw, int th, int[] palette, int palSize)
- throws Exception {
-
- int bppp = ((palSize > 16) ? 8 :
- ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
- int ptr = 0;
-
- for (int i = 0; i < th; i++) {
- int eol = ptr + tw;
- int b = 0;
- int nbits = 0;
-
- while (ptr < eol) {
- if (nbits == 0) {
- b = zrleInStream.readU8();
- nbits = 8;
- }
- nbits -= bppp;
- int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
- if (bytesPerPixel == 1) {
- zrleTilePixels8[ptr++] = (byte)palette[index];
- } else {
- zrleTilePixels24[ptr++] = palette[index];
- }
- }
- }
- }
-
- private void readZrlePlainRLEPixels(int tw, int th) throws Exception {
- int ptr = 0;
- int end = ptr + tw * th;
- while (ptr < end) {
- int pix = readPixel(zrleInStream);
- int len = 1;
- int b;
- do {
- b = zrleInStream.readU8();
- len += b;
- } while (b == 255);
-
- if (!(len <= end - ptr))
- throw new Exception("ZRLE decoder: assertion failed" +
- " (len <= end-ptr)");
-
- if (bytesPerPixel == 1) {
- while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
- } else {
- while (len-- > 0) zrleTilePixels24[ptr++] = pix;
- }
- }
- }
-
- private void readZrlePackedRLEPixels(int tw, int th, int[] palette)
- throws Exception {
-
- int ptr = 0;
- int end = ptr + tw * th;
- while (ptr < end) {
- int index = zrleInStream.readU8();
- int len = 1;
- if ((index & 128) != 0) {
- int b;
- do {
- b = zrleInStream.readU8();
- len += b;
- } while (b == 255);
-
- if (!(len <= end - ptr))
- throw new Exception("ZRLE decoder: assertion failed" +
- " (len <= end - ptr)");
- }
-
- index &= 127;
- int pix = palette[index];
-
- if (bytesPerPixel == 1) {
- while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
- } else {
- while (len-- > 0) zrleTilePixels24[ptr++] = pix;
- }
- }
- }
-
- //
- // ZRLE encoder's data.
- //
-
- private byte[] zrleBuf;
- private int zrleBufLen = 0;
- private byte[] zrleTilePixels8;
- private int[] zrleTilePixels24;
- private ZlibInStream zrleInStream;
- private boolean zrleRecWarningShown = false;
-}
+++ /dev/null
-package com.tightvnc.decoder;
-
-import com.tightvnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.io.IOException;
-import java.util.zip.DataFormatException;
-import java.util.zip.Inflater;
-
-//
-// Class that used for decoding ZLib encoded data.
-//
-
-public class ZlibDecoder extends RawDecoder {
-
- final static int EncodingZlib = 6;
-
- public ZlibDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public ZlibDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Override handleRect method to decode ZLib encoded data insted of
- // raw pixel data.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException {
-
- //
- // Write encoding ID to record output stream.
- // Remark: we forced changed encoding from zlib to raw
- // cause at this moment we cannot save data in zlib encoding.
- //
-
- if (dos != null) {
- dos.writeInt(RawDecoder.EncodingRaw);
- }
-
- int nBytes = rfbis.readU32();
-
- if (zlibBuf == null || zlibBufLen < nBytes) {
- zlibBufLen = nBytes * 2;
- zlibBuf = new byte[zlibBufLen];
- }
-
- rfbis.readFully(zlibBuf, 0, nBytes);
-
- if (zlibInflater == null) {
- zlibInflater = new Inflater();
- }
- zlibInflater.setInput(zlibBuf, 0, nBytes);
-
- try {
- if (bytesPerPixel == 1) {
- for (int dy = y; dy < y + h; dy++) {
- zlibInflater.inflate(pixels8, dy * framebufferWidth + x, w);
-
- //
- // Save decoded raw data to data output stream
- //
-
- if (dos != null)
- dos.write(pixels8, dy * framebufferWidth + x, w);
- }
- } else {
- byte[] buf = new byte[w * 4];
- int i, offset;
- for (int dy = y; dy < y + h; dy++) {
- zlibInflater.inflate(buf);
- offset = dy * framebufferWidth + x;
- for (i = 0; i < w; i++) {
- RawDecoder.pixels24[offset + i] =
- (buf[i * 4 + 2] & 0xFF) << 16 |
- (buf[i * 4 + 1] & 0xFF) << 8 |
- (buf[i * 4] & 0xFF);
- }
-
- //
- // Save decoded raw data to data output stream
- //
-
- if (dos != null)
- dos.write(buf);
- }
- }
- } catch (DataFormatException ex) {
- ex.printStackTrace();
- }
- handleUpdatedPixels(x, y, w, h);
- }
-
- //
- // Zlib encoder's data.
- //
-
- protected byte[] zlibBuf;
- protected int zlibBufLen = 0;
- protected Inflater zlibInflater;
-}
+++ /dev/null
-package com.tightvnc.decoder.common;
-
-public interface Repaintable {
-
- public void scheduleRepaint(int x, int y, int w, int h);
-
-}
+++ /dev/null
-//
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-// Copyright (C) 2002-2006 Constantin Kaplinsky. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-
-//
-// The panel which implements the user authentication scheme
-//
-
-class AuthPanel extends Panel implements ActionListener {
-
- TextField passwordField;
- Button okButton;
-
- //
- // Constructor.
- //
-
- public AuthPanel(VncViewer viewer)
- {
- Label titleLabel = new Label("VNC Authentication", Label.CENTER);
- titleLabel.setFont(new Font("Helvetica", Font.BOLD, 18));
-
- Label promptLabel = new Label("Password:", Label.CENTER);
-
- passwordField = new TextField(10);
- passwordField.setForeground(Color.black);
- passwordField.setBackground(Color.white);
- passwordField.setEchoChar('*');
-
- okButton = new Button("OK");
-
- GridBagLayout gridbag = new GridBagLayout();
- GridBagConstraints gbc = new GridBagConstraints();
-
- setLayout(gridbag);
-
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.insets = new Insets(0,0,20,0);
- gridbag.setConstraints(titleLabel,gbc);
- add(titleLabel);
-
- gbc.fill = GridBagConstraints.NONE;
- gbc.gridwidth = 1;
- gbc.insets = new Insets(0,0,0,0);
- gridbag.setConstraints(promptLabel,gbc);
- add(promptLabel);
-
- gridbag.setConstraints(passwordField,gbc);
- add(passwordField);
- passwordField.addActionListener(this);
-
- // gbc.ipady = 10;
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.fill = GridBagConstraints.BOTH;
- gbc.insets = new Insets(0,20,0,0);
- gbc.ipadx = 30;
- gridbag.setConstraints(okButton,gbc);
- add(okButton);
- okButton.addActionListener(this);
- }
-
- //
- // Move keyboard focus to the default object, that is, the password
- // text field.
- //
-
- public void moveFocusToDefaultField()
- {
- passwordField.requestFocus();
- }
-
- //
- // This method is called when a button is pressed or return is
- // pressed in the password text field.
- //
-
- public synchronized void actionPerformed(ActionEvent evt)
- {
- if (evt.getSource() == passwordField || evt.getSource() == okButton) {
- passwordField.setEnabled(false);
- notify();
- }
- }
-
- //
- // Wait for user entering a password, and return it as String.
- //
-
- public synchronized String getPassword() throws Exception
- {
- try {
- wait();
- } catch (InterruptedException e) { }
- return passwordField.getText();
- }
-
-}
+++ /dev/null
-//
-// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// ButtonPanel class implements panel with four buttons in the
-// VNCViewer desktop window.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.io.*;
-
-class ButtonPanel extends Panel implements ActionListener {
-
- VncViewer viewer;
- Button disconnectButton;
- Button optionsButton;
- Button recordButton;
- Button clipboardButton;
- Button ctrlAltDelButton;
- Button refreshButton;
- Button selectButton;
- Button videoFreezeButton;
-
- final String enableVideoFreezeLabel = "Ignore Video";
- final String disableVideoFreezeLabel = "Enable Video";
- final String selectEnterLabel = "Select Video Area";
- final String selectLeaveLabel = "Hide Selection";
-
- ButtonPanel(VncViewer v) {
- viewer = v;
-
- setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
- disconnectButton = new Button("Disconnect");
- disconnectButton.setEnabled(false);
- add(disconnectButton);
- disconnectButton.addActionListener(this);
- optionsButton = new Button("Options");
- add(optionsButton);
- optionsButton.addActionListener(this);
- clipboardButton = new Button("Clipboard");
- clipboardButton.setEnabled(false);
- add(clipboardButton);
- clipboardButton.addActionListener(this);
- if (viewer.rec != null) {
- recordButton = new Button("Record");
- add(recordButton);
- recordButton.addActionListener(this);
- }
- ctrlAltDelButton = new Button("Send Ctrl-Alt-Del");
- ctrlAltDelButton.setEnabled(false);
- add(ctrlAltDelButton);
- ctrlAltDelButton.addActionListener(this);
- refreshButton = new Button("Refresh");
- refreshButton.setEnabled(false);
- add(refreshButton);
- refreshButton.addActionListener(this);
- }
-
- /**
- * Add video selection button to the ButtonPanel.
- */
- public void addSelectButton() {
- selectButton = new Button(selectEnterLabel);
- selectButton.setEnabled(false);
- add(selectButton);
- selectButton.addActionListener(this);
- }
-
- /**
- * Add video ignore button to the ButtonPanel.
- */
- public void addVideoFreezeButton() {
- videoFreezeButton = new Button(enableVideoFreezeLabel);
- add(videoFreezeButton);
- videoFreezeButton.addActionListener(this);
- }
-
- //
- // Enable buttons on successful connection.
- //
-
- public void enableButtons() {
- disconnectButton.setEnabled(true);
- clipboardButton.setEnabled(true);
- refreshButton.setEnabled(true);
- if (selectButton != null) {
- selectButton.setEnabled(true);
- }
- }
-
- //
- // Disable all buttons on disconnect.
- //
-
- public void disableButtonsOnDisconnect() {
- remove(disconnectButton);
- disconnectButton = new Button("Hide desktop");
- disconnectButton.setEnabled(true);
- add(disconnectButton, 0);
- disconnectButton.addActionListener(this);
-
- optionsButton.setEnabled(false);
- clipboardButton.setEnabled(false);
- ctrlAltDelButton.setEnabled(false);
- refreshButton.setEnabled(false);
- if (selectButton != null) {
- selectButton.setEnabled(false);
- }
- }
-
- //
- // Enable/disable controls that should not be available in view-only
- // mode.
- //
-
- public void enableRemoteAccessControls(boolean enable) {
- ctrlAltDelButton.setEnabled(enable);
- }
-
- //
- // Event processing.
- //
-
- public void actionPerformed(ActionEvent evt) {
-
- viewer.moveFocusToDesktop();
-
- if (evt.getSource() == disconnectButton) {
- viewer.disconnect();
-
- } else if (evt.getSource() == optionsButton) {
- viewer.options.setVisible(!viewer.options.isVisible());
-
- } else if (evt.getSource() == recordButton) {
- viewer.rec.setVisible(!viewer.rec.isVisible());
-
- } else if (evt.getSource() == clipboardButton) {
- viewer.clipboard.setVisible(!viewer.clipboard.isVisible());
- } else if (evt.getSource() == videoFreezeButton) {
-
- //
- // Send video freeze message to server and change caption of button
- //
-
- //
- // TODO: Move this code to another place.
- //
-
- boolean sendOk = true;
- boolean currentFreezeState =
- videoFreezeButton.getLabel().equals(disableVideoFreezeLabel);
- try {
- viewer.rfb.trySendVideoFreeze(!currentFreezeState);
- } catch (IOException ex) {
- sendOk = false;
- ex.printStackTrace();
- }
- if (sendOk) {
- if (!currentFreezeState) {
- videoFreezeButton.setLabel(disableVideoFreezeLabel);
- } else {
- videoFreezeButton.setLabel(enableVideoFreezeLabel);
- }
- }
- } else if (evt.getSource() == ctrlAltDelButton) {
- try {
- final int modifiers = InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
-
- KeyEvent ctrlAltDelEvent =
- new KeyEvent(this, KeyEvent.KEY_PRESSED, 0, modifiers, 127);
- viewer.rfb.writeKeyEvent(ctrlAltDelEvent);
-
- ctrlAltDelEvent =
- new KeyEvent(this, KeyEvent.KEY_RELEASED, 0, modifiers, 127);
- viewer.rfb.writeKeyEvent(ctrlAltDelEvent);
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- } else if (evt.getSource() == refreshButton) {
- try {
- RfbProto rfb = viewer.rfb;
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, false);
- } catch (IOException e) {
- e.printStackTrace();
- }
- } else if (selectButton != null && evt.getSource() == selectButton) {
- if (viewer.vc != null) {
- boolean isSelecting = viewer.vc.isInSelectionMode();
- if (!isSelecting) {
- selectButton.setLabel(selectLeaveLabel);
- viewer.vc.enableSelection(true);
- } else {
- selectButton.setLabel(selectEnterLabel);
- viewer.vc.enableSelection(false);
- }
- }
- }
- }
-}
-
+++ /dev/null
-//
-// Copyright (C) 2003 Constantin Kaplinsky. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// CapabilityInfo.java - A class to hold information about a
-// particular capability as used in the RFB protocol 3.130.
-//
-
-package com.tightvnc.vncviewer;
-
-class CapabilityInfo {
-
- // Public methods
-
- public CapabilityInfo(int code,
- String vendorSignature,
- String nameSignature,
- String description) {
- this.code = code;
- this.vendorSignature = vendorSignature;
- this.nameSignature = nameSignature;
- this.description = description;
- enabled = false;
- }
-
- public CapabilityInfo(int code,
- byte[] vendorSignature,
- byte[] nameSignature) {
- this.code = code;
- this.vendorSignature = new String(vendorSignature);
- this.nameSignature = new String(nameSignature);
- this.description = null;
- enabled = false;
- }
-
- public int getCode() {
- return code;
- }
-
- public String getDescription() {
- return description;
- }
-
- public boolean isEnabled() {
- return enabled;
- }
-
- public void enable() {
- enabled = true;
- }
-
- public boolean equals(CapabilityInfo other) {
- return (other != null && this.code == other.code &&
- this.vendorSignature.equals(other.vendorSignature) &&
- this.nameSignature.equals(other.nameSignature));
- }
-
- public boolean enableIfEquals(CapabilityInfo other) {
- if (this.equals(other))
- enable();
-
- return isEnabled();
- }
-
- // Protected data
-
- protected int code;
- protected String vendorSignature;
- protected String nameSignature;
-
- protected String description;
- protected boolean enabled;
-}
+++ /dev/null
-//
-// Copyright (C) 2003 Constantin Kaplinsky. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// CapsContainer.java - A container of capabilities as used in the RFB
-// protocol 3.130
-//
-
-package com.tightvnc.vncviewer;
-
-import java.util.Vector;
-import java.util.Hashtable;
-
-class CapsContainer {
-
- // Public methods
-
- public CapsContainer() {
- infoMap = new Hashtable(64, (float)0.25);
- orderedList = new Vector(32, 8);
- }
-
- public void add(CapabilityInfo capinfo) {
- Integer key = new Integer(capinfo.getCode());
- infoMap.put(key, capinfo);
- }
-
- public void add(int code, String vendor, String name, String desc) {
- Integer key = new Integer(code);
- infoMap.put(key, new CapabilityInfo(code, vendor, name, desc));
- }
-
- public boolean isKnown(int code) {
- return infoMap.containsKey(new Integer(code));
- }
-
- public CapabilityInfo getInfo(int code) {
- return (CapabilityInfo)infoMap.get(new Integer(code));
- }
-
- public String getDescription(int code) {
- CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(new Integer(code));
- if (capinfo == null)
- return null;
-
- return capinfo.getDescription();
- }
-
- public boolean enable(CapabilityInfo other) {
- Integer key = new Integer(other.getCode());
- CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(key);
- if (capinfo == null)
- return false;
-
- boolean enabled = capinfo.enableIfEquals(other);
- if (enabled)
- orderedList.addElement(key);
-
- return enabled;
- }
-
- public boolean isEnabled(int code) {
- CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(new Integer(code));
- if (capinfo == null)
- return false;
-
- return capinfo.isEnabled();
- }
-
- public int numEnabled() {
- return orderedList.size();
- }
-
- public int getByOrder(int idx) {
- int code;
- try {
- code = ((Integer)orderedList.elementAt(idx)).intValue();
- } catch (ArrayIndexOutOfBoundsException e) {
- code = 0;
- }
- return code;
- }
-
- // Protected data
-
- protected Hashtable infoMap;
- protected Vector orderedList;
-}
-
+++ /dev/null
-//
-// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// Clipboard frame.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-
-class ClipboardFrame extends Frame
- implements WindowListener, ActionListener {
-
- TextArea textArea;
- Button clearButton, closeButton;
- String selection;
- VncViewer viewer;
-
- //
- // Constructor.
- //
-
- ClipboardFrame(VncViewer v) {
- super("TigerVNC Clipboard");
-
- viewer = v;
-
- GridBagLayout gridbag = new GridBagLayout();
- setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.fill = GridBagConstraints.BOTH;
- gbc.weighty = 1.0;
-
- textArea = new TextArea(5, 40);
- gridbag.setConstraints(textArea, gbc);
- add(textArea);
-
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.weightx = 1.0;
- gbc.weighty = 0.0;
- gbc.gridwidth = 1;
-
- clearButton = new Button("Clear");
- gridbag.setConstraints(clearButton, gbc);
- add(clearButton);
- clearButton.addActionListener(this);
-
- closeButton = new Button("Close");
- gridbag.setConstraints(closeButton, gbc);
- add(closeButton);
- closeButton.addActionListener(this);
-
- pack();
-
- addWindowListener(this);
- }
-
-
- //
- // Set the cut text from the RFB server.
- //
-
- void setCutText(String text) {
- selection = text;
- textArea.setText(text);
- if (isVisible()) {
- textArea.selectAll();
- }
- }
-
-
- //
- // When the focus leaves the window, see if we have new cut text and
- // if so send it to the RFB server.
- //
-
- public void windowDeactivated (WindowEvent evt) {
- if (selection != null && !selection.equals(textArea.getText())) {
- selection = textArea.getText();
- viewer.setCutText(selection);
- }
- }
-
- //
- // Close our window properly.
- //
-
- public void windowClosing(WindowEvent evt) {
- setVisible(false);
- }
-
- //
- // Ignore window events we're not interested in.
- //
-
- public void windowActivated(WindowEvent evt) {}
- public void windowOpened(WindowEvent evt) {}
- public void windowClosed(WindowEvent evt) {}
- public void windowIconified(WindowEvent evt) {}
- public void windowDeiconified(WindowEvent evt) {}
-
-
- //
- // Respond to button presses
- //
-
- public void actionPerformed(ActionEvent evt) {
- if (evt.getSource() == clearButton) {
- textArea.setText("");
- } else if (evt.getSource() == closeButton) {
- setVisible(false);
- }
- }
-}
+++ /dev/null
-//
-// This DES class has been extracted from package Acme.Crypto for use in VNC.
-// The bytebit[] array has been reversed so that the most significant bit
-// in each byte of the key is ignored, not the least significant. Also the
-// unnecessary odd parity code has been removed.
-//
-// These changes are:
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-//
-
-// DesCipher - the DES encryption method
-//
-// The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is:
-//
-// Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
-//
-// Permission to use, copy, modify, and distribute this software
-// and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
-// without fee is hereby granted, provided that this copyright notice is kept
-// intact.
-//
-// WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
-// OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
-// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
-// FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
-// DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
-//
-// THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
-// CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
-// PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
-// NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
-// SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
-// SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
-// PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
-// SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
-// HIGH RISK ACTIVITIES.
-//
-//
-// The rest is:
-//
-// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-// 1. Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-// SUCH DAMAGE.
-//
-// Visit the ACME Labs Java page for up-to-date versions of this and other
-// fine Java utilities: http://www.acme.com/java/
-
-
-package com.tightvnc.vncviewer;
-
-import java.io.*;
-
-/// The DES encryption method.
-// <P>
-// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped
-// in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream,
-// it does around 7000 bytes/second.
-// <P>
-// Most of this code is by Dave Zimmerman <dzimm@widget.com>, and is
-// Copyright (c) 1996 Widget Workshop, Inc. See the source file for details.
-// <P>
-// <A HREF="/resources/classes/Acme/Crypto/DesCipher.java">Fetch the software.</A><BR>
-// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
-// <P>
-// @see Des3Cipher
-// @see EncryptedOutputStream
-// @see EncryptedInputStream
-
-public class DesCipher
- {
-
- // Constructor, byte-array key.
- public DesCipher( byte[] key )
- {
- setKey( key );
- }
-
- // Key routines.
-
- private int[] encryptKeys = new int[32];
- private int[] decryptKeys = new int[32];
-
- /// Set the key.
- public void setKey( byte[] key )
- {
- deskey( key, true, encryptKeys );
- deskey( key, false, decryptKeys );
- }
-
- // Turn an 8-byte key into internal keys.
- private void deskey( byte[] keyBlock, boolean encrypting, int[] KnL )
- {
- int i, j, l, m, n;
- int[] pc1m = new int[56];
- int[] pcr = new int[56];
- int[] kn = new int[32];
-
- for ( j = 0; j < 56; ++j )
- {
- l = pc1[j];
- m = l & 07;
- pc1m[j] = ( (keyBlock[l >>> 3] & bytebit[m]) != 0 )? 1: 0;
- }
-
- for ( i = 0; i < 16; ++i )
- {
- if ( encrypting )
- m = i << 1;
- else
- m = (15-i) << 1;
- n = m+1;
- kn[m] = kn[n] = 0;
- for ( j = 0; j < 28; ++j )
- {
- l = j+totrot[i];
- if ( l < 28 )
- pcr[j] = pc1m[l];
- else
- pcr[j] = pc1m[l-28];
- }
- for ( j=28; j < 56; ++j )
- {
- l = j+totrot[i];
- if ( l < 56 )
- pcr[j] = pc1m[l];
- else
- pcr[j] = pc1m[l-28];
- }
- for ( j = 0; j < 24; ++j )
- {
- if ( pcr[pc2[j]] != 0 )
- kn[m] |= bigbyte[j];
- if ( pcr[pc2[j+24]] != 0 )
- kn[n] |= bigbyte[j];
- }
- }
- cookey( kn, KnL );
- }
-
- private void cookey( int[] raw, int KnL[] )
- {
- int raw0, raw1;
- int rawi, KnLi;
- int i;
-
- for ( i = 0, rawi = 0, KnLi = 0; i < 16; ++i )
- {
- raw0 = raw[rawi++];
- raw1 = raw[rawi++];
- KnL[KnLi] = (raw0 & 0x00fc0000) << 6;
- KnL[KnLi] |= (raw0 & 0x00000fc0) << 10;
- KnL[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
- KnL[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
- ++KnLi;
- KnL[KnLi] = (raw0 & 0x0003f000) << 12;
- KnL[KnLi] |= (raw0 & 0x0000003f) << 16;
- KnL[KnLi] |= (raw1 & 0x0003f000) >>> 4;
- KnL[KnLi] |= (raw1 & 0x0000003f);
- ++KnLi;
- }
- }
-
-
- // Block encryption routines.
-
- private int[] tempInts = new int[2];
-
- /// Encrypt a block of eight bytes.
- public void encrypt( byte[] clearText, int clearOff, byte[] cipherText, int cipherOff )
- {
- squashBytesToInts( clearText, clearOff, tempInts, 0, 2 );
- des( tempInts, tempInts, encryptKeys );
- spreadIntsToBytes( tempInts, 0, cipherText, cipherOff, 2 );
- }
-
- /// Decrypt a block of eight bytes.
- public void decrypt( byte[] cipherText, int cipherOff, byte[] clearText, int clearOff )
- {
- squashBytesToInts( cipherText, cipherOff, tempInts, 0, 2 );
- des( tempInts, tempInts, decryptKeys );
- spreadIntsToBytes( tempInts, 0, clearText, clearOff, 2 );
- }
-
- // The DES function.
- private void des( int[] inInts, int[] outInts, int[] keys )
- {
- int fval, work, right, leftt;
- int round;
- int keysi = 0;
-
- leftt = inInts[0];
- right = inInts[1];
-
- work = ((leftt >>> 4) ^ right) & 0x0f0f0f0f;
- right ^= work;
- leftt ^= (work << 4);
-
- work = ((leftt >>> 16) ^ right) & 0x0000ffff;
- right ^= work;
- leftt ^= (work << 16);
-
- work = ((right >>> 2) ^ leftt) & 0x33333333;
- leftt ^= work;
- right ^= (work << 2);
-
- work = ((right >>> 8) ^ leftt) & 0x00ff00ff;
- leftt ^= work;
- right ^= (work << 8);
- right = (right << 1) | ((right >>> 31) & 1);
-
- work = (leftt ^ right) & 0xaaaaaaaa;
- leftt ^= work;
- right ^= work;
- leftt = (leftt << 1) | ((leftt >>> 31) & 1);
-
- for ( round = 0; round < 8; ++round )
- {
- work = (right << 28) | (right >>> 4);
- work ^= keys[keysi++];
- fval = SP7[ work & 0x0000003f ];
- fval |= SP5[(work >>> 8) & 0x0000003f ];
- fval |= SP3[(work >>> 16) & 0x0000003f ];
- fval |= SP1[(work >>> 24) & 0x0000003f ];
- work = right ^ keys[keysi++];
- fval |= SP8[ work & 0x0000003f ];
- fval |= SP6[(work >>> 8) & 0x0000003f ];
- fval |= SP4[(work >>> 16) & 0x0000003f ];
- fval |= SP2[(work >>> 24) & 0x0000003f ];
- leftt ^= fval;
- work = (leftt << 28) | (leftt >>> 4);
- work ^= keys[keysi++];
- fval = SP7[ work & 0x0000003f ];
- fval |= SP5[(work >>> 8) & 0x0000003f ];
- fval |= SP3[(work >>> 16) & 0x0000003f ];
- fval |= SP1[(work >>> 24) & 0x0000003f ];
- work = leftt ^ keys[keysi++];
- fval |= SP8[ work & 0x0000003f ];
- fval |= SP6[(work >>> 8) & 0x0000003f ];
- fval |= SP4[(work >>> 16) & 0x0000003f ];
- fval |= SP2[(work >>> 24) & 0x0000003f ];
- right ^= fval;
- }
-
- right = (right << 31) | (right >>> 1);
- work = (leftt ^ right) & 0xaaaaaaaa;
- leftt ^= work;
- right ^= work;
- leftt = (leftt << 31) | (leftt >>> 1);
- work = ((leftt >>> 8) ^ right) & 0x00ff00ff;
- right ^= work;
- leftt ^= (work << 8);
- work = ((leftt >>> 2) ^ right) & 0x33333333;
- right ^= work;
- leftt ^= (work << 2);
- work = ((right >>> 16) ^ leftt) & 0x0000ffff;
- leftt ^= work;
- right ^= (work << 16);
- work = ((right >>> 4) ^ leftt) & 0x0f0f0f0f;
- leftt ^= work;
- right ^= (work << 4);
- outInts[0] = right;
- outInts[1] = leftt;
- }
-
-
- // Tables, permutations, S-boxes, etc.
-
- private static byte[] bytebit = {
- (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x08,
- (byte)0x10, (byte)0x20, (byte)0x40, (byte)0x80
- };
- private static int[] bigbyte = {
- 0x800000, 0x400000, 0x200000, 0x100000,
- 0x080000, 0x040000, 0x020000, 0x010000,
- 0x008000, 0x004000, 0x002000, 0x001000,
- 0x000800, 0x000400, 0x000200, 0x000100,
- 0x000080, 0x000040, 0x000020, 0x000010,
- 0x000008, 0x000004, 0x000002, 0x000001
- };
- private static byte[] pc1 = {
- (byte)56, (byte)48, (byte)40, (byte)32, (byte)24, (byte)16, (byte) 8,
- (byte) 0, (byte)57, (byte)49, (byte)41, (byte)33, (byte)25, (byte)17,
- (byte) 9, (byte) 1, (byte)58, (byte)50, (byte)42, (byte)34, (byte)26,
- (byte)18, (byte)10, (byte) 2, (byte)59, (byte)51, (byte)43, (byte)35,
- (byte)62, (byte)54, (byte)46, (byte)38, (byte)30, (byte)22, (byte)14,
- (byte) 6, (byte)61, (byte)53, (byte)45, (byte)37, (byte)29, (byte)21,
- (byte)13, (byte) 5, (byte)60, (byte)52, (byte)44, (byte)36, (byte)28,
- (byte)20, (byte)12, (byte) 4, (byte)27, (byte)19, (byte)11, (byte)3
- };
- private static int[] totrot = {
- 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
- };
-
- private static byte[] pc2 = {
- (byte)13, (byte)16, (byte)10, (byte)23, (byte) 0, (byte) 4,
- (byte) 2, (byte)27, (byte)14, (byte) 5, (byte)20, (byte) 9,
- (byte)22, (byte)18, (byte)11, (byte)3 , (byte)25, (byte) 7,
- (byte)15, (byte) 6, (byte)26, (byte)19, (byte)12, (byte) 1,
- (byte)40, (byte)51, (byte)30, (byte)36, (byte)46, (byte)54,
- (byte)29, (byte)39, (byte)50, (byte)44, (byte)32, (byte)47,
- (byte)43, (byte)48, (byte)38, (byte)55, (byte)33, (byte)52,
- (byte)45, (byte)41, (byte)49, (byte)35, (byte)28, (byte)31,
- };
-
- private static int[] SP1 = {
- 0x01010400, 0x00000000, 0x00010000, 0x01010404,
- 0x01010004, 0x00010404, 0x00000004, 0x00010000,
- 0x00000400, 0x01010400, 0x01010404, 0x00000400,
- 0x01000404, 0x01010004, 0x01000000, 0x00000004,
- 0x00000404, 0x01000400, 0x01000400, 0x00010400,
- 0x00010400, 0x01010000, 0x01010000, 0x01000404,
- 0x00010004, 0x01000004, 0x01000004, 0x00010004,
- 0x00000000, 0x00000404, 0x00010404, 0x01000000,
- 0x00010000, 0x01010404, 0x00000004, 0x01010000,
- 0x01010400, 0x01000000, 0x01000000, 0x00000400,
- 0x01010004, 0x00010000, 0x00010400, 0x01000004,
- 0x00000400, 0x00000004, 0x01000404, 0x00010404,
- 0x01010404, 0x00010004, 0x01010000, 0x01000404,
- 0x01000004, 0x00000404, 0x00010404, 0x01010400,
- 0x00000404, 0x01000400, 0x01000400, 0x00000000,
- 0x00010004, 0x00010400, 0x00000000, 0x01010004
- };
- private static int[] SP2 = {
- 0x80108020, 0x80008000, 0x00008000, 0x00108020,
- 0x00100000, 0x00000020, 0x80100020, 0x80008020,
- 0x80000020, 0x80108020, 0x80108000, 0x80000000,
- 0x80008000, 0x00100000, 0x00000020, 0x80100020,
- 0x00108000, 0x00100020, 0x80008020, 0x00000000,
- 0x80000000, 0x00008000, 0x00108020, 0x80100000,
- 0x00100020, 0x80000020, 0x00000000, 0x00108000,
- 0x00008020, 0x80108000, 0x80100000, 0x00008020,
- 0x00000000, 0x00108020, 0x80100020, 0x00100000,
- 0x80008020, 0x80100000, 0x80108000, 0x00008000,
- 0x80100000, 0x80008000, 0x00000020, 0x80108020,
- 0x00108020, 0x00000020, 0x00008000, 0x80000000,
- 0x00008020, 0x80108000, 0x00100000, 0x80000020,
- 0x00100020, 0x80008020, 0x80000020, 0x00100020,
- 0x00108000, 0x00000000, 0x80008000, 0x00008020,
- 0x80000000, 0x80100020, 0x80108020, 0x00108000
- };
- private static int[] SP3 = {
- 0x00000208, 0x08020200, 0x00000000, 0x08020008,
- 0x08000200, 0x00000000, 0x00020208, 0x08000200,
- 0x00020008, 0x08000008, 0x08000008, 0x00020000,
- 0x08020208, 0x00020008, 0x08020000, 0x00000208,
- 0x08000000, 0x00000008, 0x08020200, 0x00000200,
- 0x00020200, 0x08020000, 0x08020008, 0x00020208,
- 0x08000208, 0x00020200, 0x00020000, 0x08000208,
- 0x00000008, 0x08020208, 0x00000200, 0x08000000,
- 0x08020200, 0x08000000, 0x00020008, 0x00000208,
- 0x00020000, 0x08020200, 0x08000200, 0x00000000,
- 0x00000200, 0x00020008, 0x08020208, 0x08000200,
- 0x08000008, 0x00000200, 0x00000000, 0x08020008,
- 0x08000208, 0x00020000, 0x08000000, 0x08020208,
- 0x00000008, 0x00020208, 0x00020200, 0x08000008,
- 0x08020000, 0x08000208, 0x00000208, 0x08020000,
- 0x00020208, 0x00000008, 0x08020008, 0x00020200
- };
- private static int[] SP4 = {
- 0x00802001, 0x00002081, 0x00002081, 0x00000080,
- 0x00802080, 0x00800081, 0x00800001, 0x00002001,
- 0x00000000, 0x00802000, 0x00802000, 0x00802081,
- 0x00000081, 0x00000000, 0x00800080, 0x00800001,
- 0x00000001, 0x00002000, 0x00800000, 0x00802001,
- 0x00000080, 0x00800000, 0x00002001, 0x00002080,
- 0x00800081, 0x00000001, 0x00002080, 0x00800080,
- 0x00002000, 0x00802080, 0x00802081, 0x00000081,
- 0x00800080, 0x00800001, 0x00802000, 0x00802081,
- 0x00000081, 0x00000000, 0x00000000, 0x00802000,
- 0x00002080, 0x00800080, 0x00800081, 0x00000001,
- 0x00802001, 0x00002081, 0x00002081, 0x00000080,
- 0x00802081, 0x00000081, 0x00000001, 0x00002000,
- 0x00800001, 0x00002001, 0x00802080, 0x00800081,
- 0x00002001, 0x00002080, 0x00800000, 0x00802001,
- 0x00000080, 0x00800000, 0x00002000, 0x00802080
- };
- private static int[] SP5 = {
- 0x00000100, 0x02080100, 0x02080000, 0x42000100,
- 0x00080000, 0x00000100, 0x40000000, 0x02080000,
- 0x40080100, 0x00080000, 0x02000100, 0x40080100,
- 0x42000100, 0x42080000, 0x00080100, 0x40000000,
- 0x02000000, 0x40080000, 0x40080000, 0x00000000,
- 0x40000100, 0x42080100, 0x42080100, 0x02000100,
- 0x42080000, 0x40000100, 0x00000000, 0x42000000,
- 0x02080100, 0x02000000, 0x42000000, 0x00080100,
- 0x00080000, 0x42000100, 0x00000100, 0x02000000,
- 0x40000000, 0x02080000, 0x42000100, 0x40080100,
- 0x02000100, 0x40000000, 0x42080000, 0x02080100,
- 0x40080100, 0x00000100, 0x02000000, 0x42080000,
- 0x42080100, 0x00080100, 0x42000000, 0x42080100,
- 0x02080000, 0x00000000, 0x40080000, 0x42000000,
- 0x00080100, 0x02000100, 0x40000100, 0x00080000,
- 0x00000000, 0x40080000, 0x02080100, 0x40000100
- };
- private static int[] SP6 = {
- 0x20000010, 0x20400000, 0x00004000, 0x20404010,
- 0x20400000, 0x00000010, 0x20404010, 0x00400000,
- 0x20004000, 0x00404010, 0x00400000, 0x20000010,
- 0x00400010, 0x20004000, 0x20000000, 0x00004010,
- 0x00000000, 0x00400010, 0x20004010, 0x00004000,
- 0x00404000, 0x20004010, 0x00000010, 0x20400010,
- 0x20400010, 0x00000000, 0x00404010, 0x20404000,
- 0x00004010, 0x00404000, 0x20404000, 0x20000000,
- 0x20004000, 0x00000010, 0x20400010, 0x00404000,
- 0x20404010, 0x00400000, 0x00004010, 0x20000010,
- 0x00400000, 0x20004000, 0x20000000, 0x00004010,
- 0x20000010, 0x20404010, 0x00404000, 0x20400000,
- 0x00404010, 0x20404000, 0x00000000, 0x20400010,
- 0x00000010, 0x00004000, 0x20400000, 0x00404010,
- 0x00004000, 0x00400010, 0x20004010, 0x00000000,
- 0x20404000, 0x20000000, 0x00400010, 0x20004010
- };
- private static int[] SP7 = {
- 0x00200000, 0x04200002, 0x04000802, 0x00000000,
- 0x00000800, 0x04000802, 0x00200802, 0x04200800,
- 0x04200802, 0x00200000, 0x00000000, 0x04000002,
- 0x00000002, 0x04000000, 0x04200002, 0x00000802,
- 0x04000800, 0x00200802, 0x00200002, 0x04000800,
- 0x04000002, 0x04200000, 0x04200800, 0x00200002,
- 0x04200000, 0x00000800, 0x00000802, 0x04200802,
- 0x00200800, 0x00000002, 0x04000000, 0x00200800,
- 0x04000000, 0x00200800, 0x00200000, 0x04000802,
- 0x04000802, 0x04200002, 0x04200002, 0x00000002,
- 0x00200002, 0x04000000, 0x04000800, 0x00200000,
- 0x04200800, 0x00000802, 0x00200802, 0x04200800,
- 0x00000802, 0x04000002, 0x04200802, 0x04200000,
- 0x00200800, 0x00000000, 0x00000002, 0x04200802,
- 0x00000000, 0x00200802, 0x04200000, 0x00000800,
- 0x04000002, 0x04000800, 0x00000800, 0x00200002
- };
- private static int[] SP8 = {
- 0x10001040, 0x00001000, 0x00040000, 0x10041040,
- 0x10000000, 0x10001040, 0x00000040, 0x10000000,
- 0x00040040, 0x10040000, 0x10041040, 0x00041000,
- 0x10041000, 0x00041040, 0x00001000, 0x00000040,
- 0x10040000, 0x10000040, 0x10001000, 0x00001040,
- 0x00041000, 0x00040040, 0x10040040, 0x10041000,
- 0x00001040, 0x00000000, 0x00000000, 0x10040040,
- 0x10000040, 0x10001000, 0x00041040, 0x00040000,
- 0x00041040, 0x00040000, 0x10041000, 0x00001000,
- 0x00000040, 0x10040040, 0x00001000, 0x00041040,
- 0x10001000, 0x00000040, 0x10000040, 0x10040000,
- 0x10040040, 0x10000000, 0x00040000, 0x10001040,
- 0x00000000, 0x10041040, 0x00040040, 0x10000040,
- 0x10040000, 0x10001000, 0x10001040, 0x00000000,
- 0x10041040, 0x00041000, 0x00041000, 0x00001040,
- 0x00001040, 0x00040040, 0x10000000, 0x10041000
- };
-
- // Routines taken from other parts of the Acme utilities.
-
- /// Squash bytes down to ints.
- public static void squashBytesToInts( byte[] inBytes, int inOff, int[] outInts, int outOff, int intLen )
- {
- for ( int i = 0; i < intLen; ++i )
- outInts[outOff + i] =
- ( ( inBytes[inOff + i * 4 ] & 0xff ) << 24 ) |
- ( ( inBytes[inOff + i * 4 + 1] & 0xff ) << 16 ) |
- ( ( inBytes[inOff + i * 4 + 2] & 0xff ) << 8 ) |
- ( inBytes[inOff + i * 4 + 3] & 0xff );
- }
-
- /// Spread ints into bytes.
- public static void spreadIntsToBytes( int[] inInts, int inOff, byte[] outBytes, int outOff, int intLen )
- {
- for ( int i = 0; i < intLen; ++i )
- {
- outBytes[outOff + i * 4 ] = (byte) ( inInts[inOff + i] >>> 24 );
- outBytes[outOff + i * 4 + 1] = (byte) ( inInts[inOff + i] >>> 16 );
- outBytes[outOff + i * 4 + 2] = (byte) ( inInts[inOff + i] >>> 8 );
- outBytes[outOff + i * 4 + 3] = (byte) inInts[inOff + i];
- }
- }
- }
+++ /dev/null
-//
-// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// HTTPConnectSocket.java together with HTTPConnectSocketFactory.java
-// implement an alternate way to connect to VNC servers via one or two
-// HTTP proxies supporting the HTTP CONNECT method.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.net.*;
-import java.io.*;
-
-class HTTPConnectSocket extends Socket {
-
- public HTTPConnectSocket(String host, int port,
- String proxyHost, int proxyPort)
- throws IOException {
-
- // Connect to the specified HTTP proxy
- super(proxyHost, proxyPort);
-
- // Send the CONNECT request
- getOutputStream().write(("CONNECT " + host + ":" + port +
- " HTTP/1.0\r\n\r\n").getBytes());
-
- // Read the first line of the response
- DataInputStream is = new DataInputStream(getInputStream());
- String str = is.readLine();
-
- // Check the HTTP error code -- it should be "200" on success
- if (!str.startsWith("HTTP/1.0 200 ")) {
- if (str.startsWith("HTTP/1.0 "))
- str = str.substring(9);
- throw new IOException("Proxy reports \"" + str + "\"");
- }
-
- // Success -- skip remaining HTTP headers
- do {
- str = is.readLine();
- } while (str.length() != 0);
- }
-}
-
+++ /dev/null
-//
-// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// HTTPConnectSocketFactory.java together with HTTPConnectSocket.java
-// implement an alternate way to connect to VNC servers via one or two
-// HTTP proxies supporting the HTTP CONNECT method.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.applet.*;
-import java.net.*;
-import java.io.*;
-
-class HTTPConnectSocketFactory implements SocketFactory {
-
- public Socket createSocket(String host, int port, Applet applet)
- throws IOException {
-
- return createSocket(host, port,
- applet.getParameter("PROXYHOST1"),
- applet.getParameter("PROXYPORT1"));
- }
-
- public Socket createSocket(String host, int port, String[] args)
- throws IOException {
-
- return createSocket(host, port,
- readArg(args, "PROXYHOST1"),
- readArg(args, "PROXYPORT1"));
- }
-
- public Socket createSocket(String host, int port,
- String proxyHost, String proxyPortStr)
- throws IOException {
-
- int proxyPort = 0;
- if (proxyPortStr != null) {
- try {
- proxyPort = Integer.parseInt(proxyPortStr);
- } catch (NumberFormatException e) { }
- }
-
- if (proxyHost == null || proxyPort == 0) {
- System.out.println("Incomplete parameter list for HTTPConnectSocket");
- return new Socket(host, port);
- }
-
- System.out.println("HTTP CONNECT via proxy " + proxyHost +
- " port " + proxyPort);
- HTTPConnectSocket s =
- new HTTPConnectSocket(host, port, proxyHost, proxyPort);
-
- return (Socket)s;
- }
-
- private String readArg(String[] args, String name) {
-
- for (int i = 0; i < args.length; i += 2) {
- if (args[i].equalsIgnoreCase(name)) {
- try {
- return args[i+1];
- } catch (Exception e) {
- return null;
- }
- }
- }
- return null;
- }
-}
-
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-//
-// rdr::InStream marshalls data from a buffer stored in RDR (RFB Data
-// Representation).
-//
-
-package com.tightvnc.vncviewer;
-
-abstract public class InStream {
-
- // check() ensures there is buffer data for at least one item of size
- // itemSize bytes. Returns the number of items in the buffer (up to a
- // maximum of nItems).
-
- public final int check(int itemSize, int nItems) throws Exception {
- if (ptr + itemSize * nItems > end) {
- if (ptr + itemSize > end)
- return overrun(itemSize, nItems);
-
- nItems = (end - ptr) / itemSize;
- }
- return nItems;
- }
-
- public final void check(int itemSize) throws Exception {
- if (ptr + itemSize > end)
- overrun(itemSize, 1);
- }
-
- // readU/SN() methods read unsigned and signed N-bit integers.
-
- public final int readS8() throws Exception {
- check(1); return b[ptr++];
- }
-
- public final int readS16() throws Exception {
- check(2); int b0 = b[ptr++];
- int b1 = b[ptr++] & 0xff; return b0 << 8 | b1;
- }
-
- public final int readS32() throws Exception {
- check(4); int b0 = b[ptr++];
- int b1 = b[ptr++] & 0xff;
- int b2 = b[ptr++] & 0xff;
- int b3 = b[ptr++] & 0xff;
- return b0 << 24 | b1 << 16 | b2 << 8 | b3;
- }
-
- public final int readU8() throws Exception {
- return readS8() & 0xff;
- }
-
- public final int readU16() throws Exception {
- return readS16() & 0xffff;
- }
-
- public final int readU32() throws Exception {
- return readS32() & 0xffffffff;
- }
-
- // readString() reads a string - a U32 length followed by the data.
-
- public final String readString() throws Exception {
- int len = readU32();
- if (len > maxStringLength)
- throw new Exception("InStream max string length exceeded");
-
- char[] str = new char[len];
- int i = 0;
- while (i < len) {
- int j = i + check(1, len - i);
- while (i < j) {
- str[i++] = (char)b[ptr++];
- }
- }
-
- return new String(str);
- }
-
- // maxStringLength protects against allocating a huge buffer. Set it
- // higher if you need longer strings.
-
- public static int maxStringLength = 65535;
-
- public final void skip(int bytes) throws Exception {
- while (bytes > 0) {
- int n = check(1, bytes);
- ptr += n;
- bytes -= n;
- }
- }
-
- // readBytes() reads an exact number of bytes into an array at an offset.
-
- public void readBytes(byte[] data, int offset, int length) throws Exception {
- int offsetEnd = offset + length;
- while (offset < offsetEnd) {
- int n = check(1, offsetEnd - offset);
- System.arraycopy(b, ptr, data, offset, n);
- ptr += n;
- offset += n;
- }
- }
-
- // readOpaqueN() reads a quantity "without byte-swapping". Because java has
- // no byte-ordering, we just use big-endian.
-
- public final int readOpaque8() throws Exception {
- return readU8();
- }
-
- public final int readOpaque16() throws Exception {
- return readU16();
- }
-
- public final int readOpaque32() throws Exception {
- return readU32();
- }
-
- public final int readOpaque24A() throws Exception {
- check(3); int b0 = b[ptr++];
- int b1 = b[ptr++]; int b2 = b[ptr++];
- return b0 << 24 | b1 << 16 | b2 << 8;
- }
-
- public final int readOpaque24B() throws Exception {
- check(3); int b0 = b[ptr++];
- int b1 = b[ptr++]; int b2 = b[ptr++];
- return b0 << 16 | b1 << 8 | b2;
- }
-
- // pos() returns the position in the stream.
-
- abstract public int pos();
-
- // bytesAvailable() returns true if at least one byte can be read from the
- // stream without blocking. i.e. if false is returned then readU8() would
- // block.
-
- public boolean bytesAvailable() { return end != ptr; }
-
- // getbuf(), getptr(), getend() and setptr() are "dirty" methods which allow
- // you to manipulate the buffer directly. This is useful for a stream which
- // is a wrapper around an underlying stream.
-
- public final byte[] getbuf() { return b; }
- public final int getptr() { return ptr; }
- public final int getend() { return end; }
- public final void setptr(int p) { ptr = p; }
-
- // overrun() is implemented by a derived class to cope with buffer overrun.
- // It ensures there are at least itemSize bytes of buffer data. Returns
- // the number of items in the buffer (up to a maximum of nItems). itemSize
- // is supposed to be "small" (a few bytes).
-
- abstract protected int overrun(int itemSize, int nItems) throws Exception;
-
- protected InStream() {}
- protected byte[] b;
- protected int ptr;
- protected int end;
-}
+++ /dev/null
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-\f
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-\f
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-\f
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-\f
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-\f
- Appendix: How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
+++ /dev/null
-Manifest-Version: 1.0
-Main-Class: VncViewer
+++ /dev/null
-#
-# Making the VNC applet.
-#
-
-CP = cp
-JC = javac
-JCFLAGS = -target 1.1
-JAR = jar
-ARCHIVE = VncViewer.jar
-MANIFEST = MANIFEST.MF
-PAGES = index.vnc
-INSTALL_DIR = /usr/local/vnc/classes
-
-CLASSES = VncViewer.class RfbProto.class AuthPanel.class VncCanvas.class \
- VncCanvas2.class \
- OptionsFrame.class ClipboardFrame.class ButtonPanel.class \
- DesCipher.class CapabilityInfo.class CapsContainer.class \
- RecordingFrame.class SessionRecorder.class \
- SocketFactory.class HTTPConnectSocketFactory.class \
- HTTPConnectSocket.class ReloginPanel.class \
- InStream.class MemInStream.class ZlibInStream.class
-
-SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \
- VncCanvas2.java \
- OptionsFrame.java ClipboardFrame.java ButtonPanel.java \
- DesCipher.java CapabilityInfo.java CapsContainer.java \
- RecordingFrame.java SessionRecorder.java \
- SocketFactory.java HTTPConnectSocketFactory.java \
- HTTPConnectSocket.java ReloginPanel.java \
- InStream.java MemInStream.java ZlibInStream.java
-
-all: $(CLASSES) $(ARCHIVE)
-
-$(CLASSES): $(SOURCES)
- $(JC) $(JCFLAGS) -O $(SOURCES)
-
-$(ARCHIVE): $(CLASSES) $(MANIFEST)
- $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES)
-
-install: $(CLASSES) $(ARCHIVE)
- $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR)
-
-export:: $(CLASSES) $(ARCHIVE) $(PAGES)
- @$(ExportJavaClasses)
-
-clean::
- $(RM) *.class *.jar
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-package com.tightvnc.vncviewer;
-
-public class MemInStream extends InStream {
-
- public MemInStream(byte[] data, int offset, int len) {
- b = data;
- ptr = offset;
- end = offset + len;
- }
-
- public int pos() { return ptr; }
-
- protected int overrun(int itemSize, int nItems) throws Exception {
- throw new Exception("MemInStream overrun: end of stream");
- }
-}
+++ /dev/null
-//
-// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved.
-// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// Options frame.
-//
-// This deals with all the options the user can play with.
-// It sets the encodings array and some booleans.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-
-class OptionsFrame extends Frame
- implements WindowListener, ActionListener, ItemListener {
-
- static String[] names = {
- "Encoding",
- "Compression level",
- "JPEG image quality",
- "Cursor shape updates",
- "Use CopyRect",
- "Continuous updates",
- "Restricted colors",
- "Mouse buttons 2 and 3",
- "View only",
- "Scaling factor",
- "Scale remote cursor",
- "Share desktop"
- };
-
- static String[][] values = {
- { "Auto", "Raw", "RRE", "CoRRE", "Hextile", "Zlib", "Tight", "ZRLE" },
- { "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9" },
- { "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" },
- { "Enable", "Ignore", "Disable" },
- { "Yes", "No" },
- { "Yes", "No" },
- { "Yes", "No" },
- { "Normal", "Reversed" },
- { "Yes", "No" },
- { "Auto", "1%", "5%", "10%", "20%", "25%", "50%", "75%", "100%"},
- { "No", "50%", "75%", "125%", "150%" },
- { "Yes", "No" }
- };
-
- final int
- encodingIndex = 0,
- compressLevelIndex = 1,
- jpegQualityIndex = 2,
- cursorUpdatesIndex = 3,
- useCopyRectIndex = 4,
- contUpdatesIndex = 5,
- eightBitColorsIndex = 6,
- mouseButtonIndex = 7,
- viewOnlyIndex = 8,
- scalingFactorIndex = 9,
- scaleCursorIndex = 10,
- shareDesktopIndex = 11;
-
- Label[] labels = new Label[names.length];
- Choice[] choices = new Choice[names.length];
- Button closeButton;
- VncViewer viewer;
-
-
- //
- // The actual data which other classes look at:
- //
-
- int preferredEncoding;
- int compressLevel;
- int jpegQuality;
- boolean useCopyRect;
- boolean continuousUpdates;
- boolean requestCursorUpdates;
- boolean ignoreCursorUpdates;
-
- boolean eightBitColors;
-
- boolean reverseMouseButtons2And3;
- boolean shareDesktop;
- boolean viewOnly;
- int scaleCursor;
-
- boolean autoScale;
- int scalingFactor;
-
- //
- // Constructor. Set up the labels and choices from the names and values
- // arrays.
- //
-
- OptionsFrame(VncViewer v) {
- super("TigerVNC Options");
-
- viewer = v;
-
- GridBagLayout gridbag = new GridBagLayout();
- setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.fill = GridBagConstraints.BOTH;
-
- for (int i = 0; i < names.length; i++) {
- labels[i] = new Label(names[i]);
- gbc.gridwidth = 1;
- gridbag.setConstraints(labels[i],gbc);
- add(labels[i]);
-
- choices[i] = new Choice();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gridbag.setConstraints(choices[i],gbc);
- add(choices[i]);
- choices[i].addItemListener(this);
-
- for (int j = 0; j < values[i].length; j++) {
- choices[i].addItem(values[i][j]);
- }
- }
-
- closeButton = new Button("Close");
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gridbag.setConstraints(closeButton, gbc);
- add(closeButton);
- closeButton.addActionListener(this);
-
- pack();
-
- addWindowListener(this);
-
- // Set up defaults
-
- choices[encodingIndex].select("Auto");
- choices[compressLevelIndex].select("Default");
- choices[jpegQualityIndex].select("6");
- choices[cursorUpdatesIndex].select("Enable");
- choices[useCopyRectIndex].select("Yes");
- choices[contUpdatesIndex].select("No");
- choices[eightBitColorsIndex].select("No");
- choices[mouseButtonIndex].select("Normal");
- choices[viewOnlyIndex].select("No");
- choices[scaleCursorIndex].select("No");
- choices[shareDesktopIndex].select("Yes");
-
- // But let them be overridden by parameters
-
- for (int i = 0; i < names.length; i++) {
- String s = viewer.readParameter(names[i], false);
- if (s != null) {
- for (int j = 0; j < values[i].length; j++) {
- if (s.equalsIgnoreCase(values[i][j])) {
- choices[i].select(j);
- }
- }
- }
- }
-
- // Get scaling factor from parameters and set it
- // to gui and class member scalingFactor
-
- String s = viewer.readParameter("Scaling Factor", false);
- if (s == null) s = "100%";
- setScalingFactor(s);
- if (autoScale) {
- choices[scalingFactorIndex].select("Auto");
- } else {
- choices[scalingFactorIndex].select(s);
- }
-
- // Make the booleans and encodings array correspond to the state of the GUI
-
- setEncodings();
- setColorFormat();
- setContinuousUpdates();
- setOtherOptions();
- }
-
- //
- // Set scaling factor class member value
- //
-
- void setScalingFactor(int sf) {
- setScalingFactor(((Integer)sf).toString());
- }
-
- void setScalingFactor(String s) {
- autoScale = false;
- scalingFactor = 100;
- if (s != null) {
- if (s.equalsIgnoreCase("Auto")) {
- autoScale = true;
- } else {
- // Remove the '%' char at the end of string if present.
- if (s.charAt(s.length() - 1) == '%') {
- s = s.substring(0, s.length() - 1);
- }
- // Convert to an integer.
- try {
- scalingFactor = Integer.parseInt(s);
- }
- catch (NumberFormatException e) {
- scalingFactor = 100;
- }
- // Make sure scalingFactor is in the range of [1..1000].
- if (scalingFactor < 1) {
- scalingFactor = 1;
- } else if (scalingFactor > 1000) {
- scalingFactor = 1000;
- }
- }
- }
- }
-
-
- //
- // Disable the shareDesktop option
- //
-
- void disableShareDesktop() {
- labels[shareDesktopIndex].setEnabled(false);
- choices[shareDesktopIndex].setEnabled(false);
- }
-
-
- //
- // Disable the "Continuous updates" option. This method is called
- // when we figure out that the server does not support corresponding
- // protocol extensions.
- //
-
- void disableContUpdates() {
- labels[contUpdatesIndex].setEnabled(false);
- choices[contUpdatesIndex].setEnabled(false);
- choices[contUpdatesIndex].select("No");
- continuousUpdates = false;
- }
-
-
- //
- // setEncodings looks at the encoding, compression level, JPEG
- // quality level, cursor shape updates and copyRect choices and sets
- // corresponding variables properly. Then it calls the VncViewer's
- // setEncodings method to send a SetEncodings message to the RFB
- // server.
- //
-
- void setEncodings() {
- useCopyRect = choices[useCopyRectIndex].getSelectedItem().equals("Yes");
-
- preferredEncoding = RfbProto.EncodingRaw;
- boolean enableCompressLevel = false;
- boolean enableQualityLevel = false;
-
- if (choices[encodingIndex].getSelectedItem().equals("RRE")) {
- preferredEncoding = RfbProto.EncodingRRE;
- } else if (choices[encodingIndex].getSelectedItem().equals("CoRRE")) {
- preferredEncoding = RfbProto.EncodingCoRRE;
- } else if (choices[encodingIndex].getSelectedItem().equals("Hextile")) {
- preferredEncoding = RfbProto.EncodingHextile;
- } else if (choices[encodingIndex].getSelectedItem().equals("ZRLE")) {
- preferredEncoding = RfbProto.EncodingZRLE;
- } else if (choices[encodingIndex].getSelectedItem().equals("Zlib")) {
- preferredEncoding = RfbProto.EncodingZlib;
- enableCompressLevel = true;
- } else if (choices[encodingIndex].getSelectedItem().equals("Tight")) {
- preferredEncoding = RfbProto.EncodingTight;
- enableCompressLevel = true;
- enableQualityLevel = !eightBitColors;
- } else if (choices[encodingIndex].getSelectedItem().equals("Auto")) {
- preferredEncoding = -1;
- enableQualityLevel = !eightBitColors;
- }
-
- // Handle compression level setting.
-
- try {
- compressLevel =
- Integer.parseInt(choices[compressLevelIndex].getSelectedItem());
- }
- catch (NumberFormatException e) {
- compressLevel = -1;
- }
- if (compressLevel < 1 || compressLevel > 9) {
- compressLevel = -1;
- }
- labels[compressLevelIndex].setEnabled(enableCompressLevel);
- choices[compressLevelIndex].setEnabled(enableCompressLevel);
-
- // Handle JPEG quality setting.
-
- try {
- jpegQuality =
- Integer.parseInt(choices[jpegQualityIndex].getSelectedItem());
- }
- catch (NumberFormatException e) {
- jpegQuality = -1;
- }
- if (jpegQuality < 0 || jpegQuality > 9) {
- jpegQuality = -1;
- }
- labels[jpegQualityIndex].setEnabled(enableQualityLevel);
- choices[jpegQualityIndex].setEnabled(enableQualityLevel);
-
- // Request cursor shape updates if necessary.
-
- requestCursorUpdates =
- !choices[cursorUpdatesIndex].getSelectedItem().equals("Disable");
-
- if (requestCursorUpdates) {
- ignoreCursorUpdates =
- choices[cursorUpdatesIndex].getSelectedItem().equals("Ignore");
- }
-
- viewer.setEncodings();
- }
-
- //
- // setColorFormat sets eightBitColors variable depending on the GUI
- // setting, causing switches between 8-bit and 24-bit colors mode if
- // necessary.
- //
-
- void setColorFormat() {
-
- eightBitColors =
- choices[eightBitColorsIndex].getSelectedItem().equals("Yes");
-
- boolean enableJPEG = !eightBitColors &&
- (choices[encodingIndex].getSelectedItem().equals("Tight") ||
- choices[encodingIndex].getSelectedItem().equals("Auto"));
-
- labels[jpegQualityIndex].setEnabled(enableJPEG);
- choices[jpegQualityIndex].setEnabled(enableJPEG);
- }
-
- //
- // setContinuousUpdates sets continuousUpdates variable depending on
- // the GUI setting. VncViewer monitors the state of this variable and
- // send corresponding protocol messages to the server when necessary.
- //
-
- void setContinuousUpdates() {
-
- continuousUpdates =
- choices[contUpdatesIndex].getSelectedItem().equals("Yes");
- }
-
- //
- // setOtherOptions looks at the "other" choices (ones that do not
- // cause sending any protocol messages) and sets the boolean flags
- // appropriately.
- //
-
- void setOtherOptions() {
-
- reverseMouseButtons2And3
- = choices[mouseButtonIndex].getSelectedItem().equals("Reversed");
-
- viewOnly
- = choices[viewOnlyIndex].getSelectedItem().equals("Yes");
- if (viewer.vc != null)
- viewer.vc.enableInput(!viewOnly);
-
- shareDesktop
- = choices[shareDesktopIndex].getSelectedItem().equals("Yes");
-
- String scaleString = choices[scaleCursorIndex].getSelectedItem();
- if (scaleString.endsWith("%"))
- scaleString = scaleString.substring(0, scaleString.length() - 1);
- try {
- scaleCursor = Integer.parseInt(scaleString);
- }
- catch (NumberFormatException e) {
- scaleCursor = 0;
- }
- if (scaleCursor < 10 || scaleCursor > 500) {
- scaleCursor = 0;
- }
- if (requestCursorUpdates && !ignoreCursorUpdates && !viewOnly) {
- labels[scaleCursorIndex].setEnabled(true);
- choices[scaleCursorIndex].setEnabled(true);
- } else {
- labels[scaleCursorIndex].setEnabled(false);
- choices[scaleCursorIndex].setEnabled(false);
- }
- if (viewer.vc != null)
- viewer.vc.createSoftCursor(); // update cursor scaling
- }
-
-
- //
- // Respond to actions on Choice controls
- //
-
- public void itemStateChanged(ItemEvent evt) {
- Object source = evt.getSource();
-
- if (source == choices[encodingIndex] ||
- source == choices[compressLevelIndex] ||
- source == choices[jpegQualityIndex] ||
- source == choices[cursorUpdatesIndex] ||
- source == choices[useCopyRectIndex]) {
-
- setEncodings();
-
- if (source == choices[cursorUpdatesIndex]) {
- setOtherOptions(); // update scaleCursor state
- }
-
- } else if (source == choices[eightBitColorsIndex]) {
-
- setColorFormat();
-
- } else if (source == choices[contUpdatesIndex]) {
-
- setContinuousUpdates();
-
- } else if (source == choices[mouseButtonIndex] ||
- source == choices[shareDesktopIndex] ||
- source == choices[viewOnlyIndex] ||
- source == choices[scaleCursorIndex]) {
-
- setOtherOptions();
-
- } else if (source == choices[scalingFactorIndex]){
- // Tell VNC canvas that scaling factor has changed
- setScalingFactor(choices[scalingFactorIndex].getSelectedItem());
- if (viewer.vc != null)
- viewer.vc.setScalingFactor(scalingFactor);
- }
- }
-
- //
- // Respond to button press
- //
-
- public void actionPerformed(ActionEvent evt) {
- if (evt.getSource() == closeButton)
- setVisible(false);
- }
-
- //
- // Respond to window events
- //
-
- public void windowClosing(WindowEvent evt) {
- setVisible(false);
- }
-
- public void windowActivated(WindowEvent evt) {}
- public void windowDeactivated(WindowEvent evt) {}
- public void windowOpened(WindowEvent evt) {}
- public void windowClosed(WindowEvent evt) {}
- public void windowIconified(WindowEvent evt) {}
- public void windowDeiconified(WindowEvent evt) {}
-}
+++ /dev/null
-
- TigerVNC Java Viewer version 1.3.9
-
-======================================================================
-
-This distribution is based on the standard VNC source and includes new
-TightVNC-specific features and fixes, such as additional low-bandwidth
-optimizations, major GUI improvements, and more.
-
- Copyright (C) 1999 AT&T Laboratories Cambridge.
- Copyright (C) 2000 Tridia Corp.
- Copyright (C) 2002-2003 RealVNC Ltd.
- Copyright (C) 2001-2004 HorizonLive.com, Inc.
- Copyright (C) 2000-2007 Constantin Kaplinsky
- Copyright (C) 2000-2007 TightVNC Group
- All rights reserved.
-
-This software is distributed under the GNU General Public Licence as
-published by the Free Software Foundation. See the file LICENCE.TXT for the
-conditions under which this software is made available. TigerVNC also
-contains code from other sources. See the Acknowledgements section below, and
-the individual files for details of the conditions under which they are made
-available.
-
-
-Compiling from the sources
-==========================
-
-To compile all the .java files to .class files, simply do:
-
- % make all
-
-This will also generate a JAR (Java archive) file containing all the classes.
-Most JVM (Java Virtual Machine) implementations are able to use either a set
-of .class files, or the JAR archive.
-
-
-Installation
-============
-
-There are three basic ways to use TigerVNC Java viewer:
-
- 1. Running applet as part of TigerVNC server installation.
-
- Both the Unix and Windows versions of TigerVNC servers include small
- built-in HTTP server which can serve Java viewer to Web clients. This
- enables easy Web access to the shared desktop without need to install
- any software on the client computer. Unix and Windows versions of
- TigerVNC servers are different in the way they store the .class and .jar
- files: the Unix server (Xvnc) is able to serve any set of files present
- in a particular directory, while the Windows server (WinVNC) has all the
- .class and .jar files inside the WinVNC executable file. Therefore, for
- Xvnc, it's enough to copy the files into a correct directory, but for
- WinVNC, the server binaries should be rebuild if the built-in Java
- viewer should be updated.
-
- To install the Java viewer under Xvnc, copy all the .class files, the
- .jar file and the .vnc files to an installation directory (e.g.
- /usr/local/vnc/classes):
-
- cp *.class *.jar *.vnc /usr/local/vnc/classes
-
- Also, make sure that the vncserver script is configured to point to the
- installation directory (see the Xvnc manual page for the description of
- the -httpd command-line option).
-
- 2. Running applet hosted on a standalone Web server.
-
- Another possibility to use the Java viewer is to install it under a
- fully-functional HTTP server such as Apache or IIS. Obviously, this
- method requires running an HTTP server, and due to the Java security
- restrictions, it's also required that the server should be installed on
- the same machine which is running the TigerVNC server. In this case,
- installation is simply copying the .class and .jar files into a
- directory that is under control of the HTTP server. Also, an HTML page
- should be created which will act as a the base document for the viewer
- applet (see an example named index.html in this distribution).
-
- NOTE: Provided index.html page is an example only. Before using that
- file, edit it with a text editor. See more information inside
- index.html.
-
- 3. Running the viewer as a standalone application.
-
- Finally, the Java viewer can be executed locally on the client machine,
- but this method requires installation of either JRE (Java Runtime
- Environment) or JDK (Java Development Kit). If all the .class files are
- in the current directory, the Java viewer can be executed like this,
- from the command line:
-
- java VncViewer HOST vnchost PORT 5900
-
- The HOST parameter is required, PORT defaults to 5900 if omitted, and
- there is a number of other optional parameters, see the Parameters
- section below.
-
-
-Parameters
-==========
-
-TigerVNC Java viewer supports a number of parameters allowing you to
-customize its behavior. Most parameters directly correspond to the settings
-found in the Options window. However, there are parameters that do not
-correspond to those settings. For such parameters, you can see a note "no GUI
-equivalent", in the documentation below.
-
-Parameters can be specified in one of the two ways, depending on how the Java
-viewer is used:
-
- 1. When the Java viewer is run as an applet (embedded within an HTML
- document), parameters should be specified in the <PARAM> HTML tags,
- within the appropriate <APPLET> section. Here is an example:
-
- <APPLET CODE=VncViewer.class ARCHIVE=VncViewer.jar WIDTH=400 HEIGHT=300>
- <PARAM NAME="PORT" VALUE=5901>
- <PARAM NAME="Scaling factor" VALUE=50>
- </APPLET>
-
- 2. When run as a standalone application, the Java viewer reads parameters
- from the command line. Command-line arguments should be specified in
- pairs -- first goes parameter name, then parameter value. Here is a
- command line example:
-
- java VncViewer HOST vnchost PORT 5901 "Scaling factor" 50
-
-Both parameter names and their values are case-insensitive. The only
-exception is the "PASSWORD" parameter, as VNC passwords are case-sensitive.
-
-Here is the complete list of parameters supported in TigerVNC Java viewer:
-
---> "HOST" (no GUI equivalent)
-
- Value: host name or IP address of the VNC server.
- Default: in applet mode, the host from which the applet was loaded.
-
- This parameter tells the viewer which server to connect to. It's not
- needed in the applet mode, because default Java security policy allow
- connections from applets to the only one host anyway, and that is the
- host from which the applet was loaded. However, this parameter is
- required if the viewer is used as a standalone application.
-
---> "PORT" (no GUI equivalent)
-
- Value: TCP port number on the VNC server.
- Default: 5900.
-
- This parameter specifies TCP port number for outgoing VNC connection.
- Note that this port is not the one used for HTTP connection from the
- browser, it is the port used for VNC/RFB connection. Usually, VNC servers
- use ports 58xx for HTTP connections, and ports 59xx for RFB connections.
- Thus, most likely, this parameter should be set to something like 5900,
- 5901 etc.
-
---> "PASSWORD"
-
- Value: session password in plain text.
- Default: none, ask user.
-
- DO NOT EVER USE THIS PARAMETER, unless you really know what you are
- doing. It's extremely dangerous from the security point of view. When
- this parameter is set, the viewer won't ever ask for a password.
-
---> "ENCPASSWORD"
-
- Value: encrypted session password in hex-ascii.
- Default: none, ask user.
-
- The same as the "PASSWORD" parameter but DES-encrypted using a fixed key.
- Its value should be represented in hex-ascii e.g. "494015f9a35e8b22".
- This parameter has higher priority over the "PASSWORD" parameter. DO NOT
- EVER USE THIS PARAMETER, unless you really know what you are doing. It's
- extremely dangerous from the security point of view, and encryption does
- not actually help here since the decryption key is always known.
-
---> "Encoding"
-
- Values: "Auto", "Raw", "RRE", "CoRRE", "Hextile", "ZRLE", "Zlib", "Tight".
- Default: "Auto".
-
- The preferred encoding. If the value is "Auto", then the viewer will
- continuously estimate average network throughput and request encodings
- that are appropriate for current connection speed. "Hextile" is an
- encoding that was designed for fast networks, while "Tight" is better
- suited for low-bandwidth connections. From the other side, "Tight"
- decoder in the TigerVNC Java viewer seems to be more efficient than
- "Hextile" decoder so it may be ok for fast networks too. "ZRLE" encoding
- is similar to "Tight", but it does not support JPEG compression and
- compression levels. Unlike "Tight" encoding, "ZRLE" is supported in
- recent versions of RealVNC products. Other encodings are not efficient
- and provided for compatibility reasons.
-
---> "Compression level"
-
- Values: "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9".
- Default: "Default". ;-)
-
- Use specified compression level for "Tight" and "Zlib" encodings. Level 1
- uses minimum of CPU time on the server but achieves weak compression
- ratios. Level 9 offers best compression but may be slow in terms of CPU
- time consumption on the server side. Use high levels with very slow
- network connections, and low levels when working over higher-speed
- networks. The "Default" value means that the server's default compression
- level should be used.
-
---> "JPEG image quality"
-
- Values: "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9".
- Default: "6".
-
- Use the specified image quality level in "Tight" encoding. Quality level
- 0 denotes bad image quality but very impressive compression ratios, while
- level 9 offers very good image quality at lower compression ratios. If
- the value is "JPEG off", the server will not use lossy JPEG compression
- in "Tight" encoding.
-
---> "Cursor shape updates"
-
- Values: "Enable", "Ignore", "Disable".
- Default: "Enable".
-
- Cursor shape updates is a protocol extension used to handle remote cursor
- movements locally on the client side, saving bandwidth and eliminating
- delays in mouse pointer movement. Note that current implementation of
- cursor shape updates does not allow a client to track mouse cursor
- position at the server side. This means that clients would not see mouse
- cursor movements if mouse was moved either locally on the server, or by
- another remote VNC client. Set this parameter to "Disable" if you always
- want to see real cursor position on the remote side. Setting this option
- to "Ignore" is similar to "Enable" but the remote cursor will not be
- visible at all. This can be a reasonable setting if you don't care about
- cursor shape and don't want to see two mouse cursors, one above another.
-
---> "Use CopyRect"
-
- Values: "Yes", "No".
- Default: "Yes".
-
- The "CopyRect" encoding saves bandwidth and drawing time when parts of
- the remote screen are moving around. Most likely, you don't want to
- change this setting.
-
---> "Restricted colors"
-
- Values: "Yes", "No".
- Default: "No".
-
- If set to "No", then 24-bit color format is used to represent pixel data.
- If set to "Yes", then only 8 bits are used to represent each pixel. 8-bit
- color format can save bandwidth, but colors may look very inaccurate.
-
---> "Mouse buttons 2 and 3"
-
- Values: "Normal", "Reversed".
- Default: "Normal".
-
- If set to "Reversed", then right mouse button (button 2) will act as it
- was middle mouse button (button 3), and vice versa.
-
---> "View only"
-
- Values: "Yes", "No".
- Default: "No".
-
- If set to "Yes", then all keyboard and mouse events in the desktop window
- will be silently ignored and will not be passed to the remote side.
-
---> "Scale remote cursor"
-
- Values: "No", "50%", "75%", "125%", "150%".
- Default: "No".
-
- If a percentage value is specified, the remote cursor is reduced
- or enlarged accordingly. Scaling takes place only when "View only"
- is set to "No", and "Cursor shape updates" is set to "Enable".
-
---> "Share desktop"
-
- Values: "Yes", "No".
- Default: "Yes".
-
- Share the connection with other clients on the same VNC server. The exact
- behaviour in each case depends on the server configuration.
-
---> "Open new window" (no GUI equivalent, applicable only in the applet mode)
-
- Values: "Yes", "No".
- Default: "No".
-
- Operate in a separate window. This makes possible resizing the desktop,
- and adds scroll bars when necessary. If the server supports variable
- desktop size, the window will resize automatically when remote desktop
- size changes.
-
---> "Scaling factor" (no GUI equivalent)
-
- Value: an integer in the range of [1..1000], or the string "auto".
- Default: "100".
-
- Scale local representation of the remote desktop. The value is
- interpreted as scaling factor in percents. The default value of 100%
- corresponds to the original framebuffer size. Values below 100 reduce
- image size, values above 100 enlarge the image proportionally. If the
- parameter is set to "auto", automatic scaling is performed. Auto-scaling
- tries to choose scaling factor such way that the whole remote framebuffer
- will fit on the local screen. Currently, auto-scaling is supported only
- when the remote desktop is shown in a separate frame (always true in the
- application mode, and also in the applet mode with "Open new window"
- parameter set to "yes").
-
---> "Show controls" (no GUI equivalent)
-
- Values: "Yes", "No".
- Default: "Yes".
-
- Set to "No" if you want to get rid of that button panel at the top.
-
---> "Offer relogin" (no GUI equivalent, applicable only in the applet mode)
-
- Values: "Yes", "No".
- Default: "Yes".
-
- If set to "No", the buttons "Login again" and "Close window" won't be
- shown on disconnects or after an error has occured.
-
---> "Show offline desktop" (no GUI equivalent)
-
- Values: "Yes", "No".
- Default: "No".
-
- If set to "Yes", the viewer would continue to display desktop even
- if the remote side has closed the connection. In this case, if the
- button panel is enabled, then the "Disconnect" button would be
- changed to "Hide desktop" after the connection is lost.
-
---> "Defer screen updates" (no GUI equivalent)
-
- Value: time in milliseconds.
- Default: "20".
-
- When updating the desktop contents after receiving an update from server,
- schedule repaint within the specified number of milliseconds. Small delay
- helps to coalesce several small updates into one drawing operation,
- improving CPU usage. Set this parameter to 0 to disable deferred updates.
-
---> "Defer cursor updates" (no GUI equivalent)
-
- Value: time in milliseconds.
- Default: "10".
-
- When updating the desktop after moving the mouse, schedule repaint within
- the specified number of milliseconds. This setting makes sense only when
- "Cursor shape updates" parameter is set to "Enable". Small delay helps to
- coalesce several small updates into one drawing operation, improving CPU
- usage. Set this parameter to 0 to disable deferred cursor updates.
-
---> "Defer update requests" (no GUI equivalent)
-
- Value: time in milliseconds.
- Default: "0".
-
- After processing an update received from server, wait for the specified
- number of milliseconds before requesting next screen update. Such delay
- will end immediately on every mouse or keyboard event if not in the "view
- only" mode. Small delay helps the server to coalesce several small
- updates into one framebuffer update, improving both bandwidth and CPU
- usage. Increasing the parameter value does not affect responsiveness on
- mouse and keyboard events, but causes delays in updating the screen when
- there is no mouse and keyboard activity on the client side.
-
---> "SocketFactory" (no GUI equivalent)
-
- Value: name of the class.
- Default: none.
-
- This option provides the way to define an alternate I/O implementation.
- The dynamically referenced class must implement a SocketFactory
- interface, and create a Socket, as configured by this parameter. See the
- source in SocketFactory.java.
-
---> "DEBUG_XU" (no GUI equivalent)
-
- Value: non-negative integer.
- Default: 0.
-
- Debugging option that causes update statistics reset after the specified
- number of first framebuffer updates. This option was added to measure the
- performance of a VNC server. First few updates (especially the very first
- one) may be notably slower than others, and the viewer can exclude such
- updates from statistics.
-
---> "DEBUG_CU" (no GUI equivalent)
-
- Value: non-negative integer.
- Default: 0.
-
- Debugging option that causes the viewer disconnect after the specified
- number of framebuffer updates. When used with the "DEBUG_XU" parameter,
- the number of updates specified in "DEBUG_XU" is not counted as part of
- this parameter's value. E.g. if "DEBUG_XU"=2 and "DEBUG_CU"=10, then the
- viewer will disconnect after 12 framebuffer updates: update statistics
- will be reset after first two updates, then collected for next 10
- updates, then the viewer will disconnect automatically. If the value is
- 0, the viewer will not disconnect automatically. This option was added to
- measure the performance of a VNC server.
-
-
-RECORDING VNC SESSIONS
-======================
-
-Current version of the TigerVNC Java viewer is able to record VNC (RFB)
-sessions in files for later playback. The data format in saved session files
-is compatible with the rfbproxy program written by Tim Waugh. Most important
-thing about session recording is that it's supported only if Java security
-manager allows access to local filesystem. Typically, it would not work for
-unsigned applets. To use this feature, either use TigerVNC Java viewer as a
-standalone application (Java Runtime Environment or Java Development Kit
-should be installed), or as a signed applet. The code checks if it's possible
-to support session recording, and if everything's fine, the new "Record"
-button should appear in the button panel. Pressing this button opens new
-window which controls session recording. The GUI is pretty self-explained.
-
-Other important facts about session recording:
-
---> All sessions are recorded in the 24-bit color format. If you use
- restricted colors (8-bit format), it will be temporarly switched to
- 24-bit mode during session recording.
-
---> All sessions are recorded with cursor shape updates turned off. This is
- necessary to represent remote cursor movements in recorded sessions.
-
---> Closing and re-opening the recording control window does not affect the
- recording. It's not necessary to keep that window open during recording a
- session.
-
---> Avoid using Zlib and ZRLE encodings when recording sessions. If you have
- started recording BEFORE opening a VNC session, then you are ok. But
- otherwise, all Zlib-encoded updates will be saved Raw-encoded (that is,
- without compression at all). The case with ZRLE is even worse -- ZRLE
- updates will not be saved at all, so the resulting session file may be
- corrupted. Zlib decoding depends on the pixel data received earlier, thus
- saving the data received from the server at an arbitrary moment is not
- sufficient to decompress it correctly. And there is no way to tell Zlib
- or ZRLE decoder to reset decompressor's state -- that's a limitation of
- these encoders. The viewer could re-compress raw pixel data again before
- saving Zlib-encoded sessions, but unfortunately Java API does not allow
- to flush zlib data streams making it impossible to save Zlib-encoded RFB
- pixel data without using native code.
-
---> Usually, Tight encoding is the most suitable one for session recording,
- but some of the issues described above for the Zlib encoding affect the
- Tight encoding as well. Unlike Zlib sessions, Tight-encoded sessions are
- always saved Tight-encoded, but the viewer has to re-compress parts of
- data to synchronize encoder's and decoder's zlib streams. And, due to
- Java zlib API limitations, zlib streams' states have to be reset on each
- compressed rectangle, causing compression ratios to be lower than in the
- original VNC session. If you want to achieve the best possible
- performance, turn recording on BEFORE connecting to the VNC server,
- otherwise CPU usage and compression ratios may be notably less efficient.
-
-
-HINTS
-=====
-
---> To refresh remote desktop in the view-only mode, press "r" or "R"
- on the keyboard.
-
-
-ACKNOWLEDGEMENTS
-================
-
-This distribution contains Java DES software by Dave Zimmerman
-<dzimm@widget.com> and Jef Poskanzer <jef@acme.com>. This is:
-
- Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee
- is hereby granted, provided that this copyright notice is kept intact.
-
- WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
- SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
- NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE
- LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
- MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
-
- THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
- CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
- PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
- NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
- SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
- SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
- PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET
- WORKSHOP SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF
- FITNESS FOR HIGH RISK ACTIVITIES.
-
- Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights
- reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Visit the ACME Labs Java page for up-to-date versions of this and other
- fine Java utilities: http://www.acme.com/java/
+++ /dev/null
-package com.tightvnc.vncviewer;
-
-import java.io.DataOutput;
-import java.io.IOException;
-
-public class RecordOutputStream implements DataOutput {
-
- public RecordOutputStream(RfbProto rfbproto) {
- rfb = rfbproto;
- }
-
- private boolean canWrite() {
- return ((rfb != null) && (rfb.rec != null));
- }
-
- public void write(byte[] b) throws IOException {
- if (canWrite())
- rfb.rec.write(b);
- }
-
- public void write(byte[] b, int off, int len) throws IOException {
- if (canWrite())
- rfb.rec.write(b, off, len);
- }
-
- public void write(int b) throws IOException {
- if (canWrite())
- rfb.rec.writeIntBE(b);
- }
-
- public void writeBoolean(boolean v) { }
-
- public void writeByte(int v) throws IOException {
- if (canWrite()) {
- rfb.rec.writeByte(v);
- }
- }
-
- public void writeBytes(String s) { }
- public void writeChar(int v) { }
- public void writeChars(String s) { }
- public void writeDouble(double v) { }
- public void writeFloat(float v) { }
-
- public void writeInt(int v) throws IOException {
- if (canWrite())
- rfb.rec.writeIntBE(v);
- }
-
- public void writeLong(long v) { }
-
- public void writeShort(int v) throws IOException {
- if (canWrite())
- rfb.rec.writeShortBE(v);
- }
-
- public void writeUTF(String str) { }
-
- private RfbProto rfb = null;
-}
+++ /dev/null
-//
-// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// Recording frame. It allows to control recording RFB sessions into
-// FBS (FrameBuffer Stream) files.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.io.*;
-import java.awt.*;
-import java.awt.event.*;
-
-class RecordingFrame extends Frame
- implements WindowListener, ActionListener {
-
- boolean recording;
-
- TextField fnameField;
- Button browseButton;
-
- Label statusLabel;
-
- Button recordButton, nextButton, closeButton;
- VncViewer viewer;
-
- //
- // Check if current security manager allows to create a
- // RecordingFrame object.
- //
-
- public static boolean checkSecurity() {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- try {
- security.checkPropertyAccess("user.dir");
- security.checkPropertyAccess("file.separator");
- // Work around (rare) checkPropertyAccess bug
- System.getProperty("user.dir");
- } catch (SecurityException e) {
- System.out.println("SecurityManager restricts session recording.");
- return false;
- }
- }
- return true;
- }
-
- //
- // Constructor.
- //
-
- RecordingFrame(VncViewer v) {
- super("TigerVNC Session Recording");
-
- viewer = v;
-
- // Determine initial filename for next saved session.
- // FIXME: Check SecurityManager.
-
- String fname = nextNewFilename(System.getProperty("user.dir") +
- System.getProperty("file.separator") +
- "vncsession.fbs");
-
- // Construct new panel with file name field and "Browse" button.
-
- Panel fnamePanel = new Panel();
- GridBagLayout fnameGridbag = new GridBagLayout();
- fnamePanel.setLayout(fnameGridbag);
-
- GridBagConstraints fnameConstraints = new GridBagConstraints();
- fnameConstraints.gridwidth = GridBagConstraints.RELATIVE;
- fnameConstraints.fill = GridBagConstraints.BOTH;
- fnameConstraints.weightx = 4.0;
-
- fnameField = new TextField(fname, 64);
- fnameGridbag.setConstraints(fnameField, fnameConstraints);
- fnamePanel.add(fnameField);
- fnameField.addActionListener(this);
-
- fnameConstraints.gridwidth = GridBagConstraints.REMAINDER;
- fnameConstraints.weightx = 1.0;
-
- browseButton = new Button("Browse");
- fnameGridbag.setConstraints(browseButton, fnameConstraints);
- fnamePanel.add(browseButton);
- browseButton.addActionListener(this);
-
- // Construct the frame.
-
- GridBagLayout gridbag = new GridBagLayout();
- setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.fill = GridBagConstraints.BOTH;
- gbc.weighty = 1.0;
- gbc.insets = new Insets(10, 0, 0, 0);
-
- Label helpLabel =
- new Label("File name to save next recorded session in:", Label.CENTER);
- gridbag.setConstraints(helpLabel, gbc);
- add(helpLabel);
-
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.weighty = 0.0;
- gbc.insets = new Insets(0, 0, 0, 0);
-
- gridbag.setConstraints(fnamePanel, gbc);
- add(fnamePanel);
-
- gbc.fill = GridBagConstraints.BOTH;
- gbc.weighty = 1.0;
- gbc.insets = new Insets(10, 0, 10, 0);
-
- statusLabel = new Label("", Label.CENTER);
- gridbag.setConstraints(statusLabel, gbc);
- add(statusLabel);
-
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.weightx = 1.0;
- gbc.weighty = 0.0;
- gbc.gridwidth = 1;
- gbc.insets = new Insets(0, 0, 0, 0);
-
- recordButton = new Button("Record");
- gridbag.setConstraints(recordButton, gbc);
- add(recordButton);
- recordButton.addActionListener(this);
-
- nextButton = new Button("Next file");
- gridbag.setConstraints(nextButton, gbc);
- add(nextButton);
- nextButton.addActionListener(this);
-
- closeButton = new Button("Close");
- gridbag.setConstraints(closeButton, gbc);
- add(closeButton);
- closeButton.addActionListener(this);
-
- // Set correct text, font and color for the statusLabel.
- stopRecording();
-
- pack();
-
- addWindowListener(this);
- }
-
- //
- // If the given string ends with ".NNN" where NNN is a decimal
- // number, increase this number by one. Otherwise, append ".001"
- // to the given string.
- //
-
- protected String nextFilename(String fname) {
- int len = fname.length();
- int suffixPos = len;
- int suffixNum = 1;
-
- if (len > 4 && fname.charAt(len - 4) == '.') {
- try {
- suffixNum = Integer.parseInt(fname.substring(len - 3, len)) + 1;
- suffixPos = len - 4;
- } catch (NumberFormatException e) { }
- }
-
- char[] zeroes = {'0', '0', '0'};
- String suffix = String.valueOf(suffixNum);
- if (suffix.length() < 3) {
- suffix = new String(zeroes, 0, 3 - suffix.length()) + suffix;
- }
-
- return fname.substring(0, suffixPos) + '.' + suffix;
- }
-
- //
- // Find next name of a file which does not exist yet.
- //
-
- protected String nextNewFilename(String fname) {
- String newName = fname;
- File f;
- try {
- do {
- newName = nextFilename(newName);
- f = new File(newName);
- } while (f.exists());
- } catch (SecurityException e) { }
-
- return newName;
- }
-
- //
- // Let the user choose a file name showing a FileDialog.
- //
-
- protected boolean browseFile() {
- File currentFile = new File(fnameField.getText());
-
- FileDialog fd =
- new FileDialog(this, "Save next session as...", FileDialog.SAVE);
- fd.setDirectory(currentFile.getParent());
- fd.setVisible(true);
- if (fd.getFile() != null) {
- String newDir = fd.getDirectory();
- String sep = System.getProperty("file.separator");
- if (newDir.length() > 0) {
- if (!sep.equals(newDir.substring(newDir.length() - sep.length())))
- newDir += sep;
- }
- String newFname = newDir + fd.getFile();
- if (newFname.equals(fnameField.getText())) {
- fnameField.setText(newFname);
- return true;
- }
- }
- return false;
- }
-
- //
- // Start recording.
- //
-
- public void startRecording() {
- statusLabel.setText("Status: Recording...");
- statusLabel.setFont(new Font("Helvetica", Font.BOLD, 12));
- statusLabel.setForeground(Color.red);
- recordButton.setLabel("Stop recording");
-
- recording = true;
-
- viewer.setRecordingStatus(fnameField.getText());
- }
-
- //
- // Stop recording.
- //
-
- public void stopRecording() {
- statusLabel.setText("Status: Not recording.");
- statusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
- statusLabel.setForeground(Color.black);
- recordButton.setLabel("Record");
-
- recording = false;
-
- viewer.setRecordingStatus(null);
- }
-
- //
- // Close our window properly.
- //
-
- public void windowClosing(WindowEvent evt) {
- setVisible(false);
- }
-
- //
- // Ignore window events we're not interested in.
- //
-
- public void windowActivated(WindowEvent evt) {}
- public void windowDeactivated (WindowEvent evt) {}
- public void windowOpened(WindowEvent evt) {}
- public void windowClosed(WindowEvent evt) {}
- public void windowIconified(WindowEvent evt) {}
- public void windowDeiconified(WindowEvent evt) {}
-
-
- //
- // Respond to button presses
- //
-
- public void actionPerformed(ActionEvent evt) {
- if (evt.getSource() == browseButton) {
- if (browseFile() && recording)
- startRecording();
-
- } else if (evt.getSource() == recordButton) {
- if (!recording) {
- startRecording();
- } else {
- stopRecording();
- fnameField.setText(nextNewFilename(fnameField.getText()));
- }
-
- } else if (evt.getSource() == nextButton) {
- fnameField.setText(nextNewFilename(fnameField.getText()));
- if (recording)
- startRecording();
-
- } else if (evt.getSource() == closeButton) {
- setVisible(false);
-
- }
- }
-}
+++ /dev/null
-//
-// Copyright (C) 2002 Cendio Systems. All Rights Reserved.
-// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// ReloginPanel class implements panel with a button for logging in again,
-// after fatal errors or disconnect
-//
-
-package com.tightvnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.applet.*;
-
-//
-// The panel which implements the Relogin button
-//
-
-class ReloginPanel extends Panel implements ActionListener {
- Button reloginButton;
- Button closeButton;
- VncViewer viewer;
-
- //
- // Constructor.
- //
- public ReloginPanel(VncViewer v) {
- viewer = v;
- setLayout(new FlowLayout(FlowLayout.CENTER));
- reloginButton = new Button("Login again");
- add(reloginButton);
- reloginButton.addActionListener(this);
- if (viewer.inSeparateFrame) {
- closeButton = new Button("Close window");
- add(closeButton);
- closeButton.addActionListener(this);
- }
- }
-
- //
- // This method is called when a button is pressed.
- //
- public synchronized void actionPerformed(ActionEvent evt) {
- if (viewer.inSeparateFrame)
- viewer.vncFrame.dispose();
- if (evt.getSource() == reloginButton)
- viewer.getAppletContext().showDocument(viewer.getDocumentBase());
- }
-}
+++ /dev/null
-package com.tightvnc.vncviewer;
-
-import java.io.IOException;
-
-//
-// This class is layer between data of private RfbProto class
-// and classes in other packages.
-//
-// For now this class is used by com.tightvnc.decoder.RawDecoder
-//
-public class RfbInputStream {
- RfbInputStream(RfbProto rfbProto) {
- rfb = rfbProto;
- }
-
- //
- // Read data methods
- //
-
- public void readFully(byte b[]) throws IOException {
- readFully(b, 0, b.length);
- }
-
- public void readFully(byte b[], int off, int len) throws IOException {
- rfb.readFully(b, off, len);
- }
-
- public int readU32() throws IOException {
- return rfb.readU32();
- }
-
- public int readU8() throws IOException {
- return rfb.readU8();
- }
-
- public int readCompactLen() throws IOException {
- return rfb.readCompactLen();
- }
-
- public int readU16() throws IOException {
- return rfb.readU16();
- }
-
- private RfbProto rfb = null;
-}
+++ /dev/null
-//
-// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2001-2006 Constantin Kaplinsky. All Rights Reserved.
-// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// RfbProto.java
-//
-
-package com.tightvnc.vncviewer;
-
-import java.io.*;
-import java.awt.*;
-import java.awt.event.*;
-import java.net.Socket;
-import java.util.zip.*;
-
-class RfbProto {
-
- final static String
- versionMsg_3_3 = "RFB 003.003\n",
- versionMsg_3_7 = "RFB 003.007\n",
- versionMsg_3_8 = "RFB 003.008\n";
-
- // Vendor signatures: standard VNC/RealVNC, TridiaVNC, and TightVNC
- final static String
- StandardVendor = "STDV",
- TridiaVncVendor = "TRDV",
- TightVncVendor = "TGHT";
-
- // Security types
- final static int
- SecTypeInvalid = 0,
- SecTypeNone = 1,
- SecTypeVncAuth = 2,
- SecTypeTight = 16;
-
- // Supported tunneling types
- final static int
- NoTunneling = 0;
- final static String
- SigNoTunneling = "NOTUNNEL";
-
- // Supported authentication types
- final static int
- AuthNone = 1,
- AuthVNC = 2,
- AuthUnixLogin = 129;
- final static String
- SigAuthNone = "NOAUTH__",
- SigAuthVNC = "VNCAUTH_",
- SigAuthUnixLogin = "ULGNAUTH";
-
- // VNC authentication results
- final static int
- VncAuthOK = 0,
- VncAuthFailed = 1,
- VncAuthTooMany = 2;
-
- // Standard server-to-client messages
- final static int
- FramebufferUpdate = 0,
- SetColourMapEntries = 1,
- Bell = 2,
- ServerCutText = 3;
-
- // Non-standard server-to-client messages
- final static int
- EndOfContinuousUpdates = 150;
- final static String
- SigEndOfContinuousUpdates = "CUS_EOCU";
-
- // Standard client-to-server messages
- final static int
- SetPixelFormat = 0,
- FixColourMapEntries = 1,
- SetEncodings = 2,
- FramebufferUpdateRequest = 3,
- KeyboardEvent = 4,
- PointerEvent = 5,
- ClientCutText = 6;
-
- // Non-standard client-to-server messages
- final static int EnableContinuousUpdates = 150;
- final static int VideoRectangleSelection = 151;
- final static int VideoFreeze = 152;
- final static String SigVideoFreeze = "VD_FREEZ";
- final static String SigEnableContinuousUpdates = "CUC_ENCU";
- final static String SigVideoRectangleSelection = "VRECTSEL";
-
- // Supported encodings and pseudo-encodings
- final static int
- EncodingRaw = 0,
- EncodingCopyRect = 1,
- EncodingRRE = 2,
- EncodingCoRRE = 4,
- EncodingHextile = 5,
- EncodingZlib = 6,
- EncodingTight = 7,
- EncodingZRLE = 16,
- EncodingCompressLevel0 = 0xFFFFFF00,
- EncodingQualityLevel0 = 0xFFFFFFE0,
- EncodingXCursor = 0xFFFFFF10,
- EncodingRichCursor = 0xFFFFFF11,
- EncodingPointerPos = 0xFFFFFF18,
- EncodingLastRect = 0xFFFFFF20,
- EncodingNewFBSize = 0xFFFFFF21;
- final static String
- SigEncodingRaw = "RAW_____",
- SigEncodingCopyRect = "COPYRECT",
- SigEncodingRRE = "RRE_____",
- SigEncodingCoRRE = "CORRE___",
- SigEncodingHextile = "HEXTILE_",
- SigEncodingZlib = "ZLIB____",
- SigEncodingTight = "TIGHT___",
- SigEncodingZRLE = "ZRLE____",
- SigEncodingCompressLevel0 = "COMPRLVL",
- SigEncodingQualityLevel0 = "JPEGQLVL",
- SigEncodingXCursor = "X11CURSR",
- SigEncodingRichCursor = "RCHCURSR",
- SigEncodingPointerPos = "POINTPOS",
- SigEncodingLastRect = "LASTRECT",
- SigEncodingNewFBSize = "NEWFBSIZ";
-
- final static int MaxNormalEncoding = 255;
-
- // Contstants used in the Hextile decoder
- final static int
- HextileRaw = 1,
- HextileBackgroundSpecified = 2,
- HextileForegroundSpecified = 4,
- HextileAnySubrects = 8,
- HextileSubrectsColoured = 16;
-
- // Contstants used in the Tight decoder
- final static int TightMinToCompress = 12;
- final static int
- TightExplicitFilter = 0x04,
- TightFill = 0x08,
- TightJpeg = 0x09,
- TightMaxSubencoding = 0x09,
- TightFilterCopy = 0x00,
- TightFilterPalette = 0x01,
- TightFilterGradient = 0x02;
-
-
- String host;
- int port;
- Socket sock;
- OutputStream os;
- SessionRecorder rec;
- boolean inNormalProtocol = false;
- VncViewer viewer;
-
- // Input stream is declared private to make sure it can be accessed
- // only via RfbProto methods. We have to do this because we want to
- // count how many bytes were read.
- private DataInputStream is;
- private long numBytesRead = 0;
- public long getNumBytesRead() { return numBytesRead; }
-
- // Java on UNIX does not call keyPressed() on some keys, for example
- // swedish keys To prevent our workaround to produce duplicate
- // keypresses on JVMs that actually works, keep track of if
- // keyPressed() for a "broken" key was called or not.
- boolean brokenKeyPressed = false;
-
- // This will be set to true on the first framebuffer update
- // containing Zlib-, ZRLE- or Tight-encoded data.
- boolean wereZlibUpdates = false;
-
- // This fields are needed to show warnings about inefficiently saved
- // sessions only once per each saved session file.
- boolean zlibWarningShown;
- boolean tightWarningShown;
-
- // Before starting to record each saved session, we set this field
- // to 0, and increment on each framebuffer update. We don't flush
- // the SessionRecorder data into the file before the second update.
- // This allows us to write initial framebuffer update with zero
- // timestamp, to let the player show initial desktop before
- // playback.
- int numUpdatesInSession;
-
- // Measuring network throughput.
- boolean timing;
- long timeWaitedIn100us;
- long timedKbits;
-
- // Protocol version and TightVNC-specific protocol options.
- int serverMajor, serverMinor;
- int clientMajor, clientMinor;
- boolean protocolTightVNC;
- CapsContainer tunnelCaps, authCaps;
- CapsContainer serverMsgCaps, clientMsgCaps;
- CapsContainer encodingCaps;
-
- // "Continuous updates" is a TightVNC-specific feature that allows
- // receiving framebuffer updates continuously, without sending update
- // requests. The variables below track the state of this feature.
- // Initially, continuous updates are disabled. They can be enabled
- // by calling tryEnableContinuousUpdates() method, and only if this
- // feature is supported by the server. To disable continuous updates,
- // tryDisableContinuousUpdates() should be called.
- private boolean continuousUpdatesActive = false;
- private boolean continuousUpdatesEnding = false;
-
- // If true, informs that the RFB socket was closed.
- private boolean closed;
-
- //
- // Constructor. Make TCP connection to RFB server.
- //
-
- RfbProto(String h, int p, VncViewer v) throws IOException {
- viewer = v;
- host = h;
- port = p;
-
- if (viewer.socketFactory == null) {
- sock = new Socket(host, port);
- sock.setTcpNoDelay(true);
- } else {
- try {
- Class factoryClass = Class.forName(viewer.socketFactory);
- SocketFactory factory = (SocketFactory)factoryClass.newInstance();
- if (viewer.inAnApplet)
- sock = factory.createSocket(host, port, viewer);
- else
- sock = factory.createSocket(host, port, viewer.mainArgs);
- } catch(Exception e) {
- e.printStackTrace();
- throw new IOException(e.getMessage());
- }
- }
- is = new DataInputStream(new BufferedInputStream(sock.getInputStream(),
- 16384));
- os = sock.getOutputStream();
-
- timing = false;
- timeWaitedIn100us = 5;
- timedKbits = 0;
- }
-
-
- synchronized void close() {
- try {
- sock.close();
- closed = true;
- System.out.println("RFB socket closed");
- if (rec != null) {
- rec.close();
- rec = null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- synchronized boolean closed() {
- return closed;
- }
-
- //
- // Read server's protocol version message
- //
-
- void readVersionMsg() throws Exception {
-
- byte[] b = new byte[12];
-
- readFully(b);
-
- 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] != '.')
- || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9')
- || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n'))
- {
- throw new Exception("Host " + host + " port " + port +
- " is not an RFB server");
- }
-
- serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
- serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
-
- if (serverMajor < 3) {
- throw new Exception("RFB server does not support protocol version 3");
- }
- }
-
-
- //
- // Write our protocol version message
- //
-
- void writeVersionMsg() throws IOException {
- clientMajor = 3;
- if (serverMajor > 3 || serverMinor >= 8) {
- clientMinor = 8;
- os.write(versionMsg_3_8.getBytes());
- } else if (serverMinor >= 7) {
- clientMinor = 7;
- os.write(versionMsg_3_7.getBytes());
- } else {
- clientMinor = 3;
- os.write(versionMsg_3_3.getBytes());
- }
- protocolTightVNC = false;
- initCapabilities();
- }
-
-
- //
- // Negotiate the authentication scheme.
- //
-
- int negotiateSecurity() throws Exception {
- return (clientMinor >= 7) ?
- selectSecurityType() : readSecurityType();
- }
-
- //
- // Read security type from the server (protocol version 3.3).
- //
-
- int readSecurityType() throws Exception {
- int secType = readU32();
-
- switch (secType) {
- case SecTypeInvalid:
- readConnFailedReason();
- return SecTypeInvalid; // should never be executed
- case SecTypeNone:
- case SecTypeVncAuth:
- return secType;
- default:
- throw new Exception("Unknown security type from RFB server: " + secType);
- }
- }
-
- //
- // Select security type from the server's list (protocol versions 3.7/3.8).
- //
-
- int selectSecurityType() throws Exception {
- int secType = SecTypeInvalid;
-
- // Read the list of secutiry types.
- int nSecTypes = readU8();
- if (nSecTypes == 0) {
- readConnFailedReason();
- return SecTypeInvalid; // should never be executed
- }
- byte[] secTypes = new byte[nSecTypes];
- readFully(secTypes);
-
- // Find out if the server supports TightVNC protocol extensions
- for (int i = 0; i < nSecTypes; i++) {
- if (secTypes[i] == SecTypeTight) {
- protocolTightVNC = true;
- os.write(SecTypeTight);
- return SecTypeTight;
- }
- }
-
- // Find first supported security type.
- for (int i = 0; i < nSecTypes; i++) {
- if (secTypes[i] == SecTypeNone || secTypes[i] == SecTypeVncAuth) {
- secType = secTypes[i];
- break;
- }
- }
-
- if (secType == SecTypeInvalid) {
- throw new Exception("Server did not offer supported security type");
- } else {
- os.write(secType);
- }
-
- return secType;
- }
-
- //
- // Perform "no authentication".
- //
-
- void authenticateNone() throws Exception {
- if (clientMinor >= 8)
- readSecurityResult("No authentication");
- }
-
- //
- // Perform standard VNC Authentication.
- //
-
- void authenticateVNC(String pw) throws Exception {
- byte[] challenge = new byte[16];
- readFully(challenge);
-
- if (pw.length() > 8)
- pw = pw.substring(0, 8); // Truncate to 8 chars
-
- // Truncate password on the first zero byte.
- int firstZero = pw.indexOf(0);
- if (firstZero != -1)
- pw = pw.substring(0, firstZero);
-
- byte[] key = {0, 0, 0, 0, 0, 0, 0, 0};
- System.arraycopy(pw.getBytes(), 0, key, 0, pw.length());
-
- DesCipher des = new DesCipher(key);
-
- des.encrypt(challenge, 0, challenge, 0);
- des.encrypt(challenge, 8, challenge, 8);
-
- os.write(challenge);
-
- readSecurityResult("VNC authentication");
- }
-
- //
- // Read security result.
- // Throws an exception on authentication failure.
- //
-
- void readSecurityResult(String authType) throws Exception {
- int securityResult = readU32();
-
- switch (securityResult) {
- case VncAuthOK:
- System.out.println(authType + ": success");
- break;
- case VncAuthFailed:
- if (clientMinor >= 8)
- readConnFailedReason();
- throw new Exception(authType + ": failed");
- case VncAuthTooMany:
- throw new Exception(authType + ": failed, too many tries");
- default:
- throw new Exception(authType + ": unknown result " + securityResult);
- }
- }
-
- //
- // Read the string describing the reason for a connection failure,
- // and throw an exception.
- //
-
- void readConnFailedReason() throws Exception {
- int reasonLen = readU32();
- byte[] reason = new byte[reasonLen];
- readFully(reason);
- throw new Exception(new String(reason));
- }
-
- //
- // Initialize capability lists (TightVNC protocol extensions).
- //
-
- void initCapabilities() {
- tunnelCaps = new CapsContainer();
- authCaps = new CapsContainer();
- serverMsgCaps = new CapsContainer();
- clientMsgCaps = new CapsContainer();
- encodingCaps = new CapsContainer();
-
- // Supported authentication methods
- authCaps.add(AuthNone, StandardVendor, SigAuthNone,
- "No authentication");
- authCaps.add(AuthVNC, StandardVendor, SigAuthVNC,
- "Standard VNC password authentication");
-
- // Supported non-standard server-to-client messages
- serverMsgCaps.add(EndOfContinuousUpdates, TightVncVendor,
- SigEndOfContinuousUpdates,
- "End of continuous updates notification");
-
- // Supported non-standard client-to-server messages
- clientMsgCaps.add(EnableContinuousUpdates, TightVncVendor,
- SigEnableContinuousUpdates,
- "Enable/disable continuous updates");
- clientMsgCaps.add(VideoRectangleSelection, TightVncVendor,
- SigVideoRectangleSelection,
- "Select a rectangle to be treated as video");
- clientMsgCaps.add(VideoFreeze, TightVncVendor,
- SigVideoFreeze,
- "Disable/enable video rectangle");
-
- // Supported encoding types
- encodingCaps.add(EncodingCopyRect, StandardVendor,
- SigEncodingCopyRect, "Standard CopyRect encoding");
- encodingCaps.add(EncodingRRE, StandardVendor,
- SigEncodingRRE, "Standard RRE encoding");
- encodingCaps.add(EncodingCoRRE, StandardVendor,
- SigEncodingCoRRE, "Standard CoRRE encoding");
- encodingCaps.add(EncodingHextile, StandardVendor,
- SigEncodingHextile, "Standard Hextile encoding");
- encodingCaps.add(EncodingZRLE, StandardVendor,
- SigEncodingZRLE, "Standard ZRLE encoding");
- encodingCaps.add(EncodingZlib, TridiaVncVendor,
- SigEncodingZlib, "Zlib encoding");
- encodingCaps.add(EncodingTight, TightVncVendor,
- SigEncodingTight, "Tight encoding");
-
- // Supported pseudo-encoding types
- encodingCaps.add(EncodingCompressLevel0, TightVncVendor,
- SigEncodingCompressLevel0, "Compression level");
- encodingCaps.add(EncodingQualityLevel0, TightVncVendor,
- SigEncodingQualityLevel0, "JPEG quality level");
- encodingCaps.add(EncodingXCursor, TightVncVendor,
- SigEncodingXCursor, "X-style cursor shape update");
- encodingCaps.add(EncodingRichCursor, TightVncVendor,
- SigEncodingRichCursor, "Rich-color cursor shape update");
- encodingCaps.add(EncodingPointerPos, TightVncVendor,
- SigEncodingPointerPos, "Pointer position update");
- encodingCaps.add(EncodingLastRect, TightVncVendor,
- SigEncodingLastRect, "LastRect protocol extension");
- encodingCaps.add(EncodingNewFBSize, TightVncVendor,
- SigEncodingNewFBSize, "Framebuffer size change");
- }
-
- //
- // Setup tunneling (TightVNC protocol extensions)
- //
-
- void setupTunneling() throws IOException {
- int nTunnelTypes = readU32();
- if (nTunnelTypes != 0) {
- readCapabilityList(tunnelCaps, nTunnelTypes);
-
- // We don't support tunneling yet.
- writeInt(NoTunneling);
- }
- }
-
- //
- // Negotiate authentication scheme (TightVNC protocol extensions)
- //
-
- int negotiateAuthenticationTight() throws Exception {
- int nAuthTypes = readU32();
- if (nAuthTypes == 0)
- return AuthNone;
-
- readCapabilityList(authCaps, nAuthTypes);
- for (int i = 0; i < authCaps.numEnabled(); i++) {
- int authType = authCaps.getByOrder(i);
- if (authType == AuthNone || authType == AuthVNC) {
- writeInt(authType);
- return authType;
- }
- }
- throw new Exception("No suitable authentication scheme found");
- }
-
- //
- // Read a capability list (TightVNC protocol extensions)
- //
-
- void readCapabilityList(CapsContainer caps, int count) throws IOException {
- int code;
- byte[] vendor = new byte[4];
- byte[] name = new byte[8];
- for (int i = 0; i < count; i++) {
- code = readU32();
- readFully(vendor);
- readFully(name);
- caps.enable(new CapabilityInfo(code, vendor, name));
- }
- }
-
- //
- // Write a 32-bit integer into the output stream.
- //
-
- void writeInt(int value) throws IOException {
- byte[] b = new byte[4];
- b[0] = (byte) ((value >> 24) & 0xff);
- b[1] = (byte) ((value >> 16) & 0xff);
- b[2] = (byte) ((value >> 8) & 0xff);
- b[3] = (byte) (value & 0xff);
- os.write(b);
- }
-
- //
- // Write the client initialisation message
- //
-
- void writeClientInit() throws IOException {
- if (viewer.options.shareDesktop) {
- os.write(1);
- } else {
- os.write(0);
- }
- viewer.options.disableShareDesktop();
- }
-
-
- //
- // Read the server initialisation message
- //
-
- String desktopName;
- int framebufferWidth, framebufferHeight;
- int bitsPerPixel, depth;
- boolean bigEndian, trueColour;
- int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
-
- void readServerInit() throws IOException {
- framebufferWidth = readU16();
- framebufferHeight = readU16();
- bitsPerPixel = readU8();
- depth = readU8();
- bigEndian = (readU8() != 0);
- trueColour = (readU8() != 0);
- redMax = readU16();
- greenMax = readU16();
- blueMax = readU16();
- redShift = readU8();
- greenShift = readU8();
- blueShift = readU8();
- byte[] pad = new byte[3];
- readFully(pad);
- int nameLength = readU32();
- byte[] name = new byte[nameLength];
- readFully(name);
- desktopName = new String(name);
-
- // Read interaction capabilities (TightVNC protocol extensions)
- if (protocolTightVNC) {
- int nServerMessageTypes = readU16();
- int nClientMessageTypes = readU16();
- int nEncodingTypes = readU16();
- readU16();
- readCapabilityList(serverMsgCaps, nServerMessageTypes);
- readCapabilityList(clientMsgCaps, nClientMessageTypes);
- readCapabilityList(encodingCaps, nEncodingTypes);
- }
-
- if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
- viewer.options.disableContUpdates();
- }
-
- inNormalProtocol = true;
- }
-
-
- //
- // Create session file and write initial protocol messages into it.
- //
-
- void startSession(String fname) throws IOException {
- rec = new SessionRecorder(fname);
- rec.writeHeader();
- rec.write(versionMsg_3_3.getBytes());
- rec.writeIntBE(SecTypeNone);
- rec.writeShortBE(framebufferWidth);
- rec.writeShortBE(framebufferHeight);
- byte[] fbsServerInitMsg = {
- 32, 24, 0, 1, 0,
- (byte)0xFF, 0, (byte)0xFF, 0, (byte)0xFF,
- 16, 8, 0, 0, 0, 0
- };
- rec.write(fbsServerInitMsg);
- rec.writeIntBE(desktopName.length());
- rec.write(desktopName.getBytes());
- numUpdatesInSession = 0;
-
- // FIXME: If there were e.g. ZRLE updates only, that should not
- // affect recording of Zlib and Tight updates. So, actually
- // we should maintain separate flags for Zlib, ZRLE and
- // Tight, instead of one ``wereZlibUpdates'' variable.
- //
-
- zlibWarningShown = false;
- tightWarningShown = false;
- }
-
- //
- // Close session file.
- //
-
- void closeSession() throws IOException {
- if (rec != null) {
- rec.close();
- rec = null;
- }
- }
-
-
- //
- // Set new framebuffer size
- //
-
- void setFramebufferSize(int width, int height) {
- framebufferWidth = width;
- framebufferHeight = height;
- }
-
-
- //
- // Read the server message type
- //
-
- int readServerMessageType() throws IOException {
- int msgType = readU8();
-
- // If the session is being recorded:
- if (rec != null) {
- if (msgType == Bell) { // Save Bell messages in session files.
- rec.writeByte(msgType);
- if (numUpdatesInSession > 0)
- rec.flush();
- }
- }
-
- return msgType;
- }
-
-
- //
- // Read a FramebufferUpdate message
- //
-
- int updateNRects;
-
- void readFramebufferUpdate() throws IOException {
- skipBytes(1);
- updateNRects = readU16();
-
- // If the session is being recorded:
- if (rec != null) {
- rec.writeByte(FramebufferUpdate);
- rec.writeByte(0);
- rec.writeShortBE(updateNRects);
- }
-
- numUpdatesInSession++;
- }
-
- //
- // Returns true if encoding is not pseudo
- //
- // FIXME: Find better way to differ pseudo and real encodings
- //
-
- boolean isRealDecoderEncoding(int encoding) {
- if ((encoding >= 1) && (encoding <= 16)) {
- return true;
- }
- return false;
- }
-
- // Read a FramebufferUpdate rectangle header
-
- int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
-
- void readFramebufferUpdateRectHdr() throws Exception {
- updateRectX = readU16();
- updateRectY = readU16();
- updateRectW = readU16();
- updateRectH = readU16();
- updateRectEncoding = readU32();
-
- if (updateRectEncoding == EncodingZlib ||
- updateRectEncoding == EncodingZRLE ||
- updateRectEncoding == EncodingTight)
- wereZlibUpdates = true;
-
- // If the session is being recorded:
- if (rec != null) {
- if (numUpdatesInSession > 1)
- rec.flush(); // Flush the output on each rectangle.
- rec.writeShortBE(updateRectX);
- rec.writeShortBE(updateRectY);
- rec.writeShortBE(updateRectW);
- rec.writeShortBE(updateRectH);
-
- //
- // If this is pseudo encoding or CopyRect that write encoding ID
- // in this place. All real encoding ID will be written to record stream
- // in decoder classes.
-
- if (((!isRealDecoderEncoding(updateRectEncoding))) && (rec != null)) {
- rec.writeIntBE(updateRectEncoding);
- }
- }
-
- if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding)
- return;
-
- if (updateRectX + updateRectW > framebufferWidth ||
- updateRectY + updateRectH > framebufferHeight) {
- throw new Exception("Framebuffer update rectangle too large: " +
- updateRectW + "x" + updateRectH + " at (" +
- updateRectX + "," + updateRectY + ")");
- }
- }
-
- //
- // Read a ServerCutText message
- //
-
- String readServerCutText() throws IOException {
- skipBytes(3);
- int len = readU32();
- byte[] text = new byte[len];
- readFully(text);
- return new String(text);
- }
-
-
- //
- // Read an integer in compact representation (1..3 bytes).
- // Such format is used as a part of the Tight encoding.
- // Also, this method records data if session recording is active and
- // the viewer's recordFromBeginning variable is set to true.
- //
-
- int readCompactLen() throws IOException {
- int[] portion = new int[3];
- portion[0] = readU8();
- int byteCount = 1;
- int len = portion[0] & 0x7F;
- if ((portion[0] & 0x80) != 0) {
- portion[1] = readU8();
- byteCount++;
- len |= (portion[1] & 0x7F) << 7;
- if ((portion[1] & 0x80) != 0) {
- portion[2] = readU8();
- byteCount++;
- len |= (portion[2] & 0xFF) << 14;
- }
- }
-
- return len;
- }
-
-
- //
- // Write a FramebufferUpdateRequest message
- //
-
- void writeFramebufferUpdateRequest(int x, int y, int w, int h,
- boolean incremental)
- throws IOException
- {
- byte[] b = new byte[10];
-
- b[0] = (byte) FramebufferUpdateRequest;
- b[1] = (byte) (incremental ? 1 : 0);
- b[2] = (byte) ((x >> 8) & 0xff);
- b[3] = (byte) (x & 0xff);
- b[4] = (byte) ((y >> 8) & 0xff);
- b[5] = (byte) (y & 0xff);
- b[6] = (byte) ((w >> 8) & 0xff);
- b[7] = (byte) (w & 0xff);
- b[8] = (byte) ((h >> 8) & 0xff);
- b[9] = (byte) (h & 0xff);
-
- os.write(b);
- }
-
-
- //
- // Write a SetPixelFormat message
- //
-
- void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian,
- boolean trueColour,
- int redMax, int greenMax, int blueMax,
- int redShift, int greenShift, int blueShift)
- throws IOException
- {
- byte[] b = new byte[20];
-
- b[0] = (byte) SetPixelFormat;
- b[4] = (byte) bitsPerPixel;
- b[5] = (byte) depth;
- b[6] = (byte) (bigEndian ? 1 : 0);
- b[7] = (byte) (trueColour ? 1 : 0);
- b[8] = (byte) ((redMax >> 8) & 0xff);
- b[9] = (byte) (redMax & 0xff);
- b[10] = (byte) ((greenMax >> 8) & 0xff);
- b[11] = (byte) (greenMax & 0xff);
- b[12] = (byte) ((blueMax >> 8) & 0xff);
- b[13] = (byte) (blueMax & 0xff);
- b[14] = (byte) redShift;
- b[15] = (byte) greenShift;
- b[16] = (byte) blueShift;
-
- os.write(b);
- }
-
-
- //
- // Write a FixColourMapEntries message. The values in the red, green and
- // blue arrays are from 0 to 65535.
- //
-
- void writeFixColourMapEntries(int firstColour, int nColours,
- int[] red, int[] green, int[] blue)
- throws IOException
- {
- byte[] b = new byte[6 + nColours * 6];
-
- b[0] = (byte) FixColourMapEntries;
- b[2] = (byte) ((firstColour >> 8) & 0xff);
- b[3] = (byte) (firstColour & 0xff);
- b[4] = (byte) ((nColours >> 8) & 0xff);
- b[5] = (byte) (nColours & 0xff);
-
- for (int i = 0; i < nColours; i++) {
- b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff);
- b[6 + i * 6 + 1] = (byte) (red[i] & 0xff);
- b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff);
- b[6 + i * 6 + 3] = (byte) (green[i] & 0xff);
- b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff);
- b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff);
- }
-
- os.write(b);
- }
-
-
- //
- // Write a SetEncodings message
- //
-
- void writeSetEncodings(int[] encs, int len) throws IOException {
- byte[] b = new byte[4 + 4 * len];
-
- b[0] = (byte) SetEncodings;
- b[2] = (byte) ((len >> 8) & 0xff);
- b[3] = (byte) (len & 0xff);
-
- for (int i = 0; i < len; i++) {
- b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff);
- b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff);
- b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff);
- b[7 + 4 * i] = (byte) (encs[i] & 0xff);
- }
-
- os.write(b);
- }
-
-
- //
- // Write a ClientCutText message
- //
-
- void writeClientCutText(String text) throws IOException {
- byte[] b = new byte[8 + text.length()];
-
- b[0] = (byte) ClientCutText;
- b[4] = (byte) ((text.length() >> 24) & 0xff);
- b[5] = (byte) ((text.length() >> 16) & 0xff);
- b[6] = (byte) ((text.length() >> 8) & 0xff);
- b[7] = (byte) (text.length() & 0xff);
-
- System.arraycopy(text.getBytes(), 0, b, 8, text.length());
-
- os.write(b);
- }
-
-
- //
- // A buffer for putting pointer and keyboard events before being sent. This
- // is to ensure that multiple RFB events generated from a single Java Event
- // will all be sent in a single network packet. The maximum possible
- // length is 4 modifier down events, a single key event followed by 4
- // modifier up events i.e. 9 key events or 72 bytes.
- //
-
- byte[] eventBuf = new byte[72];
- int eventBufLen;
-
-
- // Useful shortcuts for modifier masks.
-
- final static int CTRL_MASK = InputEvent.CTRL_MASK;
- final static int SHIFT_MASK = InputEvent.SHIFT_MASK;
- final static int META_MASK = InputEvent.META_MASK;
- final static int ALT_MASK = InputEvent.ALT_MASK;
-
-
- //
- // Write a pointer event message. We may need to send modifier key events
- // around it to set the correct modifier state.
- //
-
- int pointerMask = 0;
-
- void writePointerEvent(MouseEvent evt) throws IOException {
- int modifiers = evt.getModifiers();
-
- int mask2 = 2;
- int mask3 = 4;
- if (viewer.options.reverseMouseButtons2And3) {
- mask2 = 4;
- mask3 = 2;
- }
-
- // Note: For some reason, AWT does not set BUTTON1_MASK on left
- // button presses. Here we think that it was the left button if
- // modifiers do not include BUTTON2_MASK or BUTTON3_MASK.
-
- if (evt.getID() == MouseEvent.MOUSE_PRESSED) {
- if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
- pointerMask = mask2;
- modifiers &= ~ALT_MASK;
- } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
- pointerMask = mask3;
- modifiers &= ~META_MASK;
- } else {
- pointerMask = 1;
- }
- } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) {
- pointerMask = 0;
- if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
- modifiers &= ~ALT_MASK;
- } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
- modifiers &= ~META_MASK;
- }
- }
-
- eventBufLen = 0;
- writeModifierKeyEvents(modifiers);
-
- int x = evt.getX();
- int y = evt.getY();
-
- if (x < 0) x = 0;
- if (y < 0) y = 0;
-
- eventBuf[eventBufLen++] = (byte) PointerEvent;
- eventBuf[eventBufLen++] = (byte) pointerMask;
- eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (x & 0xff);
- eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (y & 0xff);
-
- //
- // Always release all modifiers after an "up" event
- //
-
- if (pointerMask == 0) {
- writeModifierKeyEvents(0);
- }
-
- os.write(eventBuf, 0, eventBufLen);
- }
-
-
- //
- // Write a key event message. We may need to send modifier key events
- // around it to set the correct modifier state. Also we need to translate
- // from the Java key values to the X keysym values used by the RFB protocol.
- //
-
- void writeKeyEvent(KeyEvent evt) throws IOException {
-
- int keyChar = evt.getKeyChar();
-
- //
- // Ignore event if only modifiers were pressed.
- //
-
- // Some JVMs return 0 instead of CHAR_UNDEFINED in getKeyChar().
- if (keyChar == 0)
- keyChar = KeyEvent.CHAR_UNDEFINED;
-
- if (keyChar == KeyEvent.CHAR_UNDEFINED) {
- int code = evt.getKeyCode();
- if (code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_SHIFT ||
- code == KeyEvent.VK_META || code == KeyEvent.VK_ALT)
- return;
- }
-
- //
- // Key press or key release?
- //
-
- boolean down = (evt.getID() == KeyEvent.KEY_PRESSED);
-
- int key;
- if (evt.isActionKey()) {
-
- //
- // An action key should be one of the following.
- // If not then just ignore the event.
- //
-
- switch(evt.getKeyCode()) {
- case KeyEvent.VK_HOME: key = 0xff50; break;
- case KeyEvent.VK_LEFT: key = 0xff51; break;
- case KeyEvent.VK_UP: key = 0xff52; break;
- case KeyEvent.VK_RIGHT: key = 0xff53; break;
- case KeyEvent.VK_DOWN: key = 0xff54; break;
- case KeyEvent.VK_PAGE_UP: key = 0xff55; break;
- case KeyEvent.VK_PAGE_DOWN: key = 0xff56; break;
- case KeyEvent.VK_END: key = 0xff57; break;
- case KeyEvent.VK_INSERT: key = 0xff63; break;
- case KeyEvent.VK_F1: key = 0xffbe; break;
- case KeyEvent.VK_F2: key = 0xffbf; break;
- case KeyEvent.VK_F3: key = 0xffc0; break;
- case KeyEvent.VK_F4: key = 0xffc1; break;
- case KeyEvent.VK_F5: key = 0xffc2; break;
- case KeyEvent.VK_F6: key = 0xffc3; break;
- case KeyEvent.VK_F7: key = 0xffc4; break;
- case KeyEvent.VK_F8: key = 0xffc5; break;
- case KeyEvent.VK_F9: key = 0xffc6; break;
- case KeyEvent.VK_F10: key = 0xffc7; break;
- case KeyEvent.VK_F11: key = 0xffc8; break;
- case KeyEvent.VK_F12: key = 0xffc9; break;
- default:
- return;
- }
-
- } else {
-
- //
- // A "normal" key press. Ordinary ASCII characters go straight through.
- // For CTRL-<letter>, CTRL is sent separately so just send <letter>.
- // Backspace, tab, return, escape and delete have special keysyms.
- // Anything else we ignore.
- //
-
- key = keyChar;
-
- if (key < 0x20) {
- if (evt.isControlDown()) {
- key += 0x60;
- } else {
- switch(key) {
- case KeyEvent.VK_BACK_SPACE: key = 0xff08; break;
- case KeyEvent.VK_TAB: key = 0xff09; break;
- case KeyEvent.VK_ENTER: key = 0xff0d; break;
- case KeyEvent.VK_ESCAPE: key = 0xff1b; break;
- }
- }
- } else if (key == 0x7f) {
- // Delete
- key = 0xffff;
- } else if (key > 0xff) {
- // JDK1.1 on X incorrectly passes some keysyms straight through,
- // so we do too. JDK1.1.4 seems to have fixed this.
- // The keysyms passed are 0xff00 .. XK_BackSpace .. XK_Delete
- // Also, we pass through foreign currency keysyms (0x20a0..0x20af).
- if ((key < 0xff00 || key > 0xffff) &&
- !(key >= 0x20a0 && key <= 0x20af))
- return;
- }
- }
-
- // Fake keyPresses for keys that only generates keyRelease events
- if ((key == 0xe5) || (key == 0xc5) || // XK_aring / XK_Aring
- (key == 0xe4) || (key == 0xc4) || // XK_adiaeresis / XK_Adiaeresis
- (key == 0xf6) || (key == 0xd6) || // XK_odiaeresis / XK_Odiaeresis
- (key == 0xa7) || (key == 0xbd) || // XK_section / XK_onehalf
- (key == 0xa3)) { // XK_sterling
- // Make sure we do not send keypress events twice on platforms
- // with correct JVMs (those that actually report KeyPress for all
- // keys)
- if (down)
- brokenKeyPressed = true;
-
- if (!down && !brokenKeyPressed) {
- // We've got a release event for this key, but haven't received
- // a press. Fake it.
- eventBufLen = 0;
- writeModifierKeyEvents(evt.getModifiers());
- writeKeyEvent(key, true);
- os.write(eventBuf, 0, eventBufLen);
- }
-
- if (!down)
- brokenKeyPressed = false;
- }
-
- eventBufLen = 0;
- writeModifierKeyEvents(evt.getModifiers());
- writeKeyEvent(key, down);
-
- // Always release all modifiers after an "up" event
- if (!down)
- writeModifierKeyEvents(0);
-
- os.write(eventBuf, 0, eventBufLen);
- }
-
-
- //
- // Add a raw key event with the given X keysym to eventBuf.
- //
-
- void writeKeyEvent(int keysym, boolean down) {
- eventBuf[eventBufLen++] = (byte) KeyboardEvent;
- eventBuf[eventBufLen++] = (byte) (down ? 1 : 0);
- eventBuf[eventBufLen++] = (byte) 0;
- eventBuf[eventBufLen++] = (byte) 0;
- eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff);
- eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff);
- eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (keysym & 0xff);
- }
-
-
- //
- // Write key events to set the correct modifier state.
- //
-
- int oldModifiers = 0;
-
- void writeModifierKeyEvents(int newModifiers) {
- if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK))
- writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0);
-
- if ((newModifiers & SHIFT_MASK) != (oldModifiers & SHIFT_MASK))
- writeKeyEvent(0xffe1, (newModifiers & SHIFT_MASK) != 0);
-
- if ((newModifiers & META_MASK) != (oldModifiers & META_MASK))
- writeKeyEvent(0xffe7, (newModifiers & META_MASK) != 0);
-
- if ((newModifiers & ALT_MASK) != (oldModifiers & ALT_MASK))
- writeKeyEvent(0xffe9, (newModifiers & ALT_MASK) != 0);
-
- oldModifiers = newModifiers;
- }
-
-
- //
- // Enable continuous updates for the specified area of the screen (but
- // only if EnableContinuousUpdates message is supported by the server).
- //
-
- void tryEnableContinuousUpdates(int x, int y, int w, int h)
- throws IOException
- {
- if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
- System.out.println("Continuous updates not supported by the server");
- return;
- }
-
- if (continuousUpdatesActive) {
- System.out.println("Continuous updates already active");
- return;
- }
-
- byte[] b = new byte[10];
-
- b[0] = (byte) EnableContinuousUpdates;
- b[1] = (byte) 1; // enable
- b[2] = (byte) ((x >> 8) & 0xff);
- b[3] = (byte) (x & 0xff);
- b[4] = (byte) ((y >> 8) & 0xff);
- b[5] = (byte) (y & 0xff);
- b[6] = (byte) ((w >> 8) & 0xff);
- b[7] = (byte) (w & 0xff);
- b[8] = (byte) ((h >> 8) & 0xff);
- b[9] = (byte) (h & 0xff);
-
- os.write(b);
-
- continuousUpdatesActive = true;
- System.out.println("Continuous updates activated");
- }
-
-
- //
- // Disable continuous updates (only if EnableContinuousUpdates message
- // is supported by the server).
- //
-
- void tryDisableContinuousUpdates() throws IOException
- {
- if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
- System.out.println("Continuous updates not supported by the server");
- return;
- }
-
- if (!continuousUpdatesActive) {
- System.out.println("Continuous updates already disabled");
- return;
- }
-
- if (continuousUpdatesEnding)
- return;
-
- byte[] b = { (byte)EnableContinuousUpdates, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- os.write(b);
-
- if (!serverMsgCaps.isEnabled(EndOfContinuousUpdates)) {
- // If the server did not advertise support for the
- // EndOfContinuousUpdates message (should not normally happen
- // when EnableContinuousUpdates is supported), then we clear
- // 'continuousUpdatesActive' variable immediately. Normally,
- // it will be reset on receiving EndOfContinuousUpdates message
- // from the server.
- continuousUpdatesActive = false;
- } else {
- // Indicate that we are waiting for EndOfContinuousUpdates.
- continuousUpdatesEnding = true;
- }
- }
-
-
- //
- // Process EndOfContinuousUpdates message received from the server.
- //
-
- void endOfContinuousUpdates()
- {
- continuousUpdatesActive = false;
- continuousUpdatesEnding = false;
- }
-
-
- //
- // Check if continuous updates are in effect.
- //
-
- boolean continuousUpdatesAreActive()
- {
- return continuousUpdatesActive;
- }
-
- /**
- * Send a rectangle selection to be treated as video by the server (but
- * only if VideoRectangleSelection message is supported by the server).
- * @param rect specifies coordinates and size of the rectangule.
- * @throws java.io.IOException
- */
- void trySendVideoSelection(Rectangle rect) throws IOException
- {
- if (!clientMsgCaps.isEnabled(VideoRectangleSelection)) {
- System.out.println("Video area selection is not supported by the server");
- return;
- }
-
- // Send zero coordinates if the rectangle is empty.
- if (rect.isEmpty()) {
- rect = new Rectangle();
- }
-
- int x = rect.x;
- int y = rect.y;
- int w = rect.width;
- int h = rect.height;
-
- byte[] b = new byte[10];
-
- b[0] = (byte) VideoRectangleSelection;
- b[1] = (byte) 0; // reserved
- b[2] = (byte) ((x >> 8) & 0xff);
- b[3] = (byte) (x & 0xff);
- b[4] = (byte) ((y >> 8) & 0xff);
- b[5] = (byte) (y & 0xff);
- b[6] = (byte) ((w >> 8) & 0xff);
- b[7] = (byte) (w & 0xff);
- b[8] = (byte) ((h >> 8) & 0xff);
- b[9] = (byte) (h & 0xff);
-
- os.write(b);
-
- System.out.println("Video rectangle selection message sent");
- }
-
- void trySendVideoFreeze(boolean freeze) throws IOException
- {
- if (!clientMsgCaps.isEnabled(VideoFreeze)) {
- System.out.println("Video freeze is not supported by the server");
- return;
- }
-
- byte[] b = new byte[2];
- byte fb = 0;
- if (freeze) {
- fb = 1;
- }
-
- b[0] = (byte) VideoFreeze;
- b[1] = (byte) fb;
-
- os.write(b);
-
- System.out.println("Video freeze selection message sent");
- }
-
- public void startTiming() {
- timing = true;
-
- // Carry over up to 1s worth of previous rate for smoothing.
-
- if (timeWaitedIn100us > 10000) {
- timedKbits = timedKbits * 10000 / timeWaitedIn100us;
- timeWaitedIn100us = 10000;
- }
- }
-
- public void stopTiming() {
- timing = false;
- if (timeWaitedIn100us < timedKbits/2)
- timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
- }
-
- public long kbitsPerSecond() {
- return timedKbits * 10000 / timeWaitedIn100us;
- }
-
- public long timeWaited() {
- return timeWaitedIn100us;
- }
-
- //
- // Methods for reading data via our DataInputStream member variable (is).
- //
- // In addition to reading data, the readFully() methods updates variables
- // used to estimate data throughput.
- //
-
- public void readFully(byte b[]) throws IOException {
- readFully(b, 0, b.length);
- }
-
- public void readFully(byte b[], int off, int len) throws IOException {
- long before = 0;
- if (timing)
- before = System.currentTimeMillis();
-
- is.readFully(b, off, len);
-
- if (timing) {
- long after = System.currentTimeMillis();
- long newTimeWaited = (after - before) * 10;
- int newKbits = len * 8 / 1000;
-
- // limit rate to between 10kbit/s and 40Mbit/s
-
- if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
- if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
-
- timeWaitedIn100us += newTimeWaited;
- timedKbits += newKbits;
- }
-
- numBytesRead += len;
- }
-
- final int available() throws IOException {
- return is.available();
- }
-
- // FIXME: DataInputStream::skipBytes() is not guaranteed to skip
- // exactly n bytes. Probably we don't want to use this method.
- final int skipBytes(int n) throws IOException {
- int r = is.skipBytes(n);
- numBytesRead += r;
- return r;
- }
-
- final int readU8() throws IOException {
- int r = is.readUnsignedByte();
- numBytesRead++;
- return r;
- }
-
- final int readU16() throws IOException {
- int r = is.readUnsignedShort();
- numBytesRead += 2;
- return r;
- }
-
- final int readU32() throws IOException {
- int r = is.readInt();
- numBytesRead += 4;
- return r;
- }
-}
+++ /dev/null
-//
-// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// SessionRecorder is a class to write FBS (FrameBuffer Stream) files.
-// FBS files are used to save RFB sessions for later playback.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.io.*;
-
-class SessionRecorder {
-
- protected FileOutputStream f;
- protected DataOutputStream df;
- protected long startTime, lastTimeOffset;
-
- protected byte[] buffer;
- protected int bufferSize;
- protected int bufferBytes;
-
- public SessionRecorder(String name, int bufsize) throws IOException {
- f = new FileOutputStream(name);
- df = new DataOutputStream(f);
- startTime = System.currentTimeMillis();
- lastTimeOffset = 0;
-
- bufferSize = bufsize;
- bufferBytes = 0;
- buffer = new byte[bufferSize];
- }
-
- public SessionRecorder(String name) throws IOException {
- this(name, 65536);
- }
-
- //
- // Close the file, free resources.
- //
-
- public void close() throws IOException {
- try {
- flush();
- } catch (IOException e) {
- }
-
- df = null;
- f.close();
- f = null;
- buffer = null;
- }
-
- //
- // Write the FBS file header as defined in the rfbproxy utility.
- //
-
- public void writeHeader() throws IOException {
- df.write("FBS 001.000\n".getBytes());
- }
-
- //
- // Write one byte.
- //
-
- public void writeByte(int b) throws IOException {
- prepareWriting();
- buffer[bufferBytes++] = (byte)b;
- }
-
- //
- // Write 16-bit value, big-endian.
- //
-
- public void writeShortBE(int v) throws IOException {
- prepareWriting();
- buffer[bufferBytes++] = (byte)(v >> 8);
- buffer[bufferBytes++] = (byte)v;
- }
-
- //
- // Write 32-bit value, big-endian.
- //
-
- public void writeIntBE(int v) throws IOException {
- prepareWriting();
- buffer[bufferBytes] = (byte)(v >> 24);
- buffer[bufferBytes + 1] = (byte)(v >> 16);
- buffer[bufferBytes + 2] = (byte)(v >> 8);
- buffer[bufferBytes + 3] = (byte)v;
- bufferBytes += 4;
- }
-
- //
- // Write 16-bit value, little-endian.
- //
-
- public void writeShortLE(int v) throws IOException {
- prepareWriting();
- buffer[bufferBytes++] = (byte)v;
- buffer[bufferBytes++] = (byte)(v >> 8);
- }
-
- //
- // Write 32-bit value, little-endian.
- //
-
- public void writeIntLE(int v) throws IOException {
- prepareWriting();
- buffer[bufferBytes] = (byte)v;
- buffer[bufferBytes + 1] = (byte)(v >> 8);
- buffer[bufferBytes + 2] = (byte)(v >> 16);
- buffer[bufferBytes + 3] = (byte)(v >> 24);
- bufferBytes += 4;
- }
-
- //
- // Write byte arrays.
- //
-
- public void write(byte b[], int off, int len) throws IOException {
- prepareWriting();
- while (len > 0) {
- if (bufferBytes > bufferSize - 4)
- flush(false);
-
- int partLen;
- if (bufferBytes + len > bufferSize) {
- partLen = bufferSize - bufferBytes;
- } else {
- partLen = len;
- }
- System.arraycopy(b, off, buffer, bufferBytes, partLen);
- bufferBytes += partLen;
- off += partLen;
- len -= partLen;
- }
- }
-
- public void write(byte b[]) throws IOException {
- write(b, 0, b.length);
- }
-
- //
- // Flush the output. This method saves buffered data in the
- // underlying file object adding data sizes and timestamps. If the
- // updateTimeOffset is set to false, then the current time offset
- // will not be changed for next write operation.
- //
-
- public void flush(boolean updateTimeOffset) throws IOException {
- if (bufferBytes > 0) {
- df.writeInt(bufferBytes);
- df.write(buffer, 0, (bufferBytes + 3) & 0x7FFFFFFC);
- df.writeInt((int)lastTimeOffset);
- bufferBytes = 0;
- if (updateTimeOffset)
- lastTimeOffset = -1;
- }
- }
-
- public void flush() throws IOException {
- flush(true);
- }
-
- //
- // Before writing any data, remember time offset and flush the
- // buffer before it becomes full.
- //
-
- protected void prepareWriting() throws IOException {
- if (lastTimeOffset == -1)
- lastTimeOffset = System.currentTimeMillis() - startTime;
- if (bufferBytes > bufferSize - 4)
- flush(false);
- }
-
-}
-
+++ /dev/null
-//
-// Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// SocketFactory.java describes an interface used to substitute the
-// standard Socket class by its alternative implementations.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.applet.*;
-import java.net.*;
-import java.io.*;
-
-public interface SocketFactory {
-
- public Socket createSocket(String host, int port, Applet applet)
- throws IOException;
-
- public Socket createSocket(String host, int port, String[] args)
- throws IOException;
-}
+++ /dev/null
-//
-// Copyright (C) 2004 Horizon Wimba. All Rights Reserved.
-// Copyright (C) 2001-2003 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
-// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-package com.tightvnc.vncviewer;
-
-import com.tightvnc.decoder.CoRREDecoder;
-import com.tightvnc.decoder.CopyRectDecoder;
-import com.tightvnc.decoder.HextileDecoder;
-import com.tightvnc.decoder.RREDecoder;
-import com.tightvnc.decoder.RawDecoder;
-import com.tightvnc.decoder.TightDecoder;
-import com.tightvnc.decoder.ZRLEDecoder;
-import com.tightvnc.decoder.ZlibDecoder;
-import com.tightvnc.decoder.common.Repaintable;
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.image.*;
-import java.io.*;
-import java.lang.*;
-import java.util.zip.*;
-
-
-//
-// VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
-//
-
-class VncCanvas extends Canvas
- implements KeyListener, MouseListener, MouseMotionListener, Repaintable, Runnable {
-
- VncViewer viewer;
- RfbProto rfb;
- ColorModel cm8, cm24;
- int bytesPixel;
-
- int maxWidth = 0, maxHeight = 0;
- int scalingFactor;
- int scaledWidth, scaledHeight;
-
- Image memImage;
- Graphics memGraphics;
-
- //
- // Decoders
- //
-
- RawDecoder rawDecoder;
- RREDecoder rreDecoder;
- CoRREDecoder correDecoder;
- ZlibDecoder zlibDecoder;
- HextileDecoder hextileDecoder;
- ZRLEDecoder zrleDecoder;
- TightDecoder tightDecoder;
- CopyRectDecoder copyRectDecoder;
-
- // Base decoder decoders array
- RawDecoder []decoders = null;
-
- // Update statistics.
- long statStartTime; // time on first framebufferUpdateRequest
- long statNumUpdates; // counter for FramebufferUpdate messages
- long statNumTotalRects; // rectangles in FramebufferUpdate messages
- long statNumPixelRects; // the same, but excluding pseudo-rectangles
- long statNumRectsTight; // Tight-encoded rectangles (including JPEG)
- long statNumRectsTightJPEG; // JPEG-compressed Tight-encoded rectangles
- long statNumRectsZRLE; // ZRLE-encoded rectangles
- long statNumRectsHextile; // Hextile-encoded rectangles
- long statNumRectsRaw; // Raw-encoded rectangles
- long statNumRectsCopy; // CopyRect rectangles
- long statNumBytesEncoded; // number of bytes in updates, as received
- long statNumBytesDecoded; // number of bytes, as if Raw encoding was used
-
- // True if we process keyboard and mouse events.
- boolean inputEnabled;
-
- // True if was no one auto resize of canvas
- boolean isFirstSizeAutoUpdate = true;
-
- // Members for limiting sending mouse events to server
- long lastMouseEventSendTime = System.currentTimeMillis();
- long mouseMaxFreq = 20;
-
- //
- // The constructors.
- //
-
- public VncCanvas(VncViewer v, int maxWidth_, int maxHeight_)
- throws IOException {
-
- viewer = v;
- maxWidth = maxWidth_;
- maxHeight = maxHeight_;
-
- rfb = viewer.rfb;
- scalingFactor = viewer.options.scalingFactor;
-
- cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
- cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
-
- //
- // Create decoders
- //
-
- // Input stream for decoders
- RfbInputStream rfbis = new RfbInputStream(rfb);
- // Create output stream for session recording
- RecordOutputStream ros = new RecordOutputStream(rfb);
-
- rawDecoder = new RawDecoder(memGraphics, rfbis);
- rreDecoder = new RREDecoder(memGraphics, rfbis);
- correDecoder = new CoRREDecoder(memGraphics, rfbis);
- hextileDecoder = new HextileDecoder(memGraphics, rfbis);
- tightDecoder = new TightDecoder(memGraphics, rfbis);
- zlibDecoder = new ZlibDecoder(memGraphics, rfbis);
- zrleDecoder = new ZRLEDecoder(memGraphics, rfbis);
- copyRectDecoder = new CopyRectDecoder(memGraphics, rfbis);
-
- //
- // Set data for decoders that needs extra parameters
- //
-
- hextileDecoder.setRepainableControl(this);
- tightDecoder.setRepainableControl(this);
-
- //
- // Create array that contains our decoders
- //
-
- decoders = new RawDecoder[8];
- decoders[0] = rawDecoder;
- decoders[1] = rreDecoder;
- decoders[2] = correDecoder;
- decoders[3] = hextileDecoder;
- decoders[4] = zlibDecoder;
- decoders[5] = tightDecoder;
- decoders[6] = zrleDecoder;
- decoders[7] = copyRectDecoder;
-
- //
- // Set session recorder for decoders
- //
-
- for (int i = 0; i < decoders.length; i++) {
- decoders[i].setDataOutputStream(ros);
- }
-
- setPixelFormat();
- resetSelection();
-
- inputEnabled = false;
- if (!viewer.options.viewOnly)
- enableInput(true);
-
- // Enable mouse and keyboard event listeners.
- addKeyListener(this);
- addMouseListener(this);
- addMouseMotionListener(this);
-
- // Create thread, that will send mouse movement events
- // to VNC server.
- Thread mouseThread = new Thread(this);
- mouseThread.start();
- }
-
- public VncCanvas(VncViewer v) throws IOException {
- this(v, 0, 0);
- }
-
- //
- // Callback methods to determine geometry of our Component.
- //
-
- public Dimension getPreferredSize() {
- return new Dimension(scaledWidth, scaledHeight);
- }
-
- public Dimension getMinimumSize() {
- return new Dimension(scaledWidth, scaledHeight);
- }
-
- public Dimension getMaximumSize() {
- return new Dimension(scaledWidth, scaledHeight);
- }
-
- //
- // All painting is performed here.
- //
-
- public void update(Graphics g) {
- paint(g);
- }
-
- public void paint(Graphics g) {
- synchronized(memImage) {
- if (rfb.framebufferWidth == scaledWidth) {
- g.drawImage(memImage, 0, 0, null);
- } else {
- paintScaledFrameBuffer(g);
- }
- }
- if (showSoftCursor) {
- int x0 = cursorX - hotX, y0 = cursorY - hotY;
- Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight);
- if (r.intersects(g.getClipBounds())) {
- g.drawImage(softCursor, x0, y0, null);
- }
- }
- if (isInSelectionMode()) {
- Rectangle r = getSelection(true);
- if (r.width > 0 && r.height > 0) {
- // Don't forget to correct the coordinates for the right and bottom
- // borders, so that the borders are the part of the selection.
- r.width -= 1;
- r.height -= 1;
- g.setXORMode(Color.yellow);
- g.drawRect(r.x, r.y, r.width, r.height);
- }
- }
- }
-
- public void paintScaledFrameBuffer(Graphics g) {
- g.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null);
- }
-
- //
- // Start/stop receiving mouse events. Keyboard events are received
- // even in view-only mode, because we want to map the 'r' key to the
- // screen refreshing function.
- //
-
- public synchronized void enableInput(boolean enable) {
- if (enable && !inputEnabled) {
- inputEnabled = true;
- if (viewer.showControls) {
- viewer.buttonPanel.enableRemoteAccessControls(true);
- }
- createSoftCursor(); // scaled cursor
- } else if (!enable && inputEnabled) {
- inputEnabled = false;
- if (viewer.showControls) {
- viewer.buttonPanel.enableRemoteAccessControls(false);
- }
- createSoftCursor(); // non-scaled cursor
- }
- }
-
- public void setPixelFormat() throws IOException {
- if (viewer.options.eightBitColors) {
- rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6);
- bytesPixel = 1;
- } else {
- rfb.writeSetPixelFormat(32, 24, false, true, 255, 255, 255, 16, 8, 0);
- bytesPixel = 4;
- }
- updateFramebufferSize();
- }
-
- void setScalingFactor(int sf) {
- scalingFactor = sf;
- updateFramebufferSize();
- invalidate();
- }
-
- void updateFramebufferSize() {
-
- // Useful shortcuts.
- int fbWidth = rfb.framebufferWidth;
- int fbHeight = rfb.framebufferHeight;
-
- // FIXME: This part of code must be in VncViewer i think
- if (viewer.options.autoScale) {
- if (viewer.inAnApplet) {
- maxWidth = viewer.getWidth();
- maxHeight = viewer.getHeight();
- } else {
- if (viewer.vncFrame != null) {
- if (isFirstSizeAutoUpdate) {
- isFirstSizeAutoUpdate = false;
- Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
- maxWidth = (int)screenSize.getWidth() - 100;
- maxHeight = (int)screenSize.getHeight() - 100;
- viewer.vncFrame.setSize(maxWidth, maxHeight);
- } else {
- viewer.desktopScrollPane.doLayout();
- maxWidth = viewer.desktopScrollPane.getWidth();
- maxHeight = viewer.desktopScrollPane.getHeight();
- }
- } else {
- maxWidth = fbWidth;
- maxHeight = fbHeight;
- }
- }
- int f1 = maxWidth * 100 / fbWidth;
- int f2 = maxHeight * 100 / fbHeight;
- scalingFactor = Math.min(f1, f2);
- if (scalingFactor > 100)
- scalingFactor = 100;
- System.out.println("Scaling desktop at " + scalingFactor + "%");
- }
-
- // Update scaled framebuffer geometry.
- scaledWidth = (fbWidth * scalingFactor + 50) / 100;
- scaledHeight = (fbHeight * scalingFactor + 50) / 100;
-
- // Create new off-screen image either if it does not exist, or if
- // its geometry should be changed. It's not necessary to replace
- // existing image if only pixel format should be changed.
- if (memImage == null) {
- memImage = viewer.vncContainer.createImage(fbWidth, fbHeight);
- memGraphics = memImage.getGraphics();
- } else if (memImage.getWidth(null) != fbWidth ||
- memImage.getHeight(null) != fbHeight) {
- synchronized(memImage) {
- memImage = viewer.vncContainer.createImage(fbWidth, fbHeight);
- memGraphics = memImage.getGraphics();
- }
- }
-
- //
- // Update decoders
- //
-
- //
- // FIXME: Why decoders can be null here?
- //
-
- if (decoders != null) {
- for (int i = 0; i < decoders.length; i++) {
- //
- // Set changes to every decoder that we can use
- //
-
- decoders[i].setBPP(bytesPixel);
- decoders[i].setFrameBufferSize(fbWidth, fbHeight);
- decoders[i].setGraphics(memGraphics);
-
- //
- // Update decoder
- //
-
- decoders[i].update();
- }
- }
-
- // FIXME: This part of code must be in VncViewer i think
- // Update the size of desktop containers.
- if (viewer.inSeparateFrame) {
- if (viewer.desktopScrollPane != null) {
- if (!viewer.options.autoScale) {
- resizeDesktopFrame();
- } else {
- setSize(scaledWidth, scaledHeight);
- viewer.desktopScrollPane.setSize(maxWidth + 200,
- maxHeight + 200);
- }
- }
- } else {
- setSize(scaledWidth, scaledHeight);
- }
- viewer.moveFocusToDesktop();
- }
-
- void resizeDesktopFrame() {
- setSize(scaledWidth, scaledHeight);
-
- // FIXME: Find a better way to determine correct size of a
- // ScrollPane. -- const
- Insets insets = viewer.desktopScrollPane.getInsets();
- viewer.desktopScrollPane.setSize(scaledWidth +
- 2 * Math.min(insets.left, insets.right),
- scaledHeight +
- 2 * Math.min(insets.top, insets.bottom));
-
- viewer.vncFrame.pack();
-
- // Try to limit the frame size to the screen size.
-
- Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
- Dimension frameSize = viewer.vncFrame.getSize();
- Dimension newSize = frameSize;
-
- // Reduce Screen Size by 30 pixels in each direction;
- // This is a (poor) attempt to account for
- // 1) Menu bar on Macintosh (should really also account for
- // Dock on OSX). Usually 22px on top of screen.
- // 2) Taxkbar on Windows (usually about 28 px on bottom)
- // 3) Other obstructions.
-
- screenSize.height -= 30;
- screenSize.width -= 30;
-
- boolean needToResizeFrame = false;
- if (frameSize.height > screenSize.height) {
- newSize.height = screenSize.height;
- needToResizeFrame = true;
- }
- if (frameSize.width > screenSize.width) {
- newSize.width = screenSize.width;
- needToResizeFrame = true;
- }
- if (needToResizeFrame) {
- viewer.vncFrame.setSize(newSize);
- }
-
- viewer.desktopScrollPane.doLayout();
- }
-
- //
- // processNormalProtocol() - executed by the rfbThread to deal with the
- // RFB socket.
- //
-
- public void processNormalProtocol() throws Exception {
-
- // Start/stop session recording if necessary.
- viewer.checkRecordingStatus();
-
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, false);
-
- if (viewer.options.continuousUpdates) {
- rfb.tryEnableContinuousUpdates(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight);
- }
-
- resetStats();
- boolean statsRestarted = false;
-
- //
- // main dispatch loop
- //
-
- while (true) {
-
- // Read message type from the server.
- int msgType = rfb.readServerMessageType();
-
- // Process the message depending on its type.
- switch (msgType) {
- case RfbProto.FramebufferUpdate:
-
- if (statNumUpdates == viewer.debugStatsExcludeUpdates &&
- !statsRestarted) {
- resetStats();
- statsRestarted = true;
- } else if (statNumUpdates == viewer.debugStatsMeasureUpdates &&
- statsRestarted) {
- viewer.disconnect();
- }
-
- rfb.readFramebufferUpdate();
- statNumUpdates++;
-
- boolean cursorPosReceived = false;
-
- for (int i = 0; i < rfb.updateNRects; i++) {
-
- rfb.readFramebufferUpdateRectHdr();
- statNumTotalRects++;
- int rx = rfb.updateRectX, ry = rfb.updateRectY;
- int rw = rfb.updateRectW, rh = rfb.updateRectH;
-
- if (rfb.updateRectEncoding == rfb.EncodingLastRect)
- break;
-
- if (rfb.updateRectEncoding == rfb.EncodingNewFBSize) {
- rfb.setFramebufferSize(rw, rh);
- updateFramebufferSize();
- break;
- }
-
- if (rfb.updateRectEncoding == rfb.EncodingXCursor ||
- rfb.updateRectEncoding == rfb.EncodingRichCursor) {
- handleCursorShapeUpdate(rfb.updateRectEncoding, rx, ry, rw, rh);
- continue;
- }
-
- if (rfb.updateRectEncoding == rfb.EncodingPointerPos) {
- softCursorMove(rx, ry);
- cursorPosReceived = true;
- continue;
- }
-
- long numBytesReadBefore = rfb.getNumBytesRead();
-
- rfb.startTiming();
-
- switch (rfb.updateRectEncoding) {
- case RfbProto.EncodingRaw:
- statNumRectsRaw++;
- handleRawRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingCopyRect:
- statNumRectsCopy++;
- handleCopyRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingRRE:
- handleRRERect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingCoRRE:
- handleCoRRERect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingHextile:
- statNumRectsHextile++;
- handleHextileRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingZRLE:
- statNumRectsZRLE++;
- handleZRLERect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingZlib:
- handleZlibRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingTight:
- if (tightDecoder != null) {
- statNumRectsTightJPEG = tightDecoder.getNumJPEGRects();
- //statNumRectsTight = tightDecoder.getNumTightRects();
- }
- statNumRectsTight++;
- handleTightRect(rx, ry, rw, rh);
- break;
- default:
- throw new Exception("Unknown RFB rectangle encoding " +
- rfb.updateRectEncoding);
- }
-
- rfb.stopTiming();
-
- statNumPixelRects++;
- statNumBytesDecoded += rw * rh * bytesPixel;
- statNumBytesEncoded +=
- (int)(rfb.getNumBytesRead() - numBytesReadBefore);
- }
-
- boolean fullUpdateNeeded = false;
-
- // Start/stop session recording if necessary. Request full
- // update if a new session file was opened.
- if (viewer.checkRecordingStatus())
- fullUpdateNeeded = true;
-
- // Defer framebuffer update request if necessary. But wake up
- // immediately on keyboard or mouse event. Also, don't sleep
- // if there is some data to receive, or if the last update
- // included a PointerPos message.
- if (viewer.deferUpdateRequests > 0 &&
- rfb.available() == 0 && !cursorPosReceived) {
- synchronized(rfb) {
- try {
- rfb.wait(viewer.deferUpdateRequests);
- } catch (InterruptedException e) {
- }
- }
- }
-
- viewer.autoSelectEncodings();
-
- // Before requesting framebuffer update, check if the pixel
- // format should be changed.
- if (viewer.options.eightBitColors != (bytesPixel == 1)) {
- // Pixel format should be changed.
- if (!rfb.continuousUpdatesAreActive()) {
- // Continuous updates are not used. In this case, we just
- // set new pixel format and request full update.
- setPixelFormat();
- fullUpdateNeeded = true;
- } else {
- // Otherwise, disable continuous updates first. Pixel
- // format will be set later when we are sure that there
- // will be no unsolicited framebuffer updates.
- rfb.tryDisableContinuousUpdates();
- break; // skip the code below
- }
- }
-
- // Enable/disable continuous updates to reflect the GUI setting.
- boolean enable = viewer.options.continuousUpdates;
- if (enable != rfb.continuousUpdatesAreActive()) {
- if (enable) {
- rfb.tryEnableContinuousUpdates(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight);
- } else {
- rfb.tryDisableContinuousUpdates();
- }
- }
-
- // Finally, request framebuffer update if needed.
- if (fullUpdateNeeded) {
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, false);
- } else if (!rfb.continuousUpdatesAreActive()) {
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, true);
- }
-
- break;
-
- case RfbProto.SetColourMapEntries:
- throw new Exception("Can't handle SetColourMapEntries message");
-
- case RfbProto.Bell:
- Toolkit.getDefaultToolkit().beep();
- break;
-
- case RfbProto.ServerCutText:
- String s = rfb.readServerCutText();
- viewer.clipboard.setCutText(s);
- break;
-
- case RfbProto.EndOfContinuousUpdates:
- if (rfb.continuousUpdatesAreActive()) {
- rfb.endOfContinuousUpdates();
-
- // Change pixel format if such change was pending. Note that we
- // could not change pixel format while continuous updates were
- // in effect.
- boolean incremental = true;
- if (viewer.options.eightBitColors != (bytesPixel == 1)) {
- setPixelFormat();
- incremental = false;
- }
- // From this point, we ask for updates explicitly.
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight,
- incremental);
- }
- break;
-
- default:
- throw new Exception("Unknown RFB message type " + msgType);
- }
- }
- }
-
- //
- // Handle a raw rectangle. The second form with paint==false is used
- // by the Hextile decoder for raw-encoded tiles.
- //
-
- void handleRawRect(int x, int y, int w, int h) throws IOException, Exception {
- handleRawRect(x, y, w, h, true);
- }
-
- void handleRawRect(int x, int y, int w, int h, boolean paint)
- throws IOException , Exception{
- rawDecoder.handleRect(x, y, w, h);
- if (paint)
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a CopyRect rectangle.
- //
-
- void handleCopyRect(int x, int y, int w, int h) throws IOException {
- copyRectDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle an RRE-encoded rectangle.
- //
-
- void handleRRERect(int x, int y, int w, int h) throws IOException {
- rreDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a CoRRE-encoded rectangle.
- //
-
- void handleCoRRERect(int x, int y, int w, int h) throws IOException {
- correDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a Hextile-encoded rectangle.
- //
-
- void handleHextileRect(int x, int y, int w, int h) throws IOException,
- Exception {
- hextileDecoder.handleRect(x, y, w, h);
- }
-
- //
- // Handle a ZRLE-encoded rectangle.
- //
- // FIXME: Currently, session recording is not fully supported for ZRLE.
- //
-
- void handleZRLERect(int x, int y, int w, int h) throws Exception {
- zrleDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a Zlib-encoded rectangle.
- //
-
- void handleZlibRect(int x, int y, int w, int h) throws Exception {
- zlibDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a Tight-encoded rectangle.
- //
-
- void handleTightRect(int x, int y, int w, int h) throws Exception {
- tightDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Tell JVM to repaint specified desktop area.
- //
-
- public void scheduleRepaint(int x, int y, int w, int h) {
- // Request repaint, deferred if necessary.
- if (rfb.framebufferWidth == scaledWidth) {
- repaint(viewer.deferScreenUpdates, x, y, w, h);
- } else {
- int sx = x * scalingFactor / 100;
- int sy = y * scalingFactor / 100;
- int sw = ((x + w) * scalingFactor + 49) / 100 - sx + 1;
- int sh = ((y + h) * scalingFactor + 49) / 100 - sy + 1;
- repaint(viewer.deferScreenUpdates, sx, sy, sw, sh);
- }
- }
-
- //
- // Handle events.
- //
-
- public void keyPressed(KeyEvent evt) {
- processLocalKeyEvent(evt);
- }
- public void keyReleased(KeyEvent evt) {
- processLocalKeyEvent(evt);
- }
- public void keyTyped(KeyEvent evt) {
- evt.consume();
- }
-
- public void mousePressed(MouseEvent evt) {
- processLocalMouseEvent(evt, false);
- }
- public void mouseReleased(MouseEvent evt) {
- processLocalMouseEvent(evt, false);
- }
- public void mouseMoved(MouseEvent evt) {
- processLocalMouseEvent(evt, true);
- }
- public void mouseDragged(MouseEvent evt) {
- processLocalMouseEvent(evt, true);
- }
-
- private synchronized void trySendPointerEvent() {
- if ((needToSendMouseEvent) && (mouseEvent!=null)) {
- sendMouseEvent(mouseEvent, false);
- needToSendMouseEvent = false;
- lastMouseEventSendTime = System.currentTimeMillis();
- }
- }
-
- public void run() {
- while (true) {
- // Send mouse movement if we have it
- trySendPointerEvent();
- // Sleep for some time
- try {
- Thread.sleep(1000 / mouseMaxFreq);
- } catch (InterruptedException ex) {
- }
- }
- }
-
- //
- // Ignored events.
- //
-
- public void mouseClicked(MouseEvent evt) {}
- public void mouseEntered(MouseEvent evt) {}
- public void mouseExited(MouseEvent evt) {}
-
- //
- // Actual event processing.
- //
-
- private void processLocalKeyEvent(KeyEvent evt) {
- if (viewer.rfb != null && rfb.inNormalProtocol) {
- if (!inputEnabled) {
- if ((evt.getKeyChar() == 'r' || evt.getKeyChar() == 'R') &&
- evt.getID() == KeyEvent.KEY_PRESSED ) {
- // Request screen update.
- try {
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, false);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- } else {
- // Input enabled.
- synchronized(rfb) {
- try {
- rfb.writeKeyEvent(evt);
- } catch (Exception e) {
- e.printStackTrace();
- }
- rfb.notify();
- }
- }
- }
- // Don't ever pass keyboard events to AWT for default processing.
- // Otherwise, pressing Tab would switch focus to ButtonPanel etc.
- evt.consume();
- }
-
- private void processLocalMouseEvent(MouseEvent evt, boolean moved) {
- if (viewer.rfb != null && rfb.inNormalProtocol) {
- if (!inSelectionMode) {
- if (inputEnabled) {
- // If mouse not moved, but it's click event then
- // send it to server immideanlty.
- // Else, it's mouse movement - we can send it in
- // our thread later.
- if (!moved) {
- sendMouseEvent(evt, moved);
- } else {
- mouseEvent = evt;
- needToSendMouseEvent = true;
- }
- }
- } else {
- handleSelectionMouseEvent(evt);
- }
- }
- }
-
- private void sendMouseEvent(MouseEvent evt, boolean moved) {
- if (moved) {
- softCursorMove(evt.getX(), evt.getY());
- }
- if (rfb.framebufferWidth != scaledWidth) {
- int sx = (evt.getX() * 100 + scalingFactor/2) / scalingFactor;
- int sy = (evt.getY() * 100 + scalingFactor/2) / scalingFactor;
- evt.translatePoint(sx - evt.getX(), sy - evt.getY());
- }
- synchronized(rfb) {
- try {
- rfb.writePointerEvent(evt);
- } catch (Exception e) {
- e.printStackTrace();
- }
- rfb.notify();
- lastMouseEventSendTime = System.currentTimeMillis();
- }
- }
-
- //
- // Reset update statistics.
- //
-
- void resetStats() {
- statStartTime = System.currentTimeMillis();
- statNumUpdates = 0;
- statNumTotalRects = 0;
- statNumPixelRects = 0;
- statNumRectsTight = 0;
- statNumRectsTightJPEG = 0;
- statNumRectsZRLE = 0;
- statNumRectsHextile = 0;
- statNumRectsRaw = 0;
- statNumRectsCopy = 0;
- statNumBytesEncoded = 0;
- statNumBytesDecoded = 0;
- if (tightDecoder != null) {
- tightDecoder.setNumJPEGRects(0);
- tightDecoder.setNumTightRects(0);
- }
- }
-
- //////////////////////////////////////////////////////////////////
- //
- // Handle cursor shape updates (XCursor and RichCursor encodings).
- //
-
- boolean showSoftCursor = false;
-
- MemoryImageSource softCursorSource;
- Image softCursor;
- MouseEvent mouseEvent = null;
- boolean needToSendMouseEvent = false;
- int cursorX = 0, cursorY = 0;
- int cursorWidth, cursorHeight;
- int origCursorWidth, origCursorHeight;
- int hotX, hotY;
- int origHotX, origHotY;
-
- //
- // Handle cursor shape update (XCursor and RichCursor encodings).
- //
-
- synchronized void
- handleCursorShapeUpdate(int encodingType,
- int xhot, int yhot, int width, int height)
- throws IOException {
-
- softCursorFree();
-
- if (width * height == 0)
- return;
-
- // Ignore cursor shape data if requested by user.
- if (viewer.options.ignoreCursorUpdates) {
- int bytesPerRow = (width + 7) / 8;
- int bytesMaskData = bytesPerRow * height;
-
- if (encodingType == rfb.EncodingXCursor) {
- rfb.skipBytes(6 + bytesMaskData * 2);
- } else {
- // rfb.EncodingRichCursor
- rfb.skipBytes(width * height + bytesMaskData);
- }
- return;
- }
-
- // Decode cursor pixel data.
- softCursorSource = decodeCursorShape(encodingType, width, height);
-
- // Set original (non-scaled) cursor dimensions.
- origCursorWidth = width;
- origCursorHeight = height;
- origHotX = xhot;
- origHotY = yhot;
-
- // Create off-screen cursor image.
- createSoftCursor();
-
- // Show the cursor.
- showSoftCursor = true;
- repaint(viewer.deferCursorUpdates,
- cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
- }
-
- //
- // decodeCursorShape(). Decode cursor pixel data and return
- // corresponding MemoryImageSource instance.
- //
-
- synchronized MemoryImageSource
- decodeCursorShape(int encodingType, int width, int height)
- throws IOException {
-
- int bytesPerRow = (width + 7) / 8;
- int bytesMaskData = bytesPerRow * height;
-
- int[] softCursorPixels = new int[width * height];
-
- if (encodingType == rfb.EncodingXCursor) {
-
- // Read foreground and background colors of the cursor.
- byte[] rgb = new byte[6];
- rfb.readFully(rgb);
- int[] colors = { (0xFF000000 | (rgb[3] & 0xFF) << 16 |
- (rgb[4] & 0xFF) << 8 | (rgb[5] & 0xFF)),
- (0xFF000000 | (rgb[0] & 0xFF) << 16 |
- (rgb[1] & 0xFF) << 8 | (rgb[2] & 0xFF)) };
-
- // Read pixel and mask data.
- byte[] pixBuf = new byte[bytesMaskData];
- rfb.readFully(pixBuf);
- byte[] maskBuf = new byte[bytesMaskData];
- rfb.readFully(maskBuf);
-
- // Decode pixel data into softCursorPixels[].
- byte pixByte, maskByte;
- int x, y, n, result;
- int i = 0;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width / 8; x++) {
- pixByte = pixBuf[y * bytesPerRow + x];
- maskByte = maskBuf[y * bytesPerRow + x];
- for (n = 7; n >= 0; n--) {
- if ((maskByte >> n & 1) != 0) {
- result = colors[pixByte >> n & 1];
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
- for (n = 7; n >= 8 - width % 8; n--) {
- if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
- result = colors[pixBuf[y * bytesPerRow + x] >> n & 1];
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
-
- } else {
- // encodingType == rfb.EncodingRichCursor
-
- // Read pixel and mask data.
- byte[] pixBuf = new byte[width * height * bytesPixel];
- rfb.readFully(pixBuf);
- byte[] maskBuf = new byte[bytesMaskData];
- rfb.readFully(maskBuf);
-
- // Decode pixel data into softCursorPixels[].
- byte pixByte, maskByte;
- int x, y, n, result;
- int i = 0;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width / 8; x++) {
- maskByte = maskBuf[y * bytesPerRow + x];
- for (n = 7; n >= 0; n--) {
- if ((maskByte >> n & 1) != 0) {
- if (bytesPixel == 1) {
- result = cm8.getRGB(pixBuf[i]);
- } else {
- result = 0xFF000000 |
- (pixBuf[i * 4 + 2] & 0xFF) << 16 |
- (pixBuf[i * 4 + 1] & 0xFF) << 8 |
- (pixBuf[i * 4] & 0xFF);
- }
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
- for (n = 7; n >= 8 - width % 8; n--) {
- if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
- if (bytesPixel == 1) {
- result = cm8.getRGB(pixBuf[i]);
- } else {
- result = 0xFF000000 |
- (pixBuf[i * 4 + 2] & 0xFF) << 16 |
- (pixBuf[i * 4 + 1] & 0xFF) << 8 |
- (pixBuf[i * 4] & 0xFF);
- }
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
-
- }
-
- return new MemoryImageSource(width, height, softCursorPixels, 0, width);
- }
-
- //
- // createSoftCursor(). Assign softCursor new Image (scaled if necessary).
- // Uses softCursorSource as a source for new cursor image.
- //
-
- synchronized void
- createSoftCursor() {
-
- if (softCursorSource == null)
- return;
-
- int scaleCursor = viewer.options.scaleCursor;
- if (scaleCursor == 0 || !inputEnabled)
- scaleCursor = 100;
-
- // Save original cursor coordinates.
- int x = cursorX - hotX;
- int y = cursorY - hotY;
- int w = cursorWidth;
- int h = cursorHeight;
-
- cursorWidth = (origCursorWidth * scaleCursor + 50) / 100;
- cursorHeight = (origCursorHeight * scaleCursor + 50) / 100;
- hotX = (origHotX * scaleCursor + 50) / 100;
- hotY = (origHotY * scaleCursor + 50) / 100;
- softCursor = Toolkit.getDefaultToolkit().createImage(softCursorSource);
-
- if (scaleCursor != 100) {
- softCursor = softCursor.getScaledInstance(cursorWidth, cursorHeight,
- Image.SCALE_SMOOTH);
- }
-
- if (showSoftCursor) {
- // Compute screen area to update.
- x = Math.min(x, cursorX - hotX);
- y = Math.min(y, cursorY - hotY);
- w = Math.max(w, cursorWidth);
- h = Math.max(h, cursorHeight);
-
- repaint(viewer.deferCursorUpdates, x, y, w, h);
- }
- }
-
- //
- // softCursorMove(). Moves soft cursor into a particular location.
- //
-
- synchronized void softCursorMove(int x, int y) {
- int oldX = cursorX;
- int oldY = cursorY;
- cursorX = x;
- cursorY = y;
- if (showSoftCursor) {
- repaint(viewer.deferCursorUpdates,
- oldX - hotX, oldY - hotY, cursorWidth, cursorHeight);
- repaint(viewer.deferCursorUpdates,
- cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
- }
- }
-
- //
- // softCursorFree(). Remove soft cursor, dispose resources.
- //
-
- synchronized void softCursorFree() {
- if (showSoftCursor) {
- showSoftCursor = false;
- softCursor = null;
- softCursorSource = null;
-
- repaint(viewer.deferCursorUpdates,
- cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
- }
- }
-
- //////////////////////////////////////////////////////////////////
- //
- // Support for selecting a rectangular video area.
- //
-
- /** This flag is false in normal operation, and true in the selection mode. */
- private boolean inSelectionMode;
-
- /** The point where the selection was started. */
- private Point selectionStart;
-
- /** The second point of the selection. */
- private Point selectionEnd;
-
- /**
- * We change cursor when enabling the selection mode. In this variable, we
- * save the original cursor so we can restore it on returning to the normal
- * mode.
- */
- private Cursor savedCursor;
-
- /**
- * Initialize selection-related varibles.
- */
- private synchronized void resetSelection() {
- inSelectionMode = false;
- selectionStart = new Point(0, 0);
- selectionEnd = new Point(0, 0);
-
- savedCursor = getCursor();
- }
-
- /**
- * Check current state of the selection mode.
- * @return true in the selection mode, false otherwise.
- */
- public boolean isInSelectionMode() {
- return inSelectionMode;
- }
-
- /**
- * Get current selection.
- * @param useScreenCoords use screen coordinates if true, or framebuffer
- * coordinates if false. This makes difference when scaling factor is not 100.
- * @return The selection as a {@link Rectangle}.
- */
- private synchronized Rectangle getSelection(boolean useScreenCoords) {
- int x0 = selectionStart.x;
- int x1 = selectionEnd.x;
- int y0 = selectionStart.y;
- int y1 = selectionEnd.y;
- // Make x and y point to the upper left corner of the selection.
- if (x1 < x0) {
- int t = x0; x0 = x1; x1 = t;
- }
- if (y1 < y0) {
- int t = y0; y0 = y1; y1 = t;
- }
- // Include the borders in the selection (unless it's empty).
- if (x0 != x1 && y0 != y1) {
- x1 += 1;
- y1 += 1;
- }
- // Translate from screen coordinates to framebuffer coordinates.
- if (rfb.framebufferWidth != scaledWidth) {
- x0 = (x0 * 100 + scalingFactor/2) / scalingFactor;
- y0 = (y0 * 100 + scalingFactor/2) / scalingFactor;
- x1 = (x1 * 100 + scalingFactor/2) / scalingFactor;
- y1 = (y1 * 100 + scalingFactor/2) / scalingFactor;
- }
- // Clip the selection to framebuffer.
- if (x0 < 0)
- x0 = 0;
- if (y0 < 0)
- y0 = 0;
- if (x1 > rfb.framebufferWidth)
- x1 = rfb.framebufferWidth;
- if (y1 > rfb.framebufferHeight)
- y1 = rfb.framebufferHeight;
- // Make width a multiple of 16.
- int widthBlocks = (x1 - x0 + 8) / 16;
- if (selectionStart.x <= selectionEnd.x) {
- x1 = x0 + widthBlocks * 16;
- if (x1 > rfb.framebufferWidth) {
- x1 -= 16;
- }
- } else {
- x0 = x1 - widthBlocks * 16;
- if (x0 < 0) {
- x0 += 16;
- }
- }
- // Make height a multiple of 8.
- int heightBlocks = (y1 - y0 + 4) / 8;
- if (selectionStart.y <= selectionEnd.y) {
- y1 = y0 + heightBlocks * 8;
- if (y1 > rfb.framebufferHeight) {
- y1 -= 8;
- }
- } else {
- y0 = y1 - heightBlocks * 8;
- if (y0 < 0) {
- y0 += 8;
- }
- }
- // Translate the selection back to screen coordinates if requested.
- if (useScreenCoords && rfb.framebufferWidth != scaledWidth) {
- x0 = (x0 * scalingFactor + 50) / 100;
- y0 = (y0 * scalingFactor + 50) / 100;
- x1 = (x1 * scalingFactor + 50) / 100;
- y1 = (y1 * scalingFactor + 50) / 100;
- }
- // Construct and return the result.
- return new Rectangle(x0, y0, x1 - x0, y1 - y0);
- }
-
- /**
- * Enable or disable the selection mode.
- * @param enable enables the selection mode if true, disables if fasle.
- */
- public synchronized void enableSelection(boolean enable) {
- if (enable && !inSelectionMode) {
- // Enter the selection mode.
- inSelectionMode = true;
- savedCursor = getCursor();
- setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
- repaint();
- } else if (!enable && inSelectionMode) {
- // Leave the selection mode.
- inSelectionMode = false;
- setCursor(savedCursor);
- repaint();
- }
- }
-
- /**
- * Process mouse events in the selection mode.
- *
- * @param evt mouse event that was originally passed to
- * {@link MouseListener} or {@link MouseMotionListener}.
- */
- private synchronized void handleSelectionMouseEvent(MouseEvent evt) {
- int id = evt.getID();
- boolean button1 = (evt.getModifiers() & InputEvent.BUTTON1_MASK) != 0;
-
- if (id == MouseEvent.MOUSE_PRESSED && button1) {
- selectionStart = selectionEnd = evt.getPoint();
- repaint();
- }
- if (id == MouseEvent.MOUSE_DRAGGED && button1) {
- selectionEnd = evt.getPoint();
- repaint();
- }
- if (id == MouseEvent.MOUSE_RELEASED && button1) {
- try {
- rfb.trySendVideoSelection(getSelection(false));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-}
+++ /dev/null
-//
-// Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.awt.*;
-import java.io.*;
-
-//
-// VncCanvas2 is a special version of VncCanvas which may use Java 2 API.
-//
-
-class VncCanvas2 extends VncCanvas {
-
- public VncCanvas2(VncViewer v) throws IOException {
- super(v);
- disableFocusTraversalKeys();
- }
-
- public VncCanvas2(VncViewer v, int maxWidth_, int maxHeight_)
- throws IOException {
-
- super(v, maxWidth_, maxHeight_);
- disableFocusTraversalKeys();
- }
-
- public void paintScaledFrameBuffer(Graphics g) {
- Graphics2D g2d = (Graphics2D)g;
- g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
- RenderingHints.VALUE_RENDER_QUALITY);
- g2d.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null);
- }
-
- //
- // Try to disable focus traversal keys (JVMs 1.4 and higher).
- //
-
- private void disableFocusTraversalKeys() {
- try {
- Class[] argClasses = { Boolean.TYPE };
- java.lang.reflect.Method method =
- getClass().getMethod("setFocusTraversalKeysEnabled", argClasses);
- Object[] argObjects = { new Boolean(false) };
- method.invoke(this, argObjects);
- } catch (Exception e) {}
- }
-
-}
-
+++ /dev/null
-//
-// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// VncViewer.java - the VNC viewer applet. This class mainly just sets up the
-// user interface, leaving it to the VncCanvas to do the actual rendering of
-// a VNC desktop.
-//
-
-package com.tightvnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.io.*;
-import java.net.*;
-
-public class VncViewer extends java.applet.Applet
- implements java.lang.Runnable, WindowListener, ComponentListener {
-
- boolean inAnApplet = true;
- boolean inSeparateFrame = false;
-
- //
- // main() is called when run as a java program from the command line.
- // It simply runs the applet inside a newly-created frame.
- //
-
- public static void main(String[] argv) {
- VncViewer v = new VncViewer();
- v.mainArgs = argv;
- v.inAnApplet = false;
- v.inSeparateFrame = true;
-
- v.init();
- v.start();
- }
-
- String[] mainArgs;
-
- RfbProto rfb;
- Thread rfbThread;
-
- Frame vncFrame;
- Container vncContainer;
- ScrollPane desktopScrollPane;
- GridBagLayout gridbag;
- ButtonPanel buttonPanel;
- Label connStatusLabel;
- VncCanvas vc;
- OptionsFrame options;
- ClipboardFrame clipboard;
- RecordingFrame rec;
-
- // Control session recording.
- Object recordingSync;
- String sessionFileName;
- boolean recordingActive;
- boolean recordingStatusChanged;
- String cursorUpdatesDef;
- String eightBitColorsDef;
-
- // Variables read from parameter values.
- String socketFactory;
- String host;
- int port;
- String passwordParam;
- boolean showControls;
- boolean offerRelogin;
- boolean showOfflineDesktop;
- int deferScreenUpdates;
- int deferCursorUpdates;
- int deferUpdateRequests;
- int debugStatsExcludeUpdates;
- int debugStatsMeasureUpdates;
-
- // Reference to this applet for inter-applet communication.
- public static java.applet.Applet refApplet;
-
- //
- // init()
- //
-
- public void init() {
-
- readParameters();
-
- refApplet = this;
-
- if (inSeparateFrame) {
- vncFrame = new Frame("TigerVNC");
- if (!inAnApplet) {
- vncFrame.add("Center", this);
- }
- vncContainer = vncFrame;
- } else {
- vncContainer = this;
- }
-
- recordingSync = new Object();
-
- options = new OptionsFrame(this);
- clipboard = new ClipboardFrame(this);
- if (RecordingFrame.checkSecurity())
- rec = new RecordingFrame(this);
-
- sessionFileName = null;
- recordingActive = false;
- recordingStatusChanged = false;
- cursorUpdatesDef = null;
- eightBitColorsDef = null;
-
- if (inSeparateFrame) {
- vncFrame.addWindowListener(this);
- vncFrame.addComponentListener(this);
- }
-
- rfbThread = new Thread(this);
- rfbThread.start();
- }
-
- public void update(Graphics g) {
- }
-
- //
- // run() - executed by the rfbThread to deal with the RFB socket.
- //
-
- public void run() {
-
- gridbag = new GridBagLayout();
- vncContainer.setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.anchor = GridBagConstraints.NORTHWEST;
-
- if (showControls) {
- buttonPanel = new ButtonPanel(this);
- gridbag.setConstraints(buttonPanel, gbc);
- vncContainer.add(buttonPanel);
- }
-
- try {
- connectAndAuthenticate();
- doProtocolInitialisation();
-
- if (showControls &&
- rfb.clientMsgCaps.isEnabled(RfbProto.VideoRectangleSelection)) {
- buttonPanel.addSelectButton();
- }
-
- if (showControls &&
- rfb.clientMsgCaps.isEnabled(RfbProto.VideoFreeze)) {
- buttonPanel.addVideoFreezeButton();
- }
-
- // FIXME: Use auto-scaling not only in a separate frame.
- if (options.autoScale && inSeparateFrame) {
- Dimension screenSize;
- try {
- screenSize = vncContainer.getToolkit().getScreenSize();
- } catch (Exception e) {
- screenSize = new Dimension(0, 0);
- }
- createCanvas(screenSize.width - 32, screenSize.height - 32);
- } else {
- createCanvas(0, 0);
- }
-
- gbc.weightx = 1.0;
- gbc.weighty = 1.0;
-
- if (inSeparateFrame) {
-
- // Create a panel which itself is resizeable and can hold
- // non-resizeable VncCanvas component at the top left corner.
- Panel canvasPanel = new Panel();
- canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
- canvasPanel.add(vc);
-
- // Create a ScrollPane which will hold a panel with VncCanvas
- // inside.
- desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
- gbc.fill = GridBagConstraints.BOTH;
- gridbag.setConstraints(desktopScrollPane, gbc);
- desktopScrollPane.add(canvasPanel);
- // If auto scale is not enabled we don't need to set first frame
- // size to fullscreen
- if (!options.autoScale) {
- vc.isFirstSizeAutoUpdate = false;
- }
-
- // Finally, add our ScrollPane to the Frame window.
- vncFrame.add(desktopScrollPane);
- vncFrame.setTitle(rfb.desktopName);
- vncFrame.pack();
- vc.resizeDesktopFrame();
-
- } else {
- // Just add the VncCanvas component to the Applet.
- gridbag.setConstraints(vc, gbc);
- add(vc);
- validate();
- }
-
- if (showControls) {
- buttonPanel.enableButtons();
- }
-
- moveFocusToDesktop();
- processNormalProtocol();
-
- } catch (NoRouteToHostException e) {
- fatalError("Network error: no route to server: " + host, e);
- } catch (UnknownHostException e) {
- fatalError("Network error: server name unknown: " + host, e);
- } catch (ConnectException e) {
- fatalError("Network error: could not connect to server: " +
- host + ":" + port, e);
- } catch (EOFException e) {
- if (showOfflineDesktop) {
- e.printStackTrace();
- System.out.println("Network error: remote side closed connection");
- if (vc != null) {
- vc.enableInput(false);
- }
- if (inSeparateFrame) {
- vncFrame.setTitle(rfb.desktopName + " [disconnected]");
- }
- if (rfb != null && !rfb.closed())
- rfb.close();
- if (showControls && buttonPanel != null) {
- buttonPanel.disableButtonsOnDisconnect();
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
- }
- } else {
- fatalError("Network error: remote side closed connection", e);
- }
- } catch (IOException e) {
- String str = e.getMessage();
- if (str != null && str.length() != 0) {
- fatalError("Network Error: " + str, e);
- } else {
- fatalError(e.toString(), e);
- }
- } catch (Exception e) {
- String str = e.getMessage();
- if (str != null && str.length() != 0) {
- fatalError("Error: " + str, e);
- } else {
- fatalError(e.toString(), e);
- }
- }
-
- }
-
- //
- // Create a VncCanvas instance.
- //
-
- void createCanvas(int maxWidth, int maxHeight) throws IOException {
- // Determine if Java 2D API is available and use a special
- // version of VncCanvas if it is present.
- vc = null;
- try {
- // This throws ClassNotFoundException if there is no Java 2D API.
- Class cl = Class.forName("java.awt.Graphics2D");
- // If we could load Graphics2D class, then we can use VncCanvas2D.
- cl = Class.forName("com.tightvnc.vncviewer.VncCanvas2");
- Class[] argClasses = { this.getClass(), Integer.TYPE, Integer.TYPE };
- java.lang.reflect.Constructor cstr = cl.getConstructor(argClasses);
- Object[] argObjects =
- { this, new Integer(maxWidth), new Integer(maxHeight) };
- vc = (VncCanvas)cstr.newInstance(argObjects);
- } catch (Exception e) {
- System.out.println("Warning: Java 2D API is not available");
- }
-
- // If we failed to create VncCanvas2D, use old VncCanvas.
- if (vc == null)
- vc = new VncCanvas(this, maxWidth, maxHeight);
- }
-
-
- //
- // Process RFB socket messages.
- // If the rfbThread is being stopped, ignore any exceptions,
- // otherwise rethrow the exception so it can be handled.
- //
-
- void processNormalProtocol() throws Exception {
- try {
- vc.processNormalProtocol();
- } catch (Exception e) {
- if (rfbThread == null) {
- System.out.println("Ignoring RFB socket exceptions" +
- " because applet is stopping");
- } else {
- throw e;
- }
- }
- }
-
-
- //
- // Connect to the RFB server and authenticate the user.
- //
-
- void connectAndAuthenticate() throws Exception
- {
- showConnectionStatus("Initializing...");
- if (inSeparateFrame) {
- vncFrame.pack();
- vncFrame.show();
- } else {
- validate();
- }
-
- showConnectionStatus("Connecting to " + host + ", port " + port + "...");
-
- rfb = new RfbProto(host, port, this);
- showConnectionStatus("Connected to server");
-
- rfb.readVersionMsg();
- showConnectionStatus("RFB server supports protocol version " +
- rfb.serverMajor + "." + rfb.serverMinor);
-
- rfb.writeVersionMsg();
- showConnectionStatus("Using RFB protocol version " +
- rfb.clientMajor + "." + rfb.clientMinor);
-
- int secType = rfb.negotiateSecurity();
- int authType;
- if (secType == RfbProto.SecTypeTight) {
- showConnectionStatus("Enabling TightVNC protocol extensions");
- rfb.setupTunneling();
- authType = rfb.negotiateAuthenticationTight();
- } else {
- authType = secType;
- }
-
- switch (authType) {
- case RfbProto.AuthNone:
- showConnectionStatus("No authentication needed");
- rfb.authenticateNone();
- break;
- case RfbProto.AuthVNC:
- showConnectionStatus("Performing standard VNC authentication");
- if (passwordParam != null) {
- rfb.authenticateVNC(passwordParam);
- } else {
- String pw = askPassword();
- rfb.authenticateVNC(pw);
- }
- break;
- default:
- throw new Exception("Unknown authentication scheme " + authType);
- }
- }
-
-
- //
- // Show a message describing the connection status.
- // To hide the connection status label, use (msg == null).
- //
-
- void showConnectionStatus(String msg)
- {
- if (msg == null) {
- if (vncContainer.isAncestorOf(connStatusLabel)) {
- vncContainer.remove(connStatusLabel);
- }
- return;
- }
-
- System.out.println(msg);
-
- if (connStatusLabel == null) {
- connStatusLabel = new Label("Status: " + msg);
- connStatusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
- } else {
- connStatusLabel.setText("Status: " + msg);
- }
-
- if (!vncContainer.isAncestorOf(connStatusLabel)) {
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.anchor = GridBagConstraints.NORTHWEST;
- gbc.weightx = 1.0;
- gbc.weighty = 1.0;
- gbc.insets = new Insets(20, 30, 20, 30);
- gridbag.setConstraints(connStatusLabel, gbc);
- vncContainer.add(connStatusLabel);
- }
-
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
- }
-
-
- //
- // Show an authentication panel.
- //
-
- String askPassword() throws Exception
- {
- showConnectionStatus(null);
-
- AuthPanel authPanel = new AuthPanel(this);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.anchor = GridBagConstraints.NORTHWEST;
- gbc.weightx = 1.0;
- gbc.weighty = 1.0;
- gbc.ipadx = 100;
- gbc.ipady = 50;
- gridbag.setConstraints(authPanel, gbc);
- vncContainer.add(authPanel);
-
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
-
- authPanel.moveFocusToDefaultField();
- String pw = authPanel.getPassword();
- vncContainer.remove(authPanel);
-
- return pw;
- }
-
-
- //
- // Do the rest of the protocol initialisation.
- //
-
- void doProtocolInitialisation() throws IOException
- {
- rfb.writeClientInit();
- rfb.readServerInit();
-
- System.out.println("Desktop name is " + rfb.desktopName);
- System.out.println("Desktop size is " + rfb.framebufferWidth + " x " +
- rfb.framebufferHeight);
-
- setEncodings();
-
- showConnectionStatus(null);
- }
-
-
- //
- // Send current encoding list to the RFB server.
- //
-
- int[] encodingsSaved;
- int nEncodingsSaved;
-
- void setEncodings() { setEncodings(false); }
- void autoSelectEncodings() { setEncodings(true); }
-
- void setEncodings(boolean autoSelectOnly) {
- if (options == null || rfb == null || !rfb.inNormalProtocol)
- return;
-
- int preferredEncoding = options.preferredEncoding;
- if (preferredEncoding == -1) {
- long kbitsPerSecond = rfb.kbitsPerSecond();
- if (nEncodingsSaved < 1) {
- // Choose Tight or ZRLE encoding for the very first update.
- System.out.println("Using Tight/ZRLE encodings");
- preferredEncoding = RfbProto.EncodingTight;
- } else if (kbitsPerSecond > 2000 &&
- encodingsSaved[0] != RfbProto.EncodingHextile) {
- // Switch to Hextile if the connection speed is above 2Mbps.
- System.out.println("Throughput " + kbitsPerSecond +
- " kbit/s - changing to Hextile encoding");
- preferredEncoding = RfbProto.EncodingHextile;
- } else if (kbitsPerSecond < 1000 &&
- encodingsSaved[0] != RfbProto.EncodingTight) {
- // Switch to Tight/ZRLE if the connection speed is below 1Mbps.
- System.out.println("Throughput " + kbitsPerSecond +
- " kbit/s - changing to Tight/ZRLE encodings");
- preferredEncoding = RfbProto.EncodingTight;
- } else {
- // Don't change the encoder.
- if (autoSelectOnly)
- return;
- preferredEncoding = encodingsSaved[0];
- }
- } else {
- // Auto encoder selection is not enabled.
- if (autoSelectOnly)
- return;
- }
-
- int[] encodings = new int[20];
- int nEncodings = 0;
-
- encodings[nEncodings++] = preferredEncoding;
- if (options.useCopyRect) {
- encodings[nEncodings++] = RfbProto.EncodingCopyRect;
- }
-
- if (preferredEncoding != RfbProto.EncodingTight) {
- encodings[nEncodings++] = RfbProto.EncodingTight;
- }
- if (preferredEncoding != RfbProto.EncodingZRLE) {
- encodings[nEncodings++] = RfbProto.EncodingZRLE;
- }
- if (preferredEncoding != RfbProto.EncodingHextile) {
- encodings[nEncodings++] = RfbProto.EncodingHextile;
- }
- if (preferredEncoding != RfbProto.EncodingZlib) {
- encodings[nEncodings++] = RfbProto.EncodingZlib;
- }
- if (preferredEncoding != RfbProto.EncodingCoRRE) {
- encodings[nEncodings++] = RfbProto.EncodingCoRRE;
- }
- if (preferredEncoding != RfbProto.EncodingRRE) {
- encodings[nEncodings++] = RfbProto.EncodingRRE;
- }
-
- if (options.compressLevel >= 0 && options.compressLevel <= 9) {
- encodings[nEncodings++] =
- RfbProto.EncodingCompressLevel0 + options.compressLevel;
- }
- if (options.jpegQuality >= 0 && options.jpegQuality <= 9) {
- encodings[nEncodings++] =
- RfbProto.EncodingQualityLevel0 + options.jpegQuality;
- }
-
- if (options.requestCursorUpdates) {
- encodings[nEncodings++] = RfbProto.EncodingXCursor;
- encodings[nEncodings++] = RfbProto.EncodingRichCursor;
- if (!options.ignoreCursorUpdates)
- encodings[nEncodings++] = RfbProto.EncodingPointerPos;
- }
-
- encodings[nEncodings++] = RfbProto.EncodingLastRect;
- encodings[nEncodings++] = RfbProto.EncodingNewFBSize;
-
- boolean encodingsWereChanged = false;
- if (nEncodings != nEncodingsSaved) {
- encodingsWereChanged = true;
- } else {
- for (int i = 0; i < nEncodings; i++) {
- if (encodings[i] != encodingsSaved[i]) {
- encodingsWereChanged = true;
- break;
- }
- }
- }
-
- if (encodingsWereChanged) {
- try {
- rfb.writeSetEncodings(encodings, nEncodings);
- if (vc != null) {
- vc.softCursorFree();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- encodingsSaved = encodings;
- nEncodingsSaved = nEncodings;
- }
- }
-
-
- //
- // setCutText() - send the given cut text to the RFB server.
- //
-
- void setCutText(String text) {
- try {
- if (rfb != null && rfb.inNormalProtocol) {
- rfb.writeClientCutText(text);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-
- //
- // Order change in session recording status. To stop recording, pass
- // null in place of the fname argument.
- //
-
- void setRecordingStatus(String fname) {
- synchronized(recordingSync) {
- sessionFileName = fname;
- recordingStatusChanged = true;
- }
- }
-
- //
- // Start or stop session recording. Returns true if this method call
- // causes recording of a new session.
- //
-
- boolean checkRecordingStatus() throws IOException {
- synchronized(recordingSync) {
- if (recordingStatusChanged) {
- recordingStatusChanged = false;
- if (sessionFileName != null) {
- startRecording();
- return true;
- } else {
- stopRecording();
- }
- }
- }
- return false;
- }
-
- //
- // Start session recording.
- //
-
- protected void startRecording() throws IOException {
- synchronized(recordingSync) {
- if (!recordingActive) {
- // Save settings to restore them after recording the session.
- cursorUpdatesDef =
- options.choices[options.cursorUpdatesIndex].getSelectedItem();
- eightBitColorsDef =
- options.choices[options.eightBitColorsIndex].getSelectedItem();
- // Set options to values suitable for recording.
- options.choices[options.cursorUpdatesIndex].select("Disable");
- options.choices[options.cursorUpdatesIndex].setEnabled(false);
- options.setEncodings();
- options.choices[options.eightBitColorsIndex].select("No");
- options.choices[options.eightBitColorsIndex].setEnabled(false);
- options.setColorFormat();
- } else {
- rfb.closeSession();
- }
-
- System.out.println("Recording the session in " + sessionFileName);
- rfb.startSession(sessionFileName);
- recordingActive = true;
- }
- }
-
- //
- // Stop session recording.
- //
-
- protected void stopRecording() throws IOException {
- synchronized(recordingSync) {
- if (recordingActive) {
- // Restore options.
- options.choices[options.cursorUpdatesIndex].select(cursorUpdatesDef);
- options.choices[options.cursorUpdatesIndex].setEnabled(true);
- options.setEncodings();
- options.choices[options.eightBitColorsIndex].select(eightBitColorsDef);
- options.choices[options.eightBitColorsIndex].setEnabled(true);
- options.setColorFormat();
-
- rfb.closeSession();
- System.out.println("Session recording stopped.");
- }
- sessionFileName = null;
- recordingActive = false;
- }
- }
-
-
- //
- // readParameters() - read parameters from the html source or from the
- // command line. On the command line, the arguments are just a sequence of
- // param_name/param_value pairs where the names and values correspond to
- // those expected in the html applet tag source.
- //
-
- void readParameters() {
- host = readParameter("HOST", !inAnApplet);
- if (host == null) {
- host = getCodeBase().getHost();
- if (host.equals("")) {
- fatalError("HOST parameter not specified");
- }
- }
-
- port = readIntParameter("PORT", 5900);
-
- // Read "ENCPASSWORD" or "PASSWORD" parameter if specified.
- readPasswordParameters();
-
- String str;
- if (inAnApplet) {
- str = readParameter("Open New Window", false);
- if (str != null && str.equalsIgnoreCase("Yes"))
- inSeparateFrame = true;
- }
-
- // "Show Controls" set to "No" disables button panel.
- showControls = true;
- str = readParameter("Show Controls", false);
- if (str != null && str.equalsIgnoreCase("No"))
- showControls = false;
-
- // "Offer Relogin" set to "No" disables "Login again" and "Close
- // window" buttons under error messages in applet mode.
- offerRelogin = true;
- str = readParameter("Offer Relogin", false);
- if (str != null && str.equalsIgnoreCase("No"))
- offerRelogin = false;
-
- // Do we continue showing desktop on remote disconnect?
- showOfflineDesktop = false;
- str = readParameter("Show Offline Desktop", false);
- if (str != null && str.equalsIgnoreCase("Yes"))
- showOfflineDesktop = true;
-
- // Fine tuning options.
- deferScreenUpdates = readIntParameter("Defer screen updates", 20);
- deferCursorUpdates = readIntParameter("Defer cursor updates", 10);
- deferUpdateRequests = readIntParameter("Defer update requests", 0);
-
- // Debugging options.
- debugStatsExcludeUpdates = readIntParameter("DEBUG_XU", 0);
- debugStatsMeasureUpdates = readIntParameter("DEBUG_CU", 0);
-
- // SocketFactory.
- socketFactory = readParameter("SocketFactory", false);
- }
-
- //
- // Read password parameters. If an "ENCPASSWORD" parameter is set,
- // then decrypt the password into the passwordParam string. Otherwise,
- // try to read the "PASSWORD" parameter directly to passwordParam.
- //
-
- private void readPasswordParameters() {
- String encPasswordParam = readParameter("ENCPASSWORD", false);
- if (encPasswordParam == null) {
- passwordParam = readParameter("PASSWORD", false);
- } else {
- // ENCPASSWORD is hexascii-encoded. Decode.
- byte[] pw = {0, 0, 0, 0, 0, 0, 0, 0};
- int len = encPasswordParam.length() / 2;
- if (len > 8)
- len = 8;
- for (int i = 0; i < len; i++) {
- String hex = encPasswordParam.substring(i*2, i*2+2);
- Integer x = new Integer(Integer.parseInt(hex, 16));
- pw[i] = x.byteValue();
- }
- // Decrypt the password.
- byte[] key = {23, 82, 107, 6, 35, 78, 88, 7};
- DesCipher des = new DesCipher(key);
- des.decrypt(pw, 0, pw, 0);
- passwordParam = new String(pw);
- }
- }
-
- public String readParameter(String name, boolean required) {
- if (inAnApplet) {
- String s = getParameter(name);
- if ((s == null) && required) {
- fatalError(name + " parameter not specified");
- }
- return s;
- }
-
- for (int i = 0; i < mainArgs.length; i += 2) {
- if (mainArgs[i].equalsIgnoreCase(name)) {
- try {
- return mainArgs[i+1];
- } catch (Exception e) {
- if (required) {
- fatalError(name + " parameter not specified");
- }
- return null;
- }
- }
- }
- if (required) {
- fatalError(name + " parameter not specified");
- }
- return null;
- }
-
- int readIntParameter(String name, int defaultValue) {
- String str = readParameter(name, false);
- int result = defaultValue;
- if (str != null) {
- try {
- result = Integer.parseInt(str);
- } catch (NumberFormatException e) { }
- }
- return result;
- }
-
- //
- // moveFocusToDesktop() - move keyboard focus either to VncCanvas.
- //
-
- void moveFocusToDesktop() {
- if (vncContainer != null) {
- if (vc != null && vncContainer.isAncestorOf(vc))
- vc.requestFocus();
- }
- }
-
- //
- // disconnect() - close connection to server.
- //
-
- synchronized public void disconnect() {
- System.out.println("Disconnecting");
-
- if (vc != null) {
- double sec = (System.currentTimeMillis() - vc.statStartTime) / 1000.0;
- double rate = Math.round(vc.statNumUpdates / sec * 100) / 100.0;
- long nRealRects = vc.statNumPixelRects;
- long nPseudoRects = vc.statNumTotalRects - vc.statNumPixelRects;
- System.out.println("Updates received: " + vc.statNumUpdates + " (" +
- nRealRects + " rectangles + " + nPseudoRects +
- " pseudo), " + rate + " updates/sec");
- long numRectsOther = nRealRects - vc.statNumRectsTight
- - vc.statNumRectsZRLE - vc.statNumRectsHextile
- - vc.statNumRectsRaw - vc.statNumRectsCopy;
- System.out.println("Rectangles:" +
- " Tight=" + vc.statNumRectsTight +
- "(JPEG=" + vc.statNumRectsTightJPEG +
- ") ZRLE=" + vc.statNumRectsZRLE +
- " Hextile=" + vc.statNumRectsHextile +
- " Raw=" + vc.statNumRectsRaw +
- " CopyRect=" + vc.statNumRectsCopy +
- " other=" + numRectsOther);
-
- long raw = vc.statNumBytesDecoded;
- long compressed = vc.statNumBytesEncoded;
- if (compressed > 0) {
- double ratio = Math.round((double)raw / compressed * 1000) / 1000.0;
- System.out.println("Pixel data: " + vc.statNumBytesDecoded +
- " bytes, " + vc.statNumBytesEncoded +
- " compressed, ratio " + ratio);
- }
- }
-
- if (rfb != null && !rfb.closed())
- rfb.close();
- options.dispose();
- clipboard.dispose();
- if (rec != null)
- rec.dispose();
-
- if (inAnApplet) {
- showMessage("Disconnected");
- } else {
- System.exit(0);
- }
- }
-
- //
- // fatalError() - print out a fatal error message.
- // FIXME: Do we really need two versions of the fatalError() method?
- //
-
- synchronized public void fatalError(String str) {
- System.out.println(str);
-
- if (inAnApplet) {
- // vncContainer null, applet not inited,
- // can not present the error to the user.
- Thread.currentThread().stop();
- } else {
- System.exit(1);
- }
- }
-
- synchronized public void fatalError(String str, Exception e) {
-
- if (rfb != null && rfb.closed()) {
- // Not necessary to show error message if the error was caused
- // by I/O problems after the rfb.close() method call.
- System.out.println("RFB thread finished");
- return;
- }
-
- System.out.println(str);
- e.printStackTrace();
-
- if (rfb != null)
- rfb.close();
-
- if (inAnApplet) {
- showMessage(str);
- } else {
- System.exit(1);
- }
- }
-
- //
- // Show message text and optionally "Relogin" and "Close" buttons.
- //
-
- void showMessage(String msg) {
- vncContainer.removeAll();
-
- Label errLabel = new Label(msg, Label.CENTER);
- errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
-
- if (offerRelogin) {
-
- Panel gridPanel = new Panel(new GridLayout(0, 1));
- Panel outerPanel = new Panel(new FlowLayout(FlowLayout.LEFT));
- outerPanel.add(gridPanel);
- vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 16));
- vncContainer.add(outerPanel);
- Panel textPanel = new Panel(new FlowLayout(FlowLayout.CENTER));
- textPanel.add(errLabel);
- gridPanel.add(textPanel);
- gridPanel.add(new ReloginPanel(this));
-
- } else {
-
- vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
- vncContainer.add(errLabel);
-
- }
-
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
- }
-
- //
- // Stop the applet.
- // Main applet thread will terminate on first exception
- // after seeing that rfbThread has been set to null.
- //
-
- public void stop() {
- System.out.println("Stopping applet");
- rfbThread = null;
- }
-
- //
- // This method is called before the applet is destroyed.
- //
-
- public void destroy() {
- System.out.println("Destroying applet");
-
- vncContainer.removeAll();
- options.dispose();
- clipboard.dispose();
- if (rec != null)
- rec.dispose();
- if (rfb != null && !rfb.closed())
- rfb.close();
- if (inSeparateFrame)
- vncFrame.dispose();
- }
-
- //
- // Start/stop receiving mouse events.
- //
-
- public void enableInput(boolean enable) {
- vc.enableInput(enable);
- }
-
- //
- // Resize framebuffer if autoScale is enabled.
- //
-
- public void componentResized(ComponentEvent e) {
- if (e.getComponent() == vncFrame) {
- if (options.autoScale) {
- if (vc != null) {
- if (!vc.isFirstSizeAutoUpdate) {
- vc.updateFramebufferSize();
- }
- }
- }
- }
- }
-
- //
- // Ignore component events we're not interested in.
- //
-
- public void componentShown(ComponentEvent e) { }
- public void componentMoved(ComponentEvent e) { }
- public void componentHidden(ComponentEvent e) { }
-
- //
- // Close application properly on window close event.
- //
-
- public void windowClosing(WindowEvent evt) {
- System.out.println("Closing window");
- if (rfb != null)
- disconnect();
-
- vncContainer.hide();
-
- if (!inAnApplet) {
- System.exit(0);
- }
- }
-
- //
- // Ignore window events we're not interested in.
- //
-
- public void windowActivated(WindowEvent evt) {}
- public void windowDeactivated (WindowEvent evt) {}
- public void windowOpened(WindowEvent evt) {}
- public void windowClosed(WindowEvent evt) {}
- public void windowIconified(WindowEvent evt) {}
- public void windowDeiconified(WindowEvent evt) {}
-}
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-//
-// A ZlibInStream reads from a zlib.io.InputStream
-//
-
-package com.tightvnc.vncviewer;
-
-public class ZlibInStream extends InStream {
-
- static final int defaultBufSize = 16384;
-
- public ZlibInStream(int bufSize_) {
- bufSize = bufSize_;
- b = new byte[bufSize];
- ptr = end = ptrOffset = 0;
- inflater = new java.util.zip.Inflater();
- }
-
- public ZlibInStream() { this(defaultBufSize); }
-
- public void setUnderlying(InStream is, int bytesIn_) {
- underlying = is;
- bytesIn = bytesIn_;
- ptr = end = 0;
- }
-
- public void reset() throws Exception {
- ptr = end = 0;
- if (underlying == null) return;
-
- while (bytesIn > 0) {
- decompress();
- end = 0; // throw away any data
- }
- underlying = null;
- }
-
- public int pos() { return ptrOffset + ptr; }
-
- protected int overrun(int itemSize, int nItems) throws Exception {
- if (itemSize > bufSize)
- throw new Exception("ZlibInStream overrun: max itemSize exceeded");
- if (underlying == null)
- throw new Exception("ZlibInStream overrun: no underlying stream");
-
- if (end - ptr != 0)
- System.arraycopy(b, ptr, b, 0, end - ptr);
-
- ptrOffset += ptr;
- end -= ptr;
- ptr = 0;
-
- while (end < itemSize) {
- decompress();
- }
-
- if (itemSize * nItems > end)
- nItems = end / itemSize;
-
- return nItems;
- }
-
- // decompress() calls the decompressor once. Note that this won't
- // necessarily generate any output data - it may just consume some input
- // data. Returns false if wait is false and we would block on the underlying
- // stream.
-
- private void decompress() throws Exception {
- try {
- underlying.check(1);
- int avail_in = underlying.getend() - underlying.getptr();
- if (avail_in > bytesIn)
- avail_in = bytesIn;
-
- if (inflater.needsInput()) {
- inflater.setInput(underlying.getbuf(), underlying.getptr(), avail_in);
- }
-
- int n = inflater.inflate(b, end, bufSize - end);
-
- end += n;
- if (inflater.needsInput()) {
- bytesIn -= avail_in;
- underlying.setptr(underlying.getptr() + avail_in);
- }
- } catch (java.util.zip.DataFormatException e) {
- throw new Exception("ZlibInStream: inflate failed");
- }
- }
-
- private InStream underlying;
- private int bufSize;
- private int ptrOffset;
- private java.util.zip.Inflater inflater;
- private int bytesIn;
-}
+++ /dev/null
-<!--
- index.html - an example HTML page for TigerVNC Java viewer applet, to be
- used with a standalone Web server running on the same machine where the
- TigerVNC server is running. Before using this example, please MAKE SURE
- to check the following:
-
- * the value of the PORT parameter should be set correctly (normally, the
- port number is 5900 + display number);
-
- * the CODE and ARCHIVE attributes of the <APPLET> tag should point to
- the correct directory (this example assumes that this page is in the
- same directory with .jar and .class files);
-
- * the WIDTH and HEIGHT attributes of the <APPLET> tag correspond to the
- actual desktop size on the server (height should be increased to leave
- enough space for the button panel).
--->
-
-<HTML>
-<TITLE>
-TigerVNC desktop
-</TITLE>
-<APPLET CODE="VncViewer.class" ARCHIVE="VncViewer.jar"
- WIDTH="800" HEIGHT="632">
-<PARAM NAME="PORT" VALUE="5901">
-</APPLET>
-<BR>
-<A href="http://www.tigervnc.org/">TigerVNC site</A>
-</HTML>
+++ /dev/null
-<!--
- index.vnc - default HTML page for TigerVNC Java viewer applet, to be
- used with Xvnc. On any file ending in .vnc, the HTTP server embedded in
- Xvnc will substitute the following variables when preceded by a dollar:
- USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT,
- PARAMS. Use two dollar signs ($$) to get a dollar sign in the generated
- HTML page.
-
- NOTE: the $PARAMS variable is not supported by the standard VNC, so
- make sure you have TigerVNC on the server side, if you're using this
- variable.
--->
-
-<HTML>
-<TITLE>
-$USER's $DESKTOP desktop ($DISPLAY)
-</TITLE>
-<APPLET CODE=VncViewer.class ARCHIVE=VncViewer.jar
- WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT>
-<param name=PORT value=$PORT>
-$PARAMS
-</APPLET>
-<BR>
-<A href="http://www.tigervnc.org/">TigerVNC site</A>
-</HTML>