Removed old Java client, added new experimental PHP client.

This commit is contained in:
Michael Jumper
2010-09-23 09:57:53 +00:00
parent 7bbc9b5ae5
commit 8f3e6a7340
46 changed files with 55 additions and 1625 deletions

View File

@@ -1,11 +0,0 @@
.PHONY: client clean
all: client
client:
ant war
clean:
ant clean

View File

@@ -1,13 +0,0 @@
servlet.api.jar=/usr/share/tomcat6/lib/servlet-api.jar
src.dir=src
web.dir=web
build.dir=build
dist.dir=dist
doc.dir=doc
guac.version=0.3.0rc1
tar.dir=guacamole-${guac.version}
tar.src.dir=guacamole-src

View File

@@ -1,77 +0,0 @@
<?xml version="1.0"?>
<project name="guacamole" default="compile" basedir=".">
<property file="ant/build.properties"/>
<target name="clean" description="Removes build and dist dirs.">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
<delete dir="${tar.dir}"/>
<delete dir="${tar.src.dir}"/>
<delete file="${tar.dir}.tar.gz"/>
</target>
<target name="init" description="Creates build and dist dirs.">
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.dir}/WEB-INF/classes"/>
<mkdir dir="${dist.dir}"/>
</target>
<target name="compile" description="Compiles Guacamole."
depends="init">
<copy todir="${build.dir}">
<fileset dir="${web.dir}"/>
</copy>
<!-- Replace __GUAC_VERSION with declared version -->
<replace dir="${build.dir}" value="${guac.version}">
<include name="**/*.html"/>
<replacetoken><![CDATA[__GUAC_VERSION]]></replacetoken>
</replace>
<javac srcdir="${src.dir}" destdir="${build.dir}/WEB-INF/classes"
classpath="${servlet.api.jar}">
<compilerarg value="-Xlint:unchecked"/>
</javac>
</target>
<target name="war" description="Builds Guacamole .war file."
depends="compile">
<war destfile="${dist.dir}/guacamole.war"
webxml="${build.dir}/WEB-INF/web.xml">
<fileset dir="${build.dir}">
<exclude name="META-INF/**"/>
</fileset>
</war>
</target>
<target name="tar" description="Build distributable .tar.gz file"
depends="war">
<mkdir dir="${tar.dir}"/>
<mkdir dir="${tar.src.dir}"/>
<copy todir="${tar.src.dir}">
<fileset dir=".">
<exclude name=".git/**"/>
<exclude name="**/.svn"/>
<exclude name="${tar.dir}/**"/>
<exclude name="${tar.src.dir}/**"/>
<exclude name="${dist.dir}/**"/>
<exclude name="${build.dir}/**"/>
</fileset>
</copy>
<tar basedir="." includes="${tar.src.dir}/**" destfile="${tar.dir}/${tar.src.dir}.tar" longfile="gnu"/>
<delete dir="${tar.src.dir}"/>
<copy todir="${tar.dir}">
<fileset file="${doc.dir}/example/guacamole.xml"/>
<fileset file="${doc.dir}/example/guacamole-users.xml"/>
<fileset file="${dist.dir}/guacamole.war"/>
<fileset file="LICENSE.txt"/>
</copy>
<tar basedir="." includes="${tar.dir}/**" destfile="${tar.dir}.tar.gz" compression="gzip" longfile="gnu"/>
</target>
</project>

View File

@@ -1,6 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="guacamole"/>
<user username="guacamole" password="changeme" roles="guacamole"/>
</tomcat-users>

View File

@@ -1,75 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Guacamole - Pure JavaScript/HTML VNC Client
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 <http://www.gnu.org/licenses/>.
-->
<Context antiJARLocking="true" path="/guacamole" docBase="/var/lib/guacamole/guacamole.war">
<!-- Change the lines below to match your VNC server -->
<Parameter name="host" value="localhost"/>
<Parameter name="port" value="5900"/>
<!-- Password (VNC Authentication)
Uncomment and change the line below if your VNC server is
password protected. -->
<!--
<Parameter name="password" value="PASSWORD"/>
-->
<!-- Bits-per-pixel
This parameter controls what color depth should be
requested from the VNC server.
Valid values are "8", "16", or "24". -->
<!--
<Parameter name="bpp" value="24"/>
-->
<!-- Output (to web client) bits-per-pixel.
This parameter controls what color depth will be used
in the images sent to the web-based client.
Valid values are "8" or "24". -->
<!--
<Parameter name="output-bpp" value="24"/>
-->
<!-- Swap red and blue components. Some VNC servers may not honor
the client's request for certain pixel formats, instead
returning RGB as BGR.
If colors look strange (blues look red or brown) when using
Guacamole, uncomment and set this parameter to true. -->
<!--
<Parameter name="swap-red-blue" value="false"/>
-->
<Realm className="org.apache.catalina.realm.MemoryRealm" pathname="conf/guacamole-users.xml"/>
</Context>

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 208 B

After

Width:  |  Height:  |  Size: 208 B

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 766 B

View File

Before

Width:  |  Height:  |  Size: 71 B

After

Width:  |  Height:  |  Size: 71 B

View File

Before

Width:  |  Height:  |  Size: 72 B

After

Width:  |  Height:  |  Size: 72 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -186,38 +186,9 @@ function VNCClient(display) {
// Add event to queue, restart send loop if finished. // Add event to queue, restart send loop if finished.
outputMessageBuffer += message; outputMessageBuffer += message;
if (sendingMessages == 0)
sendPendingMessages();
} }
function sendPendingMessages() {
if (outputMessageBuffer.length > 0) {
sendingMessages = 1;
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.
message_xmlhttprequest.onreadystatechange = function() {
if (message_xmlhttprequest.readyState == 4)
sendPendingMessages();
}
message_xmlhttprequest.send(outputMessageBuffer);
outputMessageBuffer = ""; // Clear buffer
}
else
sendingMessages = 0;
}
/*****************************************/ /*****************************************/
/*** Clipboard ***/ /*** Clipboard ***/
/*****************************************/ /*****************************************/
@@ -301,7 +272,7 @@ function VNCClient(display) {
function parseResponse() { function parseResponse() {
// Start next request as soon as possible // Start next request as soon as possible
if (xmlhttprequest.readyState >= 2 && nextRequest == null) if (xmlhttprequest.readyState >= 2 && nextRequest == null && uuid)
nextRequest = makeRequest(); nextRequest = makeRequest();
// Parse stream when data is received and when complete. // Parse stream when data is received and when complete.
@@ -378,10 +349,19 @@ function VNCClient(display) {
function makeRequest() { function makeRequest() {
if (uuid)
outputMessageBuffer = "resume:" + uuid + ";" + outputMessageBuffer;
outputMessageBuffer += "pause;";
// Download self // Download self
var xmlhttprequest = new XMLHttpRequest(); var xmlhttprequest = new XMLHttpRequest();
xmlhttprequest.open("POST", "instructions"); xmlhttprequest.open("POST", "tunnel.php");
xmlhttprequest.send(null); xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttprequest.setRequestHeader("Content-length", outputMessageBuffer.length);
xmlhttprequest.send(outputMessageBuffer);
outputMessageBuffer = "";
return xmlhttprequest; return xmlhttprequest;
@@ -438,8 +418,14 @@ function VNCClient(display) {
} }
var uuid = null;
var instructionHandlers = { var instructionHandlers = {
"uuid": function(parameters) {
uuid = parameters[0];
},
"error": function(parameters) { "error": function(parameters) {
showError(unescapeGuacamoleString(parameters[0])); showError(unescapeGuacamoleString(parameters[0]));
}, },
@@ -559,16 +545,8 @@ function VNCClient(display) {
this.connect = function() { this.connect = function() {
var message = "connect;";
setState(STATE_CONNECTING); setState(STATE_CONNECTING);
sendMessage("connect;");
// Send connect message (synchronously... as necessary until handoff is implemented)
var connect_xmlhttprequest = new XMLHttpRequest();
connect_xmlhttprequest.open("POST", "inbound", false);
connect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
connect_xmlhttprequest.setRequestHeader("Content-length", message.length);
connect_xmlhttprequest.send(message);
// Start reading data // Start reading data
setState(STATE_WAITING); setState(STATE_WAITING);
@@ -583,15 +561,9 @@ function VNCClient(display) {
if (currentState != STATE_DISCONNECTED if (currentState != STATE_DISCONNECTED
&& currentState != STATE_DISCONNECTING) { && currentState != STATE_DISCONNECTING) {
var message = "disconnect;";
setState(STATE_DISCONNECTING); setState(STATE_DISCONNECTING);
// Send disconnect message (synchronously... as necessary until handoff is implemented) sendMessage("disconnect;");
var disconnect_xmlhttprequest = new XMLHttpRequest();
disconnect_xmlhttprequest.open("POST", "inbound", false);
disconnect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
disconnect_xmlhttprequest.setRequestHeader("Content-length", message.length);
disconnect_xmlhttprequest.send(message);
setState(STATE_DISCONNECTED); setState(STATE_DISCONNECTED);
} }

View File

@@ -1,32 +0,0 @@
package net.sourceforge.guacamole;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.event.KeyEvent;
import net.sourceforge.guacamole.event.PointerEvent;
public abstract class Client {
public abstract void write(char[] chunk, int off, int len) throws GuacamoleException;
public abstract char[] read() throws GuacamoleException;
public abstract void disconnect() throws GuacamoleException;
}

View File

@@ -1,133 +0,0 @@
package net.sourceforge.guacamole;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.io.InputStream;
import java.io.Reader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Writer;
import java.io.OutputStreamWriter;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.event.EventQueue;
import net.sourceforge.guacamole.event.EventHandler;
import net.sourceforge.guacamole.event.KeyEvent;
import net.sourceforge.guacamole.event.PointerEvent;
public class GuacamoleClient extends Client {
private Socket sock;
private Reader input;
private Writer output;
public GuacamoleClient(String hostname, int port) throws GuacamoleException {
try {
sock = new Socket(InetAddress.getByName(hostname), port);
input = new InputStreamReader(sock.getInputStream());
output = new OutputStreamWriter(sock.getOutputStream());
}
catch (IOException e) {
throw new GuacamoleException(e);
}
}
public void write(char[] chunk, int off, int len) throws GuacamoleException {
try {
output.write(chunk, off, len);
output.flush();
}
catch (IOException e) {
throw new GuacamoleException(e);
}
}
public void disconnect() throws GuacamoleException {
try {
sock.close();
}
catch (IOException e) {
throw new GuacamoleException(e);
}
}
private int usedLength = 0;
private char[] buffer = new char[20000];
public char[] read() throws GuacamoleException {
try {
// While we're blocking, or input is available
for (;;) {
// If past threshold, resize buffer before reading
if (usedLength > buffer.length/2) {
char[] biggerBuffer = new char[buffer.length*2];
System.arraycopy(buffer, 0, biggerBuffer, 0, usedLength);
buffer = biggerBuffer;
}
// Attempt to fill buffer
int numRead = input.read(buffer, usedLength, buffer.length - usedLength);
if (numRead == -1)
return null;
int prevLength = usedLength;
usedLength += numRead;
for (int i=usedLength-1; i>=prevLength; i--) {
char readChar = buffer[i];
// If end of instruction, return it.
if (readChar == ';') {
// Get instruction
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
return chunk;
}
}
} // End read loop
}
catch (IOException e) {
throw new GuacamoleException(e);
}
}
}

View File

@@ -1,36 +0,0 @@
package net.sourceforge.guacamole;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
public class GuacamoleException extends Exception {
public GuacamoleException(String message, Throwable cause) {
super(message, cause);
}
public GuacamoleException(String message) {
super(message);
}
public GuacamoleException(Throwable cause) {
super(cause);
}
}

View File

@@ -1,55 +0,0 @@
package net.sourceforge.guacamole.event;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
public abstract class Event implements Comparable<Event> {
private long time;
private int index;
public Event(int index) {
this.time = System.currentTimeMillis();
this.index = index;
}
public int getIndex() {
return index;
}
public long getTime() {
return time;
}
public int hashCode() {
return index;
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (getClass() != o.getClass()) return false;
return getIndex() == ((Event) o).getIndex();
}
public int compareTo(Event e) {
return getIndex() - e.getIndex();
}
}

View File

@@ -1,28 +0,0 @@
package net.sourceforge.guacamole.event;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import java.io.IOException;
public interface EventHandler<E extends Event> {
public void handle(E e) throws IOException;
}

View File

@@ -1,191 +0,0 @@
package net.sourceforge.guacamole.event;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import java.io.IOException;
import java.util.PriorityQueue;
public class EventQueue<E extends Event> {
private int nextIndex = 0;
private final PriorityQueue<E> queue = new PriorityQueue<E>();
private EventHandler<E> handler;
private final int deadline;
private AutoflushThread autoflush = new AutoflushThread();
private class AutoflushThread extends Thread {
private IOException error;
private long deadline;
private static final long ONE_YEAR = 31536000;
private boolean killed = false;
public AutoflushThread() {
this.deadline = ONE_YEAR;
start();
}
public void run() {
while (!killed) {
try {
if (deadline > 0) sleep(deadline);
dropPendingEvents();
flush();
}
catch (InterruptedException e) {
// Interrupt indicates event handled, or thread killed
if (killed) return;
}
catch (IOException e) {
error = e;
break;
}
}
}
public void setDeadline(long deadline) {
this.deadline = deadline;
interrupt();
}
public void checkError() throws IOException {
if (error != null) throw error;
}
public void kill() {
killed = true;
interrupt();
}
}
public void close() {
autoflush.kill();
}
// Starts autoflush wait thread for any waiting events on the queue
private void startDeadlineAutoflush() {
synchronized (queue) {
// No need to autoflush if nothing waiting
if (queue.size() == 0) return;
// Get waiting event
E waiting = queue.peek();
if (waiting != null) {
long untilDeadline = deadline + waiting.getTime() - System.currentTimeMillis();
// Start autoflush thread which waits for time remaining until next
// event's deadline.
autoflush.setDeadline(untilDeadline);
}
else
autoflush.setDeadline(AutoflushThread.ONE_YEAR);
}
}
public EventQueue(EventHandler<E> handler, int deadline) {
this.handler = handler;
this.deadline = deadline;
}
public void add(E event) throws IOException {
synchronized (queue) {
autoflush.checkError();
if (event.getIndex() < nextIndex) {
//System.err.println("Past event dropped.");
return;
}
if (event == null)
throw new Error("Cannot add null event.");
queue.add(event);
}
flush();
}
private E next() {
synchronized (queue) {
// If no events, return nothing.
if (queue.size() == 0) return null;
// If still waiting for true next event, return nothing.
E event = queue.peek();
if (event.getIndex() != nextIndex)
return null;
// If event found, expect next event, remove and return current.
queue.remove();
nextIndex++;
return event;
}
}
// Return number of waiting events
public int getWaiting() {
synchronized (queue) {
// If no events, then none waiting.
if (queue.size() == 0) return 0;
// If we have the next event, then none waiting.
E event = queue.peek();
if (event.getIndex() == nextIndex)
return 0;
// Otherwise, all events are waiting.
return queue.size();
}
}
// Stop waiting for any unreceived events
private void dropPendingEvents() {
synchronized (queue) {
// If no events, nothing needs to be changed;
if (queue.size() == 0) return;
// Otherwise, update nextIndex to index of next event
E event = queue.peek();
nextIndex = event.getIndex();
}
}
// Attempts to flush queue
// If any events remain, an autoflush thread is started.
private void flush() throws IOException {
synchronized (queue) {
E nextEvent;
while ((nextEvent = next()) != null)
handler.handle(nextEvent);
}
// Start autoflush thread for any remaining events.
startDeadlineAutoflush();
}
}

View File

@@ -1,39 +0,0 @@
package net.sourceforge.guacamole.event;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
public class KeyEvent extends Event {
private int keysym;
private boolean pressed;
public KeyEvent(int index, int keysym, boolean pressed) {
super(index);
this.keysym = keysym;
this.pressed = pressed;
}
public int getKeySym() {
return keysym;
}
public boolean getPressed() {
return pressed;
}
}

View File

@@ -1,69 +0,0 @@
package net.sourceforge.guacamole.event;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
public class PointerEvent extends Event {
private boolean leftButtonPressed;
private boolean middleButtonPressed;
private boolean rightButtonPressed;
private boolean upButtonPressed;
private boolean downButtonPressed;
private int x;
private int y;
public PointerEvent(int index, boolean leftButtonPressed, boolean middleButtonPressed, boolean rightButtonPressed, boolean upButtonPressed, boolean downButtonPressed, int x, int y) {
super(index);
this.leftButtonPressed = leftButtonPressed;
this.middleButtonPressed = middleButtonPressed;
this.rightButtonPressed = rightButtonPressed;
this.upButtonPressed = upButtonPressed;
this.downButtonPressed = downButtonPressed;
this.x = x;
this.y = y;
}
public boolean isLeftButtonPressed() {
return leftButtonPressed;
}
public boolean isMiddleButtonPressed() {
return middleButtonPressed;
}
public boolean isRightButtonPressed() {
return rightButtonPressed;
}
public boolean isUpButtonPressed() {
return upButtonPressed;
}
public boolean isDownButtonPressed() {
return downButtonPressed;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}

View File

@@ -1,66 +0,0 @@
package net.sourceforge.guacamole.net;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
public class Base64 {
private static String characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
public static String toString(byte[] data) {
StringBuffer buff = new StringBuffer();
for (int i=0; i<data.length; i+=3) {
int a = data[i];
int b = 0; if (i+1 < data.length) b = data[i+1];
int c = 0; if (i+2 < data.length) c = data[i+2];
buff.append(characters.charAt(
(a & 0xFC) >> 2
));
buff.append(characters.charAt(
((a & 0x03) << 4) |
((b & 0xF0) >> 4)
));
if (i+1 < data.length)
buff.append(characters.charAt(
((b & 0x0F) << 2) |
((c & 0xC0) >> 6)
));
else
buff.append('=');
if (i+2 < data.length)
buff.append(characters.charAt(
(c & 0x3F)
));
else
buff.append('=');
}
return buff.toString();
}
}

View File

@@ -1,130 +0,0 @@
package net.sourceforge.guacamole.net;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import javax.servlet.ServletContext;
import net.sourceforge.guacamole.GuacamoleException;
public abstract class Configuration {
private ServletContext context;
protected String humanReadableList(Object... values) {
String list = "";
for (int i=0; i<values.length; i++) {
if (i >= 1)
list += ", ";
if (i == values.length -1)
list += " or ";
list += "\"" + values[i] + "\"";
}
return list;
}
protected String readParameter(String name, String defaultValue, String... allowedValues) throws GuacamoleException {
String value = context.getInitParameter(name);
// Use default if not specified
if (value == null) {
if (defaultValue == null)
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
return defaultValue;
}
// If not restricted to certain values, just return whatever is given.
if (allowedValues.length == 0)
return value;
// If restricted, only return value within given list
for (String allowedValue : allowedValues)
if (value.equals(allowedValue))
return value;
throw new GuacamoleException("Parameter \"" + name + "\" must be " + humanReadableList((Object) allowedValues));
}
protected boolean readBooleanParameter(String name, Boolean defaultValue) throws GuacamoleException {
String value = context.getInitParameter(name);
// Use default if not specified
if (value == null) {
if (defaultValue == null)
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
return defaultValue;
}
value = value.trim();
if (value.equals("true"))
return true;
if (value.equals("false"))
return false;
throw new GuacamoleException("Parameter \"" + name + "\" must be \"true\" or \"false\".");
}
protected int readIntParameter(String name, Integer defaultValue, Integer... allowedValues) throws GuacamoleException {
String parmString = context.getInitParameter(name);
// Use default if not specified
if (parmString== null) {
if (defaultValue == null)
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
return defaultValue;
}
try {
int value = Integer.parseInt(parmString);
// If not restricted to certain values, just return whatever is given.
if (allowedValues.length == 0)
return value;
// If restricted, only return value within given list
for (int allowedValue : allowedValues)
if (value == allowedValue)
return value;
throw new GuacamoleException("Parameter \"" + name + "\" must be " + humanReadableList((Object) allowedValues));
}
catch (NumberFormatException e) {
throw new GuacamoleException("Parameter \"" + name + "\" must be an integer.", e);
}
}
public Configuration(ServletContext context) {
this.context = context;
}
}

View File

@@ -1,46 +0,0 @@
package net.sourceforge.guacamole.net;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import javax.servlet.ServletContext;
import net.sourceforge.guacamole.GuacamoleException;
public class GuacamoleConfiguration extends Configuration {
private String hostname;
private int port;
public GuacamoleConfiguration(ServletContext context) throws GuacamoleException {
super(context);
hostname = context.getInitParameter("hostname");
port = readIntParameter("port", null);
}
public int getPort() {
return port;
}
public String getHostname() {
return hostname;
}
}

View File

@@ -1,62 +0,0 @@
package net.sourceforge.guacamole.net;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sourceforge.guacamole.GuacamoleException;
public abstract class GuacamoleServlet extends HttpServlet {
@Override
protected final void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
handleRequest(req, resp);
}
catch (GuacamoleException e) {
throw new ServletException(e);
}
}
@Override
protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
handleRequest(req, resp);
}
catch (GuacamoleException e) {
throw new ServletException(e);
}
}
private final void handleRequest(HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
GuacamoleSession session = new GuacamoleSession(request.getSession(shouldCreateSession()));
handleRequest(session, request, response);
}
protected abstract void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException;
protected boolean shouldCreateSession() {
return false;
}
}

View File

@@ -1,147 +0,0 @@
package net.sourceforge.guacamole.net;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import net.sourceforge.guacamole.Client;
import net.sourceforge.guacamole.GuacamoleClient;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.event.KeyEvent;
import net.sourceforge.guacamole.event.PointerEvent;
public class GuacamoleSession {
private GuacamoleConfiguration config;
private final HttpSession session;
private Client client;
private ReentrantLock instructionStreamLock;
private class SessionClient extends Client implements HttpSessionBindingListener {
private Client client;
public SessionClient(Client client) {
this.client = client;
}
public void valueBound(HttpSessionBindingEvent event) {
// Do nothing
}
public void valueUnbound(HttpSessionBindingEvent event) {
try {
disconnect();
}
catch (GuacamoleException e) {
// Ignore
}
}
public void write(char[] data, int off, int len) throws GuacamoleException {
client.write(data, off, len);
}
public char[] read() throws GuacamoleException {
return client.read();
}
public void disconnect() throws GuacamoleException {
client.disconnect();
}
}
public GuacamoleSession(HttpSession session) throws GuacamoleException {
if (session == null)
throw new GuacamoleException("User has no session.");
this.session = session;
synchronized (session) {
// Read configuration parameters
ServletContext context = session.getServletContext();
config = new GuacamoleConfiguration(context);
client = (Client) session.getAttribute("CLIENT");
instructionStreamLock = (ReentrantLock) session.getAttribute("INSTRUCTION_STREAM_LOCK");
}
}
public void connect() throws GuacamoleException {
synchronized (session) {
if (client != null)
client.disconnect();
client = new SessionClient(
new GuacamoleClient (
config.getHostname(),
config.getPort()
)
);
session.setAttribute("CLIENT", client);
instructionStreamLock = new ReentrantLock();
session.setAttribute("INSTRUCTION_STREAM_LOCK", instructionStreamLock);
}
}
public boolean isConnected() {
synchronized (session) {
return client != null;
}
}
public GuacamoleConfiguration getConfiguration() {
return config;
}
public Client getClient() {
synchronized (session) {
return client;
}
}
public void invalidate() {
session.invalidate();
}
public void disconnect() throws GuacamoleException {
if (client != null) {
client.disconnect();
session.removeAttribute("CLIENT");
client = null;
}
}
public ReentrantLock getInstructionStreamLock() {
return instructionStreamLock;
}
}

View File

@@ -1,132 +0,0 @@
package net.sourceforge.guacamole.net;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import net.sourceforge.guacamole.Client;
import net.sourceforge.guacamole.GuacamoleException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public abstract class XMLGuacamoleServlet extends GuacamoleServlet {
@Override
protected final void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
try {
// Create document
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.newDocument();
// Root element
Element root = document.createElement("guacamole");
document.appendChild(root);
try {
handleRequest(session, request, root);
}
catch (Throwable t) {
addFatalError(root, t.getMessage());
// FATAL error ... try to disconnect
if (session != null) {
Client client = session.getClient();
try {
if (client != null)
client.disconnect();
}
catch (GuacamoleException e) {
addFatalError(root, e.getMessage());
}
}
}
// Set up transformer
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
// Write XML using transformer
ByteArrayOutputStream bos = new ByteArrayOutputStream();
StreamResult result = new StreamResult(bos);
DOMSource source = new DOMSource(document);
transformer.transform(source, result);
bos.flush();
byte[] xmlData = bos.toByteArray();
response.setContentLength(xmlData.length);
OutputStream outputStream = response.getOutputStream();
outputStream.write(xmlData);
// Close stream
outputStream.close();
}
catch (ParserConfigurationException e) {
throw new GuacamoleException(e);
}
catch (TransformerConfigurationException e) {
throw new GuacamoleException(e);
}
catch (TransformerException e) {
throw new GuacamoleException(e);
}
catch (IOException e) {
throw new GuacamoleException(e);
}
}
private void addFatalError(Element root, String message) {
Element error = root.getOwnerDocument().createElement("error");
error.setAttribute("type", "fatal");
error.setTextContent(message);
root.appendChild(error);
}
protected abstract void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException;
}

View File

@@ -1,64 +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 <http://www.gnu.org/licenses/>.
*/
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;
public class Inbound extends XMLGuacamoleServlet {
protected boolean shouldCreateSession() {
return true;
}
@Override
protected void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException {
if (!session.isConnected())
session.connect();
// Send data
try {
Reader input = request.getReader();
char[] buffer = new char[8192];
int length;
while ((length = input.read(buffer, 0, buffer.length)) != -1)
session.getClient().write(buffer, 0, length);
}
catch (IOException e) {
throw new GuacamoleException("I/O Error sending data to server: " + e.getMessage(), e);
}
catch (GuacamoleException e) {
throw new GuacamoleException("Error sending data to server: " + e.getMessage(), e);
}
}
}

View File

@@ -1,97 +0,0 @@
package net.sourceforge.guacamole.net.output;
/*
* 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 <http://www.gnu.org/licenses/>.
*/
import java.io.Writer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sourceforge.guacamole.Client;
import net.sourceforge.guacamole.net.GuacamoleServlet;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.GuacamoleSession;
public class InstructionStream extends GuacamoleServlet {
@Override
protected void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
ReentrantLock instructionStreamLock = session.getInstructionStreamLock();
instructionStreamLock.lock();
try {
response.setContentType("text/plain");
Writer out = response.getWriter();
try {
// Query new update from server
Client client = session.getClient();
// For all messages, until another stream is ready (we send at least one message)
char[] message;
while ((message = client.read()) != null) {
// Get message output bytes
out.write(message, 0, message.length);
out.flush();
response.flushBuffer();
// No more messages another stream can take over
if (instructionStreamLock.hasQueuedThreads())
break;
}
if (message == null) {
session.disconnect();
throw new GuacamoleException("Disconnected.");
}
}
catch (GuacamoleException e) {
out.write("error:" + e.getMessage() + ";");
out.flush();
response.flushBuffer();
}
// End-of-instructions marker
out.write(';');
out.flush();
response.flushBuffer();
}
catch (UnsupportedEncodingException e) {
throw new GuacamoleException("UTF-8 not supported by Java.", e);
}
catch (IOException e) {
throw new GuacamoleException("I/O error writing to servlet output stream.", e);
}
finally {
instructionStreamLock.unlock();
}
}
}

View File

@@ -0,0 +1,35 @@
<?php
# End all output buffers
while (@ob_end_flush());
# Create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0);
if (!$socket) {
die("error:Could not create socket.;");
}
# Open connection
$result = socket_connect($socket, "localhost", 2222);
if (!$result) {
die("error:Could not connect: " . socket_strerror(socket_last_error()) . ";");
}
# Socket should block
socket_set_block($socket);
# Write all data sent here
socket_write($socket, file_get_contents("php://input"));
# Read until EOF
while (($buffer = socket_read($socket, 8192))) {
echo $buffer;
flush();
}
echo ";";
# Close socket
socket_close($socket);
?>

View File

@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Guacamole - Pure JavaScript/HTML VNC Client
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 <http://www.gnu.org/licenses/>.
-->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Basic config -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<!-- Servlets -->
<servlet>
<description>Instruction stream servlet.</description>
<servlet-name>InstructionStream</servlet-name>
<servlet-class>net.sourceforge.guacamole.net.output.InstructionStream</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>InstructionStream</servlet-name>
<url-pattern>/instructions</url-pattern>
</servlet-mapping>
<servlet>
<description>Input servlet.</description>
<servlet-name>Inbound</servlet-name>
<servlet-class>net.sourceforge.guacamole.net.input.Inbound</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Inbound</servlet-name>
<url-pattern>/inbound</url-pattern>
</servlet-mapping>
<security-constraint>
<display-name>Guacamole Access Restrictions</display-name>
<web-resource-collection>
<web-resource-name>Guacamole</web-resource-name>
<description>All servlets/pages within Guacamole.</description>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description>Only allow Guacamole users access.</description>
<role-name>guacamole</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Guacamole</realm-name>
</login-config>
<security-role>
<description>Guacamole</description>
<role-name>guacamole</role-name>
</security-role>
</web-app>