/* This code is part of Freenet. It is distributed under the GNU General * Public License, version 2 (or at your option any later version). See * http://www.gnu.org/ for further details of the GPL. */ package freenet.clients.fcp; import java.net.MalformedURLException; import freenet.client.HighLevelSimpleClientImpl; import freenet.client.InsertContext; import freenet.clients.fcp.ClientRequest.Persistence; import freenet.keys.FreenetURI; import freenet.node.Node; import freenet.node.RequestStarter; import freenet.support.HexUtil; import freenet.support.SimpleFieldSet; import freenet.support.compress.Compressor.COMPRESSOR_TYPE; import freenet.support.compress.InvalidCompressionCodecException; /** * Put a directory, rather than a file. * Base class. * * Two forms: ClientPutDiskDir and ClientPutComplexDir * * Both share: * Identifier=<identifier> * Verbosity=<verbosity as ClientPut> * MaxRetries=<max retries as ClientPut> * PriorityClass=<priority class> * URI=<target URI> * GetCHKOnly=<GetCHKOnly as ClientPut> * DontCompress=<DontCompress as ClientPut> * ClientToken=<ClientToken as ClientPut> * Persistence=<Persistence as ClientPut> * Global=<Global as ClientPut> */ public abstract class ClientPutDirMessage extends BaseDataCarryingMessage { // Some subtypes of this (ClientPutComplexDirMessage) may carry a payload. final String identifier; final FreenetURI uri; final int verbosity; final int maxRetries; final boolean getCHKOnly; final short priorityClass; final Persistence persistence; final boolean dontCompress; final String clientToken; final boolean global; final String defaultName; final boolean earlyEncode; final boolean canWriteClientCache; final String compressorDescriptor; public boolean forkOnCacheable; final int extraInsertsSingleBlock; final int extraInsertsSplitfileHeaderBlock; final InsertContext.CompatibilityMode compatibilityMode; final byte[] overrideSplitfileCryptoKey; final boolean localRequestOnly; final boolean realTimeFlag; final String targetFilename; final boolean ignoreUSKDatehints; public ClientPutDirMessage(SimpleFieldSet fs) throws MessageInvalidException { identifier = fs.get("Identifier"); global = fs.getBoolean("Global", false); defaultName = fs.get("DefaultName"); String s = fs.get("CompatibilityMode"); InsertContext.CompatibilityMode cmode = null; if(s == null) cmode = InsertContext.CompatibilityMode.COMPAT_DEFAULT; else { try { cmode = InsertContext.CompatibilityMode.valueOf(s); } catch (IllegalArgumentException e) { try { cmode = InsertContext.CompatibilityMode.values()[Integer.parseInt(s)]; } catch (NumberFormatException e1) { throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid CompatibilityMode (not a name and not a number)", identifier, global); } catch (ArrayIndexOutOfBoundsException e1) { throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid CompatibilityMode (not a valid number)", identifier, global); } } } compatibilityMode = cmode.intern(); s = fs.get("OverrideSplitfileCryptoKey"); if(s == null) overrideSplitfileCryptoKey = null; else try { overrideSplitfileCryptoKey = HexUtil.hexToBytes(s); } catch (NumberFormatException e1) { throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid splitfile crypto key (not hex)", identifier, global); } catch (IndexOutOfBoundsException e1) { throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid splitfile crypto key (too short)", identifier, global); } localRequestOnly = fs.getBoolean("LocalRequestOnly", false); if(identifier == null) throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "No Identifier", null, global); try { String u = fs.get("URI"); if(u == null) throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "No URI", identifier, global); FreenetURI uu = new FreenetURI(u); // Client is allowed to put a slash at the end if it wants to, but this is discouraged. String[] meta = uu.getAllMetaStrings(); if(meta != null && meta.length == 1 && meta[0].length() == 0) uu = uu.setMetaString(null); uri = uu; } catch (MalformedURLException e) { throw new MessageInvalidException(ProtocolErrorMessage.FREENET_URI_PARSE_ERROR, e.getMessage(), identifier, global); } String verbosityString = fs.get("Verbosity"); if(verbosityString == null) verbosity = 0; else { try { verbosity = Integer.parseInt(verbosityString, 10); } catch (NumberFormatException e) { throw new MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error parsing Verbosity field: "+e.getMessage(), identifier, global); } } String maxRetriesString = fs.get("MaxRetries"); if(maxRetriesString == null) // default to 0 maxRetries = 0; else { try { maxRetries = Integer.parseInt(maxRetriesString, 10); } catch (NumberFormatException e) { throw new MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error parsing MaxSize field: "+e.getMessage(), identifier, global); } } getCHKOnly = fs.getBoolean("GetCHKOnly", false); String priorityString = fs.get("PriorityClass"); if(priorityString == null) { // defaults to the one just below FProxy priorityClass = RequestStarter.IMMEDIATE_SPLITFILE_PRIORITY_CLASS; } else { try { priorityClass = Short.parseShort(priorityString); if(!RequestStarter.isValidPriorityClass(priorityClass)) throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid priority class "+priorityClass+" - range is "+RequestStarter.PAUSED_PRIORITY_CLASS+" to "+RequestStarter.MAXIMUM_PRIORITY_CLASS, identifier, global); } catch (NumberFormatException e) { throw new MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error parsing PriorityClass field: "+e.getMessage(), identifier, global); } } dontCompress = fs.getBoolean("DontCompress", false); String persistenceString = fs.get("Persistence"); persistence = Persistence.parseOrThrow(persistenceString, identifier, global); canWriteClientCache = fs.getBoolean("WriteToClientCache", false); clientToken = fs.get("ClientToken"); targetFilename = fs.get("TargetFilename"); earlyEncode = fs.getBoolean("EarlyEncode", false); String codecs = fs.get("Codecs"); if (codecs != null) { COMPRESSOR_TYPE[] ca; try { ca = COMPRESSOR_TYPE.getCompressorsArrayNoDefault(codecs); } catch (InvalidCompressionCodecException e) { throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, e.getMessage(), identifier, global); } if (ca == null) codecs = null; } compressorDescriptor = codecs; if(fs.get("ForkOnCacheable") != null) forkOnCacheable = fs.getBoolean("ForkOnCacheable", false); else forkOnCacheable = Node.FORK_ON_CACHEABLE_DEFAULT; extraInsertsSingleBlock = fs.getInt("ExtraInsertsSingleBlock", HighLevelSimpleClientImpl.EXTRA_INSERTS_SINGLE_BLOCK); extraInsertsSplitfileHeaderBlock = fs.getInt("ExtraInsertsSplitfileHeaderBlock", HighLevelSimpleClientImpl.EXTRA_INSERTS_SPLITFILE_HEADER); realTimeFlag = fs.getBoolean("RealTimeFlag", false); ignoreUSKDatehints = fs.getBoolean("IgnoreUSKDatehints", false); } @Override public SimpleFieldSet getFieldSet() { SimpleFieldSet sfs = new SimpleFieldSet(true); sfs.putSingle("URI", uri.toString()); sfs.putSingle("Identifier", identifier); sfs.put("Verbosity", verbosity); sfs.put("MaxRetries", maxRetries); sfs.putSingle("ClientToken", clientToken); sfs.put("GetCHKOnly", getCHKOnly); sfs.put("PriorityClass", priorityClass); sfs.putSingle("Persistence", persistence.toString().toLowerCase()); sfs.put("DontCompress", dontCompress); if (compressorDescriptor != null) sfs.putSingle("Codecs", compressorDescriptor); sfs.put("Global", global); sfs.putSingle("DefaultName", defaultName); return sfs; } }