/* This file is part of leafdigital leafChat. leafChat 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 3 of the License, or (at your option) any later version. leafChat 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 leafChat. If not, see <http://www.gnu.org/licenses/>. Copyright 2011 Samuel Marshall. */ package com.leafdigital.irc.api; import java.io.UnsupportedEncodingException; import java.util.*; import com.leafdigital.irc.api.IRCEncoding.EncodingInfo; import leafchat.core.api.*; /** Represents a parsed message received from an IRC server, parsed */ public class IRCMsg extends Msg { /** Server that sent the message */ private Server s = null; /** Entire line */ private byte[] line = null; /** Prefix (may be null) */ private byte[] prefix = null; /** Command */ private byte[] command = null; /** Parameters */ private byte[][] params = new byte[][]{}; /** Whether or not last param was a postfix type */ private boolean includesPostfix; /** Encoding set by user for this type of message */ private EncodingInfo encoding; /** * Converts text using ISO 8859-1 which is generally appropriate for 'system' * parts of a message * @param data Bytes * @return String */ public static String convertISO(byte[] data) { if(data == null) { return null; } try { return new String(data, "ISO-8859-1"); } catch(UnsupportedEncodingException e) { throw new Error("Missing basic character encodings",e); } } /** * @param data Bytes from this message * @return Message converted into a string as per user's encoding preferences */ public String convertEncoding(byte[] data) { return encoding.convertIncoming(data); } /** * Given an array of bytes, splits it on spaces. * @param data Data to split * @return Array of byte arrays with split data */ public static byte[][] splitBytes(byte[] data) { List<byte[]> arrays = new LinkedList<byte[]>(); for(int i=0; i<data.length; i++) { if(data[i] == 32) { if(i > 0) { byte[] before = new byte[i]; System.arraycopy(data, 0, before, 0, i); arrays.add(before); } if(i+1 < data.length) { byte[] after = new byte[data.length - ( i+ 1)]; System.arraycopy(data, i+1, after, 0, data.length - (i + 1)); data = after; i = -1; // Restart loop for new 'data' array } else { // Nothing after the space data = new byte[0]; break; } } } if(data.length>0) { arrays.add(data); } return arrays.toArray(new byte[arrays.size()][]); } /** * Creates bytes suitable for an IRC message where the first part is in ISO * 8859-1 and the second part has been converted to bytes * @param isoPart ISO part of text (may be null) * @param secondPart Other character set part (may be null) * @return Bytes containing both parts */ public static byte[] constructBytes( String isoPart, byte[] secondPart) { try { byte[] data1 = null, data2 = secondPart; if(isoPart != null) { data1 = isoPart.getBytes("ISO-8859-1"); } if(data1 == null && data2 == null) { return new byte[0]; } if(data2 == null) { return data1; } if(data1 == null) { return data2; } byte[] out = new byte[data1.length + data2.length]; System.arraycopy(data1, 0, out, 0, data1.length); System.arraycopy(data2, 0, out, data1.length, data2.length); return out; } catch(UnsupportedEncodingException e) { throw new Error(e); } } /** * @param iso String that should be converted to bytes * @return Bytes of string in ISO-8859-1 charset */ public static byte[] constructBytes(String iso) { return constructBytes(iso,null); } /** * Sets up encoding for message (used by system only). * @param encoding Encoding */ public void setEncoding(EncodingInfo encoding) { this.encoding = encoding; } /** @return True if encoding has been set up (used by system) */ public boolean hasEncoding() { return encoding!=null; } /** * @param base Message to copy parameters from */ public void init(IRCMsg base) { this.s = base.s; this.line = base.line; this.prefix = base.prefix; this.command = base.command; this.params = base.params; this.includesPostfix = base.includesPostfix; setSequence(base); } /** * Init with actual parameters * @param s Server * @param line Original line * @param prefix Prefix (or null) * @param command Command * @param params Parameters * @param includesPostfix Whether or not the last param was a postfix type */ public void init(Server s, byte[] line, byte[] prefix, byte[] command, byte[][] params, boolean includesPostfix) { this.s = s; this.line = line; this.prefix = prefix; this.command = command; this.params = params; this.includesPostfix = includesPostfix; } /** @return Server that sent the message */ public Server getServer() { return s; } /** @return Entire line */ public byte[] getLine() { return line; }; /** @return Entire line as string */ public String getLineISO() { return convertISO(line); } /** @return Prefix (may be null) */ public byte[] getPrefixBytes() { return prefix; } /** @return Prefix (may be null) */ public String getPrefix() { return convertISO(prefix); } /** @return Command */ public byte[] getCommandBytes() { return command; } /** @return Command */ public String getCommand() { return convertISO(command); } /** @return Parameters */ public byte[][] getParams() { return params; } /** * @param index Parameter index * @return ISO-converted string */ public String getParamISO(int index) { return convertISO(getParams()[index]); } /** * @param index Parameter index * @return True if it is an integer */ public boolean isParamInteger(int index) { return getParamISO(index).matches("-?[0-9]+"); } /** @return True if last param was a postfix type */ public boolean includesPostfix() { return includesPostfix; } @Override public String toString() { String className = getClass().getName(); int dot = className.lastIndexOf('.'); if(dot != -1) { className=className.substring(dot + 1); } String value= "[" + className + "]\n" + " Server: " + s + "\n" + " Line: "+convertISO(line) + "\n" + " Prefix: "+getPrefix() + "\n" + " Command: "+getCommand() + "\n"; for(int i=0;i<params.length;i++) { value+=" Param: "+convertISO(params[i])+ (i==params.length-1 && includesPostfix() ? " [postfix]\n" : "\n"); } return value; } /** * Message info for scripting. */ public static MessageInfo info = new MessageInfo(IRCMsg.class, "IRC", "Events that are received from an IRC server.") { @Override public String getContextInit() { return "registerContext(msg.getServer(),null,null,null);"; } @Override public boolean allowScripting() { return true; } @Override protected void listAppropriateFilters(Collection<FilterInfo> list) { super.listAppropriateFilters(list); list.add(ServerFilter.info); } }; }