/*
*
* Hamsam - Instant Messaging API
*
* Copyright (C) 2003 Mike Miller <mikemil@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package hamsam.protocol.aim.command;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import hamsam.exception.IllegalStateException;
import hamsam.net.Connection;
import hamsam.protocol.aim.flap.FlapHeader;
import hamsam.protocol.aim.flap.FlapConstants;
import hamsam.protocol.aim.snac.SNACPacket;
import hamsam.protocol.aim.util.TLV;
/**
* @author mike
*/
public abstract class Command {
protected FlapHeader flapHdr;
protected SNACPacket snacPacket;
protected List tlvList;
protected byte[] data;
/**
* Default constructor
*/
public Command() {
super();
}
/**
* Constructor
* @param hdr FlapHeader
* @param snac SNACPacket
* @param tlvs list of TLVs
* @param dataArray command data, not part of the above parms
*/
public Command(FlapHeader hdr, SNACPacket snac, List tlvs, byte[] dataArray) {
flapHdr = hdr;
snacPacket = snac;
tlvList = tlvs;
data = dataArray;
}
/**
* Writes the command data to the output stream. This method must be implemented
* by all class extending this class. Each command class will know what data it
* has and wants to write/send to AIM.
* @param os Output stream
* @throws IOException
*/
public abstract void writeCommandData(OutputStream os) throws IOException;
/**
* method to get the byte array representing the command
*/
public byte[] getBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (data == null) {
// put command specific data in the outputstream
writeCommandData(baos);
// add the TLVs to the outputstream
if (tlvList != null && !tlvList.isEmpty()) {
for (Iterator iter = tlvList.iterator(); iter.hasNext();) {
baos.write( ((TLV)iter.next()).getBytes() );
}
}
data = baos.toByteArray();
}
ByteArrayOutputStream cmdOS = new ByteArrayOutputStream();
int cmdDataLen = 0;
if (snacPacket != null) {
cmdDataLen += SNACPacket.SNACPACKET_LENGTH;
}
if (data != null) {
cmdDataLen += data.length;
}
// set the flap header length
flapHdr.setDataLength(cmdDataLen);
cmdOS.write( flapHdr.getBytes() );
if (snacPacket != null) {
cmdOS.write(snacPacket.getBytes());
}
cmdOS.write(data, 0, data.length);
byte[] cmdBytes = cmdOS.toByteArray();
return cmdBytes;
}
/**
* Return string representation of the Command object
* @return string representation of the Command object
*/
public String toString() {
StringBuffer sb = new StringBuffer(200);
sb.append(flapHdr).append("\n");
if (snacPacket != null) {
sb.append(snacPacket).append("\n");
}
if (tlvList != null && !tlvList.isEmpty()) {
for (Iterator iter = tlvList.iterator(); iter.hasNext();) {
sb.append( ((TLV) iter.next()).toString() );
}
}
return sb.toString();
}
/**
* Gets the next incoming command from the AOL server, thru the connection
* @param conn Connection
* @return Command from the AOL server
* @throws IOException
* @throws InterruptedException
*/
public static Command getCommand(Connection conn) throws IOException, InterruptedException {
byte[] cmdData = null;
FlapHeader hdr = null;
SNACPacket pkt = null;
List tlvs = null;
try {
hdr = FlapHeader.getHeader(conn);
} catch (IllegalStateException e1) {
e1.printStackTrace();
}
if (hdr != null) {
/* get the length of the data portion */
int dataLength = hdr.getDataLength();
/* now load the data portion */
cmdData = new byte[dataLength];
int count = 0;
while (count != cmdData.length) {
try {
count += conn.read(cmdData, count, cmdData.length - count);
} catch (IOException e) {
e.printStackTrace();
}
}
// create the SNAC from the buffer
if (hdr.getChannelId() == FlapConstants.FLAP_CHANNEL_SNAC) {
// create snac packet
pkt = new SNACPacket(cmdData);
// moved all SNAC data into the SNACPacket
cmdData = null;
} else if (hdr.getChannelId() == FlapConstants.FLAP_CHANNEL_DISCONNECT) {
// anything left MAY/MAY not be a list of TLVs -
tlvs = TLV.getTLVs(cmdData, 0);
}
}
Command cmd = null;
if (hdr!= null) {
cmd = new BaseCmd(hdr, pkt, tlvs, cmdData);
}
return cmd;
}
/*
* Adds a TLV object to the list
*/
protected void addTLV(TLV tlv) {
if (tlvList == null) {
tlvList = new LinkedList();
}
tlvList.add(tlv);
}
/*
* Get the bytes for the list of TLVs
*/
protected byte[] getTLVBytes() {
byte[] tlvBytes = null;
if (tlvList != null && !tlvList.isEmpty()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
for (Iterator iter = tlvList.iterator(); iter.hasNext();) {
baos.write(((TLV) iter.next()).getBytes());
}
} catch (IOException e) {
//e.printStackTrace();
}
tlvBytes = baos.toByteArray();
}
return tlvBytes;
}
/**
* Get the TLV for the type requested from the Command
* @param tlvid TLV type id
* @return TLV object or null if matching TLV type not found
*/
public TLV getTLV(int tlvid) {
TLV tlv = null;
if (tlvList != null && !tlvList.isEmpty() ) {
for (Iterator iter = tlvList.iterator(); iter.hasNext();) {
TLV element = (TLV)iter.next();
if (tlvid == element.getType()) {
tlv = element;
break;
}
}
}
return tlv;
}
/**
* Get the FlapHeader for this command
* @return FlapHeader for this command
*/
public FlapHeader getFlapHdr() {
return flapHdr;
}
/**
* Get the SNACPacket from this command
* @return SNACPacket for this command
*/
public SNACPacket getSNAC() {
return snacPacket;
}
/**
* Get the channel id for the Command
* @return channel id from the FlapHeader
*/
public byte getChannel() {
return flapHdr.getChannelId();
}
/**
* Get the Family Id for the Command
* @return family id from the SNACPacket, or -1 if no SNACPacket available
*/
public int getFamily() {
if (snacPacket != null) {
return snacPacket.getFamilyId();
} else{
return -1;
}
}
/**
* Get the Sub type from the Command
* @return sub type id from the SNACPacket, of -1 if no SNACPacket available
*/
public int getSubType() {
if (snacPacket != null) {
return snacPacket.getSubTypeId();
} else {
return -1;
}
}
public byte[] getData() {
return data;
}
public byte[] getSNACData() {
if (snacPacket == null) {
return null;
} else {
return snacPacket.getSNACData();
}
}
}