gt: 		sendBerInteger(buffer, 1); // num_priorities
context: /* MCS.java
   * Component: ProperJavaRDP
   * 
   * Revision: $Revision: 1.1.1.1 $
   * Author: $Author: suvarov $
   * Date: $Date: 2007/03/08 00:26:14 $
   *
   * Copyright (c) 2005 Propero Limited
   *
   * Purpose: MCS Layer of communication
   */
  package com.lixia.rdp;
  
  import java.io.*;
  import java.net.*;
  
  import javax.swing.JPanel;
  
  import com.lixia.rdp.crypto.CryptoException;
  import com.lixia.rdp.rdp5.VChannels;
  
  import org.apache.log4j.Logger;
  
  public class MCS {
  	static Logger logger = Logger.getLogger("MCS");
  	private ISO IsoLayer = null;
  	private int McsUserID;
  
  	/* this for the MCS Layer */
  	private static final int CONNECT_INITIAL = 0x7f65;
  	private static final int CONNECT_RESPONSE = 0x7f66;
  
  	private static final int BER_TAG_BOOLEAN = 1;
  	private static final int BER_TAG_INTEGER = 2;
  	private static final int BER_TAG_OCTET_STRING = 4;
  	private static final int BER_TAG_RESULT = 10;
  	private static final int TAG_DOMAIN_PARAMS = 0x30;
  
  	public static final int MCS_GLOBAL_CHANNEL = 1003;
  	public static final int MCS_USERCHANNEL_BASE = 1001;
  
  	private static final int EDRQ = 1; /* Erect Domain Request */
  	private static final int DPUM = 8; /* Disconnect Provider Ultimatum */
  	private static final int AURQ = 10; /* Attach User Request */
  	private static final int AUCF = 11; /* Attach User Confirm */
  	private static final int CJRQ = 14; /* Channel Join Request */
  	private static final int CJCF = 15; /* Channel Join Confirm */
  	private static final int SDRQ = 25; /* Send Data Request */
  	private static final int SDIN = 26; /* Send Data Indication */
  
  	private VChannels channels;
  
  	/**
  	 * Initialise the MCS layer (and lower layers) with provided channels
  	 * @param channels Set of available MCS channels
  	 */
  	public MCS(VChannels channels) {
  		this.channels = channels;
  		IsoLayer = new ISO_Localised();
  	}
  
  	/**
  	 * Connect to a server
  	 * @param host Address of server
  	 * @param port Port to connect to on server
  	 * @param data Packet to use for sending connection data
  	 * @throws IOException
  	 * @throws RdesktopException
  	 * @throws OrderException
  	 * @throws CryptoException
  	 */
  	public void connect(InetAddress host, int port, RdpPacket_Localised data)
  			throws IOException, RdesktopException, OrderException,
  			CryptoException {
  		logger.debug("MCS.connect");
  		IsoLayer.connect(host, port);
  
  		this.sendConnectInitial(data);
  		this.receiveConnectResponse(data);
  
  		logger.debug("connect response received");
  
  		send_edrq();
  		send_aurq();
  
  		this.McsUserID = receive_aucf();
  		send_cjrq(this.McsUserID + MCS_USERCHANNEL_BASE);
  		receive_cjcf();
  		send_cjrq(MCS_GLOBAL_CHANNEL);
  		receive_cjcf();
  
  		for (int i = 0; i < channels.num_channels(); i++) {
  			send_cjrq(channels.mcs_id(i));
  			receive_cjcf();
  		}
  
  	}
  
  	/**
  	 * Disconnect from server
  	 *
  	 */
  	public void disconnect() {
  		IsoLayer.disconnect();
  		//in=null;
  		//out=null;
  	}
  
  	/**
  	 * Initialise a packet as an MCS PDU
  	 * @param length Desired length of PDU
  	 * @return
  	 * @throws RdesktopException
  	 */
  	public RdpPacket_Localised init(int length) throws RdesktopException {
  		RdpPacket_Localised data = IsoLayer.init(length + 8);
  		//data.pushLayer(RdpPacket_Localised.MCS_HEADER, 8);
  		data.setHeader(RdpPacket_Localised.MCS_HEADER);
  		data.incrementPosition(8);
  		data.setStart(data.getPosition());
  		return data;
  	}
  
  	/**
  	 * Send a packet to the global channel
  	 * @param buffer Packet to send
  	 * @throws RdesktopException
  	 * @throws IOException
  	 */
  	public void send(RdpPacket_Localised buffer) throws RdesktopException,
  			IOException {
  		send_to_channel(buffer, MCS_GLOBAL_CHANNEL);
  	}
  
  	/**
  	 * Send a packet to a specified channel
  	 * @param buffer Packet to send to channel
  	 * @param channel Id of channel on which to send packet
  	 * @throws RdesktopException
  	 * @throws IOException
  	 */
  	public void send_to_channel(RdpPacket_Localised buffer, int channel)
  			throws RdesktopException, IOException {
  		int length = 0;
  		buffer.setPosition(buffer.getHeader(RdpPacket_Localised.MCS_HEADER));
  
  		length = buffer.getEnd()
  				- buffer.getHeader(RdpPacket_Localised.MCS_HEADER) - 8;
  		length |= 0x8000;
  
  		buffer.set8((SDRQ << 2));
  		buffer.setBigEndian16(this.McsUserID);
  		buffer.setBigEndian16(channel);
  		buffer.set8(0x70); //Flags
  		buffer.setBigEndian16(length);
  		IsoLayer.send(buffer);
  	}
  
  	/**
  	 * Receive an MCS PDU from the next channel with available data
  	 * @param channel ID of channel will be stored in channel[0]
  	 * @return Received packet
  	 * @throws IOException
  	 * @throws RdesktopException
  	 * @throws OrderException
  	 * @throws CryptoException
  	 */
  	public RdpPacket_Localised receive(int[] channel) throws IOException,
  			RdesktopException, OrderException, CryptoException {
  //		logger.debug("receive");
  		int opcode = 0, appid = 0, length = 0;
  		RdpPacket_Localised buffer = IsoLayer.receive();
  		if (buffer == null)
  			return null;
  		buffer.setHeader(RdpPacket_Localised.MCS_HEADER);
  		opcode = buffer.get8();
  
  		appid = opcode >> 2;
  
  		if (appid != SDIN) {
  			if (appid != DPUM) {
  				throw new RdesktopException("Expected data got" + opcode);
  			}
  			throw new EOFException("End of transmission!");
  		}
  
  		buffer.incrementPosition(2); // Skip UserID
  		channel[0] = buffer.getBigEndian16(); // Get ChannelID
  //		logger.debug("Channel ID = " + channel[0]);
  		buffer.incrementPosition(1); // Skip Flags
  
  		length = buffer.get8();
  
  		if ((length & 0x80) != 0) {
  			buffer.incrementPosition(1);
  		}
  		buffer.setStart(buffer.getPosition());
  		
  		return buffer;
  		
  		
  		
  	}
  
  	/**
  	 * send an Integer encoded according to the ISO ASN.1 Basic Encoding Rules
  	 * @param buffer Packet in which to store encoded value
  	 * @param value Integer value to store
  	 */
  	public void sendBerInteger(RdpPacket_Localised buffer, int value) {
  
  		int len = 1;
  
  		if (value > 0xff)
  			len = 2;
  
  		sendBerHeader(buffer, BER_TAG_INTEGER, len);
  
  		if (value > 0xff) {
  			buffer.setBigEndian16(value);
  		} else {
  			buffer.set8(value);
  		}
  
  	}
  
  	/**
  	 * Determine the size of a BER header encoded for the specified tag and data length
  	 * @param tagval Value of tag identifying data type
  	 * @param length Length of data header will precede
  	 * @return
  	 */
  	private int berHeaderSize(int tagval, int length) {
  		int total = 0;
  		if (tagval > 0xff) {
  			total += 2;
  		} else {
  			total += 1;
  		}
  
  		if (length >= 0x80) {
  			total += 3;
  		} else {
  			total += 1;
  		}
  		return total;
  	}
  
  	/**
  	 * Send a Header encoded according to the ISO ASN.1 Basic Encoding rules
  	 * @param buffer Packet in which to send the header
  	 * @param tagval Data type for header
  	 * @param length Length of data header precedes
  	 */
  	public void sendBerHeader(RdpPacket_Localised buffer, int tagval, int length) {
  		if (tagval > 0xff) {
  			buffer.setBigEndian16(tagval);
  		} else {
  			buffer.set8(tagval);
  		}
  
  		if (length >= 0x80) {
  			buffer.set8(0x82);
  			buffer.setBigEndian16(length);
  		} else {
  			buffer.set8(length);
  		}
  	}
  
  	/**
  	 * Determine the size of a BER encoded integer with specified value
  	 * @param value Value of integer
  	 * @return Number of bytes the encoded data would occupy
  	 */
  	private int BERIntSize(int value) {
  		if (value > 0xff)
  			return 4;
  		else
  			return 3;
  	}
  
  	/**
  	 * Determine the size of the domain parameters, encoded according to the ISO ASN.1 Basic Encoding Rules
  	 * @param max_channels Maximum number of channels
  	 * @param max_users Maximum number of users
  	 * @param max_tokens Maximum number of tokens
  	 * @param max_pdusize Maximum size of an MCS PDU
  	 * @return Number of bytes the domain parameters would occupy
  	 */
  	private int domainParamSize(int max_channels, int max_users,
  			int max_tokens, int max_pdusize) {
  		int endSize = BERIntSize(max_channels) + BERIntSize(max_users)
  				+ BERIntSize(max_tokens) + BERIntSize(1) + BERIntSize(0)
  				+ BERIntSize(1) + BERIntSize(max_pdusize) + BERIntSize(2);
  		return berHeaderSize(TAG_DOMAIN_PARAMS, endSize) + endSize;
  	}
  
  	/**
  	 * send a DOMAIN_PARAMS structure encoded according to the ISO ASN.1
  	 * Basic Encoding rules
  	 * @param buffer Packet in which to send the structure
  	 * @param max_channels Maximum number of channels
  	 * @param max_users Maximum number of users
  	 * @param max_tokens Maximum number of tokens
  	 * @param max_pdusize Maximum size for an MCS PDU
  	 */
  	public void sendDomainParams(RdpPacket_Localised buffer, int max_channels,
  			int max_users, int max_tokens, int max_pdusize) {
  
  		int size = BERIntSize(max_channels) + BERIntSize(max_users)
  				+ BERIntSize(max_tokens) + BERIntSize(1) + BERIntSize(0)
  				+ BERIntSize(1) + BERIntSize(max_pdusize) + BERIntSize(2);
  
  		sendBerHeader(buffer, TAG_DOMAIN_PARAMS, size);
  		sendBerInteger(buffer, max_channels);
  		sendBerInteger(buffer, max_users);
  		sendBerInteger(buffer, max_tokens);
  
  