/* Rdp.java
* Component: ProperJavaRDP
*
* Revision: $Revision: 1.6 $
* Author: $Author: telliott $
* Date: $Date: 2005/09/27 14:15:39 $
*
* Copyright (c) 2005 Propero Limited
*
* Purpose: Rdp layer of communication
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* (See gpl.txt for details of the GNU General Public License.)
*
*/
package org.jopenray.rdp;
import java.awt.Cursor;
import java.awt.Image;
import java.awt.image.IndexColorModel;
import java.io.EOFException;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.NoRouteToHostException;
import java.net.UnknownHostException;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.jopenray.adapter.RDPAdapter;
import org.jopenray.rdp.crypto.CryptoException;
import org.jopenray.rdp.rdp5.VChannels;
public class Rdp {
public static int RDP5_DISABLE_NOTHING = 0x00;
public static int RDP5_NO_WALLPAPER = 0x01;
public static int RDP5_NO_FULLWINDOWDRAG = 0x02;
public static int RDP5_NO_MENUANIMATIONS = 0x04;
public static int RDP5_NO_THEMING = 0x08;
public static int RDP5_NO_CURSOR_SHADOW = 0x20;
public static int RDP5_NO_CURSORSETTINGS = 0x40; /*
* disables cursor blinking
*/
protected static Logger logger = Logger.getLogger(Rdp.class);
/* constants for RDP Layer */
public static final int RDP_LOGON_NORMAL = 0x33;
public static final int RDP_LOGON_AUTO = 0x8;
public static final int RDP_LOGON_BLOB = 0x100;
// PDU Types
private static final int RDP_PDU_DEMAND_ACTIVE = 1;
private static final int RDP_PDU_CONFIRM_ACTIVE = 3;
private static final int RDP_PDU_DEACTIVATE = 6;
private static final int RDP_PDU_DATA = 7;
// Data PDU Types
private static final int RDP_DATA_PDU_UPDATE = 2;
private static final int RDP_DATA_PDU_CONTROL = 20;
private static final int RDP_DATA_PDU_POINTER = 27;
private static final int RDP_DATA_PDU_INPUT = 28;
private static final int RDP_DATA_PDU_SYNCHRONISE = 31;
private static final int RDP_DATA_PDU_BELL = 34;
private static final int RDP_DATA_PDU_LOGON = 38;
private static final int RDP_DATA_PDU_FONT2 = 39;
private static final int RDP_DATA_PDU_DISCONNECT = 47;
// Control PDU types
private static final int RDP_CTL_REQUEST_CONTROL = 1;
private static final int RDP_CTL_GRANT_CONTROL = 2;
private static final int RDP_CTL_DETACH = 3;
private static final int RDP_CTL_COOPERATE = 4;
// Update PDU Types
private static final int RDP_UPDATE_ORDERS = 0;
private static final int RDP_UPDATE_BITMAP = 1;
private static final int RDP_UPDATE_PALETTE = 2;
private static final int RDP_UPDATE_SYNCHRONIZE = 3;
// Pointer PDU Types
private static final int RDP_POINTER_SYSTEM = 1;
private static final int RDP_POINTER_MOVE = 3;
private static final int RDP_POINTER_COLOR = 6;
private static final int RDP_POINTER_CACHED = 7;
// System Pointer Types
private static final int RDP_NULL_POINTER = 0;
private static final int RDP_DEFAULT_POINTER = 0x7F00;
// Input Devices
private static final int RDP_INPUT_SYNCHRONIZE = 0;
private static final int RDP_INPUT_CODEPOINT = 1;
private static final int RDP_INPUT_VIRTKEY = 2;
private static final int RDP_INPUT_SCANCODE = 4;
private static final int RDP_INPUT_MOUSE = 0x8001;
/* RDP capabilities */
private static final int RDP_CAPSET_GENERAL = 1;
private static final int RDP_CAPLEN_GENERAL = 0x18;
private static final int OS_MAJOR_TYPE_UNIX = 4;
private static final int OS_MINOR_TYPE_XSERVER = 7;
private static final int RDP_CAPSET_BITMAP = 2;
private static final int RDP_CAPLEN_BITMAP = 0x1C;
private static final int RDP_CAPSET_ORDER = 3;
private static final int RDP_CAPLEN_ORDER = 0x58;
private static final int ORDER_CAP_NEGOTIATE = 2;
private static final int ORDER_CAP_NOSUPPORT = 4;
private static final int RDP_CAPSET_BMPCACHE = 4;
private static final int RDP_CAPLEN_BMPCACHE = 0x28;
private static final int RDP_CAPSET_CONTROL = 5;
private static final int RDP_CAPLEN_CONTROL = 0x0C;
private static final int RDP_CAPSET_ACTIVATE = 7;
private static final int RDP_CAPLEN_ACTIVATE = 0x0C;
private static final int RDP_CAPSET_POINTER = 8;
private static final int RDP_CAPLEN_POINTER = 0x08;
private static final int RDP_CAPSET_SHARE = 9;
private static final int RDP_CAPLEN_SHARE = 0x08;
private static final int RDP_CAPSET_COLCACHE = 10;
private static final int RDP_CAPLEN_COLCACHE = 0x08;
private static final int RDP_CAPSET_UNKNOWN = 13;
private static final int RDP_CAPLEN_UNKNOWN = 0x9C;
private static final int RDP_CAPSET_BMPCACHE2 = 19;
private static final int RDP_CAPLEN_BMPCACHE2 = 0x28;
private static final int BMPCACHE2_FLAG_PERSIST = (1 << 31);
/* RDP bitmap cache (version 2) constants */
public static final int BMPCACHE2_C0_CELLS = 0x78;
public static final int BMPCACHE2_C1_CELLS = 0x78;
public static final int BMPCACHE2_C2_CELLS = 0x150;
public static final int BMPCACHE2_NUM_PSTCELLS = 0x9f6;
private static final int RDP5_FLAG = 0x0030;
private static final byte[] RDP_SOURCE = { (byte) 0x4D, (byte) 0x53,
(byte) 0x54, (byte) 0x53, (byte) 0x43, (byte) 0x00 }; // string
// MSTSC
// encoded
// as 7 byte
// US-Ascii
protected Secure SecureLayer = null;
// private RdesktopFrame frame = null;
private RDPCanvas surface = null;
protected Orders orders = null;
private Cache cache = null;
private int next_packet = 0;
private int rdp_shareid = 0;
private boolean connected = false;
private RdpPacket_Localised stream = null;
private final byte[] canned_caps = { 0x01, 0x00, 0x00, 0x00, 0x09, 0x04,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00,
0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x34, 0x00,
(byte) 0xfe, 0x00, 0x04, 0x00, (byte) 0xfe, 0x00, 0x04, 0x00,
(byte) 0xFE, 0x00, 0x08, 0x00, (byte) 0xFE, 0x00, 0x08, 0x00,
(byte) 0xFE, 0x00, 0x10, 0x00, (byte) 0xFE, 0x00, 0x20, 0x00,
(byte) 0xFE, 0x00, 0x40, 0x00, (byte) 0xFE, 0x00, (byte) 0x80,
0x00, (byte) 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, 0x00,
0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00 };
static byte caps_0x0d[] = { 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static byte caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
static byte caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
static byte caps_0x10[] = { (byte) 0xFE, 0x00, 0x04, 0x00, (byte) 0xFE,
0x00, 0x04, 0x00, (byte) 0xFE, 0x00, 0x08, 0x00, (byte) 0xFE, 0x00,
0x08, 0x00, (byte) 0xFE, 0x00, 0x10, 0x00, (byte) 0xFE, 0x00, 0x20,
0x00, (byte) 0xFE, 0x00, 0x40, 0x00, (byte) 0xFE, 0x00,
(byte) 0x80, 0x00, (byte) 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
0x08, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00 };
/**
* Process a general capability set
*
* @param data
* Packet containing capability set data at current read position
*/
static void processGeneralCaps(RdpPacket_Localised data) {
int pad2octetsB; /* rdp5 flags? */
data.incrementPosition(10); // in_uint8s(s, 10);
pad2octetsB = data.getLittleEndian16(); // in_uint16_le(s, pad2octetsB);
if (pad2octetsB != 0)
Options.use_rdp5 = false;
}
/**
* Process a bitmap capability set
*
* @param data
* Packet containing capability set data at current read position
*/
static void processBitmapCaps(RdpPacket_Localised data) {
int width, height, bpp;
bpp = data.getLittleEndian16(); // in_uint16_le(s, bpp);
data.incrementPosition(6); // in_uint8s(s, 6);
width = data.getLittleEndian16(); // in_uint16_le(s, width);
height = data.getLittleEndian16(); // in_uint16_le(s, height);
logger.debug("setting desktop size and bpp to: " + width + "x" + height
+ "x" + bpp);
/*
* The server may limit bpp and change the size of the desktop (for
* example when shadowing another session).
*/
if (Options.server_bpp != bpp) {
logger.warn("colour depth changed from " + Options.server_bpp
+ " to " + bpp);
Options.server_bpp = bpp;
}
if (Options.width != width || Options.height != height) {
logger.warn("screen size changed from " + Options.width + "x"
+ Options.height + " to " + width + "x" + height);
Options.width = width;
Options.height = height;
// ui_resize_window(); TODO: implement resize thingy
}
}
/**
* Process server capabilities
*
* @param data
* Packet containing capability set data at current read position
*/
void processServerCaps(RdpPacket_Localised data, int length) {
int n;
int next, start;
int ncapsets, capset_type, capset_length;
start = data.getPosition();
ncapsets = data.getLittleEndian16(); // in_uint16_le(s, ncapsets);
data.incrementPosition(2); // in_uint8s(s, 2); /* pad */
for (n = 0; n < ncapsets; n++) {
if (data.getPosition() > start + length)
return;
capset_type = data.getLittleEndian16(); // in_uint16_le(s,
// capset_type);
capset_length = data.getLittleEndian16(); // in_uint16_le(s,
// capset_length);
next = data.getPosition() + capset_length - 4;
switch (capset_type) {
case RDP_CAPSET_GENERAL:
processGeneralCaps(data);
break;
case RDP_CAPSET_BITMAP:
processBitmapCaps(data);
break;
}
data.setPosition(next);
}
}
/**
* Process a disconnect PDU
*
* @param data
* Packet containing disconnect PDU at current read position
* @return Code specifying the reason for disconnection
*/
protected int processDisconnectPdu(RdpPacket_Localised data) {
logger.debug("Received disconnect PDU");
return data.getLittleEndian32();
}
/**
* Initialise RDP comms layer, and register virtual channels
*
* @param channels
* Virtual channels to be used in connection
*/
public Rdp(VChannels channels) {
this.SecureLayer = new Secure(channels);
Common.secure = SecureLayer;
this.orders = new Orders();
this.cache = new Cache();
orders.registerCache(cache);
}
/**
* Initialise a packet for sending data on the RDP layer
*
* @param size
* Size of RDP data
* @return Packet initialised for RDP
* @throws RdesktopException
*/
private RdpPacket_Localised initData(int size) throws RdesktopException {
RdpPacket_Localised buffer = null;
buffer = SecureLayer.init(
Constants.encryption ? Secure.SEC_ENCRYPT : 0, size + 18);
buffer.pushLayer(RdpPacket_Localised.RDP_HEADER, 18);
// buffer.setHeader(RdpPacket_Localised.RDP_HEADER);
// buffer.incrementPosition(18);
// buffer.setStart(buffer.getPosition());
return buffer;
}
/**
* Send a packet on the RDP layer
*
* @param data
* Packet to send
* @param data_pdu_type
* Type of data
* @throws RdesktopException
* @throws IOException
* @throws CryptoException
*/
private void sendData(RdpPacket_Localised data, int data_pdu_type)
throws RdesktopException, IOException, CryptoException {
CommunicationMonitor.lock(this);
int length;
data.setPosition(data.getHeader(RdpPacket_Localised.RDP_HEADER));
length = data.getEnd() - data.getPosition();
data.setLittleEndian16(length);
data.setLittleEndian16(RDP_PDU_DATA | 0x10);
data.setLittleEndian16(SecureLayer.getUserID() + 1001);
data.setLittleEndian32(this.rdp_shareid);
data.set8(0); // pad
data.set8(1); // stream id
data.setLittleEndian16(length - 14);
data.set8(data_pdu_type);
data.set8(0); // compression type
data.setLittleEndian16(0); // compression length
SecureLayer.send(data, Constants.encryption ? Secure.SEC_ENCRYPT : 0);
CommunicationMonitor.unlock(this);
}
/**
* Receive a packet from the RDP layer
*
* @param type
* Type of PDU received, stored in type[0]
* @return Packet received from RDP layer
* @throws IOException
* @throws RdesktopException
* @throws CryptoException
* @throws OrderException
*/
private RdpPacket_Localised receive(int[] type) throws IOException,
RdesktopException, CryptoException, OrderException {
int length = 0;
if ((this.stream == null) || (this.next_packet >= this.stream.getEnd())) {
this.stream = SecureLayer.receive();
if (stream == null)
return null;
this.next_packet = this.stream.getPosition();
} else {
this.stream.setPosition(this.next_packet);
}
length = this.stream.getLittleEndian16();
/* 32k packets are really 8, keepalive fix - rdesktop 1.2.0 */
if (length == 0x8000) {
logger.warn("32k packet keepalive fix");
next_packet += 8;
type[0] = 0;
return stream;
}
type[0] = this.stream.getLittleEndian16() & 0xf;
if (stream.getPosition() != stream.getEnd()) {
stream.incrementPosition(2);
}
this.next_packet += length;
return stream;
}
/**
* Connect to a server
*
* @param username
* Username for log on
* @param server
* Server to connect to
* @param flags
* Flags defining logon type
* @param domain
* Domain for log on
* @param password
* Password for log on
* @param command
* Alternative shell for session
* @param directory
* Initial working directory for connection
* @throws ConnectionException
*/
public void connect(String username, InetAddress server, int flags,
String domain, String password, String command, String directory)
throws ConnectionException {
try {
SecureLayer.connect(server);
this.connected = true;
this.sendLogonInfo(flags, domain, username, password, command,
directory);
}
// Handle an unresolvable hostname
catch (UnknownHostException e) {
throw new ConnectionException("Could not resolve host name: "
+ server);
}
// Handle a refused connection
catch (ConnectException e) {
throw new ConnectionException(
"Connection refused when trying to connect to " + server
+ " on port " + Options.port);
}
// Handle a timeout on connecting
catch (NoRouteToHostException e) {
throw new ConnectionException(
"Connection timed out when attempting to connect to "
+ server);
} catch (IOException e) {
throw new ConnectionException("Connection Failed");
} catch (RdesktopException e) {
e.printStackTrace();
throw new ConnectionException(e.getMessage());
} catch (OrderException e) {
throw new ConnectionException(e.getMessage());
} catch (CryptoException e) {
throw new ConnectionException(e.getMessage());
}
}
/**
* Disconnect from an RDP session
*/
public void disconnect() {
this.connected = false;
SecureLayer.disconnect();
}
/**
* Retrieve status of connection
*
* @return True if connection to RDP session
*/
public boolean isConnected() {
return this.connected;
}
boolean deactivated;
int ext_disc_reason;
/**
* RDP receive loop
*
* @param deactivated
* On return, stores true in deactivated[0] if the session
* disconnected cleanly
* @param ext_disc_reason
* On return, stores the reason for disconnection in
* ext_disc_reason[0]
* @param adapter
* @throws IOException
* @throws RdesktopException
* @throws OrderException
* @throws CryptoException
*/
public void mainLoop(boolean[] deactivated, int[] ext_disc_reason,
RDPAdapter adapter) throws IOException, RdesktopException,
OrderException, CryptoException {
int[] type = new int[1];
boolean disc = false; /* True when a disconnect PDU was received */
boolean cont = true;
RdpPacket_Localised data = null;
while (!adapter.isStopped()) {
try {
data = this.receive(type);
if (data == null)
return;
} catch (EOFException e) {
return;
}
switch (type[0]) {
case (Rdp.RDP_PDU_DEMAND_ACTIVE):
logger.debug("Rdp.RDP_PDU_DEMAND_ACTIVE");
// get this after licence negotiation, just before the 1st
// order...
NDC.push("processDemandActive");
this.processDemandActive(data);
// can use this to trigger things that have to be done before
// 1st order
logger.debug("ready to send (got past licence negotiation)");
// /////// FIXME: virer frame.triggerReadyToSend();
NDC.pop();
deactivated[0] = false;
break;
case (Rdp.RDP_PDU_DEACTIVATE):
// get this on log off
deactivated[0] = true;
this.stream = null; // ty this fix
break;
case (Rdp.RDP_PDU_DATA):
logger.debug("Rdp.RDP_PDU_DATA");
// all the others should be this
NDC.push("processData");
disc = this.processData(data, ext_disc_reason);
NDC.pop();
break;
case 0:
break; // 32K keep alive fix, see receive() - rdesktop 1.2.0.
default:
throw new RdesktopException("Unimplemented type in main loop :"
+ type[0]);
}
if (disc)
return;
}
return;
}
/**
* Send user logon details to the server
*
* @param flags
* Set of flags defining logon type
* @param domain
* Domain for logon
* @param username
* Username for logon
* @param password
* Password for logon
* @param command
* Alternative shell for session
* @param directory
* Starting working directory for session
* @throws RdesktopException
* @throws IOException
* @throws CryptoException
*/
private void sendLogonInfo(int flags, String domain, String username,
String password, String command, String directory)
throws RdesktopException, IOException, CryptoException {
//System.out.println("Rdp.sendLogonInfo():" + flags + ":" + domain + ":"
// + username + ":" + password + " c:" + command + " dir:"
// + directory);
// flags=59;
int len_ip = 2 * "127.0.0.1".length();
int len_dll = 2 * "C:\\WINNT\\System32\\mstscax.dll".length();
int packetlen = 0;
int sec_flags = Constants.encryption ? (Secure.SEC_LOGON_INFO | Secure.SEC_ENCRYPT)
: Secure.SEC_LOGON_INFO;
int domainlen = 2 * domain.length();
int userlen = 2 * username.length();
int passlen = 2 * password.length();
int commandlen = 2 * command.length();
int dirlen = 2 * directory.length();
RdpPacket_Localised data;
if (!Options.use_rdp5 || 1 == Options.server_rdp_version) {
logger.debug("Sending RDP4-style Logon packet");
data = SecureLayer.init(sec_flags, 18 + domainlen + userlen
+ passlen + commandlen + dirlen + 10);
data.setLittleEndian32(0);
data.setLittleEndian32(flags);
data.setLittleEndian16(domainlen);
data.setLittleEndian16(userlen);
data.setLittleEndian16(passlen);
data.setLittleEndian16(commandlen);
data.setLittleEndian16(dirlen);
data.outUnicodeString(domain, domainlen);
data.outUnicodeString(username, userlen);
data.outUnicodeString(password, passlen);
data.outUnicodeString(command, commandlen);
data.outUnicodeString(directory, dirlen);
} else {
flags |= RDP_LOGON_BLOB;
logger.debug("Sending RDP5-style Logon packet");
packetlen = 4
+ // Unknown uint32
4
+ // flags
2
+ // len_domain
2
+ // len_user
((flags & RDP_LOGON_AUTO) != 0 ? 2 : 0)
+ // len_password
((flags & RDP_LOGON_BLOB) != 0 ? 2 : 0)
+ // Length of BLOB
2
+ // len_program
2
+ // len_directory
(0 < domainlen ? domainlen + 2 : 2)
+ // domain
userlen
+ ((flags & RDP_LOGON_AUTO) != 0 ? passlen : 0)
+ 0
+ // We have no 512 byte BLOB. Perhaps we must?
((flags & RDP_LOGON_BLOB) != 0
&& (flags & RDP_LOGON_AUTO) == 0 ? 2 : 0)
+ (0 < commandlen ? commandlen + 2 : 2)
+ (0 < dirlen ? dirlen + 2 : 2) + 2 + // Unknown (2)
2 + // Client ip length
len_ip + // Client ip
2 + // DLL string length
len_dll + // DLL string
2 + // Unknown
2 + // Unknown
64 + // Time zone #0
20 + // Unknown
64 + // Time zone #1
32 + 6; // Unknown
data = SecureLayer.init(sec_flags, packetlen); // s =
// sec_init(sec_flags,
// packetlen);
// logger.debug("Called sec_init with packetlen " + packetlen);
data.setLittleEndian32(0); // out_uint32(s, 0); // Unknown
data.setLittleEndian32(flags); // out_uint32_le(s, flags);
data.setLittleEndian16(domainlen); // out_uint16_le(s, len_domain);
data.setLittleEndian16(userlen); // out_uint16_le(s, len_user);
if ((flags & RDP_LOGON_AUTO) != 0) {
data.setLittleEndian16(passlen); // out_uint16_le(s,
// len_password);
}
if ((flags & RDP_LOGON_BLOB) != 0
&& ((flags & RDP_LOGON_AUTO) == 0)) {
data.setLittleEndian16(0); // out_uint16_le(s, 0);
}
data.setLittleEndian16(commandlen); // out_uint16_le(s,
// len_program);
data.setLittleEndian16(dirlen); // out_uint16_le(s, len_directory);
if (0 < domainlen)
data.outUnicodeString(domain, domainlen); // rdp_out_unistr(s,
// domain,
// len_domain);
else
data.setLittleEndian16(0); // out_uint16_le(s, 0);
data.outUnicodeString(username, userlen); // rdp_out_unistr(s,
// user, len_user);
if ((flags & RDP_LOGON_AUTO) != 0) {
data.outUnicodeString(password, passlen); // rdp_out_unistr(s,
// password,
// len_password);
}
if ((flags & RDP_LOGON_BLOB) != 0 && (flags & RDP_LOGON_AUTO) == 0) {
data.setLittleEndian16(0); // out_uint16_le(s, 0);
}
if (0 < commandlen) {
data.outUnicodeString(command, commandlen); // rdp_out_unistr(s,
// program,
// len_program);
} else {
data.setLittleEndian16(0); // out_uint16_le(s, 0);
}
if (0 < dirlen) {
data.outUnicodeString(directory, dirlen); // rdp_out_unistr(s,
// directory,
// len_directory);
} else {
data.setLittleEndian16(0); // out_uint16_le(s, 0);
}
data.setLittleEndian16(2); // out_uint16_le(s, 2);
data.setLittleEndian16(len_ip + 2); // out_uint16_le(s, len_ip + 2);
// // Length of client ip
data.outUnicodeString("127.0.0.1", len_ip); // rdp_out_unistr(s,
// "127.0.0.1",
// len_ip);
data.setLittleEndian16(len_dll + 2); // out_uint16_le(s, len_dll
// + 2);
data.outUnicodeString("C:\\WINNT\\System32\\mstscax.dll", len_dll); // rdp_out_unistr(s,
// "C:\\WINNT\\System32\\mstscax.dll",
// len_dll);
data.setLittleEndian16(0xffc4); // out_uint16_le(s, 0xffc4);
data.setLittleEndian16(0xffff); // out_uint16_le(s, 0xffff);
data.outUnicodeString("GTB, normaltid", 2 * "GTB, normaltid"
.length()); // rdp_out_unistr(s, "GTB, normaltid", 2 *
// strlen("GTB, normaltid"));
data.incrementPosition(62 - 2 * "GTB, normaltid".length()); // out_uint8s(s,
// 62 -
// 2 *
// strlen("GTB,
// normaltid"));
data.setLittleEndian32(0x0a0000); // out_uint32_le(s, 0x0a0000);
data.setLittleEndian32(0x050000); // out_uint32_le(s, 0x050000);
data.setLittleEndian32(3); // out_uint32_le(s, 3);
data.setLittleEndian32(0); // out_uint32_le(s, 0);
data.setLittleEndian32(0); // out_uint32_le(s, 0);
data.outUnicodeString("GTB, sommartid", 2 * "GTB, sommartid"
.length()); // rdp_out_unistr(s, "GTB, sommartid", 2 *
// strlen("GTB, sommartid"));
data.incrementPosition(62 - 2 * "GTB, sommartid".length()); // out_uint8s(s,
// 62 -
// 2 *
// strlen("GTB,
// sommartid"));
data.setLittleEndian32(0x30000); // out_uint32_le(s, 0x30000);
data.setLittleEndian32(0x050000); // out_uint32_le(s, 0x050000);
data.setLittleEndian32(2); // out_uint32_le(s, 2);
data.setLittleEndian32(0); // out_uint32(s, 0);
data.setLittleEndian32(0xffffffc4); // out_uint32_le(s, 0xffffffc4);
data.setLittleEndian32(0xfffffffe); // out_uint32_le(s, 0xfffffffe);
data.setLittleEndian32(Options.rdp5_performanceflags); // out_uint32_le(s,
// 0x0f);
data.setLittleEndian32(0); // out_uint32(s, 0);
}
data.markEnd();
byte[] buffer = new byte[data.getEnd()];
data.copyToByteArray(buffer, 0, 0, data.getEnd());
SecureLayer.send(data, sec_flags);
}
/**
* Process an activation demand from the server (received between licence
* negotiation and 1st order)
*
* @param data
* Packet containing demand at current read position
* @throws RdesktopException
* @throws IOException
* @throws CryptoException
* @throws OrderException
*/
private void processDemandActive(RdpPacket_Localised data)
throws RdesktopException, IOException, CryptoException,
OrderException {
int type[] = new int[1];
this.rdp_shareid = data.getLittleEndian32();
this.sendConfirmActive();
this.sendSynchronize();
this.sendControl(RDP_CTL_COOPERATE);
this.sendControl(RDP_CTL_REQUEST_CONTROL);
this.receive(type); // Receive RDP_PDU_SYNCHRONIZE
this.receive(type); // Receive RDP_CTL_COOPERATE
this.receive(type); // Receive RDP_CTL_GRANT_CONTROL
this.sendInput(0, RDP_INPUT_SYNCHRONIZE, 0, 0, 0);
this.sendFonts(1);
this.sendFonts(2);
this.receive(type); // Receive an unknown PDU Code = 0x28
this.orders.resetOrderState();
}
/**
* Process a data PDU received from the server
*
* @param data
* Packet containing data PDU at current read position
* @param ext_disc_reason
* If a disconnect PDU is received, stores disconnection reason
* at ext_disc_reason[0]
* @return True if disconnect PDU was received
* @throws RdesktopException
* @throws OrderException
*/
private boolean processData(RdpPacket_Localised data, int[] ext_disc_reason)
throws RdesktopException, OrderException {
int data_type, ctype, clen, len, roff, rlen;
data_type = 0;
data.incrementPosition(6); // skip shareid, pad, streamid
len = data.getLittleEndian16();
data_type = data.get8();
ctype = data.get8(); // compression type
clen = data.getLittleEndian16(); // compression length
clen -= 18;
switch (data_type) {
case (Rdp.RDP_DATA_PDU_UPDATE):
logger.debug("Rdp.RDP_DATA_PDU_UPDATE");
this.processUpdate(data);
break;
case RDP_DATA_PDU_CONTROL:
logger.debug(("Received Control PDU\n"));
break;
case RDP_DATA_PDU_SYNCHRONISE:
logger.debug(("Received Sync PDU\n"));
break;
case (Rdp.RDP_DATA_PDU_POINTER):
logger.debug("Received pointer PDU");
this.processPointer(data);
break;
case (Rdp.RDP_DATA_PDU_BELL):
logger.debug("Received bell PDU");
// Toolkit tx = Toolkit.getDefaultToolkit();
// tx.beep();
System.err.println("beep");
break;
case (Rdp.RDP_DATA_PDU_LOGON):
logger.debug("User logged on");
break;
case RDP_DATA_PDU_DISCONNECT:
/*
* Normally received when user logs out or disconnects from a
* console session on Windows XP and 2003 Server
*/
ext_disc_reason[0] = processDisconnectPdu(data);
logger.debug(("Received disconnect PDU\n"));
break;
default:
logger.warn("Unimplemented Data PDU type " + data_type);
}
return false;
}
private void processUpdate(RdpPacket_Localised data) throws OrderException,
RdesktopException {
int update_type = 0;
update_type = data.getLittleEndian16();
switch (update_type) {
case (Rdp.RDP_UPDATE_ORDERS):
data.incrementPosition(2); // pad
int n_orders = data.getLittleEndian16();
data.incrementPosition(2); // pad
this.orders.processOrders(data, next_packet, n_orders);
break;
case (Rdp.RDP_UPDATE_BITMAP):
this.processBitmapUpdates(data);
break;
case (Rdp.RDP_UPDATE_PALETTE):
this.processPalette(data);
break;
case (Rdp.RDP_UPDATE_SYNCHRONIZE):
break;
default:
logger.warn("Unimplemented Update type " + update_type);
}
}
private void sendConfirmActive() throws RdesktopException, IOException,
CryptoException {
int caplen = RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER
+ RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE
+ RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + RDP_CAPLEN_POINTER
+ RDP_CAPLEN_SHARE + RDP_CAPLEN_UNKNOWN + 4; // this is a fix
// for W2k.
// Purpose
// unknown
int sec_flags = Options.encryption ? (RDP5_FLAG | Secure.SEC_ENCRYPT)
: RDP5_FLAG;
RdpPacket_Localised data = SecureLayer.init(sec_flags, 6 + 14 + caplen
+ RDP_SOURCE.length);
// RdpPacket_Localised data = this.init(14 + caplen +
// RDP_SOURCE.length);
data.setLittleEndian16(2 + 14 + caplen + RDP_SOURCE.length);
data.setLittleEndian16((RDP_PDU_CONFIRM_ACTIVE | 0x10));
data.setLittleEndian16(Common.mcs.getUserID() /* McsUserID() */+ 1001);
data.setLittleEndian32(this.rdp_shareid);
data.setLittleEndian16(0x3ea); // user id
data.setLittleEndian16(RDP_SOURCE.length);
data.setLittleEndian16(caplen);
data.copyFromByteArray(RDP_SOURCE, 0, data.getPosition(),
RDP_SOURCE.length);
data.incrementPosition(RDP_SOURCE.length);
data.setLittleEndian16(0xd); // num_caps
data.incrementPosition(2); // pad
this.sendGeneralCaps(data);
// ta.incrementPosition(this.RDP_CAPLEN_GENERAL);
this.sendBitmapCaps(data);
this.sendOrderCaps(data);
if (Options.use_rdp5 && Options.persistent_bitmap_caching) {
logger.info("Persistent caching enabled");
this.sendBitmapcache2Caps(data);
} else
this.sendBitmapcacheCaps(data);
this.sendColorcacheCaps(data);
this.sendActivateCaps(data);
this.sendControlCaps(data);
this.sendPointerCaps(data);
this.sendShareCaps(data);
// this.sendUnknownCaps(data);
this.sendUnknownCaps(data, 0x0d, 0x58, caps_0x0d); // rdp_out_unknown_caps(s,
// 0x0d, 0x58,
// caps_0x0d); /*
// international? */
this.sendUnknownCaps(data, 0x0c, 0x08, caps_0x0c); // rdp_out_unknown_caps(s,
// 0x0c, 0x08,
// caps_0x0c);
this.sendUnknownCaps(data, 0x0e, 0x08, caps_0x0e); // rdp_out_unknown_caps(s,
// 0x0e, 0x08,
// caps_0x0e);
this.sendUnknownCaps(data, 0x10, 0x34, caps_0x10); // rdp_out_unknown_caps(s,
// 0x10, 0x34,
// caps_0x10); /*
// glyph cache? */
data.markEnd();
logger.debug("confirm active");
// this.send(data, RDP_PDU_CONFIRM_ACTIVE);
Common.secure.send(data, sec_flags);
}
private void sendGeneralCaps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_GENERAL);
data.setLittleEndian16(RDP_CAPLEN_GENERAL);
data.setLittleEndian16(1); /* OS major type */
data.setLittleEndian16(3); /* OS minor type */
data.setLittleEndian16(0x200); /* Protocol version */
data.setLittleEndian16(Options.use_rdp5 ? 0x40d : 0);
// data.setLittleEndian16(Options.use_rdp5 ? 0x1d04 : 0); // this seems
/*
* Pad, according to T.128. 0x40d seems to trigger the server to start
* sending RDP5 packets. However, the value is 0x1d04 with W2KTSK and
* NT4MS. Hmm.. Anyway, thankyou, Microsoft, for sending such
* information in a padding field..
*/
data.setLittleEndian16(0); /* Compression types */
data.setLittleEndian16(0); /* Pad */
data.setLittleEndian16(0); /* Update capability */
data.setLittleEndian16(0); /* Remote unshare capability */
data.setLittleEndian16(0); /* Compression level */
data.setLittleEndian16(0); /* Pad */
}
private void sendBitmapCaps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_BITMAP);
data.setLittleEndian16(RDP_CAPLEN_BITMAP);
data.setLittleEndian16(Options.server_bpp); /* Preferred BPP */
data.setLittleEndian16(1); /* Receive 1 BPP */
data.setLittleEndian16(1); /* Receive 4 BPP */
data.setLittleEndian16(1); /* Receive 8 BPP */
data.setLittleEndian16(Options.width); /* Desktop width */
data.setLittleEndian16(Options.height); /* Desktop height */
data.setLittleEndian16(0); /* Pad */
data.setLittleEndian16(1); /* Allow resize */
data.setLittleEndian16(Options.bitmap_compression ? 1 : 0); /*
* Support
* compression
*/
data.setLittleEndian16(0); /* Unknown */
data.setLittleEndian16(1); /* Unknown */
data.setLittleEndian16(0); /* Pad */
}
private void sendOrderCaps(RdpPacket_Localised data) {
byte[] order_caps = new byte[32];
order_caps[0] = 1; /* dest blt */
order_caps[1] = 1; /* pat blt */// nb no rectangle orders if this is 0
order_caps[2] = 1; /* screen blt */
order_caps[3] = (byte) (Options.bitmap_caching ? 1 : 0); /* memblt */
order_caps[4] = 0; /* triblt */
order_caps[8] = 1; /* line */
order_caps[9] = 1; /* line */
order_caps[10] = 1; /* rect */
order_caps[11] = (Constants.desktop_save ? 1 : 0); /* desksave */
order_caps[13] = 1; /* memblt */
order_caps[14] = 1; /* triblt */
order_caps[20] = (byte) (Options.polygon_ellipse_orders ? 1 : 0); /* polygon */
order_caps[21] = (byte) (Options.polygon_ellipse_orders ? 1 : 0); /* polygon2 */
order_caps[22] = 1; /* polyline */
order_caps[25] = (byte) (Options.polygon_ellipse_orders ? 1 : 0); /* ellipse */
order_caps[26] = (byte) (Options.polygon_ellipse_orders ? 1 : 0); /* ellipse2 */
order_caps[27] = 1; /* text2 */
data.setLittleEndian16(RDP_CAPSET_ORDER);
data.setLittleEndian16(RDP_CAPLEN_ORDER);
data.incrementPosition(20); /* Terminal desc, pad */
data.setLittleEndian16(1); /* Cache X granularity */
data.setLittleEndian16(20); /* Cache Y granularity */
data.setLittleEndian16(0); /* Pad */
data.setLittleEndian16(1); /* Max order level */
data.setLittleEndian16(0x147); /* Number of fonts */
data.setLittleEndian16(0x2a); /* Capability flags */
data.copyFromByteArray(order_caps, 0, data.getPosition(), 32); /*
* Orders
* supported
*/
data.incrementPosition(32);
data.setLittleEndian16(0x6a1); /* Text capability flags */
data.incrementPosition(6); /* Pad */
data.setLittleEndian32(Constants.desktop_save ? 0x38400 : 0); /*
* Desktop
* cache
* size
*/
data.setLittleEndian32(0); /* Unknown */
data.setLittleEndian32(0x4e4); /* Unknown */
}
private void sendBitmapcacheCaps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_BMPCACHE);
data.setLittleEndian16(RDP_CAPLEN_BMPCACHE);
data.incrementPosition(24); /* unused */
data.setLittleEndian16(0x258); /* entries */
data.setLittleEndian16(0x100); /* max cell size */
data.setLittleEndian16(0x12c); /* entries */
data.setLittleEndian16(0x400); /* max cell size */
data.setLittleEndian16(0x106); /* entries */
data.setLittleEndian16(0x1000); /* max cell size */
}
/* Output bitmap cache v2 capability set */
private void sendBitmapcache2Caps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_BMPCACHE2); // out_uint16_le(s,
// RDP_CAPSET_BMPCACHE2);
data.setLittleEndian16(RDP_CAPLEN_BMPCACHE2); // out_uint16_le(s,
// RDP_CAPLEN_BMPCACHE2);
data.setLittleEndian16(Options.persistent_bitmap_caching ? 2 : 0); /* version */
data.setBigEndian16(3); /* number of caches in this set */
/* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
data.setLittleEndian32(BMPCACHE2_C0_CELLS); // out_uint32_le(s,
// BMPCACHE2_C0_CELLS);
data.setLittleEndian32(BMPCACHE2_C1_CELLS); // out_uint32_le(s,
// BMPCACHE2_C1_CELLS);
// data.setLittleEndian32(PstCache.pstcache_init(2) ?
// (BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST) :
// BMPCACHE2_C2_CELLS);
if (PstCache.pstcache_init(2)) {
logger.info("Persistent cache initialized");
data.setLittleEndian32(BMPCACHE2_NUM_PSTCELLS
| BMPCACHE2_FLAG_PERSIST);
} else {
logger.info("Persistent cache not initialized");
data.setLittleEndian32(BMPCACHE2_C2_CELLS);
}
data.incrementPosition(20); // out_uint8s(s, 20); /* other bitmap caches
// not used */
}
private void sendColorcacheCaps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_COLCACHE);
data.setLittleEndian16(RDP_CAPLEN_COLCACHE);
data.setLittleEndian16(6); /* cache size */
data.setLittleEndian16(0); /* pad */
}
private void sendActivateCaps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_ACTIVATE);
data.setLittleEndian16(RDP_CAPLEN_ACTIVATE);
data.setLittleEndian16(0); /* Help key */
data.setLittleEndian16(0); /* Help index key */
data.setLittleEndian16(0); /* Extended help key */
data.setLittleEndian16(0); /* Window activate */
}
private void sendControlCaps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_CONTROL);
data.setLittleEndian16(RDP_CAPLEN_CONTROL);
data.setLittleEndian16(0); /* Control capabilities */
data.setLittleEndian16(0); /* Remote detach */
data.setLittleEndian16(2); /* Control interest */
data.setLittleEndian16(2); /* Detach interest */
}
private void sendPointerCaps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_POINTER);
data.setLittleEndian16(RDP_CAPLEN_POINTER);
data.setLittleEndian16(0); /* Colour pointer */
data.setLittleEndian16(20); /* Cache size */
}
private void sendShareCaps(RdpPacket_Localised data) {
data.setLittleEndian16(RDP_CAPSET_SHARE);
data.setLittleEndian16(RDP_CAPLEN_SHARE);
data.setLittleEndian16(0); /* userid */
data.setLittleEndian16(0); /* pad */
}
private void sendUnknownCaps(RdpPacket_Localised data, int id, int length,
byte[] caps) {
data.setLittleEndian16(id /* RDP_CAPSET_UNKNOWN */);
data.setLittleEndian16(length /* 0x58 */);
data.copyFromByteArray(caps, 0, data.getPosition(), /* RDP_CAPLEN_UNKNOWN */
length - 4);
data.incrementPosition(/* RDP_CAPLEN_UNKNOWN */length - 4);
}
private void sendSynchronize() throws RdesktopException, IOException,
CryptoException {
RdpPacket_Localised data = this.initData(4);
data.setLittleEndian16(1); // type
data.setLittleEndian16(1002);
data.markEnd();
logger.debug("sync");
this.sendData(data, RDP_DATA_PDU_SYNCHRONISE);
}
private void sendControl(int action) throws RdesktopException, IOException,
CryptoException {
RdpPacket_Localised data = this.initData(8);
data.setLittleEndian16(action);
data.setLittleEndian16(0); // userid
data.setLittleEndian32(0); // control id
data.markEnd();
logger.debug("control");
this.sendData(data, RDP_DATA_PDU_CONTROL);
}
public void sendInput(int time, int message_type, int device_flags,
int param1, int param2) {
RdpPacket_Localised data = null;
try {
data = this.initData(16);
} catch (RdesktopException e) {
// Rdesktop.error(e, this, frame, false);
e.printStackTrace();
}
data.setLittleEndian16(1); /* number of events */
data.setLittleEndian16(0); /* pad */
data.setLittleEndian32(time);
data.setLittleEndian16(message_type);
data.setLittleEndian16(device_flags);
data.setLittleEndian16(param1);
data.setLittleEndian16(param2);
data.markEnd();
// logger.info("input");
// if(logger.isInfoEnabled()) logger.info(data);
try {
this.sendData(data, RDP_DATA_PDU_INPUT);
} catch (Exception e) {
e.printStackTrace();
}
}
private void sendFonts(int seq) throws RdesktopException, IOException,
CryptoException {
RdpPacket_Localised data = this.initData(8);
data.setLittleEndian16(0); /* number of fonts */
data.setLittleEndian16(0x3e); /* unknown */
data.setLittleEndian16(seq); /* unknown */
data.setLittleEndian16(0x32); /* entry size */
data.markEnd();
logger.debug("fonts");
this.sendData(data, RDP_DATA_PDU_FONT2);
}
private void processPointer(RdpPacket_Localised data)
throws RdesktopException {
int message_type = 0;
int x = 0, y = 0;
message_type = data.getLittleEndian16();
data.incrementPosition(2);
switch (message_type) {
case (Rdp.RDP_POINTER_MOVE):
logger.debug("Rdp.RDP_POINTER_MOVE");
x = data.getLittleEndian16();
y = data.getLittleEndian16();
if (data.getPosition() <= data.getEnd()) {
surface.movePointer(x, y);
}
break;
case (Rdp.RDP_POINTER_COLOR):
process_colour_pointer_pdu(data);
break;
case (Rdp.RDP_POINTER_CACHED):
process_cached_pointer_pdu(data);
break;
case RDP_POINTER_SYSTEM:
process_system_pointer_pdu(data);
break;
default:
break;
}
}
private void process_system_pointer_pdu(RdpPacket_Localised data) {
int system_pointer_type = 0;
data.getLittleEndian16(system_pointer_type); // in_uint16(s,
// system_pointer_type);
switch (system_pointer_type) {
case RDP_NULL_POINTER:
logger.debug("RDP_NULL_POINTER");
surface.setCursor(null);
break;
default:
logger.warn("Unimplemented system pointer message 0x"
+ Integer.toHexString(system_pointer_type));
// unimpl("System pointer message 0x%x\n", system_pointer_type);
}
}
protected void processBitmapUpdates(RdpPacket_Localised data)
throws RdesktopException {
// logger.info("processBitmapUpdates");
int n_updates = 0;
int left = 0, top = 0, right = 0, bottom = 0, width = 0, height = 0;
int cx = 0, cy = 0, bitsperpixel = 0, compression = 0, buffersize = 0, size = 0;
byte[] pixel = null;
int minX, minY, maxX, maxY;
maxX = maxY = 0;
minX = surface.getWidth();
minY = surface.getHeight();
n_updates = data.getLittleEndian16();
for (int i = 0; i < n_updates; i++) {
// System.err.println("Rdp.processBitmapUpdates()");
left = data.getLittleEndian16();
top = data.getLittleEndian16();
right = data.getLittleEndian16();
bottom = data.getLittleEndian16();
width = data.getLittleEndian16();
height = data.getLittleEndian16();
bitsperpixel = data.getLittleEndian16();
int Bpp = (bitsperpixel + 7) / 8;
compression = data.getLittleEndian16();
buffersize = data.getLittleEndian16();
cx = right - left + 1;
cy = bottom - top + 1;
if (minX > left)
minX = left;
if (minY > top)
minY = top;
if (maxX < right)
maxX = right;
if (maxY < bottom)
maxY = bottom;
/* Server may limit bpp - this is how we find out */
if (Options.server_bpp != bitsperpixel) {
logger.warn("Server limited colour depth to " + bitsperpixel
+ " bits");
Options.set_bpp(bitsperpixel);
}
if (compression == 0) {
// logger.info("compression == 0");
pixel = new byte[width * height * Bpp];
for (int y = 0; y < height; y++) {
data.copyToByteArray(pixel, (height - y - 1)
* (width * Bpp), data.getPosition(), width * Bpp);
data.incrementPosition(width * Bpp);
}
surface.displayImage(Bitmap.convertImage(pixel, Bpp), width,
height, left, top, cx, cy);
continue;
}
if ((compression & 0x400) != 0) {
// logger.info("compression & 0x400 != 0");
size = buffersize;
} else {
// logger.info("compression & 0x400 == 0");
data.incrementPosition(2); // pad
size = data.getLittleEndian16();
data.incrementPosition(4); // line size, final size
}
if (Bpp == 1) {
pixel = Bitmap.decompress(width, height, size, data, Bpp);
if (pixel != null)
surface.displayImage(Bitmap.convertImage(pixel, Bpp),
width, height, left, top, cx, cy);
else
logger.warn("Could not decompress bitmap");
} else {
if (Options.bitmap_decompression_store == Options.INTEGER_BITMAP_DECOMPRESSION) {
int[] pixeli = Bitmap.decompressInt(width, height, size,
data, Bpp);
if (pixeli != null)
surface.displayImage(pixeli, width, height, left, top,
cx, cy);
else
logger.warn("Could not decompress bitmap");
} else if (Options.bitmap_decompression_store == Options.BUFFEREDIMAGE_BITMAP_DECOMPRESSION) {
Image pix = Bitmap.decompressImg(width, height, size, data,
Bpp, null);
if (pix != null)
surface.displayImage(pix, left, top);
else
logger.warn("Could not decompress bitmap");
} else {
surface.displayCompressed(left, top, width, height, size,
data, Bpp, null);
}
}
}
// surface.repaint(minX, minY, maxX - minX + 1, maxY - minY + 1);
}
protected void processPalette(RdpPacket_Localised data) {
int n_colors = 0;
IndexColorModel cm = null;
byte[] palette = null;
byte[] red = null;
byte[] green = null;
byte[] blue = null;
int j = 0;
data.incrementPosition(2); // pad
n_colors = data.getLittleEndian16(); // Number of Colors in Palette
data.incrementPosition(2); // pad
palette = new byte[n_colors * 3];
red = new byte[n_colors];
green = new byte[n_colors];
blue = new byte[n_colors];
data.copyToByteArray(palette, 0, data.getPosition(), palette.length);
data.incrementPosition(palette.length);
for (int i = 0; i < n_colors; i++) {
red[i] = palette[j];
green[i] = palette[j + 1];
blue[i] = palette[j + 2];
j += 3;
}
cm = new IndexColorModel(8, n_colors, red, green, blue);
surface.registerPalette(cm);
}
/*public void registerDrawingSurface(RdesktopFrame fr) {
// this.frame = fr;
RDPCanvas ds = fr.getCanvas();
registerSurface(ds);
}*/
public void registerSurface(RDPCanvas ds) {
this.surface = ds;
orders.registerDrawingSurface(ds);
}
/* Process a null system pointer PDU */
protected void process_null_system_pointer_pdu(RdpPacket_Localised s)
throws RdesktopException {
// FIXME: We should probably set another cursor here,
// like the X window system base cursor or something.
surface.setCursor(cache.getCursor(0));
}
protected void process_colour_pointer_pdu(RdpPacket_Localised data)
throws RdesktopException {
logger.debug("Rdp.RDP_POINTER_COLOR");
int x = 0, y = 0, width = 0, height = 0, cache_idx = 0, masklen = 0, datalen = 0;
byte[] mask = null, pixel = null;
Cursor cursor = null;
cache_idx = data.getLittleEndian16();
x = data.getLittleEndian16();
y = data.getLittleEndian16();
width = data.getLittleEndian16();
height = data.getLittleEndian16();
masklen = data.getLittleEndian16();
datalen = data.getLittleEndian16();
mask = new byte[masklen];
pixel = new byte[datalen];
data.copyToByteArray(pixel, 0, data.getPosition(), datalen);
data.incrementPosition(datalen);
data.copyToByteArray(mask, 0, data.getPosition(), masklen);
data.incrementPosition(masklen);
cursor = surface.createCursor(x, y, width, height, mask, pixel,
cache_idx);
// logger.info("Creating and setting cursor " + cache_idx);
surface.setCursor(cursor);
cache.putCursor(cache_idx, cursor);
}
protected void process_cached_pointer_pdu(RdpPacket_Localised data)
throws RdesktopException {
logger.debug("Rdp.RDP_POINTER_CACHED");
int cache_idx = data.getLittleEndian16();
// logger.info("Setting cursor "+cache_idx);
surface.setCursorFromIdx(cache_idx);
}
}