package uc.protocols; import uc.FavHub; import uc.crypto.HashValue; import uc.crypto.Tiger; import uc.protocols.hub.Hub; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.ProtocolException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import logger.LoggerFactory; import org.apache.log4j.Logger; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; public abstract class DCProtocol extends ConnectionProtocol { private static Logger logger = LoggerFactory.make(); public static final String PROTOCOL_EXTENSIONPOINT = "eu.jucy.protocol"; public static final String NMDC_CHARENCODING = "windows-1252"; public static final Charset NMDC_CHARSET; public static final String ADC_CHARENCODING = "utf-8"; public static final Charset ADC_CHARSET; static { NMDC_CHARSET = Charset.forName(NMDC_CHARENCODING); ADC_CHARSET = Charset.forName(ADC_CHARENCODING); } public static final Pattern NMDCCommand = Pattern.compile("([^|]+)\\|"); public static final Pattern ADCCommand = Pattern.compile("([^\\n]+)\\n"); public static final Pattern NMDC_PREFIX_PATTERN = Pattern.compile("(\\$\\S+)[^|]*"); public static final Pattern ADC_PREFIX_PATTERN = Pattern.compile("[BCDEFHIU]([A-Z][A-Z0-9]{2})[^\\n]*"); public static final Pattern NMDC_AND_ADC_PREFIX_PATTERN = Pattern.compile("[BCDEFHIU]?(\\$?\\S+)[^\\|\\n]*"); public static final Pattern NMDCANDADCCommand = Pattern.compile("([^|\\n]+)[\\|\\n]"); /** * variable to signal if this hub is running NMDC protocol.. * true if NMDC protocol is running * false if ADC protocol is running * * default is NMDC */ protected Boolean nmdc = true; public DCProtocol() { setCharset(NMDC_CHARSET); } public DCProtocol(int[] perfPref) { super(perfPref); setCharset(NMDC_CHARSET); } /** * sets DC char-set * based on NMDC variable */ protected void setCharSet() { setCharset(isNMDC()? NMDC_CHARSET:ADC_CHARSET); } public void setProtocolNMDC(Boolean nmdc) { // if (this.nmdc == null || !this.nmdc.equals(nmdc)) { this.nmdc = nmdc; setCharSet(); setPrefixPattern(); // } } private void setPrefixPattern() { if (nmdc == null) { setPrefix(NMDC_AND_ADC_PREFIX_PATTERN); } else { setPrefix(nmdc?NMDC_PREFIX_PATTERN: ADC_PREFIX_PATTERN); } } public boolean isNMDC() { return nmdc == null || nmdc; } public Boolean getNMDC() { return nmdc; } @Override public Pattern getCommandRegexPattern() { if (nmdc == null) { return NMDCANDADCCommand; } return nmdc ? NMDCCommand :ADCCommand; } /** * stop byte per command.. */ public int getCommandStopByte() { return nmdc == null||nmdc ? '|' : '\n'; } /* public static void main(String[] args) throws UnsupportedEncodingException { Random rand = new Random(); for (int i = 0 ; i < 5000 ; i ++) { String lock = "$Lock EXTENDEDPROTOCOL::This_hub_was_written_by_Yoshi::CTRL["; String seperating = ""; for (int x = 0; x < 5; x++) { int num =rand.nextInt(256); lock += (char)num; seperating+= num+","; } lock += "] Pk=YnHub|"; byte[] key = generateKey(lock,NMDCCHARENCODING).getBytes(NMDCCHARENCODING); byte[] key2 = generateKey(lock, NMDCCHARSET); boolean valid = key.length == key2.length; for (int s = 0 ; s < key.length && valid ; s++) { valid &= key[s] == key2[s]; } if (!valid) { System.out.println("Invalid: "+seperating+"\n" + new String(key,NMDCCHARENCODING)+"\n" + new String(key2,NMDCCHARENCODING)+"\n"); } } } */ // ------------------------------------------------------------------------------ // ------ Lock part START // -------------------------------------------------------- // ------------------------------------------------------------------------------ // Mysterious method to Compute a Key String from a Lock String public static byte[] generateKey(String lockstr,Charset cs) throws UnsupportedEncodingException ,ProtocolException{ int firstpos = lockstr.indexOf(' '); int lastpos = lockstr.indexOf(" Pk="); if (lastpos < 0) { lastpos = lockstr.indexOf(' ', firstpos+1); } if (firstpos < 0 || lastpos < 0 || firstpos >= lastpos) { throw new ProtocolException("Invalid Lock received: "+lockstr); } byte[] lock = lockstr.substring(firstpos+1, lastpos).getBytes(cs.name()); byte[] key = new byte[lock.length]; for (int i = 1; i < lock.length; i++) { key[i] = (byte) ((lock[i] ^ lock[i - 1]) & 0xFF); } key[0] = (byte) ((((lock[0] ^ lock[lock.length - 1]) ^ lock[lock.length - 2]) ^ 5) & 0xFF); for (int i = 0; i < key.length; i++) { key[i] = (byte) ((((key[i] << 4) & 0xF0) | ((key[i] >> 4) & 0x0F)) & 0xFF); } byte[] dcnEncoded = dcnEncode(key,cs); byte[] completeKey = new byte[dcnEncoded.length + 6]; completeKey[0] = '$'; completeKey[1] = 'K'; completeKey[2] = 'e'; completeKey[3] = 'y'; completeKey[4] = ' '; completeKey[completeKey.length-1] = '|'; System.arraycopy(dcnEncoded, 0, completeKey, 5, dcnEncoded.length); return completeKey; } private static byte[] dcnEncode(byte[] lock,Charset cs) throws UnsupportedEncodingException { List<Byte> encoded = new ArrayList<Byte>(); for (byte b: lock ) { if (b == 0 || b == 5 || b == 36 || b == 96 || b == 124 || b == 126 ) { String paddedDecimal= "/%DCN"+String.format("%03d", (int)b)+"%/"; for (byte dcn : paddedDecimal.getBytes(cs.name()) ) { encoded.add(dcn); } } else { encoded.add(b); } } byte[] encodedBytes = new byte[encoded.size()]; for (int i = 0; i < encodedBytes.length ; i++) { encodedBytes[i] = encoded.get(i); } return encodedBytes; } // ------------------------------------------------------------------------------ // -------- Lockpart END // -------------------------------------------------------- // ------------------------------------------------------------------------------ public void onLogIn() throws IOException { super.onLogIn(); loadCommands(false); } @Override public void beforeConnect() { super.beforeConnect(); loadCommands(true); } /** * * @param connect true for on connect * false for login */ private void loadCommands(boolean connect) { IExtensionRegistry reg = Platform.getExtensionRegistry(); IConfigurationElement[] configElements = reg .getConfigurationElementsFor(PROTOCOL_EXTENSIONPOINT); for (IConfigurationElement protocolExtension:configElements) { if (nmdc == null || nmdc.equals(Boolean.valueOf(protocolExtension.getAttribute("nmdc")))) { IConfigurationElement[] protocols = protocolExtension.getChildren("protocol"); for (IConfigurationElement protocol:protocols) { if (getClass().getName().equals(protocol.getAttribute("target")) && Boolean.parseBoolean(protocol.getAttribute("active_from_start")) == connect) { IConfigurationElement[] commands = protocol .getChildren("command"); for (IConfigurationElement command : commands) { try { @SuppressWarnings("unchecked") IProtocolCommand<? extends ConnectionProtocol> prot = (IProtocolCommand<? extends ConnectionProtocol>) command .createExecutableExtension("commandClass"); addCommand(prot); } catch (CoreException e) { logger.error(e, e); } } } } } } } /** * * @param hub - if true hub supports are loaded.. otherwise inf extension * * @return all protocols contributed.. */ public List<String> getSupports(boolean hub) { List<String> supports = new ArrayList<String>(); IExtensionRegistry reg = Platform.getExtensionRegistry(); IConfigurationElement[] configElements = reg .getConfigurationElementsFor(PROTOCOL_EXTENSIONPOINT); for (IConfigurationElement protocolExtension:configElements) { if (nmdc.equals(Boolean.valueOf(protocolExtension.getAttribute("nmdc")))) { String ext = protocolExtension.getAttribute(hub?"hub_support":"inf_support"); if (ext != null) { supports.add(ext); } } } return supports; } public static String doReplaces(String toReplace) { // Replaces DC protocol // relevant chars return toReplace.replace("&#", "&#").replace("$", "$").replace( "|", "|"); } public static String reverseReplaces(String toReplace) { return toReplace.replace("|", "|").replace("$", "$").replace( "&#", "&#"); } /** * convenience method reverses NMDC replaces in all strings of the array * * @param toReplace - * the array to do the replaces.. * @return - an array containing the same string just reverse replaced */ public static String[] reverseReplaces(String[] toReplace) { for (int i = 0; i < toReplace.length; i++) { toReplace[i] = reverseReplaces(toReplace[i]); } return toReplace; } /* * one-way function to compute a "artificial" uid for an nmdc user @param * nick the nick of the user @param hubid the hubid of the user @return the * unique userid * * @deprecated use different method without int for hubid * * * public static HashValue nickToUserID(String nick, int hubid){ return * Tiger.tigerOfString(hubid+"$$"+nick); } */ public static HashValue nickToUserID(String nick, FavHub hub) { return Tiger.tigerOfString(hub.getSimpleHubaddy() + "$$" + nick); } public static HashValue nickToUserID(String nick, Hub hub) { return nickToUserID(nick, hub.getFavHub()); } public static HashValue CIDToUserID(HashValue cid, Hub hub) { return CIDToUserID(cid,hub.getFavHub()); } public static HashValue CIDToUserID(HashValue cid, FavHub hub) { return Tiger.tigerOfString(cid.toString()+"$"+hub.getSimpleHubaddy()); } @Override protected void registerListenerFirst(IProtocolStatusChangedListener listener) { super.registerListenerFirst(listener); } }