package uc.protocols; import helpers.SizeEnum; import java.net.InetAddress; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import uc.IHub; import uc.IUser; import uc.crypto.HashValue; import uc.files.IDownloadable; import uc.files.IDownloadable.IDownloadableFile; import uc.files.MagnetLink; import uc.files.filelist.FileListFolder; import uc.protocols.hub.AbstractADCHubCommand; import uc.protocols.hub.INFField; /** * specifies a context in which a command is sent * and allows the string to be formatted with this context.. * * * @author quicksilver * */ public class SendContext { private static final Map<String,String> DateMappings = Collections.synchronizedMap(new HashMap<String,String>()); static { String[] normalMappings = new String[]{"a","A","b","B","c","d","H","I","j","m","M","p","S","y","Y"}; for (String normal : normalMappings) { DateMappings.put("%"+normal, "%t"+normal); } DateMappings.put("%x", "%tF"); DateMappings.put("%X", "%tR"); DateMappings.put("%z", ""); DateMappings.put("%Z", ""); } protected static final Pattern replace = Pattern.compile(".*?(%\\[(.+?)\\]).*"); private static final Pattern datematcher = Pattern.compile(".*?(%[aAbBcdHIjmMpSxXyYzZ]).*"); /** * the hub and with it, the user we represent our self is always * available */ private IHub hub; /** * the other user.. */ private IUser user; private IDownloadable fileOrFolder; protected Map<String,String> replacements; /** * empty send context.. if none is available */ public SendContext() {} public SendContext(Map<String,String> replacements) { this.replacements = replacements; } /** * create a send Context with a set other user.. * @param other */ public SendContext(IUser other,Map<String,String> replacements) { this(replacements); this.user = other; } public SendContext(IDownloadable fileOrFolder,Map<String,String> replacements) { this(fileOrFolder,fileOrFolder.getUser(),replacements); } public SendContext(IDownloadable fileOrFolder,IUser user,Map<String,String> replacements) { this.fileOrFolder = fileOrFolder; this.user = user; this.replacements = replacements; } /** * * @param command - a command that is to be sent.. * @return the command formatted with date and time stuff * and with %[userNI]/ %[myNI] and alike stuff that is usual in * DC */ public String format(String command) { if (replacements != null) { for (Entry<String,String> e : replacements.entrySet()) { String repl = hub.isNMDC()? DCProtocol.doReplaces(e.getValue()): AbstractADCCommand.doReplaces(e.getValue()); command = command.replace(e.getKey(), repl); } } Matcher m = replace.matcher(command); int currentpos = 0; while(m.find(currentpos)) { String formatStringfound = m.group(2); Formatter f = Formatter.parse(formatStringfound ); String replacement = f.getReplacement(this, formatStringfound); command = command.replace(m.group(1), replacement); currentpos = m.start(1)+1; } return formatDate(command); } /** * method needed as the java date format is different than * the POSIX/UNIX one.. */ private String formatDate(String command) { Matcher m = datematcher.matcher(command); int currentpos = 0 ; Calendar c = null; while (m.find(currentpos)) { if (c == null) { c = Calendar.getInstance(); } String dateSpec = m.group(1); String replaceSpec = DateMappings.get(dateSpec); String replaceString = String.format(replaceSpec, c); command = command.replace(dateSpec, replaceString); currentpos = m.start(1)+1; } return command; } public void setHub(IHub hub) { this.hub = hub; } /* * just a testfunction.. * public static void main(String[] args) { SendContext sc = new SendContext(); sc.user = Population.get().get("schnüffi", TigerHashValue.SELFHASH); String command= "hello says %[userNI]"; Matcher m = replace.matcher(command); System.out.println(m.matches()); System.out.println(m.group(1)); System.out.println(m.group(2)); System.out.println(sc.format(command)); } */ public IUser getUser() { return user; } public IHub getHub() { return hub; } public IDownloadable getFile() { return fileOrFolder; } /*private static abstract class Formatter<T> { private final String replacePrefix; /** * formatters replace * @param replace what the formatter does replace for example * "userNI" for a formatter that does replace "" * public Formatter(String replaceprefix) { this.replacePrefix = replaceprefix; } public String getReplacePrefix() { return replacePrefix; } public abstract String format(String command,T t); }*/ private static enum Formatter { userI6(true,getINFFields()), //default for all inf myI6(false,getINFFields()), nick(FormatterType.USER), mynick(FormatterType.MY), ip(FormatterType.USER), userTAG(FormatterType.USER,"tag"), myTAG(FormatterType.MY), description(FormatterType.USER), email(FormatterType.USER), share(FormatterType.USER), userSSshort(FormatterType.USER,"shareshort"), mySSshort(FormatterType.MY), userCID(FormatterType.USER,"cid"), myCID(FormatterType.MY,"mycid"), userSID(FormatterType.USER), mySID(FormatterType.MY), fileFN(FormatterType.FILE,"file"), filePath(FormatterType.FILE), Directory(FormatterType.FILE), fileSI(FormatterType.FILE,"fileSIsize","filesize"), fileSIshort(FormatterType.FILE,"filesizeshort"), fileTR(FormatterType.FILE,"tth"), fileMN(FormatterType.FILE), type(FormatterType.FILE), hubNI(FormatterType.HUB), hubDE(FormatterType.HUB), hubVE(FormatterType.HUB), //line(FormatterType.OTHER), .. line is not allowed here.. DEFAULT(FormatterType.OTHER); private final FormatterType formatterType; private final String[] alternateNames; private Formatter(FormatterType t,String... alternateNames) { formatterType = t; this.alternateNames = alternateNames; } private Formatter(boolean user,INFField... alternateNames) { formatterType = user? FormatterType.USER : FormatterType.MY; this.alternateNames = new String[alternateNames.length]; for (int i = 0 ; i < alternateNames.length; i++) { this.alternateNames[i] =formatterType.name().toLowerCase()+alternateNames[i].name(); } } private static INFField[] getINFFields() { Set<INFField> fields = new HashSet<INFField>(Arrays.asList(INFField.values())); fields.remove( INFField.PD ); //these fields are not used/allowed fields.remove( INFField.RF ); fields.remove( INFField.TO ); return fields.toArray(new INFField[0]); } private static final Map<String,Formatter> formatters = new HashMap<String,Formatter>(); static { for (Formatter f:Formatter.values()) { formatters.put(f.name(), f); for (String alternate :f.alternateNames) { formatters.put(alternate, f); } } } /** * * @param formatstring the string between the brackets .. so userNI for %[userNI] * @return the matching formatter.. */ public static Formatter parse(String formatstring) { int i = formatstring.indexOf(':'); if (i != -1) { formatstring = formatstring.substring(0, i); } Formatter f = formatters.get(formatstring); if (f != null) { return f; } else { return DEFAULT; } } private String getReplacement(SendContext sc,String formatString) { IUser usr = null; IDownloadable file = sc.getFile(); switch(formatterType) { case USER: usr = sc.getUser(); if ( usr == null) { return "%["+formatString+"]"; } break; case MY: if (sc.getHub() == null || (usr =sc.getHub().getSelf()) == null) { return "%["+formatString+"]"; } break; case FILE: if (file == null) { return "%["+formatString+"]"; } break; case HUB: if (sc.getHub() == null) { return "%["+formatString+"]"; } break; } switch (this) { case nick: case mynick: return usr.getNick(); case ip: InetAddress ia = usr.getIp(); if (ia == null) { return "%["+formatString+"]"; } else { return ia.getHostAddress(); } case userTAG: case myTAG: return usr.getTag(); case description: return usr.getDescription(); case email: return usr.getEMail(); case share: return ""+usr.getShared(); case userSSshort: case mySSshort: return SizeEnum.getReadableSize(usr.getShared()); case userCID: case myCID: HashValue cid = usr.getCID(); if (cid != null) { return cid.toString(); } break; case userSID: case mySID: int sid = usr.getSid(); if (sid != -1) { return AbstractADCHubCommand.SIDToStr(usr.getSid()); } break; case userI6: case myI6: String inf = formatString.substring(formatString.length()-2); INFField inff = INFField.parse(inf); if (inff != null) { String prop = inff.getProperty(usr); if (prop != null) { return prop; } } break; //end User stuff //start File stuff case fileFN: return file.getName(); case Directory: return file.getOnlyPath(); case filePath: return file.getPath(); case fileSI: if (file.isFile()) { return ""+ ((IDownloadableFile)file).getSize(); } if (file instanceof FileListFolder) { return ""+ ((FileListFolder)file).getSize(); } return ""; case fileSIshort: if (file.isFile()) { return SizeEnum.getReadableSize(((IDownloadableFile)file).getSize()); } if (file instanceof FileListFolder) { return SizeEnum.getReadableSize(((FileListFolder)file).getSize()); } return ""; case fileTR: if (file.isFile()) { return ((IDownloadableFile)file).getTTHRoot().toString(); } else { return ""; } case fileMN: if (file.isFile()) { return new MagnetLink((IDownloadableFile)file).toString(); } else { return ""; } case type: if (file.isFile()) { return "File"; } else { return "Directory"; } case hubNI: return sc.getHub().getName(); case hubDE: return sc.getHub().getTopic(); case hubVE: return sc.getHub().getVersion(); case DEFAULT: return "%["+formatString+"]"; } return "%["+formatString+"]"; } } private static enum FormatterType { USER,MY,HUB,FILE,OTHER; } }