[freenet-cvs] r17860 - in trunk/apps/thingamablog/src/net/sf/thingamablog: . util util/freenet util/freenet/fcp

dieppe at freenetproject.org dieppe at freenetproject.org
Thu Feb 14 15:32:37 UTC 2008


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;
+	}
+
+}




More information about the cvs mailing list