Author: dieppe
Date: 2008-02-13 03:26:33 +0000 (Wed, 13 Feb 2008)
New Revision: 17860

Added:
   trunk/apps/thingamablog/src/net/sf/thingamablog/util/
   trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/
   trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/
   trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Client.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientHello.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPut.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPutComplexDir.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPutDir.java
   trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Command.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Connection.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ConnectionListener.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/DirectFileEntry.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/DiskFileEntry.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/FileEntry.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/GenerateSSK.java
   trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Message.java
   trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Node.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Persistence.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/PriorityClass.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/RedirectFileEntry.java
   
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Verbosity.java
Log:
Updates : add the fcp package of jSite



Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Client.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Client.java    
                            (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Client.java    
    2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,216 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Client executes {@link Command}s over a {@link Connection} to a
+ * {@link Node} and delivers resulting {@link Message}s.
+ * 
+ * @author David Roden <droden at gmail.com>
+ * @version $Id: Client.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public class Client implements ConnectionListener {
+
+       /** The connection this client operates on. */
+       private final Connection connection;
+
+       /** The identifiers the client filters messages for. */
+       private List<String> identifiers = new ArrayList<String>();
+
+       /** The queued messages. */
+       private final List<Message> messageQueue = new ArrayList<Message>();
+
+       /** Whether the client was disconnected. */
+       private boolean disconnected = false;
+
+       /** Whether to catch all messages from the connection. */
+       private boolean catchAll = false;
+
+       /**
+        * Creates a new client that operates on the specified connection.
+        * 
+        * @param connection
+        *            The connection to operate on
+        */
+       public Client(Connection connection) {
+               this.connection = connection;
+               connection.addConnectionListener(this);
+       }
+
+       /**
+        * Creates a new client that operates on the specified connection and
+        * immediately executes the specified command.
+        * 
+        * @param connection
+        *            The connection to operate on
+        * @param command
+        *            The command to execute
+        * @throws IOException
+        *             if an I/O error occurs
+        * @see #execute(Command)
+        */
+       public Client(Connection connection, Command command) throws 
IOException {
+               this(connection);
+               execute(command);
+       }
+
+       /**
+        * Returns whether this client catches all messages going over the
+        * connection.
+        * 
+        * @return <code>true</code> if the client catches all messages,
+        *         <code>false</code> otherwise
+        */
+       public boolean isCatchAll() {
+               return catchAll;
+       }
+
+       /**
+        * Sets whether this client catches all messages going over the 
connection.
+        * 
+        * @param catchAll
+        *            <code>true</code> if the client should catch all messages,
+        *            <code>false</code> otherwise
+        */
+       public void setCatchAll(boolean catchAll) {
+               this.catchAll = catchAll;
+       }
+
+       /**
+        * Executes the specified command. This will also clear the queue of
+        * messages, discarding all messages that resulted from the previous 
command
+        * and have not yet been read.
+        * 
+        * @param command
+        *            The command to execute
+        * @throws IOException
+        *             if an I/O error occurs
+        * @see #execute(Command, boolean)
+        */
+       public void execute(Command command) throws IOException {
+               execute(command, true);
+       }
+
+       /**
+        * Executes the specified command and optionally clears the list of
+        * identifiers this clients listens to before starting the command.
+        * 
+        * @param command
+        *            The command to execute
+        * @param removeExistingIdentifiers
+        *            If <code>true</code>, the list of identifiers that this
+        *            clients listens to is cleared
+        * @throws IOException
+        *             if an I/O error occurs
+        */
+       public void execute(Command command, boolean removeExistingIdentifiers) 
throws IOException {
+               synchronized (messageQueue) {
+                       messageQueue.clear();
+                       if (removeExistingIdentifiers) {
+                               identifiers.clear();
+                       }
+                       identifiers.add(command.getIdentifier());
+               }
+               connection.execute(command);
+       }
+
+       /**
+        * Returns the next message, waiting endlessly for it, if need be. If 
you
+        * are not sure whether a message will arrive, better use
+        * {@link #readMessage(long)} to only wait for a specific time.
+        * 
+        * @return The next message that resulted from the execution of the last
+        *         command
+        * @see #readMessage(long)
+        * @see #execute(Command)
+        */
+       public Message readMessage() {
+               return readMessage(0);
+       }
+
+       /**
+        * Returns the next message. If the message queue is currently empty, at
+        * least <code>maxWaitTime</code> milliseconds will be waited for a
+        * message to arrive.
+        * 
+        * @param maxWaitTime
+        *            The minimum time to wait for a message, in milliseconds
+        * @return The message, or <code>null</code> if no message arrived in 
time
+        *         or the client is currently disconnected
+        * @see #isDisconnected()
+        * @see Object#wait(long)
+        */
+       public Message readMessage(long maxWaitTime) {
+               synchronized (messageQueue) {
+                       if (disconnected) {
+                               return null;
+                       }
+                       if (messageQueue.size() == 0) {
+                               try {
+                                       messageQueue.wait(maxWaitTime);
+                               } catch (InterruptedException ie1) {
+                               }
+                       }
+                       if (messageQueue.size() > 0) {
+                               return messageQueue.remove(0);
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Returns whether the client is currently disconnected.
+        * 
+        * @return <code>true</code> if the client is disconnected,
+        *         <code>false</code> otherwise
+        */
+       public boolean isDisconnected() {
+               synchronized (messageQueue) {
+                       return disconnected;
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public void messageReceived(Connection connection, Message message) {
+               synchronized (messageQueue) {
+                       if (catchAll || (message.getIdentifier().length() == 0) 
|| identifiers.contains(message.getIdentifier())) {
+                               messageQueue.add(message);
+                               messageQueue.notify();
+                       }
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public void connectionTerminated(Connection connection) {
+               synchronized (messageQueue) {
+                       disconnected = true;
+                       messageQueue.notify();
+               }
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientHello.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientHello.java
                           (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientHello.java
   2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,101 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Implementation of the <code>ClientHello</code> command. This command must
+ * be sent as the first command on a connection ({@link 
de.todesbaum.util.freenet.fcp2.Connection#connect()}
+ * takes care of that) and must not be sent afterwards.
+ * <p>
+ * The node can answer with the following messages: <code>NodeHello</code>.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: ClientHello.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public class ClientHello extends Command {
+
+       /** The name of the client. */
+       protected String name;
+
+       /** The version of the FCP protocol the client expects. */
+       protected String expectedVersion = "2.0";
+
+       /**
+        * Creates a new <code>ClientHello</code> command.
+        */
+       public ClientHello() {
+               super("ClientHello", "ClientHello-" + 
System.currentTimeMillis());
+       }
+
+       /**
+        * Returns the value of the <code>ExpectedVersion</code> parameter of 
this
+        * command. At the moment this value is not used by the node but in the
+        * future this may be used to enforce certain node versions.
+        * 
+        * @return The expected version
+        */
+       public String getExpectedVersion() {
+               return expectedVersion;
+       }
+
+       /**
+        * Sets the value of the <code>ExpectedVersion</code> parameter of this
+        * command. At the moment this value is not used by the node but in the
+        * future this may be used to enforce certain node versions.
+        * 
+        * @param expectedVersion
+        *            The expected version
+        */
+       public void setExpectedVersion(String expectedVersion) {
+               this.expectedVersion = expectedVersion;
+       }
+
+       /**
+        * Returns the name of the client that is connecting.
+        * 
+        * @return The name of the client
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Sets the name of the client that is connecting.
+        * 
+        * @param name
+        *            The name of the client
+        */
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       protected void write(Writer writer) throws IOException {
+               writer.write("Name=" + name + LINEFEED);
+               writer.write("ExpectedVersion=" + expectedVersion + LINEFEED);
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPut.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPut.java 
                            (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPut.java 
    2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,217 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all put requests. It contains all parameters that 
put
+ * requests have in common.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: ClientPut.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public abstract class ClientPut extends Command {
+
+       /** The URI of this request. */
+       protected final String uri;
+       
+       /** The client token of this request. */
+       protected String clientToken = null;
+
+       /** Whether this request should only create a CHK. */
+       protected boolean getCHKOnly = false;
+
+       /** Whether this request is a global request. */
+       protected boolean global = false;
+
+       /** Whether the node should not try to compress the file. */
+       protected boolean dontCompress = false;
+
+       /** The maximum number of retries of this command. */
+       protected int maxRetries = 0;
+
+       /** The persistence of this request. */
+       protected Persistence persistence = Persistence.CONNECTION;
+
+       /** The priority class of this request. */
+       protected PriorityClass priorityClass = PriorityClass.INTERACTIVE;
+
+       /** The verbosiry of this request. */
+       protected Verbosity verbosity = Verbosity.NONE;
+
+       /**
+        * Creates a new put request with the specified name, identifier and 
URI.
+        * 
+        * @param name
+        *            The name of this request
+        * @param identifier
+        *            The identifier of this request
+        * @param uri
+        *            The URI of this request
+        */
+       protected ClientPut(String name, String identifier, String uri) {
+               super(name, identifier);
+               this.uri = uri;
+       }
+
+       /**
+        * Returns whether the node should not try to compress the data.
+        * 
+        * @return <code>true</code> if the node should <strong>not</strong> try
+        *         to compress the data
+        */
+       public boolean isDontCompress() {
+               return dontCompress;
+       }
+
+       /**
+        * Sets whether the node should not try to compress the data. A client 
might
+        * set this hint on data that is clearly not compressible, like MPEG 
audio
+        * files, JPEG or PNG images, highly compressed movies, or compressed
+        * archives like ZIP files. Otherwise the node will try to compress the 
file
+        * which -- depending on the size of the data -- might take a lot of 
time
+        * and memory.
+        * 
+        * @param dontCompress
+        *            <code>true</code> if the node should <strong>not</strong>
+        *            try to compress the data
+        */
+       public void setDontCompress(boolean dontCompress) {
+               this.dontCompress = dontCompress;
+       }
+
+       /**
+        * Returns whether this request should only return the CHK of the data.
+        * @return Whether this request should only return the CHK of the data
+        */
+       public boolean isGetCHKOnly() {
+               return getCHKOnly;
+       }
+
+       /**
+        * Sets whether this request should only return the CHK of the data.
+        * @param getCHKOnly
+        *            <code>true</code> if this request should only return the 
CHK of the data
+        */
+       public void setGetCHKOnly(boolean getCHKOnly) {
+               this.getCHKOnly = getCHKOnly;
+       }
+
+       /**
+        * Returns whether this request is a global request.
+        * @return <code>true</code> if this request is a global request, 
<code>false</code> otherwise
+        */
+       public boolean isGlobal() {
+               return global;
+       }
+
+       /**
+        * Sets whether this request is a global request.
+        * @param global
+        *            <code>true</code> if this request is a global request, 
<code>false</code> otherwise
+        */
+       public void setGlobal(boolean global) {
+               this.global = global;
+       }
+
+       /**
+        * Returns the maximum number of retries of this request.
+        * @return The maximum number of retries of this request
+        */
+       public int getMaxRetries() {
+               return maxRetries;
+       }
+
+       /**
+        * Sets the maximum number of retries of this request
+        * @param maxRetries
+        *            The maximum number of retries of this request
+        */
+       public void setMaxRetries(int maxRetries) {
+               this.maxRetries = maxRetries;
+       }
+
+       /**
+        * Returns the priority class of this request.
+        * @return The priority class of this request
+        */
+       public PriorityClass getPriorityClass() {
+               return priorityClass;
+       }
+
+       /**
+        * Sets the priority class of this request.
+        * @param priorityClass
+        *            The priority class of this request
+        */
+       public void setPriorityClass(PriorityClass priorityClass) {
+               this.priorityClass = priorityClass;
+       }
+
+       /**
+        * Returns the verbosity of this request.
+        * @return The verbosity of this request
+        */
+       public Verbosity getVerbosity() {
+               return verbosity;
+       }
+
+       /**
+        * Sets the verbosity of this request.
+        * @param verbosity
+        *            The verbosity of this request
+        */
+       public void setVerbosity(Verbosity verbosity) {
+               this.verbosity = verbosity;
+       }
+
+       /**
+        * Returns the URI of this request
+        * @return The URI of this request.
+        */
+       public String getUri() {
+               return uri;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       protected void write(Writer writer) throws IOException {
+               super.write(writer);
+               writer.write("URI=" + uri + LINEFEED);
+               if (verbosity != null)
+                       writer.write("Verbosity=" + verbosity.getValue() + 
LINEFEED);
+               if (maxRetries != 0)
+                       writer.write("MaxRetries=" + maxRetries + LINEFEED);
+               if (priorityClass != null)
+                       writer.write("PriorityClass=" + 
priorityClass.getValue() + LINEFEED);
+               writer.write("GetCHKOnly=" + getCHKOnly + LINEFEED);
+               writer.write("Global=" + global + LINEFEED);
+               writer.write("DontCompress=" + dontCompress + LINEFEED);
+               if (clientToken != null)
+                       writer.write("ClientToken=" + clientToken + LINEFEED);
+               if (persistence != null)
+                       writer.write("Persistence=" + persistence.getName() + 
LINEFEED);
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPutComplexDir.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPutComplexDir.java
                           (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPutComplexDir.java
   2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,158 @@
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.todesbaum.util.io.Closer;
+
+/**
+ * Implementation of the <code>ClientPutComplexDir</code> command. This
+ * command can be used to insert directories that do not exist on disk.
+ *
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: ClientPutComplexDir.java 17481 2008-02-02 21:21:16Z bombe $
+ */
+public class ClientPutComplexDir extends ClientPutDir {
+
+       /** The file entries of this directory. */
+       private List<FileEntry> fileEntries = new ArrayList<FileEntry>();
+
+       /** Whether this request has payload. */
+       private boolean hasPayload = false;
+
+       /** The input streams for the payload. */
+       private File payloadFile;
+
+       /** The total number of bytes of the payload. */
+       private long payloadLength = 0;
+
+       /**
+        * Creates a new <code>ClientPutComplexDir</code> command with the 
specified identifier and URI.
+        * @param identifier The identifier of the command
+        * @param uri The URI of the command
+        */
+       public ClientPutComplexDir(String identifier, String uri) {
+               super("ClientPutComplexDir", identifier, uri);
+       }
+
+       /**
+        * Adds a file to the directory inserted by this request.
+        * @param fileEntry The file entry to add to the directory
+        */
+       public void addFileEntry(FileEntry fileEntry) {
+               if (fileEntry instanceof DirectFileEntry) {
+                       if (payloadFile == null){
+                               try {
+                                       payloadFile = 
File.createTempFile("payload", ".dat");
+                                       payloadFile.deleteOnExit();
+                               } catch (IOException e) {
+                               }
+                       }
+                       if (payloadFile != null) {
+                               InputStream payloadInputStream = 
((DirectFileEntry) fileEntry).getDataInputStream();
+                               FileOutputStream payloadOutputStream = null;
+                               try {
+                                       payloadOutputStream = new 
FileOutputStream(payloadFile, true);
+                                       byte[] buffer = new byte[65536];
+                                       int read = 0;
+                                       while ((read = 
payloadInputStream.read(buffer)) != -1) {
+                                               
payloadOutputStream.write(buffer, 0, read);
+                                       }
+                                       payloadOutputStream.flush();
+                                       fileEntries.add(fileEntry);
+                               } catch (IOException ioe1) {
+                                       /* hmm, ignore? */
+                               } finally {
+                                       Closer.close(payloadOutputStream);
+                                       Closer.close(payloadInputStream);
+                               }
+                       }
+               } else {
+                       fileEntries.add(fileEntry);
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       protected void write(Writer writer) throws IOException {
+               super.write(writer);
+               int fileIndex = 0;
+               for (FileEntry fileEntry: fileEntries) {
+                       writer.write("Files." + fileIndex + ".Name=" + 
fileEntry.getFilename() + LINEFEED);
+                       if (fileEntry.getContentType() != null) {
+                               writer.write("Files." + fileIndex + 
".Metadata.ContentType=" + fileEntry.getContentType() + LINEFEED);
+                       }
+                       writer.write("Files." + fileIndex + ".UploadFrom=" + 
fileEntry.getName() + LINEFEED);
+                       if (fileEntry instanceof DirectFileEntry) {
+                               hasPayload = true;
+                               writer.write("Files." + fileIndex + 
".DataLength=" + ((DirectFileEntry) fileEntry).getDataLength() + LINEFEED);
+                               payloadLength += ((DirectFileEntry) 
fileEntry).getDataLength();
+                       } else if (fileEntry instanceof DiskFileEntry) {
+                               writer.write("Files." + fileIndex + 
".Filename=" + ((DiskFileEntry) fileEntry).getFilename() + LINEFEED);
+                       } else if (fileEntry instanceof RedirectFileEntry) {
+                               writer.write("Files." + fileIndex + 
".TargetURI=" + ((RedirectFileEntry) fileEntry).getTargetURI() + LINEFEED);
+                       }
+                       fileIndex++;
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       protected boolean hasPayload() {
+               return hasPayload;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       protected long getPayloadLength() {
+               return payloadLength;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       protected InputStream getPayload() {
+               if (payloadFile != null) {
+                       try {
+                               return new FileInputStream(payloadFile);
+                       } catch (FileNotFoundException e) {
+                               /* shouldn't occur. */
+                       }
+               }
+               return null;
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPutDir.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPutDir.java
                          (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ClientPutDir.java
  2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,83 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all put requests that insert a directory.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: ClientPutDir.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public class ClientPutDir extends ClientPut {
+
+       /** The default file of the directory. */
+       protected String defaultName;
+
+       /**
+        * Creates a new request with the specified name, identifier, and URI.
+        * 
+        * @param name
+        *            The name of the request
+        * @param identifier
+        *            The identifier of the request
+        * @param uri
+        *            The URI of the request
+        */
+       public ClientPutDir(String name, String identifier, String uri) {
+               super(name, identifier, uri);
+       }
+
+       /**
+        * Returns the default name of the directory.
+        * 
+        * @return The default name of the directory
+        */
+       public String getDefaultName() {
+               return defaultName;
+       }
+
+       /**
+        * Sets the default name of the directory. The default name of a 
directory
+        * is the name of the file that will be delivered if the directory was
+        * requested without a filename. It's about the same as the
+        * <code>index.html</code> file that gets delivered if you only request 
a
+        * directory from a webserver.
+        * 
+        * @param defaultName
+        *            The default name of the directory
+        */
+       public void setDefaultName(String defaultName) {
+               this.defaultName = defaultName;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       protected void write(Writer writer) throws IOException {
+               super.write(writer);
+               if (defaultName != null)
+                       writer.write("DefaultName=" + defaultName + LINEFEED);
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Command.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Command.java   
                            (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Command.java   
    2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,138 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all commands.
+ * <p>
+ * In addition to the replies listed at the type comment of each specific
+ * command the node can <strong>always</strong> send the following messages:
+ * <code>ProtocolError</code> (if this library screws up),
+ * <code>CloseConnectionDuplicateClientName</code> (if a client with the same
+ * name of the {@link de.todesbaum.util.freenet.fcp2.Connection} connects). So
+ * when receiving messages from the node you should always be prepared for
+ * something you did not expect.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: Command.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public abstract class Command {
+
+       /** The line feed sequence used by the library. */
+       protected static final String LINEFEED = "\r\n";
+
+       /**
+        * The name of the command. The name is sent to the node so it can not 
be
+        * chosen arbitrarily!
+        */
+       private final String commandName;
+
+       /**
+        * The identifier of the command. This identifier is used to identify
+        * replies that are caused by a command.
+        */
+       private final String identifier;
+
+       /**
+        * Creates a new command with the specified name and identifier.
+        * 
+        * @param name
+        *            The name of the command
+        * @param identifier
+        *            The identifier of the command
+        */
+       public Command(String name, String identifier) {
+               this.commandName = name;
+               this.identifier = identifier;
+       }
+
+       /**
+        * Returns the name of this command.
+        * 
+        * @return The name of this command
+        */
+       public String getCommandName() {
+               return commandName;
+       }
+
+       /**
+        * Return the identifier of this command.
+        * 
+        * @return The identifier of this command
+        */
+       public String getIdentifier() {
+               return identifier;
+       }
+
+       /**
+        * Writes all parameters to the specified writer.
+        * <p>
+        * <strong>NOTE:</strong> Subclasses of Command <strong>must</strong> 
call
+        * <code>super.write(writer)</code> before or after writing their own
+        * parameters!
+        * 
+        * @param writer
+        *            The stream to write the parameters to
+        * @throws IOException
+        *             if an I/O error occurs
+        */
+       protected void write(Writer writer) throws IOException {
+               if (identifier != null)
+                       writer.write("Identifier=" + identifier + LINEFEED);
+       }
+
+       /**
+        * Returns whether this command has payload to send after the message.
+        * Subclasses need to return <code>true</code> here if they need to send
+        * payload after the message.
+        * 
+        * @return <code>true</code> if this command has payload to send,
+        *         <code>false</code> otherwise
+        */
+       protected boolean hasPayload() {
+               return false;
+       }
+
+       /**
+        * Returns the payload of this command as an {@link InputStream}. This
+        * method is never called if {@link #hasPayload()} returns
+        * <code>false</code>.
+        * 
+        * @return The payload of this command
+        */
+       protected InputStream getPayload() {
+               return null;
+       }
+
+       /**
+        * Returns the length of the payload. This method is never called if
+        * {@link #hasPayload()} returns <code>false</code>.
+        * 
+        * @return The length of the payload
+        */
+       protected long getPayloadLength() {
+               return -1;
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Connection.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Connection.java
                            (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Connection.java
    2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,378 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.Socket;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.todesbaum.util.io.Closer;
+import de.todesbaum.util.io.LineInputStream;
+import de.todesbaum.util.io.StreamCopier;
+import de.todesbaum.util.io.TempFileInputStream;
+
+/**
+ * A physical connection to a Freenet node.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: Connection.java 15384 2007-09-29 12:11:36Z bombe $
+ */
+public class Connection {
+
+       /** The listeners that receive events from this connection. */
+       private List<ConnectionListener> connectionListeners = new 
ArrayList<ConnectionListener>();
+
+       /** The node this connection is connected to. */
+       private final Node node;
+
+       /** The name of this connection. */
+       private final String name;
+
+       /** The network socket of this connection. */
+       private Socket nodeSocket;
+
+       /** The input stream that reads from the socket. */
+       private InputStream nodeInputStream;
+
+       /** The output stream that writes to the socket. */
+       private OutputStream nodeOutputStream;
+
+       /** The thread that reads from the socket. */
+       private NodeReader nodeReader;
+
+       /** A writer for the output stream. */
+       private Writer nodeWriter;
+
+       /** The NodeHello message sent by the node on connect. */
+       protected Message nodeHello;
+
+       /**
+        * Creates a new connection to the specified node with the specified 
name.
+        * 
+        * @param node
+        *            The node to connect to
+        * @param name
+        *            The name of this connection
+        */
+       public Connection(Node node, String name) {
+               this.node = node;
+               this.name = name;
+       }
+
+       /**
+        * Adds a listener that gets notified on connection events.
+        * 
+        * @param connectionListener
+        *            The listener to add
+        */
+       public void addConnectionListener(ConnectionListener 
connectionListener) {
+               connectionListeners.add(connectionListener);
+       }
+
+       /**
+        * Removes a listener from the list of registered listeners. Only the 
first
+        * matching listener is removed.
+        * 
+        * @param connectionListener
+        *            The listener to remove
+        * @see List#remove(java.lang.Object)
+        */
+       public void removeConnectionListener(ConnectionListener 
connectionListener) {
+               connectionListeners.remove(connectionListener);
+       }
+
+       /**
+        * Notifies listeners about a received message.
+        * 
+        * @param message
+        *            The received message
+        */
+       protected void fireMessageReceived(Message message) {
+               for (ConnectionListener connectionListener: 
connectionListeners) {
+                       connectionListener.messageReceived(this, message);
+               }
+       }
+
+       /**
+        * Notifies listeners about the loss of the connection.
+        */
+       protected void fireConnectionTerminated() {
+               for (ConnectionListener connectionListener: 
connectionListeners) {
+                       connectionListener.connectionTerminated(this);
+               }
+       }
+
+       /**
+        * Returns the name of the connection.
+        * 
+        * @return The name of the connection
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Connects to the node.
+        * 
+        * @return <code>true</code> if the connection succeeded and the node
+        *         returned a NodeHello message
+        * @throws IOException
+        *             if an I/O error occurs
+        * @see #getNodeHello()
+        */
+       public synchronized boolean connect() throws IOException {
+               nodeSocket = null;
+               nodeInputStream = null;
+               nodeOutputStream = null;
+               nodeWriter = null;
+               nodeReader = null;
+               try {
+                       nodeSocket = new Socket(node.getHostname(), 
node.getPort());
+                       nodeSocket.setReceiveBufferSize(65535);
+                       nodeInputStream = nodeSocket.getInputStream();
+                       nodeOutputStream = nodeSocket.getOutputStream();
+                       nodeWriter = new OutputStreamWriter(nodeOutputStream, 
Charset.forName("UTF-8"));
+                       nodeReader = new NodeReader(nodeInputStream);
+                       Thread nodeReaderThread = new Thread(nodeReader);
+                       nodeReaderThread.setDaemon(true);
+                       nodeReaderThread.start();
+                       ClientHello clientHello = new ClientHello();
+                       clientHello.setName(name);
+                       clientHello.setExpectedVersion("2.0");
+                       execute(clientHello);
+                       synchronized (this) {
+                               try {
+                                       wait();
+                               } catch (InterruptedException e) {
+                               }
+                       }
+                       return nodeHello != null;
+               } catch (IOException ioe1) {
+                       disconnect();
+                       throw ioe1;
+               }
+       }
+
+       /**
+        * Returns whether this connection is still connected to the node.
+        * 
+        * @return <code>true</code> if this connection is still valid,
+        *         <code>false</code> otherwise
+        */
+       public boolean isConnected() {
+               return (nodeHello != null) && (nodeSocket != null) && 
(nodeSocket.isConnected());
+       }
+
+       /**
+        * Returns the NodeHello message the node sent on connection.
+        * 
+        * @return The NodeHello message of the node
+        */
+       public Message getNodeHello() {
+               return nodeHello;
+       }
+
+       /**
+        * Disconnects from the node.
+        */
+       public void disconnect() {
+               if (nodeWriter != null) {
+                       try {
+                               nodeWriter.close();
+                       } catch (IOException ioe1) {
+                       }
+                       nodeWriter = null;
+               }
+               if (nodeOutputStream != null) {
+                       try {
+                               nodeOutputStream.close();
+                       } catch (IOException ioe1) {
+                       }
+                       nodeOutputStream = null;
+               }
+               if (nodeInputStream != null) {
+                       try {
+                               nodeInputStream.close();
+                       } catch (IOException ioe1) {
+                       }
+                       nodeInputStream = null;
+               }
+               if (nodeSocket != null) {
+                       try {
+                               nodeSocket.close();
+                       } catch (IOException ioe1) {
+                       }
+                       nodeSocket = null;
+               }
+               synchronized (this) {
+                       notify();
+               }
+               fireConnectionTerminated();
+       }
+
+       /**
+        * Executes the specified command.
+        * 
+        * @param command
+        *            The command to execute
+        * @throws IllegalStateException
+        *             if the connection is not connected
+        * @throws IOException
+        *             if an I/O error occurs
+        */
+       public synchronized void execute(Command command) throws 
IllegalStateException, IOException {
+               if (nodeSocket == null) {
+                       throw new IllegalStateException("connection is not 
connected");
+               }
+               nodeWriter.write(command.getCommandName() + Command.LINEFEED);
+               command.write(nodeWriter);
+               nodeWriter.write("EndMessage" + Command.LINEFEED);
+               nodeWriter.flush();
+               if (command.hasPayload()) {
+                       InputStream payloadInputStream = null;
+                       try {
+                               payloadInputStream = command.getPayload();
+                               StreamCopier.copy(payloadInputStream, 
nodeOutputStream, command.getPayloadLength());
+                       } finally {
+                               Closer.close(payloadInputStream);
+                       }
+                       nodeOutputStream.flush();
+               }
+       }
+
+       /**
+        * The reader thread for this connection. This is essentially a thread 
that
+        * reads lines from the node, creates messages from them and notifies
+        * listeners about the messages.
+        * 
+        * @author David Roden &lt;droden at gmail.com&gt;
+        * @version $Id: Connection.java 15384 2007-09-29 12:11:36Z bombe $
+        */
+       private class NodeReader implements Runnable {
+
+               /** The input stream to read from. */
+               @SuppressWarnings("hiding")
+               private InputStream nodeInputStream;
+
+               /**
+                * Creates a new reader that reads from the specified input 
stream.
+                * 
+                * @param nodeInputStream
+                *            The input stream to read from
+                */
+               public NodeReader(InputStream nodeInputStream) {
+                       this.nodeInputStream = nodeInputStream;
+               }
+
+               /**
+                * Main loop of the reader. Lines are read and converted into
+                * {@link Message} objects.
+                */
+               public void run() {
+                       LineInputStream nodeReader = null;
+                       try {
+                               nodeReader = new 
LineInputStream(nodeInputStream);
+                               String line = "";
+                               Message message = null;
+                               while (line != null) {
+                                       line = nodeReader.readLine();
+                                       // System.err.println("> " + line);
+                                       if (line == null) {
+                                               break;
+                                       }
+                                       if (message == null) {
+                                               message = new Message(line);
+                                               continue;
+                                       }
+                                       if ("Data".equals(line)) {
+                                               /* need to read message from 
stream now */
+                                               File tempFile = null;
+                                               try {
+                                                       tempFile = 
File.createTempFile("fcpv2", "data");
+                                                       tempFile.deleteOnExit();
+                                                       FileOutputStream 
tempFileOutputStream = new FileOutputStream(tempFile);
+                                                       long dataLength = 
Long.parseLong(message.get("DataLength"));
+                                                       
StreamCopier.copy(nodeInputStream, tempFileOutputStream, dataLength);
+                                                       
tempFileOutputStream.close();
+                                                       
message.setPayloadInputStream(new TempFileInputStream(tempFile));
+                                               } catch (IOException ioe1) {
+                                                       ioe1.printStackTrace();
+                                               }
+                                       }
+                                       if ("Data".equals(line) || 
"EndMessage".equals(line)) {
+                                               if 
(message.getName().equals("NodeHello")) {
+                                                       nodeHello = message;
+                                                       synchronized 
(Connection.this) {
+                                                               
Connection.this.notify();
+                                                       }
+                                               } else {
+                                                       
fireMessageReceived(message);
+                                               }
+                                               message = null;
+                                               continue;
+                                       }
+                                       int equalsPosition = line.indexOf('=');
+                                       if (equalsPosition > -1) {
+                                               String key = line.substring(0, 
equalsPosition).trim();
+                                               String value = 
line.substring(equalsPosition + 1).trim();
+                                               if (key.equals("Identifier")) {
+                                                       
message.setIdentifier(value);
+                                               } else {
+                                                       message.put(key, value);
+                                               }
+                                               continue;
+                                       }
+                                       /* skip lines consisting of whitespace 
only */
+                                       if (line.trim().length() == 0) {
+                                               continue;
+                                       }
+                                       /* if we got here, some error occured! 
*/
+                                       throw new IOException("Unexpected line: 
" + line);
+                               }
+                       } catch (IOException ioe1) {
+                               // ioe1.printStackTrace();
+                       } finally {
+                               if (nodeReader != null) {
+                                       try {
+                                               nodeReader.close();
+                                       } catch (IOException ioe1) {
+                                       }
+                               }
+                               if (nodeInputStream != null) {
+                                       try {
+                                               nodeInputStream.close();
+                                       } catch (IOException ioe1) {
+                                       }
+                               }
+                       }
+                       Connection.this.disconnect();
+               }
+
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ConnectionListener.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ConnectionListener.java
                            (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/ConnectionListener.java
    2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,50 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.util.EventListener;
+
+/**
+ * Interface for clients that want to be notified when a message was received.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: ConnectionListener.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public interface ConnectionListener extends EventListener {
+
+       /**
+        * Notifies a client that a message was received.
+        * 
+        * @param connection
+        *            The connection the message was received on
+        * @param message
+        *            The message that was received
+        */
+       public void messageReceived(Connection connection, Message message);
+
+       /**
+        * Notifies a client that the connection to the node has been lost.
+        * 
+        * @param connection
+        *            The connection that was lost
+        */
+       public void connectionTerminated(Connection connection);
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/DirectFileEntry.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/DirectFileEntry.java
                               (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/DirectFileEntry.java
       2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,100 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * A {@link FileEntry} that sends its payload directly to the node, using the
+ * existing FCP connection.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: DirectFileEntry.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public class DirectFileEntry extends FileEntry {
+
+       /** The input stream to read the data for this file from. */
+       private final InputStream dataInputStream;
+
+       /** The length of the data. */
+       private final long dataLength;
+
+       /**
+        * Creates a new FileEntry with the specified name and content type that
+        * gets its data from the specified byte array.
+        * 
+        * @param filename
+        *            The name of the file
+        * @param contentType
+        *            The content type of the file
+        * @param dataBytes
+        *            The content of the file
+        */
+       public DirectFileEntry(String filename, String contentType, byte[] 
dataBytes) {
+               this(filename, contentType, new 
ByteArrayInputStream(dataBytes), dataBytes.length);
+       }
+
+       /**
+        * Creates a new FileEntry with the specified name and content type that
+        * gets its data from the specified input stream.
+        * 
+        * @param filename
+        *            The name of the file
+        * @param contentType
+        *            The content type of the file
+        * @param dataInputStream
+        *            The input stream to read the content from
+        * @param dataLength
+        *            The length of the data input stream
+        */
+       public DirectFileEntry(String filename, String contentType, InputStream 
dataInputStream, long dataLength) {
+               super(filename, contentType);
+               this.dataInputStream = dataInputStream;
+               this.dataLength = dataLength;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getName() {
+               return "direct";
+       }
+
+       /**
+        * Returns the input stream for the file's content.
+        * 
+        * @return The input stream for the file's content
+        */
+       public InputStream getDataInputStream() {
+               return dataInputStream;
+       }
+
+       /**
+        * Returns the length of this file's content.
+        * 
+        * @return The length of this file's content
+        */
+       public long getDataLength() {
+               return dataLength;
+       }
+
+}
\ No newline at end of file

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/DiskFileEntry.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/DiskFileEntry.java
                         (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/DiskFileEntry.java
 2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,67 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+/**
+ * A {@link FileEntry} that reads the content from a file on the disk.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: DiskFileEntry.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public class DiskFileEntry extends FileEntry {
+
+       /** The local file name. */
+       private final String localFilename;
+
+       /**
+        * Creates a new {@link FileEntry} with the specified name and content 
type
+        * that is read from the file specified by <code>localFilename</code>.
+        * 
+        * @param filename
+        *            The name of the file
+        * @param contentType
+        *            The content type of the file
+        * @param localFilename
+        *            The name of the local file that holds the content of the 
file
+        *            to insert
+        */
+       public DiskFileEntry(String filename, String contentType, String 
localFilename) {
+               super(filename, contentType);
+               this.localFilename = localFilename;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getName() {
+               return "disk";
+       }
+
+       /**
+        * Returns the name of the local file that holds the content for this 
file.
+        * 
+        * @return The name of the local file
+        */
+       public String getLocalFilename() {
+               return localFilename;
+       }
+
+}
\ No newline at end of file

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/FileEntry.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/FileEntry.java 
                            (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/FileEntry.java 
    2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,83 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+/**
+ * Abstract base class of file entries that are used in the
+ * {@link de.todesbaum.util.freenet.fcp2.ClientPutComplexDir} command to define
+ * the files of an insert.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: FileEntry.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public abstract class FileEntry {
+
+       /** The name of the file. */
+       private final String filename;
+
+       /** The content type of the file. */
+       private final String contentType;
+
+       /**
+        * Creates a new file entry with the specified name and content type. 
The
+        * content type should be a standard MIME type with an additional 
charset
+        * specification for text-based types.
+        * 
+        * @param filename
+        *            The name of the file
+        * @param contentType
+        *            The content type of the file, e.g.
+        *            <code>"application/x-tar"</code> or
+        *            <code>"text/html; charset=iso8859-15"</code>
+        */
+       protected FileEntry(String filename, String contentType) {
+               this.filename = filename;
+               this.contentType = contentType;
+       }
+
+       /**
+        * Returns the name of this entry's type. Can be one of 
<code>direct</code>,
+        * <code>disk</code>, or <code>redirect</code>. This method is
+        * implemented by the subclasses {@link DirectFileEntry},
+        * {@link DiskFileEntry}, and {@link RedirectFileEntry}, respectively.
+        * 
+        * @return The name of this entry's type
+        */
+       public abstract String getName();
+
+       /**
+        * Returns the content type of this file.
+        * 
+        * @return The content type of this file
+        */
+       public String getContentType() {
+               return contentType;
+       }
+
+       /**
+        * Returns the name of this file.
+        * 
+        * @return The name of this file
+        */
+       public String getFilename() {
+               return filename;
+       }
+
+}
\ No newline at end of file

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/GenerateSSK.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/GenerateSSK.java
                           (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/GenerateSSK.java
   2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,39 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+/**
+ * Implementation of the <code>GenerateSSK</code> command.
+ * <p>
+ * The node can answer with the following messages: <code>SSKKeypair</code>.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: GenerateSSK.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public class GenerateSSK extends Command {
+
+       /**
+        * Creates a new <code>GenerateSSK</code> request.
+        */
+       public GenerateSSK() {
+               super("GenerateSSK", null);
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Message.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Message.java   
                            (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Message.java   
    2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,175 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * Contains replies sent by the Freenet node. A message always has a name, and
+ * most of the messages also have an identifier which binds it to a specific
+ * command. Exceptions are among others <code>NodeHello</code>,
+ * <code>SSKKeypair</code>, and <code>EndListPersistentRequests</code>.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: Message.java 9647 2006-07-17 18:24:50Z bombe $
+ * @see de.todesbaum.util.freenet.fcp2.Client
+ */
+public class Message {
+
+       /** The name of this message. */
+       private final String name;
+
+       /** The identifier of this message. */
+       private String identifier = "";
+
+       /** The parameters of this message. */
+       private Map<String, String> parameters = new HashMap<String, String>();
+
+       /** The payload. */
+       private InputStream payloadInputStream;
+
+       /**
+        * Creates a new message with the specified name.
+        * 
+        * @param name
+        *            The name of this message
+        */
+       public Message(String name) {
+               this.name = name;
+       }
+
+       /**
+        * Returns the identifier of this message.
+        * 
+        * @return The identifier
+        */
+       public String getIdentifier() {
+               return identifier;
+       }
+
+       /**
+        * Sets the identifier of this message.
+        * 
+        * @param identifier
+        *            The identifier of this message
+        */
+       public void setIdentifier(String identifier) {
+               this.identifier = identifier;
+       }
+
+       /**
+        * Returns the name of this message.
+        * 
+        * @return The name of this message
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Tests whether this message contains the parameter with the specified 
key.
+        * Key names are compared ignoring case.
+        * 
+        * @param key
+        *            The name of the parameter
+        * @return <code>true</code> if this parameter exists in this message,
+        *         <code>false</code> otherwise
+        */
+       public boolean containsKey(String key) {
+               return parameters.containsKey(key.toLowerCase());
+       }
+
+       /**
+        * Returns all parameters of this message. The keys of the entries are 
all
+        * lower case so if you want to match the parameter names you have to 
watch
+        * out.
+        * 
+        * @return All parameters of this message
+        */
+       public Set<Entry<String, String>> entrySet() {
+               return parameters.entrySet();
+       }
+
+       /**
+        * Returns the value of the parameter with the name specified by
+        * <code>key</code>.
+        * 
+        * @param key
+        *            The name of the parameter
+        * @return The value of the parameter
+        */
+       public String get(String key) {
+               return parameters.get(key.toLowerCase());
+       }
+
+       /**
+        * Stores the specified value as parameter with the name specified by
+        * <code>key</code>.
+        * 
+        * @param key
+        *            The name of the parameter
+        * @param value
+        *            The value of the parameter
+        * @return The previous value, or <code>null</code> if there was no
+        *         previous value
+        */
+       public String put(String key, String value) {
+               return parameters.put(key.toLowerCase(), value);
+       }
+
+       /**
+        * Returns the number of parameters in this message.
+        * 
+        * @return The number of parameters
+        */
+       public int size() {
+               return parameters.size();
+       }
+
+       /**
+        * @return Returns the payloadInputStream.
+        */
+       public InputStream getPayloadInputStream() {
+               return payloadInputStream;
+       }
+
+       /**
+        * @param payloadInputStream
+        *            The payloadInputStream to set.
+        */
+       public void setPayloadInputStream(InputStream payloadInputStream) {
+               this.payloadInputStream = payloadInputStream;
+       }
+
+       /**
+        * Returns a textual representation of this message, containing its 
name,
+        * the identifier, and the parameters.
+        * 
+        * @return A textual representation of this message
+        */
+       public String toString() {
+               return name + "[identifier=" + identifier + ",parameters=" + 
parameters.toString() + "]";
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Node.java
===================================================================
--- trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Node.java  
                        (rev 0)
+++ trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Node.java  
2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,82 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+/**
+ * Contains the hostname and port number of the Freenet node.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: Node.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public class Node {
+
+       /** The default port of FCPv2. */
+       public static final int DEFAULT_PORT = 9481;
+
+       /** The hostname of the node. */
+       protected String hostname;
+
+       /** The port number of the node. */
+       protected int port;
+
+       /**
+        * Creates a new node with the specified hostname and the default port
+        * number.
+        * 
+        * @param hostname
+        *            The hostname of the node
+        * @see #DEFAULT_PORT
+        */
+       public Node(String hostname) {
+               this(hostname, DEFAULT_PORT);
+       }
+
+       /**
+        * Creates a new node with the specified hostname and port number.
+        * 
+        * @param hostname
+        *            The hostname of the node
+        * @param port
+        *            The port number of the node
+        */
+       public Node(String hostname, int port) {
+               this.hostname = hostname;
+               this.port = port;
+       }
+
+       /**
+        * Returns the hostname of the node.
+        * 
+        * @return The hostname of the node
+        */
+       public String getHostname() {
+               return hostname;
+       }
+
+       /**
+        * Returns the port number of the node.
+        * 
+        * @return The port number of the node
+        */
+       public int getPort() {
+               return port;
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Persistence.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Persistence.java
                           (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Persistence.java
   2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,87 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+/**
+ * The possible persistence options. This specify whether (and for how long) 
the
+ * node remembers to execute a request and the results. Possible values are
+ * <code>connection</code>, <code>reboot</code>, and <code>forever</code>.
+ * <code>connection</code> means that a request is aborted as soon as the
+ * connection to the node is severed. <code>reboot</code> means that a request
+ * is remembered as long as the node is running but not after restarts.
+ * <code>forever</code> finally means that a request persists until it is
+ * explicitely deleted.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: Persistence.java 9647 2006-07-17 18:24:50Z bombe $
+ * @see de.todesbaum.util.freenet.fcp2.ModifyPersistentRequest
+ * @see de.todesbaum.util.freenet.fcp2.RemovePersistentRequest
+ */
+public final class Persistence {
+
+       /**
+        * Denotes that a request should be terminated if the connection to the 
node
+        * is severed.
+        */
+       public static final Persistence CONNECTION = new 
Persistence("connection");
+
+       /** Denotes that a request should be remembered until the node is 
restarted. */
+       public static final Persistence REBOOT = new Persistence("reboot");
+
+       /**
+        * Denotes that a request should be remembered until it is explicitely
+        * deleted.
+        */
+       public static final Persistence FOREVER = new Persistence("forever");
+
+       /** The name of this persistence option. */
+       private String name;
+
+       /**
+        * Private constructor that creates a persistence option with the 
specified
+        * name.
+        * 
+        * @param name
+        *            The name of the persistence option.
+        */
+       private Persistence(String name) {
+               this.name = name;
+       }
+
+       /**
+        * Returns the name of this persistence option.
+        * 
+        * @return The name of this persistence option
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Returns a textual representation of this persistence option. The 
result
+        * is identical to calling {@link #getName()}.
+        * 
+        * @return The name of this persistence option
+        */
+       public String toString() {
+               return name;
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/PriorityClass.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/PriorityClass.java
                         (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/PriorityClass.java
 2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,93 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+/**
+ * The possible priority classes. Possible values are, in order of descending
+ * priority: <code>maximum</code> (anything more important than fproxy),
+ * <code>interactive</code> (fproxy), <code>semi-interactive</code> (fproxy
+ * immediate mode large file downloads, not to disk), <code>updatable</code>
+ * (updatable site checks), <code>bulk</code> (large file downloads to disk),
+ * <code>prefetch</code>, <code>minimum</code>.
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: PriorityClass.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public final class PriorityClass {
+
+       /** Denotes <code>maximum</code> priority class. */
+       public static final PriorityClass MAXIMUM = new 
PriorityClass("maximum", 0);
+
+       /** Denotes <code>interactive</code> priority class. */
+       public static final PriorityClass INTERACTIVE = new 
PriorityClass("interactive", 1);
+
+       /** Denotes <code>semi-interactive</code> priority class. */
+       public static final PriorityClass SEMI_INTERACTIVE = new 
PriorityClass("semiInteractive", 2);
+
+       /** Denotes <code>updatable</code> priority class. */
+       public static final PriorityClass UPDATABLE = new 
PriorityClass("updatable", 3);
+
+       /** Denotes <code>bulk</code> priority class. */
+       public static final PriorityClass BULK = new PriorityClass("bulk", 4);
+
+       /** Denotes <code>prefetch</code> priority class. */
+       public static final PriorityClass PREFETCH = new 
PriorityClass("prefetch", 5);
+
+       /** Denotes <code>minimum</code> priority class. */
+       public static final PriorityClass MINIMUM = new 
PriorityClass("minimum", 6);
+
+       /** The name of the priority class. */
+       private String name;
+
+       /** The value of the priority class. */
+       private int value;
+
+       /**
+        * Creates a new priority class with the specified name and value.
+        * 
+        * @param name
+        *            The name of the priority class
+        * @param value
+        *            The value of the priority class
+        */
+       private PriorityClass(String name, int value) {
+               this.name = name;
+               this.value = value;
+       }
+
+       /**
+        * Returns the name of this priority class.
+        * 
+        * @return The name of this priority class
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Returns the value of this priority class.
+        * 
+        * @return The value of this priority class
+        */
+       public int getValue() {
+               return value;
+       }
+
+}

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/RedirectFileEntry.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/RedirectFileEntry.java
                             (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/RedirectFileEntry.java
     2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,45 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+public class RedirectFileEntry extends FileEntry {
+
+       final String targetURI;
+
+       public RedirectFileEntry(String filename, String contentType, String 
targetURI) {
+               super(filename, contentType);
+               this.targetURI = targetURI;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getName() {
+               return "redirect";
+       }
+
+       /**
+        * @return Returns the targetURI.
+        */
+       public String getTargetURI() {
+               return targetURI;
+       }
+}
\ No newline at end of file

Added: 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Verbosity.java
===================================================================
--- 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Verbosity.java 
                            (rev 0)
+++ 
trunk/apps/thingamablog/src/net/sf/thingamablog/util/freenet/fcp/Verbosity.java 
    2008-02-13 03:26:33 UTC (rev 17860)
@@ -0,0 +1,51 @@
+/*
+ * todesbaum-lib - 
+ * Copyright (C) 2006 David Roden
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.sf.thingamablog.util.freenet.fcp;
+
+/**
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id: Verbosity.java 9647 2006-07-17 18:24:50Z bombe $
+ */
+public final class Verbosity {
+
+       public static final Verbosity PROGRESS = new Verbosity(1);
+       public static final Verbosity COMPRESSION = new Verbosity(512);
+
+       public static final Verbosity NONE = new Verbosity(0);
+       public static final Verbosity ALL = new Verbosity(PROGRESS, 
COMPRESSION);
+
+       private final int value;
+
+       private Verbosity(int value) {
+               this.value = value;
+       }
+
+       private Verbosity(Verbosity verbosity1, Verbosity verbosity2) {
+               this(verbosity1.value | verbosity2.value);
+       }
+
+       /**
+        * @return Returns the value.
+        */
+       public int getValue() {
+               return value;
+       }
+
+}


Reply via email to