mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 09:03:21 +00:00 
			
		
		
		
	Added dummy proxy implementation, moved client, added main Makefile.
This commit is contained in:
		
				
					committed by
					
						 Mike Jumper
						Mike Jumper
					
				
			
			
				
	
			
			
			
						parent
						
							7ee970c88a
						
					
				
				
					commit
					c048537232
				
			
							
								
								
									
										35
									
								
								guacamole/client/src/net/sourceforge/guacamole/Client.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								guacamole/client/src/net/sourceforge/guacamole/Client.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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 disconnect() throws GuacamoleException; | ||||
|     public abstract Instruction nextInstruction(boolean blocking) throws GuacamoleException; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,36 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,55 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.event; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,28 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.event; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| public interface EventHandler<E extends Event> { | ||||
|  | ||||
|     public void handle(E e) throws IOException; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,191 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.event; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
| package net.sourceforge.guacamole.event; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,69 @@ | ||||
| package net.sourceforge.guacamole.event; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.instruction; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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()) + ";"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.instruction; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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()) + ";"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,63 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.instruction; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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 String escape(String str) { | ||||
|  | ||||
|         StringBuffer sb = new StringBuffer(); | ||||
|  | ||||
|         for (int i=0; i<str.length(); i++) { | ||||
|  | ||||
|             char c = str.charAt(i); | ||||
|  | ||||
|             switch (c) { | ||||
|                 case ',': | ||||
|                     sb.append("\\c"); | ||||
|                     break; | ||||
|  | ||||
|                 case ';': | ||||
|                     sb.append("\\s"); | ||||
|                     break; | ||||
|  | ||||
|                 case '\\': | ||||
|                     sb.append("\\\\"); | ||||
|                     break; | ||||
|  | ||||
|                 default: | ||||
|                     sb.append(c); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         return sb.toString(); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.instruction; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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()) + ";"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.instruction; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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() + ";"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,78 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.instruction.framebuffer; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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() + ";"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,66 @@ | ||||
| package net.sourceforge.guacamole.instruction.framebuffer; | ||||
|  | ||||
| import net.sourceforge.guacamole.net.Base64; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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()) + ";"; | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.instruction.framebuffer; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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()) + ";"; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,95 @@ | ||||
| package net.sourceforge.guacamole.instruction.framebuffer; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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<ImageWriter> 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(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,65 @@ | ||||
| package net.sourceforge.guacamole.instruction.framebuffer; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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()) + ";"; | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,66 @@ | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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(); | ||||
|          | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,130 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,65 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import javax.servlet.ServletContext; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
|  | ||||
| public class GuacamoleConfiguration extends Configuration { | ||||
|  | ||||
|     private String password; | ||||
|     private int outputBPP; | ||||
|     private boolean compressStream; | ||||
|     private String protocol; | ||||
|     private boolean swapRedAndBlue; | ||||
|  | ||||
|     public GuacamoleConfiguration(ServletContext context) throws GuacamoleException { | ||||
|  | ||||
|         super(context); | ||||
|  | ||||
|         password       = context.getInitParameter("password"); | ||||
|         outputBPP      = readIntParameter("output-bpp", 8, 8, 24); | ||||
|         compressStream = readBooleanParameter("compress-stream", false); | ||||
|         protocol       = readParameter("protocol", "vnc", "vnc"); | ||||
|         swapRedAndBlue = readBooleanParameter("swap-red-blue", false); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public int getOutputBPP() { | ||||
|         return outputBPP; | ||||
|     } | ||||
|  | ||||
|     public String getPassword() { | ||||
|         return password; | ||||
|     } | ||||
|  | ||||
|     public boolean getCompressStream() { | ||||
|         return compressStream; | ||||
|     } | ||||
|  | ||||
|     public String getProtocol() { | ||||
|         return protocol; | ||||
|     } | ||||
|  | ||||
|     public boolean getSwapRedAndBlue() { | ||||
|         return swapRedAndBlue; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,62 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,171 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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.GuacamoleException; | ||||
| import net.sourceforge.guacamole.instruction.Instruction; | ||||
| import net.sourceforge.guacamole.event.KeyEvent; | ||||
| import net.sourceforge.guacamole.event.PointerEvent; | ||||
| import net.sourceforge.guacamole.vnc.VNCClient; | ||||
| import net.sourceforge.guacamole.vnc.VNCConfiguration; | ||||
| import net.sourceforge.guacamole.vnc.VNCException; | ||||
|  | ||||
| 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 send(KeyEvent event) throws GuacamoleException { | ||||
|             client.send(event); | ||||
|         } | ||||
|  | ||||
|         public void send(PointerEvent event) throws GuacamoleException { | ||||
|             client.send(event); | ||||
|         } | ||||
|  | ||||
|         public void setClipboard(String clipboard) throws GuacamoleException { | ||||
|             client.setClipboard(clipboard); | ||||
|         } | ||||
|  | ||||
|         public void disconnect() throws GuacamoleException { | ||||
|             client.disconnect(); | ||||
|         } | ||||
|  | ||||
|         public Instruction nextInstruction(boolean blocking) throws GuacamoleException { | ||||
|             return client.nextInstruction(blocking); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
|  | ||||
|  | ||||
|             String protocol = config.getProtocol(); | ||||
|             if (protocol.equals("vnc")) { | ||||
|  | ||||
|                 // Connect to VNC server | ||||
|                 try { | ||||
|  | ||||
|                     // Read VNC-specific parameters | ||||
|                     ServletContext context = session.getServletContext(); | ||||
|                     VNCConfiguration vncconfig = new VNCConfiguration(context); | ||||
|  | ||||
|                     client = new SessionClient( | ||||
|                             new VNCClient( | ||||
|                                 vncconfig.getHostname(), | ||||
|                                 vncconfig.getPort(), | ||||
|                                 vncconfig.getPassword(), | ||||
|                                 vncconfig.getBPP(), | ||||
|                                 config.getOutputBPP(), | ||||
|                                 config.getSwapRedAndBlue() | ||||
|                             ) | ||||
|                     ); | ||||
|  | ||||
|                 } | ||||
|                 catch (VNCException e) { | ||||
|                     throw new GuacamoleException(e); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|             else | ||||
|                 throw new GuacamoleException("Unsupported protocol: " + protocol); | ||||
|  | ||||
|             session.setAttribute("CLIENT", client); | ||||
|  | ||||
|             instructionStreamLock = new ReentrantLock(); | ||||
|             session.setAttribute("INSTRUCTION_STREAM_LOCK", instructionStreamLock); | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
|     } | ||||
|  | ||||
|     public ReentrantLock getInstructionStreamLock() { | ||||
|         return instructionStreamLock; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,132 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
| package net.sourceforge.guacamole.net.control; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import javax.servlet.ServletRequest; | ||||
|  | ||||
| import org.w3c.dom.Element; | ||||
|  | ||||
| import net.sourceforge.guacamole.net.XMLGuacamoleServlet; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.net.GuacamoleSession; | ||||
|  | ||||
| public class Connect extends XMLGuacamoleServlet { | ||||
|     | ||||
|     protected boolean shouldCreateSession() { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException { | ||||
|  | ||||
|         try { | ||||
|             session.connect(); | ||||
|         } | ||||
|         catch (GuacamoleException e) { | ||||
|             throw new GuacamoleException("Error connecting to server: " + e.getMessage(), e); | ||||
|         } | ||||
|  | ||||
|     }  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,43 @@ | ||||
| package net.sourceforge.guacamole.net.control; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import javax.servlet.ServletRequest; | ||||
|  | ||||
| import org.w3c.dom.Element; | ||||
|  | ||||
| import net.sourceforge.guacamole.net.XMLGuacamoleServlet; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.net.GuacamoleSession; | ||||
|  | ||||
| public class Disconnect extends XMLGuacamoleServlet { | ||||
|     | ||||
|     @Override | ||||
|     protected void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException { | ||||
|  | ||||
|         try { | ||||
|             session.disconnect(); // Disconnect client. | ||||
|         } | ||||
|         catch (GuacamoleException e) { | ||||
|             throw new GuacamoleException("Error disconnecting from VNC server: " + e.getMessage(), e); | ||||
|         } | ||||
|  | ||||
|     }  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,69 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net.input; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import javax.servlet.ServletRequest; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import org.w3c.dom.Element; | ||||
|  | ||||
| import net.sourceforge.guacamole.net.GuacamoleSession; | ||||
| import net.sourceforge.guacamole.net.XMLGuacamoleServlet; | ||||
| import net.sourceforge.guacamole.vnc.VNCException; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
|  | ||||
| /** | ||||
|  * Servlet which sets the VNC 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 { | ||||
|  | ||||
|         try { | ||||
|  | ||||
|             // Read data from request body | ||||
|             Reader reader = request.getReader(); | ||||
|             StringBuilder data = new StringBuilder(); | ||||
|  | ||||
|             int codepoint; | ||||
|             while ((codepoint = reader.read()) != -1) | ||||
|                 data.appendCodePoint(codepoint); | ||||
|  | ||||
|             // Set clipboard | ||||
|             session.getClient().setClipboard(data.toString()); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleException("I/O error sending clipboard to server: " + e.getMessage(), e); | ||||
|         } | ||||
|         catch (GuacamoleException e) { | ||||
|             throw new GuacamoleException("Error sending clipboard to server: " + e.getMessage(), e); | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,67 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net.input; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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; | ||||
| import net.sourceforge.guacamole.vnc.VNCException; | ||||
|  | ||||
| /** | ||||
|  * Servlet which accepts keyboard input events, forwards these events to the | ||||
|  * VNC 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); | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,64 @@ | ||||
| package net.sourceforge.guacamole.net.input; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| 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; | ||||
| import net.sourceforge.guacamole.vnc.VNCException; | ||||
|  | ||||
| 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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,130 @@ | ||||
| package net.sourceforge.guacamole.net.output; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import java.io.OutputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| 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; | ||||
| 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 { | ||||
|  | ||||
|     @Override | ||||
|     protected void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException { | ||||
|  | ||||
|         ReentrantLock instructionStreamLock = session.getInstructionStreamLock(); | ||||
|         instructionStreamLock.lock(); | ||||
|  | ||||
|         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; | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|  | ||||
|             try { | ||||
|  | ||||
|                 // Query new update from VNC server | ||||
|                 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) { | ||||
|  | ||||
|                     // Get message output bytes | ||||
|                     byte[] outputBytes = message.toString().getBytes("UTF-8"); | ||||
|                     out.write(outputBytes); | ||||
|                     out.flush(); | ||||
|                     response.flushBuffer(); | ||||
|  | ||||
|                     // No more messages another stream can take over | ||||
|                     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.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(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,63 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.vnc; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.LinkedList; | ||||
|  | ||||
| public class InputOutputStream extends InputStream { | ||||
|  | ||||
|     private int pos = 0; | ||||
|     private byte[] current = null; | ||||
|     private LinkedList<byte[]> buffer = new LinkedList<byte[]>(); | ||||
|  | ||||
|     public void write(byte[] data) { | ||||
|  | ||||
|         if (data.length == 0) | ||||
|             return; | ||||
|  | ||||
|         if (current == null) | ||||
|             current = data; | ||||
|         else | ||||
|             buffer.addLast(data); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int read() throws IOException { | ||||
|  | ||||
|         if (pos >= current.length) { | ||||
|             if (buffer.size() == 0) | ||||
|                 throw new IOException("Buffer underrun."); | ||||
|  | ||||
|             current = buffer.removeFirst(); | ||||
|             pos = 0; | ||||
|         } | ||||
|  | ||||
|         return 0xFF & current[pos++]; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int read(byte[] data) throws IOException { | ||||
|         return read(data, 0, data.length); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int read(byte[] data, int off, int len) throws IOException { | ||||
|  | ||||
|         if (pos >= current.length) { | ||||
|             if (buffer.size() == 0) | ||||
|                 throw new IOException("Buffer underrun."); | ||||
|  | ||||
|             current = buffer.removeFirst(); | ||||
|             pos = 0; | ||||
|         } | ||||
|  | ||||
|         int amountRead = Math.min(current.length - pos, len); | ||||
|         System.arraycopy(current, pos, data, off, amountRead); | ||||
|         pos += amountRead; | ||||
|  | ||||
|         return amountRead; | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										1113
									
								
								guacamole/client/src/net/sourceforge/guacamole/vnc/VNCClient.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1113
									
								
								guacamole/client/src/net/sourceforge/guacamole/vnc/VNCClient.java
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,60 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.vnc; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import net.sourceforge.guacamole.net.Configuration; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import javax.servlet.ServletContext; | ||||
|  | ||||
| public class VNCConfiguration extends Configuration { | ||||
|  | ||||
|     private String hostname; | ||||
|     private int port; | ||||
|     private String password; | ||||
|     private int bpp; | ||||
|  | ||||
|     public VNCConfiguration(ServletContext context) throws GuacamoleException { | ||||
|  | ||||
|         super(context); | ||||
|  | ||||
|         hostname       = readParameter("host", null); | ||||
|         port           = readIntParameter("port", null); | ||||
|         password  = context.getInitParameter("password"); | ||||
|         bpp = readIntParameter("bpp", 24, 8, 16, 24); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public int getBPP() { | ||||
|         return bpp; | ||||
|     } | ||||
|  | ||||
|     public String getPassword() { | ||||
|         return password; | ||||
|     } | ||||
|  | ||||
|     public String getHostname() { | ||||
|         return hostname; | ||||
|     } | ||||
|  | ||||
|     public int getPort() { | ||||
|         return port; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,32 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.vnc; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| public class VNCException extends Exception { | ||||
|  | ||||
|     public VNCException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     public VNCException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,239 @@ | ||||
| package net.sourceforge.guacamole.vnc; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import java.awt.image.BufferedImage; | ||||
| import java.awt.image.IndexColorModel; | ||||
| import java.io.DataInputStream; | ||||
| import java.io.IOException; | ||||
|  | ||||
|  | ||||
| public class VNCFullColorImageReader extends VNCImageReader { | ||||
|  | ||||
|     private int bpp; | ||||
|     private int depth; | ||||
|  | ||||
|     private int redBits; | ||||
|     private int greenBits; | ||||
|     private int blueBits; | ||||
|  | ||||
|     private int redMax; | ||||
|     private int greenMax; | ||||
|     private int blueMax; | ||||
|  | ||||
|     private int redShift; | ||||
|     private int greenShift; | ||||
|     private int blueShift; | ||||
|  | ||||
|     private boolean readAsIndexed; | ||||
|     private boolean bigEndian; | ||||
|  | ||||
|     private boolean swapRedAndBlue; | ||||
|  | ||||
|     public boolean isBigEndian() { | ||||
|         return bigEndian; | ||||
|     } | ||||
|  | ||||
|     public int getBitsPerPixel() { | ||||
|         return bpp; | ||||
|     } | ||||
|  | ||||
|     public int getDepth() { | ||||
|         return depth; | ||||
|     } | ||||
|  | ||||
|     public int getRedMax() { | ||||
|         return redMax; | ||||
|     } | ||||
|  | ||||
|     public int getGreenMax() { | ||||
|         return greenMax; | ||||
|     } | ||||
|  | ||||
|     public int getBlueMax() { | ||||
|         return blueMax; | ||||
|     } | ||||
|  | ||||
|     public int getRedShift() { | ||||
|         return redShift; | ||||
|     } | ||||
|  | ||||
|     public int getGreenShift() { | ||||
|         return greenShift; | ||||
|     } | ||||
|  | ||||
|     public int getBlueShift() { | ||||
|         return blueShift; | ||||
|     } | ||||
|  | ||||
|     // Set up BGR reader | ||||
|     public VNCFullColorImageReader(boolean bigEndian, int redBits, int greenBits, int blueBits, int outputBPP, boolean swapRedAndBlue) throws VNCException { | ||||
|          | ||||
|         this.swapRedAndBlue = swapRedAndBlue; | ||||
|  | ||||
|         depth = redBits + greenBits + blueBits; | ||||
|  | ||||
|         if (depth > 0 && depth <= 8) | ||||
|             bpp = 8; | ||||
|         else if (depth <= 16) | ||||
|             bpp = 16; | ||||
|         else if (depth <= 32) | ||||
|             bpp = 32; | ||||
|         else | ||||
|             throw new VNCException("Illegal bit depth for VNC images: " + bpp); | ||||
|  | ||||
|         this.redBits = redBits; | ||||
|         this.greenBits = greenBits; | ||||
|         this.blueBits = blueBits; | ||||
|  | ||||
|         blueMax  = (1 << blueBits)  - 1; | ||||
|         greenMax = (1 << greenBits) - 1; | ||||
|         redMax   = (1 << redBits)   - 1; | ||||
|  | ||||
|         redShift = greenBits + blueBits; | ||||
|         greenShift = blueBits; | ||||
|         blueShift  = 0; | ||||
|  | ||||
|         if (outputBPP == 8) | ||||
|             this.readAsIndexed = true; | ||||
|         else if (outputBPP == 24) | ||||
|             this.readAsIndexed = false; | ||||
|         else | ||||
|             throw new VNCException("Only 8-bit or 24-bit output is supported."); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int readCPixel(DataInputStream input) throws IOException { | ||||
|  | ||||
|         if (redBits != 8 || greenBits != 8 || blueBits != 8) | ||||
|             return readPixel(input); | ||||
|  | ||||
|         int red; | ||||
|         int green; | ||||
|         int blue; | ||||
|  | ||||
|         if (bigEndian) { | ||||
|             red   = input.read(); | ||||
|             green = input.read(); | ||||
|             blue  = input.read(); | ||||
|         } | ||||
|         else { | ||||
|             blue  = input.read(); | ||||
|             green = input.read(); | ||||
|             red   = input.read(); | ||||
|         } | ||||
|  | ||||
|         if (swapRedAndBlue) | ||||
|             return (blue << 16) | (green << 8) | red; | ||||
|         else | ||||
|             return (red << 16) | (green << 8) | blue; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int readPixel(DataInputStream input) throws IOException { | ||||
|         int value; | ||||
|         switch (bpp) { | ||||
|             case 8: | ||||
|                 value = input.read(); | ||||
|                 break; | ||||
|             case 16: | ||||
|  | ||||
|                 short inputShort = input.readShort(); | ||||
|                 if (!bigEndian) inputShort = Short.reverseBytes(inputShort); | ||||
|  | ||||
|                 value = inputShort; | ||||
|                 break; | ||||
|             case 32: | ||||
|  | ||||
|                 int inputInt = input.readInt(); | ||||
|                 if (!bigEndian) inputInt = Integer.reverseBytes(inputInt); | ||||
|  | ||||
|                 value = inputInt; | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new IOException("Invalid BPP."); | ||||
|         } | ||||
|  | ||||
|         int red   = (value >> redShift)   & redMax; | ||||
|         int green = (value >> greenShift) & greenMax; | ||||
|         int blue  = (value >> blueShift)  & blueMax; | ||||
|  | ||||
|         red   <<= 8 - redBits; | ||||
|         green <<= 8 - greenBits; | ||||
|         blue  <<= 8 - blueBits; | ||||
|  | ||||
|         if (swapRedAndBlue) | ||||
|             return (blue << 16) | (green << 8) | red; | ||||
|         else | ||||
|             return (red << 16) | (green << 8) | blue; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BufferedImage generateBlankImage(int width, int height) { | ||||
|         if (readAsIndexed) | ||||
|             return new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED, COLOR_MODEL); | ||||
|         return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); | ||||
|     } | ||||
|  | ||||
|     // Load color model | ||||
|     public static final IndexColorModel COLOR_MODEL; | ||||
|     static { | ||||
|         // Construct color model | ||||
|         byte[] colorShade = {0, (byte) 51, (byte) 104, (byte) 153, (byte) 204, (byte) 255}; | ||||
|         byte[] greyShade = new byte[39]; | ||||
|         for (int i=1; i<40; i++) | ||||
|             greyShade[i-1] = (byte) (6*i); | ||||
|  | ||||
|         byte[] red = new byte[colorShade.length*colorShade.length*colorShade.length+greyShade.length+1]; | ||||
|         byte[] green = new byte[colorShade.length*colorShade.length*colorShade.length+greyShade.length+1]; | ||||
|         byte[] blue = new byte[colorShade.length*colorShade.length*colorShade.length+greyShade.length+1]; | ||||
|         byte[] alpha = new byte[colorShade.length*colorShade.length*colorShade.length+greyShade.length+1]; | ||||
|  | ||||
|         int color = 0; | ||||
|         for (int r=0; r<colorShade.length; r++) { | ||||
|             for (int g=0; g<colorShade.length; g++) { | ||||
|                 for (int b=0; b<colorShade.length; b++) { | ||||
|                     red[color] = colorShade[r]; | ||||
|                     green[color] = colorShade[g]; | ||||
|                     blue[color] = colorShade[b]; | ||||
|                     alpha[color] = (byte) 255; | ||||
|                     color++; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (int grey=0; grey<greyShade.length; grey++) { | ||||
|             red[color] = greyShade[grey]; | ||||
|             green[color] = greyShade[grey]; | ||||
|             blue[color] = greyShade[grey]; | ||||
|             alpha[color] = (byte) 255; | ||||
|             color++; | ||||
|         } | ||||
|  | ||||
|         red[color] = 0; | ||||
|         green[color] = 0; | ||||
|         blue[color] = 0; | ||||
|         alpha[color] = (byte) 0; | ||||
|  | ||||
|         COLOR_MODEL = new IndexColorModel(8, 256, red, green, blue, alpha); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,64 @@ | ||||
| package net.sourceforge.guacamole.vnc; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import java.awt.image.BufferedImage; | ||||
| import java.io.DataInputStream; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public abstract class VNCImageReader { | ||||
|  | ||||
|     public BufferedImage readCImage(DataInputStream input, int width, int height) throws IOException { | ||||
|  | ||||
|         BufferedImage image = generateBlankImage(width, height); | ||||
|         // Read image | ||||
|  | ||||
|         for (int pixelY=0; pixelY<height; pixelY++) { | ||||
|             for (int pixelX=0; pixelX<width; pixelX++) { | ||||
|                 int color = 0xFF000000 | readCPixel(input); | ||||
|                 image.setRGB(pixelX, pixelY, color); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return image; | ||||
|     } | ||||
|  | ||||
|     public BufferedImage readImage(DataInputStream input, int width, int height) throws IOException { | ||||
|  | ||||
|         BufferedImage image = generateBlankImage(width, height); | ||||
|         // Read image | ||||
|  | ||||
|         for (int pixelY=0; pixelY<height; pixelY++) { | ||||
|             for (int pixelX=0; pixelX<width; pixelX++) { | ||||
|                 int color = 0xFF000000 | readPixel(input); | ||||
|                 image.setRGB(pixelX, pixelY, color); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return image; | ||||
|     } | ||||
|  | ||||
|     public abstract BufferedImage generateBlankImage(int width, int height); | ||||
|     public abstract int readPixel(DataInputStream input) throws IOException; | ||||
|     public int readCPixel(DataInputStream input) throws IOException { | ||||
|         return readPixel(input); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,104 @@ | ||||
| package net.sourceforge.guacamole.vnc; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| import java.awt.image.BufferedImage; | ||||
| import java.awt.image.IndexColorModel; | ||||
| import java.io.DataInputStream; | ||||
| import java.io.IOException; | ||||
|  | ||||
|  | ||||
| public class VNCIndexedImageReader extends VNCImageReader { | ||||
|  | ||||
|     private IndexColorModel palette; | ||||
|     private byte[] red; | ||||
|     private byte[] green; | ||||
|     private byte[] blue; | ||||
|  | ||||
|     // Set up BGR reader | ||||
|     public VNCIndexedImageReader(byte[] red, byte[] green, byte[] blue) throws VNCException { | ||||
|  | ||||
|         this.red = red; | ||||
|         this.green = green; | ||||
|         this.blue = blue; | ||||
|  | ||||
|         palette = new IndexColorModel(8, 256, red, green, blue); | ||||
|         if (palette.getMapSize() != 256) | ||||
|             throw new VNCException("Currently, only 256-color maps are supported."); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int readPixel(DataInputStream input) throws IOException { | ||||
|         int value = input.read(); | ||||
|         int color = (red[value] << 16) | (green[value] << 8) | blue[value]; | ||||
|         return color; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BufferedImage generateBlankImage(int width, int height) { | ||||
|         BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED, palette); | ||||
|         return image; | ||||
|     } | ||||
|  | ||||
|     // Load color model | ||||
|     public static final IndexColorModel COLOR_MODEL; | ||||
|     static { | ||||
|         // Construct color model | ||||
|         byte[] colorShade = {0, (byte) 51, (byte) 104, (byte) 153, (byte) 204, (byte) 255}; | ||||
|         byte[] greyShade = new byte[39]; | ||||
|         for (int i=1; i<40; i++) | ||||
|             greyShade[i-1] = (byte) (6*i); | ||||
|  | ||||
|         byte[] red = new byte[colorShade.length*colorShade.length*colorShade.length+greyShade.length+1]; | ||||
|         byte[] green = new byte[colorShade.length*colorShade.length*colorShade.length+greyShade.length+1]; | ||||
|         byte[] blue = new byte[colorShade.length*colorShade.length*colorShade.length+greyShade.length+1]; | ||||
|         byte[] alpha = new byte[colorShade.length*colorShade.length*colorShade.length+greyShade.length+1]; | ||||
|  | ||||
|         int color = 0; | ||||
|         for (int r=0; r<colorShade.length; r++) { | ||||
|             for (int g=0; g<colorShade.length; g++) { | ||||
|                 for (int b=0; b<colorShade.length; b++) { | ||||
|                     red[color] = colorShade[r]; | ||||
|                     green[color] = colorShade[g]; | ||||
|                     blue[color] = colorShade[b]; | ||||
|                     alpha[color] = (byte) 255; | ||||
|                     color++; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (int grey=0; grey<greyShade.length; grey++) { | ||||
|             red[color] = greyShade[grey]; | ||||
|             green[color] = greyShade[grey]; | ||||
|             blue[color] = greyShade[grey]; | ||||
|             alpha[color] = (byte) 255; | ||||
|             color++; | ||||
|         } | ||||
|  | ||||
|         red[color] = 0; | ||||
|         green[color] = 0; | ||||
|         blue[color] = 0; | ||||
|         alpha[color] = (byte) 0; | ||||
|  | ||||
|         COLOR_MODEL = new IndexColorModel(8, 256, red, green, blue, alpha); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user