diff --git a/guacamole/client/src/net/sourceforge/guacamole/Client.java b/guacamole/client/src/net/sourceforge/guacamole/Client.java index 5be1b9704..93000aaf4 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/Client.java +++ b/guacamole/client/src/net/sourceforge/guacamole/Client.java @@ -19,17 +19,14 @@ package net.sourceforge.guacamole; * along with this program. If not, see . */ -import net.sourceforge.guacamole.instruction.Instruction; import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.event.KeyEvent; import net.sourceforge.guacamole.event.PointerEvent; public abstract class Client { - public abstract void send(KeyEvent event) throws GuacamoleException; - public abstract void send(PointerEvent event) throws GuacamoleException; - public abstract void setClipboard(String clipboard) throws GuacamoleException; + public abstract void write(char[] chunk, int off, int len) throws GuacamoleException; + public abstract char[] read() throws GuacamoleException; public abstract void disconnect() throws GuacamoleException; - public abstract Instruction nextInstruction(boolean blocking) throws GuacamoleException; } diff --git a/guacamole/client/src/net/sourceforge/guacamole/GuacamoleClient.java b/guacamole/client/src/net/sourceforge/guacamole/GuacamoleClient.java index a2cbc40b3..f79e8a1b4 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/GuacamoleClient.java +++ b/guacamole/client/src/net/sourceforge/guacamole/GuacamoleClient.java @@ -31,7 +31,6 @@ import java.io.OutputStream; import java.io.Writer; import java.io.OutputStreamWriter; -import net.sourceforge.guacamole.instruction.Instruction; import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.event.EventQueue; import net.sourceforge.guacamole.event.EventHandler; @@ -57,64 +56,9 @@ public class GuacamoleClient extends Client { } - - private static final int EVENT_DEADLINE = 500; - - private EventQueue keyEvents = new EventQueue(new EventHandler() { - - public void handle(KeyEvent event) throws IOException { - int pressed = 0; - if (event.getPressed()) pressed = 1; - - output.write("key:" + event.getKeySym() + "," + pressed + ";"); - output.flush(); - } - - }, EVENT_DEADLINE); - - private EventQueue pointerEvents = new EventQueue(new EventHandler() { - - public void handle(PointerEvent event) throws IOException { - int mask = 0; - if (event.isLeftButtonPressed()) mask |= 1; - if (event.isMiddleButtonPressed()) mask |= 2; - if (event.isRightButtonPressed()) mask |= 4; - if (event.isUpButtonPressed()) mask |= 8; - if (event.isDownButtonPressed()) mask |= 16; - - - output.write("mouse:" + event.getX() + "," + event.getY() + "," + mask + ";"); - output.flush(); - } - - }, EVENT_DEADLINE); - - - public void send(KeyEvent event) throws GuacamoleException { - + public void write(char[] chunk, int off, int len) throws GuacamoleException { try { - keyEvents.add(event); - } - catch (IOException e) { - throw new GuacamoleException(e); - } - - } - - public void send(PointerEvent event) throws GuacamoleException { - - try { - pointerEvents.add(event); - } - catch (IOException e) { - throw new GuacamoleException(e); - } - - } - - public void setClipboard(String clipboard) throws GuacamoleException { - try { - output.write("clipboard:" + Instruction.escape(clipboard) + ";"); + output.write(chunk, off, len); output.flush(); } catch (IOException e) { @@ -134,7 +78,7 @@ public class GuacamoleClient extends Client { private int usedLength = 0; private char[] buffer = new char[20000]; - public Instruction nextInstruction(boolean blocking) throws GuacamoleException { + public char[] read() throws GuacamoleException { try { @@ -164,20 +108,15 @@ public class GuacamoleClient extends Client { if (readChar == ';') { // Get instruction - final String instruction = new String(buffer, 0, i+1); + char[] chunk = new char[i+1]; + System.arraycopy(buffer, 0, chunk, 0, i+1); // Reset buffer usedLength -= i+1; System.arraycopy(buffer, i+1, buffer, 0, usedLength); - // Return instruction string wrapped in Instruction class - return new Instruction() { - - public String toString() { - return instruction; - } - - }; + // Return instruction string + return chunk; } } diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/ClipboardInstruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/ClipboardInstruction.java deleted file mode 100644 index 5eb29737b..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/ClipboardInstruction.java +++ /dev/null @@ -1,39 +0,0 @@ - -package net.sourceforge.guacamole.instruction; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -public class ClipboardInstruction extends Instruction { - - private String data; - - public ClipboardInstruction(String data) { - this.data = data; - } - - public String getData() { - return data; - } - - @Override - public String toString() { - return "clipboard:" + escape(getData()) + ";"; - } - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/ErrorInstruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/ErrorInstruction.java deleted file mode 100644 index acc550777..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/ErrorInstruction.java +++ /dev/null @@ -1,39 +0,0 @@ - -package net.sourceforge.guacamole.instruction; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -public class ErrorInstruction extends Instruction { - - private String error; - - public ErrorInstruction(String error) { - this.error = error; - } - - public String getError() { - return error; - } - - @Override - public String toString() { - return "error:" + escape(getError()) + ";"; - } - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/Instruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/Instruction.java deleted file mode 100644 index 81e506e60..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/Instruction.java +++ /dev/null @@ -1,63 +0,0 @@ - -package net.sourceforge.guacamole.instruction; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -public abstract class Instruction { - - - // All Instructions must provide a toString() implementation - // which returns the properly formatted instruction: - // OPCODE:parm1,parm2,...,parmN; - - @Override - public abstract String toString(); - - public static String escape(String str) { - - StringBuffer sb = new StringBuffer(); - - for (int i=0; i. - */ - -public class NameInstruction extends Instruction { - - private String name; - - public NameInstruction(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - @Override - public String toString() { - return "name:" + escape(getName()) + ";"; - } - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/SizeInstruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/SizeInstruction.java deleted file mode 100644 index e21364469..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/SizeInstruction.java +++ /dev/null @@ -1,47 +0,0 @@ - -package net.sourceforge.guacamole.instruction; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -public class SizeInstruction extends Instruction { - - private int width; - private int height; - - public SizeInstruction(int width, int height) { - this.width = width; - this.height = height; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - @Override - public String toString() { - return "size:" - + getWidth() + "," - + getHeight() + ";"; - } - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/CopyRectInstruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/CopyRectInstruction.java deleted file mode 100644 index 1b23f7777..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/CopyRectInstruction.java +++ /dev/null @@ -1,78 +0,0 @@ - -package net.sourceforge.guacamole.instruction.framebuffer; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import net.sourceforge.guacamole.instruction.Instruction; - -public class CopyRectInstruction extends Instruction { - - private final int x; - private final int y; - private final int width; - private final int height; - - private final int srcX; - private final int srcY; - - public CopyRectInstruction(int x, int y, int width, int height, int srcX, int srcY) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.srcX = srcX; - this.srcY = srcY; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public int getSrcX() { - return srcX; - } - - public int getSrcY() { - return srcY; - } - - @Override - public String toString() { - return "copy:" - + getSrcX() + "," - + getSrcY() + "," - + getWidth() + "," - + getHeight() + "," - + getX() + "," - + getY() + ";"; - } - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/CursorInstruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/CursorInstruction.java deleted file mode 100644 index b5cbe656f..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/CursorInstruction.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.sourceforge.guacamole.instruction.framebuffer; - -import net.sourceforge.guacamole.net.Base64; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import net.sourceforge.guacamole.instruction.Instruction; - -public class CursorInstruction extends Instruction { - - private int x; - private int y; - private PNGImage image; - - public CursorInstruction(int x, int y, PNGImage image) { - this.x = x; - this.y = y; - this.image = image; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public PNGImage getImage() { - return image; - } - - public int getWidth() { - return getImage().getWidth(); - } - - public int getHeight() { - return getImage().getHeight(); - } - - @Override - public String toString() { - return "cursor:" - + getX() + "," - + getY() + "," - + Base64.toString(getImage().getData()) + ";"; - } - - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/DrawRectInstruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/DrawRectInstruction.java deleted file mode 100644 index 544aed334..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/DrawRectInstruction.java +++ /dev/null @@ -1,72 +0,0 @@ - -package net.sourceforge.guacamole.instruction.framebuffer; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import net.sourceforge.guacamole.instruction.Instruction; - -public class DrawRectInstruction extends Instruction { - - private final int x; - private final int y; - private final int width; - private final int height; - private final int color; - - public DrawRectInstruction(int x, int y, int width, int height, int color) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.color = color; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public int getColor() { - return color; - } - - @Override - public String toString() { - - return "rect:" - + getX() + "," - + getY() + "," - + getWidth() + "," - + getHeight() + "," - + String.format("#%06X", getColor()) + ";"; - - } - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/PNGImage.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/PNGImage.java deleted file mode 100644 index 79489dfd3..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/PNGImage.java +++ /dev/null @@ -1,95 +0,0 @@ -package net.sourceforge.guacamole.instruction.framebuffer; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; -import javax.imageio.IIOImage; -import javax.imageio.ImageIO; -import javax.imageio.ImageWriter; -import javax.imageio.stream.ImageOutputStream; -import net.sourceforge.guacamole.GuacamoleException; - -public class PNGImage { - - private int width; - private int height; - private byte[] data; - - public PNGImage(BufferedImage image) throws GuacamoleException { - - width = image.getWidth(); - height = image.getHeight(); - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - try { - writeImage(image, bos); - bos.flush(); - } - catch (IOException e) { - throw new GuacamoleException("I/O Error while creating PNG.", e); - } - - data = bos.toByteArray(); - } - - public byte[] getData() { - return data; - } - - public int getHeight() { - return height; - } - - public int getWidth() { - return width; - } - - private static void writeImage(BufferedImage image, OutputStream outputStream) throws GuacamoleException, IOException { - - // Obtain list of image writers - // If no such writers exist, fail with error, exit. - Iterator writers = ImageIO.getImageWritersByMIMEType("image/png"); - if (!writers.hasNext()) - throw new GuacamoleException("No useful image writers found."); - - // Obtain JPEG writer - ImageWriter imageWriter = writers.next(); - - // Setup image parameters (including compression quality) - /*ImageWriteParam imageParameters = new JPEGImageWriteParam(Locale.ENGLISH); - imageParameters.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); - imageParameters.setCompressionQuality(0.6f); // 60% quality, currently... - imageParameters.setProgressiveMode(ImageWriteParam.MODE_DEFAULT);*/ - - ImageOutputStream out = ImageIO.createImageOutputStream(outputStream); - - // Write image - imageWriter.setOutput(out); - imageWriter.write(null, new IIOImage(image, null, null), null/*imageParameters*/); - imageWriter.dispose(); - - out.flush(); - } - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/PNGInstruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/PNGInstruction.java deleted file mode 100644 index 4d5e26962..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/framebuffer/PNGInstruction.java +++ /dev/null @@ -1,65 +0,0 @@ -package net.sourceforge.guacamole.instruction.framebuffer; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import net.sourceforge.guacamole.instruction.Instruction; -import net.sourceforge.guacamole.net.Base64; - -public class PNGInstruction extends Instruction { - - private int x; - private int y; - private PNGImage image; - - public PNGInstruction(int x, int y, PNGImage image) { - this.x = x; - this.y = y; - this.image = image; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public PNGImage getImage() { - return image; - } - - public int getWidth() { - return getImage().getWidth(); - } - - public int getHeight() { - return getImage().getHeight(); - } - - @Override - public String toString() { - return "png:" - + getX() + "," - + getY() + "," - + Base64.toString(getImage().getData()) + ";"; - } - - -} diff --git a/guacamole/client/src/net/sourceforge/guacamole/net/GuacamoleSession.java b/guacamole/client/src/net/sourceforge/guacamole/net/GuacamoleSession.java index a76060590..52a7d0ac6 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/net/GuacamoleSession.java +++ b/guacamole/client/src/net/sourceforge/guacamole/net/GuacamoleSession.java @@ -27,7 +27,6 @@ import javax.servlet.http.HttpSessionBindingListener; import net.sourceforge.guacamole.Client; import net.sourceforge.guacamole.GuacamoleClient; import net.sourceforge.guacamole.GuacamoleException; -import net.sourceforge.guacamole.instruction.Instruction; import net.sourceforge.guacamole.event.KeyEvent; import net.sourceforge.guacamole.event.PointerEvent; @@ -59,26 +58,18 @@ public class GuacamoleSession { } } - public void send(KeyEvent event) throws GuacamoleException { - client.send(event); + public void write(char[] data, int off, int len) throws GuacamoleException { + client.write(data, off, len); } - public void send(PointerEvent event) throws GuacamoleException { - client.send(event); - } - - public void setClipboard(String clipboard) throws GuacamoleException { - client.setClipboard(clipboard); + public char[] read() throws GuacamoleException { + return client.read(); } public void disconnect() throws GuacamoleException { client.disconnect(); } - public Instruction nextInstruction(boolean blocking) throws GuacamoleException { - return client.nextInstruction(blocking); - } - } public GuacamoleSession(HttpSession session) throws GuacamoleException { diff --git a/guacamole/client/src/net/sourceforge/guacamole/net/input/Clipboard.java b/guacamole/client/src/net/sourceforge/guacamole/net/input/Inbound.java similarity index 63% rename from guacamole/client/src/net/sourceforge/guacamole/net/input/Clipboard.java rename to guacamole/client/src/net/sourceforge/guacamole/net/input/Inbound.java index ec299061a..4d3429410 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/net/input/Clipboard.java +++ b/guacamole/client/src/net/sourceforge/guacamole/net/input/Inbound.java @@ -1,4 +1,3 @@ - package net.sourceforge.guacamole.net.input; /* @@ -23,46 +22,37 @@ import javax.servlet.ServletRequest; import net.sourceforge.guacamole.GuacamoleException; import org.w3c.dom.Element; +import java.io.Reader; +import java.io.IOException; + import net.sourceforge.guacamole.net.GuacamoleSession; import net.sourceforge.guacamole.net.XMLGuacamoleServlet; -import java.io.IOException; -import java.io.Reader; +public class Inbound extends XMLGuacamoleServlet { -/** - * Servlet which sets the clipboard data. - * - * This servlet takes one parameter: - * data: The data to set the clipboard to. - * - * @author Michael Jumper - */ - -public class Clipboard extends XMLGuacamoleServlet { @Override protected void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException { + // Send data try { - // Read data from request body - Reader reader = request.getReader(); - StringBuilder data = new StringBuilder(); + Reader input = request.getReader(); + char[] buffer = new char[8192]; - int codepoint; - while ((codepoint = reader.read()) != -1) - data.appendCodePoint(codepoint); + int length; + while ((length = input.read(buffer, 0, buffer.length)) != -1) + session.getClient().write(buffer, 0, length); - // Set clipboard - session.getClient().setClipboard(data.toString()); } catch (IOException e) { - throw new GuacamoleException("I/O error sending clipboard to server: " + e.getMessage(), e); + throw new GuacamoleException("I/O Error sending data to server: " + e.getMessage(), e); } catch (GuacamoleException e) { - throw new GuacamoleException("Error sending clipboard to server: " + e.getMessage(), e); + throw new GuacamoleException("Error sending data to server: " + e.getMessage(), e); } } + } diff --git a/guacamole/client/src/net/sourceforge/guacamole/net/input/Key.java b/guacamole/client/src/net/sourceforge/guacamole/net/input/Key.java deleted file mode 100644 index 9e5b80fdb..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/net/input/Key.java +++ /dev/null @@ -1,66 +0,0 @@ - -package net.sourceforge.guacamole.net.input; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import javax.servlet.ServletRequest; -import net.sourceforge.guacamole.GuacamoleException; -import org.w3c.dom.Element; -import net.sourceforge.guacamole.event.KeyEvent; - -import net.sourceforge.guacamole.net.GuacamoleSession; -import net.sourceforge.guacamole.net.XMLGuacamoleServlet; - -/** - * Servlet which accepts keyboard input events, forwards these events to the - * client associated with the session, and returns the result (if any) - * to the HTTP client via XML. - * - * This servlet takes three parameters: - * index: The event index. As HTTP requests may arrive out of order, - * this index provides the event queue with a means of sorting - * events, and determining if events are missing. The first - * event has index 0. - * pressed: Whether the key was pressed (1) or released (0). - * keysym: The integer representing the corresponding X11 keysym. - * - * @author Michael Jumper - */ - -public class Key extends XMLGuacamoleServlet { - - @Override - protected void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException { - - // Event parameters - int index = Integer.parseInt(request.getParameter("index")); - boolean pressed = request.getParameter("pressed").equals("1"); - int keysym = Integer.parseInt(request.getParameter("keysym")); - - // Send/queue event - try { - session.getClient().send(new KeyEvent(index, keysym, pressed)); - } - catch (GuacamoleException e) { - throw new GuacamoleException("Error sending key event to server: " + e.getMessage(), e); - } - - } -} - diff --git a/guacamole/client/src/net/sourceforge/guacamole/net/input/Pointer.java b/guacamole/client/src/net/sourceforge/guacamole/net/input/Pointer.java deleted file mode 100644 index 52ccaacb6..000000000 --- a/guacamole/client/src/net/sourceforge/guacamole/net/input/Pointer.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.sourceforge.guacamole.net.input; - -/* - * Guacamole - Clientless Remote Desktop - * Copyright (C) 2010 Michael Jumper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import javax.servlet.ServletRequest; -import net.sourceforge.guacamole.GuacamoleException; -import org.w3c.dom.Element; -import net.sourceforge.guacamole.event.PointerEvent; - -import net.sourceforge.guacamole.net.GuacamoleSession; -import net.sourceforge.guacamole.net.XMLGuacamoleServlet; - -public class Pointer extends XMLGuacamoleServlet { - - - @Override - protected void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException { - // Event parameters - String[] events = request.getParameterValues("event"); - - for (String event : events) { - - String[] parameters = event.split(","); - - int index = Integer.parseInt(parameters[0]); - - int x = Integer.parseInt(parameters[1]); - int y = Integer.parseInt(parameters[2]); - - boolean left = parameters[3].equals("1"); - boolean middle = parameters[4].equals("1"); - boolean right = parameters[5].equals("1"); - boolean up = parameters[6].equals("1"); - boolean down = parameters[7].equals("1"); - - // Store event - try { - session.getClient().send(new PointerEvent(index, left, middle, right, up, down, x, y)); - } - catch (GuacamoleException e) { - throw new GuacamoleException("Error sending pointer event to server: " + e.getMessage(), e); - } - } - } - -} - diff --git a/guacamole/client/src/net/sourceforge/guacamole/net/output/InstructionStream.java b/guacamole/client/src/net/sourceforge/guacamole/net/output/InstructionStream.java index 6a66c2c7d..33237d44a 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/net/output/InstructionStream.java +++ b/guacamole/client/src/net/sourceforge/guacamole/net/output/InstructionStream.java @@ -18,12 +18,9 @@ package net.sourceforge.guacamole.net.output; * along with this program. If not, see . */ -import java.io.OutputStream; -import java.io.ByteArrayOutputStream; +import java.io.Writer; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.GZIPOutputStream; import java.util.concurrent.locks.ReentrantLock; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -31,8 +28,6 @@ import net.sourceforge.guacamole.Client; import net.sourceforge.guacamole.net.GuacamoleServlet; import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.net.GuacamoleSession; -import net.sourceforge.guacamole.instruction.Instruction; -import net.sourceforge.guacamole.instruction.ErrorInstruction; public class InstructionStream extends GuacamoleServlet { @@ -46,36 +41,7 @@ public class InstructionStream extends GuacamoleServlet { try { response.setContentType("text/plain"); - OutputStream out = response.getOutputStream(); - - // Compress if enabled and supported by browser - if (session.getConfiguration().getCompressStream()) { - - String encodingHeader = request.getHeader("Accept-Encoding"); - if (encodingHeader != null) { - - String[] encodings = encodingHeader.split(","); - for (String encoding : encodings) { - - // Use gzip if supported - if (encoding.equals("gzip")) { - response.setHeader("Content-Encoding", "gzip"); - out = new GZIPOutputStream(out); - break; - } - - // Use deflate if supported - if (encoding.equals("deflate")) { - response.setHeader("Content-Encoding", "deflate"); - out = new DeflaterOutputStream(out); - break; - } - - } - - } - - } + Writer out = response.getWriter(); try { @@ -83,12 +49,11 @@ public class InstructionStream extends GuacamoleServlet { Client client = session.getClient(); // For all messages, until another stream is ready (we send at least one message) - Instruction message = client.nextInstruction(true); // Block until first message is read - while (message != null) { + char[] message; + while ((message = client.read()) != null) { // Get message output bytes - byte[] outputBytes = message.toString().getBytes("UTF-8"); - out.write(outputBytes); + out.write(message, 0, message.length); out.flush(); response.flushBuffer(); @@ -96,14 +61,11 @@ public class InstructionStream extends GuacamoleServlet { if (instructionStreamLock.hasQueuedThreads()) break; - message = client.nextInstruction(false); // Read remaining messages, do not block. } } catch (GuacamoleException e) { - Instruction message = new ErrorInstruction(e.getMessage()); - byte[] outputBytes = message.toString().getBytes("UTF-8"); - out.write(outputBytes); + out.write("error:" + e.getMessage() + ";"); out.flush(); response.flushBuffer(); } diff --git a/guacamole/client/web/WEB-INF/web.xml b/guacamole/client/web/WEB-INF/web.xml index 6e54cf951..f46926389 100644 --- a/guacamole/client/web/WEB-INF/web.xml +++ b/guacamole/client/web/WEB-INF/web.xml @@ -53,31 +53,13 @@ /instructions - Clipboard input servlet. - Clipboard - net.sourceforge.guacamole.net.input.Clipboard + Input servlet. + Inbound + net.sourceforge.guacamole.net.input.Inbound - Clipboard - /clipboard - - - Key input servlet. - Key - net.sourceforge.guacamole.net.input.Key - - - Key - /key - - - Pointer input servlet. - Pointer - net.sourceforge.guacamole.net.input.Pointer - - - Pointer - /pointer + Inbound + /inbound Guacamole Access Restrictions diff --git a/guacamole/client/web/javascript/guacamole.js b/guacamole/client/web/javascript/guacamole.js index fe2006bb5..83a65991a 100644 --- a/guacamole/client/web/javascript/guacamole.js +++ b/guacamole/client/web/javascript/guacamole.js @@ -46,9 +46,6 @@ function VNCClient(display) { || currentState == STATE_WAITING; } - var keyIndex = 0; - var xmlIndex = 0; - // Layers var background = null; var cursor = null; @@ -118,17 +115,7 @@ function VNCClient(display) { this.enableKeyboard(); function sendKeyEvent(pressed, keysym) { - - // Do not send requests if not connected - if (!isConnected()) - return; - - var key_xmlhttprequest = new XMLHttpRequest(); - key_xmlhttprequest.open("GET", - "key?index=" + (keyIndex++) - + "&pressed=" + pressed - + "&keysym=" + keysym); - key_xmlhttprequest.send(null); + sendMessage("key:" + keysym + "," + pressed + ";"); } this.pressKey = function(keysym) { @@ -170,47 +157,63 @@ function VNCClient(display) { ); - var sendingMouseEvents = 0; - var mouseEventBuffer = ""; - function sendMouseState(mouseState) { + // Build mask + var buttonMask = 0; + if (mouseState.getLeft()) buttonMask |= 1; + if (mouseState.getMiddle()) buttonMask |= 2; + if (mouseState.getRight()) buttonMask |= 4; + if (mouseState.getUp()) buttonMask |= 8; + if (mouseState.getDown()) buttonMask |= 16; + + // Send message + sendMessage("mouse:" + mouseState.getX() + "," + mouseState.getY() + "," + buttonMask + ";"); + } + + var sendingMessages = 0; + var outputMessageBuffer = ""; + + function sendMessage(message) { + // Do not send requests if not connected if (!isConnected()) return; // Add event to queue, restart send loop if finished. - if (mouseEventBuffer.length > 0) mouseEventBuffer += "&"; - mouseEventBuffer += "event=" + mouseState.toString(); - if (sendingMouseEvents == 0) - sendPendingMouseEvents(); + outputMessageBuffer += message; + if (sendingMessages == 0) + sendPendingMessages(); } - function sendPendingMouseEvents() { + function sendPendingMessages() { // Do not send requests if not connected if (!isConnected()) return; - if (mouseEventBuffer.length > 0) { + if (outputMessageBuffer.length > 0) { - sendingMouseEvents = 1; + sendingMessages = 1; - var mouse_xmlhttprequest = new XMLHttpRequest(); - mouse_xmlhttprequest.open("GET", "pointer?" + mouseEventBuffer); - mouseEventBuffer = ""; // Clear buffer + var message_xmlhttprequest = new XMLHttpRequest(); + message_xmlhttprequest.open("POST", "inbound"); + message_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + message_xmlhttprequest.setRequestHeader("Content-length", outputMessageBuffer.length); // Once response received, send next queued event. - mouse_xmlhttprequest.onreadystatechange = function() { - if (mouse_xmlhttprequest.readyState == 4) - sendPendingMouseEvents(); + message_xmlhttprequest.onreadystatechange = function() { + if (message_xmlhttprequest.readyState == 4) + sendPendingMessages(); } - mouse_xmlhttprequest.send(null); + message_xmlhttprequest.send(outputMessageBuffer); + outputMessageBuffer = ""; // Clear buffer + } else - sendingMouseEvents = 0; + sendingMessages = 0; } @@ -225,10 +228,7 @@ function VNCClient(display) { if (!isConnected()) return; - var clipboard_xmlhttprequest = new XMLHttpRequest(); - clipboard_xmlhttprequest.open("POST", "clipboard"); - clipboard_xmlhttprequest.send(data); - + sendMessage("clipboard:" + escapeGuacamoleString(data) + ";"); } @@ -387,6 +387,28 @@ function VNCClient(display) { } + function escapeGuacamoleString(str) { + + var escapedString = ""; + + for (var i=0; i