gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r137 - / freeway freeway/doc freeway/etc freeway/etc/suppor


From: grothoff
Subject: [GNUnet-SVN] r137 - / freeway freeway/doc freeway/etc freeway/etc/support freeway/etc/support/clib freeway/lib freeway/res freeway/res/gnunet-swing freeway/res/gnunet-swing/images freeway/res/jnlp freeway/res/swing freeway/res/swing/images freeway/res/swing/system freeway/res/tests freeway/src freeway/src/org freeway/src/org/gnu freeway/src/org/gnu/freeway freeway/src/org/gnu/freeway/protocol freeway/src/org/gnu/freeway/protocol/afs freeway/src/org/gnu/freeway/protocol/afs/esed2 freeway/src/org/gnu/freeway/protocol/afs/swing freeway/src/org/gnu/freeway/protocol/chat freeway/src/org/gnu/freeway/protocol/dht freeway/src/org/gnu/freeway/protocol/tbench freeway/src/org/gnu/freeway/protocol/testbed freeway/src/org/gnu/freeway/protocol/tracekit freeway/src/org/gnu/freeway/server freeway/src/org/gnu/freeway/test freeway/src/org/gnu/freeway/transport freeway/src/org/gnu/freeway/transport/nat freeway/src/org/gnu/freeway/transport/tcp freeway/src/org/gnu/freeway/transport/udp freeway/src/org/gnu/freeway/util freeway/src/org/gnu/freeway/util/crypto freeway/src/org/gnu/freeway/util/io freeway/src/org/gnu/freeway/util/net freeway/src/org/gnu/freeway/util/ui
Date: Mon, 31 Jan 2005 17:07:29 -0800 (PST)

Author: grothoff
Date: 2005-01-31 17:07:27 -0800 (Mon, 31 Jan 2005)
New Revision: 137

Added:
   freeway/
   freeway/.classpath
   freeway/.cvsignore
   freeway/.project
   freeway/AUTHORS
   freeway/COPYING
   freeway/README
   freeway/build.properties
   freeway/build.sh
   freeway/build.xml
   freeway/build/
   freeway/doc/
   freeway/doc/examples.txt
   freeway/doc/man.css
   freeway/doc/man.xml
   freeway/doc/man.xsl
   freeway/doc/packaging
   freeway/doc/todo
   freeway/doc/using eclipse
   freeway/etc/
   freeway/etc/gnunet-chat.sh
   freeway/etc/gnunet-config.sh
   freeway/etc/gnunet-directory.sh
   freeway/etc/gnunet-download.sh
   freeway/etc/gnunet-insert.sh
   freeway/etc/gnunet-peer-info.sh
   freeway/etc/gnunet-pseudonym.sh
   freeway/etc/gnunet-search.sh
   freeway/etc/gnunet-shutdown.sh
   freeway/etc/gnunet-stats.sh
   freeway/etc/gnunet-swing.sh
   freeway/etc/gnunet-tests.sh
   freeway/etc/gnunet-trace.sh
   freeway/etc/gnunet-transport-check.sh
   freeway/etc/gnunet-ui-config.sh
   freeway/etc/gnunetd.sh
   freeway/etc/support/
   freeway/etc/support/Cleaner.java
   freeway/etc/support/clib/
   freeway/etc/support/clib/freeway-clib.c
   freeway/etc/support/clib/freeway-clib.h
   freeway/etc/support/clib/links.c
   freeway/etc/support/clib/links.h
   freeway/etc/support/clib/signals.c
   freeway/etc/support/clib/signals.h
   freeway/etc/support/debug/
   freeway/etc/support/proxy/
   freeway/lib/
   freeway/lib/batik-all.jar
   freeway/lib/bcprov-jdk14-124.jar
   freeway/lib/concurrent.jar
   freeway/lib/mysql-connector-java-3.0.10-stable-bin.jar
   freeway/lib/readme
   freeway/readme.html
   freeway/res/
   freeway/res/api.css
   freeway/res/daemon.logging
   freeway/res/gnunet-swing/
   freeway/res/gnunet-swing/images/
   freeway/res/gnunet-swing/images/16x16/
   freeway/res/gnunet.client.template
   freeway/res/gnunet.daemon.template
   freeway/res/jnlp/
   freeway/res/jnlp/batik.jnlp
   freeway/res/jnlp/bouncycastle-jce.jnlp
   freeway/res/jnlp/concurrent.jnlp
   freeway/res/jnlp/freeway.jnlp
   freeway/res/jnlp/logo64.jpg
   freeway/res/jnlp/mysql.jnlp
   freeway/res/quiet.logging
   freeway/res/swing/
   freeway/res/swing/daemon-window.xml
   freeway/res/swing/download.xml
   freeway/res/swing/gnunet-config.xml
   freeway/res/swing/images/
   freeway/res/swing/images/16x16/
   freeway/res/swing/images/logo.svg
   freeway/res/swing/images/splash.svg
   freeway/res/swing/images/start.svg
   freeway/res/swing/images/stop.svg
   freeway/res/swing/images/watermark.svg
   freeway/res/swing/insert.xml
   freeway/res/swing/main.xml
   freeway/res/swing/search-panel.xml
   freeway/res/swing/search-window.xml
   freeway/res/swing/stats-window.xml
   freeway/res/swing/system/
   freeway/res/swing/system/wizard.xml
   freeway/res/tests/
   freeway/res/tests/test-charset
   freeway/res/tests/test-config
   freeway/res/tests/test-config-2
   freeway/src/
   freeway/src/org/
   freeway/src/org/gnu/
   freeway/src/org/gnu/freeway/
   freeway/src/org/gnu/freeway/AbstractApplication.java
   freeway/src/org/gnu/freeway/AbstractClient.java
   freeway/src/org/gnu/freeway/AbstractServer.java
   freeway/src/org/gnu/freeway/Application.java
   freeway/src/org/gnu/freeway/Command.java
   freeway/src/org/gnu/freeway/DaemonLauncher.java
   freeway/src/org/gnu/freeway/GNUNetChat.java
   freeway/src/org/gnu/freeway/GNUNetConfig.java
   freeway/src/org/gnu/freeway/GNUNetDaemon.java
   freeway/src/org/gnu/freeway/GNUNetDirectory.java
   freeway/src/org/gnu/freeway/GNUNetDownload.java
   freeway/src/org/gnu/freeway/GNUNetInsert.java
   freeway/src/org/gnu/freeway/GNUNetPeerInfo.java
   freeway/src/org/gnu/freeway/GNUNetPseudonym.java
   freeway/src/org/gnu/freeway/GNUNetSearch.java
   freeway/src/org/gnu/freeway/GNUNetShutdown.java
   freeway/src/org/gnu/freeway/GNUNetStats.java
   freeway/src/org/gnu/freeway/GNUNetSwing.java
   freeway/src/org/gnu/freeway/GNUNetTests.java
   freeway/src/org/gnu/freeway/GNUNetTrace.java
   freeway/src/org/gnu/freeway/GNUNetTransportCheck.java
   freeway/src/org/gnu/freeway/GNUNetUIConfig.java
   freeway/src/org/gnu/freeway/Server.java
   freeway/src/org/gnu/freeway/gnunet-check.c
   freeway/src/org/gnu/freeway/gnunet-convert.c
   freeway/src/org/gnu/freeway/gnunet-delete.c
   freeway/src/org/gnu/freeway/gnunet-tbench.c
   freeway/src/org/gnu/freeway/gnunet-testbed.c
   freeway/src/org/gnu/freeway/net/
   freeway/src/org/gnu/freeway/protocol/
   freeway/src/org/gnu/freeway/protocol/AbstractProtocol.java
   freeway/src/org/gnu/freeway/protocol/Protocol.java
   freeway/src/org/gnu/freeway/protocol/afs/
   freeway/src/org/gnu/freeway/protocol/afs/AFSProtocol.java
   freeway/src/org/gnu/freeway/protocol/afs/BloomFilter2.java
   freeway/src/org/gnu/freeway/protocol/afs/DBHandle.java
   freeway/src/org/gnu/freeway/protocol/afs/EntryCallback.java
   freeway/src/org/gnu/freeway/protocol/afs/FileIndex.java
   freeway/src/org/gnu/freeway/protocol/afs/Handler.java
   freeway/src/org/gnu/freeway/protocol/afs/IndexedFileNameCallback.java
   freeway/src/org/gnu/freeway/protocol/afs/IndirectionTableEntry.java
   freeway/src/org/gnu/freeway/protocol/afs/IterState.java
   freeway/src/org/gnu/freeway/protocol/afs/LFS.java
   freeway/src/org/gnu/freeway/protocol/afs/Manager.java
   freeway/src/org/gnu/freeway/protocol/afs/Migration.java
   freeway/src/org/gnu/freeway/protocol/afs/MySQLHandle.java
   freeway/src/org/gnu/freeway/protocol/afs/Policy2.java
   freeway/src/org/gnu/freeway/protocol/afs/QueryManager.java
   freeway/src/org/gnu/freeway/protocol/afs/QueryRecord.java
   freeway/src/org/gnu/freeway/protocol/afs/Routing.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/
   freeway/src/org/gnu/freeway/protocol/afs/esed2/AFSConstants.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/AFSUtils.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/Block.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSDelete3Hash.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSDeleteChk.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSGetAvgPriority.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexFile.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexSuper.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSInsert3Hash.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSInsertChk.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSInsertSBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSLinkFile.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSNSQuery.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSQuery.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSResult3Hash.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSResultChk.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSResultSBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSUnindexBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSUnindexFile.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSUnindexSuper.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/CSUploadFile.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/ChkHashes.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/ContentBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/ContentEncoding.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/ContentIndex.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/DBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/DeleteURI.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/DeleteUtil.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/DownloadURI.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/DownloadUtil.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/EncryptedSBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/Extractor.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/FileIdentifier.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/GNDirectory.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/GNDirectoryDatabase.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/GeneralURI.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/IBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/IBlockData.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/IOContext.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/InsertURI.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/InsertUtil.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/InsertWrapper.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/KeyWords.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/Listener.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/NSSearchResultCallback.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/Node.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/NodeContext.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/P2P3HashResult.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/P2PChkResult.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/P2PNSQuery.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/P2PQuery.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/P2PSBlockResult.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/Policy.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/Priority.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/ProgressModel.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/ProgressStats.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/Pseudonym.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/RequestContinuation.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/RequestEntry.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/RequestManager.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/RootNode.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/RootNodeCallback.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/SBlock.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/SearchResultCallback.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/SearchURI.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/SendNSQueryContext.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/SendQueriesContext.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/TestTerminateThread.java
   freeway/src/org/gnu/freeway/protocol/afs/esed2/URI.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/
   freeway/src/org/gnu/freeway/protocol/afs/swing/CreatePseudonymDialog.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/DaemonWindow.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/DeletePseudonymDialog.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/DownloadAdapter.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/DownloadModel.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/DownloadWindow.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/InsertDialog.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/SController.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/SearchAdapter.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/SearchOverviewPanel.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/SearchPanel.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/SearchWindow.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/SelectDialog.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/StatsWindow.java
   freeway/src/org/gnu/freeway/protocol/afs/swing/about.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/about.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/delete.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/delete.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/directory.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/directory.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/directorydisplay.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/directorydisplay.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/download.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/download.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/helper.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/helper.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/insert.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/insert.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/insertprogress.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/insertprogress.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/main.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/main.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/namespace.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/namespace.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/pseudonyms.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/pseudonyms.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/saveas.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/saveas.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/search.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/search.h
   freeway/src/org/gnu/freeway/protocol/afs/swing/statistics.c
   freeway/src/org/gnu/freeway/protocol/afs/swing/statistics.h
   freeway/src/org/gnu/freeway/protocol/chat/
   freeway/src/org/gnu/freeway/protocol/chat/CSChatMessage.java
   freeway/src/org/gnu/freeway/protocol/chat/ChatProtocol.java
   freeway/src/org/gnu/freeway/protocol/chat/P2PChatMessage.java
   freeway/src/org/gnu/freeway/protocol/dht/
   freeway/src/org/gnu/freeway/protocol/dht/DHTConstants.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTDataContainer.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTDataList.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTDataListItem.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTFetchResult.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTMessageHeader.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTProtocol.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTReplyFailure.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTReplyResults.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTReplyStandard.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTReplyStatus.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestAPIId.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestCreate.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestDrop.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestFetch.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestInsert.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestInserted.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestJoin.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestLeave.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestStatus.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTRequestTables.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTResultSet.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTResultSetItem.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTStoredDataReference.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTTableConfig.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTTableHandle.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTTableId.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTTableMetaData.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTTableSet.java
   freeway/src/org/gnu/freeway/protocol/dht/DHTTableSetItem.java
   freeway/src/org/gnu/freeway/protocol/tbench/
   freeway/src/org/gnu/freeway/protocol/tbench/CSBenchReply.java
   freeway/src/org/gnu/freeway/protocol/tbench/CSBenchRequest.java
   freeway/src/org/gnu/freeway/protocol/tbench/P2PBenchReply.java
   freeway/src/org/gnu/freeway/protocol/tbench/P2PBenchRequest.java
   freeway/src/org/gnu/freeway/protocol/tbench/TBenchProtocol.java
   freeway/src/org/gnu/freeway/protocol/testbed/
   freeway/src/org/gnu/freeway/protocol/testbed/commands.c
   freeway/src/org/gnu/freeway/protocol/testbed/commands.h
   freeway/src/org/gnu/freeway/protocol/testbed/connect.php3
   freeway/src/org/gnu/freeway/protocol/testbed/display.php3
   freeway/src/org/gnu/freeway/protocol/testbed/functions.sh
   freeway/src/org/gnu/freeway/protocol/testbed/get-stats.c
   freeway/src/org/gnu/freeway/protocol/testbed/get-stats.h
   freeway/src/org/gnu/freeway/protocol/testbed/socket.c
   freeway/src/org/gnu/freeway/protocol/testbed/socket.h
   freeway/src/org/gnu/freeway/protocol/testbed/startup.php3
   freeway/src/org/gnu/freeway/protocol/testbed/testbed.c
   freeway/src/org/gnu/freeway/protocol/testbed/testbed.h
   freeway/src/org/gnu/freeway/protocol/tracekit/
   freeway/src/org/gnu/freeway/protocol/tracekit/CSTraceProbe.java
   freeway/src/org/gnu/freeway/protocol/tracekit/CSTraceReply.java
   freeway/src/org/gnu/freeway/protocol/tracekit/P2PTraceProbe.java
   freeway/src/org/gnu/freeway/protocol/tracekit/P2PTraceReply.java
   freeway/src/org/gnu/freeway/protocol/tracekit/RTE.java
   freeway/src/org/gnu/freeway/protocol/tracekit/TraceKitProtocol.java
   freeway/src/org/gnu/freeway/server/
   freeway/src/org/gnu/freeway/server/BufferEntry.java
   freeway/src/org/gnu/freeway/server/BufferEntryCallback.java
   freeway/src/org/gnu/freeway/server/BufferFillCallback.java
   freeway/src/org/gnu/freeway/server/CSGetCSMessageSupported.java
   freeway/src/org/gnu/freeway/server/CSGetClientCount.java
   freeway/src/org/gnu/freeway/server/CSGetHostInfo.java
   freeway/src/org/gnu/freeway/server/CSGetOptionReply.java
   freeway/src/org/gnu/freeway/server/CSGetOptionRequest.java
   freeway/src/org/gnu/freeway/server/CSGetP2PMessageSupported.java
   freeway/src/org/gnu/freeway/server/CSHostInfo.java
   freeway/src/org/gnu/freeway/server/CSShutdownRequest.java
   freeway/src/org/gnu/freeway/server/CSStatistics.java
   freeway/src/org/gnu/freeway/server/CSStatisticsRequest.java
   freeway/src/org/gnu/freeway/server/CSTrafficInfo.java
   freeway/src/org/gnu/freeway/server/CSTrafficRequest.java
   freeway/src/org/gnu/freeway/server/Capability.java
   freeway/src/org/gnu/freeway/server/ClientExitHandler.java
   freeway/src/org/gnu/freeway/server/ClientServer.java
   freeway/src/org/gnu/freeway/server/ConnectionService.java
   freeway/src/org/gnu/freeway/server/Core.java
   freeway/src/org/gnu/freeway/server/CoreForProtocol.java
   freeway/src/org/gnu/freeway/server/CoreForTransport.java
   freeway/src/org/gnu/freeway/server/CoreService.java
   freeway/src/org/gnu/freeway/server/DirectedTrafficCounter.java
   freeway/src/org/gnu/freeway/server/HELOCallback.java
   freeway/src/org/gnu/freeway/server/HELOLoader.java
   freeway/src/org/gnu/freeway/server/HelloExchangeService.java
   freeway/src/org/gnu/freeway/server/Host.java
   freeway/src/org/gnu/freeway/server/HostFailure.java
   freeway/src/org/gnu/freeway/server/HostIterator.java
   freeway/src/org/gnu/freeway/server/KnownHostsService.java
   freeway/src/org/gnu/freeway/server/LocalIdentity.java
   freeway/src/org/gnu/freeway/server/MessagesDispatcher.java
   freeway/src/org/gnu/freeway/server/P2PCapability.java
   freeway/src/org/gnu/freeway/server/P2PHangUp.java
   freeway/src/org/gnu/freeway/server/P2PHello.java
   freeway/src/org/gnu/freeway/server/P2PNoise.java
   freeway/src/org/gnu/freeway/server/P2PPing.java
   freeway/src/org/gnu/freeway/server/P2PPong.java
   freeway/src/org/gnu/freeway/server/P2PSequence.java
   freeway/src/org/gnu/freeway/server/P2PSessionKey.java
   freeway/src/org/gnu/freeway/server/PerNodeCallback.java
   freeway/src/org/gnu/freeway/server/PingPongService.java
   freeway/src/org/gnu/freeway/server/PolicyService.java
   freeway/src/org/gnu/freeway/server/SendEntry.java
   freeway/src/org/gnu/freeway/server/TrafficService.java
   freeway/src/org/gnu/freeway/server/TransportCallback.java
   freeway/src/org/gnu/freeway/server/TransportService.java
   freeway/src/org/gnu/freeway/test/
   freeway/src/org/gnu/freeway/test/AbstractTest.java
   freeway/src/org/gnu/freeway/test/BloomTest.java
   freeway/src/org/gnu/freeway/test/CRCTest.java
   freeway/src/org/gnu/freeway/test/CharsetTest.java
   freeway/src/org/gnu/freeway/test/ConfigTest.java
   freeway/src/org/gnu/freeway/test/CronTest.java
   freeway/src/org/gnu/freeway/test/FilterTest.java
   freeway/src/org/gnu/freeway/test/HashTest.java
   freeway/src/org/gnu/freeway/test/LayoutTest.java
   freeway/src/org/gnu/freeway/test/MySQLTest.java
   freeway/src/org/gnu/freeway/test/RSATest.java
   freeway/src/org/gnu/freeway/test/SemaphoreTest.java
   freeway/src/org/gnu/freeway/test/ShutdownTest.java
   freeway/src/org/gnu/freeway/test/SignalsTest.java
   freeway/src/org/gnu/freeway/test/StateTest.java
   freeway/src/org/gnu/freeway/test/StatusCallsTest.java
   freeway/src/org/gnu/freeway/test/StorageTest.java
   freeway/src/org/gnu/freeway/test/SymCipherTest.java
   freeway/src/org/gnu/freeway/test/TCPTest.java
   freeway/src/org/gnu/freeway/test/TableTest.java
   freeway/src/org/gnu/freeway/test/TimerTest.java
   freeway/src/org/gnu/freeway/test/high_db_test.c
   freeway/src/org/gnu/freeway/test/low_db_test.c
   freeway/src/org/gnu/freeway/test/weakkeytest.c
   freeway/src/org/gnu/freeway/transport/
   freeway/src/org/gnu/freeway/transport/AbstractSession.java
   freeway/src/org/gnu/freeway/transport/AbstractTransport.java
   freeway/src/org/gnu/freeway/transport/MessageHandler.java
   freeway/src/org/gnu/freeway/transport/MessagePack.java
   freeway/src/org/gnu/freeway/transport/Session.java
   freeway/src/org/gnu/freeway/transport/Transport.java
   freeway/src/org/gnu/freeway/transport/http.c
   freeway/src/org/gnu/freeway/transport/nat/
   freeway/src/org/gnu/freeway/transport/nat/NATAddress.java
   freeway/src/org/gnu/freeway/transport/nat/NATTransport.java
   freeway/src/org/gnu/freeway/transport/smtp.c
   freeway/src/org/gnu/freeway/transport/tcp/
   freeway/src/org/gnu/freeway/transport/tcp/TCPAddress.java
   freeway/src/org/gnu/freeway/transport/tcp/TCPMessagePack.java
   freeway/src/org/gnu/freeway/transport/tcp/TCPSession.java
   freeway/src/org/gnu/freeway/transport/tcp/TCPTransport.java
   freeway/src/org/gnu/freeway/transport/tcp/TCPWelcome.java
   freeway/src/org/gnu/freeway/transport/tcp6.c
   freeway/src/org/gnu/freeway/transport/udp/
   freeway/src/org/gnu/freeway/transport/udp/UDPAddress.java
   freeway/src/org/gnu/freeway/transport/udp/UDPMessage.java
   freeway/src/org/gnu/freeway/transport/udp/UDPSession.java
   freeway/src/org/gnu/freeway/transport/udp/UDPTransport.java
   freeway/src/org/gnu/freeway/transport/udp6.c
   freeway/src/org/gnu/freeway/util/
   freeway/src/org/gnu/freeway/util/AbstractAction.java
   freeway/src/org/gnu/freeway/util/AbstractFormatter.java
   freeway/src/org/gnu/freeway/util/AbstractIterator.java
   freeway/src/org/gnu/freeway/util/AbstractLogFormatter.java
   freeway/src/org/gnu/freeway/util/AbstractService.java
   freeway/src/org/gnu/freeway/util/Action.java
   freeway/src/org/gnu/freeway/util/BloomFilter.java
   freeway/src/org/gnu/freeway/util/CIDRNetwork.java
   freeway/src/org/gnu/freeway/util/CIDRNetworks.java
   freeway/src/org/gnu/freeway/util/ConfigurationParser.java
   freeway/src/org/gnu/freeway/util/ConsoleFormatter.java
   freeway/src/org/gnu/freeway/util/Constant.java
   freeway/src/org/gnu/freeway/util/DurationFormatter.java
   freeway/src/org/gnu/freeway/util/DynamicLibrary.java
   freeway/src/org/gnu/freeway/util/EvalAction.java
   freeway/src/org/gnu/freeway/util/FileFormatter.java
   freeway/src/org/gnu/freeway/util/IdentityService.java
   freeway/src/org/gnu/freeway/util/LoggedObject.java
   freeway/src/org/gnu/freeway/util/MasterTask.java
   freeway/src/org/gnu/freeway/util/NulAction.java
   freeway/src/org/gnu/freeway/util/OSAccess.java
   freeway/src/org/gnu/freeway/util/Option.java
   freeway/src/org/gnu/freeway/util/OptionsParser.java
   freeway/src/org/gnu/freeway/util/OutputFilter.java
   freeway/src/org/gnu/freeway/util/Prefs.java
   freeway/src/org/gnu/freeway/util/SafeAction.java
   freeway/src/org/gnu/freeway/util/ScheduledTask.java
   freeway/src/org/gnu/freeway/util/Scheduler.java
   freeway/src/org/gnu/freeway/util/Service.java
   freeway/src/org/gnu/freeway/util/ServiceException.java
   freeway/src/org/gnu/freeway/util/ServiceManager.java
   freeway/src/org/gnu/freeway/util/SignalEvent.java
   freeway/src/org/gnu/freeway/util/SignalListener.java
   freeway/src/org/gnu/freeway/util/SignalManager.java
   freeway/src/org/gnu/freeway/util/Signals.java
   freeway/src/org/gnu/freeway/util/SlaveTask.java
   freeway/src/org/gnu/freeway/util/StarFormatter.java
   freeway/src/org/gnu/freeway/util/Stat.java
   freeway/src/org/gnu/freeway/util/Statistics.java
   freeway/src/org/gnu/freeway/util/StatusCallsService.java
   freeway/src/org/gnu/freeway/util/Task.java
   freeway/src/org/gnu/freeway/util/TaskHome.java
   freeway/src/org/gnu/freeway/util/TrafficCounter.java
   freeway/src/org/gnu/freeway/util/Unit.java
   freeway/src/org/gnu/freeway/util/Utils.java
   freeway/src/org/gnu/freeway/util/Voyager.java
   freeway/src/org/gnu/freeway/util/crypto/
   freeway/src/org/gnu/freeway/util/crypto/Crypto.java
   freeway/src/org/gnu/freeway/util/crypto/EncryptedData.java
   freeway/src/org/gnu/freeway/util/crypto/HashCode160.java
   freeway/src/org/gnu/freeway/util/crypto/HostIdentity.java
   freeway/src/org/gnu/freeway/util/crypto/PrivateKey.java
   freeway/src/org/gnu/freeway/util/crypto/PublicKey.java
   freeway/src/org/gnu/freeway/util/crypto/SessionKey.java
   freeway/src/org/gnu/freeway/util/crypto/Signature.java
   freeway/src/org/gnu/freeway/util/io/
   freeway/src/org/gnu/freeway/util/io/Connector.java
   freeway/src/org/gnu/freeway/util/io/ConnectorEndPoint.java
   freeway/src/org/gnu/freeway/util/io/DirLocation.java
   freeway/src/org/gnu/freeway/util/io/FileLocation.java
   freeway/src/org/gnu/freeway/util/io/IOUtils.java
   freeway/src/org/gnu/freeway/util/io/LineDecoder.java
   freeway/src/org/gnu/freeway/util/io/LinkLocation.java
   freeway/src/org/gnu/freeway/util/io/Location.java
   freeway/src/org/gnu/freeway/util/io/MappedFile.java
   freeway/src/org/gnu/freeway/util/io/TextDecoder.java
   freeway/src/org/gnu/freeway/util/io/Traverser.java
   freeway/src/org/gnu/freeway/util/io/TraverserContext.java
   freeway/src/org/gnu/freeway/util/io/storage.c
   freeway/src/org/gnu/freeway/util/net/
   freeway/src/org/gnu/freeway/util/net/CSHandler.java
   freeway/src/org/gnu/freeway/util/net/CSMessage.java
   freeway/src/org/gnu/freeway/util/net/CSResult.java
   freeway/src/org/gnu/freeway/util/net/CSServer.java
   freeway/src/org/gnu/freeway/util/net/CSSession.java
   freeway/src/org/gnu/freeway/util/net/CSSessionHandler.java
   freeway/src/org/gnu/freeway/util/net/CSUnknown.java
   freeway/src/org/gnu/freeway/util/net/ErrorReporter.java
   freeway/src/org/gnu/freeway/util/net/NetUtils.java
   freeway/src/org/gnu/freeway/util/net/P2PHandler.java
   freeway/src/org/gnu/freeway/util/net/P2PMessage.java
   freeway/src/org/gnu/freeway/util/net/Persistent.java
   freeway/src/org/gnu/freeway/util/net/PersistentDecoder.java
   freeway/src/org/gnu/freeway/util/net/PersistentHelper.java
   freeway/src/org/gnu/freeway/util/net/PersistentReader.java
   freeway/src/org/gnu/freeway/util/net/PersistentSocket.java
   freeway/src/org/gnu/freeway/util/net/PersistentWriter.java
   freeway/src/org/gnu/freeway/util/net/TCPServer.java
   freeway/src/org/gnu/freeway/util/net/TCPSession.java
   freeway/src/org/gnu/freeway/util/ui/
   freeway/src/org/gnu/freeway/util/ui/AbstractAdapter.java
   freeway/src/org/gnu/freeway/util/ui/Adapter.java
   freeway/src/org/gnu/freeway/util/ui/CompoundComparator.java
   freeway/src/org/gnu/freeway/util/ui/Controller.java
   freeway/src/org/gnu/freeway/util/ui/DefaultComparator.java
   freeway/src/org/gnu/freeway/util/ui/GBar.java
   freeway/src/org/gnu/freeway/util/ui/GColumn.java
   freeway/src/org/gnu/freeway/util/ui/GConsole.java
   freeway/src/org/gnu/freeway/util/ui/GDialog.java
   freeway/src/org/gnu/freeway/util/ui/GFile.java
   freeway/src/org/gnu/freeway/util/ui/GForm.java
   freeway/src/org/gnu/freeway/util/ui/GFrame.java
   freeway/src/org/gnu/freeway/util/ui/GProgress.java
   freeway/src/org/gnu/freeway/util/ui/GScrollPane.java
   freeway/src/org/gnu/freeway/util/ui/GSplash.java
   freeway/src/org/gnu/freeway/util/ui/GStack.java
   freeway/src/org/gnu/freeway/util/ui/GStatus.java
   freeway/src/org/gnu/freeway/util/ui/GStyledText.java
   freeway/src/org/gnu/freeway/util/ui/GSwap.java
   freeway/src/org/gnu/freeway/util/ui/GTable.java
   freeway/src/org/gnu/freeway/util/ui/GText.java
   freeway/src/org/gnu/freeway/util/ui/GWizard.java
   freeway/src/org/gnu/freeway/util/ui/GWizardPage.java
   freeway/src/org/gnu/freeway/util/ui/ListToTableModel.java
   freeway/src/org/gnu/freeway/util/ui/SVGRenderer.java
   freeway/src/org/gnu/freeway/util/ui/SortedListModel.java
   freeway/src/org/gnu/freeway/util/ui/SortedSelectionModel.java
   freeway/src/org/gnu/freeway/util/ui/TileLayout.java
   freeway/src/org/gnu/freeway/util/ui/UIAction.java
   freeway/src/org/gnu/freeway/util/ui/UIHelper.java
   freeway/src/org/gnu/freeway/util/ui/UIResources.java
Log:
i

Added: freeway/.classpath
===================================================================
--- freeway/.classpath  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/.classpath  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="etc/support"/>
+       <classpathentry kind="con" 
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry kind="lib" 
path="/Users/svallee/Dev/Projects/freeway/lib/concurrent.jar"/>
+       <classpathentry kind="lib" 
path="/Users/svallee/Dev/Projects/freeway/lib/batik-all.jar"/>
+       <classpathentry kind="output" path=".build"/>
+</classpath>

Added: freeway/.cvsignore
===================================================================
--- freeway/.cvsignore  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/.cvsignore  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1 @@
+build

Added: freeway/.project
===================================================================
--- freeway/.project    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/.project    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>freeway</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+       <linkedResources>
+               <link>
+                       <name>*config*</name>
+                       <type>2</type>
+                       <location>/Users/svallee/.freeway</location>
+               </link>
+       </linkedResources>
+</projectDescription>

Added: freeway/AUTHORS
===================================================================
--- freeway/AUTHORS     2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/AUTHORS     2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,54 @@
+Primary developers (at the moment):
+Blake Matheny <address@hidden>
+Christian Grothoff <address@hidden>
+Glenn McGrath <address@hidden>
+Igor Wronsky <address@hidden>
+Krista Bennett <address@hidden>
+Stéphane Vallée <address@hidden>
+Nils Durner <address@hidden>
+
+Code contributions also came from:
+Eric Haumant <address@hidden>
+Gerd Knorr <address@hidden>
+Hendrik Pagenhardt <address@hidden>
+Ioana Patrascu <address@hidden>
+<address@hidden>
+James Blackwell <address@hidden>
+James Liang <address@hidden>
+Jan Vitek <address@hidden>
+Jürgen Appel <address@hidden>
+Larry Waldo <address@hidden>
+Ludovic Courtès <address@hidden>
+Paul Ruth <address@hidden>
+Renaldo Ferreira <address@hidden>
+Tiberius Stef <address@hidden>
+Tzvetan Horozov <address@hidden>
+Uli Luckas <address@hidden>
+Werner Koch <address@hidden> [original code of libgcrypt]
+Kevin Vandersloot <address@hidden> [original code of gnome-system-monitor]
+
+DHT-module was contributed by:
+Marko Räihä
+Risto Saarelma
+Antti Salonen
+Tuomas Toivonen
+Tomi Tukiainen 
+Simo Viitanen
+
+Translations:
+Chinese  : Di Ma <address@hidden>
+Danish   : Jens Palsberg <address@hidden>
+Deutsch  : Christian Grothoff <address@hidden>
+French   : Mathieu <address@hidden>, Eric Haumant <address@hidden>, 
address@hidden
+Japanese : Hiroshi Yamauchi <address@hidden>
+Polish   : Adam Welc <address@hidden>
+Romaneste: Bogdan Carbunar <address@hidden>
+
+Logos:
+GNU in Net  : Christian Muellner <address@hidden>
+GNU with Net: Christian Muellner <address@hidden>
+AFS Face    : Alex Jones <address@hidden>
+
+Maintainers:
+FreeBSD Port - Kirill Ponomarew <address@hidden>
+Debian Package - Glenn McGrath <address@hidden>

Added: freeway/COPYING
===================================================================
--- freeway/COPYING     2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/COPYING     2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: freeway/README
===================================================================
--- freeway/README      2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/README      2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,72 @@
+                       Welcome to Freeway
+
+Freeway is a Java port of the secure peer-to-peer GNUnet framework.
+For a longer description of the GNUnet system, please see GNUnet's
+webpages (http://www.gnu.org/projects/GNUnet/ and
+http://www.ovmj.org/GNUnet/).
+
+Goals
+-----
+
+Freeway aims to...
+  . spread the use of secure peer-to-peer tools
+  . reach a larger audience by bringing GNUnet project to the Java community
+  . educate by providing a clean Java implementation that uses 
+    well-known design patterns
+
+
+Release
+-------
+
+The Freeway team is very happy to announce that the initial version of
+Freeway is now available.  This release provides a minimal
+implementation of the GNUnet core along with a few command tools. A
+first draft of a Swing client is also available.
+
+Please note that this is an ALPHA release. The framework has not been
+tested on a large scale yet. Bugs are common and the documentation may
+not be adequate for unexperienced users.
+
+
+How to build it ?
+-----------------
+
+You need Jikes to compile Freeway.
+An ant build file has been provided. To build needed jars, type:
+> cd $PROJECT_HOME
+> ant build
+
+
+How to use it ?
+---------------
+
+The default configuration should be okay for most of the systems
+($PROJECT_HOME/res/gnunet.root and $PROJECT_HOME/res/gnunet.user). For
+more information on available options and their meanings, please see
+pages on http://www.ovmj.org/GNUnet/.
+
+To start daemon, use gnunetd.sh script in $PROJECT_HOME/etc:
+> cd $PROJECT_HOME
+> ./etc/gnunetd.sh -L INFO
+
+Don't forget to set logging level to appropriate value since a lot of
+logging may be generated.
+
+
+Make the project live
+---------------------
+
+Any contribution will be greatly appreciated. Please submit bugs to
+http://www.ovmj.org/~mantis/ and patches via E-Mail to
address@hidden
+
+
+Stay tuned
+----------
+
+http://www.ovmj.org/GNUnet/freeway/
+http://mail.gnu.org/mailman/listinfo/freeway-developers
+
+
+Want to freely travel from peer to peer?  Take the freeway!
+The Freeway team.

Added: freeway/build.properties
===================================================================
--- freeway/build.properties    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/build.properties    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,11 @@
+# Put here some additional configuration you need to execute targets
+#
+
+api.target=../freeway-docs/doc/api
+
+archive.target=..
+
+jnlp.target=../freeway-docs/doc/jnlp
+jnlp.target.url=http://localhost/~svallee/dev/freeway-docs/jnlp/
+jnlp.sign.alias=freeway-team
+jnlp.sign.password=blurp9998

Added: freeway/build.sh
===================================================================
--- freeway/build.sh    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/build.sh    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Build C library used by Freeway.
+#
+
+rm -f  \
+       build/*.o       \
+       build/*.jnilib
+
+cc -Wall       \
+       -I etc/support/clib     \
+       -c etc/support/clib/signals.c   \
+       -o build/signals.o
+
+cc -Wall       \
+       -I etc/support/clib     \
+       -c etc/support/clib/links.c     \
+       -o build/links.o
+
+cc -Wall       \
+       -I etc/support/clib     \
+       -I $JAVA_HOME/include   \
+       -c etc/support/clib/freeway-clib.c      \
+       -o build/freeway-clib.o
+
+
+# fixme: Mac OS X specific
+
+cc -dynamiclib \
+       -framework JavaVM       \
+       build/signals.o build/links.o build/freeway-clib.o      \
+       -o build/libfreeway-clib.jnilib
+

Added: freeway/build.xml
===================================================================
--- freeway/build.xml   2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/build.xml   2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,309 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="Freeway" default="build" basedir=".">
+       <property name="build.compiler" value="jikes" />
+       <property name="build.sysclasspath" value="ignore" />
+       <property file="build.properties" />
+
+       <target name="init">
+               <tstamp>
+                       <format property="stamp" pattern="MMddyyyyHHmmss" />
+               </tstamp>
+
+               <property name="project.root" value="${basedir}" />
+               <dirname property="project.parent" file="${project.root}" />
+               <basename property="project.name" file="${project.root}" />
+
+               <property name="project.build" location="${project.root}/build" 
/>
+               <property name="project.doc" location="${project.root}/doc" />
+               <property name="project.etc" location="${project.root}/etc" />
+               <property name="project.lib" location="${project.root}/lib" />
+               <property name="project.res" location="${project.root}/res" />
+               <property name="project.src" location="${project.root}/src" />
+
+               <path id="build.classpath">
+                       <fileset dir="${project.lib}">
+                               <include name="*.jar" />
+                       </fileset>
+               </path>
+       </target>
+
+       <target name="build" depends="init">
+               <mkdir dir="${project.build}/classes" />
+
+               <javac srcdir="${project.src}"
+                       destdir="${project.build}/classes"
+                       classpathref="build.classpath"
+                       includeJavaRuntime="no"
+                       includeAntRuntime="no"
+                       source="1.4"
+                       encoding="UTF-8"
+                       debug="on"
+                       optimize="off"
+                       />
+
+               <jar destfile="${project.build}/freeway.jar">
+                       <fileset dir="${project.build}/classes">
+                               <exclude name="org/gnu/freeway/protocol/**" />
+                               <exclude name="org/gnu/freeway/transport/**" />
+                       </fileset>
+
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/Protocol.class" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/MessagePack.class" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/Session.class" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/Transport.class" />
+               </jar>
+
+               <jar destfile="${project.build}/freeway-afs.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/afs/**" 
excludes="org/gnu/freeway/protocol/afs/MySQLHandle*" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/AbstractProtocol*" />
+                       <fileset dir="${project.res}/swing" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.protocol.afs.AFSProtocol" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-afs-mysql.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/afs/MySQLHandle*" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.protocol.afs.MySQLHandle" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-chat.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/chat/**" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/AbstractProtocol*" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.protocol.chat.ChatProtocol" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-dht.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/dht/**" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/AbstractProtocol*" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.protocol.dht.DHTProtocol" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-tbench.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/tbench/**" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/AbstractProtocol*" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.protocol.tbench.TBenchProtocol" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-tracekit.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/tracekit/**" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/protocol/AbstractProtocol*" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.protocol.tracekit.TraceKitProtocol" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-tcp.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/tcp/**" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/AbstractSession.class" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/AbstractTransport.class" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.transport.tcp.TCPTransport" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-udp.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/udp/**" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/AbstractSession.class" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/AbstractTransport.class" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.transport.udp.UDPTransport" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-nat.jar">
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/nat/**" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/AbstractSession.class" />
+                       <fileset dir="${project.build}/classes" 
includes="org/gnu/freeway/transport/AbstractTransport.class" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.transport.nat.NATTransport" />
+                       </manifest>
+               </jar>
+
+               <jar destfile="${project.build}/freeway-for-apps.jar">
+                       <fileset dir="${project.build}/classes" />
+                       <zipfileset dir="${project.res}/tests" prefix="tests" />
+                       <zipfileset dir="${project.res}/swing" prefix="" />
+                       <zipfileset dir="${project.res}" includes="*.template" 
prefix="" />
+                       <manifest>
+                               <attribute name="Main-Class" 
value="org.gnu.freeway.GNUNetSwing" />
+                       </manifest>
+               </jar>
+
+               <exec dir="." executable="./build.sh" />
+       </target>
+
+       <target name="fix-build" depends="build">
+               <javac srcdir="${project.etc}/support"
+                       destdir="${project.build}/classes"
+                       includeJavaRuntime="no"
+                       includeAntRuntime="no"
+                       source="1.4"
+                       encoding="UTF-8"
+                       debug="on"
+                       optimize="off"
+                       includes="Cleaner.java">
+                       <classpath>
+                               <path refid="build.classpath" />
+                               <path location="${project.build}/classes" />
+                       </classpath>
+               </javac>
+       </target>
+
+       <target name="fix-tabs" depends="fix-build">
+               <java classname="Cleaner" fork="yes" dir="${project.build}">
+                       <classpath>
+                               <path refid="build.classpath" />
+                               <path location="${project.build}/classes" />
+                       </classpath>
+
+                       <jvmarg value="-ea" />
+                       <arg value="${project.src}" />
+               </java>
+       </target>
+
+       <target name="test" depends="init">
+               <mkdir dir="${project.build}/classes" />
+               <javac srcdir="${project.etc}/support"
+                       destdir="${project.build}/classes"
+                       classpathref="build.classpath"
+                       includeJavaRuntime="no"
+                       includeAntRuntime="no"
+                       source="1.4"
+                       encoding="UTF-8"
+                       debug="on"
+                       optimize="off"
+                       includes="ReachTest.java"
+                       />
+               <java classname="ReachTest" fork="yes" dir="${project.build}">
+                       <classpath>
+                               <path refid="build.classpath" />
+                               <path location="${project.build}/classes" />
+                       </classpath>
+
+                       <jvmarg value="-ea" />
+                       <jvmarg value="-Djava.nio.preferSelect=true" />
+               </java>
+       </target>
+
+       <target name="make-headers" depends="build">
+               <javah outputFile="${project.etc}/support/clib/freeway-clib.h">
+                       <class name="org.gnu.freeway.util.OSAccess" />
+                       <classpath>
+                               <path refid="build.classpath" />
+                               <path location="${project.build}/freeway.jar" />
+                       </classpath>
+               </javah>
+       </target>
+
+       <!-- Delete All Compilation Generated Files -->
+
+       <target name="clean" depends="init">
+               <delete dir="${project.build}/classes" quiet="true" />
+               <delete dir="${project.build}/doc" quiet="true" />
+
+               <delete quiet="true">
+                       <fileset dir="${project.build}" 
includes="*.jar,*.o,*.jnilib" />
+               </delete>
+       </target>
+
+       <!-- API Documentation Generation -->
+
+       <target name="doc" depends="init" if="api.target">
+               <mkdir dir="${project.build}/doc/api" />
+
+               <javadoc sourcepath="${project.src}"
+                       destdir="${project.build}/doc/api"
+                       author="true" version="true" private="true" use="true" 
splitindex="true"
+                       windowtitle="Freeway API"
+                       stylesheetfile="${project.res}/api.css"
+                       packagenames="org.gnu.*"
+                       classpathref="build.classpath"
+                       additionalparam="-breakiterator"
+                       source="1.4">
+
+                       <doctitle><![CDATA[<h1>Freeway API 
${stamp}</h1>]]></doctitle>
+                       <header><![CDATA[Freeway API ${stamp}]]></header>
+                       <bottom><![CDATA[<i>2004 GNU</i>]]></bottom>
+
+                       <link href="http://java.sun.com/j2se/1.4/docs/api/"; />
+                       <link href="http://xml.apache.org/batik/javadoc/"; />
+
+                       <group title="NAT Transport Layer" 
packages="org.gnu.freeway.transport.nat*" />
+                       <group title="TCP Transport Layer" 
packages="org.gnu.freeway.transport.tcp*" />
+                       <group title="UDP Transport Layer" 
packages="org.gnu.freeway.transport.udp*" />
+
+                       <group title="AFS Protocol" 
packages="org.gnu.freeway.protocol.afs*" />
+                       <group title="Chat Protocol" 
packages="org.gnu.freeway.protocol.chat*" />
+                       <group title="DHT Protocol" 
packages="org.gnu.freeway.protocol.dht*" />
+                       <group title="TBench Protocol" 
packages="org.gnu.freeway.protocol.tbench*" />
+                       <group title="TraceKit Protocol" 
packages="org.gnu.freeway.protocol.tracekit*" />
+               </javadoc>
+
+               <delete quiet="true">
+                       <fileset dir="${api.target}" excludes="**/CVS/**/*" />
+               </delete>
+
+               <copy todir="${api.target}">
+                       <fileset dir="${project.build}/doc/api" />
+               </copy>
+       </target>
+
+       <!-- Nothing But A Clean Archive (Nor CVS, Neither Build Stuff) -->
+
+       <target name="make-archive" depends="clean" if="archive.target">
+               <property name="backup.name" 
value="${project.name}-${stamp}.tar.bz2" />
+
+               <delete file="${archive.target}/${backup.name}" quiet="true" />
+
+               <tar destfile="${archive.target}/${backup.name}"
+                       basedir="${project.parent}"
+                       compression="bzip2">
+
+                       <include name="${project.name}/**/*" />
+                       <exclude name="${project.name}/.*" />
+                       <exclude name="${project.name}/.*/**/*" />
+                       <exclude name="${project.name}/**/CVS/**/*" />
+               </tar>
+       </target>
+
+       <!-- JNLP Package Creation -->
+
+       <target name="install-jnlp" depends="build" if="jnlp.target">
+               <delete quiet="true">
+                       <fileset dir="${jnlp.target}" includes="**/*" />
+               </delete>
+
+               <copy todir="${jnlp.target}">
+                       <fileset dir="${project.build}" 
includes="freeway-for-apps.jar" />
+                       <fileset dir="${project.lib}" includes="*.jar" />
+                       <fileset dir="${project.res}/jnlp" includes="logo.png" 
/>
+               </copy>
+
+               <copy todir="${jnlp.target}" overwrite="true">
+                       <fileset dir="${project.res}/jnlp" includes="*.jnlp" />
+                       <filterset>
+                               <filter token="REMOTE_URL" 
value="${jnlp.target.url}"/>
+                       </filterset>
+               </copy>
+
+               <signjar jar="${jnlp.target}/freeway-for-apps.jar" 
alias="${jnlp.sign.alias}" storepass="${jnlp.sign.password}" />
+               <signjar jar="${jnlp.target}/batik-all.jar" 
alias="${jnlp.sign.alias}" storepass="${jnlp.sign.password}" />
+               <signjar jar="${jnlp.target}/concurrent.jar" 
alias="${jnlp.sign.alias}" storepass="${jnlp.sign.password}" />
+               <signjar 
jar="${jnlp.target}/mysql-connector-java-3.0.10-stable-bin.jar" 
alias="${jnlp.sign.alias}" storepass="${jnlp.sign.password}" />
+
+               <mkdir dir="${jnlp.target}/daemon" />
+               <copy todir="${jnlp.target}/daemon">
+                       <fileset dir="${project.build}" includes="*.jar" 
excludes="freeway-for-apps.jar" />
+               </copy>
+       </target>
+</project>

Added: freeway/doc/examples.txt
===================================================================
--- freeway/doc/examples.txt    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/doc/examples.txt    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,6 @@
+gnunet-download -o "COPYING" -- 
gnunet://afs/77DBE6F971D66F641B2262DDCE78CA8FB6815E60.E34BFD7843D4C8469EFC3DAD260F1F71783E2A87.0466DC92.17992
+=> The GNU Public License <= (mimetype: text/plain)
+
+gnunet-download -o "not_the_gpl.txt" -- 
gnunet://afs/1A6ECAD995A986CE8AA30E28FB0C43FD64D014B5.AB4C7104D0F29379BAC660BC380FE02A2222A45D.EE7E98D4.25
+=> This is not the GNU GPL <= (mimetype: unknown)
+

Added: freeway/doc/man.css
===================================================================
--- freeway/doc/man.css 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/doc/man.css 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,66 @@
+/* manual pages' stylesheet */
+
+body {
+       color:                          #000000;
+       background-color:       #ffffff;
+       font:                           normal normal normal 15px "Trebuchet 
MS";
+       padding:                                13px;
+       margin:                         0px;
+       }
+
+.block0 {
+       font-size:                      20px;
+       margin:                         0px 0px 30px 0px;
+       }
+
+.block1 {
+       font-size:                      15px;
+       margin:                         0px 0px 13px 0px;
+       }
+
+.block2 {
+       font-size:                      12px;
+       margin:                         2px 0px 7px 45px;
+       }
+
+.block3 {
+       font-size:                      12px;
+       margin:                         2px 0px 0px 45px;
+       }
+
+.emp {
+       background-color:       #dddddd;
+       border-bottom:          solid 1px black;
+       margin-bottom:          13px;
+       }
+
+.value {
+       color:                          #215788;
+       font-weight:                    bold;
+       font-style:                     italic;
+       }
+
+.code {
+       font-family:                    monospace;
+       zborder:                                solid 1px black;
+       background-color:       rgb(127,159,191);
+       padding:                                3px 3px 3px 10px;
+       margin:                         3px 3px 3px 0px;
+       }
+
+a {
+       color:                          #42adff;
+       }
+
+a:visited {
+       color:                          #215788;
+       }
+
+a:hover {
+       color:                          #215788;
+       }
+
+a:active {
+       color:                          #215788;
+       }
+

Added: freeway/doc/man.xml
===================================================================
--- freeway/doc/man.xml 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/doc/man.xml 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,1544 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<?xml-stylesheet type="text/xsl" href="man.xsl" ?>
+
+<man-pages>
+
+<man-page id="GNUNET-CHAT" level="1" name="gnunet-chat" last="2004/04/24">
+       <description>a command line interface to chat via GNUnet</description>
+
+       <long-description>
+       Chat via GNUnet.
+       </long-description>
+
+       <synopsis>gnunet-chat [OPTIONS]</synopsis>
+
+       <options>
+               <option short="h" long="help">
+               Print help page.
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               Load config file <arg /> (default is 
<v>~/.gnunet/gnunet.conf</v>).
+               </option>
+
+               <option short="v" long="version">
+               Print the version number.
+               </option>
+
+               <option short="n" arg="NICKNAME">
+               Use <arg /> for the nick.
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       <page /> is meant as a demo application for how to implement 
applications using the GNUnet infrastructure.
+       It is not meant as a serious tool. You need to enable the "chat" in 
gnunet.conf in order to use <page />.<break />
+       <page /> is neither efficient nor secure and has serious design flaws. 
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="GNUnet 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-CHECK" level="1" name="gnunet-check" last="2004/04/26">
+       <description>a tool to check gnunetd's storage for 
consistency</description>
+
+       <long-description>
+               <page /> checks gnunetd's AFS databases for consistency.
+               This includes verifying that the different lookup methods
+               used by GNUnet (index list, database buckets, bloomfilters, 
+               etc) are consistent with each other. In some cases the
+               only solution available is to remove the problematic data entry.
+               <break />
+
+               Warning: each problematic but fixable, nonindexed content 
+               block will be restored with priority 0. This means that as
+               the database gets full, the restored content is among
+               the first to flush out. 
+       </long-description>
+
+       <synopsis>
+               gnunet-check [OPTIONS] 
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               Print help page.
+               </option>
+               
+               <option short="c" long="config" arg="FILENAME">
+               Load config file <arg /> (default is <v>/etc/gnunet.conf</v>).
+               </option>
+               
+               <option short="v" long="version">
+               Print the version number.
+               </option>
+               
+               <option short="u" long="update">
+               Update AFS databases from one version of GNUnet to another (if 
possible).
+               </option>
+               
+               <option short="a" long="all">
+               Check everything.
+               </option>
+               
+               <option short="f" long="files">
+               Check only the file list database (re-inserts all indexed files 
and checks if the database is consistent with that).
+               </option>
+               
+               <option short="d" long="data">
+               Check the block database (walks over all blocks in the database 
and checks if they make sense).
+               </option>
+               
+               <option short="p" long="prio" arg="PRIORITY">
+               Priority for the restored, non-indexed content.<break />
+               For indexed content, the config file value 
<v>GNUNET-INSERT/CONTENT-PRIORITY</v> will be used.<break />
+               Note: priority defaults to <v>0</v> which will cause the 
restored content to flush out when the disk gets full. 
+               </option>
+
+               <option short="n" long="nofix">
+               Check but do not fix problems.
+               </option>
+
+               <option short="V" long="verbose">
+               Be verbose.
+               </option>
+
+               <option short="q" long="quiet">
+               Be quiet.
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       <page /> can run for a long, long time, depending on
+       how much content you are sharing.  You should
+       also expect to see some heavy disk activity.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="Used GNUnet 
configuration file" />
+               <file path="~/.gnunet/data/afs/*" content="AFS database related 
files." />
+               <file path="~/.gnunet/data/afs/database*" content="Indexing 
database files." />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-CONVERT" level="1" name="gnunet-convert" 
last="2004/04/20">
+       <description>a tool to convert the GNUnet AFS database</description>
+
+       <long-description>
+               <page /> can convert an existing GNUnet AFS block database from
+               one format to another.  Current formats are "gdbm", "tdb", 
"bdb",
+               "mysql" and "directory".  
+               You must call <page /> whenever you change the quota or the 
database type.  
+       </long-description>
+
+       <synopsis>
+               gnunet-convert [OPTIONS] 
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               Print help page.
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               Load config file (default is <v>/etc/gnunet.conf</v>).
+               </option>
+
+               <option short="V" long="verbose">
+               Be verbose.
+               </option>
+
+               <option short="q" long="quiet">
+               Be quiet.
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       You cannot convert databases of GNUnet versions older than 0.5.3 with 
this tool.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="Users GNUnet 
configuration file" />
+               <file path="~/.gnunet/data/afs/content*" content="Default 
location of the GNUnet AFS database." />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET-CHECK" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-DELETE" level="1" name="gnunet-delete" last="2003/04/05">
+       <description>a command line interface for deleting indexed files from 
GNUnet</description>
+
+       <long-description>
+               <page /> is used for deleting indexed files from GNUnet. 
+       </long-description>
+
+       <synopsis>
+               gnunet-delete [OPTIONS] -f FILENAME 
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               use config file (defaults: ~/.gnunet/gnunet.conf)
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+
+               <option short="V" long="verbose">
+               be berbose; prints progress information and the hash-pair, CRC 
and filesize that can be used to download the file
+               </option>
+
+               <option short="f" long="file" arg="FILENAME">
+               delete <arg /> (obligatory)
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       The option -f is used to specify the name of the file that should be 
deleted.<break />
+       You can only delete files that you indexed (or inserted?? FIXME!) and 
that you still have
+       available locally in full.  You should use <page /> on files that you 
indexed (not
+       inserted) and that you are going to delete locally.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="GNUnet 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-DIRECTORY" level="1" name="gnunet-directory" 
last="2004/04/30">
+       <description>display directories and show or delete lists of 
encountered file identifiers</description>
+
+       <long-description>
+       <page /> lists the contents of a GNUnet directory.
+       It also can be used to manipulate the file-identifier database which is 
used by GNUnet for building directories.        <break />
+       <page /> will always list the contents of the GNUnet directories that 
are passed as filenames.<break />
+       Manipulating the file-identifier database is done by passing additional 
options to <page />.
+       Note that by default GNUnet does not build the file-identifier database 
and the database will thus always be empty.
+       You need to edit your configuration before the database is used.  The 
reason is that storing file identifiers
+       in plaintext in the database can compromise your privacy if your 
machine should fall under the control of an adversary.
+       </long-description>
+
+       <synopsis>
+               gnunet-directory [OPTIONS] FILENAMES
+       </synopsis>
+
+       <options>
+               <option short="a" long="list-all">
+               display all entries from the file-identifier database
+               </option>
+
+               <option short="A" long="kill-all">
+               delete all entries from the file-identifier database
+               </option>
+
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="i" long="list-insert">
+               display entries from the insertion category in the 
file-identifier database
+               </option>
+
+               <option short="I" long="kill-insert">
+               delete all entries from the insertion category in the 
file-identifier database
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+
+               <option short="s" long="list-search">
+               display entries from the search-result category in the 
file-identifier database
+               </option>
+
+               <option short="S" long="kill-search">
+               delete all entries from the search-result category in the 
file-identifier database
+               </option>
+
+               <option short="x" long="list-directory">
+               display entries from the directory-contents category in the 
file-identifier databae
+               </option>
+
+               <option short="X" long="kill-directory">
+               delete all entries from the directory-contents category in the 
file-identifier databae
+               </option>
+       </options>
+
+       <notes>
+       In order to allow users maximum flexibility when building directories, 
GNUnet collects file-identifiers of files that the clients encounter in the 
file-identifier database.  The file-identifiers are classified into four 
categories (search, insert, directory, namespace) according to how they were 
obtained (as search results, by insertion of that file, as part of a directory 
that was downloaded).  When a user uses gnunet-gtk to build a directory, he can 
build the directory using a subset of the file-identifiers stored in the 
file-identifier database.
+       A GNUnet directory is a file containing a list of keys.  The keys can 
point to files, other directories or files in namespaces.  In other words, a 
GNUnet directory is similar to UNIX directories.  The difference to tar and zip 
is that GNUnet directory does not contain the actual files, just symbolic 
(links), similar to directories with symbolic links in UNIX filesystems.  The 
benefit is that the individual files can be retrieved separately (if desired) 
and if some of the files are inserted to another node in GNUnet, this just 
increases their availability but does not produce useless duplicates (for 
example, it is a better idea to publish a collection of pictures or compressed 
sound files using a GNUnet directory instead of processing them with archivers 
such as tar or zip first).
+       Directories can be created at the moment by gnunet-gtk and 
gnunet-insert.  They can point to content created by the user or content 
inserted by others.  Just like ordinary files, a directory can be published 
under a pseudonym-signed namespace.  A directory can also contain links to 
files in namespaces.
+       GNUnet-directories use the (unregistered) mimetype 
application/gnunet-directory.  They can show up among normal search results or 
be pointed-to by sblocks. The directory file can be downloaded to disk by 
gnunet-download(1) for later processing or be handled more directly by 
gnunet-gtk(1).
+       </notes>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-DOWNLOAD" level="1" name="gnunet-download" 
last="2004/04/18">
+       <description>a command line interface for downloading files from 
GNUnet</description>
+
+       <long-description>
+               Download files from GNUnet.
+       </long-description>
+
+       <synopsis>gnunet-download [OPTIONS] -- GNUNET_URI</synopsis>
+
+       <options>
+               <option short="a" long="anonymity" arg="LEVEL">
+               set additional receiver anonymity enforcing level. If unset,
+               value specified in config file is used. Default is 0.
+               </option>
+
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               use config file (defaults: ~/.gnunet/gnunet.conf)
+               </option>
+
+               <option short="o" long="output" arg="FILENAME">
+               write the file to <arg /> (required)
+               </option>
+
+               <option short="R" long="recursive">
+               download directories recursively and in parallel
+               </option>
+
+               <option short="t" long="threads" arg="NUMBER">
+               when downloading directories recursively, this option specifies 
how many downloads are done in parallel.  The default is 30.  If you have not 
so much memory or if your system can not support about 64 threads, you may want 
to pass a smaller value here.  The default can be changed by adding an option 
PARALLELIZATION in the gnunet.conf file in the section [GNUNET-DOWNLOAD].
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+
+               <option short="V" long="verbose">
+               print progress information
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       The GNUNET_URI is typically obtained from gnunet-search. gnunet-gtk 
+       can also be used instead of <page />.
+       If you ever have to abort a download, you can at any time continue it 
by re-issuing <page /> with the same filename. In that case GNUnet will not 
download blocks again that are already present. GNUnets file-encoding will 
ensure file integrity, even if the existing file was not downloaded from GNUnet 
in the first place. Temporary information will be stored in FILENAME.X files 
until the download is completed. These files are used only if a download is 
resumed later. If you abort a download for good, you should remember to delete 
these files.
+
+       <break title="SETTING ANONYMITY LEVEL" />
+       The -a option can be used to specify additional anonymity
+       constraints. If set to 0, GNUnet will try to download the
+       file as fast as possible without any additional
+       slowdown by the anonymity code. Note that you
+       will still have a fair degree of anonymity depending
+       on the current network load and the power of the
+       adversary. The download is still unlikely to be
+       terribly fast since the sender may have requested
+       sender-anonymity and since in addition to that,
+       GNUnet will still do the anonymous routing.
+       
+       This option can be used to limit requests further
+       than that. In particular, you can require GNUnet to
+       receive certain amounts of traffic from other peers
+       before sending your queries. This way, you can gain
+       very high levels of anonymity - at the expense of
+       much more traffic and much higher latency. So set
+       it only if you really believe you need it.
+
+       The definition of ANONYMITY-RECEIVE is the following:
+       <![CDATA[If the value v is < 1000, it means that if GNUnet
+         routes n bytes of messages from foreign peers, it
+         may originate n/v bytes of queries in the same time-period.
+         The time-period is twice the average delay that GNUnet
+         deferrs forwarded queries.
+       
+         If the value v is >= 1000, it means that if GNUnet
+         routes n bytes of QUERIES from at least (v % 1000)
+         peers, it may originate n/v/1000 bytes of queries
+         in the same time-period.]]>
+
+       The default is 0 and this should be fine for most
+       users. Also notice that if you choose values above
+       1000, you may end up having no throughput at all,
+       especially if many of your fellow GNUnet-peers do
+       the same.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="GNUnet 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-GTK" level="1" name="gnunet-gtk" last="2002/06/06">
+       <description>a gtk interface for accessing GNUnet</description>
+
+       <long-description>
+               gnunet-gtk is a gtk+ based GUI for searching, downloading and 
inserting files on GNUnet. It supports queries of the form foo AND bar (notice 
that AND must be capitalized and that keywords are case-sensitive), just like 
gnunet-search. It can also be used to create and publish content directories 
out of search results and inserted files. 
+       </long-description>
+
+       <synopsis>
+               gnunet-gtk [OPTIONS]
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               load config file (defaults: ~/.gnunet/gnunet.conf)
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+       </options>
+
+       <notes>
+       Multiple files can be downloaded by holding down CTRL while selecting,
+       or by SHIFT, if you wish to select everything between the last 
selection and the currently pointed row. If you want to insert multiple files 
at once,
+       use gnunet-insert. Some functionality of gnunet-gtk can be
+       accessed by pressing down the right mouse button in appropriate windows.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="Users GNUnet 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-INSERT" level="1" name="gnunet-insert" last="2004/05/02">
+       <description>a command line interface for inserting new content into 
GNUnet</description>
+
+       <long-description>
+               In order to share files with other GNUnet users, the files must 
first be made
+               available to GNUnet.  GNUnet does not automatically share all 
files from a
+               certain directory.  In fact, even files that are downloaded are 
not automatically shared.
+               <break />
+
+               In order to start sharing files, the files must be added either 
using
+               gnunet-insert or gnunet-gtk.  The command line tool 
gnunet-insert is more
+               useful if many files are supposed to be added.  gnunet-insert 
can
+               automatically insert batches of files, recursively insert 
directories, create
+               directories that can be browsed within GNUnet and publish file 
lists
+               in a namespace.
+               <break />
+
+               If libextractor was available when GNUnet was compiled, 
gnunet-insert can
+               automatically extract keywords from the files that are shared.  
Users that
+               want to download files from GNUnet use keywords to search for 
the appropriate
+               content.  You can disable keyword extraction with the -x 
option.  You can
+               manually add keywords using the -k and -K options.
+               <break />
+
+               In addition to searching for files by keyword, GNUnet allows 
organizing
+               files into directories.  With directories, the user only needs 
to find the
+               directory in order to be able to download any of the files 
listed in the
+               directory.   Directories can contain pointers to other 
directories.
+               <break />
+
+               With gnunet-insert, it is easy to create new directories 
simultaneously
+               when adding the files. Simply add the option -b to create a 
directory.
+               With -b alone, a directory containing all of the files listed 
at the command
+               line is created.  Together with the -R (recursive) option, an 
entire directory
+               tree can be added to GNUnet.  The structure of the tree is 
preserved.
+               <break />
+
+               Since keywords can be spammed (any user can add any content 
under any
+               keyword), GNUnet supports namespaces.  A namespace is a subset 
of the
+               searchspace into which only the holder of a certain pseudonym 
can add content.
+               Any GNUnet user can create any number of pseudonyms using
+               gnunet-pseudonym-create. Pseudonyms are stored in the users 
GNUnet 
+               directory and can  be additionally protected with a password.  
While 
+               pseudonyms are locally identified with an arbitrary string that 
+               the user selects when the pseudonym is created, the namespace 
is  
+               globally known only under the hash of the public key of the 
pseudonym. 
+               Since only the owner of the pseudonym can add content to the 
namespace, 
+               it is impossible for other users to pollute the namespace.  
+               gnunet-insert automatically inserts the top-directory (or the 
only
+               file if only one file is specified) into the namespace if a 
pseudonym is
+               specified.  If no specific namespace-identifier is specified 
(option -t),
+               gnunet-insert selects a random identifier.
+               <break />
+
+               It is possible to update content in GNUnet if that content was 
placed and
+               obtained from a particular namespace.  Updates are only 
possible for content
+               in namespaces since this is the only way to assure that a 
malicious party can
+               not supply counterfeited updates.  GNUnet supports two types of 
updateable content,
+               sporadically updated content and periodically updated content. 
If content is
+               periodically updated (every day, every week, etc.), the period 
must be passed
+               to gnunet-insert with the -i option. The -S option is used to 
indicate
+               sporadically updated content. You can use the -N option to 
specify the future
+               identifier of the update (only for the first update of 
periodically updated
+               content). Without -N, gnunet-insert will select (and output) a 
random
+               identifier that must be used for the update.
+               <break />
+
+               To update content in a namespace, gnunet-insert options -e and 
-o can be used. 
+               On the first insert, -o can be used to output the namespace 
block data into a file. 
+               On subsequent updates, -e can be used to read the previous 
block, which is used
+               to automatically calculate the information required for an 
update. Currently
+               the most convenient way to make regular namespace updates 
efficiently
+               remains a bit awkward. The trick is to insert a filesystem 
directory 
+               that instead of containing a possibly very large directory 
hierarchy, 
+               contains only the top level ".gnd" GNUnet directory files you 
have previously 
+               created or downloaded. That is, what is inserted is a flat 
directory,
+               with time cost same as inserting the .gnd files, but the result
+               will still be equal to a full-blown directory tree having 
+               actual files and further subdirectories.
+               <break />
+
+               You can use libextractor or command-line options to specify a 
mimetype and a
+               description for the files.  The description and keywords are 
used to help
+               users in searching for files on the network.  The keywords are 
case-sensitive.
+               GNUnet supports two styles of publishing files on the network.  
Inserting
+               a file means that a copy of the file is made in the local (!) 
database of
+               the node.  Indexing a file means that an index is added to the 
local (!)
+               database with pointers to the file itself.  Since 0.6.2 GNUnet 
will make
+               a copy of the file in the directory specified in gnunet.conf.  
The copy
+               will be in plaintext and have the RIPE160MD hash of the entire 
file as
+               the filename.  This makes it possible to create links to that 
file, if
+               gnunetd is running locally.  Note that for indexed files a 
different quota
+               is applied than for the normal GNUnet AFS database.  Indexing 
is generally 
+               significantly more efficient and the default choice.  In either 
case,
+               the file is slowly (depending on how often it is requested and 
on how much
+               bandwidth is available) dispersed into the network.  If you 
insert or index
+               a file and then leave the network, it will almost always NOT be 
available
+               anymore.
+       </long-description>
+
+       <synopsis>
+               gnunet-insert [OPTIONS] FILENAME*
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               Print a brief help page with all the options.
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               Use alternate config file (if this option is not specified, the 
default is ~/.gnunet/gnunet.conf).
+               </option>
+
+               <option short="v" long="version">
+               Print the version number.
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+
+               <option short="V" long="verbose">
+               Be verbose.  Using this option causes gnunet-insert to print 
progress information and at the end the file identification that can be used to 
 download the file from GNUnet.
+               </option>
+
+               <option short="R" long="recursive">
+               Process directories recursively.  Without this option, 
directories are ignored.
+               With this option, gnunet-insert will process files in 
directories recursively.  
+               </option>
+
+               <option short="b" long="builddir">
+               Build a directory.  With this option, gnunet-insert will create 
a directory
+               containing all the files specified at the command-line and 
insert that directory into GNUnet.
+               This allows grouping multiple files together.  Together with 
the -R option, gnunet-insert can be used
+               to mirror an entire directory tree in GNUnet.  The directory 
structure is preserved (not all files are placed at the top-level directory).  
+               </option>
+
+               <option short="E" long="extract">
+               Print the list of keywords that will be extracted.  Do not 
perform any indexing or insertion.
+               </option>
+
+               <option short="l" long="link">
+               When indexing a file, gnunet-insert will create a copy of the 
file in the "share" directory of gnunetd.  If that directory happens to be on 
the local machine (i.e. gnunetd runs on localhost) then gnunet-insert can 
instead just use a link.  This will not work over the network, if the 
file-permissions do not allow gnunetd to read the file or if the file maybe 
changed afterwards.  Hence the default is to be inefficient and to make a copy. 
 With this option you can cause gnunet-insert to TRY to make a link.  If the 
link does not work for some reason that GNUnet can detect, gnunet-insert will 
fall back to creating a copy.
+               </option>
+
+               <option short="k" long="key" arg="KEYWORD">
+               additional key to index the content with (to add multiple keys, 
specify multiple times). Each additional key is case-sensitive. Can be 
specified multiple times.  The keyword is only applied to the top-level file or 
directory.
+               </option>
+
+               <option short="K" long="global-key" arg="KEYWORD">
+               additional key to index the content with.  Keywords specified 
with -K are applied to files and directories encountered on the command-line or 
in the recursive scan.  This is the only difference to the -k option.  This 
option can be specified multiple times.
+               </option>
+
+               <option short="s" long="pseudonym" arg="NAME">
+               For each file at the command line (or, if -b is specified, for 
the top-level directory) create an SBlock that places the file into the 
namespace specified by the pseudonym <arg />.  
+               </option>
+
+               <option short="P" long="pass" arg="PASSWORD">
+               Specifies the password for the pseudonym (if needed).  If the 
password is invalid gnunet-insert aborts with an error.  This option is only 
valid together with the -s option.
+               </option>
+
+               <option short="t" long="this" arg="ID">
+               Specifies the identifier <arg /> of the SBlock.  This option is 
only valid together with the -s option and together with either the option -b 
or only a single filename on the command-line.
+               The identifier can be given in HEX notation, otherwise the HEX 
code is derived by hashing the given identifier <arg /> string
+               which may be a natural language keyword.
+               </option>
+
+               <option short="T" long="time" arg="TIME">
+               Specifies the SBlock creation time. Requires format 
+               "DAY-MONTHNUMBER-YEAR HOUR:MINUTE" 
+               for <arg />. This option can be used to publish past and future 
periodical 
+               SBlocks. The option works best when used together with -e. 
Default time is the current time.
+               </option>
+
+               <option short="N" long="next" arg="ID">
+               Specifies the next identifier <arg /> of a future version of 
the SBlock.  This option is only valid together with the -s option and together 
with either the option -b or only a single filename on the command-line.  This 
option can be used to specify what the identifier of an updated version will 
look like.  Without the -i option, a one-shot update SBlock is used 
(a-periodic).  With the -i option, the difference between  the current 
identifier (this) and the next identifier is used to compute all future 
identifiers.  Note that specifying -i and -N without -t hardly ever makes 
sense. 
+               The identifier <arg /> can be given in HEX notation, otherwise 
the HEX code is derived by hashing the given identifier string.
+               </option>
+
+               <option short="e" long="sprev" arg="FILENAME">
+               Specifies the previous SBlock file that contains the necessary 
information to update a periodical SBlock. On the first time of inserting a 
periodical, use -o to create the file, without -e. Filenames in -o and -e can 
be the same.
+               </option>
+
+               <option short="o" long="sout" arg="FILENAME">
+               Write the created SBlock to a file. This is especially useful 
with periodical updates done by a script. The SBlock file contains the 
necessary information to update the periodical SBlock. Filenames in -o and -e 
can be the same.
+               </option>
+
+               <option short="i" long="interval" arg="SECONDS">
+               Specifies the update frequency of the content in seconds. This 
option is only valid together with the -s option. If no current and next 
identifier are specified, the system picks some random start values for the 
sequence. 
+               Most recent update can be found by gnunet-gtk automatically. 
gnunet-search will print all edition ids 
+               between the insertion time and the current time. A new search 
can be then performed with one of the printed keys. 
+               Also, using gnunet-insert for updating content is cumbersome, 
in the future gnunet-gtk will provide a more interactive 
+               way to manage content updates.
+               </option>
+
+               <option short="S" long="sporadic">
+               This option specifies that the file will be updated 
sporadically but not periodically.  It is only valid in conjunction with the -s 
option.  It is implied if  -N is specified but not -i.  It can not be used 
together with the -i option.  Use -S if you intend to publish an update at an 
unknown point in the future and if you want gnunet-insert to pick a random  
identifier for that future content.  
+               If you use -s but not -S, -N or -i, the content will not be 
updateable.
+               </option>
+
+               <option short="m" long="mime" arg="MIMETYPE">
+               Set the mime-type of all (!) files to be <arg />.  This option 
has no effect on directories (option -b). If not supplied and the option -x is 
not specified,  gnunet-insert will attempt to determine the mime-type using 
libextractor and otherwise use "unknown".
+               </option>
+
+               <option short="p" long="prio" arg="PRIORITY">
+               Executive summary: You probably don't need it.<break />
+               Set the priority of the inserted content (default: 65535).  If 
the local database is full, GNUnet will discard the content with the lowest 
ranking.  Note that ranks change over time depending on popularity.  The 
default should be high enough to preserve the locally inserted content in favor 
of content that migrates from other peers.
+               </option>
+
+               <option short="n" long="noindex">
+               Executive summary: You probably don't need it.<break />
+               Do not index, full insertion.  Note that directories, RBlocks, 
SBlocks and IBlocks are always inserted (even without this option).  With this 
option, every block of the actual files is stored in encrypted form in the 
block database of the local peer.  While this adds security if the local node 
is compromised (the adversary snags your machine), it is significantly less 
efficient compared to on-demand encryption and is definitely not recommended 
for large files.
+               </option>
+
+               <option short="x" long="extraction">
+               Executive summary: You probably don't need it.<break />
+               Disable automatic keyword extraction. This option is only 
available if you compiled GNUnet with libextractor.  With this option, you can 
disable the use of libextractor to obtain meta-data (mime-type, description, 
keywords) from the files being processed.  In this case, you probably want to 
manually supply a list of keywords and a description on the command line.  Note 
that if you process multiple files or do recursive processing, the description, 
mime-type and  keywords will be used for all files (and directories).
+               -x implies -X.
+               </option>
+
+               <option short="X" long="nodirectindex">
+               Executive summary: You probably don't need it.<break />
+               With this option, gnunet-insert will not create individual 
RBlocks for all files except for keywords specified with the -K option.  With 
-X, gnunet-insert will  create an RBlock for each keyword infered from the 
files.  It does not disable the use of libextractor for finding the description 
and mime-types for these files.  
+               </option>
+
+               <option short="f" long="name" arg="NAME">
+               Executive summary: You probably don't need it.<break />
+               If a single file is inserted with RBlocks or an SBlock, use 
<arg /> as the published name for that file.  If multiple files are specified 
and no directory is created, <arg /> is again used for all of these files. In 
both cases, if this option is not given, the default is to preserve the actual 
filenames without the path.
+               If a directory is created, <arg /> is used for the directory. 
The names for the individual files are still the original filenames without 
path. If a directory is created recursively from a single filename on the 
command line and if <arg /> is not specified, the last component of the 
specified filename is used for the directory.  If a directory is created from 
multiple filenames specified on the command line, "not set" is used for the 
name of the directory.
+               </option>
+       </options>
+
+       <notes>
+       Basic examples
+
+       Index a file COPYING:
+
+       # gnunet-insert COPYING
+
+       Insert a file COPYING:
+
+       # gnunet-insert -n COPYING
+
+       Index a file COPYING with the keywords gpl and test:
+
+       # gnunet-insert -k gpl -k test COPYING
+
+       Index a file COPYING with description "GNU License"
+       and keywords gpl and test:
+
+       # gnunet-insert -D "GNU License" -k gpl -k test COPYING
+
+       Using directories
+
+       Index the files COPYING and AUTHORS with keyword test and 
+       build a directory containing the two files.  
+       Make the directory itself available under keyword gnu:
+
+       # gnunet-insert -K test -k gnu -b COPYING AUTHORS
+
+       Neatly publish an image gallery in kittendir/ and its
+       subdirs with keyword kittens for the directory but no 
+       keywords for the individual files or subdirs (-brX). 
+       Force description for all files:
+
+       # gnunet-insert -bRX -D "Kitten collection" -k kittens kittendir
+
+       Secure publishing with namespaces
+
+       Insert file COPYING with pseudonym RIAA (-s) and password MPAA (-P) 
+       with identifier gpl (-t) and no updates:
+
+       # gnunet-insert -s RIAA -P MPAA -t gpl COPYING
+
+       Recursively (-R) index /home/ogg and build a matching directory 
structure (-b).
+       Insert the top-level directory into the namespace under the pseudonym 
+       RIAA (-s) with password MPAA (-P) under identifier MUSIC (-t) and 
+       promise to provide an update with identifier VIDEOS (-N) at an 
+       arbitrary point in the future (-S is implied by lack of -i 
+       and presence of -N):
+
+       # gnunet-insert -Rb -s RIAA -P MPAA -t MUSIC -N VIDEOS /home/ogg
+
+       Recursively (-R) insert (-n) /var/lib/mysql and build a matching 
directory
+       structure (-b) but disable the use of libextractor to extract keywords 
+       (-X) while allowing the use of libextractor to provide descriptions 
(lack
+       of -x).  Print the file identifiers (-V) that can be used to retrieve
+       the files.  This will store a copy of the MySQL database in GNUnet but 
+       without adding any keywords to search for it.  Thus only people that
+       have been told the secret file identifiers printed with the -V option
+       can retrieve the (secret?) files:
+
+       # gnunet-insert -RnbXV /var/lib/mysql
+
+       Create a periodical SBlock with 24h update interval 
+       and store the created block to a file sblock.dat (unencrypted):
+
+       # gnunet-insert -s RIAA -P MPAA -o sblock.dat -i 86400 -D "My noisy 
file" -t noise noise.mp3
+
+       Update the periodical SBlock using settings from a previous time:
+
+       # gnunet-insert -s RIAA -P MPAA -e sblock.dat -o sblock.dat -D "My 
updated noisy file" noise_updated.mp3
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="GNUnet 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-PSEUDONYM" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-PEER-INFO" level="1" name="gnunet-peer-info" 
last="2004/04/20">
+       <description>Display information about other known nodes.</description>
+
+       <long-description>
+               gnunet-peer-info display the last known IP and GNUnet host 
address of known nodes.
+       </long-description>
+
+       <synopsis>
+               gnunet-peer-info [ options ]
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               Print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               Load config file (default: /etc/gnunet.conf)
+               </option>
+
+               <option short="v" long="version">
+               Print the version number
+               </option>
+
+               <option short="L" long="loglelvel" arg="LOGLEVEL">
+               Set the loglevel
+               </option>
+       </options>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-PSEUDONYM" level="1" name="gnunet-pseudonym" 
last="2004/04/31">
+       <description>create, delete or list pseudonyms</description>
+
+       <long-description>
+               By default, gnunet-pseudonyms lists all pseudonyms created 
locally. 
+       </long-description>
+
+       <synopsis>
+               gnunet-pseudonym [options]
+       </synopsis>
+
+       <options>
+               <option short="p" long="password" arg="PASS">
+               Specify password to decrypt pseudonyms encountered or to 
encrypt pseudonyms created.  The namespace identifiers are displayed for the 
pseudonyms that could be decrypted.
+               </option>
+
+               <option short="C" long="create" arg="NAME">
+               Creates a new pseudonym with the given <arg />.
+               </option>
+
+               <option short="D" long="delete" arg="NAME">
+               Deletes the pseudonym with the given <arg />.
+               </option>
+
+               <option short="q" long="quiet">
+               Do not print the list of pseudonyms (only perform create or 
delete operation).
+               </option>
+
+               <option short="h" long="help">
+               print help page
+               </option>
+       </options>
+
+       <files>
+               <file path="~/.gnunet/data/pseudonyms/" content="Directory 
where the pseudonyms are stored" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-SEARCH" level="1" name="gnunet-search" last="2004/03/20">
+       <description>a command line interface to search for content on 
GNUnet</description>
+
+       <long-description>
+               Search for content on GNUnet. The keywords are case-sensitive.
+       </long-description>
+
+       <synopsis>
+               gnunet-search [OPTIONS] KEYWORD [AND KEYWORD]*
+       </synopsis>
+
+       <options>
+               <option short="a" long="anonymity" arg="LEVEL">
+               set additional receiver anonymity enforcing. If unset, 
+               value specified in config file is used. Default is 0.
+               </option>
+
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               use config file (defaults: ~/.gnunet/gnunet.conf)
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+
+               <option short="t" arg="TIMEOUT">
+               wait <arg /> seconds before aborting the search.
+               </option>
+
+               <option short="m" arg="MAXRESULTS">
+               exit after finding <arg /> results.
+               </option>
+
+               <option short="n" arg="NAMESPACE">
+               Searches the given <arg />.  The keyword argument specified is 
used as the identifier in the namespace.
+               </option>
+
+               <option short="o" long="output" arg="PREFIX">
+               This option only works together with -s (at the moment).
+               Writes encountered (unencrypted) SBlocks to files with name
+               <arg />.XXX, where XXX is a number. This may be useful e.g.
+               if you forgot to save the SBlock when inserting a periodical.
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       The -t option specifies that the query should timeout after 
approximately TIMEOUT seconds.
+       A value of zero is interpreted as never.
+       The default value can be changed via the SEARCHTIMEOUT variable in the 
GNUnet configuration file.
+       If multiple words are passed as keywords that are not separated by an 
AND, gnunet-search will concatenate them
+       to one bigger keyword. Thus
+
+       <code><page /> Das Kapital<break /></code>
+
+       and<break />
+
+       <code><page /> "Das Kapital"</code>
+
+       are identical. You can use AND to separate keywords.
+       In that case, <page /> will only display results that match all the 
keywords.
+       <page /> can not do multiple independent queries ("OR"), you must use 
multiple processes for that.
+       Mind that each GNUnet-server (gnunetd) has a build-in limit on the 
number of clients
+       (like <page /> or <xpage id="GNUNET-DOWNLOAD" level="1" />) that can 
connect simultaniously
+       (you can change it in src/include/config.h).<break />
+
+       Search results are printed by <page /> like this:<break />
+
+       <code><xpage id="GNUNET-DOWNLOAD" level="1" /> -o "COPYING" 
gnunet://afs/77DBE6F971D66F641B2262DDCE78CA8FB6815E60.E34BFD7843D4C8469EFC3DAD260F1F71783E2A87.466DC92.17992<break
 />
+       <![CDATA[=> The GNU Public License <= (mimetype: unknown)]]></code>
+
+       The first value line is the command to run to download the file.
+       The suggested filename in the example is COPYING.
+       The GNUnet URI consists of the key and query hash of the file, the 
CRC32 (GNUnet style) and finally the size of the file.
+       The second line contains the description of the file, here "The GNU 
Public License" and the mime-type
+       (see the options for gnunet-insert on how to change these).
+
+       <break title="SETTING ANONYMITY LEVEL" />
+       The -a option can be used to specify additional anonymity
+       constraints. If set to 0, GNUnet will try to download the
+       file as fast as possible without any additional
+       slowdown by the anonymity code. Note that you
+       will still have a fair degree of anonymity depending
+       on the current network load and the power of the
+       adversary. The download is still unlikely to be
+       terribly fast since the sender may have requested
+       sender-anonymity and since in addition to that,
+       GNUnet will still do the anonymous routing.
+       
+       This option can be used to limit requests further
+       than that. In particular, you can require GNUnet to
+       receive certain amounts of traffic from other peers
+       before sending your queries. This way, you can gain
+       very high levels of anonymity - at the expense of
+       much more traffic and much higher latency. So set
+       it only if you really believe you need it. 
+       
+       The definition of ANONYMITY-RECEIVE is the following:
+         <![CDATA[If the value v is < 1000, it means that if GNUnet
+         routes n bytes of messages from foreign peers, it
+         may originate n/v bytes of queries in the same time-period.
+         The time-period is twice the average delay that GNUnet
+         deferrs forwarded queries.
+       
+         If the value v is >= 1000, it means that if GNUnet
+         routes n bytes of QUERIES from at least (v % 1000)
+         peers, it may originate n/v/1000 bytes of queries
+         in the same time-period.]]>
+       
+       The default is 0 and this should be fine for most
+       users. Also notice that if you choose values above
+       1000, you may end up having no throughput at all,
+       especially if many of your fellow GNUnet-peers do
+       the same.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="GNUnet 
configuration file; specifies the default value for the timeout" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-STATS" level="1" name="gnunet-stats" last="2003/04/30">
+       <description>Display statistics about your GNUnet server.</description>
+
+       <long-description>
+               <page /> is used to display detailed information about various 
aspect of gnunetd's operation.
+       </long-description>
+
+       <synopsis>
+               gnunet-stats [ options ]
+       </synopsis>
+
+       <options>
+               <option short="p" long="protocols">
+               print supported protocol messages
+               </option>
+
+               <option short="h" long="help">
+               print this page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               load config file
+               </option>
+
+               <option short="v" long="version">
+               print version number
+               </option>
+
+               <option short="H" long="host" arg="HOSTNAME">
+               on which host is gnunetd running (default: localhost)
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               set the loglevel
+               </option>
+
+               <option short="d" long="debug">
+               run in debug mode, write logs to stderr
+               </option>
+       </options>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-TBENCH" level="1" name="gnunet-tbench" last="2003/05/08">
+       <description>transport profiling tool</description>
+
+       <long-description>
+               <page /> can be used to test the performance of the GNUnet
+               core (link-to-link encryption and the available transport 
services).
+               <page /> is useless to most ordinary users since its primary
+               function is to test the performance and correctness 
+               of GNUnet transport service implementations. 
+               <break />
+
+               <page /> sends a sequence of messages to another peer that
+               has the tbench module loaded. The service then measures the 
+               throughput, latency and loss of the messages round-trip. 
+               <page /> can only be used to test a direct peer-to-peer
+               connection. You must load the tbench module (via
+               the configuration gnunet.conf, section GNUNETD under 
APPLICATIONS)
+               in each of the two peers before <page /> can be used.
+               <break />
+
+               The two peers must know of each other and be connected (use
+               gnunet-stats to test for connections). Typically, <page />
+               reports the time it took to sent all specified messages and the
+               percentage of messages lost. 
+       </long-description>
+
+       <synopsis>
+               gnunet-tbench [OPTIONS] 
+       </synopsis>
+
+       <options>
+               <option short="r" long="rec" arg="RECEIVER">
+               use this option to specify the identity of the
+               <arg /> peer that is used for the benchmark. This option is 
required.
+               </option>
+
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               load config file (defaults: ~/.gnunet/gnunet.conf)
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+
+               <option short="n" long="msg" arg="MESSAGES">
+               how many messages should be used in each iteration (used to
+               compute average, min, max, etc.)
+               </option>
+
+               <option short="s" long="size" arg="SIZE">
+               test using the specified message size
+               </option>
+
+               <option short="i" long="iterations" arg="ITER">
+               perform <arg /> iterations of the benchmark
+               </option>
+
+               <option short="t" long="timeout" arg="TIMEOUT">
+               wait <arg /> milli-seconds for replies to arrive before aborting
+               </option>
+
+               <option short="S" long="space" arg="SPACE">
+               use <arg /> milli-seconds of delays between trains of messages 
+               </option>
+
+               <option short="X" long="xspace" arg="COUNT">
+               use trains of <arg /> messages 
+               </option>
+
+               <option short="g" long="gnuplot">
+               create output in two colums suitable for gnuplot. 
+               When using this option, concatenate the output of multiple
+               runs with various options into a file 'tbench' and run
+               the following gnuplot script to visualize the time/loss 
ratio:<break />
+               set xlabel "time"<break />
+               set ylabel "percent transmitted"<break />
+               plot "tbench" title 'Transport benchmarking' with points
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       <page /> can run for a long time, depending on how high you have set 
the numbers.
+       Run first with small numbers to get an initial estimate on the runtime.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="Users GNUnet 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-TESTBED" level="1" name="gnunet-testbed" 
last="2003/12/09">
+       <description>interactive environment for GNUnet 
simulations</description>
+
+       <long-description>
+               <page /> can be used to control GNUnet peers to perform testing 
and benchmarking of the system.
+               Note that <page /> is at this point still a very new tool and 
not functional.
+               <page /> is fully scriptable and uses bash as a scripting 
language.  All features of bash
+               are supported, including the execution of arbitrary shell 
commands.  <page /> extends bash
+               with additional, testbed specific commands.
+       </long-description>
+
+       <synopsis>
+               gnunet-testbed [OPTIONS]
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               load config file (defaults: ~/.gnunet/gnunet.conf)
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       <page /> is not yet fully implemented.  Peers that participate in a 
testbed must load the
+       testbed module.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="GNUnet 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-TRACEKIT" level="1" name="gnunet-tracekit" 
last="2003/02/20">
+       <description>overlay network tracing</description>
+
+       <long-description>
+               <page /> can be used to visualize the GNUnet overlay
+               network.  This tool broadcasts a message into the network
+               querying every peer about a list of other connected peers.
+               The result is then printed to the screen.
+               <break />
+
+               <page /> is primarily useful for developers to determine
+               the structure of the network.  End-users will find little use
+               for the tool itself (except to satisfy their curiosity) but
+               should at the moment still enable this protocol to help the
+               developers that trace the network.
+       </long-description>
+
+       <synopsis>
+               gnunet-tracekit [OPTIONS] 
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               load config file (defaults: ~/.gnunet/gnunet.conf)
+               </option>
+
+               <option short="W" long="wait" arg="WAIT">
+               set how many seconds to wait for replies
+               </option>
+
+               <option short="D" long="depth" arg="DEPTH">
+               until which depth should the network be traced (how many hops)
+               </option>
+
+               <option short="F" long="format" arg="FORMAT">
+               specifies the output format, 0 is human readable, 1 is dot
+               </option>
+
+               <option short="P" long="priority" arg="PRIORITY">
+               what should the priority of the probe be
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       <page /> may not be supported by all GNUnet peers.  Peers that
+       do not support tracekit will still be discovered and will be marked 
specially
+       in the output.
+       </notes>
+
+       <files>
+               <file path="~/.gnunet/gnunet.conf" content="Users GNUnet 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET-TRANSPORT-CHECK" level="1" name="gnunet-transport-check" 
last="2003/12/19">
+       <description>a tool to test a GNUnet transport service</description>
+
+       <long-description>
+               <page /> can be used to test or profile
+               a GNUnet transport service.  The tool can be used to test
+               both the correctness of the software as well as the correctness
+               of the configuration.  <page /> features two modes,
+               called loopback mode and ping mode.  In loopback mode the test 
is limited to testing if the
+               transport can be used to communicate with itself (loopback).
+               This mode does not include communication with other peers which
+               may be blocked by firewalls and other general Internet 
connectivity
+               problems.  The loopback mode is particularly useful to test
+               the SMTP transport service since this service is fairly hard to
+               configure correctly and most problems can be reveiled by just
+               testing the loopback.  In ping mode the tool will attempt to 
download
+               peer advertisements from the URL specified in the configuration 
file
+               and then try to contact each of the peers.  Note that it is 
perfectly
+               normal that some peers do not respond, but if no peer responds 
something
+               is likely to be wrong.  The configuration is always taken
+               from the configuration file.  Do not run gnunetd while running
+               <page /> since the transport services can not 
+               be used by two processes at the same time.
+               <break />
+
+               <page /> will always produce an error-message for
+               the NAT transport in loopback mode.  If NAT is configured in 
accept-mode (as in,
+               accept connections from peers using network address 
translation),
+               the check will fail with the message "could not create HELO",
+               which is correct since the peer itself is clearly not going to
+               advertise itself as a NAT.  If the peer is configured in 
NAT-mode,
+               that is, the peer is behind a NAT box, the message will be
+               'could not connect'.  For NAT, both messages are NOT errors
+               but exactly what is supposed to happen.
+               <break />
+
+               Similarly, a NAT-ed peer should typically configure the TCP 
transport
+               to use port 0 (not listen on any port).  In this case, 
+               <page /> will print 'could not create HELO' for the
+               TCP transport.  This is also ok.  In fact, a correctly 
configured
+               peer using NAT should give just two errors (could not connect 
for
+               tcp and could not create HELO for NAT) when tested using
+               <page />.  The reason is, that <page />
+               only tests loopback connectivity, and for a NAT-ed peer, that 
just
+               does not apply.
+               <break />
+
+               Note that in ping mode the HTTP download times out after 5 
minutes,
+               so if the list of peers is very large and not all peers can be
+               queried within the 5 minutes the tool may abort before trying 
all
+               peers.
+       </long-description>
+
+       <synopsis>
+               gnunet-transport-check [OPTIONS] 
+       </synopsis>
+
+       <options>
+               <option short="c" long="config" arg="FILENAME">
+               use config file (default: /etc/gnunet.conf)
+               </option>
+
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+
+               <option short="p" long="ping">
+               use ping mode (loopback mode is default)
+               </option>
+
+               <option short="r" long="repeat" arg="COUNT">
+               send <arg /> messages in a sequence over the same connection
+               </option>
+
+               <option short="s" long="size" arg="SIZE">
+               test using the specified message size, default is 11
+               </option>
+
+               <option short="t" long="transport" arg="TRANSPORT">
+               run using the specified transport, if not given the transports
+               configured in the configuration file are used.
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+
+               <option short="V" long="verbose">
+               be verbose
+               </option>
+       </options>
+
+       <notes>
+       <page /> can run for a long time, depending on
+       how high you have set the COUNT level. Run first with small numbers
+       for COUNT to get an initial estimate on the runtime.
+       </notes>
+
+       <files>
+               <file path="/etc/gnunet.conf" content="default gnunetd 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNET.CONF" level="5" name="gnunet.conf" last="2003/12/10">
+       <description>GNUnet configuration file</description>
+
+       <long-description>
+               GNUnet uses two configuration files.  /etc/gnunet.conf is the 
default location for the configuration file used by gnunetd, the GNUnet daemon. 
 It contains the network and resource configuration for the peer.  A template 
can be found in contrib/gnunet.root.  The RPM installs the template to 
/etc/gnunet.conf.
+               <break />
+
+               Another configuration file is used to allow users to customize 
GNUnet according to their needs.  It is used by all of the GNUnet tools and the 
default location is ~/.gnunet/gnunet.conf.  The user configuration allows the 
specification of personal options, such as the nickname in the chat.  A 
template can be found in contrib/gnunet.user.  The RPM installs a template for 
this file in /etc/skel/.gnunet/gnunet.conf. 
+               <break />
+
+               Both configuration files use the same basic syntax.  The file 
is split into sections.  Every section begins with [SECTIONNAME] and contains a 
number of options of the form OPTION=VALUE.  Empty lines and lines beginning 
with a # are treated as comments.  Some options are optional, in particular 
certain sections are not used at all unless the corresponding service module is 
loaded (e.g. you do not have to configure the SMTP transport unless you decide 
to use it).
+       </long-description>
+
+       <notes>
+               ~/.gnunet/gnunet.conf and /etc/gnunet.conf
+       </notes>
+
+       <files>
+               <file path="/etc/gnunet.conf" content="gnunetd configuration 
file" />
+               <file path="~/.gnunet/gnunet.conf" content="GNUnet user 
configuration file" />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+<man-page id="GNUNETD" level="1" name="gnunetd" last="2004/04/20">
+       <description>The GNUnet deamon</description>
+
+       <long-description>
+               The GNUnet deamon, required for any GNUnet operations 
(searches, downloads, etc). gnunetd does not require root rights.
+       </long-description>
+
+       <synopsis>
+               gnunetd [OPTIONS]
+       </synopsis>
+
+       <options>
+               <option short="h" long="help">
+               print help page
+               </option>
+
+               <option short="c" long="config" arg="FILENAME">
+               load config file (default: /etc/gnunet.conf)
+               </option>
+
+               <option short="v" long="version">
+               print the version number
+               </option>
+
+               <option short="d" long="debug">
+               do not detach from the console (for debugging); log messages 
are written to stderr instead of the logfile in -d mode.
+               </option>
+
+               <option short="u" long="user" arg="USER">
+               run as user <arg /> (and if available as group <arg />). Note 
that to use this option, you will probably have to start gnunetd as
+               root. It is typically better to directly start gnunetd as that 
user instead.
+               </option>
+
+               <option short="L" long="loglevel" arg="LOGLEVEL">
+               Change the log level to <arg />.
+               Possible values for <arg /> are <v>NOTHING</v>, <v>FATAL</v>, 
<v>ERROR</v>, <v>FAILURE</v>, <v>WARNING</v>, <v>MESSAGE</v>, <v>INFO</v>, 
<v>DEBUG</v>, <v>CRON</v> and <v>EVERYTHING</v>.
+               </option>
+       </options>
+
+       <notes>
+       Before you can share, search or download files from GNUnet you must 
start the GNUnet server, gnunetd.
+       If you start gnunetd as root (which is not required), you can use the 
-u option such that GNUnet runs as a different user. If a group of the same 
name exists, GNUnet will also change to that group. If GNUnet can not change 
its UID to USER or GID to USER, a warning will be printed and gnunetd will 
*continue* with the rights of the user that invoked gnunetd.
+       </notes>
+
+       <files>
+               <file path="/etc/gnunet.conf" content="gnunetd configuration 
file (default location).  " />
+               <file path="/var/lib/GNUnet/.hostkey" content="Nodes GNUnet RSA 
private key.  Keep secret." />
+               <file path="/var/lib/GNUnet/data/hosts/" content="Hostkeys.  
GNUnet stores contact information and public keys of other nodes here. You may 
want to make this directory publically available." />
+               <file path="/var/lib/GNUnet/data/afs/content/" content="Block 
database for anonymous file sharing. Depending on how you compiled GNUnet, a 
gdbm or tdb database or a directory is used.  GNUnet will store isolated blocks 
of files here. " />
+               <file path="/var/lib/GNUnet/data/credit/" content="Trust 
directory.  GNUnet stores economic information about other nodes here, in 
particular how much useful data we have received from which remote node." />
+       </files>
+
+       <reporting-bugs />
+
+       <see-also>
+               <page id="GNUNET-GTK" level="1" />
+               <page id="GNUNET-INSERT" level="1" />
+               <page id="GNUNET-SEARCH" level="1" />
+               <page id="GNUNET-DOWNLOAD" level="1" />
+               <page id="GNUNET.CONF" level="5" />
+               <page id="GNUNETD" level="1" />
+       </see-also>
+</man-page>
+
+</man-pages>

Added: freeway/doc/man.xsl
===================================================================
--- freeway/doc/man.xsl 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/doc/man.xsl 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,184 @@
+<?xml version="1.0"?>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
+
+<xsl:template match="/">
+       <html>
+
+       <head>
+       <title>Manual Pages</title>
+       <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+       <link href="man.css" rel="stylesheet" type="text/css" />
+       </head>
+
+       <body>
+       <xsl:apply-templates select="/man-pages/man-page" />
+       </body>
+
+       </html>
+</xsl:template>
+
+<xsl:template match="man-page">
+       <a name='address@hidden/address@hidden'></a>
+
+       <div class="block0">
+               <div class="emp">
+               <b><xsl:value-of select="@name" /></b> - <i><xsl:value-of 
select="description/text()" /></i>
+               </div>
+
+               <xsl:apply-templates />
+       </div>
+</xsl:template>
+
+
+<!-- **************** DESCRIPTION and LONG DESCRIPTION **************** -->
+
+<xsl:template match="description" />
+
+<xsl:template match="long-description">
+       <div class="block1">    DESCRIPTION
+       <div class="block2">    
+       <xsl:apply-templates />
+       </div>
+       </div>
+</xsl:template>
+
+
+<!-- **************** SYNOPSIS **************** -->
+
+<xsl:template match="synopsis">
+       <div class="block1">    SYNOPSIS
+       <div class="block2">    
+       <xsl:apply-templates />
+       </div>
+       </div>
+</xsl:template>
+
+
+<!-- **************** OPTIONS **************** -->
+
+<xsl:template match="options">
+       <div class="block1">    OPTIONS
+       <xsl:apply-templates />
+       </div>
+</xsl:template>
+
+<xsl:template match="option">
+       <div class="block2">
+               <xsl:if test="@short!=''">
+                       -<xsl:value-of select="@short" />
+                       <xsl:if test="@arg!=''"><xsl:text> 
</xsl:text><b><xsl:value-of select="@arg" /></b></xsl:if>
+               </xsl:if>
+
+               <xsl:if test="@short!='' and @long!=''">,</xsl:if>
+
+               <xsl:if test="@long!=''">
+                       --<xsl:value-of select="@long" />
+                       <xsl:if test="@arg!=''">=<b><xsl:value-of select="@arg" 
/></b></xsl:if>
+               </xsl:if>
+
+               <div class="block3"><xsl:apply-templates />
+               </div>
+       </div>
+</xsl:template>
+
+<xsl:template match="option/arg">
+       <b><xsl:value-of select="../@arg" /></b>
+</xsl:template>
+
+<xsl:template match="option/v">
+       <span class='value'><xsl:apply-templates /></span>
+</xsl:template>
+
+
+<!-- **************** NOTES **************** -->
+
+<xsl:template match="notes">
+       <div class="block1">    NOTES
+       <div class="block2">    
+       <xsl:apply-templates />
+       </div>
+       </div>
+</xsl:template>
+
+
+<!-- **************** FILES **************** -->
+
+<xsl:template match="files">
+       <div class="block1">    FILES
+       <xsl:apply-templates />
+       </div>
+</xsl:template>
+
+<xsl:template match="files/file">
+       <div class="block2" style="xpadding-bottom: 10px;">
+       <b><xsl:value-of select="@path" /></b>
+               <div class="block3" style="xpadding-bottom: 5px; ">
+               <xsl:value-of select="@content" />
+               </div>
+       </div>
+</xsl:template>
+
+
+<!-- **************** REPORTING BUGS **************** -->
+
+<xsl:template match="reporting-bugs">
+       <div class="block1">    REPORTING BUGS
+       <div class="block2">
+               Report bugs by using mantis <a 
href="http://www.ovmj.org/~mantis/";>http://www.ovmj.org/~mantis/</a>
+               or by sending electronic mail to <a 
href="mailto:address@hidden";>address@hidden</a>.
+       </div>
+       </div>
+</xsl:template>
+
+
+<!-- **************** SEE ALSO **************** -->
+
+<xsl:template match="see-also">
+       <div class="block1">    SEE ALSO
+       <div class="block2">    <xsl:apply-templates /></div>
+       </div>
+</xsl:template>
+
+<xsl:template match="see-also/page">
+       <xsl:variable name="target-id" select="@id" />
+       <xsl:variable name="target-level" select="@level" />
+       <xsl:variable name="target" select="//address@hidden and 
@level=$target-level]" />
+
+       <b><a href="#{$target-id}/{$target-level}"><xsl:value-of 
select="$target/@name" /></a></b>
+
+       <xsl:if test="position()!=last()-1">,
+       </xsl:if>
+</xsl:template>
+
+
+<!-- **************** BREAK **************** -->
+
+<xsl:template match="break[not(@title!='')]">
+       <br />
+</xsl:template>
+
+<xsl:template match="address@hidden'']">
+       <br /><br /><b><xsl:value-of select="@title" /></b><br />
+</xsl:template>
+
+
+<xsl:template match="code">
+       <div class="code"><xsl:apply-templates />
+       </div>
+</xsl:template>
+
+
+<xsl:template match="page[not(@id!='')]">
+       <b><xsl:value-of 
select="ancestor-or-self::node()address@hidden'']/@name" /></b>
+</xsl:template>
+
+<xsl:template match="address@hidden'']">
+       <xsl:variable name="target-id" select="@id" />
+       <xsl:variable name="target-level" select="@level" />
+       <xsl:variable name="target" select="//address@hidden and 
@level=$target-level]" />
+
+       <b><a href="#{$target-id}/{$target-level}"><xsl:value-of 
select="$target/@name" /></a></b>
+</xsl:template>
+
+</xsl:stylesheet>

Added: freeway/doc/packaging
===================================================================
--- freeway/doc/packaging       2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/doc/packaging       2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,36 @@
+When building Freeway, many jars are created.
+
+freeway.jar
+       core classes (no protocol, no transport)
+       no resources
+
+freeway-afs.jar
+       AFS protocol classes only
+
+freeway-afs-mysql.jar
+       MySQL access classes only (loaded by AFS protocol)
+
+freeway-chat.jar
+       Chat protocol classes
+
+freeway-tracekit.jar
+       Trace protocol classes
+
+freeway-tcp.jar
+       TCP transport classes
+
+freeway-udp.jar
+       UDP transport classes
+
+freeway-nat.jar
+       NAT transport classes
+
+
+freeway-for-apps.jar
+       *All* classes
+       resources : tests/*             prefix = tests
+       resources : swing/*             no prefix
+       resources : *.template  no prefix
+
+Warning : freeway-for-apps.jar is a all-in-one jar. No need to load additional 
libraries, all classes are already loaded.
+Used by client applications that do not need to be aware of 
transport/protocols classloading issues

Added: freeway/doc/todo
===================================================================
--- freeway/doc/todo    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/doc/todo    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,22 @@
+
+
+daemon
+------
+
+
+tools
+-----
+
+
+ui
+--
+       . gerer le focus pour les wizards
+       . creer des logos pour les joptionpane : logo freeway + un signe
+       . setSelectedFile sur file chooser ne semble pas marcher
+
+
+       . quand rien de configuré sur les dimensions
+               - ouvrir les GFrame centrées à peu près à 1/3 écran
+               - ouvrir les GDialog 1/2 de la GFrame owner
+       -> important quand une configuration neuve...
+

Added: freeway/doc/using eclipse
===================================================================
--- freeway/doc/using eclipse   2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/doc/using eclipse   2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,27 @@
+Using Eclipse to access freeway sources
+---------------------------------------
+WARNING: tested on Eclipse 3.0M7/Mac OS X
+
+Set up
+       . get a developer cvs account (see [pending])
+       . enable SSH2 protocol (diabled by default) in 
/Preferences/Team/CVS/SSH2 Connection Method
+       . create the repository in CVS perspective
+               connection type : extssh
+               user : your cvs account user name
+               host : ovjm.org
+               repository : /home/cvs/GNUnet
+       . a SSH2 Client error dialog might appears the first time you log in
+       . if you've used a passphrase to protect your keystore, a dialog will 
next appear to ask it
+
+Create project
+       . expand HEAD
+       . use context menu 'Check Out As...' on freeway item
+       a lot of problems should have been found
+       . open Project Properties dialog
+       . in Source tab, open Add Folder dialog and select 'src' subdirectory
+       . in Libraries tab, open Add External Jars dialog and select jars found 
in 'lib' subdirectory
+
+
+Please note that *all* Java sources are UTF-8 encoded. Be sure you've 
configured Eclipse
+to have this encoding as default one when editing sources.
+

Added: freeway/etc/gnunet-chat.sh
===================================================================
--- freeway/etc/gnunet-chat.sh  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-chat.sh  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetChat "$@"
+

Added: freeway/etc/gnunet-config.sh
===================================================================
--- freeway/etc/gnunet-config.sh        2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-config.sh        2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetConfig "$@"
+

Added: freeway/etc/gnunet-directory.sh
===================================================================
--- freeway/etc/gnunet-directory.sh     2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-directory.sh     2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetDirectory "$@"
+

Added: freeway/etc/gnunet-download.sh
===================================================================
--- freeway/etc/gnunet-download.sh      2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-download.sh      2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetDownload "$@"
+

Added: freeway/etc/gnunet-insert.sh
===================================================================
--- freeway/etc/gnunet-insert.sh        2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-insert.sh        2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetInsert "$@"
+

Added: freeway/etc/gnunet-peer-info.sh
===================================================================
--- freeway/etc/gnunet-peer-info.sh     2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-peer-info.sh     2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetPeerInfo "$@"
+

Added: freeway/etc/gnunet-pseudonym.sh
===================================================================
--- freeway/etc/gnunet-pseudonym.sh     2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-pseudonym.sh     2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetPseudonym "$@"
+

Added: freeway/etc/gnunet-search.sh
===================================================================
--- freeway/etc/gnunet-search.sh        2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-search.sh        2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetSearch "$@"
+

Added: freeway/etc/gnunet-shutdown.sh
===================================================================
--- freeway/etc/gnunet-shutdown.sh      2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-shutdown.sh      2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetShutdown "$@"
+

Added: freeway/etc/gnunet-stats.sh
===================================================================
--- freeway/etc/gnunet-stats.sh 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-stats.sh 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetStats "$@"
+

Added: freeway/etc/gnunet-swing.sh
===================================================================
--- freeway/etc/gnunet-swing.sh 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-swing.sh 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       -Dcom.apple.mrj.application.apple.menu.about.name=GNUNetSwing   \
+       org.gnu.freeway.GNUNetSwing "$@"
+

Added: freeway/etc/gnunet-tests.sh
===================================================================
--- freeway/etc/gnunet-tests.sh 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-tests.sh 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetTests "$@"
+

Added: freeway/etc/gnunet-trace.sh
===================================================================
--- freeway/etc/gnunet-trace.sh 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-trace.sh 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetTrace "$@"
+

Added: freeway/etc/gnunet-transport-check.sh
===================================================================
--- freeway/etc/gnunet-transport-check.sh       2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/etc/gnunet-transport-check.sh       2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetTransportCheck "$@"
+

Added: freeway/etc/gnunet-ui-config.sh
===================================================================
--- freeway/etc/gnunet-ui-config.sh     2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunet-ui-config.sh     2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway-for-apps.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetUIConfig "$@"
+

Added: freeway/etc/gnunetd.sh
===================================================================
--- freeway/etc/gnunetd.sh      2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/gnunetd.sh      2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+
+CLASSPATH="freeway.jar"
+
+for JAR in lib/*.jar; do
+       BASE=`basename "$JAR"`
+       CLASSPATH="$CLASSPATH:../lib/$BASE"
+done
+
+cd build;      \
+       java -ea        \
+       -classpath "$CLASSPATH" \
+       -Djava.library.path=.   \
+       -Djava.nio.preferSelect=true    \
+       org.gnu.freeway.GNUNetDaemon "$@"
+

Added: freeway/etc/support/Cleaner.java
===================================================================
--- freeway/etc/support/Cleaner.java    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/support/Cleaner.java    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,329 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+import org.gnu.freeway.util.io.*;
+
+import java.io.*;
+import java.nio.charset.*;
+
+
+public class Cleaner extends Object
+{
+       private static final String     EOL     =       
System.getProperty("line.separator");
+       private static final int        TAB     =       4;
+
+       private DirLocation     base;
+       private int                     totalFiles;
+       private int                     totalLines;
+       private boolean         success;
+       private boolean         printOnly;
+
+
+       public Cleaner( DirLocation dir )
+       {
+               super();
+               base=dir;
+               totalFiles=0;
+               totalLines=0;
+               success=true;
+               printOnly=false;
+       }
+
+       public String toString()
+       {
+               return "Cleaner [base="+base+"]";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public void setPrintOnly( boolean flag )
+       {
+               printOnly=flag;
+       }
+
+       public boolean clean()
+       {
+               TraverserContext        ctx;
+
+               ctx=new TraverserContext();
+               ctx.setFilesOnly(true);
+               ctx.setFilter(IOUtils.newSuffixFilter(".java",false));
+
+               totalFiles=0;
+               totalLines=0;
+               success=true;
+               base.traverse(new Traverser() {
+                       public boolean examine( Location node, int depth )
+                       {
+                               try {
+                                       if (!clean((FileLocation) node,depth)) {
+                                               return false;
+                                               }
+                                       totalFiles++;
+                                       return true;
+                                       }
+                               catch( IOException x ) {
+                                       System.err.println("Got I/O exception 
while dealing with "+node.getPath()+"; aborting...");
+                                       x.printStackTrace(System.err);
+                                       success=false;
+                                       return false;
+                                       }
+                       }
+                       },ctx);
+
+               System.out.println();
+               System.out.println("Total files : "+totalFiles);
+               System.out.println("Total lines : "+totalLines);
+               return success;
+       }
+
+       protected boolean clean( FileLocation f, int depth ) throws IOException
+       {
+               BufferedReader  r;
+               BufferedWriter  w;
+               StringBuffer            buf;
+               String                  str;
+               FileLocation            tmp;
+               int                             line;
+               boolean                 errors;
+
+//             System.out.println(f.getName(depth)+":");
+
+               line=1;
+               errors=false;
+
+               tmp=FileLocation.temporary(f);
+
+               w=new BufferedWriter(new OutputStreamWriter(new 
FileOutputStream(tmp.getPath()),Charset.forName("UTF-8")));
+               try {
+                       r=new BufferedReader(new InputStreamReader(new 
FileInputStream(f.getPath()),Charset.forName("UTF-8")));
+                       try {
+                               buf=new StringBuffer();
+                               for (str=r.readLine(); str!=null; 
str=r.readLine()) {
+                                       if 
(clean(f,line,str.toCharArray(),buf,depth,errors)) {
+                                               w.write(buf.toString());
+                                               errors=true;
+                                               }
+                                       else {
+                                               w.write(str);
+                                               }
+                                       w.write(EOL);
+
+                                       line++;
+                                       }
+
+                               totalLines+=line;
+                               }
+                       finally {
+                               r.close();
+                               }
+                       }
+               finally {
+                       w.close();
+                       }
+
+               if (printOnly || !errors) {
+                       return tmp.delete();
+                       }
+               return renameAndDelete(new File(tmp.getPath()),new 
File(f.getPath()));
+       }
+
+       protected boolean clean( FileLocation f, int line, char[] c, 
StringBuffer buf, int depth, boolean errors )
+       {
+               int     mask;
+
+               // collect errors...
+               mask=0;
+               if (detectWhiteLine(c)) {
+                       mask|=1;
+                       }
+               else {
+                       if (detectBadIndentation(c)) {
+                               mask|=2;
+                               }
+                       if (detectBadTrailer(c)) {
+                               mask|=4;
+                               }
+                       }
+
+               if (mask==0) {
+                       return false;
+                       }
+
+               if (!errors) {
+                       System.out.println(f.getPath(depth)+":");
+                       }
+
+               // print them...
+               System.out.print("  Line #"+line+":");
+               if ((mask & 1)!=0) {
+                       System.out.print(" white line");
+                       }
+               if ((mask & 2)!=0) {
+                       System.out.print(" bad indentation");
+                       }
+               if ((mask & 4)!=0) {
+                       System.out.print(" trailing whitespace(s)");
+                       }
+               System.out.println();
+
+               // and correct them !
+               if ((mask & 1)!=0) {
+                       correctWhiteLine(c,buf);
+                       c=buf.toString().toCharArray();
+                       }
+               if ((mask & 2)!=0) {
+                       correctBadIndentation(c,buf);
+                       c=buf.toString().toCharArray();
+                       }
+               if ((mask & 4)!=0) {
+                       correctBadTrailer(c,buf);
+                       c=buf.toString().toCharArray();
+                       }
+               return true;
+       }
+
+       protected boolean detectWhiteLine( char[] c )
+       {
+               int     i;
+
+               for (i=0; i<c.length && Character.isWhitespace(c[i]); i++) {}
+               return (c.length>0 && i==c.length);
+       }
+
+       protected void correctWhiteLine( char[] c, StringBuffer buf )
+       {
+               buf.setLength(0);
+       }
+
+       protected boolean detectBadIndentation( char[] c )
+       {
+               int     i,j;
+
+               for (i=0; i<c.length && c[i]=='\t'; i++) {}
+               if (i<c.length) {
+                       for (j=i; j<c.length && c[j]==' '; j++) {}
+                       if (j>=i+TAB) {
+                               return true;
+                               }
+                       if (j<c.length && Character.isWhitespace(c[j])) {
+                               return true;
+                               }
+                       }
+               return false;
+       }
+
+       protected void correctBadIndentation( char[] c, StringBuffer buf )
+       {
+               int     pos,i;
+
+               buf.setLength(0);
+
+               pos=0;
+               for (i=0; i<c.length && Character.isWhitespace(c[i]); i++) {
+                       switch (c[i]) {
+                               case ' ':
+                                       pos++;
+                                       break;
+                               case '\t':
+                                       pos=((pos/TAB)+1)*TAB;
+                                       break;
+                               }
+                       }
+               while (pos>=TAB) {
+                       buf.append('\t');
+                       pos-=TAB;
+                       }
+               while (pos>0) {
+                       buf.append(' ');
+                       pos--;
+                       }
+               buf.append(c,i,c.length-i);
+       }
+
+       protected boolean detectBadTrailer( char[] c )
+       {
+               int     i;
+
+               for (i=c.length; i>0 && Character.isWhitespace(c[i-1]); i--) {}
+               return (i<c.length);
+       }
+
+       protected void correctBadTrailer( char[] c, StringBuffer buf )
+       {
+               int     i;
+
+               buf.setLength(0);
+
+               for (i=c.length; i>0 && Character.isWhitespace(c[i-1]); i--) {}
+               buf.append(c,0,i);
+       }
+
+       protected boolean renameAndDelete( File from, File to )
+       {
+               File    temp;
+               boolean                 ok;
+
+               ok=false;
+
+               temp=new File(to.getParent(),"blah");
+               if (to.renameTo(temp)) {
+                       if (from.renameTo(to)) {
+                               if (temp.delete()) {
+                                       ok=true;
+                                       }
+                               else {
+                                       System.err.println("Cannot delete 
temporary "+temp+" !");
+                                       }
+                               }
+                       else {
+                               System.err.println("Cannot rename "+from+" to 
"+to+" !");
+                               if (!temp.renameTo(to)) {
+                                       System.err.println("Cannot revert 
"+temp+" to "+to+" !");
+                                       }
+                               if (!from.delete()) {
+                                       System.err.println("Cannot delete 
temporary "+from+" !");
+                                       }
+                               }
+                       }
+               else {
+                       System.err.println("Cannot rename "+to+" to "+temp+" 
!");
+                       if (!from.delete()) {
+                               System.err.println("Cannot delete temporary 
"+from+" !");
+                               }
+                       }
+               return ok;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               Cleaner         cleaner;
+               DirLocation     dir;
+
+               if (args.length==0) {
+                       System.err.println("No base directory specified.");
+                       System.exit(-1);
+                       }
+               System.out.println("Base directory is "+args[0]+".");
+
+               dir=new DirLocation(args[0]);
+               if (!dir.exists()) {
+                       System.err.println(args[0]+" does not exist or is not a 
directory.");
+                       System.exit(-1);
+                       }
+
+               cleaner=new Cleaner(dir);
+               cleaner.setPrintOnly(args.length>1 && args[1].equals("print"));
+               if (!cleaner.clean()) {
+                       System.err.println("Failed to clean "+args[0]+".");
+                       System.exit(-1);
+                       }
+
+               System.exit(0);
+       }
+}

Added: freeway/etc/support/clib/freeway-clib.c
===================================================================
--- freeway/etc/support/clib/freeway-clib.c     2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/etc/support/clib/freeway-clib.c     2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,128 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <jni.h>
+
+#include "freeway-clib.h"
+#include "signals.h"
+#include "links.h"
+
+char* getString( JNIEnv* env, jstring str )
+{
+       const char*     ptr;
+       char*           p;
+       int                     len;
+
+       p=NULL;
+
+       ptr=(*env)->GetStringUTFChars(env,str,NULL);
+       if (ptr!=NULL) {
+               len=(*env)->GetStringUTFLength(env,str);
+
+               p=(char*) malloc((len+1)*sizeof(char));
+               memcpy(p,ptr,len);
+               p[len]=0;
+
+               (*env)->ReleaseStringUTFChars(env,str,ptr);
+               }
+       return p;
+}
+
+JNIEXPORT void JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsInit( 
JNIEnv* env, jclass class )
+{
+       signals_init();
+}
+
+JNIEXPORT void JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsDone( 
JNIEnv* env, jclass class )
+{
+       signals_done();
+}
+
+JNIEXPORT jboolean JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsCatch( 
JNIEnv* env, jclass class, jint num )
+{
+       return (signals_catch((int) num) ? JNI_TRUE : JNI_FALSE);
+}
+
+JNIEXPORT jboolean JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsLeave( 
JNIEnv* env, jclass class, jint num )
+{
+       return (signals_leave((int) num) ? JNI_TRUE : JNI_FALSE);
+}
+
+JNIEXPORT jint JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsWait( 
JNIEnv* env, jclass class )
+{
+       return (jint) signals_wait();
+}
+
+JNIEXPORT jint JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsGetPID( 
JNIEnv* env, jclass class )
+{
+       return (jint) getpid();
+}
+
+JNIEXPORT void JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsSignal( 
JNIEnv* env, jclass class, jint pid, jint num )
+{
+       kill((pid_t) pid,(int) num);
+}
+
+JNIEXPORT jboolean JNICALL Java_org_gnu_freeway_util_OSAccess__1fileIsLink( 
JNIEnv* env, jclass class, jstring path )
+{
+       char*   fn;
+       int             ret;
+
+       fn=getString(env,path);
+       if (fn==NULL) {
+               return JNI_FALSE;
+               }
+       ret=links_is(fn);
+       free(fn);
+       return (ret ? JNI_TRUE : JNI_FALSE);
+}
+
+JNIEXPORT jstring JNICALL 
Java_org_gnu_freeway_util_OSAccess__1fileGetLinkTarget( JNIEnv* env, jclass 
class, jstring path )
+{
+       jstring str;
+       char*   fn;
+       char*   buf;
+
+       fn=getString(env,path);
+       if (fn==NULL) {
+               return NULL;
+               }
+
+       buf=links_get_target(fn);
+       free(fn);
+       if (buf==NULL) {
+               return NULL;
+               }
+
+       str=(*env)->NewStringUTF(env,buf);
+       free(buf);
+       return str;
+}
+
+JNIEXPORT jboolean JNICALL 
Java_org_gnu_freeway_util_OSAccess__1fileCreateLink( JNIEnv* env, jclass class, 
jstring path, jstring target )
+{
+       char*   fn;
+       char*   targ;
+       int             ret;
+
+       fn=getString(env,path);
+       if (fn==NULL) {
+               return JNI_FALSE;
+               }
+
+       targ=getString(env,target);
+       if (targ==NULL) {
+               free(fn);
+               return JNI_FALSE;
+               }
+
+       ret=links_create(fn,targ);
+
+       free(fn);
+       free(targ);
+       return (ret ? JNI_TRUE : JNI_FALSE);
+}

Added: freeway/etc/support/clib/freeway-clib.h
===================================================================
--- freeway/etc/support/clib/freeway-clib.h     2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/etc/support/clib/freeway-clib.h     2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,96 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_gnu_freeway_util_OSAccess */
+
+#ifndef _Included_org_gnu_freeway_util_OSAccess
+#define _Included_org_gnu_freeway_util_OSAccess
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Inaccessible static: logger */
+/* Inaccessible static: loaded */
+/* Inaccessible static: 
class_00024org_00024gnu_00024freeway_00024util_00024OSAccess */
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _signalsInit
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsInit
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _signalsDone
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsDone
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _signalsCatch
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsCatch
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _signalsLeave
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsLeave
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _signalsWait
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsWait
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _signalsGetPID
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsGetPID
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _signalsSignal
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_org_gnu_freeway_util_OSAccess__1signalsSignal
+  (JNIEnv *, jclass, jint, jint);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _fileIsLink
+ * Signature: (Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_gnu_freeway_util_OSAccess__1fileIsLink
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _fileGetLinkTarget
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL 
Java_org_gnu_freeway_util_OSAccess__1fileGetLinkTarget
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     org_gnu_freeway_util_OSAccess
+ * Method:    _fileCreateLink
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_gnu_freeway_util_OSAccess__1fileCreateLink
+  (JNIEnv *, jclass, jstring, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

Added: freeway/etc/support/clib/links.c
===================================================================
--- freeway/etc/support/clib/links.c    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/support/clib/links.c    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "links.h"
+
+#define        DEBUG   0
+#define LOG    if (DEBUG) printf
+#define ERR if (DEBUG) printf
+
+int links_is( const char* fn )
+{
+       struct stat     buf;  
+
+       if (lstat(fn,&buf)!=0) {
+               ERR("Can't stat %s (%s) !\n",fn,strerror(errno));
+               return 0;
+               }
+       return (S_ISLNK(buf.st_mode) ? 1 : 0);
+}
+
+int links_create( const char* fn, const char* targ )
+{
+       if (symlink(targ,fn)!=0) {
+               ERR("Can't create symbolic link %s -> %s (%s) 
!\n",fn,targ,strerror(errno));
+               return 0;
+               }
+       return 1;
+}
+
+char* links_get_target( const char* fn )
+{
+       char*   buf;
+       int             len;
+
+       buf=(char*) malloc(1024);
+       if (buf==NULL) {
+               return NULL;
+               }
+
+       len=readlink(fn,buf,1023);
+       if (len==-1) {
+               ERR("Can't get %s's target (%s) !\n",fn,strerror(errno));
+               return NULL;
+               }
+
+       buf[len]=0;
+       return buf;
+}

Added: freeway/etc/support/clib/links.h
===================================================================
--- freeway/etc/support/clib/links.h    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/support/clib/links.h    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,8 @@
+#ifndef _LINKS_H
+#define _LINKS_H
+
+int links_is( const char* fn );
+int links_create( const char* fn, const char* targ );
+char* links_get_target( const char* fn );
+
+#endif

Added: freeway/etc/support/clib/signals.c
===================================================================
--- freeway/etc/support/clib/signals.c  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/support/clib/signals.c  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,149 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "signals.h"
+
+static void signals_handler( int num );
+
+#define FIFO_SIZE      16
+
+#define        DEBUG   0
+#define LOG    if (DEBUG) printf
+#define ERR printf
+
+static pthread_mutex_t mutex;
+static pthread_cond_t  cond;
+
+static int*                            fifo;
+static int                             fifo_size;
+static int                             fifo_first;
+static int                             fifo_count;
+
+
+int signals_init()
+{
+       pthread_mutexattr_t     attr;
+
+       LOG("Init signals\n");
+
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_settype(&attr,(int) PTHREAD_MUTEX_NORMAL);
+       if (pthread_mutex_init(&mutex,&attr)!=0) {
+               ERR("Could not create mutex !\n");
+               return 0;
+               }
+       if (pthread_cond_init(&cond,NULL)!=0) {
+               ERR("Could not create conditional object !\n");
+               return 0;
+               }
+
+       fifo=(int*) malloc(FIFO_SIZE*sizeof(int));
+       fifo_size=FIFO_SIZE;
+       fifo_first=0;
+       fifo_count=0;
+       return 1;
+}
+
+int signals_done()
+{
+       LOG("Done with signals\n");
+
+       free(fifo);
+       pthread_cond_destroy(&cond);
+       pthread_mutex_destroy(&mutex);
+       return 1;
+}
+
+int signals_catch( int num )
+{
+       struct sigaction        newsig;
+       struct sigaction        oldsig;
+
+       memset(&oldsig,0,sizeof(struct sigaction));
+       memset(&newsig,0,sizeof(struct sigaction));
+       newsig.sa_handler=&signals_handler;
+       newsig.sa_flags=(SA_NODEFER | SA_RESTART);
+       sigemptyset(&newsig.sa_mask);
+
+       if (sigaction(num,&newsig,&oldsig)<0) {
+               ERR("Failed to install handler for signal #%d ! 
(%s)\n",num,strerror(errno));
+               return 0;
+               }
+
+       LOG("Installed handler for signal #%d.\n",num);
+       return 1;
+}
+
+int signals_leave( int num )
+{
+       struct sigaction        newsig;
+       struct sigaction        oldsig;
+
+       memset(&oldsig,0,sizeof(struct sigaction));
+       memset(&newsig,0,sizeof(struct sigaction));
+       newsig.sa_handler=SIG_DFL;
+       newsig.sa_flags=(SA_NODEFER | SA_RESTART);
+       sigemptyset(&newsig.sa_mask);
+
+       if (sigaction(num,&newsig,&oldsig)<0) {
+               ERR("Failed to reset handler for signal #%d ! 
(%s)\n",num,strerror(errno));
+               return 0;
+               }
+
+       LOG("Did reset handler for signal #%d.\n",num);
+       return 1;
+}
+
+int signals_wait()
+{
+       int     num;
+
+       LOG("Enter signals_wait\n");
+
+       pthread_mutex_lock(&mutex);
+       do {
+               pthread_cond_wait(&cond,&mutex);
+
+               if (fifo_count>0) {
+                       num=fifo[fifo_first++];
+                       if (fifo_first==fifo_size) {
+                               fifo_first=0;
+                               }
+                       fifo_count--;
+                       }
+               else {
+                       num=0;
+                       }
+
+               LOG("Awaken for signal #%d.\n",num);
+               }
+       while (num==0);
+       pthread_mutex_unlock(&mutex);
+
+       LOG("Exit signals_wait\n");
+       return num;
+}
+
+static void signals_handler( int num )
+{
+       LOG("Caught signal #%d.\n",num);
+
+       pthread_mutex_lock(&mutex);
+
+       if (fifo_count<fifo_size) {
+               fifo[(fifo_first+fifo_count) % fifo_size]=num;
+               fifo_count++;
+               }
+       else {
+               ERR("Buffer is full, discard signal !\n");
+               }
+
+       pthread_mutex_unlock(&mutex);
+       pthread_cond_signal(&cond);
+}

Added: freeway/etc/support/clib/signals.h
===================================================================
--- freeway/etc/support/clib/signals.h  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/etc/support/clib/signals.h  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,10 @@
+#ifndef _SIGNALS_H
+#define _SIGNALS_H
+
+int signals_init();
+int signals_done();
+int signals_catch( int num );
+int signals_leave( int num );
+int signals_wait();
+
+#endif

Added: freeway/lib/batik-all.jar
===================================================================
(Binary files differ)


Property changes on: freeway/lib/batik-all.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: freeway/lib/bcprov-jdk14-124.jar
===================================================================
(Binary files differ)


Property changes on: freeway/lib/bcprov-jdk14-124.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: freeway/lib/concurrent.jar
===================================================================
(Binary files differ)


Property changes on: freeway/lib/concurrent.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: freeway/lib/mysql-connector-java-3.0.10-stable-bin.jar
===================================================================
(Binary files differ)


Property changes on: freeway/lib/mysql-connector-java-3.0.10-stable-bin.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: freeway/lib/readme
===================================================================
--- freeway/lib/readme  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/lib/readme  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,15 @@
+This folder contains third-party libraries needed to run freeway. These 
libraries
+are automatically added to classpath by scripts in etc/.
+
+       batik-all.jar .................................. 
http://xml.apache.org/batik/
+       Batik 1.5 full libraries for SVG rendering.
+
+       bcprov-jdk14-122.jar ........................... 
http://www.bouncycastle.org/
+       RIPE160 implementation.
+
+       concurrent.jar ............ 
http://gee.cs.oswego.edu/dl/concurrency-interest/
+       Provides synchronization mechanisms defined in jsr 166.
+
+       mysql-connector-java-3.0.10-stable-bin.jar ............ 
http://www.mysql.com/
+       JDBC driver for mysql database.
+

Added: freeway/readme.html
===================================================================
--- freeway/readme.html 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/readme.html 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
"http://www.w3.org/TR/html4/strict.dtd";>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>readme.html</title>
+<link href="docs/project.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+
+<div>
+This is the readme.html for freeway project.
+</div>
+
+<div>
+See in <a href='docs/index.html'>docs</a> folder for more information. 
Available screenshots are in <a 
href='docs/screenshots/index.html'>docs/screenshots</a>.
+</div>
+
+</body>
+</html>

Added: freeway/res/api.css
===================================================================
--- freeway/res/api.css 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/api.css 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,62 @@
+/* Javadoc style sheet */
+
+/* Define colors, fonts and other style attributes here to override the 
defaults */
+
+/* Page background color */
+
+body {
+       color:                          #000000;
+       background-color:       #ffffff;
+       font:                           normal normal normal 12px "Trebuchet 
MS";
+       }
+
+a {
+       color:                          #42adff;
+       }
+
+a:visited {
+       color:                          #215788;
+       }
+
+a:hover {
+       color:                          #000000;
+       }
+
+a:active {
+       color:                          #000000;
+       }
+
+td {
+       font-size:      12px;
+       }
+
+tr {
+       font-size:      16px;
+       }
+
+th {
+       font-size:      16px;
+       }
+
+/* Table colors */
+.TableHeadingColor     { background: #cccccc; } /* Dark mauve */
+.TableSubHeadingColor  { background: #aaaaaa; } /* Light mauve */
+.TableRowColor         { background: #FFFFFF; } /* White */
+
+/* Font used in left-hand frame lists */
+.FrameTitleFont   { font: normal normal normal 12px "Trebuchet MS"; }
+.FrameHeadingFont { font: normal normal normal 12px "Trebuchet MS"; }
+.FrameItemFont    { font: normal normal normal 12px "Trebuchet MS"; }
+
+/* Example of smaller, sans-serif font in frames */
+/* .FrameItemFont  { font: normal normal normal 12px "Trebuchet MS"; } */
+
+/* Navigation bar fonts and colors */
+.NavBarCell1    { background-color:#EEEEFF;}/* Light mauve */
+.NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */
+.NavBarFont1    { font-family: Arial, Helvetica, sans-serif; color:#000000;}
+.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}
+
+.NavBarCell2    { font-family: Arial, Helvetica, sans-serif; 
background-color:#FFFFFF;}
+.NavBarCell3    { font-family: Arial, Helvetica, sans-serif; 
background-color:#FFFFFF;}
+

Added: freeway/res/daemon.logging
===================================================================
--- freeway/res/daemon.logging  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/daemon.logging  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,9 @@
+# Daemon logging configuration
+
+org.gnu.freeway.server = INFO
+org.gnu.freeway.util.PersistentDecoder = INFO
+org.gnu.freeway.util.PersistentReader = INFO
+org.gnu.freeway.util.PersistentWriter = INFO
+
+org.gnu.freeway.transport = INFO
+

Added: freeway/res/gnunet.client.template
===================================================================
--- freeway/res/gnunet.client.template  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/gnunet.client.template  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,148 @@
+# This is the USER configuration for your GNUnet node.  Copy this file to
+# "~/.gnunet/gnunet.conf".
+# For any other location, you must tell every GNUnet application 
+# that you start where this file is.  (option -c FILENAME).
+#
+#
+#################################################
+#
+# This line gives the directory where GNUnet is putting
+# user-specific files (such as pseudonyms).  Typically,
+# GNUnet should not put more than a few of MB there.
+#
+# Default is GNUNET_HOME       = ~/.gnunet
+GNUNET_HOME    = "%clients.basedir@/org/gnu/freeway/config%"
+
+
+###############################################
+# General client options...
+###############################################
+[GNUNET]
+# Loglevel. What kinds of (debug) output should be printed? You can 
+# use NOTHING, FATAL, ERROR, FAILURE, WARNING, MESSAGE, INFO, DEBUG, 
+# CRON or EVERYTHING (which print more and more messages in this order). 
+# Default is WARNING which is usually enough to let you know if there
+# is any problems.
+LOGLEVEL        = FINEST
+
+# Where to write the messages? Leave the entry unspecified (as
+# default) to make the clients print their messages to stderr.
+# Default is unspecified (stderr).
+#LOGFILE = $GNUNET_HOME/logs
+
+# Which crypto provider do we use ? (JCE compliant)
+# Default is BouncyCastle
+CRYPTO_PROVIDER        =       
org.bouncycastle.jce.provider.BouncyCastleProvider
+
+
+###############################################
+# MySQL parameters for test app
+###############################################
+
+[TEST]
+
+MYSQL_DRIVER   = com.mysql.jdbc.Driver
+MYSQL_HOST     = "%mysql.host@/org/gnu/freeway/config%"
+MYSQL_USER     = "%mysql.user@/org/gnu/freeway/config%"
+MYSQL_PASSWORD = "%mysql.password@/org/gnu/freeway/config%"
+
+
+###############################################
+# Network options for the clients...
+###############################################
+[NETWORK]
+# Port to use to talk to gnunetd, default is 2087
+PORT = 2087
+
+# On which machine runs gnunetd (for clients) This is equivalent to
+# the -H option.  Default is localhost.
+HOST = localhost
+
+
+
+
+################################################
+# Options for anonymous filesharing (AFS).
+################################################
+[AFS]
+
+# How long should gnunet-search try to get an answer to a query before
+# timing out (in seconds).  Default is "3000", which should be enough
+# for pretty much anything. Use 0 for no timeout.
+SEARCHTIMEOUT   = 3000
+
+# Specify which additional extractor libraries should be used.
+# gnunet-insert uses libextractor to extract keywords from files.
+# libextractor can be dynamically extended to handle additional file
+# formats. If you want to use more than the default set of extractors,
+# specify additional extractor libraries here.  The format is
+# [[-]LIBRARYNAME[:[-]LIBRARYNAME]*] The default is to use filenames
+# and to break larger words at spaces (and underscores, etc.).  This
+# should be just fine for most people. The - before a library name
+# indicates that this should be executed last and makes only sense for
+# the split-library.
+# Default is libextractor_filename:-libextractor_split:-libextractor_lower
+EXTRACTORS = libextractor_filename:-libextractor_split:-libextractor_lower
+
+# Where to download files to (by default)?
+# Default is /tmp/gnunet-downloads/
+DOWNLOADDIR     = /tmp/gnunet-downloads/
+
+# This option allows enabling/disabling of the code that collects
+# file-identifiers for building directories.  Note that you can
+# build directories of files that you insert without collecting
+# file-identifiers by using the option "-b" of gnunet-insert.
+# You can not add entries from namespaces to directories without
+# at least temporarily collecting file-identifiers.
+# Default is NO
+COLLECT-FILE-IDENTIFIERS = YES
+
+
+#################################################
+# Default options for the gnunet-insert tool
+#################################################
+[GNUNET-INSERT]
+
+# What is the initial priority of content that is locally inserted? 
+# Default is 65535 which is "very high".
+CONTENT-PRIORITY = 65535
+
+##########################################
+# Defaults for gnunet-chat
+##########################################
+[GNUNET-CHAT]
+
+# You can specify your nickname here and thus avoid having to pass it
+# with -n NICK at the command-line.  The default is empty.
+#
+# NICK = "my nickname"
+
+##########################################
+# Defaults for gnunet-tracekit
+##########################################
+[GNUNET-TRACEKIT]
+
+# How long to wait for replies (in seconds)? (default: 30)
+WAIT      = 30
+
+# How many hops should the trace go? (default: 5)
+HOPS     = 5
+
+# How important is the trace message? (default: 1000)
+PRIORITY = 1000
+
+# Output format, 0 is human readable, 1 is dot (default: 1)
+FORMAT   = 1
+
+
+[GNUNET-TESTBED]
+
+# Port used internally by gnunet-testbed
+# (for the IPC in the gnunet-testbed shell).
+# The default is 2089.
+PORT = 2089
+
+# At which URL does the registration software
+# run?
+# Default is http://www.ovmj.org/GNUnet/testbed/
+REGISTERURL = "http://www.ovmj.org/GNUnet/testbed/";

Added: freeway/res/gnunet.daemon.template
===================================================================
--- freeway/res/gnunet.daemon.template  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/gnunet.daemon.template  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,629 @@
+# This is the configuration for the GNUnet daemon, gnunetd.
+# Copy this file to "/etc/gnunet.conf" if you are root. 
+# For any other location, you must explicitly tell gnunetd
+# where this file is (option -c FILENAME).
+#
+# After any change in this file, you may want to manually restart
+# gnunetd since some changes are only recognized after a re-start.
+# Sending a SIGHUP to gnunetd will trigger re-reading the following
+# options:
+# NETWORK: HELOEXCHANGE
+# GNUNETD: LOGLEVEL
+# LOAD: INTERFACES
+# LOAD: BASICLIMITING
+# LOAD: MAXNETDOWNBPSTOTAL
+# LOAD: MAXNETUPBPSTOTAL
+# LOAD: MAXCPULOAD
+#
+#
+# This file is structured as follows.
+# 1) GNUNETD_HOME - base directory for all GNUnet files
+# 2) gnunetd options (which transport and application services, logging)
+# 3) network configuration 
+# 4) load management (resource limitations)
+# 5) UDP, TCP and SMTP transport configuration
+# 6) configuration for anonymous file sharing (AFS)
+#
+#################################################
+#
+# This line gives the root-directory of the GNUnet installation. Make
+# sure there is some space left in that directory. :-)  Users inserting
+# or indexing files will be able to store data in this directory
+# up to the (global) quota specified below.  Having a few gigabytes
+# of free space is recommended.
+# Default: GNUNETD_HOME     = /var/lib/GNUnet
+GNUNETD_HOME     = "%daemon.basedir@/org/gnu/freeway/config%"
+
+#########################################
+# Options for the GNUnet server, gnunetd
+#########################################
+[GNUNETD]
+
+# Which crypto provider do we use ? (JCE compliant)
+# Default is BouncyCastle
+CRYPTO_PROVIDER        =       
org.bouncycastle.jce.provider.BouncyCastleProvider
+
+
+# How many minutes is the current IP valid?  (GNUnet will sign HELO
+# messages with this expiration timeline. If you are on dialup, 60
+# (for 1 hour) is suggested. If you are having a static IP address,
+# you may want to set this to a large value (say 14400).  The default
+# is 1440 (1 day). If your IP changes periodically, you will want to
+# choose the expiration to be smaller than the frequency with which
+# your IP changes.
+# The largest legal value is 14400 (10 days).
+# Default: HELOEXPIRES     = 1440
+HELOEXPIRES     = 1440
+
+# Loglevel, how much should be logged? You can use NOTHING, FATAL,
+# ERROR, FAILURE, WARNING, MESSAGE, INFO, DEBUG, CRON or EVERYTHING
+# (which log more and more messages in this order). Default is
+# WARNING.
+LOGLEVEL        = FINEST
+
+# In which file should daemon write the logs ?
+# If you specify nothing, logs are written to stderr (and note that if gnunetd 
runs
+# in the background, stderr is closed and all logs are discarded).
+# Default: LOGFILE         = $GNUNETD_HOME/logs
+#LOGFILE         = $GNUNETD_HOME/logs
+
+# In which file should gnunetd write the process-id of the server?  If
+# you run gnunetd as root, you may want to choose
+# /var/run/gnunetd.pid. It's not the default since gnunetd may not
+# have write rights at that location.
+# Default: PIDFILE         = $GNUNETD_HOME/gnunetd.pid
+PIDFILE         = $GNUNETD_HOME/gnunetd.pid
+
+# This directory should be made available periodically --- it contains
+# information how to join GNUnet that is in no way private to the
+# local node.  This directory can be shared between nodes AND should
+# be put on a public web-server (if possible).  You should find a list
+# of known hosts under http://www.ovmj.org/GNUnet/hosts/, you can copy
+# those files into this directory.
+# 
+# If you specify a HOSTLISTURL, the directory will be automatically
+# populated by gnunetd with an initial set of nodes.
+# Default: HOSTS       = $GNUNETD_HOME/data/hosts/
+HOSTS          = $GNUNETD_HOME/data/hosts/
+
+# GNUnet can automatically update the hostlist from the web. While
+# GNUnet internally communicates which hosts are online, it is
+# typically a good idea to get a fresh hostlist whenever gnunetd
+# starts from the WEB. By setting this option, you can specify from
+# which server gnunetd should try to download the hostlist. The
+# default should be fine for now.
+#
+# The general format is a list of space-separated URLs.  Each URL must
+# have the format http://HOSTNAME/FILENAME
+#
+# If you want to setup an alternate hostlist server, you must run a
+# permanent node and "cat data/hosts/* > hostlist" every few minutes
+# to keep the list up-to-date.
+#
+# If you do not specify a HOSTLISTURL, you must copy valid hostkeys to
+# data/hosts manually.
+# Default: HOSTLISTURL = "http://www.ovmj.org/GNUnet/download/hostlist 
http://gnunet.cryss.net/hostlist http://www.woodtick.co.uk/hostlist";
+HOSTLISTURL = "http://www.ovmj.org/GNUnet/download/hostlist 
http://gnunet.cryss.net/hostlist http://www.woodtick.co.uk/hostlist";
+
+# If you have to use a proxy for outbound HTTP connections,
+# specify the proxy configuration here.  Default is no proxy.
+# HTTP-PROXY = localhost
+# HTTP-PROXY-PORT = 1080
+
+# Which applications should gnunetd support? Specify the name of the
+# dynamic shared object (DSO) that implements the service in the
+# gnunetd core here. Separate multiple modules with spaces.
+#
+# Currently, the available applications are:
+# afs: anonymous file sharing
+# chat: broadcast chat (demo-application)
+# tbench: benchmark tool for transport performance
+# tracekit: GNUnet topology visualization toolkit
+#
+# All protocols but "afs" are potential security risks
+# and have been engineered for testing GNUnet or demonstrating how
+# GNUnet works. They should be used with caution.
+#
+# Typical choices are: "afs chat tbench tracekit"
+# Default: APPLICATIONS = "afs tbench tracekit"
+APPLICATIONS = "afs tbench chat tracekit"
+
+# Which transport mechanisms are available? Use space-separated list
+# of the modules, e.g.  "udp smtp tcp". The order is irrelevant, each
+# protocol has a build-in cost-factor and this factor determines which
+# protocols are preferred.  
+#
+# The available transports at this point are udp, tcp, http, smtp,
+# tcp6, udp6 and the special 'nat' service.
+#
+# Loading the 'nat' and 'tcp' modules is required for peers behind NAT
+# boxes that can not directly be reached from the outside.  Peers that
+# are NOT behind a NAT box and that want to *allow* peers that ARE
+# behind a NAT box to connect must ALSO load the 'nat' module.  Note
+# that the actual transfer will always be via tcp initiated by the peer
+# behind the NAT box.
+#
+# Usually, the default is just fine for most people.
+# Choices are: "udp tcp udp6 tcp6 nat http smtp"
+# Default: TRANSPORTS = "udp tcp nat"
+TRANSPORTS = "udp tcp"
+
+
+
+
+############################################
+# Network configuration
+############################################
+[NETWORK]
+
+# Which is the client-server port that is used between gnunetd and the
+# clients (TCP only).  You may firewall this port for non-local
+# machines.
+# Default: PORT = 2087
+PORT = 2087
+
+# Set if GNUnet fails to determine your IP.  GNUnet first tries to
+# determine your IP by looking at the IP that matches the interface
+# that is given with the option INTERFACE.
+# Under Windows, specify the index number reported by
+#  "gnunet-win-tool -n"
+# Default: INTERFACE = eth0
+INTERFACE = ppp0
+
+# If this fails, GNUnet will try to do a DNS lookup on your HOSTNAME,
+# which may also fail, in particular if you are on dialup.
+#
+# If both options are not viable for you, you can specify an IP in
+# this configuration file.  This may be required if you have multiple
+# interfaces (currently GNUnet can only work on one of them) or if you
+# are behind a router/gateway that performs network address
+# translation (NAT). In the latter case, set this IP to the *external*
+# IP of the router (!) and make sure that the router forwards incoming
+# UDP packets on the GNUnet port (default: 2086) to the dedicated
+# GNUnet server in the local network.
+#
+# The given example value (127.0.0.1) will NOT work!  If you do not know
+# what all this means, try without!
+# Default is no IP specified.
+# IP   = 127.0.0.1
+
+# If this host is connected to two networks, a private which is not
+# reachable from the Internet and that contains GNUnet clients and to
+# a public network, typically the Internet (and is this host is thus
+# in the position of a router, typically doing NAT), then this option
+# should be set to 'NO'. It prevents the node from forwarding HELOs
+# other than its own. If you do not know what the above is about, just
+# keep it set to YES (which is also the default when the option is not
+# given).
+# Default is yes: HELOEXCHANGE = YES
+HELOEXCHANGE = YES
+
+# With this option, you can specify which networks are trusted enough
+# to connect as clients to the TCP port.  This is useful if you run
+# gnunetd on one host of your network and want to allow all other
+# hosts to use this node as their server. By default, this is set to
+# 'loopback only'. The format is the same as for the BLACKLIST.
+# Default is: TRUSTED = 127.0.0.0/8;
+TRUSTED = 127.0.0.0/8;
+
+
+
+
+
+
+######################################
+# Options for load management 
+######################################
+[LOAD]
+# In this section you specify how many resources GNUnet is allowed to
+# use. GNUnet may exceed the limits by a small margin (network & CPU
+# are hard to control directly), but should do a reasonable job to
+# keep the average around these values
+
+# For which interfaces should we do accounting?  GNUnet will evaluate
+# the total traffic (not only the GNUnet related traffic) and adjust
+# its bandwidth usage accordingly. You can currently only specify a
+# single interface. GNUnet will also use this interface to determine
+# the IP to use. Typical values are eth0, ppp0, eth1, wlan0, etc.
+# 'ifconfig' will tell you what you have.  Never use 'lo', that just
+# won't work.
+# Under Windows, specify the index number reported by
+#  "gnunet-win-tool -n".
+# Default is: INTERFACES      = eth0
+INTERFACES      = ppp0
+
+# Use basic bandwidth limitation? YES or NO.  The basic method (YES)
+# notes only GNUnet traffic and can be used to specify simple maximum
+# bandwidth usage of GNUnet.  Choose the basic method if you don't
+# want other network traffic to interfere with GNUnet's operation, but
+# still wish to constrain GNUnet's bandwidth usage, or if you can't
+# reliably measure the maximum capabilities of your connection.  YES
+# can be very useful if other applications are causing a lot of
+# traffic on your LAN.  In this case, you do not want to limit the
+# traffic that GNUnet can inflict on your WAN connection whenever your
+# high-speed LAN gets used (e.g. by NFS).
+#
+# The advanced bandwidth limitation (NO) measures total traffic over
+# the chosen interface (including traffic by other applications), and
+# allows gnunetd to participate if the total traffic is low enough.
+# Default is: BASICLIMITING = YES
+BASICLIMITING = YES
+
+# Bandwidth limits in bytes per second. These denote the maximum
+# amounts GNUnet is allowed to use.
+# Defaults are: 
+# MAXNETUPBPSTOTAL     = 50000
+# MAXNETDOWNBPSTOTAL   = 50000
+MAXNETUPBPSTOTAL       = 50000
+MAXNETDOWNBPSTOTAL     = 50000
+
+
+# Which CPU load can be tolerated (total, GNUnet will adapt if the
+# load goes up due to other processes). A value of 50 means that once
+# your 1 minute-load average goes over 50% non-idle, GNUnet will start
+# dropping packets until it goes under that threshold again.
+# Default is MAXCPULOAD                = 50
+MAXCPULOAD             = 50
+
+
+
+
+###########################################
+# Options for the UDP transport layer.
+###########################################
+[UDP]
+
+# To which port does GNUnet bind? Default is 2086 and there is usually
+# no reason to change that.
+PORT           = 2086
+
+# With this option, you can specify which networks you do NOT want to
+# connect to. Usually you will want to filter loopback (127.0.0.1,
+# misconfigured GNUnet hosts), virtual private networks, [add a class
+# C network here], 192.168.0.0, 172.16.0.0 and 10.0.0.0 (RFC
+# 1918). The format is IP/NETMASK where the IP is specified in
+# dotted-decimal and the netmask either in CIDR notation (/16) or in
+# dotted decimal (255.255.0.0). Several entries must be separated by a
+# semicolon, spaces are not allowed.  Notice that if your host is on a
+# private network like the above, you will have to configure your NAT
+# to allow incoming requests and you will want to modify this option.
+# The idea behind this option is not to discriminate against NAT users
+# but to ensure that hosts only attempt to connect to machines that
+# they have a chance to actually reach.  Of course, you could also use
+# it against known adversaries that have a small IP range at their
+# disposal :-) 
+#
+# Example (and default):
+# 127.0.0.1/8;172.16.0.0/12;192.168.0.0/16;10.0.0.0/255.0.0.0;
+BLACKLIST = 127.0.0.1/8;172.16.0.0/12;192.168.0.0/16;10.0.0.0/255.0.0.0;
+
+
+# The MTU to use. Do not use more than your OS
+# (and firewall) can support. Typically, your 
+# network-MTU - 28 is optimal, for ethernet, this
+# is 1472, the default. Do not use less than 1200.
+#
+# The default is 1472, which is also used if you specify
+# nothing.
+MTU = 1472
+
+
+###########################################
+# Options for the TCP transport layer.
+###########################################
+[TCP]
+
+# To which port does GNUnet bind? Default is 2086 and there is usually
+# no reason to change that.  Make sure that this port does not
+# conflict with the port for GNUnet clients (section NETWORK), which
+# defaults to 2087.  
+PORT = 2086
+
+# With this option, you can specify which networks you do NOT want to
+# connect to. Usually you will want to filter loopback (127.0.0.1,
+# misconfigured GNUnet hosts), virtual private networks, [add a class
+# C network here], 192.168.0.0, 172.16.0.0 and 10.0.0.0 (RFC
+# 1918). The format is IP/NETMASK where the IP is specified in
+# dotted-decimal and the netmask either in CIDR notation (/16) or in
+# dotted decimal (255.255.0.0). Several entries must be separated by a
+# semicolon, spaces are not allowed.  Notice that if your host is on a
+# private network like the above, you will have to configure your NAT
+# to allow incoming requests and you will want to modify this option.
+# The idea behind this option is not to discriminate against NAT users
+# but to ensure that hosts only attempt to connect to machines that
+# they have a chance to actually reach.  Of course, you could also use
+# it against known adversaries that have a small IP range at their
+# disposal :-)
+# Example (and default):
+# BLACKLIST = 127.0.0.1/8;192.168.0.0/16;10.0.0.0/255.0.0.0; 
+BLACKLIST = 127.0.0.1/8;192.168.0.0/16;10.0.0.0/255.0.0.0;
+
+# The MTU to use (TCP is stream oriented, so we are pretty free to
+# choose what we want, but note that larger MTUs mean more noise if
+# traffic is low). Do not use less than 1200.  Default is 1460.
+MTU = 1460
+
+###############################################
+# Options for NAT transport
+###############################################
+[NAT]
+
+# Is this machine behind a NAT that does not allow
+# connections from the outside to the GNUnet port?
+# (if you can configure the NAT box to allow
+# direct connections from other peers, set this
+# to NO).  Set this only to YES if other peers
+# cannot contact you directly via TCP or UDP.
+# If you set this to YES, you should also set the
+# TCP port to '0' and disable UDP to indicate that you
+# can not accept inbound connections.
+#
+# Default: NO
+LIMITED = NO
+
+
+##########################################
+# IPv6 transports, don't bother unless you
+# want to use IPv6.
+##########################################
+
+[UDP6]
+
+# Default port is 2088 and MTU is 1452.
+PORT = 2088
+# BLACKLIST = 
+MTU = 1452
+
+[TCP6]
+
+# Default port is 2088 and MTU is 1440.
+PORT = 2088
+# BLACKLIST = 
+MTU = 1440
+
+[HTTP]
+
+# Default port is 1080 and MTU is 1400.
+PORT = 1080
+# BLACKLIST =
+MTU = 1400
+
+
+###############################################
+# Options for SMTP transport
+###############################################
+[SMTP]
+
+# E-mail address to use to receive messages.  Do not specify anything
+# if you do not want to allow SMTP as a receiver protocol; you can
+# still *send* email to establish connections in that case.  Example:
+# EMAIL = address@hidden
+# EMAIL =
+
+# MTU for the E-mail. How large should the E-mails be that we send
+# out? Default is 65536 (bytes).
+MTU = 65536
+
+# Port of the SMTP server for outbound mail.  If not specified, the
+# TCP/SMTP entry from /etc/services is consulted.  Default is 25.
+PORT = 25
+
+# Hostname of the SMTP server. Default is "localhost".
+SERVER = localhost
+
+# Hostname of the sender host to use in the HELO message of the SMTP
+# protocol (not to be confused with the HELO in the GNUnet p2p
+# protocol). Pick a hostname that works for your SMTP server. This
+# hostname has nothing to do with the hostname of the SMTP server or
+# your E-mail sender address (though those names should work in most
+# cases). In fact, it often does not even have to exist as a real
+# machine. Example: "myhost.example.com"
+SENDERHOSTNAME = myhost.example.com
+
+# Filter-line to use in the E-mail header. This filter will be
+# included in the GNUnet-generated E-mails and should be used to
+# filter out GNUnet traffic from the rest of your E-mail. Make sure
+# that the filter you choose is highly unlikely to occur in any other
+# message.
+#
+# Examples:
+# FILTER = "X-mailer: myGNUnetmail"
+# FILTER = "Subject: foobar5252"
+FILTER = "X-mailer: 590N"
+
+# Name of the pipe via which procmail sends the filtered E-mails to
+# the node.  Default is /tmp/gnunet.smtp
+PIPE = /tmp/gnunet.smtp
+
+
+
+
+
+################################################
+# Options for anonymous filesharing (AFS).
+################################################
+[AFS]
+
+# How much disk space (MB) is GNUnet allowed to use for anonymous file
+# sharing?  This does not take indexed files into account, only the
+# space directly used by GNUnet is accounted for.  GNUnet will gather
+# content from the network if the current space-consumption is below
+# the number given here (and if content migration is allowed below).
+#
+# IMPORTANT:
+# Note that if you change the quota, you need to run gnunet-convert,
+# otherwise your databases will be inconsistent and gnunetd will
+# refuse to work.  Default is 1024 (1 GB)
+DISKQUOTA      = 1024
+
+# Which database type should be used for content? Valid types are
+# "gdbm", "mysql", "tdb" and "directory". Specified type must have
+# been available at compile time. "directory" is available on all
+# systems but typically uses more space and can also be slower.  mysql
+# will require some additional setup of the database.
+#
+# Note that if you change the databaset type, you need to run
+# gnunet-convert, otherwise your databases will be
+# inconsistent (and gnunetd will refuse to work).  Default is gdbm.
+DATABASETYPE    = "mysql"
+
+MYSQL_DRIVER   = com.mysql.jdbc.Driver
+MYSQL_HOST     = "%mysql.host@/org/gnu/freeway/config%"
+MYSQL_USER     = "%mysql.user@/org/gnu/freeway/config%"
+MYSQL_PASSWORD = "%mysql.password@/org/gnu/freeway/config%"
+
+# What degree of receiver anonymity is required?  If set to 0, GNUnet
+# will try to download the file as fast as possible without any
+# additional slowdown by the anonymity code. Note that you will still
+# have a fair degree of anonymity depending on the current network
+# load and the power of the adversary. The download is still unlikely
+# to be terribly fast since the sender may have requested
+# sender-anonymity and since in addition to that, GNUnet will still do
+# the anonymous routing.
+#
+# This option can be used to limit requests further than that. In
+# particular, you can require GNUnet to receive certain amounts of
+# traffic from other peers before sending your queries. This way, you
+# can gain very high levels of anonymity - at the expense of much more
+# traffic and much higher latency. So set it only if you really
+# believe you need it.
+#
+# The definition of ANONYMITY-RECEIVE is the following: 
+#  If the value v # is < 1000, it means that if GNUnet routes n bytes
+#  of messages from # foreign peers, it may originate n/v bytes of
+#  queries in the same # time-period.  The time-period is twice the
+#  average delay that GNUnet # deferrs forwarded queries.
+# 
+#  If the value v is >= 1000, it means that if GNUnet routes n bytes
+#  of QUERIES from at least (v % 1000) peers, it may originate
+#  n/v/1000 bytes of queries in the same time-period.
+#
+# The default is 0 and this should be fine for most users. Also notice
+# that if you choose values above 1000, you may end up having no
+# throughput at all, especially if many of your fellow GNUnet-peers do
+# the same.
+ANONYMITY-RECEIVE = 0
+
+# You can also request a certain degree of anonymity for the files and
+# blocks that you are sharing. In this case, only a certain faction of
+# the traffic that you are routing will be allowed to be replies that
+# originate from your machine. Again, 0 means unlimited.
+#
+# The semantics of ANONYMITY-SEND are equivalent to the semantics of
+# ANONYMITY-RECEIVE.
+#
+# The default is 0 and this should be fine for most users.
+ANONYMITY-SEND = 0
+
+
+# Should we participate in content migration?  If you say yes here,
+# GNUnet will migrate content to your server, and you will not be able
+# to control what data is stored on your machine.  This option has
+# advantages and disadvantages.
+#
+# If you activate it, you can claim for *all* the non-indexed (-n to
+# gnunet-insert) content that you did not know what it was even if an
+# adversary takes control of your machine.
+#
+# If you do not activate it, it is obvious that you have knowledge of
+# all the content that is hosted on your machine and thus can be
+# considered liable for it.  
+#
+# So if you think that the legal system in your country has gone
+# postal, you may want to set it to "NO" and make sure that the
+# content you put on your machine does not get you into too much
+# trouble if an adversary takes control of your machine.  If you think
+# that you're safe if you host content that you don't know anything
+# about (like an ISP) or that you don't have to fear prosecution
+# no-matter-what, turn it to YES, which will also improve GNUnet's
+# performance and thereby your results.
+#
+# Note that as long as the adversary is not really powerful (e.g. can
+# not take control of your machine), GNUnet's build-in anonymity
+# mechanisms should protect you from being singled out easily.
+# 
+# Currently, activating active migration can cause some problems when
+# the database is getting full (gdbm reorganization can take very,
+# very long and make GNUnet look like it hangs for that time). Thus if
+# you turn it on, you may want to disable it after you hit the
+# quota. A better content management system should solve this problem
+# in the near future... [at the time of GNUnet 0.6.1c, the MySQL 
+# database module already works well even if the db is full.]
+# Default is YES.
+ACTIVEMIGRATION = YES
+
+# Where to store the AFS related data (content, etc)?
+AFSDIR          = $GNUNETD_HOME/data/afs/
+
+# Where to store indexed files (NEW!)
+# Note that you MUST not copy files directly to this
+# directory.  gnunet-insert (or gnunet-gtk) will copy
+# the files that you index to this directory.  With the
+# -l option you instead create a link (if gnunetd and
+# gnunet-insert run on the same machine) instead.
+#
+# The QUOTA option does NOT apply for this directory.
+# To limit how much can be placed in this directory
+# set the option INDEX-QUOTA.  Files that are merely
+# linked do not count towards the quota.
+#
+# If you uncomment this option gnunetd will refuse
+# content indexing requests (insertion will still be
+# possible).
+#
+# Note that files indexed with GNUnet before Version
+# 0.6.2 were not moved/linked to this directory.  But that
+# should not cause any immediate problems (the files
+# will continue to be downloadable).  What will be
+# impossible is unindexing these files with
+# gnunet-delete and GNUnet >= 0.6.2. 
+# Default is $GNUNETD_HOME/data/shared/
+INDEX-DIRECTORY = $GNUNETD_HOME/data/shared/
+
+# Indexing quota.  Default is 8192.
+INDEX-QUOTA = 8192
+
+
+#######################################
+# Experimental GDBM options
+#######################################
+
+[GDBM]
+
+# Use experimental settings for managing
+# free blocks in gdbm.  Default is YES!
+EXPERIMENTAL = YES
+
+# This option allows avoiding gdbm database reorganization
+# on startup.  It should definitely only be used together
+# with the experimental gdbm free blocks option.  Nevertheless,
+# the option has not been tested extensively yet, so to be
+# safe it should be set to 'YES' (do reorganize).  Default
+# is 'YES'.
+REORGANIZE = YES
+
+
+#######################################
+# TESTBED (experimental!)
+#######################################
+
+[TESTBED]
+
+# Where should we register the testbed service?
+# Default is "http://www.ovmj.org/GNUnet/testbed/";
+REGISTERURL = "http://www.ovmj.org/GNUnet/testbed/";
+
+# Is the testbed operator allowed to load and
+# unload modules? (somewhat of a security risk!)
+# Default is NO.
+ALLOW_MODULE_LOADING = NO
+
+# Where should file-uploads go?
+# Default is $GNUNETD_HOME/testbed
+UPLOAD-DIR = $GNUNETD_HOME/testbed
+
+# Login-name for SSH-tunnel (for secure testbed
+# connections).  Without login name the testbed-server
+# will try to make a direct TCP connection to the
+# application port (default: 2087).
+# LOGIN = 

Added: freeway/res/jnlp/batik.jnlp
===================================================================
--- freeway/res/jnlp/batik.jnlp 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/jnlp/batik.jnlp 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<jnlp spec="1.0+" codebase="@REMOTE_URL@" href="batik.jnlp">
+       <information>
+               <title>Batik</title>
+               <vendor>Batik</vendor>
+       </information>
+
+       <resources>
+               <jar href="batik-all.jar" />
+       </resources>
+
+       <security>
+               <all-permissions />
+       </security>
+
+       <component-desc />
+</jnlp> 

Added: freeway/res/jnlp/bouncycastle-jce.jnlp
===================================================================
--- freeway/res/jnlp/bouncycastle-jce.jnlp      2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/res/jnlp/bouncycastle-jce.jnlp      2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<jnlp spec="1.0+" codebase="@REMOTE_URL@" href="bouncycastle-jce.jnlp">
+       <information>
+               <title>Bouncy Castle JCE</title>
+               <vendor>The Legion of the Bouncy Castle</vendor>
+       </information>
+
+       <resources>
+               <jar href="bcprov-jdk14-122.jar" />
+       </resources>
+
+       <security>
+               <all-permissions />
+       </security>
+
+       <component-desc />
+</jnlp> 

Added: freeway/res/jnlp/concurrent.jnlp
===================================================================
--- freeway/res/jnlp/concurrent.jnlp    2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/jnlp/concurrent.jnlp    2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<jnlp spec="1.0+" codebase="@REMOTE_URL@" href="concurrent.jnlp">
+       <information>
+               <title>Concurrent Library</title>
+               <vendor>Concurrent Library</vendor>
+       </information>
+
+       <resources>
+               <jar href="concurrent.jar" />
+       </resources>
+
+       <security>
+               <all-permissions />
+       </security>
+
+       <component-desc />
+</jnlp> 

Added: freeway/res/jnlp/freeway.jnlp
===================================================================
--- freeway/res/jnlp/freeway.jnlp       2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/jnlp/freeway.jnlp       2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- JNLP File for Freeway/GNUnet Standalone Application -->
+
+<jnlp spec="1.0+" codebase="@REMOTE_URL@" href="freeway.jnlp">
+       <information>
+               <title>Freeway/GNUnet Standalone Application</title>
+               <vendor>GNU 2004</vendor>
+               <homepage href="http://www.ovmj.org/GNUnet/freeway/"; />
+               <description>Freeway/GNUnet Standalone Application</description>
+               <icon href="logo64.jpg" />
+
+               <offline-allowed />
+       </information>
+
+       <security>
+               <all-permissions />
+       </security>
+
+       <resources>
+               <j2se version="1.4+" />
+               <jar href="freeway-for-apps.jar" />
+               <extension href="batik.jnlp" />
+               <extension href="bouncycastle-jce.jnlp" />
+               <extension href="concurrent.jnlp" />
+               <extension href="mysql.jnlp" />
+       </resources>
+
+       <application-desc main-class="org.gnu.freeway.GNUNetSwing">
+               <argument>-L</argument>
+               <argument>INFO</argument>
+               <argument>--nosplash</argument>
+               <argument>address@hidden@</argument>
+       </application-desc>
+</jnlp> 

Added: freeway/res/jnlp/logo64.jpg
===================================================================
(Binary files differ)


Property changes on: freeway/res/jnlp/logo64.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: freeway/res/jnlp/mysql.jnlp
===================================================================
--- freeway/res/jnlp/mysql.jnlp 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/jnlp/mysql.jnlp 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<jnlp spec="1.0+" codebase="@REMOTE_URL@" href="mysql.jnlp">
+       <information>
+               <title>MySQL JDBC Driver</title>
+               <vendor>MySQL</vendor>
+       </information>
+
+       <resources>
+               <jar href="mysql-connector-java-3.0.10-stable-bin.jar" />
+       </resources>
+
+       <security>
+               <all-permissions />
+       </security>
+
+       <component-desc />
+</jnlp> 

Added: freeway/res/quiet.logging
===================================================================
--- freeway/res/quiet.logging   2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/quiet.logging   2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,8 @@
+# Disable full logging for socket specific classes
+
+org.gnu.freeway.DaemonSocket = WARNING
+org.gnu.freeway.util.PersistentChannel = WARNING
+org.gnu.freeway.util.PersistentDecoder = WARNING
+org.gnu.freeway.util.PersistentReader = WARNING
+org.gnu.freeway.util.PersistentWriter = WARNING
+

Added: freeway/res/swing/daemon-window.xml
===================================================================
--- freeway/res/swing/daemon-window.xml 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/daemon-window.xml 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <images locale="enUS">
+               <image id="start.icon" src="images/24x24/start.png" />
+               <image id="stop.icon" src="images/24x24/stop.png" />
+       </images>
+
+       <actions locale="enUS">
+               <action id="start.action" method="onLaunchDaemon">
+                       <label>Start</label>
+                       <description>Start daemon</description>
+                       <accelerator>S</accelerator>
+                       <shortcut>meta S</shortcut>
+                       <icon refid="start.icon" />
+               </action>
+
+               <action id="stop.action" method="onKillDaemon">
+                       <label>Stop</label>
+                       <description>Stop daemon</description>
+                       <icon refid="stop.icon" />
+               </action>
+
+               <action id="close.action" method="onClose">
+                       <label>Close</label>
+                       <shortcut>meta W</shortcut>
+               </action>
+       </actions>
+
+       <menus locale="enUS">
+               <menu id="main.menu">
+                       <menu>
+                               <label>Daemon</label>
+                               <accelerator>D</accelerator>
+
+                               <action refid="start.action" />
+                               <action refid="stop.action" />
+                               <separator />
+                               <action refid="close.action" />
+                       </menu>
+               </menu>
+       </menus>
+</ressources>

Added: freeway/res/swing/download.xml
===================================================================
--- freeway/res/swing/download.xml      2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/download.xml      2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <actions locale="enUS">
+               <action id="abort.id" method="onAbort">
+                       <label>Abort selection</label>
+               </action>
+
+               <action id="close.id" method="onClose">
+                       <label>Close</label>
+               </action>
+       </actions>
+</ressources>

Added: freeway/res/swing/gnunet-config.xml
===================================================================
--- freeway/res/swing/gnunet-config.xml 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/gnunet-config.xml 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <images locale="enUS">
+               <image id="application.icon" 
src="images/128x128/logo.png?bg=ffffff" />
+               <image id="application.medium.icon" 
src="images/64x64/logo.png?bg=ffffff" />
+               <image id="dot.icon" src="images/8x8/logo.png?bg=ffffff" />
+       </images>
+
+       <actions locale="enUS">
+               <action id="quit.action" method="onQuit">
+                       <label>Quit</label>
+               </action>
+       </actions>
+</ressources>

Added: freeway/res/swing/images/logo.svg
===================================================================
--- freeway/res/swing/images/logo.svg   2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/images/logo.svg   2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
+  "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd";>
+
+<svg width="372" height="372" viewBox="0 0 372 372"
+       xmlns="http://www.w3.org/2000/svg";
+       xmlns:xlink="http://www.w3.org/1999/xlink";>
+
+       <defs>
+               <path id="gnu" 
d="M112.993,304.372c-3.634,0.247-8.365,1.875-11.539,7.564
+                       
c-2.591,4.646-8.661,5.387-11.495,4.451c-4.721-1.56-10.755-2.642-16.6,1.523c-5.845,4.164-12.157,1.015-11.05-6.576
+                       
c1.107-7.59,3.849-14.351,11.127-18.538c15.895-9.144,4.848-15.508,13.572-24.685c8.741-9.195,6.81-12.009,6.52-24.497
+                       
c-29.543-4.438-46.287-12.953-64.984-36.313c-18.697-23.361-25.945-42.59-27.883-71.878c-1.938-29.288-0.258-48.269,12.396-72.58
+                       
s25.977-36.014,49.065-48.153C85.21,2.553,107.832-0.354,128.742,0c20.91,0.353,34.843,1.885,46.658,8.626
+                       
c11.814,6.741,22.622,15.224,29.512,15.285c6.891,0.061,11.582-1.744,14.931-4.31c0.894,22.703-19.539,24.675-37.819,25.155
+                       
c-18.281,0.479-29.514-7.083-46.351-4.27S91.269,50.961,77.84,74.336s-13.887,31.638-12.771,51.24
+                       
c1.116,19.603,17.988,34.228,27.512,34.387c9.523,0.159,11.649-2.599,19.985-8.036c8.337-5.438,50.896-58.122,65.418-69.956
+                       
c14.523-11.834,28.854-15.488,44.328-15.678c15.474-0.19,19.428,0.335,31.908,5.45c12.48,5.114,20.149,14.533,30.211,20.291
+                       
c5.143-3.027,8.338-7.547,13.057-10.996c16.877-12.335,25.646-15.659,45.705-13.707c11.529,1.122,26.066,7.708,34.74,15.25
+                       
c15.445,13.429,28.205,32.125,38.516,46.328c8.029,11.061,17.477,24.295,30.965,28.432c14.727,4.515,25.809-14.559,27.436-25.139
+                       
c0.922-5.995,2.125-11.249,2.135-17.847c0.01-6.599-0.664-14.607-2.566-21.484s-5.16-13.72-8.688-19.394
+                       
c-5.742-9.235-15.137-18.899-24.912-23.871c-5.486-2.79-18.393-7.863-26.529-8.041c-9.969-0.216-17.564,3.133-26.781,3.761
+                       
c-11.156,0.761-31.084,3.269-39.83-5.35c-5.566-5.485-6.266-9.144-7.217-16.296c2.459,2.026,5.898,3.358,8.959,3.617
+                       
c6.986,0.59,13.527-5.114,19.166-8.419c4.645-2.723,11.223-7.589,17.324-10.048c15.676-6.32,34.932-6.138,51.48-4.445
+                       
c13.264,1.356,30.461,7.257,42.094,13.84c11.688,6.612,22.951,17.761,31.201,28.271c10.379,13.224,16.053,24.57,19.812,41.063
+                       
c4.805,21.062,6.137,52.702,0.328,73.469c-4.578,16.365-19.779,41.504-32.719,53.827c-12.762,12.155-27.498,18.022-44.256,21.231
+                       
c0.656,3.382,0.764,6.536,1.631,9.309c1.232,3.936,3.588,8.324,8.428,6.936c1.93-0.553,2.963-1.032,5.508,1.194
+                       
c2.543,2.226,1.219,10.825-5.938,14.684c-3.629,1.957-7.459,2.382-13.271,2.498s-14.883,0.141-21.193-0.964
+                       
c-6.309-1.104-10.078-6.111-17.066-6.895c-10.799-1.208-19.068-9.01-27.727-14.59c-3.613-2.329-4.832-2.353-6.914-3.53
+                       
c1.125,3.444,2.625,7.021,3.373,10.332c0.75,3.311,0.43,6.378,0.828,9.028c0.396,2.648,1.131,4.707,1.559,6.855
+                       
c1.73,1.547,2.283,3.9,5.189,4.64c2.908,0.739,7.461-0.412,10.436-0.812s4.969-2.021,7.303-1.577
+                       
c2.336,0.443,4.549,2.115,6.506,3.682s3.639,1.796,5.223,5.706s3.037,11.917,3.254,17.269s-0.383,10.183-1.969,14.43
+                       
s-2.98,6.13-7.275,10.336c-4.295,4.207-11.289,10.38-18.268,14.68c1.285,1.903,1.855,3.645,3.859,5.71
+                       
c2.004,2.066,6.182,4.381,8.041,6.56c1.857,2.179,2.799,3.742,2.826,6.186c0.029,2.443-0.09,5.619-2.074,8.283
+                       
c-4.941,6.633-10.785,7.821-17.891,10.941c1.195,7.462,2.17,12.793,0.443,20.244c-0.705,3.036-2.271,9.92-6.016,11.686
+                       
c-3.746,1.766-10.969,0.911-15.541,1.637c-4.572,0.727-7.131,1.417-10.695,2.125c-2.166,3.131-5.391,6.586-6.496,9.392
+                       
c-1.107,2.807-0.773,3.813,0.156,6.679s4.092,7.039,4.988,10.395s1.07,6.969,0.234,10.334c-0.838,3.365-2.271,5.807-5.139,8.795
+                       
c-2.867,2.989-8.508,5.336-11.318,7.758c-2.812,2.423-5.611,2.714-4.844,6.723c1.055,5.506,9.1,14.436,14.92,16.562
+                       
c3.488,1.275,8.17,0.873,12.406-0.915c-0.287,4.703-4.357,7.873-7.016,10.996c7.201-2.059,14.184-6.001,19.014-11.226
+                       
c-1.498,4.538-6.652,11.823-14.361,18.22c-7.709,6.397-7.662,5.088-11.494,7.633c6.992,1.405,13.494,1.025,18.91,0.052
+                       
c-2.969,1.637-7.836,3.939-14.283,4.616c-6.447,0.676-10.422,0.198-16.232-1.213c-5.811-1.412-11.115-6.694-18.156-10.335
+                       
c0.686,2.612,1.174,5.753,4.135,8.439c2.961,2.686,7.441,4.052,12.203,6.375c-6.062-0.688-12.432-0.896-18.389-2.209
+                       
c-4.41-0.973-7.373-2.005-10.6-3.603c-3.225-1.598-5.715-3.929-8.572-5.893c1.369,2.615,1.775,5.691,4.105,7.847
+                       
s6.117,2.959,9.18,4.44c-3.195-0.07-6.268,0.623-9.58-0.21c-3.314-0.833-6.422-2.142-9.867-4.68s-6.998-5.663-9.938-8.858
+                       
c-2.938-3.195-6.566-7.337-7.664-10.283c-1.1-2.947,0.66-5.008,0.99-7.509c-2.029,1.333-4.525,2.067-6.084,4.002
+                       
s-2.941,3.702-2.251,7.075c0.691,3.373,3.804,7.496,6.005,11.248c-6.568-5.371-10.236-7.439-11.799-13.918
+                       
c-1.463-6.066,2.322-11.572,5.199-16.159c1.429-2.278,3.567-4.398,4.903-6.597c-2.967-2.903-6.358-5.398-8.901-8.709
+                       
c-2.542-3.31-3.61-7.79-6.205-10.957c-2.596-3.168-6.088-5.173-9.129-7.756c2.673,5.742,7.066,12.785,8.02,17.229
+                       
c0.953,4.444-1.069,7.164-2.646,9.563c-1.578,2.399-4.124,2.934-6.539,4.408c-2.415,1.475-6.171,0.312-7.61,2.501
+                       
c-1.438,2.188-1.824,5.48-0.449,7.648l5.64,8.902c-2.078-1.049-5.658-4.1-7.272-6.264s-4.09-4.163-4.429-7.089
+                       
c-0.339-2.925-0.504-5.464,1.391-8.07c1.896-2.605,7.086-3.477,9.409-5.48c2.323-2.003,3.626-3.307,3.493-5.896
+                       
c-0.132-2.589-2.661-4.441-4.835-6.073c-6.637-4.978-15.151-9.565-20.787-15.565c-3.184-3.39-4.712-6.127-5.352-8.466
+                       
c-0.639-2.338,0.037-4.162,1.619-7.038c1.582-2.877,7.007-6.718,7.667-9.843c0.659-3.124-2.081-3.795-4.554-4.897
+                       
s-7.17,0.565-9.464-1.352c-2.293-1.917,0.674-5.945-1.911-8.154c-2.584-2.209-8.499-0.976-11.552-3.352
+                       
c-3.053-2.377-4.315-5.327-5.367-8.775s-1.171-7.225-0.458-9.722s2.855-2.934,4.147-4.228s2.413-2.367,0.691-4.297
+                       
c-1.722-1.929-7.365,0.108-10.609-2.369c-3.244-2.477-1.258-8.41-3.552-10.911c-2.293-2.501-6.409-1.522-8.581-2.321
+                       
c-2.171-0.799-3.023,2.02-4.355-2.438c-1.332-4.459-1.368-17.75-3.16-22.71s-5.311-0.335-6.945-5.265
+                       
c-1.634-4.929-0.085-12.812-0.821-20.257l-3.335-20.257c-11.634,7.815-19.314,10.269-31.813,12.477
+                       
c-1.043,30.582-3.916,48.591,6.464,82.52c10.38,33.928,31.387,53.924,59.726,82.649c-37.395-28.016-55.248-50.792-66.422-79.97
+                       C109.723,356.876,111.869,332.472,112.993,304.372z" />
+
+               <linearGradient id="grad1">
+                       <stop offset="0" 
style="stop-color:#ff6f00;stop-opacity:0.9059;" id="stop650"/>
+                       <stop offset="1.000000" 
style="stop-color:#ffff00;stop-opacity:0.6235;" id="stop649"/>
+               </linearGradient>
+
+               <linearGradient id="grad2" xlink:href="#grad1" x1="0.519995" 
y1="6.250001e-2" x2="0.520000" y2="0.945313"/>
+
+               <path id="arc" d="M0,0 a150 150 0 0 0 300 0" />
+       </defs>
+
+       <g>
+<!--           <rect x="0" y="0" width="372" height="372" fill="yellow" 
stroke="#000000" stroke-width="1" />-->
+
+               <g transform="translate(-28,-20)">
+               <g transform="translate(43,35) scale(1.7,1.7)">
+                       <circle cx="100" cy="100" r="100" fill="url(#grad2)" 
stroke="#510000" stroke-width="10" />
+                       <circle cx="100" cy="100" r="105" fill="none" 
stroke="#000000" stroke-width="1.5"  />
+                       <use xlink:href="#gnu" style="stroke:none; fill:black;" 
transform="translate(31,30) scale(0.25,0.25) " />
+               </g>
+
+               <g transform="translate(63,207)">
+<!--                   <use xlink:href="#arc" style="stroke:#ff0000; fill: 
none; stroke-width:1;" />-->
+       
+                       <text style="stroke-width:1.5; stroke:#000000; 
font-family:'Verdana'; font-size:60; font-weight:900; fill:#ff6f00; 
text-anchor:middle"
+                               letter-spacing="13">
+                               <textPath xlink:href="#arc" 
startOffset="50%">Freeway</textPath>
+                       </text>
+               </g>
+               </g>
+       </g>
+</svg>

Added: freeway/res/swing/images/splash.svg
===================================================================
--- freeway/res/swing/images/splash.svg 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/images/splash.svg 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
+  "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd";>
+
+<svg width="517" height="510" viewBox="0 0 517 510"
+       xmlns="http://www.w3.org/2000/svg";
+       xmlns:xlink="http://www.w3.org/1999/xlink";>
+
+       <defs>
+               <path id="gnu" 
d="M112.993,304.372c-3.634,0.247-8.365,1.875-11.539,7.564
+                       
c-2.591,4.646-8.661,5.387-11.495,4.451c-4.721-1.56-10.755-2.642-16.6,1.523c-5.845,4.164-12.157,1.015-11.05-6.576
+                       
c1.107-7.59,3.849-14.351,11.127-18.538c15.895-9.144,4.848-15.508,13.572-24.685c8.741-9.195,6.81-12.009,6.52-24.497
+                       
c-29.543-4.438-46.287-12.953-64.984-36.313c-18.697-23.361-25.945-42.59-27.883-71.878c-1.938-29.288-0.258-48.269,12.396-72.58
+                       
s25.977-36.014,49.065-48.153C85.21,2.553,107.832-0.354,128.742,0c20.91,0.353,34.843,1.885,46.658,8.626
+                       
c11.814,6.741,22.622,15.224,29.512,15.285c6.891,0.061,11.582-1.744,14.931-4.31c0.894,22.703-19.539,24.675-37.819,25.155
+                       
c-18.281,0.479-29.514-7.083-46.351-4.27S91.269,50.961,77.84,74.336s-13.887,31.638-12.771,51.24
+                       
c1.116,19.603,17.988,34.228,27.512,34.387c9.523,0.159,11.649-2.599,19.985-8.036c8.337-5.438,50.896-58.122,65.418-69.956
+                       
c14.523-11.834,28.854-15.488,44.328-15.678c15.474-0.19,19.428,0.335,31.908,5.45c12.48,5.114,20.149,14.533,30.211,20.291
+                       
c5.143-3.027,8.338-7.547,13.057-10.996c16.877-12.335,25.646-15.659,45.705-13.707c11.529,1.122,26.066,7.708,34.74,15.25
+                       
c15.445,13.429,28.205,32.125,38.516,46.328c8.029,11.061,17.477,24.295,30.965,28.432c14.727,4.515,25.809-14.559,27.436-25.139
+                       
c0.922-5.995,2.125-11.249,2.135-17.847c0.01-6.599-0.664-14.607-2.566-21.484s-5.16-13.72-8.688-19.394
+                       
c-5.742-9.235-15.137-18.899-24.912-23.871c-5.486-2.79-18.393-7.863-26.529-8.041c-9.969-0.216-17.564,3.133-26.781,3.761
+                       
c-11.156,0.761-31.084,3.269-39.83-5.35c-5.566-5.485-6.266-9.144-7.217-16.296c2.459,2.026,5.898,3.358,8.959,3.617
+                       
c6.986,0.59,13.527-5.114,19.166-8.419c4.645-2.723,11.223-7.589,17.324-10.048c15.676-6.32,34.932-6.138,51.48-4.445
+                       
c13.264,1.356,30.461,7.257,42.094,13.84c11.688,6.612,22.951,17.761,31.201,28.271c10.379,13.224,16.053,24.57,19.812,41.063
+                       
c4.805,21.062,6.137,52.702,0.328,73.469c-4.578,16.365-19.779,41.504-32.719,53.827c-12.762,12.155-27.498,18.022-44.256,21.231
+                       
c0.656,3.382,0.764,6.536,1.631,9.309c1.232,3.936,3.588,8.324,8.428,6.936c1.93-0.553,2.963-1.032,5.508,1.194
+                       
c2.543,2.226,1.219,10.825-5.938,14.684c-3.629,1.957-7.459,2.382-13.271,2.498s-14.883,0.141-21.193-0.964
+                       
c-6.309-1.104-10.078-6.111-17.066-6.895c-10.799-1.208-19.068-9.01-27.727-14.59c-3.613-2.329-4.832-2.353-6.914-3.53
+                       
c1.125,3.444,2.625,7.021,3.373,10.332c0.75,3.311,0.43,6.378,0.828,9.028c0.396,2.648,1.131,4.707,1.559,6.855
+                       
c1.73,1.547,2.283,3.9,5.189,4.64c2.908,0.739,7.461-0.412,10.436-0.812s4.969-2.021,7.303-1.577
+                       
c2.336,0.443,4.549,2.115,6.506,3.682s3.639,1.796,5.223,5.706s3.037,11.917,3.254,17.269s-0.383,10.183-1.969,14.43
+                       
s-2.98,6.13-7.275,10.336c-4.295,4.207-11.289,10.38-18.268,14.68c1.285,1.903,1.855,3.645,3.859,5.71
+                       
c2.004,2.066,6.182,4.381,8.041,6.56c1.857,2.179,2.799,3.742,2.826,6.186c0.029,2.443-0.09,5.619-2.074,8.283
+                       
c-4.941,6.633-10.785,7.821-17.891,10.941c1.195,7.462,2.17,12.793,0.443,20.244c-0.705,3.036-2.271,9.92-6.016,11.686
+                       
c-3.746,1.766-10.969,0.911-15.541,1.637c-4.572,0.727-7.131,1.417-10.695,2.125c-2.166,3.131-5.391,6.586-6.496,9.392
+                       
c-1.107,2.807-0.773,3.813,0.156,6.679s4.092,7.039,4.988,10.395s1.07,6.969,0.234,10.334c-0.838,3.365-2.271,5.807-5.139,8.795
+                       
c-2.867,2.989-8.508,5.336-11.318,7.758c-2.812,2.423-5.611,2.714-4.844,6.723c1.055,5.506,9.1,14.436,14.92,16.562
+                       
c3.488,1.275,8.17,0.873,12.406-0.915c-0.287,4.703-4.357,7.873-7.016,10.996c7.201-2.059,14.184-6.001,19.014-11.226
+                       
c-1.498,4.538-6.652,11.823-14.361,18.22c-7.709,6.397-7.662,5.088-11.494,7.633c6.992,1.405,13.494,1.025,18.91,0.052
+                       
c-2.969,1.637-7.836,3.939-14.283,4.616c-6.447,0.676-10.422,0.198-16.232-1.213c-5.811-1.412-11.115-6.694-18.156-10.335
+                       
c0.686,2.612,1.174,5.753,4.135,8.439c2.961,2.686,7.441,4.052,12.203,6.375c-6.062-0.688-12.432-0.896-18.389-2.209
+                       
c-4.41-0.973-7.373-2.005-10.6-3.603c-3.225-1.598-5.715-3.929-8.572-5.893c1.369,2.615,1.775,5.691,4.105,7.847
+                       
s6.117,2.959,9.18,4.44c-3.195-0.07-6.268,0.623-9.58-0.21c-3.314-0.833-6.422-2.142-9.867-4.68s-6.998-5.663-9.938-8.858
+                       
c-2.938-3.195-6.566-7.337-7.664-10.283c-1.1-2.947,0.66-5.008,0.99-7.509c-2.029,1.333-4.525,2.067-6.084,4.002
+                       
s-2.941,3.702-2.251,7.075c0.691,3.373,3.804,7.496,6.005,11.248c-6.568-5.371-10.236-7.439-11.799-13.918
+                       
c-1.463-6.066,2.322-11.572,5.199-16.159c1.429-2.278,3.567-4.398,4.903-6.597c-2.967-2.903-6.358-5.398-8.901-8.709
+                       
c-2.542-3.31-3.61-7.79-6.205-10.957c-2.596-3.168-6.088-5.173-9.129-7.756c2.673,5.742,7.066,12.785,8.02,17.229
+                       
c0.953,4.444-1.069,7.164-2.646,9.563c-1.578,2.399-4.124,2.934-6.539,4.408c-2.415,1.475-6.171,0.312-7.61,2.501
+                       
c-1.438,2.188-1.824,5.48-0.449,7.648l5.64,8.902c-2.078-1.049-5.658-4.1-7.272-6.264s-4.09-4.163-4.429-7.089
+                       
c-0.339-2.925-0.504-5.464,1.391-8.07c1.896-2.605,7.086-3.477,9.409-5.48c2.323-2.003,3.626-3.307,3.493-5.896
+                       
c-0.132-2.589-2.661-4.441-4.835-6.073c-6.637-4.978-15.151-9.565-20.787-15.565c-3.184-3.39-4.712-6.127-5.352-8.466
+                       
c-0.639-2.338,0.037-4.162,1.619-7.038c1.582-2.877,7.007-6.718,7.667-9.843c0.659-3.124-2.081-3.795-4.554-4.897
+                       
s-7.17,0.565-9.464-1.352c-2.293-1.917,0.674-5.945-1.911-8.154c-2.584-2.209-8.499-0.976-11.552-3.352
+                       
c-3.053-2.377-4.315-5.327-5.367-8.775s-1.171-7.225-0.458-9.722s2.855-2.934,4.147-4.228s2.413-2.367,0.691-4.297
+                       
c-1.722-1.929-7.365,0.108-10.609-2.369c-3.244-2.477-1.258-8.41-3.552-10.911c-2.293-2.501-6.409-1.522-8.581-2.321
+                       
c-2.171-0.799-3.023,2.02-4.355-2.438c-1.332-4.459-1.368-17.75-3.16-22.71s-5.311-0.335-6.945-5.265
+                       
c-1.634-4.929-0.085-12.812-0.821-20.257l-3.335-20.257c-11.634,7.815-19.314,10.269-31.813,12.477
+                       
c-1.043,30.582-3.916,48.591,6.464,82.52c10.38,33.928,31.387,53.924,59.726,82.649c-37.395-28.016-55.248-50.792-66.422-79.97
+                       C109.723,356.876,111.869,332.472,112.993,304.372z" />
+
+               <linearGradient id="grad1">
+                       <stop offset="0" 
style="stop-color:#ff6f00;stop-opacity:0.9059;" id="stop650"/>
+                       <stop offset="1.000000" 
style="stop-color:#ffff00;stop-opacity:0.6235;" id="stop649"/>
+               </linearGradient>
+
+               <linearGradient id="grad2" xlink:href="#grad1" x1="0.519995" 
y1="6.250001e-2" x2="0.520000" y2="0.945313"/>
+
+               <path id="arc" d="M0,0 a150 150 0 0 0 300 0" />
+       </defs>
+
+       <rect x="0" y="0" width="517" height="510" fill="#dddddd" 
stroke="#000000" stroke-width="5"/>
+
+       <g>
+               <g transform="translate(45,-10)">
+                       <g transform="translate(43,35) scale(1.7,1.7)">
+                               <circle cx="100" cy="100" r="100" 
fill="url(#grad2)" stroke="#510000" stroke-width="10" />
+                               <circle cx="100" cy="100" r="105" fill="none" 
stroke="#000000" stroke-width="1.5"  />
+                               <use xlink:href="#gnu" style="stroke:none; 
fill:black;" transform="translate(31,30) scale(0.25,0.25) " />
+                       </g>
+       
+                       <g transform="translate(63,207)">
+                               <text style="stroke-width:1.5; stroke:#000000; 
font-family:'Verdana'; font-size:60; font-weight:900; fill:#ff6f00; 
text-anchor:middle"
+                                       letter-spacing="13">
+                                       <textPath xlink:href="#arc" 
startOffset="50%">Freeway</textPath>
+                               </text>
+                       </g>
+               </g>
+       </g>
+
+       <text x="65" y="423" style="font-family: Arial; font-size: 36; 
font-style: italic; font-weight: bold;">A Java port of GNUnet</text>
+       <text x="70" y="463" style="font-family: Arial; font-size: 26; 
font-style: italic;">Freeway v0.6 - GNUnet v0.6.1b</text>
+
+       <rect x="0" y="500" width="517" height="10" fill="#42adff" 
stroke="#000000" stroke-width="5"/>
+       <rect x="0" y="490" width="517" height="10" fill="#215788" 
stroke="#000000" stroke-width="5"/>
+</svg>
+

Added: freeway/res/swing/images/start.svg
===================================================================
--- freeway/res/swing/images/start.svg  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/images/start.svg  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" 
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd";>
+
+<svg width="512" height="512" viewBox="-65 -65 130 130"
+       xmlns="http://www.w3.org/2000/svg";
+       xmlns:xlink="http://www.w3.org/1999/xlink";>
+
+       <defs>
+               <polygon id="triangle" points="-28,-50 52,0 -28,50" 
stroke-width="10" stroke-linejoin="round" />
+       </defs>
+
+       <g>
+               <use xlink:href="#triangle"
+                       fill="#000000"
+                       stroke="#000000"
+                       />
+
+               <use xlink:href="#triangle"
+                       fill="#42adff"
+                       stroke="#215788"
+                       transform="scale(0.7 0.7)" />
+       </g>
+</svg>

Added: freeway/res/swing/images/stop.svg
===================================================================
--- freeway/res/swing/images/stop.svg   2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/images/stop.svg   2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" 
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd";>
+
+<svg width="512" height="512" viewBox="-65 -65 130 130"
+       xmlns="http://www.w3.org/2000/svg";
+       xmlns:xlink="http://www.w3.org/1999/xlink";>
+
+       <defs>
+               <polygon id="rect" points="-40,-40 -40,40 40,40 40,-40" 
stroke-width="10" stroke-linejoin="round" />
+       </defs>
+
+       <g>
+               <use xlink:href="#rect"
+                       fill="#000000"
+                       stroke="#000000"
+                       />
+
+               <use xlink:href="#rect"
+                       fill="#42adff"
+                       stroke="#215788"
+                       transform="scale(0.8 0.8)" />
+       </g>
+</svg>

Added: freeway/res/swing/images/watermark.svg
===================================================================
--- freeway/res/swing/images/watermark.svg      2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/res/swing/images/watermark.svg      2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
+  "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd";>
+
+<svg width="372" height="372" viewBox="0 0 372 372"
+       xmlns="http://www.w3.org/2000/svg";
+       xmlns:xlink="http://www.w3.org/1999/xlink";>
+
+       <defs>
+               <path id="gnu" 
d="M112.993,304.372c-3.634,0.247-8.365,1.875-11.539,7.564
+                       
c-2.591,4.646-8.661,5.387-11.495,4.451c-4.721-1.56-10.755-2.642-16.6,1.523c-5.845,4.164-12.157,1.015-11.05-6.576
+                       
c1.107-7.59,3.849-14.351,11.127-18.538c15.895-9.144,4.848-15.508,13.572-24.685c8.741-9.195,6.81-12.009,6.52-24.497
+                       
c-29.543-4.438-46.287-12.953-64.984-36.313c-18.697-23.361-25.945-42.59-27.883-71.878c-1.938-29.288-0.258-48.269,12.396-72.58
+                       
s25.977-36.014,49.065-48.153C85.21,2.553,107.832-0.354,128.742,0c20.91,0.353,34.843,1.885,46.658,8.626
+                       
c11.814,6.741,22.622,15.224,29.512,15.285c6.891,0.061,11.582-1.744,14.931-4.31c0.894,22.703-19.539,24.675-37.819,25.155
+                       
c-18.281,0.479-29.514-7.083-46.351-4.27S91.269,50.961,77.84,74.336s-13.887,31.638-12.771,51.24
+                       
c1.116,19.603,17.988,34.228,27.512,34.387c9.523,0.159,11.649-2.599,19.985-8.036c8.337-5.438,50.896-58.122,65.418-69.956
+                       
c14.523-11.834,28.854-15.488,44.328-15.678c15.474-0.19,19.428,0.335,31.908,5.45c12.48,5.114,20.149,14.533,30.211,20.291
+                       
c5.143-3.027,8.338-7.547,13.057-10.996c16.877-12.335,25.646-15.659,45.705-13.707c11.529,1.122,26.066,7.708,34.74,15.25
+                       
c15.445,13.429,28.205,32.125,38.516,46.328c8.029,11.061,17.477,24.295,30.965,28.432c14.727,4.515,25.809-14.559,27.436-25.139
+                       
c0.922-5.995,2.125-11.249,2.135-17.847c0.01-6.599-0.664-14.607-2.566-21.484s-5.16-13.72-8.688-19.394
+                       
c-5.742-9.235-15.137-18.899-24.912-23.871c-5.486-2.79-18.393-7.863-26.529-8.041c-9.969-0.216-17.564,3.133-26.781,3.761
+                       
c-11.156,0.761-31.084,3.269-39.83-5.35c-5.566-5.485-6.266-9.144-7.217-16.296c2.459,2.026,5.898,3.358,8.959,3.617
+                       
c6.986,0.59,13.527-5.114,19.166-8.419c4.645-2.723,11.223-7.589,17.324-10.048c15.676-6.32,34.932-6.138,51.48-4.445
+                       
c13.264,1.356,30.461,7.257,42.094,13.84c11.688,6.612,22.951,17.761,31.201,28.271c10.379,13.224,16.053,24.57,19.812,41.063
+                       
c4.805,21.062,6.137,52.702,0.328,73.469c-4.578,16.365-19.779,41.504-32.719,53.827c-12.762,12.155-27.498,18.022-44.256,21.231
+                       
c0.656,3.382,0.764,6.536,1.631,9.309c1.232,3.936,3.588,8.324,8.428,6.936c1.93-0.553,2.963-1.032,5.508,1.194
+                       
c2.543,2.226,1.219,10.825-5.938,14.684c-3.629,1.957-7.459,2.382-13.271,2.498s-14.883,0.141-21.193-0.964
+                       
c-6.309-1.104-10.078-6.111-17.066-6.895c-10.799-1.208-19.068-9.01-27.727-14.59c-3.613-2.329-4.832-2.353-6.914-3.53
+                       
c1.125,3.444,2.625,7.021,3.373,10.332c0.75,3.311,0.43,6.378,0.828,9.028c0.396,2.648,1.131,4.707,1.559,6.855
+                       
c1.73,1.547,2.283,3.9,5.189,4.64c2.908,0.739,7.461-0.412,10.436-0.812s4.969-2.021,7.303-1.577
+                       
c2.336,0.443,4.549,2.115,6.506,3.682s3.639,1.796,5.223,5.706s3.037,11.917,3.254,17.269s-0.383,10.183-1.969,14.43
+                       
s-2.98,6.13-7.275,10.336c-4.295,4.207-11.289,10.38-18.268,14.68c1.285,1.903,1.855,3.645,3.859,5.71
+                       
c2.004,2.066,6.182,4.381,8.041,6.56c1.857,2.179,2.799,3.742,2.826,6.186c0.029,2.443-0.09,5.619-2.074,8.283
+                       
c-4.941,6.633-10.785,7.821-17.891,10.941c1.195,7.462,2.17,12.793,0.443,20.244c-0.705,3.036-2.271,9.92-6.016,11.686
+                       
c-3.746,1.766-10.969,0.911-15.541,1.637c-4.572,0.727-7.131,1.417-10.695,2.125c-2.166,3.131-5.391,6.586-6.496,9.392
+                       
c-1.107,2.807-0.773,3.813,0.156,6.679s4.092,7.039,4.988,10.395s1.07,6.969,0.234,10.334c-0.838,3.365-2.271,5.807-5.139,8.795
+                       
c-2.867,2.989-8.508,5.336-11.318,7.758c-2.812,2.423-5.611,2.714-4.844,6.723c1.055,5.506,9.1,14.436,14.92,16.562
+                       
c3.488,1.275,8.17,0.873,12.406-0.915c-0.287,4.703-4.357,7.873-7.016,10.996c7.201-2.059,14.184-6.001,19.014-11.226
+                       
c-1.498,4.538-6.652,11.823-14.361,18.22c-7.709,6.397-7.662,5.088-11.494,7.633c6.992,1.405,13.494,1.025,18.91,0.052
+                       
c-2.969,1.637-7.836,3.939-14.283,4.616c-6.447,0.676-10.422,0.198-16.232-1.213c-5.811-1.412-11.115-6.694-18.156-10.335
+                       
c0.686,2.612,1.174,5.753,4.135,8.439c2.961,2.686,7.441,4.052,12.203,6.375c-6.062-0.688-12.432-0.896-18.389-2.209
+                       
c-4.41-0.973-7.373-2.005-10.6-3.603c-3.225-1.598-5.715-3.929-8.572-5.893c1.369,2.615,1.775,5.691,4.105,7.847
+                       
s6.117,2.959,9.18,4.44c-3.195-0.07-6.268,0.623-9.58-0.21c-3.314-0.833-6.422-2.142-9.867-4.68s-6.998-5.663-9.938-8.858
+                       
c-2.938-3.195-6.566-7.337-7.664-10.283c-1.1-2.947,0.66-5.008,0.99-7.509c-2.029,1.333-4.525,2.067-6.084,4.002
+                       
s-2.941,3.702-2.251,7.075c0.691,3.373,3.804,7.496,6.005,11.248c-6.568-5.371-10.236-7.439-11.799-13.918
+                       
c-1.463-6.066,2.322-11.572,5.199-16.159c1.429-2.278,3.567-4.398,4.903-6.597c-2.967-2.903-6.358-5.398-8.901-8.709
+                       
c-2.542-3.31-3.61-7.79-6.205-10.957c-2.596-3.168-6.088-5.173-9.129-7.756c2.673,5.742,7.066,12.785,8.02,17.229
+                       
c0.953,4.444-1.069,7.164-2.646,9.563c-1.578,2.399-4.124,2.934-6.539,4.408c-2.415,1.475-6.171,0.312-7.61,2.501
+                       
c-1.438,2.188-1.824,5.48-0.449,7.648l5.64,8.902c-2.078-1.049-5.658-4.1-7.272-6.264s-4.09-4.163-4.429-7.089
+                       
c-0.339-2.925-0.504-5.464,1.391-8.07c1.896-2.605,7.086-3.477,9.409-5.48c2.323-2.003,3.626-3.307,3.493-5.896
+                       
c-0.132-2.589-2.661-4.441-4.835-6.073c-6.637-4.978-15.151-9.565-20.787-15.565c-3.184-3.39-4.712-6.127-5.352-8.466
+                       
c-0.639-2.338,0.037-4.162,1.619-7.038c1.582-2.877,7.007-6.718,7.667-9.843c0.659-3.124-2.081-3.795-4.554-4.897
+                       
s-7.17,0.565-9.464-1.352c-2.293-1.917,0.674-5.945-1.911-8.154c-2.584-2.209-8.499-0.976-11.552-3.352
+                       
c-3.053-2.377-4.315-5.327-5.367-8.775s-1.171-7.225-0.458-9.722s2.855-2.934,4.147-4.228s2.413-2.367,0.691-4.297
+                       
c-1.722-1.929-7.365,0.108-10.609-2.369c-3.244-2.477-1.258-8.41-3.552-10.911c-2.293-2.501-6.409-1.522-8.581-2.321
+                       
c-2.171-0.799-3.023,2.02-4.355-2.438c-1.332-4.459-1.368-17.75-3.16-22.71s-5.311-0.335-6.945-5.265
+                       
c-1.634-4.929-0.085-12.812-0.821-20.257l-3.335-20.257c-11.634,7.815-19.314,10.269-31.813,12.477
+                       
c-1.043,30.582-3.916,48.591,6.464,82.52c10.38,33.928,31.387,53.924,59.726,82.649c-37.395-28.016-55.248-50.792-66.422-79.97
+                       C109.723,356.876,111.869,332.472,112.993,304.372z" />
+
+               <linearGradient id="grad1">
+                       <stop offset="0" 
style="stop-color:#ff6f00;stop-opacity:0.9059;" id="stop650"/>
+                       <stop offset="1.000000" 
style="stop-color:#ffff00;stop-opacity:0.6235;" id="stop649"/>
+               </linearGradient>
+
+               <linearGradient id="grad2" xlink:href="#grad1" x1="0.519995" 
y1="6.250001e-2" x2="0.520000" y2="0.945313"/>
+
+               <path id="arc" d="M0,0 a150 150 0 0 0 300 0" />
+       </defs>
+
+       <g opacity="0.33">
+<!--           <rect x="0" y="0" width="372" height="372" fill="yellow" 
stroke="#000000" stroke-width="1" />-->
+
+               <g transform="translate(-28,-20)">
+               <g transform="translate(43,35) scale(1.7,1.7)">
+                       <circle cx="100" cy="100" r="100" fill="url(#grad2)" 
stroke="#510000" stroke-width="10" />
+                       <circle cx="100" cy="100" r="105" fill="none" 
stroke="#000000" stroke-width="1.5"  />
+                       <use xlink:href="#gnu" style="stroke:none; fill:black;" 
transform="translate(31,30) scale(0.25,0.25) " />
+               </g>
+
+               <g transform="translate(63,207)">
+<!--                   <use xlink:href="#arc" style="stroke:#ff0000; fill: 
none; stroke-width:1;" />-->
+       
+                       <text style="stroke-width:1.5; stroke:#000000; 
font-family:'Verdana'; font-size:60; font-weight:900; fill:#ff6f00; 
text-anchor:middle"
+                               letter-spacing="13">
+                               <textPath xlink:href="#arc" 
startOffset="50%">Freeway</textPath>
+                       </text>
+               </g>
+               </g>
+       </g>
+</svg>

Added: freeway/res/swing/insert.xml
===================================================================
--- freeway/res/swing/insert.xml        2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/insert.xml        2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <images locale="enUS">
+               <image id="application.icon" 
src="images/128x128/logo.png?bg=ffffff" />
+               <image id="application.medium.icon" 
src="images/64x64/logo.png?bg=ffffff" />
+
+               <image id="dot.icon" src="images/13x13/start.png?bg=ffffff" />
+       </images>
+
+       <actions locale="enUS">
+               <action id="quit.action" method="onQuit">
+                       <label>Quit</label>
+               </action>
+       </actions>
+</ressources>

Added: freeway/res/swing/main.xml
===================================================================
--- freeway/res/swing/main.xml  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/main.xml  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <images locale="enUS">
+               <image id="splash" src="images/258x255/splash.png" />
+               <image id="app.minilogo" src="images/64x64/logo.png?bg=ffffff" 
/>
+       </images>
+</ressources>

Added: freeway/res/swing/search-panel.xml
===================================================================
--- freeway/res/swing/search-panel.xml  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/search-panel.xml  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <actions locale="enUS">
+               <action id="popup.selectall" method="onSelectAll">
+                       <label>Select all</label>
+               </action>
+
+               <action id="popup.unselectall" method="onClearSelection">
+                       <label>Unselect all</label>
+               </action>
+
+               <action id="popup.searchSelectByName" method="onSelectByName">
+                       <label>Select by filename</label>
+               </action>
+
+               <action id="popup.searchSelectByDesc" 
method="onSelectByDescription">
+                       <label>Select by description</label>
+               </action>
+
+               <action id="popup.searchSelectByMime" method="onSelectByMime">
+                       <label>Select by mimetype</label>
+               </action>
+
+               <action id="popup.searchDownloadSelected" method="onDownload">
+                       <label>Download selected</label>
+               </action>
+
+               <action id="popup.searchClose" method="onAbortSearch">
+                       <label>Abort search</label>
+               </action>
+
+               <action id="download.id" method="onDownload">
+                       <label>Download</label>
+               </action>
+       </actions>
+
+       <menus locale="enUS">
+               <menu id="popup.menu">
+                       <label>Selection</label>
+
+                       <action refid="popup.selectall" />
+                       <action refid="popup.unselectall" />
+                       <separator />
+                       <action refid="popup.searchSelectByName" />
+                       <action refid="popup.searchSelectByDesc" />
+                       <action refid="popup.searchSelectByMime" />
+                       <separator />
+                       <action refid="popup.searchDownloadSelected" />
+                       <action refid="popup.searchClose" />
+               </menu>
+       </menus>
+</ressources>

Added: freeway/res/swing/search-window.xml
===================================================================
--- freeway/res/swing/search-window.xml 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/search-window.xml 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,271 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <images locale="enUS">
+               <image id="splash" src="images/284x166/logo.png?bg=ffffff" />
+       </images>
+
+       <actions locale="enUS">
+               <action id="file.insert" method="openSelectFile">
+                       <label>Insert</label>
+                       <accelerator>I</accelerator>
+                       <shortcut>meta I</shortcut>
+               </action>
+
+               <action id="file.download.uri" method="fetchURI">
+                       <label>Download URI</label>
+                       <accelerator>D</accelerator>
+                       <shortcut>meta D</shortcut>
+               </action>
+
+               <action id="file.import.directory" method="importDirectory">
+                       <label>Import directory</label>
+                       <accelerator>r</accelerator>
+                       <shortcut>meta R</shortcut>
+               </action>
+
+               <action id="file.unindex.file" method="openDeleteFile">
+                       <label>Unindex file</label>
+                       <accelerator>U</accelerator>
+                       <shortcut>meta U</shortcut>
+               </action>
+
+               <action id="file.show.downloads" method="show_dlwindow">
+                       <label>Show downloads</label>
+                       <shortcut>meta W</shortcut>
+               </action>
+
+               <action id="file.show.messages" method="show_infowindow">
+                       <label>Show messages</label>
+                       <shortcut>meta M</shortcut>
+               </action>
+
+               <action id="file.show.stats" method="showStats">
+                       <label>Show statistics</label>
+                       <shortcut>meta 2</shortcut>
+               </action>
+
+               <action id="file.quit" method="destroy_stub">
+                       <label>Quit</label>
+                       <accelerator>Q</accelerator>
+                       <shortcut>meta Q</shortcut>
+               </action>
+
+               <action id="advanced.assemble.directory.from.sr" 
method="openAssembleDirectoryDialogDIR_CONTEXT_SEARCH">
+                       <label>from search results</label>
+                       <accelerator>s</accelerator>
+               </action>
+
+               <action id="advanced.assemble.directory.from.if" 
method="openAssembleDirectoryDialogDIR_CONTEXT_INSERT">
+                       <label>from inserted files</label>
+                       <accelerator>i</accelerator>
+               </action>
+
+               <action id="advanced.assemble.directory.from.lns" 
method="openAssembleDirectoryDialogDIR_CONTEXT_INSERT_SB">
+                       <label>from local namespaces</label>
+                       <accelerator>n</accelerator>
+               </action>
+
+               <action id="advanced.assemble.directory.from.fid" 
method="openAssembleDirectoryDialogDIR_CONTEXT_DIRECTORY">
+                       <label>from file identifiers from downloaded 
directories</label>
+                       <accelerator>d</accelerator>
+               </action>
+
+               <action id="advanced.assemble.directory.from.all" 
method="openAssembleDirectoryDialogDIR_CONTEXT_ALL">
+                       <label>from all known file identifiers</label>
+                       <accelerator>a</accelerator>
+               </action>
+
+               <action id="advanced.manage.pseudonyms.create" 
method="onCreatePseudonym">
+                       <label>Create new pseudonym</label>
+                       <accelerator>C</accelerator>
+                       <shortcut>meta P</shortcut>
+               </action>
+
+               <action id="advanced.manage.pseudonyms.delete" 
method="onDeletePseudonym">
+                       <label>Delete pseudonym</label>
+                       <accelerator>D</accelerator>
+               </action>
+
+               <action id="advanced.insert_into_namespace.select_sr" 
method="openAssembleNamespaceDialogDIR_CONTEXT_SEARCH">
+                       <label>Select from search results</label>
+                       <accelerator>s</accelerator>
+               </action>
+
+               <action id="advanced.insert_into_namespace.select_if" 
method="openAssembleNamespaceDialogDIR_CONTEXT_INSERT">
+                       <label>Select from inserted files</label>
+                       <accelerator>i</accelerator>
+               </action>
+
+               <action id="advanced.insert_into_namespace.select_dd" 
method="openAssembleNamespaceDialogDIR_CONTEXT_INSERT">
+                       <label>Select from results from downloaded 
directories</label>
+                       <accelerator>d</accelerator>
+               </action>
+
+               <action id="advanced.insert_into_namespace.select_lns" 
method="openAssembleNamespaceDialogDIR_CONTEXT_INSERT_SB">
+                       <label>Select from results from local namespaces</label>
+                       <accelerator>n</accelerator>
+               </action>
+
+               <action id="advanced.insert_into_namespace.select_all" 
method="openAssembleNamespaceDialogDIR_CONTEXT_ALL">
+                       <label>Select from all known file identifiers</label>
+                       <accelerator>a</accelerator>
+               </action>
+
+               <action id="advanced.search.namespace" method="searchNamespace">
+                       <label>Search Namespace</label>
+                       <accelerator>S</accelerator>
+                       <shortcut>meta S</shortcut>
+               </action>
+
+               <action id="advanced.reset_fid.list_sr" 
method="emptyDirectoryDatabaseIndDIR_CONTEXT_SEARCH">
+                       <label>List of search results</label>
+                       <accelerator>s</accelerator>
+               </action>
+
+               <action id="advanced.reset_fid.list_if" 
method="emptyDirectoryDatabaseIndDIR_CONTEXT_INSERT">
+                       <label>List of inserted files</label>
+                       <accelerator>i</accelerator>
+               </action>
+
+               <action id="advanced.reset_fid.list_lns" 
method="emptyDirectoryDatabaseIndDIR_CONTEXT_INSERT_SB">
+                       <label>List of entries in local namespaces</label>
+                       <accelerator>n</accelerator>
+               </action>
+
+               <action id="advanced.reset_fid.list_dd" 
method="emptyDirectoryDatabaseIndDIR_CONTEXT_DIRECTORY">
+                       <label>List of files from downloaded directories</label>
+                       <accelerator>d</accelerator>
+               </action>
+
+               <action id="advanced.reset_fid.all" 
method="emptyDirectoryDatabaseIndDIR_CONTEXT_ALL">
+                       <label>All known file identifiers</label>
+                       <accelerator>A</accelerator>
+               </action>
+
+               <action id="advanced.launch.gnunetd" method="onLaunchDaemon">
+                       <label>Launch daemon</label>
+               </action>
+
+               <action id="advanced.kill.gnunetd" method="onKillDaemon">
+                       <label>Stop daemon</label>
+               </action>
+
+               <action id="advanced.daemon.window" method="onDaemonWindow">
+                       <label>Show daemon window</label>
+                       <shortcut>meta 1</shortcut>
+               </action>
+
+               <action id="help.about" method="about">
+                       <label>About</label>
+                       <accelerator>A</accelerator>
+                       <icon>images/16x16/help.gif</icon>
+                       <description>Display an about dialog</description>
+               </action>
+
+               <action id="download.show.id" method="onShowDownload">
+                       <label>Download window</label>
+                       <shortcut>meta 3</shortcut>
+               </action>
+
+       </actions>
+
+       <menus locale="enUS">
+               <menu id="window-menu">
+                       <menu>
+                               <label>File</label>
+                               <accelerator>F</accelerator>
+       
+                               <action refid="file.insert" />
+                               <action refid="file.download.uri" />
+                               <action refid="file.import.directory" />
+                               <separator />
+                               <action refid="file.unindex.file" />
+                               <separator />
+                               <action refid="file.show.downloads" />
+                               <action refid="file.show.messages" />
+                               <separator />
+                               <action refid="file.quit" />
+                       </menu>
+       
+                       <menu>
+                               <label>Advanced</label>
+                               <accelerator>A</accelerator>
+       
+                               <menu>
+                                       <label>Assemble Directory</label>
+                                       <accelerator>A</accelerator>
+       
+                                       <action 
refid="advanced.assemble.directory.from.sr" />
+                                       <action 
refid="advanced.assemble.directory.from.if" />
+                                       <action 
refid="advanced.assemble.directory.from.lns" />
+                                       <action 
refid="advanced.assemble.directory.from.fid" />
+                                       <separator />
+                                       <action 
refid="advanced.assemble.directory.from.all" />
+                               </menu>
+                               <separator />
+       
+                               <menu>
+                                       <label>Manage Pseudonyms</label>
+                                       <accelerator>P</accelerator>
+       
+                                       <action 
refid="advanced.manage.pseudonyms.create" />
+                                       <action 
refid="advanced.manage.pseudonyms.delete" />
+                               </menu>
+       
+                               <menu>
+                                       <label>Insert into Namespace</label>
+                                       <accelerator>I</accelerator>
+       
+                                       <action 
refid="advanced.insert_into_namespace.select_sr" />
+                                       <action 
refid="advanced.insert_into_namespace.select_if" />
+                                       <action 
refid="advanced.insert_into_namespace.select_dd" />
+                                       <action 
refid="advanced.insert_into_namespace.select_lns" />
+                                       <separator />
+                                       <action 
refid="advanced.insert_into_namespace.select_all" />
+                               </menu>
+       
+                               <action refid="advanced.search.namespace" />
+                               <separator />
+       
+                               <menu>
+                                       <label>Reset File Identifiers</label>
+                                       <accelerator>R</accelerator>
+       
+                                       <action 
refid="advanced.reset_fid.list_sr" />
+                                       <action 
refid="advanced.reset_fid.list_if" />
+                                       <action 
refid="advanced.reset_fid.list_lns" />
+                                       <action 
refid="advanced.reset_fid.list_dd" />
+                                       <separator />
+                                       <action refid="advanced.reset_fid.all" 
/>
+                               </menu>
+       
+                       </menu>
+
+                       <menu>
+                               <label>Daemon</label>
+
+                               <action refid="advanced.launch.gnunetd" />
+                               <action refid="advanced.kill.gnunetd" />
+<!--                           <separator />
+                               <action refid="advanced.daemon.window" />
+                               <action refid="file.show.stats" />-->
+                       </menu>
+       
+                       <menu>
+                               <label>Windows</label>
+
+                               <action refid="advanced.daemon.window" />
+                               <action refid="file.show.stats" />
+                               <action refid="download.show.id" />
+                       </menu>
+       
+                       <menu>
+                               <label>Help</label>
+                               <accelerator>H</accelerator>
+       
+                               <action refid="help.about" />
+                       </menu>
+               </menu>
+       </menus>
+</ressources>

Added: freeway/res/swing/stats-window.xml
===================================================================
--- freeway/res/swing/stats-window.xml  2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/stats-window.xml  2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <actions locale="enUS">
+               <action id="main.refresh" method="onRefresh">
+                       <label>Refresh</label>
+                       <accelerator>R</accelerator>
+                       <shortcut>meta R</shortcut>
+                       <description>Poll daemon for last 
statistics</description>
+               </action>
+
+               <action id="main.close" method="onClose">
+                       <label>Close</label>
+                       <shortcut>meta W</shortcut>
+                       <description>Close this window</description>
+               </action>
+
+               <action id="help.about" method="about">
+                       <label>About</label>
+                       <accelerator>A</accelerator>
+                       <icon>images/16x16/help.gif</icon>
+                       <description>Display an about dialog</description>
+               </action>
+       </actions>
+
+       <menus locale="enUS">
+               <menu id="window-menu">
+                       <menu>
+                               <label>File</label>
+                               <accelerator>F</accelerator>
+       
+                               <action refid="main.refresh" />
+                               <separator />
+                               <action refid="main.close" />
+                       </menu>
+               </menu>
+
+               <menu id="popup-menu">
+                       <label>Popup</label>
+                       <accelerator>P</accelerator>
+
+                       <action refid="main.refresh" />
+                       <separator />
+                       <action refid="main.close" />
+               </menu>
+       </menus>
+</ressources>

Added: freeway/res/swing/system/wizard.xml
===================================================================
--- freeway/res/swing/system/wizard.xml 2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/swing/system/wizard.xml 2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<ressources>
+       <actions locale="enUS">
+               <action id="next.action" method="onNext">
+                       <label>Next</label>
+               </action>
+
+               <action id="previous.action" method="onPrevious">
+                       <label>Previous</label>
+               </action>
+
+               <action id="exec.action" method="onExec">
+                       <label>Go</label>
+               </action>
+       </actions>
+</ressources>

Added: freeway/res/tests/test-charset
===================================================================
--- freeway/res/tests/test-charset      2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/tests/test-charset      2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,4 @@
+line 1
+àéèû
+ßõöçëœ
+end.
\ No newline at end of file

Added: freeway/res/tests/test-config
===================================================================
--- freeway/res/tests/test-config       2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/tests/test-config       2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,19 @@
+SUBST=hello
+GNUNET_HOME=/tmp
+
+[test]
+a=a
+b=b
+five=5
+
+[more]
+c=c
+five=42
+
+               
+[last]
+test = $SUBST/world
+boom = "1 2 3 testing"
+trailing = YES 
+
address@hidden@ tests/test-config-2

Added: freeway/res/tests/test-config-2
===================================================================
--- freeway/res/tests/test-config-2     2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/res/tests/test-config-2     2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,49 @@
+# This is the configuration for your GNUnet node.
+# Put this file in ~/.gnunet/gnunet.conf and you
+# should be fine.
+# GNUnet installation. Make sure there is some
+# space left in that directory. :-)
+#
+# If you are not installing as root, ~/.gnunet
+# may be a good choice.
+
+#GNUNET_HOME   = ~/.gnunet
+GNUNET_HOME    = 'e:/.gnunet'  #dddd
+# For root, you may want to choose instead:
+# GNUNET_HOME     = /var/lib/GNUnet
+
+TEST   =       test  
+
+[TEST ESC \i\\ FIN] 
+
+[A]                    #dd
+AAA=aaa
+AAAplus        =       'aaa\'bbb'   
+AAAmore=more
+
+############################################
+# Network configuration
+############################################
+   [NETWORK  jjj;]     J=j
+
+# [error 1 !!! # <-- error
+
+
+# On which machine runs gnunetd (for clients)
+# This is equivalent to the -H option.
+HOST = localhost       \
+       ttee    \
+       oeoi\\uiie
+
+HOST2=host
+
+    REPLACE = $HOST2 + $AAA         #\   
+\
+  [error 2 !!!
+
+# Which is the client-server port that is used
+   # between gnunetd and the clients (TCP only).
+# You may firewall this port for non-local
+# machines.
+PORT = 2087
+

Added: freeway/src/org/gnu/freeway/AbstractApplication.java
===================================================================
--- freeway/src/org/gnu/freeway/AbstractApplication.java        2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/AbstractApplication.java        2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,299 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import java.security.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ *
+ */
+
+public abstract class AbstractApplication extends Command implements 
Application
+{
+       static {
+               // setup mac os specific ui properties
+               if 
(System.getProperty("os.name").toLowerCase().indexOf("mac")>=0) {
+                       System.setProperty("apple.laf.useScreenMenuBar","true");
+                       }
+               }
+
+       private boolean                 daemon;
+
+       private Prefs                   preferences;
+       private Statistics              statistics;
+       private ServiceManager  services;
+
+       private List                            before; //todo: toujours utile 
???
+
+
+       protected AbstractApplication( String nm, int v, boolean dm )
+       {
+               super(nm,v);
+               daemon=dm;//todo: encore utile comme distinction ???
+               services=ServiceManager.getInstance(this);
+               preferences=new Prefs();
+               before=new ArrayList();
+               statistics=new Statistics();
+
+               addCritical(new AbstractAction("FLUSH-PREFS") {
+                       public void perform()
+                       {
+                               preferences.flushGlobals();
+                               LoggedObject.flushLogs();
+                       }
+                       });
+       }
+
+       public String toString()
+       {
+               return "Abstract application [name="+getName()+", 
version="+getVersion()+"]";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public Prefs getPreferences()
+       {
+               return preferences;
+       }
+
+       public Statistics getStatistics()
+       {
+               return statistics;
+       }
+
+       public Service service( Class c )
+       {
+               return services.service(c);
+       }
+
+
+
+
+       public DirLocation getHome()
+       {
+               DirLocation     dir;
+               String          str;
+
+               str=(daemon ? "GNUNETD_HOME" : "GNUNET_HOME");
+
+               dir=preferences.getDirLocation("",str);
+               if (dir==null) {
+                       log(Level.SEVERE,"Configuration file must specify a 
directory for GNUnet to store per-peer data under "+str+" ! Uses \"~\"...");
+                       dir=new DirLocation("~");
+                       }
+               return (dir.create() ? dir : null);
+       }
+
+       /**
+        * Re-read the loggig configuration.
+        * Call on SIGHUP if the configuration file has changed.
+        */
+
+       protected void resetLogs()
+       {
+               FileLocation            f;
+               Level                   level;
+               String                  str;
+
+               str=preferences.getString((daemon ? "GNUNETD" : 
"GNUNET"),"LOGLEVEL","WARNING");
+               level=Level.parse(str);
+
+               f=preferences.getFileLocation((daemon ? "GNUNETD" : 
"GNUNET"),"LOGFILE");
+               if (f==null || !LoggedObject.sendLogsToFile(level,f)) {
+                       LoggedObject.sendLogsToConsole(level);
+                       }
+
+               f=preferences.getFileLocation((daemon ? "GNUNETD" : 
"GNUNET"),"LOGLEVELS-FILE");
+               if (f!=null) {
+                       LoggedObject.setUpLogLevels(f);
+                       }
+       }
+
+       public int run1()
+       {
+               Action  resetAction;
+               String  str;
+               int             ret;
+
+               /* init 1: get options and basic services up */
+               preferences.readConfiguration(daemon);
+
+               resetAction=new AbstractAction() {
+                       public void perform()
+                       {
+                               AbstractApplication.this.resetLogs();
+                       }
+                       };
+               resetLogs();
+               preferences.registerConfigurationUpdateCallback(resetAction);
+
+               str=preferences.getString((daemon ? "GNUNETD" : 
"GNUNET"),"CRYPTO_PROVIDER",null);
+               if (str!=null) {
+                       try {
+                               Security.insertProviderAt((Provider) 
Class.forName(str).newInstance(),0);
+                               log(Level.INFO,"Installed cryptographic classes 
("+str+"), hope they provide enough privacy...");
+                               }
+                       catch( Throwable x ) {
+                               err("Could not install cryptographic classes 
("+str+"), exit !",x);
+                               return -4;
+                               }
+                       }
+
+               /* init 3a: start core services */
+               preferences.init(this);
+               services.start();
+               beurk0();
+               ret=run();
+               /* init 5: shutdown in inverse order */
+               services.stop();
+
+               preferences.unregisterConfigurationUpdateCallback(resetAction);
+
+               /* init 6: goodbye */
+               // Shutdown the util services in proper order.
+               services.shutdown();
+
+               beurk2();
+
+               statistics.done();
+               log(Level.INFO,"Shutdown complete.");
+               return ret;
+       }
+
+       public void beurk0()
+       {
+       }
+
+       public void beurk2()
+       {
+       }
+
+       //TODO: a mettre ailleurs !!!
+       //todo: merger HELP_CONFIG avec :
+       //      str=(daemon ? preferences.getSystemDaemonConfiguration() : 
preferences.getSystemClientsConfiguration());
+       //      opts.addOption("config|c|FILENAME","load config 
file"+(str!=null ? " (default: "+str+")" : ""));
+
+       public static final Option      HELP_CONFIG                     =       
new Option("config|c|FILENAME","use configuration FILENAME") {
+               public boolean exec( Command app )
+               {
+                       ((Application) 
app).getPreferences().setString("FILES","gnunet.conf",getValue());
+                       return true;
+               }
+               };
+
+       public static final Option      HELP_HOSTNAME           =       new 
Option("host|H|HOSTNAME","specify host on which daemon is running (default: 
localhost)") {
+               public boolean exec( Command app )
+               {
+                       ((Application) 
app).getPreferences().setString("NETWORK","HOST",getValue());
+                       return true;
+               }
+               };
+
+       public static final Option      HELP_LOGLEVEL           =       new 
Option("loglevel|L|LEVEL","set verbosity to LEVEL") {
+               public boolean exec( Command app )
+               {
+                       ((Application) 
app).getPreferences().setString((((AbstractApplication) app).daemon ? "GNUNETD" 
: "GNUNET"),"LOGLEVEL",getValue());
+                       return true;
+               }
+               };
+
+       public static final Option      HELP_LOGLEVEL_FILE      =       new 
Option("level-file||FILE","read various log levels from file") {
+               public boolean exec( Command app )
+               {
+                       ((Application) 
app).getPreferences().setString((((AbstractApplication) app).daemon ? "GNUNETD" 
: "GNUNET"),"LOGLEVELS-FILE",getValue());
+                       return true;
+               }
+               };
+
+       public static final Option      HELP_VERSION                    =       
new Option("version|v","print the version number") {
+               public boolean exec( Command app )
+               {
+                       ((AbstractApplication) app).printVersion();
+                       return false;
+               }
+               };
+
+       public void printVersion()
+       {
+               System.out.println(getName()+" 
v"+Utils.formatVersion(getVersion()));
+       }
+
+       public abstract int run();
+
+       public void addCritical( Action a )
+       {
+               if (before.size()==0) {
+                       Runtime.getRuntime().addShutdownHook(new Thread(new 
Runnable() {
+                               public void run()
+                               {
+                                       Action  ac;
+                                       int             i;
+
+                                       // don't use logging services, since 
being in shutdown
+                                       System.out.println("Exec. 
#"+before.size()+" critical actions before shutdown.");
+
+                                       for (i=0; i<before.size(); i++) {
+                                               ac=(Action) before.get(i);
+                                               try {
+                                                       ac.perform();
+                                                       }
+                                               catch( Throwable x ) {
+                                                       
System.err.println("Unable to execute action '"+ac.getName()+"' !");
+                                                       
x.printStackTrace(System.err);
+                                                       }
+                                               }
+                               }
+                               },"CRITICALS"));
+                       }
+               before.add(0,a);
+       }
+
+       /**
+        * Obtain option from a peer.
+        * @param sock
+        * @param section
+        * @param option
+        * @return null on error
+        */
+
+       //TODO: a bouger !!!
+       public static String getConfigurationOptionValue( CSSession sock, 
String section, String option )
+       {
+               CSGetOptionRequest      req;
+               CSGetOptionReply                reply;
+
+               req=new CSGetOptionRequest(section,option);
+               if (!sock.send(req)) {
+                       return null;
+                       }
+
+               reply=(CSGetOptionReply) sock.receive(CSGetOptionReply.class);
+               if (reply==null) {
+                       return null;
+                       }
+               return reply.getValue();
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void launch( Class c, String[] args )
+       {
+               // check minimal system config., launch configuration wizard if 
needed
+               if (!c.equals(GNUNetUIConfig.class) && 
!c.equals(GNUNetConfig.class)) {
+                       Prefs.ensureInitialized();
+                       }
+
+               Command.launch(c,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/AbstractClient.java
===================================================================
--- freeway/src/org/gnu/freeway/AbstractClient.java     2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/AbstractClient.java     2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,99 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.net.*;
+
+import java.net.*;
+import java.util.logging.*;
+
+/**
+ *
+ */
+
+public abstract class AbstractClient extends AbstractApplication
+{
+       protected AbstractClient( String name, int version )
+       {
+               super(name,version,false);
+       }
+
+       public String toString()
+       {
+               return "Abstract client";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public void printVersion()
+       {
+               System.out.println("GNUnet 
v"+Utils.formatVersion(GNUNetDaemon.VERSION)+", "+getName()+" 
v"+Utils.formatVersion(getVersion()));
+       }
+
+       /**
+        * Get a GNUnet TCP socket that is connected to gnunetd.
+        *
+        * @return
+        */
+
+       public CSSession connect()
+       {
+               CSSession       session;
+               Prefs           prefs;
+               InetAddress     ip;
+               String          host;
+               int                     port;
+
+               prefs=getPreferences();
+               host=prefs.getString("NETWORK","HOST","localhost");
+               port=prefs.getInt("NETWORK","PORT",0);
+
+               try {
+                       ip=InetAddress.getByName(host);
+                       }
+               catch( UnknownHostException x ) {
+                       err("Could not find IP for "+host+".",x);
+                       return null;
+                       }
+
+               session=new TCPSession();
+               if (!session.connect(ip,port,true)) {
+                       log(Level.SEVERE,"Could not connect to gnunetd !");
+
+                       session.disconnect();
+                       session=null;
+                       }
+               return session;
+       }
+
+/*
+Exemple de communication:
+
+               decoder=new PersistentDecoder();
+               decoder.add(ProxyCommand.TOKEN_ID,ProxyToken.class);
+               decoder.add(ProxyCommand.ERROR_ID,ProxyError.class);
+               decoder.add(ProxyCommand.UNKNOWN_ID,ProxyUnknown.class);
+               decoder.add(ProxyCommand.CORRUPTED_ID,ProxyCorrupted.class);
+               decoder.setDefault(ProxyCommand.UNKNOWN_ID);
+               decoder.setCorrupted(ProxyCommand.CORRUPTED_ID);
+
+               session=new TCP Session(decoder,true);
+               session.connect("localhost",100);
+
+               log(Level.INFO,"Send Hello.");
+               session.send(new ProxyHello());
+
+               tok=(ProxyToken) session.receive(ProxyToken.class);
+               log(Level.INFO,"Received token : "+tok);
+
+               session.send(new ProxyConnect("www.yahoo.com",80));
+
+               session.send(new ProxySetBlocking(true));
+               session.disconnect();
+
+*/
+}

Added: freeway/src/org/gnu/freeway/AbstractServer.java
===================================================================
--- freeway/src/org/gnu/freeway/AbstractServer.java     2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/AbstractServer.java     2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,132 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.transport.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.net.*;
+
+/**
+ *
+ */
+
+public abstract class AbstractServer extends AbstractApplication implements 
Server, P2PHandler
+{
+       private MessagesDispatcher              dispatcher;
+
+       /** Noise received-stats. */
+       private Stat                            receivedNoiseBytes;
+
+       private ClientServer    server;
+
+       /** */
+       private LocalIdentity                           keys;
+
+
+       protected AbstractServer( String name, int version )
+       {
+               super(name,version,true);
+               dispatcher=new MessagesDispatcher();
+               receivedNoiseBytes=getStatistics().getHandle("# bytes of noise 
received");
+               server=new ClientServer();
+
+               keys=new LocalIdentity();
+       }
+
+       public String toString()
+       {
+               return "Abstract server";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * The identity of the local node.
+        * @return
+        */
+
+       public LocalIdentity getKeys()
+       {
+               return keys;
+       }
+
+
+       public boolean isCSHandlerRegistered( int type )
+       {
+               return server.isCSHandlerRegistered(type);
+       }
+
+       public boolean registerCSHandler( int type, Class c, CSHandler handler )
+       {
+               return server.registerCSHandler(type,handler);
+       }
+
+       public boolean unregisterCSHandler( int type, CSHandler handler )
+       {
+               return server.unregisterCSHandler(type,handler);
+       }
+
+       public boolean registerCSExitHandler( ClientExitHandler callback )
+       {
+               return server.registerClientExitHandler(callback);
+       }
+
+       public boolean unregisterCSExitHandler( ClientExitHandler callback )
+       {
+               return server.unregisterClientExitHandler(callback);
+       }
+
+
+
+       public MessagesDispatcher getDispatcher()
+       {
+               return dispatcher;
+       }
+
+       public boolean handle( Session session, P2PMessage msg, boolean 
encrypted )
+       {
+               if (msg instanceof P2PNoise) {
+                       return handleNoise(session,(P2PNoise) msg);
+                       }
+               return false;
+       }
+
+       protected boolean handleNoise( Session session, P2PNoise msg )
+       {
+               receivedNoiseBytes.add(msg.getByteSize());
+               return true;
+       }
+
+       public void beurk0()
+       {
+               keys.load(getHome());
+       }
+
+       public void beurk1()
+       {
+               server.start(this);
+       }
+
+       public void beurk2()
+       {
+               server.stop();
+       }
+
+       public int run( String[] args )
+       {
+               int     ret;
+
+               dispatcher.init(this);
+               
dispatcher.registerP2PHandler(P2PMessage.IS_NOISE,P2PNoise.class,this);
+
+               ret=super.run(args);
+
+               dispatcher.unregisterP2PHandler(P2PMessage.IS_NOISE,this);
+               dispatcher.done();
+               return ret;
+       }
+}

Added: freeway/src/org/gnu/freeway/Application.java
===================================================================
--- freeway/src/org/gnu/freeway/Application.java        2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/Application.java        2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,34 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+
+/**
+ *
+ */
+
+public interface Application
+{
+       public String getName();
+       public int getVersion();
+       public Prefs getPreferences();
+       public Service service( Class c );
+       public void addCritical( Action a );
+
+
+
+       /**
+        * Return a directory where application can store local files.
+        * @return
+        */
+
+       public DirLocation getHome();
+
+       public Scheduler getScheduler();
+
+       public Statistics getStatistics();
+}

Added: freeway/src/org/gnu/freeway/Command.java
===================================================================
--- freeway/src/org/gnu/freeway/Command.java    2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/src/org/gnu/freeway/Command.java    2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,221 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.util.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+import java.util.logging.*;
+
+/**
+ *
+ *
+ * code to allow clean shutdown of application with signals
+ *
+ * Helper code for writing proper termination code when an application
+ * receives a SIGTERM/SIGHUP etc.
+ */
+
+public abstract class Command extends LoggedObject implements Signals
+{
+       public static final int ERR_CANNOT_INSTANTIATE  =       -1001;
+       public static final int ERR_UNHANDLED_EXCEPTION =       -1002;
+       public static final int ERR_PARSING_STOPPED             =       -1003;
+
+       private String                  name;
+       private int                             version;
+       private String[]                        arguments;
+       private OptionsParser           parser;
+       private Scheduler               scheduler;//todo: a garder ici ???
+
+       /** Semaphore used to signal shutdown. */
+       private Semaphore               doShutdown;
+
+       /** This flag is set if application is shutting down. */
+       private boolean                 shutdown;
+
+
+       protected Command( String str, int v )
+       {
+               super(true);
+               name=str;
+               version=v;
+               arguments=new String[] {};
+               parser=null;
+               scheduler=new Scheduler();
+
+               doShutdown=new Semaphore(0);
+               shutdown=false;
+       }
+
+       public String toString()
+       {
+               return "Command [name="+name+", version="+version+"]";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public String getName()
+       {
+               return name;
+       }
+
+       public int getVersion()
+       {
+               return version;
+       }
+
+       public String[] getArguments()
+       {
+               return (parser!=null ? parser.getArguments() : arguments);
+       }
+
+       public OptionsParser getParser()
+       {
+               return parser;
+       }
+
+       public abstract OptionsParser createParser();
+
+       public Scheduler getScheduler()
+       {
+               return scheduler;
+       }
+
+       public int run( String[] args )
+       {
+               SignalManager   mgr;
+               SignalListener  listener;
+               int                             ret;
+
+               arguments=args;
+
+               parser=createParser();
+               if (parser!=null && !parser.parse(this,args)) {
+                       return ERR_PARSING_STOPPED;     // parse error, --help, 
etc
+                       }
+
+               // initialize the signal handlers
+               listener=new SignalListener() {
+                       public void signalReceived( SignalEvent evt )
+                       {
+                               log(Level.INFO,"Received signal 
"+evt.getSignalName()+".");
+                               shutdown(evt.getSignal());
+                       }
+                       };
+
+               mgr=SignalManager.getInstance();
+               mgr.addSignalListener(SIGINT,listener);
+               mgr.addSignalListener(SIGTERM,listener);
+               mgr.addSignalListener(SIGQUIT,listener);
+
+               scheduler.start();
+               ret=run1();
+               scheduler.stop();
+
+               mgr=SignalManager.getInstance();
+               mgr.removeSignalListener(SIGQUIT,listener);
+               mgr.removeSignalListener(SIGTERM,listener);
+               mgr.removeSignalListener(SIGINT,listener);
+
+               return ret;
+       }
+
+       public abstract int run1();
+
+       /**
+        * Test if the shutdown has been initiated.
+        * @return YES if we are shutting down, NO otherwise
+        */
+
+       public boolean isShutdowning()
+       {
+               return shutdown;
+       }
+
+       /**
+        * Try a propper shutdown of application.
+        *
+        * @param signum
+        */
+
+       public void shutdown( int signum )
+       {
+               shutdown=true;
+               doShutdown.release();
+       }
+
+       /**
+        * Wait until the shutdown has been initiated.
+        */
+
+       public void waitForShutdown()
+       {
+               try {
+                       doShutdown.acquire();
+                       }
+               catch( InterruptedException x ) {
+                       err("Could not acquire semaphore !",x);
+                       }
+       }
+
+       /**
+        * Wait until the shutdown has been initiated, or timeout expired.
+        *
+        * @param units Timeout.
+        */
+
+       public void waitForShutdown( long units )
+       {
+               getScheduler().addJob(new 
ScheduledTask("SHUTDOWN-WITH-SIGUSR1",new AbstractAction() {
+                       public void perform()
+                       {
+                               shutdown(SIGUSR1);
+                       }
+                       }),units);
+
+               waitForShutdown();
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void launch( Class c, String[] args )
+       {
+               Command cmd;
+               Logger  logger;
+               int             ret;
+
+               LoggedObject.sendLogsToConsole(Level.FINEST);
+
+               logger=Logger.getLogger(c.getName());
+
+               ret=0;
+               try {
+                       cmd=(Command) c.newInstance();
+                       try {
+                               ret=cmd.run(args);
+                               if (ret!=0) {
+                                       logger.log(Level.WARNING,"Command 
returned error #"+ret+".");
+                                       }
+                               }
+                       catch( Throwable x ) {
+                               logger.log(Level.SEVERE,"Unhandled exception, 
exit !",x);
+                               ret=ERR_UNHANDLED_EXCEPTION;
+                               }
+                       }
+               catch( InstantiationException x ) {
+                       logger.log(Level.SEVERE,"Can't instantiate class 
"+c.getName()+" !",x);
+                       ret=ERR_CANNOT_INSTANTIATE;
+                       }
+               catch( IllegalAccessException x ) {
+                       logger.log(Level.SEVERE,"Can't instantiate class 
"+c.getName()+" !",x);
+                       ret=ERR_CANNOT_INSTANTIATE;
+                       }
+               System.exit(ret);
+       }
+}

Added: freeway/src/org/gnu/freeway/DaemonLauncher.java
===================================================================
--- freeway/src/org/gnu/freeway/DaemonLauncher.java     2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/DaemonLauncher.java     2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,333 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+import org.gnu.freeway.util.ui.*;
+
+import java.io.*;
+import java.security.*;
+import java.net.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ *
+ */
+
+public class DaemonLauncher extends LoggedObject
+{
+       //todo: utiliser un premier fichier sur REMOTE : date de derniere modif 
+ liste à charger
+       private static final String[]   REMOTE_JARS_TO_COPY     =       {
+               "daemon/freeway.jar",
+               "daemon/freeway-tcp.jar",
+               "daemon/freeway-udp.jar",
+               "daemon/freeway-nat.jar",
+               "daemon/freeway-afs.jar",
+               "daemon/freeway-afs-mysql.jar",
+               "daemon/freeway-chat.jar",
+               "daemon/freeway-tracekit.jar",
+               "batik-all.jar",
+               "bcprov-jdk14-122.jar",
+               "concurrent.jar",
+               "mysql-connector-java-3.0.10-stable-bin.jar"
+               };
+
+       private static final String[]   REMOTE_JARS_FOR_CLASSPATH       =       
{
+               "freeway.jar",
+               "batik-all.jar",
+               "bcprov-jdk14-122.jar",
+               "concurrent.jar",
+               "mysql-connector-java-3.0.10-stable-bin.jar"
+               };
+
+       private static final String[]   LOCAL_JARS_FOR_CLASSPATH        =       
{
+               "freeway.jar",
+               "../lib/batik-all.jar",
+               "../lib/bcprov-jdk14-122.jar",
+               "../lib/concurrent.jar",
+               "../lib/mysql-connector-java-3.0.10-stable-bin.jar"
+               };
+
+       /** */
+       private AbstractClient  client;
+
+       /** */
+       private Prefs                   prefs;
+
+
+       public DaemonLauncher( Application app )
+       {
+               super(true);
+               client=(AbstractClient) app;
+               prefs=app.getPreferences();
+       }
+
+       public String toString()
+       {
+               return "Daemon launcher";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Checks if gnunetd is running
+        *
+        * NOTE: Uses CS_PROTO_CLIENT_COUNT query to determine if daemon is 
running
+        * @return
+        */
+
+       public boolean checkDaemonRunning()
+       {
+               CSSession       sock;
+               CSResult        rv;
+
+               sock=client.connect();
+               if (sock==null) {
+                       log(Level.WARNING,"Socket creation failed, shouldn't 
happen.");
+                       return false;
+                       }
+
+               try {
+                       if (!sock.send(new CSGetClientCount())) {
+                               log(Level.FINEST,"Daemon is NOT running.");
+                               return false;
+                               }
+
+                       rv=(CSResult) sock.receive(CSResult.class);
+                       if (rv==null) {
+                               log(Level.FINEST,"Failed to read reply from 
daemon.");
+                               return false;
+                               }
+                       }
+               finally {
+                       sock.disconnect();
+                       }
+               return true;
+       }
+
+       public boolean launchWithExec( GProgress progress, String argLine, 
ConnectorEndPoint end )
+       {
+               String[]                a;
+               DirLocation             baseDir;
+               List                    args;
+               StringBuffer    buf;
+               String                  str;
+               URL                             url;
+               int                             i;
+
+               str=prefs.getString("GNUNET-SWING","REMOTE",null);
+               if (str!=null && str.length()>0) {
+                       try {
+                               url=new URL(str);
+                               }
+                       catch( MalformedURLException x ) {
+                               err("Invalid URL !",x);
+                               return false;
+                               }
+
+                       if (!progress.getFrame().askMessage("Daemon will be 
launched as a separate Java process.\n"+
+                               "Needed libraries will be downloaded from 
'"+str+"'\n"+
+                               " after a first check to determine if they are 
up to date (not yet implemented).\n"+
+                               "Do you still want to continue ?")) {
+                               return false;
+                               }
+
+                       
str=prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.CLIENTS_BASEDIR_NAME)+File.separator+"remote";
+
+                       baseDir=new DirLocation(str);
+                       if (!baseDir.create()) {
+                               log(Level.SEVERE,"Could not access base 
directory ("+str+") !");
+                               return false;
+                               }
+
+                       if (!isBaseDirectoryUp(baseDir,url)) {
+                               if (!setBaseDirectoryUp(baseDir,url,progress)) {
+                                       return false;
+                                       }
+                               }
+
+                       buf=new StringBuffer();
+                       for (i=0; i<REMOTE_JARS_FOR_CLASSPATH.length; i++) {
+                               buf.append(baseDir.getPath());
+                               buf.append(File.separator);
+                               buf.append(REMOTE_JARS_FOR_CLASSPATH[i]);
+                               if (i<REMOTE_JARS_FOR_CLASSPATH.length-1) {
+                                       buf.append(File.pathSeparator);
+                                       }
+                               }
+                       }
+               else {
+                       log(Level.WARNING,"No remote URL given to download 
daemon classes, going to try with current dir...");
+
+                       baseDir=new DirLocation(".");
+
+                       buf=new StringBuffer();
+                       for (i=0; i<LOCAL_JARS_FOR_CLASSPATH.length; i++) {
+                               buf.append(new 
FileLocation(LOCAL_JARS_FOR_CLASSPATH[i]).getPath());
+                               if (i<LOCAL_JARS_FOR_CLASSPATH.length-1) {
+                                       buf.append(File.pathSeparator);
+                                       }
+                               }
+                       }
+
+               args=new ArrayList();
+               args.add("java");
+               args.add("-ea");        //fixme: a voir
+               args.add("-classpath");
+               args.add(buf.toString());
+               args.add("-Djava.library.path="+baseDir.getPath());
+               args.add("-Djava.nio.preferSelect=true");       //fixme: a voir
+               args.add("org.gnu.freeway.GNUNetDaemon");
+               if (argLine!=null && argLine.length()>0) {
+                       a=OptionsParser.toArgs(argLine);
+                       for (i=0; i<a.length; i++) {
+                               args.add(a[i]);
+                               }
+                       }
+               log(Level.INFO,"About to launch daemon with arguments : "+args);
+
+               final DirLocation                       _baseDir = baseDir;
+               final List                              _args = args;
+               final ConnectorEndPoint _end = end;
+
+               AccessController.doPrivileged(new PrivilegedAction() {
+                       public Object run()
+                       {
+                               Task    task;
+
+                               task=new Task("FORK",new AbstractAction() {
+                                       public void perform()
+                                       {
+                                               
launchProcess(_baseDir,(String[]) _args.toArray(new String[_args.size()]),_end);
+                                       }
+                                       });
+                               task.launch();
+                               return null;
+                       }
+                       });
+               return true;
+       }
+
+       protected String strip( String str )
+       {
+               return str.substring(str.lastIndexOf("/")+1);
+       }
+
+       protected boolean launchProcess( DirLocation baseDir, String[] args, 
ConnectorEndPoint end )
+       {
+               Process process;
+               int             ret;
+
+               try {
+                       process=Runtime.getRuntime().exec(args,null,new 
File(baseDir.getPath()));
+                       log(Level.INFO,"Launched process : "+process);
+
+                       Connector.connect(process,end);
+
+                       ret=process.waitFor();
+                       log(Level.INFO,"Process returned with code "+ret+".");
+                       return ret==0;
+                       }
+               catch( Throwable x ) {
+                       err("Failed to launch process !",x);
+                       }
+               return false;
+       }
+
+       protected boolean isBaseDirectoryUp( DirLocation dir, URL remote )
+       {
+               return false;
+       }
+
+       protected boolean setBaseDirectoryUp( DirLocation dir, URL remote, 
GProgress progress )
+       {
+               URL             url;
+               FileLocation    file;
+               String  path;
+               MappedFile      mm;
+               int             i;
+
+               if (!dir.deleteUnder()) {
+                       log(Level.WARNING,"Unable to delete existing files 
under \""+dir.getPath()+"\" !");
+                       return false;
+                       }
+
+               for (i=0; i<REMOTE_JARS_TO_COPY.length; i++) {
+                       path=remote.getPath();
+                       if (!path.endsWith("/")) {
+                               path+="/";
+                               }
+                       path+=REMOTE_JARS_TO_COPY[i];
+
+                       if (progress!=null) {
+                               
progress.progress(i+1,REMOTE_JARS_TO_COPY.length,"Downloading \""+path+"\"");
+                               }
+
+                       file=dir.getFile(strip(REMOTE_JARS_TO_COPY[i]));
+                       if (!file.create()) {
+                               log(Level.WARNING,"Failed to create local file 
\""+REMOTE_JARS_TO_COPY[i]+"\" !");
+                               return false;
+                               }
+
+                       try {
+                               mm=file.openNew();
+                               try {
+                                       url=new 
URL(remote.getProtocol(),remote.getHost(),remote.getPort(),path);
+                                       if (!mm.writeURL(url)) {
+                                               log(Level.WARNING,"Failed to 
copy \""+path+"\" !");
+                                               return false;
+                                               }
+                                       Scheduler.sleep(Scheduler.MILLIS_500);
+                                       }
+                               finally {
+                                       mm.close();
+                                       }
+                               }
+                       catch( MalformedURLException x ) {
+                               err("Bad URL format !",x);
+                               return false;
+                               }
+                       }
+               return true;
+       }
+
+       /**
+        * Kill gnunetd
+        * @return
+        */
+
+       public boolean killDaemon()
+       {
+               CSSession       sock;
+               CSResult        rv;
+
+               if (!checkDaemonRunning()) {
+                       return false;
+                       }
+
+               sock=client.connect();
+               try {
+                       if (!sock.send(new CSShutdownRequest())) {
+                               log(Level.WARNING,"Error sending shutdown 
request to daemon.");
+                               return false;
+                               }
+
+                       rv=(CSResult) sock.receive(CSResult.class);
+                       if (rv==null) {
+                               log(Level.FINEST,"Error reading shutdown reply 
from daemon.");
+                               return false;
+                               }
+                       return rv.isOkay();
+                       }
+               finally {
+                       sock.disconnect();
+                       }
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetChat.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetChat.java 2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/src/org/gnu/freeway/GNUNetChat.java 2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,142 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.protocol.chat.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.net.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * Chat command line tool
+ */
+
+public class GNUNetChat extends AbstractClient
+{
+       private Prefs   prefs;
+
+
+       protected GNUNetChat()
+       {
+               super("gnunet-chat",Utils.makeVersion(0,0,3));
+               prefs=getPreferences();
+       }
+
+       public String toString()
+       {
+               return "Chat";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-chat [OPTIONS]","Start GNUnet 
chat client.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("nickname|n|NICK","specify 
nickname") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-CHAT","NICK",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       public int run()
+       {
+               CSSession               sock;
+               Task                            thread;
+               int                             ret;
+               CSChatMessage   msg;
+               BufferedReader  reader;
+               String                  nick,str;
+
+               sock=connect();
+               if (sock==null) {
+                       log(Level.SEVERE,"Could not connect to gnunetd.");
+                       return -29;
+                       }
+
+               final CSSession _sock = sock;
+
+               log(Level.INFO,"Start receive thread.");
+               thread=new Task("CLIENT-RECEIVE",new AbstractAction() {
+                       public void perform()
+                       {
+                               CSChatMessage   buffer;
+
+                               buffer=(CSChatMessage) 
_sock.receive(CSChatMessage.class);
+                               while (buffer!=null) {
+                                       System.out.println("["+new 
Date()+"]["+buffer.getNickName()+"]: "+buffer.getMessage());
+
+                                       buffer=(CSChatMessage) 
_sock.receive(CSChatMessage.class);
+                                       }
+                       }
+                       });
+               thread.launch();
+
+               nick=prefs.getString("GNUNET-CHAT","NICK",null);
+               if (nick==null) {
+                       log(Level.SEVERE,"You must specify a nickname (use 
option -n).");
+                       ret=-2;
+                       }
+               else {
+                       msg=new CSChatMessage();
+                       msg.setMessage("Hi!\n");
+                       msg.setNickName(nick);
+
+                       // send first "Hi!" message to gnunetd to indicate 
"join"
+                       if (!sock.send(msg)) {
+                               log(Level.SEVERE,"Could not send join message 
to gnunetd.");
+                               ret=-3;
+                               }
+                       else {
+                               ret=0;
+
+                               // read messages from command line and send
+                               try {
+                                       reader=new BufferedReader(new 
InputStreamReader(System.in));
+                                       for (str=reader.readLine(); str!=null; 
str=reader.readLine()) {
+                                               msg.setMessage(str+"\n");
+                                               if (!sock.send(msg)) {
+                                                       log(Level.SEVERE,"Could 
not send message to gnunetd.");
+                                                       ret=-4;
+                                                       break;
+                                                       }
+                                               }
+                                       }
+                               catch( IOException x ) {
+                                       err("",x);
+                                       }
+                               }
+                       }
+
+               log(Level.INFO,"Waiting for receive thread to finish.");
+
+               sock.disconnect();
+               thread.join();
+               return ret;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetChat.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetConfig.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetConfig.java       2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetConfig.java       2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,289 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+
+import java.io.*;
+import java.sql.*;
+
+/**
+ *
+ */
+
+public class GNUNetConfig extends AbstractClient
+{
+       private Prefs   prefs;
+       private boolean doErase;
+       private boolean doForce;
+       private boolean doPrint;
+
+
+       protected GNUNetConfig()
+       {
+               super("gnunet-config",Utils.makeVersion(1,0,0));
+               prefs=getPreferences();
+               doErase=false;
+               doForce=false;
+               doPrint=false;
+       }
+
+       public String toString()
+       {
+               return "Configuration tool";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-config [OPTIONS]","Start 
GNUnet configuration program.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(new Option("erase|e","erase all stored 
configuration (after confirmation !)") {
+                       public boolean exec( Command c )
+                       {
+                               doErase=true;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("force|f","force to reenter all 
configuration information") {
+                       public boolean exec( Command c )
+                       {
+                               doForce=true;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("print|p","print stored 
configuration information") {
+                       public boolean exec( Command c )
+                       {
+                               doPrint=true;
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       public int run()
+       {
+               String          str;
+               int                     ret;
+               boolean         check;
+
+               // sanity checks
+               if (doErase && (doForce || doPrint)) {
+                       error("You cannot specify another action with 
--erase.");
+                       return -2;
+                       }
+
+               if (doErase) {
+                       ret=askChoice("Do you *really* want to erase all 
configuration information ?","yes|no",1,false);
+                       if (ret==0) {
+                               prefs.eraseGlobals();
+                               }
+                       return 0;
+                       }
+
+               check=false;
+               if (doForce || !prefs.isSystemInitialized()) {
+                       if (doForce || 
!prefs.hasGlobalString(Prefs.CONFIG_NODE,Prefs.DAEMON_BASEDIR_NAME)) {
+                               str=askDirectory("Home directory for freeway 
daemon ?",Prefs.DAEMON_BASEDIR_NAME,Prefs.DAEMON_BASEDIR_DEFAULT);
+                               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.DAEMON_BASEDIR_NAME,str);
+                               }
+
+                       if (doForce || 
!prefs.hasGlobalString(Prefs.CONFIG_NODE,Prefs.CLIENTS_BASEDIR_NAME)) {
+                               str=askDirectory("Home directory for freeway 
clients ?",Prefs.CLIENTS_BASEDIR_NAME,Prefs.CLIENTS_BASEDIR_DEFAULT);
+                               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.CLIENTS_BASEDIR_NAME,str);
+                               }
+
+                       if (doForce || 
!prefs.hasGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_HOST_NAME)) {
+                               str=askWithDefaultNotNull("MySQL host 
?",prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_HOST_NAME,Prefs.MYSQL_HOST_DEFAULT));
+                               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_HOST_NAME,str);
+                               }
+
+                       if (doForce || 
!prefs.hasGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_USER_NAME)) {
+                               str=askWithDefaultNotNull("MySQL user 
?",prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_USER_NAME,Prefs.MYSQL_USER_DEFAULT));
+                               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_USER_NAME,str);
+                               check=true;
+                               }
+
+                       if (doForce || 
!prefs.hasGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_PASSWORD_NAME)) {
+                               str=askWithDefaultNullable("MySQL password 
?",prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_PASSWORD_NAME,Prefs.MYSQL_PASSWORD_DEFAULT));
+                               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_PASSWORD_NAME,str);
+                               check=true;
+                               }
+                       }
+
+               if (check && !checkForMySQL()) {
+                       error("Failed to connect to MySQL database. Check your 
MySQL configuration and re-run program later.");
+                       }
+
+               str=prefs.getSystemDaemonConfiguration();
+               if (str!=null && !new FileLocation(str).exists()) {
+                       message("Create daemon configuration file. You can 
customize it later by editing \""+str+"\".");
+                       
prefs.copyTemplateWithGlobals("gnunet.daemon.template",new FileLocation(str));
+                       }
+
+               str=prefs.getSystemClientsConfiguration();
+               if (str!=null && !new FileLocation(str).exists()) {
+                       message("Create tools configuration file. You can 
customize it later by editing \""+str+"\".");
+                       
prefs.copyTemplateWithGlobals("gnunet.client.template",new FileLocation(str));
+                       }
+
+               if (prefs.isSystemInitialized()) {
+                       message("Configuration entries are okay. Please have a 
look to \""+prefs.getSystemDaemonConfiguration()+"\" and 
\""+prefs.getSystemClientsConfiguration()+"\" for further customizations.");
+                       }
+
+               if (doPrint) {
+                       prefs.printGlobals();
+                       }
+               return 0;
+       }
+
+       protected String askDirectory( String prompt, String entry, String def )
+       {
+               DirLocation     dir;
+               String          str;
+
+               
str=askWithDefaultNotNull(prompt,prefs.getGlobalString(Prefs.CONFIG_NODE,entry,def));
+               dir=new DirLocation(str);
+               while (!dir.create()) {
+                       error("Failed to create directory 
\""+dir.getPath()+"\"\n. Please, enter a new value.");
+
+                       
str=askWithDefaultNotNull(prompt,prefs.getGlobalString(Prefs.CONFIG_NODE,entry,def));
+                       dir=new DirLocation(str);
+                       }
+               return str;
+       }
+
+       protected boolean checkForMySQL()
+       {
+               Connection      conn;
+
+               try {
+                       Class.forName("com.mysql.jdbc.Driver");
+                       conn=DriverManager.getConnection(
+                               
"jdbc:mysql://"+prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_HOST_NAME,"")+"/",
+                               
prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_USER_NAME,""),
+                               
prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_PASSWORD_NAME,"")
+                               );
+                       conn.close();
+                       }
+               catch( SQLException x ) {
+                       err("Unable to connect to MySQL !",x);
+                       return false;
+                       }
+               catch( ClassNotFoundException x ) {
+                       err("Unable to load MySQL driver !",x);
+                       return false;
+                       }
+               return true;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       protected void message( String str )
+       {
+               System.out.println(str);
+       }
+
+       protected void error( String str )
+       {
+               System.err.println(str);
+       }
+
+       protected String askWithDefaultNullable( String str, String def )
+       {
+               return askWithDefault(str,def,true);
+       }
+
+       protected String askWithDefaultNotNull( String str, String def )
+       {
+               return askWithDefault(str,def,false);
+       }
+
+       protected String askWithDefault( String prompt, String def, boolean 
allowNull )
+       {
+               String  str;
+
+               do {
+                       System.out.print(prompt+" ["+def+"] ? ");
+
+                       try {
+                               str=new BufferedReader(new 
InputStreamReader(System.in)).readLine();
+                               }
+                       catch( IOException x ) {
+                               err("I/O exception",x);
+                               str=null;
+                               }
+                       str=((str!=null && str.length()>0) ? str : def);
+                       }
+               while (!allowNull && (str==null || str.length()==0));
+               return str;
+       }
+
+       public int askChoice( String prompt, String choices, int def, boolean 
allowNull )
+       {
+               String[]        p;
+               String          str;
+               int                     i;
+
+               p=choices.split("\\|");
+
+               do {
+                       System.out.print(prompt+" ("+info(p)+") : ");
+                       System.out.flush();
+
+                       try {
+                               str=new BufferedReader(new 
InputStreamReader(System.in)).readLine();
+                               }
+                       catch( IOException x ) {
+                               err("I/O exception",x);
+                               str=null;
+                               }
+
+                       i=-1;
+                       if (str!=null && str.length()>0) {
+                               str=str.toLowerCase();
+                               for (i=0; i<p.length && 
!p[i].toLowerCase().startsWith(str); i++) {}
+                               }
+                       }
+               while ((i<0 && !allowNull) || i==p.length);
+               return i;
+       }
+
+       protected String info( String[] p )
+       {
+               StringBuffer    buf;
+               int                             i;
+
+               buf=new StringBuffer();
+               for (i=0; i<p.length; i++) {
+                       buf.append(p[i]);
+                       buf.append(", ");
+                       }
+               if (i>0) {
+                       buf.setLength(buf.length()-2);
+                       }
+               return buf.toString();
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetConfig.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetDaemon.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetDaemon.java       2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetDaemon.java       2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,257 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import java.util.logging.*;
+
+/**
+ * Daemon that must run on every GNUnet peer.
+ *
+ * + Helper methods for the startup of gnunetd:
+ * - install signal handling
+ * - system checks on startup
+ * - PID file handling
+ * - detaching from terminal
+ * - command line parsing
+ */
+
+public class GNUNetDaemon extends AbstractServer implements CSHandler
+{
+       public static final int VERSION =       Utils.makeVersion(0,6,2,0xb);
+
+       /** */
+       private ScheduledTask           dotTask;
+
+       /** */
+       private boolean                 download;
+
+
+
+       public GNUNetDaemon()
+       {
+               super("gnunetd",VERSION);
+               dotTask=new ScheduledTask("PRINT-DOT",new AbstractAction() {
+                       public void perform()
+                       {
+                               log(Level.FINEST, ".");
+                       }
+                       },Scheduler.SECS_1);
+               download=false;
+       }
+
+       public String toString()
+       {
+               return "GNUnet daemon";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunetd [OPTIONS]","Start gnunetd 
daemon.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(new Option("debug|d","run in debug mode; 
gnunetd will not daemonize and error messages will be written to stderr instead 
of a logfile") {
+                       public boolean exec( Command c )
+                       {
+                               
getPreferences().setString("GNUNETD","LOGFILE",null);
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("livedot|l","print a dot every 
second to show that gnunetd is alive") {
+                       public boolean exec( Command c )
+                       {
+                               getScheduler().addJob(dotTask,Scheduler.SECS_1);
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("padding|p|PADDING","enable 
padding") {
+                       public boolean exec( Command c )
+                       {
+                               
getPreferences().setString("GNUNETD-EXPERIMENTAL","PADDING",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("user|u|USER","run as user USER") {
+                       public boolean exec( Command c )
+                       {
+                               //todo: to implement
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("download|","download host list") {
+                       public boolean exec( Command c )
+                       {
+                               download=true;
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       public int run()
+       {
+               Prefs   prefs;
+               int             version,stop;
+               boolean firstStart;
+
+               prefs=getPreferences();
+
+               // check version; possibly not the best place here since 
gnunet-check is AFS specific (at least at the moment).
+               version=prefs.getContentAsInt("VERSION",-1);
+               if (version!=-1) {
+                       // basic idea: whenever we make an incompatible change, 
bump the version
+                       // requirement here and add the necessary update code 
to gnunet-check...
+                       if (version<0x0620) {
+                               System.err.println("Old version "+version+" 
detected. Please run gnunet-check -u first !");
+                               return -99;
+                               }
+                       firstStart=false;
+                       }
+               else {
+                       version=0x0620; // first start
+                       prefs.putContent("VERSION",version);
+                       firstStart=true;
+                       }
+
+               /* init 2: become deamon, initialize core subsystems */
+               log(Level.FINE,"Daemon starting...");
+
+               /* initialize signal handler (CTRL-C / SIGTERM) */
+               writePIDFile();
+
+               /* init 3b: load application services */
+               beurk1();
+
+               service(CoreService.class);
+               service(HelloExchangeService.class);
+               service(PingPongService.class);
+               service(ConnectionService.class);
+
+               ((CoreService) service(CoreService.class)).loadProtocols();
+               if (firstStart || download) {
+                       ((HELOLoader) 
service(HELOLoader.class)).downloadRandomHostList();      // right away !
+                       }
+
+               /* init 4: wait for shutdown */
+               /* wait for SIGTERM, SIGTERM will set
+                doShutdown to true and send this thread
+                a SIGUSR1 which will wake us up from the
+                sleep */
+               
registerCSHandler(CSMessage.IS_SHUTDOWN,CSShutdownRequest.class,this);
+               log(Level.FINE,"Daemon up and running.");
+
+               ((CoreService) service(CoreService.class)).getManager().dump();
+
+               // mechanism to stop gnunetd after a certain time without a 
signal
+               stop=getPreferences().getInt("GNUNETD","AUTOMATIC-STOP",0);
+               if (stop>0) {
+                       waitForShutdown(Scheduler.seconds(stop));
+                       }
+               else {
+                       waitForShutdown();
+                       }
+
+               log(Level.FINE,"Daemon shutting down...");
+
+               deletePIDFile();
+
+               log(Level.FINE,"Daemon has said : \"Bye\".");
+               return 0;
+       }
+
+       public boolean handle( CSSession client, CSMessage message )
+       {
+               boolean ret;
+
+               log(Level.INFO,client.getLabel()+" Shutdown request accepted.");
+
+               unregisterCSHandler(CSMessage.IS_SHUTDOWN,this);
+
+               ret=client.send(CSResult.OKAY);
+
+               // wait for a small amount of time to enable clients to receive 
responses...
+               Scheduler.sleep(Scheduler.SECS_1);      //todo: faire plus 
deterministe
+
+               shutdown(0);
+               return ret;
+       }
+
+       /**
+        * Write our process ID to the pid file.
+        */
+
+       public void writePIDFile()
+       {
+               FileLocation            pif;
+               MappedFile              f;
+
+               pif=getPreferences().getFileLocation("GNUNETD","PIDFILE");
+               if (pif==null) {
+                       log(Level.SEVERE,"No PID file is defined in 
configuration (GNUNETD/PIDFILE) !");
+                       return;
+                       }
+
+               f=pif.openNew();
+               if (f!=null) {
+                       
f.writeString(String.valueOf(SignalManager.getInstance().getPID()));
+                       f.close();
+                       }
+               else {
+                       log(Level.WARNING,"Could not write PID to file 
\""+pif.getLabel()+"\".");
+                       }
+       }
+
+       /**
+        * Delete the pid file.
+        */
+
+       public void deletePIDFile()
+       {
+               FileLocation            pif;
+
+               pif=getPreferences().getFileLocation("GNUNETD","PIDFILE");
+               if (pif==null) {
+                       log(Level.SEVERE,"No PID file is defined in 
configuration (GNUNETD/PIDFILE) !");
+                       return;
+                       }
+               pif.delete();
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * The main method of gnunetd. And here is how it works:
+        * <ol>
+        * <li>initialize util (parse command line, options)
+        * <li>detach from tty, initialize all coresystems
+        * <li>a) start core-services
+        *     b) initialize application services and download hostlist
+        * <li>wait for semaphore to signal shutdown
+        * <li>shutdown all services (in roughly inverse order)
+        * <li>exit
+        * </ol>
+        * @param args
+        */
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetDaemon.class,args);
+       }
+
+       // You have reached the end of GNUnet. You can shutdown your computer 
and get a life now.
+}

Added: freeway/src/org/gnu/freeway/GNUNetDirectory.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetDirectory.java    2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetDirectory.java    2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,186 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.protocol.afs.*;
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+
+/**
+ * Tool to list the entries stored in the database holding files for building 
directories,
+ * to delete all of these entries and to display the contents of directories.
+ */
+
+public class GNUNetDirectory extends AbstractClient implements AFSConstants
+{
+       private int             listMask;
+       private int             killMask;
+       private RootNodeCallback        printNode = new RootNodeCallback() {
+                               public void rootNode( RootNode root, Object 
closure )
+                               {
+                                       System.out.println(root.toLabel());
+                               }
+                               };
+
+
+       protected GNUNetDirectory()
+       {
+               super("gnunet-directory",AFSProtocol.VERSION);
+               listMask=0;
+               killMask=0;
+       }
+
+       public String toString()
+       {
+               return "List, delete and display database entries";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-directory [OPTIONS] 
[FILENAMES]","Perform directory related operations.");
+               options.setAllowArguments(true);
+               options.addOption(new Option("list-all|a","list all entries 
from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               listMask|=DIR_CONTEXT_ALL;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("kill-all|A","remove all entries 
from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               killMask=DIR_CONTEXT_ALL;
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(new Option("list-insert|i","list all insert 
entries from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               listMask|=DIR_CONTEXT_INSERT;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("kill-insert|I","delete all insert 
entries from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               killMask=DIR_CONTEXT_INSERT;
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("list-namespace|n","list all 
namespace entries from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               listMask|=DIR_CONTEXT_INSERT_SB;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("kill-namespace|N","delete all 
namespace entries from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               killMask=DIR_CONTEXT_INSERT_SB;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("list-search|s","list all search 
result entries from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               listMask|=DIR_CONTEXT_SEARCH;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("kill-search|S","delete all search 
result entries from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               killMask=DIR_CONTEXT_SEARCH;
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               options.addOption(new Option("list-directory|x","list all 
directory entries from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               listMask|=DIR_CONTEXT_DIRECTORY;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("kill-directory|X","remove all 
directory entries from the directory database") {
+                       public boolean exec( Command c )
+                       {
+                               killMask=DIR_CONTEXT_DIRECTORY;
+                               return true;
+                       }
+                       });
+               return options;
+       }
+
+       protected void printDirectory( FileLocation filename )
+       {
+               GNDirectory     dir;
+               MappedFile      mm;
+               int                     i;
+
+               if (!filename.exists()) {
+                       System.out.println("==> Directory 
'"+filename.getLabel()+"': DOES NOT EXIST");
+                       return;
+                       }
+
+               System.out.println("==> Directory '"+filename.getLabel()+"':");
+
+               mm=filename.open();
+               dir=(GNDirectory) mm.asPersistent(GNDirectory.class);
+               mm.close();
+
+               if (dir == null) {
+                       System.out.println("No such file or invalid format for 
GNUnet directory.");
+                       return;
+                       }
+
+               System.out.println(dir.getDescription());
+               for (i=0;i<dir.number_of_files;i++) {
+                       System.out.print(i+": ");
+                       printNode.rootNode(dir.contents[i], null);
+                       }
+               System.out.println();
+       }
+
+       public int run()
+       {
+               Prefs   prefs;
+               int                                     i;
+               String[]        filenames;
+
+               prefs=getPreferences();
+
+               if (listMask!=0) {
+                       System.out.println("Listed "+new 
GNDirectoryDatabase(prefs).iterateDirectoryDatabase(listMask,printNode,null)+" 
matching entries.");
+                       }
+               if (killMask!=0) {
+                       new 
GNDirectoryDatabase(prefs).emptyDirectoryDatabase(killMask);
+                       }
+               filenames=getArguments();
+               for (i=0; i<filenames.length; i++) {
+                       printDirectory(new FileLocation(filenames[i]));
+                       }
+               return 0;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetDirectory.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetDownload.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetDownload.java     2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetDownload.java     2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,435 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.protocol.afs.*;
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+import java.util.logging.*;
+
+/**
+ * Main function to download files from GNUnet.
+ */
+
+public class GNUNetDownload extends AbstractClient implements AFSConstants
+{
+       /* just not false/true */
+       private static final int        PENDING =       42;
+       private static final int        RUNNING =       43;
+       private static final int        JOINED  =       44;
+
+       private DownloadInfo[]          pending = null;
+       private int                                     pendingCount = 0;
+       private Object                          lock;
+       private Semaphore                       semSignal;
+       private Prefs   prefs;
+       private DownloadUtil                    dutil;
+       private Priority                                priority;
+       private Policy                          policy;
+
+
+       public GNUNetDownload()
+       {
+               super("gnunet-download",AFSProtocol.VERSION);
+               prefs=getPreferences();
+               dutil=new DownloadUtil();
+       }
+
+       public String toString()
+       {
+               return "Download";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-download [OPTIONS] 
GNUNET-URI","Download file from GNUnet.");
+               options.setAllowArguments(true);
+               options.addOption(new Option("anonymity|a|LEVEL","set the 
desired LEVEL of receiver-anonymity") {
+                       public boolean exec( Command c )
+                       {
+                               int     receivePolicy;
+
+                               try {
+                                       
receivePolicy=Integer.parseInt(getValue());
+                                       
prefs.setInt("AFS","ANONYMITY-RECEIVE",receivePolicy);
+                                       }
+                               catch( NumberFormatException x ) {
+                                       log(Level.SEVERE,"You must pass a 
number to the -a option.");
+                                       return false;
+                                       }
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("output|o|FILENAME","write the 
file to FILENAME (required)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-DOWNLOAD","FILENAME",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("recursive|R","download a GNUnet 
directory recursively") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-DOWNLOAD","RECURSIVE","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("threads|t|NUMBER","specifies the 
NUMBER of files that maybe downloaded in parallel for a recursive download") {
+                       public boolean exec( Command c )
+                       {
+                               int     threads;
+
+                               threads=getIntValue(-1);
+                               if (threads<0) {
+                                       log(Level.WARNING,"You must pass a 
number to the -t option.");
+                                       return false;
+                                       }
+                               if (threads == 0) {
+                                       threads = 1; /* actual minimum value */
+                                       }
+                               
prefs.setInt("GNUNET-DOWNLOAD","PARALLELIZATION",threads);
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               options.addOption(new Option("verbose|V","be verbose") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-DOWNLOAD","VERBOSE","YES");
+                               return true;
+                       }
+                       });
+               return options;
+       }
+
+       /**
+        * This method is called whenever data is received.
+        * The current incarnation just ensures that the main
+        * method exits once the download is complete.
+        * @param stats
+        * @param data
+        */
+
+       protected void progressModel2( ProgressStats stats, DownloadInfo data )
+       {
+               if (prefs.testString("GNUNET-DOWNLOAD","VERBOSE","YES")) {
+                       if (stats.progress != data.lastProgress) {
+                               System.out.print("Download at 
"+stats.progress+" out of "+stats.filesize+" bytes "+
+                                       "("+(stats.progress/(double)  
Scheduler.toSeconds(Scheduler.now()-(data.startTime-1))/1024)+" kbps)"+
+                                       "\r");
+                               }
+                       }
+
+               data.lastProgress = stats.progress;
+               if (stats.progress == stats.filesize) {
+                       data.sem.release();
+                       }
+       }
+
+       protected boolean downloadFileHelper( DownloadInfo di ) throws 
InterruptedException
+       {
+               RequestManager  rm;
+               boolean                 ok;
+
+               assert(di.sem==null);
+
+               di.startTime=Scheduler.now();
+               di.lastProgress = 0;
+               di.sem = new Semaphore(0);
+
+               rm=dutil.downloadFile(
+                               this,
+                               policy,
+                               priority,
+                               di.fid,
+                               di.filename,
+                               new ProgressModel() {
+                                       public void progress( ProgressStats 
stats, Object data )
+                                       {
+                                               
progressModel2(stats,(DownloadInfo) data);
+                                       }
+                                       },
+                               di);
+               if (rm == null) {
+                       System.out.println("Download "+di.filename+" failed 
(error messages should have been provided).");
+                       return false;
+                       }
+               di.sem.acquire();
+               di.sem = null;
+               rm.destroy();
+               System.out.println();
+               System.out.println("Download "+di.filename+" 
"+((di.fid.getFileLength()==di.lastProgress) ? "complete" : "incomplete")+". "+
+                       "Speed was "+(di.lastProgress/(double) 
Scheduler.toSeconds(Scheduler.now()-di.startTime)/1024)+" kilobyte per 
second.");
+
+               ok=(di.fid.getFileLength() == di.lastProgress);
+               if (ok && 
prefs.testString("GNUNET-DOWNLOAD","RECURSIVE","YES")) {
+                       /* download files in directory! */
+                       MappedFile      exp;
+                       FileLocation    loc;
+                       GNDirectory     dir;
+                       int                     i;
+
+                       loc=new FileLocation(di.filename);
+                       loc.create();
+
+                       exp = loc.open();
+                       dir=(GNDirectory) exp.asPersistent(GNDirectory.class);
+                       exp.close();
+
+                       if (dir == null) {
+                               return ok; /* not a directory */
+                               }
+
+                       for (i=0; i<dir.number_of_files; i++) {
+                               RootNode                rn;
+                               String          fn,rfn;
+
+                               rn=dir.contents[i];
+
+                               rfn=rn.getFileName();
+
+                               fn=di.filename;
+
+                               /* remove '.gnd' or add ".dir" */
+                               if (fn.endsWith(GNUNET_DIRECTORY_EXT)) {
+                                       
fn=fn.substring(0,fn.length()-GNUNET_DIRECTORY_EXT.length());
+                                       }
+                               else {
+                                       fn+=".dir";
+                                       }
+
+                               new DirLocation(fn).create(); /* create 
directory */
+
+                               fn+="/";
+                               fn+=rfn;
+
+                               scheduleDownload(rn.getFileIdentifier(),fn);
+                               }
+                       }
+               return ok;
+       }
+
+       protected void scheduleDownload( FileIdentifier fid, String filename )
+       {
+               DownloadInfo[]  tmp;
+
+               synchronized(lock) {
+                       tmp=new DownloadInfo[pendingCount+1];
+                       System.arraycopy(pending,0,tmp,0,pending.length);
+                       pending=tmp;
+                       pendingCount++;
+
+                       pending[pendingCount-1] = new DownloadInfo();
+                       pending[pendingCount-1].fid=(FileIdentifier) 
PersistentHelper.copy(fid);
+                       pending[pendingCount-1].filename = filename;
+                       pending[pendingCount-1].result = PENDING;
+                       pending[pendingCount-1].sem = null;
+                       }
+       }
+
+       protected Object process( DownloadInfo di ) throws InterruptedException
+       {
+               di.result = (downloadFileHelper(di) ? 1 : -1);
+               semSignal.release();
+               return null;
+       }
+
+       protected boolean run( int threadLimit ) throws InterruptedException
+       {
+               int             left,running,i;
+               boolean ret;
+
+               if (threadLimit == 0) /* should never happen */
+                       threadLimit = 1; /* need at least 1! */
+
+               ret = true;
+               semSignal = new Semaphore(threadLimit);
+
+               left = pendingCount;
+               running = 0;
+               while (left>0 || running>0) {
+                       if (left > 0) {
+                               semSignal.acquire();
+                               for (i=0; i<pendingCount; i++) {
+                                       final int       _i = i;
+
+                                       if (pending[i].result == PENDING) {
+                                               pending[i].result = RUNNING;
+
+                                               pending[i].thread=new 
Task("DOWNLOAD-"+i,new AbstractAction() {
+                                                       public void perform() 
throws Throwable
+                                                       {
+                                                               
process(pending[_i]);
+                                                       }
+                                                       });
+                                               pending[i].thread.launch();
+                                               break;
+                                               }
+                                       }
+                               }
+
+                       left = 0;
+                       running = 0;
+                       for (i=0;i<pendingCount;i++) {
+                               if (pending[i].result == PENDING) {
+                                       left++;
+                                       continue;
+                                       }
+                               if (pending[i].result == RUNNING) {
+                                       running++;
+                                       continue;
+                                       }
+                               if (pending[i].result == JOINED)
+                                       continue;
+                               if (pending[i].result == -1)
+                                       ret = false;
+                               pending[i].thread.join();
+                               pending[i].result = JOINED;
+                               }
+
+                       /* wait a bit */
+                       if (left==0 && running>0) {
+                               Scheduler.sleep(Scheduler.MILLIS_150);
+                               }
+                       }
+
+               /* wait for all threads to terminate */
+               for (i=0; i<threadLimit; i++) {
+                       semSignal.acquire();
+                       }
+
+               /* join on all */
+               for (i=0; i<pendingCount; i++) {
+                       assert(pending[i].result!=PENDING);
+
+                       if (pending[i].result == JOINED) {
+                               continue;
+                               }
+                       if (pending[i].result == -1) {
+                               ret = false;
+                               }
+                       pending[i].thread.join();
+                       pending[i].result = JOINED;
+                       }
+
+               pending=null;
+               pendingCount=0;
+               return ret;
+       }
+
+       public int run()
+       {
+               CSSession       sock;
+               int                             ret;
+
+               sock=connect();
+               if (sock==null) {
+                       log(Level.SEVERE,"Could not connect to gnunetd.");
+                       return -29;
+                       }
+               ret=run2(sock);
+               return ret;
+       }
+
+       /**
+        * @param sock
+        * @return return value from download file: 0: ok, -1, 1: error
+        */
+
+       public int run2( CSSession sock )
+       {
+               FileIdentifier  fid;
+               String                  filename,fstring;
+               int                             threadLimit;
+               boolean                 ok;
+
+               if (getArguments().length!=1) {
+                       log(Level.WARNING,"Not enough/too many arguments. You 
must specify exactly one GNUnet AFS URI.");
+                       getParser().printHelp();
+                       return -11;
+                       }
+
+               prefs.setString("GNUNET-DOWNLOAD","URI",getArguments()[0]);
+
+               filename = prefs.getString("GNUNET-DOWNLOAD","FILENAME",null);
+               if (filename == null) {
+                       log(Level.SEVERE,"You must specify a filename (option 
-o).");
+                       getParser().printHelp();
+                       return -11;
+                       }
+
+               priority=new Priority(this);
+
+               threadLimit = 
prefs.getInt("GNUNET-DOWNLOAD","PARALLELIZATION",0);
+               if (threadLimit == 0)
+                       threadLimit = 30; /* default */
+
+               filename = prefs.getString("GNUNET-DOWNLOAD","FILENAME",null);
+
+               fstring = prefs.getString("GNUNET-DOWNLOAD","URI",null);
+
+               fid=FileIdentifier.parseURI(fstring);
+               if(fid == null) {
+                       log(Level.SEVERE,"Can't proceed without a valid URI.");
+                       return -1;
+                       }
+
+               lock=new Object();
+               priority.startAFSPriorityTracker();
+
+               policy=new Policy(getPreferences(),connect());
+
+               scheduleDownload(fid,   filename);
+               try {
+                       ok=run(threadLimit);
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       ok=false;
+                       }
+
+               policy.doneAnonymityPolicy();
+               priority.stopAFSPriorityTracker();
+               return (ok ? 0 : 1);
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Main function to download files from GNUnet.
+        * @param args command line arguments
+        */
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetDownload.class,args);
+       }
+}
+
+class DownloadInfo extends Object
+{
+       public Semaphore                        sem;
+       public String                   filename;
+       public FileIdentifier           fid;
+       public long                             startTime;
+       public int                              lastProgress;
+       public int                              result;
+       public Task                             thread;
+}

Added: freeway/src/org/gnu/freeway/GNUNetInsert.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetInsert.java       2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetInsert.java       2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,791 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.protocol.afs.*;
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * Tool to insert or index files into GNUnet's AFS.
+ */
+
+public class GNUNetInsert extends AbstractClient implements AFSConstants
+{
+       private Prefs           prefs;
+       private List                    topKeywords;
+       private List                    gloKeywords;
+       private InsertUtil      insertUtil;
+       private boolean         printAndReturn;
+
+
+       public GNUNetInsert()
+       {
+               super("gnunet-insert",AFSProtocol.VERSION);
+               prefs=getPreferences();
+               prefs.setString("GNUNET-INSERT","INDEX-CONTENT","YES");
+               topKeywords=new ArrayList();
+               gloKeywords=new ArrayList();
+               insertUtil=new InsertUtil(prefs);
+               printAndReturn=false;
+       }
+
+       public String toString()
+       {
+               return "Insert";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-insert [OPTIONS] 
FILENAME*","Make files available to GNUnet for sharing.");
+               options.setAllowArguments(true);
+               options.addOption(new Option("builddir|b","build a directory 
listing all processed files") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","BUILDDIR","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_CONFIG);
+               options.addOption(new Option("desc|D|DESCRIPTION","set 
description for all files") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","DESCRIPTION",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("sprev|e|FILENAME","filename of 
the SBlock of a previous version of the content (for namespace insertions 
only)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","PREVIOUS_SBLOCK",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("extract|E","print list of 
extracted keywords that would be used, but do not perform insertion or 
indexing") {
+                       public boolean exec( Command c )
+                       {
+                               printAndReturn = true;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("name|f|NAME","publish NAME as the 
name of the file or directory") {
+                       public boolean exec( Command c )
+                       {
+                               String  root;
+                               int             index;
+
+                               
prefs.setString("GNUNET-INSERT","FILENAME",getValue());
+
+                               root = 
prefs.getString("GNUNET-INSERT","FILENAMEROOT",null);
+                               if (root == null) {
+                                       // if filename is '/home/user/foo', use 
'foo' as the filenameRoot
+                                       root = getValue();
+                                       
index=root.lastIndexOf(File.separatorChar);
+                                       root=(index>=0 ? 
root.substring(index+1) : root);
+                                       }
+                               
prefs.setString("GNUNET-INSERT","FILENAMEROOT",root);
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(new Option("interval|i|SECONDS","set interval 
for availability of updates to SECONDS (for namespace insertions only)") {
+                       public boolean exec( Command c )
+                       {
+                               int     interval;
+
+                               try {
+                                       interval=Integer.parseInt(getValue());
+                                       
prefs.setInt("GNUNET-INSERT","INTERVAL",interval);
+                                       }
+                               catch( NumberFormatException x ) {
+                                       log(Level.SEVERE,"You must pass a 
positive number to the -i option.");
+                                       return false;
+                                       }
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("key|k|KEYWORD","add an additional 
keyword for the top-level file or directory (this option can be specified 
multiple times)") {
+                       public boolean exec( Command c )
+                       {
+                               topKeywords.add(getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("global-key|K|KEYWORD","add an 
additional keyword for all files and directories (this option can be specified 
multiple times)") {
+                       public boolean exec( Command c )
+                       {
+                               gloKeywords.add(getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("link|l","if gnunetd is running on 
the local machine, create a link instead of making a copy in the GNUnet share 
directory") {
+                       public boolean exec( Command c )
+                       {
+                               prefs.setString("GNUNET-INSERT","LINK","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("mime|m|MIMETYPE","set the 
mimetype for the file to be MIMETYPE") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","MIMETYPE",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("noindex|n","do not index, perform 
full insertion (stores entire file in encrypted form in GNUnet database)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","INDEX-CONTENT","NO");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("next|N|ID","specify ID of an 
updated version to be published in the future (for namespace insertions only)") 
{
+                       public boolean exec( Command c )
+                       {
+                               HashCode160     nextId;
+
+                               nextId=HashCode160.parse(getValue());
+                               if (nextId==null)
+                                       nextId=HashCode160.create(getValue());
+                               
prefs.setString("GNUNET-INSERT","NEXTHASH",nextId.toHex());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("sout|o|FILENAME","write the 
created SBlock in plaintext to FILENAME (for namespace insertions only)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","OUTPUT_SBLOCK",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("prio|p|PRIORITY","specify the 
priority of the content") {
+                       public boolean exec( Command c )
+                       {
+                               int     contentPriority;
+
+                               try {
+                                       
contentPriority=Integer.parseInt(getValue());
+                                       
prefs.setInt("GNUNET-INSERT","CONTENT-PRIORITY",contentPriority);
+                                       }
+                               catch( NumberFormatException x ) {
+                                       log(Level.SEVERE,"You must pass a 
number to the -p option.");
+                                       return false;
+                                       }
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("pass|P|PASSWORD","use PASSWORD to 
decrypt the secret key of the pseudonym (for namespace insertions only)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","PASSWORD",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("recursive|R","process directories 
recursively") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","RECURSIVE","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("pseudonym|s|NAME","publish the 
files under the pseudonym NAME (place file into namespace)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","PSEUDONYM",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("sporadic|S","specifies this as an 
aperiodic but updated publication (for namespace insertions only)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","SPORADIC","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("this|t|ID","set the ID of this 
version of the publication (for namespace insertions only)") {
+                       public boolean exec( Command c )
+                       {
+                               HashCode160     thisId;
+
+                               thisId=HashCode160.parse(getValue());
+                               if (thisId==null)
+                                       thisId=HashCode160.create(getValue());
+                               
prefs.setString("GNUNET-INSERT","THISHASH",thisId.toHex());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("time|T|TIME","specify creation 
time for SBlock (see man-page for format)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","INSERTTIME",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("url|u","print the GNUnet URL of 
the inserted file(s)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","PRINTURL","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               options.addOption(new Option("verbose|V","be verbose") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","VERBOSE","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("noextraction|x","disable 
automatic metadata extraction") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","EXTRACT-KEYWORDS","NO");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("nodirectindex|X","disable 
generation of RBlocks for keywords extracted from each file") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-INSERT","ADDITIONAL-RBLOCKS","NO");
+                               return true;
+                       }
+                       });
+               return options;
+       }
+
+       /**
+        * Print progess message.
+        *
+        * @param stats
+        * @param verbose
+        */
+
+       protected void printstatus( ProgressStats stats, boolean[] verbose )
+       {
+               if (verbose[0]) {
+                       System.out.print(stats.progress+" of "+stats.filesize+" 
bytes inserted\r");
+                       System.out.flush();
+                       }
+       }
+
+       protected PrivateKey getUsedPseudonym()
+       {
+               PrivateKey      key;
+               String          user,password;
+
+               key=null;
+
+               user=prefs.getString("GNUNET-INSERT","PSEUDONYM",null);
+               if (user!=null) {
+                       
password=prefs.getString("GNUNET-INSERT","PASSWORD",null);
+                       key=new Pseudonym(prefs).readPseudonym(user,password);
+                       if (key==null) {
+                               System.out.println("Could not read pseudonym 
"+user+" (does not exist or password invalid).");
+                               }
+                       }
+               return key;
+       }
+
+       public int run()
+       {
+               CSSession       sock;
+               int                             ret;
+
+               sock=connect();
+               if (sock==null) {
+                       log(Level.SEVERE,"Could not connect to gnunetd.");
+                       return -29;
+                       }
+               ret=run2(sock);
+               return ret;
+       }
+
+       public int run2( CSSession sock )
+       {
+               RootNode[]              roots;
+               String[]                        fileNames,keywords;
+               Extractor[]             extractors;
+               PrivateKey              pseudonym;
+               RootNode                        r;
+               String                  fileName,description,mimetype,shortFN;
+               int                             
fileNameCount,i,num_keywords,interval,skip;
+               boolean[]               verbose;
+               String[]                        filesToInsert;
+               FileIdentifier  fid=null;       //todo: utilisation de 'fid' a 
eclaircir
+
+               filesToInsert=getArguments();
+               if (filesToInsert.length==0) {
+                       log(Level.WARNING,"You must specify a list of files to 
insert.");
+                       getParser().printHelp();
+                       return -11;
+                       }
+
+               if (printAndReturn) {
+                       Extractor[]     l;
+
+                       l=new KeyWords().getExtractors();
+                       for (i=0; i<filesToInsert.length; i++) {
+                               System.out.println("Keywords for file 
"+filesToInsert[i]+":");
+
+                               String[]                k=new 
KeyWords().extractKeywords(new File(filesToInsert[i]),null,null,l);
+                               System.out.println(Arrays.asList(k));
+                               }
+                       return 0;
+                       }
+
+               verbose = new boolean[1];
+               verbose[0]=prefs.testString("GNUNET-INSERT","VERBOSE","YES");
+
+               // check arguments
+               pseudonym=getUsedPseudonym();
+
+               /* fixme: other sanity checks here? */
+
+               fileNameCount = filesToInsert.length;
+               fileNames = filesToInsert;
+
+               if ( ( prefs.testString("GNUNET-INSERT","BUILDDIR","YES") || 
prefs.testString("GNUNET-INSERT","RECURSIVE","YES") || (fileNameCount > 1) ) && 
(null != prefs.getString("GNUNET-INSERT","FILENAMEROOT",null) ) ) {
+                       log(Level.SEVERE,"FATAL: the options -b, -r or multiple 
file arguments can not be used together with option -f.");
+                       return -1;
+                       }
+
+               if (pseudonym == null) {
+                       if (null != 
prefs.getString("GNUNET-INSERT","NEXTHASH",null)) {
+                               log(Level.SEVERE,"FATAL: Option -N makes no 
sense without -P");
+                               return -1;
+                               }
+                       if (null != 
prefs.getString("GNUNET-INSERT","THISHASH",null)) {
+                               log(Level.SEVERE,"FATAL: Option -t makes no 
sense without -P");
+                               return -1;
+                               }
+                       if (null != 
prefs.getString("GNUNET-INSERT","PASSWORD",null)) {
+                               log(Level.SEVERE,"FATAL: Option -P makes no 
sense without -P");
+                               return -1;
+                               }
+                       if (0 != prefs.getInt("GNUNET-INSERT","INTERVAL",0)) {
+                               log(Level.SEVERE,"FATAL: Option -i makes no 
sense without -P");
+                               return -1;
+                               }
+                       if (prefs.testString("GNUNET-INSERT","SPORADIC","YES")) 
{
+                               log(Level.SEVERE,"FATAL: Option -S makes no 
sense without -P");
+                               return -1;
+                               }
+                       }
+
+               if (prefs.testString("GNUNET-INSERT","EXTRACT-KEYWORDS","NO") 
&& prefs.testString("GNUNET-INSERT","ADDITIONAL-RBLOCKS","NO") )
+                       System.out.println("WARNING: -X is implied by -x.");
+
+
+               /* fundamental init */
+               if (sock == null) {
+                       log(Level.SEVERE,"FATAL: could not connect to 
gnunetd.");
+                       return -5;
+                       }
+
+               extractors = new KeyWords().getExtractors();
+
+               mimetype = prefs.getString("GNUNET-INSERT","MIMETYPE",null);
+
+               roots = new RootNode[fileNameCount];
+               skip = 0;
+               fileName = null;
+               for (i=0; i<fileNameCount; i++) {
+                       fileName = new FileLocation(fileNames[i]).getPath();
+
+                       r=insertUtil.insertRecursively(sock,
+                                       fileName,
+                                       (String[]) gloKeywords.toArray(new 
String[gloKeywords.size()]),
+                                       gloKeywords.size(),
+                                       Arrays.asList(extractors),
+                                       new ProgressModel() {
+                                               public void progress( 
ProgressStats stats, Object data )
+                                               {
+                                                       
printstatus(stats,(boolean[]) data);
+                                               }
+                                               },
+                                       verbose,
+                                       new InsertWrapper() {
+                                               public FileIdentifier insert( 
CSSession sockx, String filename, Object closure )
+                                               {
+                                                       return 
doFile(sockx,filename,(boolean[]) closure);
+                                               }
+                                               },
+                                       verbose);
+                       if (r != null) {
+                               fid=r.getFileIdentifier();
+                               roots[i]=(RootNode) PersistentHelper.copy(r);
+                               }
+                       else {
+                               fid=null;
+                               skip++;
+                               }
+                       }
+               if ( (fileNameCount == 1) && new 
DirLocation(fileName).exists()) {
+                       mimetype = GNUNET_DIRECTORY_MIME;
+                       }
+
+               shortFN = prefs.getString("GNUNET-INSERT","FILENAME",null);
+               if ( (shortFN == null) && (fileName != null)) {
+                       int index=fileName.lastIndexOf(File.separatorChar);
+                       shortFN = fileName.substring(index+1);
+                       }
+               fileNameCount -= skip;
+
+               // if build directory and > 1 file, build directory and reduce 
to 1 file
+               if (fileNameCount>1 && 
prefs.testString("GNUNET-INSERT","BUILDDIR","YES") ) {
+                       fileName = 
prefs.getString("GNUNET-INSERT","FILENAMEROOT",null);
+                       if (fileName == null)
+                               fileName = "no name specified";
+
+                       
fid=insertUtil.insertDirectory(sock,fileNameCount,roots,fileName,
+                               new ProgressModel() {
+                                       public void progress( ProgressStats 
stats, Object data )
+                                       {
+                                               printstatus(stats,(boolean[]) 
data);
+                                       }
+                                       },verbose);
+
+                       if (fid==null) {
+                               skip += fileNameCount;
+                               fileNameCount = 0;
+                               }
+                       else {
+                               if 
(prefs.testString("GNUNET-INSERT","PRINTURL",        "YES")) {
+                                       System.out.println(fid.toURI());
+                                       }
+
+                               if (verbose[0]) {
+                                       System.out.println("Directory 
"+fileName+" successfully indexed -- "+fid.toURI());
+                                       }
+
+                               description = 
prefs.getString("GNUNET-INSERT","DESCRIPTION",null);
+                               if (description == null) {
+                                       description = "no description supplied";
+                                       }
+
+                               r=insertUtil.buildDirectoryRBlock(sock,
+                                               fid,
+                                               fileName,
+                                               description,
+                                               (String[]) 
gloKeywords.toArray(new String[gloKeywords.size()]),
+                                               gloKeywords.size());
+                               mimetype = GNUNET_DIRECTORY_MIME;
+                               skip = fileNameCount - 1;
+                               fileNameCount = 1;
+                               }
+                       }
+
+               num_keywords = 0;
+               keywords = null;
+
+               /* if fileNameCount == 1 and !isDirectory(fileName): run 
libextractor! */
+               description = 
prefs.getString("GNUNET-INSERT","DESCRIPTION",null);
+               if (fileNameCount==1 && !new DirLocation(fileName).exists()) {
+                       if 
(!prefs.testString("GNUNET-INSERT","EXTRACT-KEYWORDS","NO")) {
+                               keywords=new 
KeyWords().extractKeywordsMulti(fileName,description,mimetype,extractors);
+                               }
+                       }
+               if (mimetype == null)
+                       mimetype = "unknown";
+               if (description == null)
+                       description = "no description supplied";
+
+               /* if a directory, add mimetype as key unless forbidden */
+               if (mimetype.equals(GNUNET_DIRECTORY_MIME) && 
!prefs.testString("GNUNET-INSERT","ADDITIONAL-RBLOCKS","NO")) {
+                       topKeywords.add(GNUNET_DIRECTORY_MIME);
+                       }
+
+               /* if fileNameCount == 1, add RBlocks for all keywords */
+               if ( fileNameCount == 1) {
+                       r = new RootNode(fid);
+                       r.setDescription(description);
+                       r.setFileName(shortFN);
+                       r.setMimeType(mimetype);
+
+                       for (i=0;i<gloKeywords.size();i++) {
+                               insertRBlock(sock,r, (String) 
gloKeywords.get(i));
+                               System.out.println("Inserting "+shortFN+" 
("+description+", "+mimetype+") under keyword "+gloKeywords.get(i)+".");
+                               }
+                       for (i=0; i<topKeywords.size(); i++) {
+                               insertRBlock(sock,r, (String) 
topKeywords.get(i));
+                               System.out.println("Inserting "+shortFN+" 
("+description+", "+mimetype+") under keyword "+topKeywords.get(i)+".");
+                               }
+
+                       if (! 
prefs.testString("GNUNET-INSERT","ADDITIONAL-RBLOCKS","NO") )
+                               for (i=0;i<num_keywords;i++) {
+                                       insertRBlock(sock,r, keywords[i]);
+                                       System.out.println("Inserting 
"+shortFN+" ("+description+", "+mimetype+") under keyword "+keywords[i]+".");
+                                       }
+                       }
+
+               /* if SBlock and == 1 file, create SBlock */
+               if ( (pseudonym != null) && (fileNameCount == 1) ) {
+                       HashCode160     thisId=new HashCode160();
+                       HashCode160     nextId;
+                       String          hx;
+                       String          prevname;
+                       int                     creationTime;
+                       int                     now;
+                       String          timestr;
+                       Date            d;
+
+                       timestr = 
prefs.getString("GNUNET-INSERT","INSERTTIME",null);
+                       if(timestr != null) {
+                               try {
+                                       d=new SimpleDateFormat("dd-MM-yyyy 
HH:mm").parse(timestr);
+                                       }
+                               catch( ParseException x ) {
+                                       err("Parsing time failed. Use 
\"DAY-MONTHNUMBER-YEAR HOUR:MINUTE\" format",x);
+                                       return -2;
+                                       }
+                               now = (int) (d.getTime()/1000);
+                               log(Level.FINEST,"DEBUG: read time 
"+DateFormat.getInstance().format(d));
+                               }
+                       else {
+                               /* use current time */
+                               now=(int) Scheduler.toSeconds(Scheduler.now());
+                               }
+
+                       prevname = 
prefs.getString("GNUNET-INSERT","PREVIOUS_SBLOCK",null);
+                       if(prevname != null) {
+                               /* options from the previous sblock override */
+                               SBlock          pb;
+                               PublicKey       pkey;
+                               MappedFile      f;
+
+                               f=new FileLocation(prevname).open();
+                               pb=(f!=null ? (SBlock) 
f.asPersistent(SBlock.class) : null);
+                               if (f!=null) {
+                                       f.close();
+                                       }
+                               if (pb==null) {
+                                       log(Level.SEVERE,"SBlock in 
"+prevname+" either doesn't exist or is malformed");
+                                       return -3;
+                                       }
+                               /* check that it matches the selected pseudonym 
*/
+                               pkey=pseudonym.toPublicKey();
+                               if (!pkey.equals(pb.getPublisherKey())) {
+                                       log(Level.SEVERE,"Given SBlock doesn't 
match the selected pseudonym");
+                                       return -4;
+                                       }
+
+                               if (!pb.verify()) {
+                                       log(Level.SEVERE,"Verification of 
SBlock in "+prevname+" failed");
+                                       return -5;
+                                       }
+                               new 
Pseudonym(prefs).addNamespace(pb.getPublisherNameSpace());
+
+                               interval = pb.getUpdateInterval();
+
+                               /* now, compute CURRENT ID and next ID */
+                               thisId=pb.computeIdAtTime(now);
+                               if ( (interval != SBLOCK_UPDATE_NONE) && 
(interval != SBLOCK_UPDATE_SPORADIC) ) {
+                                       int delta;
+
+                                       /* periodic update */
+                                       delta = now - pb.getCreationTime();
+                                       delta = delta / pb.getUpdateInterval();
+                                       if (delta <= 0)
+                                               delta = 1; /* force to be in 
the future from the updated block! */
+                                       creationTime = pb.getCreationTime() + 
delta * pb.getUpdateInterval();
+
+                                       /* periodic update, compute _next_ ID 
as increment! */
+                                       nextId=new HashCode160(thisId); /* n = 
k + inc */
+                                       nextId.add(pb.getIdentifierIncrement());
+                                       }
+                               else {
+                                       creationTime = now;
+                                       if (interval == SBLOCK_UPDATE_SPORADIC) 
{
+                                               log(Level.FINEST,"DEBUG: 
sporadic update in sblock...");
+                                               hx = 
prefs.getString("GNUNET-INSERT","NEXTHASH",null);
+                                               if (hx == null) {
+                                                       
nextId=HashCode160.random();
+                                                       }
+                                               else {
+                                                       
nextId=HashCode160.parse(hx);
+                                                       if (nextId==null) {
+                                                               
nextId=HashCode160.create(hx);
+                                                               }
+                                                       }
+                                               }
+                                       else {
+                                               log(Level.SEVERE,"FATAL: trying 
to update nonupdatable sblock");
+                                               return -6;
+                                               }
+                                       }
+                               }
+                       else {
+                               /* no previous sblock specified */
+                               creationTime = now;
+                               interval = 
prefs.getInt("GNUNET-INSERT","INTERVAL",0);
+
+                               hx = 
prefs.getString("GNUNET-INSERT","THISHASH",null);
+
+                               thisId=HashCode160.parse(hx);
+                               if (thisId==null) {
+                                       thisId=HashCode160.create(hx);
+                                       }
+
+                               hx = 
prefs.getString("GNUNET-INSERT","NEXTHASH",null);
+                               if (hx == null) {
+                                       if (interval == SBLOCK_UPDATE_NONE) {
+                                               /* no next id and no interval 
specified, to be    */
+                                               /* consistent with gnunet-gtk, 
nextId == thisId   */
+                                               nextId=(HashCode160) 
PersistentHelper.copy(thisId);
+                                               }
+                                       else {
+                                               nextId=HashCode160.random();
+                                               }
+                                       }
+                               else {
+                                       nextId=HashCode160.parse(hx);
+                                       if (nextId==null) {
+                                               nextId=HashCode160.create(hx);
+                                               }
+
+                                       if (interval == SBLOCK_UPDATE_NONE) {
+                                               /* if next was specified, 
aperiodic is default */
+                                               interval = 
SBLOCK_UPDATE_SPORADIC;
+                                               }
+                                       }
+                               if 
(prefs.testString("GNUNET-INSERT","SPORADIC","YES"))
+                                       interval = SBLOCK_UPDATE_SPORADIC;
+                               }
+
+
+                       log(Level.FINEST,"Building SBlock "+shortFN+": 
"+description+" -- "+mimetype);
+                       log(Level.FINEST,"Building SBlock with key 
"+thisId.toHex()+" and next key "+nextId.toHex());
+
+                       SBlock  sb;
+                       EncryptedSBlock esb;
+
+                       sb=new SBlock(fid);
+                       sb.setDescription(description);
+                       sb.setFileName(shortFN);
+                       sb.setMimeType(mimetype);
+                       sb.setCreationTime(creationTime);
+                       sb.setUpdateInterval(interval);
+
+                       esb=sb.encryptAndSign(pseudonym,thisId,nextId);
+                       if (esb==null) {
+                               trace("Insertion failure !");
+                               return -101;
+                               }
+
+                       log(Level.FINEST,"Building SBlock for namespace 
"+sb.getPublisherNameSpace().toHex()+" and query "+sb.getIdentifier().toHex());
+
+                       new 
GNDirectoryDatabase(prefs).makeRootNodeAvailable(sb,DIR_CONTEXT_INSERT_SB);
+
+                       if (insertUtil.insert(esb,sock)) {
+                               String  outname;
+
+                               outname = 
prefs.getString("GNUNET-INSERT","OUTPUT_SBLOCK",null);
+                               if (outname != null) {
+                                       MappedFile      mm;
+
+                                       mm=new FileLocation(outname).openNew();
+                                       mm.writePersistent(sb);
+                                       mm.close();
+                                       }
+
+                               /* FIXME: until URI is decided for sblocks, 
stick to SPACE KEY -format */
+                               System.out.println("File "+shortFN+" 
("+description+","+mimetype+") successfully inserted into namespace under  
"+sb.getPublisherNameSpace().toHex()+" "+thisId.toHex());
+                               }
+                       else
+                               System.out.println("Insertion of file into 
namespace failed.");
+                       }
+               return 0;
+       }
+
+       /**
+        * Insert a single file.
+        *
+        * @param sock
+        * @param filename the name of the file to insert
+        * @param verbose
+        * @return resulting file identifier for the node on success, null on 
error
+        */
+
+       protected FileIdentifier doFile( CSSession sock, String filename, final 
boolean[] verbose )
+       {
+               Block                   top;
+               FileIdentifier  fid;
+               long                            startTime;
+
+               startTime=Scheduler.now();
+               if (verbose[0]) {
+                       System.out.println("Working on file "+filename+"...");
+                       }
+
+               top = insertUtil.insertFile(sock,filename,new ProgressModel() {
+                       public void progress( ProgressStats stats, Object data )
+                       {
+                               printstatus(stats,(boolean[]) data);
+                       }
+                       },null);
+
+               if (top == null) {
+                       System.out.println("Error inserting file "+filename+". 
You may want to check whether or not you are out of space. Run gnunet-stats | 
grep \"AFS storage left\" to check.");
+                       return null;
+                       }
+
+               fid=new FileIdentifier(top);
+               if (prefs.testString("GNUNET-INSERT","PRINTURL","YES")) {
+                       System.out.println(fid.toURI());
+                       }
+
+               if (verbose[0]) {
+                       long    elapsed,speed;
+
+                       System.out.println("File "+filename+" successfully 
indexed -- "+fid.toURI());
+
+                       elapsed=Scheduler.toMillis(Scheduler.now()-startTime);
+                       if (elapsed==0) {
+                               elapsed=1;
+                               }
+                       speed=(1000*top.getFileSize())/elapsed;
+                       System.out.println("Speed was 
"+IOUtils.newSizeFormatter().format(new Long(speed))+" per second 
("+top.getFileSize()+" bytes in "+elapsed+" ms).");
+                       }
+               top.destroy(null);
+               return fid;
+       }
+
+       /**
+        * Insert the given RBlock into GNUnet.
+        *
+        * @param sock
+        * @param rb the root node
+        * @param keyword the keyword to use
+        */
+
+       public void insertRBlock( CSSession sock, RootNode rb, String keyword )
+       {
+               if 
(!insertUtil.insertRootWithKeyword(sock,rb,keyword,prefs.getInt("GNUNET-INSERT","CONTENT-PRIORITY",0)))
+                       System.out.println("ERROR inserting root node. Is 
gnunetd running and space available?");
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetInsert.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetPeerInfo.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetPeerInfo.java     2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetPeerInfo.java     2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,134 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.transport.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+
+import java.util.logging.*;
+
+/**
+ * Print information about other known peers.
+ */
+
+public class GNUNetPeerInfo extends AbstractServer
+{
+       private static final String     TRUSTDIR                =       
"data/credit/";
+       private static final String     EOL                     =       
System.getProperty("line.separator");
+
+       private DirLocation     trustDirectory;
+
+
+       public GNUNetPeerInfo()
+       {
+               super("gnunet-peer-info",Utils.makeVersion(0,9));
+       }
+
+       public String toString()
+       {
+               return "Peer info";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-peer-info [OPTIONS]","Print 
information about GNUnet peers.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       public int run()
+       {
+               trustDirectory=getHome().getDirectory(TRUSTDIR);
+               trustDirectory.create();
+
+               ((KnownHostsService) 
service(KnownHostsService.class)).forEachHost(new HostIterator() {
+                       public void iterate( HostIdentity identity, int 
protocol, Object data )
+                       {
+                               printHostInfo(identity,protocol,data);
+                       }
+                       },0,null);
+               return 0;
+       }
+
+       /**
+        * Print information about the peer.
+        * Currently prints the HostIdentity, trust and the IP.
+        * Could of course do more (e.g. resolve via DNS).
+        * @param id
+        * @param proto
+        * @param data
+        */
+
+       protected void printHostInfo( HostIdentity id, int proto, Object data )
+       {
+               P2PHello                helo;
+               MappedFile      f;
+               FileLocation    loc;
+               StringBuffer    bb;
+               String          str;
+               long                    t;
+               int                     trust;
+               Transport       tr;
+
+               helo=((KnownHostsService) 
service(KnownHostsService.class)).identity2HELO(id,proto,false);
+               if (helo==null) {
+                       log(Level.WARNING,"Could not obtain HELO 
("+id.getName()+").");
+                       return;
+                       }
+
+               if (!helo.verify()) {
+                       log(Level.WARNING,"Could not verify HELO 
("+id.getName()+").");
+                       return;
+                       }
+
+               tr=((TransportService) 
service(TransportService.class)).getTransport(helo);
+               str=(tr!=null ? tr.addressToString(helo) : null);
+               if (str==null) {
+                       log(Level.WARNING,"Could not convert HELO to string 
("+id.getName()+").");
+                       return;
+                       }
+
+               trust=0;
+               loc=trustDirectory.getFile(id.getName());
+               if (loc.exists()) {
+                       f=loc.open();
+                       if (f!=null) {
+                               if (loc.getSize()==4) {
+                                       trust=f.readInt(0);
+                                       }
+                               f.close();
+                               }
+                       }
+
+               t=((TransportService) 
service(TransportService.class)).getLastNotConnect(helo);
+
+               bb=new StringBuffer();
+               bb.append("          host : "+id.getName()+EOL);
+               bb.append("         trust : "+trust+EOL);
+               bb.append("       address : "+str+EOL);
+               bb.append(" connectable ? : "+(t>0 ? "not since 
"+Scheduler.toSeconds(Scheduler.now()-t)+"s" : "don't know")+EOL);
+               System.out.println(bb);
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetPeerInfo.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetPseudonym.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetPseudonym.java    2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetPseudonym.java    2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,157 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.util.logging.*;
+
+/**
+ * create a new pseudoynm
+ * delete a pseudoynm
+ * list all available pseudoynms
+ * create, list or delete pseudoynms
+ */
+
+public class GNUNetPseudonym extends AbstractClient
+{
+       private Prefs   prefs;
+
+
+       public GNUNetPseudonym()
+       {
+               super("gnunet-pseudonym",Utils.makeVersion(1,1,0));
+               prefs=getPreferences();
+       }
+
+       public String toString()
+       {
+               return "Pseudonym management";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-pseudonym [OPTIONS]","List 
existing, create or delete pseudonyms.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(new Option("create|C|NAME","create a new 
pseudonym (with the given password if specified)") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("PSEUDONYM","CREATE",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("delete|D|NAME","delete the given 
pseudonym") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("PSEUDONYM","DELETE",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("password|p|PASS","use the given 
password for the new pseudonym or to decrypt pseudonyms from the pseudonym 
database") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("PSEUDONYM","PASSWORD",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("quiet|q","do not list the 
pseudonyms from the pseudonym database") {
+                       public boolean exec( Command c )
+                       {
+                               prefs.setString("PSEUDONYM","QUIET","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       public int run()
+       {
+               String[]                list;
+               PrivateKey      hk;
+               String          pname,pass;
+               int                     success;
+               int                     i;
+               String          id;
+               PrivateKey      p;
+               PublicKey       pk;
+               HashCode160     hc;
+               Pseudonym       pseudo;
+
+               pseudo=new Pseudonym(prefs);
+
+               success = 0; /* no errors */
+
+               pname =prefs.getString("PSEUDONYM","DELETE",null);
+               if (pname != null) {
+                       if (pseudo.deletePseudonym(pname)) {
+                               System.out.println("Pseudonym "+pname+" 
deleted.");
+                               }
+                       else {
+                               success += 2;
+                               System.out.println("Error deleting pseudonym 
"+pname+" (does not exist ?).");
+                               }
+                       }
+
+               pass = prefs.getString("PSEUDONYM","PASSWORD",null);
+               pname = prefs.getString("PSEUDONYM","CREATE",null);
+               if (pname != null) {
+                       if (pass==null || pass.length()==0) {
+                               log(Level.WARNING,"No password supplied.");
+                               }
+                       hk=pseudo.createPseudonym(pname,pass);
+                       if (hk==null) {
+                               System.out.println("Could not create pseudonym 
"+pname+" (exists ?).");
+                               success++;
+                               }
+                       else {
+                               System.out.println("Pseudonym "+pname+" 
created.");
+                               }
+                       }
+
+               if (prefs.testString("PSEUDONYM","QUIET","YES"))
+                       return success; /* do not print! */
+
+               list=pseudo.listPseudonyms();
+               if (list==null) {
+                       System.out.println("Could not access pseudonym 
directory.");
+                       return 127;
+                       }
+               for (i=0; i<list.length; i++) {
+                       p=pseudo.readPseudonym(list[i],pass);
+                       if (p!=null) {
+                               pk=p.toPublicKey();
+                               
hc=HashCode160.create(PersistentHelper.toBytes(pk));
+
+                               id=hc.toHex();
+                               }
+                       else {
+                               id = "not decrypted";
+                               }
+                       System.out.println(list[i]+" "+id);
+                       }
+               return success;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetPseudonym.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetSearch.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetSearch.java       2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetSearch.java       2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,409 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import java.io.*;
+import java.util.logging.*;
+
+/**
+ * Main function to search for files on GNUnet.
+ *
+ * Todo: namespace search should be more like the normal
+ * search (add cron for repeated queries, allow multiple results).
+ * But this requires some changes in esed2-lib first!
+ *
+ * OTOH, it would also probably be good if we had a convenience
+ * method for printing RBlocks in esed2-lib like what we have
+ * for SBlocks.
+ */
+
+public class GNUNetSearch extends AbstractClient implements AFSConstants
+{
+       private Prefs   prefs;
+       private Policy  policy;
+
+
+       public GNUNetSearch()
+       {
+               super("gnunet-search",Utils.makeVersion(1,1,0));
+               prefs=getPreferences();
+               policy=null;
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-search [OPTIONS] KEYWORD [AND 
KEYWORD]*","Search GNUnet for files.");
+               options.setAllowArguments(true);
+               options.addOption(new Option("anonymity|a|LEVEL","set the 
desired LEVEL of receiver-anonymity") {
+                       public boolean exec( Command c )
+                       {
+                               int     receivePolicy;
+
+                               receivePolicy=getIntValue(-1);
+                               if (receivePolicy<0) {
+                                       log(Level.WARNING,"FAILURE: You must 
pass a number to the -a option.");
+                                       return false;
+                                       }
+                               
prefs.setInt("AFS","ANONYMITY-RECEIVE",receivePolicy);
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("max|m|LIMIT","exit after 
receiving LIMIT results") {
+                       public boolean exec( Command c )
+                       {
+                               int     max;
+
+                               max=getIntValue(-1);
+                               if (max<=0) {
+                                       log(Level.WARNING,"You must pass a 
number to the -m option.");
+                                       return false;
+                                       }
+                               prefs.setInt("AFS","MAXRESULTS",max);
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("namespace|n|HEX","only search the 
namespace identified by HEX") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-SEARCH","NAMESPACE",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("output|o|PREFIX","write 
encountered (decrypted) search results to the file PREFIX") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-SEARCH","OUTPUT_PREFIX",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("timeout|t|TIMEOUT","wait TIMEOUT 
seconds for search results before aborting") {
+                       public boolean exec( Command c )
+                       {
+                               int     timeout;
+
+                               timeout=getIntValue(-1);
+                               if (timeout<0) {
+                                       log(Level.WARNING,"You must pass a 
number to the -t option.");
+                                       return false;
+                                       }
+                               prefs.setInt("AFS","SEARCHTIMEOUT",timeout);
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       /**
+        * Handle the search result.
+        * @param rootNode
+        * @param sc
+        */
+
+       protected void handleNormalResult( RootNode rootNode, SearchClosure sc )
+       {
+               String  fstring,fname,prefix;
+
+               /* write rblock to file? */
+               prefix = prefs.getString("GNUNET-SEARCH","OUTPUT_PREFIX",null);
+               if (prefix != null) {
+                       String  outfile;
+
+                       
outfile=prefix+"."+Utils.alignRight(sc.resultCount++,3,'0');
+
+                       MappedFile      mm;
+
+                       mm=new FileLocation(outfile).openNew();
+                       mm.writePersistent(rootNode);
+                       mm.close();
+                       }
+
+               sc.max--;
+               fstring = rootNode.getFileIdentifier().toURI();
+
+               if (rootNode.getMimeType().equals(GNUNET_DIRECTORY_MIME)) {
+                       fname = 
GNDirectory.expandDirectoryName(rootNode.getFileName());
+                       }
+               else {
+                       fname = rootNode.getFileName();
+                       }
+
+               System.out.println("gnunet-download -o \""+fname+"\" "+fstring);
+               System.out.println("=> "+rootNode.getDescription()+" <= 
(mimetype: "+rootNode.getMimeType()+")");
+
+               if (sc.max==0) {
+                       shutdown(Signals.SIGUSR1);
+                       }
+       }
+
+       /**
+        * Handle namespace result.
+        * @param sb
+        * @param sqc
+        */
+
+       protected void handleNamespaceResult( SBlock sb, NSSearchClosure sqc )
+       {
+               HashCode160[]   tmp;
+               HashCode160             curK;
+               int                             i;
+               String                  prefix;
+
+               curK=HashCode160.create(PersistentHelper.toBytes(sb));
+
+               for (i=0;i<sqc.resultCount;i++) {
+                       if (curK.equals(sqc.results[i])) {
+                               log(Level.FINEST,"DEBUG: SBlock already 
seen\n");
+                               return; /* displayed already */
+                               }
+                       }
+
+               tmp=new HashCode160[sqc.resultCount+1];
+               System.arraycopy(sqc.results,0,tmp,0,sqc.resultCount);
+               sqc.results=tmp;
+               sqc.resultCount++;
+
+               sqc.results[sqc.resultCount-1]=(HashCode160) 
PersistentHelper.copy(curK);
+               sb.print(new PrintWriter(System.out,true));
+               sqc.max--;
+               /* write sblock to file */
+               prefix = prefs.getString("GNUNET-SEARCH","OUTPUT_PREFIX",null);
+               if (prefix != null) {
+                       String  outfile;
+
+                       
outfile=prefix+"."+Utils.alignRight(sqc.resultCount-1,3,'0');
+
+                       MappedFile      mm;
+
+                       mm=new FileLocation(outfile).openNew();
+                       mm.writePersistent(sb);
+                       mm.close();
+                       }
+               if (sqc.max==0) {
+                       shutdown(Signals.SIGUSR1);
+                       }
+       }
+
+       /**
+        * Perform a normal (non-namespace) search.
+        * @param sock
+        * @param keywords
+        */
+
+       protected void normalSearchMain( CSSession sock, String[] keywords )
+       {
+               final SearchClosure max=new SearchClosure();
+
+               max.max = prefs.getInt("AFS","MAXRESULTS",0);
+               max.resultCount = 0;
+               if (max.max == 0)
+                       max.max = Integer.MAX_VALUE; /* infty */
+
+               SendNSQueryContext.searchRBlock(
+                               prefs,getScheduler(),policy,
+                               sock,
+                               keywords,
+                               keywords.length,
+                               new SearchResultCallback() {
+                                       public void searchResult( RootNode root 
)
+                                       {
+                                               handleNormalResult(root,max);
+                                       }
+
+                                       public void newNameFor( RootNode root, 
String str )
+                                       {
+                                       }
+                                       },
+                               max,
+                               new TestTerminateThread() {
+                                       public boolean test()
+                                       {
+                                               return isShutdowning();
+                                       }
+                                       },
+                               null);
+               keywords=null;
+       }
+
+       /**
+        * Perform a namespace search.
+        * @param sock
+        * @param keywords
+        * @return
+        */
+
+       protected boolean namespaceSearchMain( CSSession sock, String[] 
keywords )
+       {
+               NSSearchClosure sqc;
+               HashCode160             namespace,identifier;
+               String                  nsstring,idstring;
+               int                             i;
+               boolean                 ret;
+
+               nsstring = prefs.getString("GNUNET-SEARCH","NAMESPACE",null);
+
+               sqc=new NSSearchClosure();
+               sqc.max = prefs.getInt("AFS","MAXRESULTS",0);
+               if (sqc.max == 0)
+                       sqc.max = Integer.MAX_VALUE; /* infty */
+               namespace=HashCode160.parse(nsstring);
+
+               idstring="";
+               for (i=0; i<keywords.length; i++) {
+                       idstring+=keywords[i];
+                       }
+               keywords=null;
+
+               identifier=HashCode160.parse(idstring);
+               if (identifier==null) {
+                       log(Level.FINEST,"DEBUG: namespace ID entered is not in 
HEX format, using hash of ASCII text ("+idstring+").");
+                       identifier=HashCode160.create(idstring);
+                       }
+
+               sqc.results = null;
+               sqc.resultCount = 0;
+               ret = new 
SendNSQueryContext().searchSBlock(policy,getScheduler(),prefs,
+                               sock,
+                               namespace,
+                               identifier,
+                               new TestTerminateThread() {
+                                       public boolean test()
+                                       {
+                                               return isShutdowning();
+                                       }
+                                       },
+                               new NSSearchResultCallback() {
+                                       public void searchResult( SBlock sb, 
Object data )
+                                       {
+                                               
handleNamespaceResult(sb,(NSSearchClosure) data);
+                                       }
+                                       },
+                               sqc);
+               if (!ret) {
+                       System.out.println("Sorry, nothing found.");
+                       }
+
+               sqc.results=null;
+               return ret;
+       }
+
+       public int run()
+       {
+               CSSession       sock;
+               int                             ret;
+
+               sock=connect();
+               if (sock==null) {
+                       log(Level.SEVERE,"Could not connect to gnunetd.");
+                       return -29;
+                       }
+               ret=run2(sock);
+               return ret;
+       }
+
+       /**
+        * The main function to search for files on GNUnet.
+        *
+        * @param sock
+        * @return return value from gnunetsearch: 0: ok, -1: error
+        */
+
+       public int run2( final CSSession sock )
+       {
+               Task            searchThread;
+               Priority        priority;
+               final String[]          keywords;
+
+               keywords=getArguments();
+               if (keywords.length==0) {
+                       log(Level.WARNING,"Not enough arguments. You must 
specify a keyword or identifier.");
+                       getParser().printHelp();
+                       return -11;
+                       }
+
+               if (sock == null) {
+                       log(Level.SEVERE,"Could not connect to gnunetd.");
+                       return -5;
+                       }
+
+               policy=new Policy(prefs,connect());
+
+               priority=new Priority(this);
+               priority.startAFSPriorityTracker();
+
+               searchThread=new Task("SEARCH",new AbstractAction() {
+                       public void perform()
+                       {
+                               String  ns;
+                               ns = 
prefs.getString("GNUNET-SEARCH","NAMESPACE",null);
+                               if (ns != null) {
+                                       namespaceSearchMain(sock,keywords);
+                                       }
+                               else {
+                                       normalSearchMain(sock,keywords);
+                                       }
+                       }
+                       });
+               searchThread.launch();
+
+               
waitForShutdown(Scheduler.seconds(prefs.getInt("AFS","SEARCHTIMEOUT",0)));
+
+               sock.disconnect();
+
+               priority.stopAFSPriorityTracker();
+
+               searchThread.join();
+
+               policy.doneAnonymityPolicy();
+               return 0;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * The main function to search for files on GNUnet.
+        *
+        * @param args command line arguments
+        */
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetSearch.class,args);
+       }
+}
+
+class SearchClosure extends Object
+{
+       public int      resultCount;
+       public int      max;
+}
+
+class NSSearchClosure extends Object
+{
+       public HashCode160[]    results;
+       public int                      resultCount;
+       public int                      max;
+}

Added: freeway/src/org/gnu/freeway/GNUNetShutdown.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetShutdown.java     2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetShutdown.java     2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,74 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.net.*;
+
+/**
+ *
+ */
+
+public class GNUNetShutdown extends AbstractClient
+{
+       public GNUNetShutdown()
+       {
+               super("gnunet-shutdown",Utils.makeVersion(0,6));
+       }
+
+       public String toString()
+       {
+               return "Shutdown";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-shutdown [OPTIONS]","Shutdown 
gracefully GNUnet daemon.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       public int run()
+       {
+               CSSession               sock;
+               CSResult        rv;
+//todo: verifier avec pid() (voir helper.c dans afs/gtkui)
+
+               sock=connect();
+               try {
+                       if (!sock.send(new CSShutdownRequest())) {
+                               return -1;
+                               }
+
+                       rv=(CSResult) sock.receive(CSResult.class);
+                       if (rv==null) {
+                               return -2;
+                               }
+                       }
+               finally {
+                       sock.disconnect();
+                       }
+               return 0;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetShutdown.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetStats.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetStats.java        2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetStats.java        2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,246 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.net.*;
+
+import java.io.*;
+import java.util.logging.*;
+
+/**
+ * Tool to obtain statistics from gnunetd.
+ */
+
+public class GNUNetStats extends AbstractClient
+{
+       private boolean printProtocols;
+       private int             minLevel;
+
+
+       public GNUNetStats()
+       {
+               super("gnunet-stats",Utils.makeVersion(2,0,1));
+               printProtocols=false;
+               minLevel=Stat.NORMAL;
+       }
+
+       public String toString()
+       {
+               return "Statistics";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-stats [OPTIONS]","Print 
statistics about GNUnet operations.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("protocols|p","prints supported 
protocol messages") {
+                       public boolean exec( Command c )
+                       {
+                               printProtocols=true;
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("min-level|m|LEVEL","set minimum 
level of verbosity to LEVEL") {
+                       public boolean exec( Command c )
+                       {
+                               minLevel=getIntValue(Stat.NORMAL);
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       public int run()
+       {
+               CSSession               sock;
+               PrintWriter             out;
+               boolean                 res;
+
+               sock=connect();
+               //todo: faire le test dans la superclasse!!!
+               if (sock==null) {
+                       log(Level.SEVERE,"Could not connect to gnunetd.");
+                       return -5;
+                       }
+
+               out=new PrintWriter(System.out);
+
+               res=requestAndPrintStatistics(out,sock);
+               if (res && printProtocols) {
+                       res=requestAndPrintProtocols(out,sock);
+                       }
+               printClients(out,sock);
+               out.flush();
+
+               sock.disconnect();
+               return (res ? 0 : 1);
+       }
+
+       /**
+        * Print statistics received from TCP socket.
+        * @param out where to print the statistics
+        * @param sock the socket to use
+        * @return OK on success, false on error
+        */
+
+       protected boolean requestAndPrintStatistics( PrintWriter out, CSSession 
sock )
+       {
+               Stat[]          stats;
+               CSStatistics            statMsg;
+               long                            t;
+               int                             totalCounters,count,i;
+
+               if (!sock.send(new CSStatisticsRequest(minLevel))) {
+                       out.println("Error sending request for statistics to 
gnunetd.");
+                       return false;
+                       }
+
+               out.println("Statistics :");
+
+               count=0;
+               totalCounters=1;
+
+               while (count<totalCounters) {
+                       statMsg=(CSStatistics) sock.receive(CSStatistics.class);
+                       if (statMsg==null) {
+                               out.println("Error receiving reply for 
statistics from gnunetd.");
+                               return false;
+                               }
+
+                       if (count==0) {
+                               t=Scheduler.toSeconds(Scheduler.now());
+                               t-=statMsg.getStartTime();
+
+                               out.println(Utils.alignRight("Uptime 
(seconds)",60)+" : "+Utils.alignLeft(t,16));
+                               totalCounters=statMsg.getTotalCounters();
+                               }
+
+                       if (statMsg.getTotalCounters()!=totalCounters) {
+                               out.println("Corrupted data ?");
+                               return false;
+                               }
+
+                       stats=statMsg.getStatistics();
+                       for (i=0; i<stats.length; i++) {
+                               
out.println(Utils.alignRight(stats[i].getName()+" /"+stats[i].getLevel(),60)+" 
: "+Utils.alignLeft(stats[i].get(),16));
+                               }
+                       count+=stats.length;
+                       }
+               out.println();
+               return true;
+       }
+
+       /**
+        * Queries the server for what protocol messages are supported and 
prints a list of them.
+        *
+        * @param out where to print the statistics
+        * @param sock the socket to use
+        * @return true on success, false on error
+        */
+
+       protected boolean requestAndPrintProtocols( PrintWriter out, CSSession 
sock )
+       {
+               CSResult        rv;
+               String                  name;
+               int                             i;
+
+               out.println("Supported Peer to Peer messages :");
+               for (i=0; i<500; i++) {
+                       if (!sock.send(new CSGetP2PMessageSupported(i))) {
+                               out.println("Error sending request for p2p 
protocol status to gnunetd.");
+                               return false;
+                               }
+
+                       rv=(CSResult) sock.receive(CSResult.class);
+                       if (rv==null) {
+                               out.println("Error reading p2p protocol status 
to gnunetd.");
+                               return false;
+                               }
+
+                       if (rv.isOkay()) {
+                               out.print("\t"+i);
+                               name = P2PMessage.nameFor(i);
+                               if (name != null) {
+                                       out.print("\t("+name+")");
+                                       }
+                               out.println();
+                               }
+                       }
+               out.println();
+
+               out.println("Supported Client Server messages :");
+               for (i=0; i<1020; i++) {
+                       if (!sock.send(new CSGetCSMessageSupported(i))) {
+                               out.println("Error sending request for 
client-server protocol status to gnunetd.");
+                               return false;
+                               }
+
+                       rv=(CSResult) sock.receive(CSResult.class);
+                       if (rv==null) {
+                               out.println("Error reading client-server 
protocol status to gnunetd.");
+                               return false;
+                               }
+
+                       if (rv.isOkay()) {
+                               out.print("\t"+i);
+                               name = CSMessage.nameFor( i );
+                               if (name != null) {
+                                       out.print("\t("+name+")");
+                                       }
+                               out.println();
+                               }
+                       }
+               out.println();
+               return true;
+       }
+
+       protected boolean printClients( PrintWriter out, CSSession sock )
+       {
+               CSResult        rv;
+
+               out.println("Connected clients :");
+
+               if (!sock.send(new CSGetClientCount())) {
+                       out.println("I/O error.");
+                       return false;
+                       }
+
+               rv=(CSResult) sock.receive(CSResult.class);
+               if (rv==null) {
+                       out.println("I/O error.");
+                       return false;
+                       }
+
+               out.println("  Count : "+rv.getResult());
+               out.println();
+               return true;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * The main function to obtain statistics from gnunetd.
+        *
+        * @param args command line arguments
+        */
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetStats.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetSwing.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetSwing.java        2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetSwing.java        2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,409 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.protocol.afs.swing.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+import org.gnu.freeway.util.ui.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+import java.beans.*;
+import java.io.*;
+import java.net.*;
+import java.util.logging.*;
+import javax.swing.*;
+
+/**
+ * This is the main file for the swing user interface.
+ *
+ * Basic structure of the code is this:
+ * main
+ * -> search -> saveas -> download
+ * -> insert
+ * -> directory -> insert
+ * -> pseudonyms (create|delete)
+ * -> namespace insert/update
+ * -> about
+ */
+
+public class GNUNetSwing extends AbstractClient implements AFSConstants
+{
+       /** */
+       private Prefs   prefs;
+       private SController     controller;
+
+       /** */
+       private Policy                                  policy;
+
+       /** This semaphore can be used to prevent the main window from killing 
GTK at an unhealty time.
+        It is used by the un-interruptable but GUI-updating insert thread.
+        This semaphore can be up'ed by threads that will need the GUI and that 
want to prevent gnunet-gtk
+        from exiting while they are running. */
+       private Semaphore                               refuseToDie;
+
+       private SearchWindow                    mainWindow;
+       private DownloadWindow                  dlWindow;
+       private StatsWindow                             statsWindow;
+       private PropertyChangeSupport   support;
+       private UIResources                             resources;
+
+
+       public GNUNetSwing()
+       {
+               super("gnunet-swing",Utils.makeVersion(0,0,1));
+               prefs=getPreferences();
+               support=new PropertyChangeSupport(this);
+               controller=createController();
+
+               resources=new UIResources("main.xml",controller.getCache());
+               resources.setGlobalTarget(this);
+       }
+
+       public String toString()
+       {
+               return "Swing basic interface";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-swing [OPTIONS]","Start 
GNUnet graphical client application.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(HELP_VERSION);
+               options.addOption(new Option("nosplash|n","disable splash 
screen") {
+                       public boolean exec( Command c )
+                       {
+                               prefs.setString("GNUNET-SWING","SPLASH","NO");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("remote|r|URL","enable downloading 
of daemon classes from URL") {
+                       public boolean exec( Command c )
+                       {
+                               URL     url;
+
+                               try {
+                                       url=new URL(getValue());
+                                       
prefs.setString("GNUNET-SWING","REMOTE",url.toString());
+                                       }
+                               catch( MalformedURLException x ) {
+                                       err("Invalid URL !",x);
+                                       return false;
+                                       }
+                               return true;
+                       }
+                       });
+               return options;
+       }
+
+       protected SController createController()
+       {
+               return new SController() {
+                       public void enterCritical()
+                       {
+                               try {
+                                       refuseToDie.acquire();
+                                       }
+                               catch( InterruptedException x ) {
+                                       err("",x);
+                                       }
+                       }
+
+                       public void leaveCritical()
+                       {
+                               refuseToDie.release();
+                       }
+
+                       public File getCache()
+                       {
+                               return getPreferences().getSystemCache();
+                       }
+                       public Application getApplication()
+                       {
+                               return GNUNetSwing.this;
+                       }
+
+                       public UIResources getResources()
+                       {
+                               return GNUNetSwing.this.resources;
+                       }
+
+                       public Service service( Class c )
+                       {
+                               return GNUNetSwing.this.service(c);
+                       }
+
+                       public void log( Level level, String msg )
+                       {
+                               GNUNetSwing.this.log(level,msg);
+                       }
+
+                       public void err( String msg, Throwable x )
+                       {
+                               GNUNetSwing.this.err(msg,x);
+                       }
+
+                       public Policy getPolicy()
+                       {
+                               return policy;
+                       }
+
+                       public void refreshMenus()
+                       {
+                               mainWindow.refreshMenus();
+                       }
+
+                       public void showStats()
+                       {
+                               GNUNetSwing.this.showStats();
+                       }
+
+                       public void download( Node node )
+                       {
+                               openSaveAs(node);
+                       }
+
+                       public void guiMessage( String str )
+                       {
+                               JOptionPane.showMessageDialog(mainWindow,str);
+                       }
+
+                       public void infoMessage( boolean doPopup, String str )
+                       {
+                       }
+
+                       public void displayDirectory( String fileName, Node 
root )
+                       {
+                               //todo: a implementer
+                       }
+
+                       public CSSession connect()
+                       {
+                               return GNUNetSwing.this.connect();
+                       }
+       public Prefs getPreferences()
+       {
+               return GNUNetSwing.this.getPreferences();
+       }
+       public void addPropertyChangeListener( PropertyChangeListener listener )
+       {
+               support.addPropertyChangeListener(listener);
+       }
+
+       public void addPropertyChangeListener( String name, 
PropertyChangeListener listener )
+       {
+               support.addPropertyChangeListener(name,listener);
+       }
+
+       public void removePropertyChangeListener( PropertyChangeListener 
listener )
+       {
+               support.removePropertyChangeListener(listener);
+       }
+
+       public void removePropertyChangeListener( String name, 
PropertyChangeListener listener )
+       {
+               support.removePropertyChangeListener(name,listener);
+       }
+                       };
+       }
+
+       public int run()
+       {
+               GSplash         splash;
+               DirLocation     downloadDir;
+               Scheduler       scheduler;
+
+               scheduler=getScheduler();
+
+               policy=new Policy(prefs,connect());
+
+               downloadDir=prefs.getDirLocation("AFS","DOWNLOADDIR");
+               if (downloadDir!=null) {
+                       downloadDir.create();
+                       //todo: faire un chdir() sur le repertoire
+                       }
+
+               refuseToDie = new Semaphore(1);
+
+               mainWindow=new SearchWindow(controller);
+
+               if (!prefs.testString("GNUNET-SWING","SPLASH","NO")) {
+                       try {
+                               splash=new 
GSplash(resources.getImageURL("splash"),5);
+                               splash.splash();
+                               }
+                       catch( IOException x ) {
+                               err("Unable to display splash screen !",x);
+                               }
+                       }
+
+               /* Check if gnunetd is running */
+               checkForDaemon();
+
+               /* refresh the kill/launch sensitivities once per two secs */
+               scheduler.addJob(new ScheduledTask("CHECK-DAEMON",new 
EvalAction(mainWindow,"cronCheckDaemon"),Scheduler.SECS_2),0);
+
+               mainWindow.display();
+
+               Scheduler.sleep();
+
+               log(Level.FINEST,"GUI leaving...");
+               refuseToDie=null;
+               policy.doneAnonymityPolicy();
+               policy=null;
+               scheduler.deleteJob(new ScheduledTask("CHECK-DAEMON",new 
EvalAction(mainWindow,"cronCheckDaemon"),Scheduler.SECS_2));
+               return 0;
+       }
+
+       public void checkForDaemon()
+       {
+       }
+
+       public void onQuit()
+       {
+               
support.firePropertyChange(SController.QUIT_EVENT,null,Boolean.TRUE);
+       }
+
+       /**
+        * Open the window that prompts the user for the
+        * filename.
+        * This method must open the window,
+        * copy the arguments and return. After the method
+        * returns, the arguments passed to it will be
+        * freed, so pointer should not be retained.
+        * The method executes during a signal handler,
+        * so a GTK lock is not required to to GUI
+        * operations.
+        * Open the window that prompts the user for the filename.  This
+        * method must open the window, copy the arguments and return.  After
+        * the method returns, the arguments passed to it will be freed, so
+        * pointer should not be retained.  The method executes during a
+        * signal handler, so a GTK lock is not required to to GUI operations.
+        *
+        * @param node search result of the file to download
+        */
+
+       protected void openSaveAs( Node node )
+       {
+               JFileChooser            fc;
+               File                            file;
+               SaveAs                  saveas;
+               StringBuffer            buf;
+               int                             ret,i;
+               char                            c;
+
+               saveas=new SaveAs();
+               saveas.root=(Node) PersistentHelper.copy(node);
+               saveas.filename="";
+
+               // if the search result specified a suggested filename, fill it 
in !
+               /* if it is a GNUnet directory, replace suffix '/' with ".gnd" 
*/
+               if (node.getMimeType().equals(GNUNET_DIRECTORY_MIME)) {
+                       
saveas.filename=GNDirectory.expandDirectoryName(node.getFileName());
+                       }
+               else {
+                       saveas.filename=node.getFileName();
+                       }
+
+               log(Level.FINEST,">>>>>>> "+saveas.filename);
+               if (saveas.filename.length()==0 || 
prefs.testString("GNUNET-GTK","ALWAYS-ASK-SAVEAS","YES")) {
+                       fc=new JFileChooser();
+                       fc.setDialogTitle("save as");
+                       fc.setSelectedFile(new File(saveas.filename));//todo: 
ne semble pas marcher
+
+                       ret=fc.showSaveDialog(mainWindow);
+                       if (ret!=JFileChooser.APPROVE_OPTION) {
+                               log(Level.INFO,"Save aborted.");
+                               return;
+                               }
+
+                       file=fc.getSelectedFile();
+                       saveas.filename=file.getPath();
+                       }
+               else {
+                       // sanity check the filename
+                       buf=new StringBuffer();
+                       for(i=0; i<saveas.filename.length();i++) {
+                               c=saveas.filename.charAt(i);
+                               switch(c) {
+                                       case '*':
+                                       case '/':
+                                       case '\\':
+                                       case '?':
+                                       case ':':
+                                               c='_';
+                                               break;
+                                       }
+                               buf.append(c);
+                                 }
+                       saveas.filename=new 
FileLocation(buf.toString()).getPath();
+                       }
+               startDownload(saveas.filename,saveas.root);
+       }
+
+       protected void startDownload( String str, Node node )
+       {
+               log(Level.INFO,"Save to : "+str);
+
+               if (dlWindow==null) {
+                       dlWindow=new DownloadWindow(controller);
+                       }
+
+               dlWindow.display();
+               dlWindow.addDownload(str,node);
+       }
+
+       public void onShowDownload()
+       {
+               if (dlWindow==null) {
+                       dlWindow=new DownloadWindow(controller);
+                       }
+
+               dlWindow.display();
+       }
+
+       /**
+        * A not so dirty way to pump some stats from gnunetd
+        */
+
+       public void showStats()
+       {
+               if (statsWindow==null) {
+                       statsWindow=new StatsWindow(controller);
+                       }
+               statsWindow.display();
+               statsWindow.onRefresh();
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetSwing.class,args);
+       }
+}
+
+/**
+ * State of the SaveAs window
+ */
+
+class SaveAs extends Object
+{
+       public Node     root;
+       public String   filename;
+}

Added: freeway/src/org/gnu/freeway/GNUNetTests.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetTests.java        2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetTests.java        2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,155 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.test.*;
+import org.gnu.freeway.util.*;
+
+import java.util.logging.*;
+
+/**
+ */
+
+public class GNUNetTests extends AbstractClient implements Signals
+{
+       public GNUNetTests()
+       {
+               super("gnunet-tests",Utils.makeVersion(1,0));
+       }
+
+       public String toString()
+       {
+               return "Test suite";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-tests [OPTIONS]","Mini test 
suite.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(HELP_VERSION);
+               return options;
+       }
+
+       public int run()
+       {
+               boolean succeedeed;
+
+               succeedeed=true;
+
+/*             out("=== Bloom Test ===");
+               ucceedeed=(succeedeed && new BloomTest().test(this));
+               out("==================");
+*/
+/*             out("=== Charset Test ===");
+               succeedeed=(succeedeed && new CharsetTest().test(this));
+               out("====================");
+*/
+/*             out("=== CRC Test ===");
+               new CRCTest().test(this);
+               out("================");
+*/
+/*             out("=== Cron Test ===");
+               new CronTest().test(this);
+               out("=================");
+*/
+/*             out("=== Filter Test ===");
+               new FilterTest().test(this);
+               out("===================");
+*/
+/*             out("=== Hash Test ===");
+               new HashTest().test(this);
+               out("=================");
+*/
+/*             out("=== Layout Test ===");
+               new LayoutTest().test(this);
+               out("===================");
+*/
+/*             out("=== MySQL Test ===");
+               new MySQLTest().test(this);
+               out("==================");
+*/
+/*             out("=== RSA Test ===");
+               new RSATest().test(this);
+               out("================");
+*/
+/*             out("=== Semaphore Test ===");
+               new SemaphoreTest().test(this);
+               out("======================");
+*/
+/*             out("=== Shutdown Test ===");
+               new ShutdownTest().test(this);
+               out("=====================");
+*/
+/*             out("=== Signals Test ===");
+               new SignalsTest().test(this);
+               out("====================");
+*/
+/*             out("=== State Test ===");
+               new StateTest().test(this);
+               out("==================");
+*/
+/*             out("=== Status Calls Test ===");
+               new StatusCallsTest().test(this);
+               out("=========================");
+*/
+               out("=== Storage Test ===");
+               new StorageTest().test(this);
+               out("====================");
+
+/*             out("=== Sym. Cypher Test ===");
+               new SymCipherTest().test(this);
+               out("====================");
+*/
+/*             out("=== TCP Test ===");
+               new TCPTest().test(this);
+               out("================");
+*/
+/*             out("=== Table Test ===");
+               new TableTest().test(this);
+               out("==================");
+*/
+/*             out("=== Timer Test ===");
+               new TimerTest().test(this);
+               out("==================");
+*/
+               // erase configuration values, must be run at the end
+/*             out("=== Config Test ===");
+               new ConfigTest().test(this);
+               out("===================");
+*/             return (succeedeed ? 0 : -1);
+       }
+
+       public void out( String str )
+       {
+               log(Level.INFO,str);
+       }
+
+       public void err( String str )
+       {
+               log(Level.WARNING,str);
+       }
+
+       public void err( String str, Throwable x )
+       {
+               err(str,x);
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetTests.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetTrace.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetTrace.java        2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetTrace.java        2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,235 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.protocol.tracekit.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.transport.*;
+import org.gnu.freeway.transport.tcp.*;
+import org.gnu.freeway.transport.udp.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * tool that sends a trace request and prints the received network topology
+ */
+
+public class GNUNetTrace extends AbstractClient
+{
+       private Prefs   prefs;
+
+
+       public GNUNetTrace()
+       {
+               super("gnunet-tracekit",Utils.makeVersion(0,1,2));
+               prefs=getPreferences();
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-tracekit [OPTIONS]","Trace 
GNUnet network topology.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(new Option("depth|D|DEPTH","probe network to 
the given DEPTH") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setInt("GNUNET-TRACEKIT","HOPS",Integer.parseInt(getValue()));
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("format|F|FORMAT","0 for human 
readable output, 1 for dot") {
+                       public boolean exec( Command c )
+                       {
+                               //todo: to implement
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("priority|P|PRIO","use PRIO for 
the priority of the trace request") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setInt("GNUNET-TRACEKIT","PRIORITY",Integer.parseInt(getValue()));
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               options.addOption(new Option("wait|W|DELAY","wait DELAY seconds 
for replies") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setInt("GNUNET-TRACEKIT","WAIT",Integer.parseInt(getValue()));
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_HOSTNAME);
+               return options;
+       }
+
+       protected void printHostInfos( HostIdentity host )
+       {
+               P2PHello[]              helos;
+               CSSession       sock;
+               CSHostInfo              infos;
+               TCPAddress              tcpAddr;
+               UDPAddress              udpAddr;
+               int                             i;
+
+               sock=connect();
+
+               infos=null;
+               if (sock.send(new CSGetHostInfo(host))) {
+                       infos=(CSHostInfo) sock.receive(CSHostInfo.class);
+                       }
+
+               if (infos!=null) {
+                       helos=infos.getHELOs();
+
+                       System.out.println("Host \""+host.getName()+"\" is 
advertised "+helos.length+" times");
+                       for (i=0; i<helos.length; i++) {
+                               switch (helos[i].getProtocol()) {
+                                       case Transport.TCP_PROTOCOL_NUMBER:
+                                               tcpAddr=(TCPAddress) 
helos[i].decodeSenderAddress(TCPAddress.class);
+                                               System.out.println(" Protocol 
TCP : "+tcpAddr.getIP().getHostAddress()+" at "+tcpAddr.getPort());
+                                               break;
+                                       case Transport.UDP_PROTOCOL_NUMBER:
+                                               udpAddr=(UDPAddress) 
helos[i].decodeSenderAddress(UDPAddress.class);
+                                               System.out.println(" Protocol 
UDP : "+udpAddr.getIP().getHostAddress()+" at "+udpAddr.getPort());
+                                               break;
+                                       default:
+                                               System.out.println(" Protocol 
#"+helos[i].getProtocol());
+                                               break;
+                                       }
+                               }
+                       }
+               else {
+                       System.err.println("Failed to talk with daemon.");
+                       }
+
+               sock.disconnect();
+       }
+
+       public int run()
+       {
+               CSSession       sock;
+               int                     ret;
+               Task                    thread;
+
+               sock=connect();
+               if (sock==null) {
+                       log(Level.SEVERE,"Could not connect to gnunetd.");
+                       return -29;
+                       }
+
+               final CSSession _sock = sock;
+
+               log(Level.INFO,"Start receive thread.");
+               thread=new Task("CLIENT-RECEIVE",new AbstractAction() {
+                       public void perform()
+                       {
+                               receive333(_sock);
+                       }
+                       });
+               thread.launch();
+
+               ret=process2(sock);
+
+               log(Level.INFO,"Waiting for receive thread to finish.");
+
+               sock.disconnect();
+               thread.join();
+
+               return ret;
+       }
+
+       protected void receive333( CSSession sock )
+       {
+               CSTraceReply    reply;
+               List                    peersSeen;
+               List                    peersResponding;
+               int                             count,i;
+               HostIdentity    host;
+
+               peersSeen=new ArrayList();
+               peersResponding=new ArrayList();
+
+               reply=(CSTraceReply) sock.receive(CSTraceReply.class);
+               while (reply!=null) {
+                       host=reply.responderId;
+                       if (!peersResponding.contains(host)) {
+                               peersResponding.add(host);
+
+                               
System.out.println("===============================================================================================");
+                               printHostInfos(host);
+                               System.out.println();
+                               }
+
+                       count=reply.getHostsCount();
+                       if (count==0) {
+                               System.out.println(host.getName()+" is not 
connected to any peer.");
+                               }
+                       else {
+                               for (i=0; i<count; i++) {
+                                       if 
(!peersSeen.contains(reply.getHost(i))) {
+                                               
peersSeen.add(PersistentHelper.copy(reply.getHost(i)));
+                                               }
+                                       System.out.println(host.getName()+" 
connected to "+reply.getHost(i).getName()+".");
+                                       }
+                               }
+                       System.out.println();
+
+                       reply=(CSTraceReply) sock.receive(CSTraceReply.class);
+                       }
+
+               for (i=0; i<peersSeen.size(); i++) {
+                       if (!peersResponding.contains(peersSeen.get(i))) {
+                               System.out.println("Peer "+((HostIdentity) 
peersSeen.get(i)).getName()+" did not report back.");
+                               }
+                       }
+       }
+
+       protected int process2( CSSession sock )
+       {
+               CSTraceProbe    probe;
+               int                             sleepTime;
+
+               probe=new CSTraceProbe();
+               probe.hops = prefs.getInt("GNUNET-TRACEKIT","HOPS",0);
+               probe.priority= prefs.getInt("GNUNET-TRACEKIT","PRIORITY",0);
+               if (!sock.send(probe)) {
+                       log(Level.SEVERE,"Could not send request to daemon.");
+                       return -1;
+                       }
+
+               sleepTime=prefs.getInt("GNUNET-TRACEKIT","WAIT",0);
+               if (sleepTime==0) {
+                       sleepTime=30;
+                       }
+
+               waitForShutdown(Scheduler.seconds(sleepTime));
+               return 0;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetTrace.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetTransportCheck.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetTransportCheck.java       2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetTransportCheck.java       2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,609 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.transport.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+import java.nio.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * Test for the transports.
+ *
+ * This utility can be used to test if a transport mechanism for GNUnet is 
properly configured.
+ */
+
+public class GNUNetTransportCheck extends AbstractServer
+{
+       public static final byte[]      DEFAULT_DATA    =       "Hello, World 
!".getBytes();
+
+       public static final boolean     DEBUG_TRANSPORT_CHECK           =       
true;
+
+       private Semaphore       semaphore;
+       private ScheduledTask           releaseSemaphore;
+       private ScheduledTask           releaseSemaphoreEvery5S;
+       private byte[]          testData;
+       private MessagePack     received;
+       private boolean         failed;
+       private boolean         terminate;
+       private long                    timeout = Scheduler.SECS_15;
+
+       private TransportService                transports;
+       private Prefs   prefs;
+       private Scheduler                       scheduler;
+       private HELOLoader                      loader;
+
+
+       public GNUNetTransportCheck()
+       {
+               super("gnunet-transport-check",Utils.makeVersion(0,9,8));
+
+               semaphore=new Semaphore(0);
+               releaseSemaphore=new ScheduledTask("RELEASE-SEMAPHORE",new 
AbstractAction() {
+                       public void perform()
+                       {
+                               terminate=true;
+                               semaphore.release();
+                       }
+                       });
+               releaseSemaphoreEvery5S=new 
ScheduledTask("RELEASE-SEMAPHORE",new AbstractAction() {
+                       public void perform()
+                       {
+                               terminate=true;
+                               semaphore.release();
+                       }
+                       },Scheduler.SECS_5);
+
+               testData=DEFAULT_DATA;
+               received=null;
+               failed=false;
+
+               TransportService.useCoreFacade(new CoreForTransport() {
+                       public int getVersion()
+                       {
+                               return 0;
+                       }
+
+                       public HostIdentity getIdentity()
+                       {
+                               return ((CoreService) 
service(CoreService.class)).getIdentity();
+                       }
+
+                       public org.gnu.freeway.util.Service service( Class c )
+                       {
+                               return GNUNetTransportCheck.this.service(c);
+                       }
+
+                       public void receive( MessagePack mp )
+                       {
+                               if ( (semaphore == null) || (received != null) 
) {
+                                       return; /* spurious receive or 
double-receive, happens */
+                                       }
+                               if 
(prefs.testString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES")) {
+                                       System.err.println(".");
+                                       }
+
+                               received = mp;
+                               semaphore.release();
+                       }
+
+                       public Application getApplication()
+                       {
+                               return GNUNetTransportCheck.this;
+                       }
+                       });
+               transports=(TransportService) service(TransportService.class);
+               prefs=getPreferences();
+               loader=(HELOLoader) service(HELOLoader.class);
+       }
+
+       public String toString()
+       {
+               return "Transport layer check";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-transport-check 
[OPTIONS]","Test if GNUnet transport services are operational.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(new Option("ping|p","ping peers from 
HOSTLISTURL that match transports") {
+                       public boolean exec( Command c )
+                       {
+                               prefs.setString("TRANSPORT-CHECK","PING","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("repeat|r|COUNT","send COUNT 
messages") {
+                       public boolean exec( Command c )
+                       {
+                               int     n;
+
+                               n=getIntValue(-1);
+                               if (n<1) {
+                                       log(Level.SEVERE,"You must pass a 
strictly positive number to the -r option.");
+                                       return false;
+                                       }
+                               prefs.setInt("TRANSPORT-CHECK","REPEAT",n);
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("size|s|SIZE","send messages with 
SIZE bytes payload") {
+                       public boolean exec( Command c )
+                       {
+                               int     n;
+
+                               n=Utils.parseInt(getValue(),-1);
+                               if (n<1) {
+                                       log(Level.SEVERE,"You must pass a 
strictly positive number to the -s option.");
+                                       return false;
+                                       }
+
+                               testData=new byte[n];
+                               Arrays.fill(testData,(byte) 'A');
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("transport|t|TRANSPORT","specifies 
which TRANSPORT should be tested") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNETD","TRANSPORTS",getValue());
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("timeout|T|MS","specifies after 
how many MS to time-out") {
+                       public boolean exec( Command c )
+                       {
+                               timeout=Utils.parseLong(getValue(),-1);
+                               if (timeout<=0) {
+                                       log(Level.SEVERE,"You must pass a 
number to the -T option.");
+                                       return false;
+                                       }
+                               return true;
+                       }
+                       });
+               options.addOption(HELP_VERSION);
+               options.addOption(new Option("verbose|V","be verbose") {
+                       public boolean exec( Command c )
+                       {
+                               
prefs.setString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES");
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("Xrepeat|X|REPEAT","repeat test 
REPEAT times") {
+                       public boolean exec( Command c )
+                       {
+                               int     n;
+
+                               n=Utils.parseInt(getValue(),-1);
+                               if (n<1) {
+                                       log(Level.SEVERE,"You must pass a 
positive number to the -X option.");
+                                       return false;
+                                       }
+                               prefs.setInt("TRANSPORT-CHECK","X-REPEAT",n);
+                               return true;
+                       }
+                       });
+               options.addOption(new Option("Xport|P|PORT","set TCP and UDP 
port to PORT") {
+                       public boolean exec( Command c )
+                       {
+                               int     n;
+
+                               n=Utils.parseInt(getValue(),-1);
+                               if (n<=0) {
+                                       log(Level.SEVERE,"You must pass a 
number to the -P option.");
+                                       return false;
+                                       }
+                               prefs.setInt("TCP","PORT",n);
+                               prefs.setInt("UDP","PORT",n);
+                               prefs.setInt("TCP6","PORT",n);
+                               prefs.setInt("UDP6","PORT",n);
+                               prefs.setInt("HTTP","PORT",n);
+                               return true;
+                       }
+                       });
+               return options;
+       }
+
+       public int run()
+       {
+               String[]                urls;
+               int[]           stats;
+               String          str;
+               int                     count,i;
+               boolean         ping;
+
+               str=prefs.getString("GNUNETD","TRANSPORTS",null);
+               if (str==null) {
+                       log(Level.SEVERE,"You must specify a non-empty set of 
transports to test !");
+                       return 1;
+                       }
+
+               ping=prefs.testString("TRANSPORT-CHECK","PING","YES");
+               if (!ping) {
+                       System.out.println("Testing transport(s) "+str);
+                       }
+               else {
+                       System.out.println("Available transport(s): "+str);
+                       }
+
+               if (!ping) {
+                       /* disable blacklists (loopback is often 
blacklisted)... */
+                       prefs.setString("TCP","BLACKLIST",null);
+                       prefs.setString("UDP","BLACKLIST",null);
+                       prefs.setString("TCP6","BLACKLIST",null);
+                       prefs.setString("UDP6","BLACKLIST",null);
+                       prefs.setString("HTTP","BLACKLIST",null);
+                       }
+
+               count=prefs.getInt("TRANSPORT-CHECK","X-REPEAT",0);
+               if (count<1) {
+                       count=1;
+                       }
+
+               failed=false;
+
+               if (ping) {
+                       stats=new int[3];
+                       stats[0]=0;
+                       stats[1]=0;
+                       stats[2]=0;
+
+                       urls=prefs.getArray("GNUNETD","HOSTLISTURL","[\\s;]+");
+                       if (urls.length>0) {
+                               for (i=0; i<urls.length; i++) {
+                                       if (DEBUG_TRANSPORT_CHECK) {
+                                               System.err.println("URL: 
"+urls[i]);
+                                               }
+                                       loader.downloadHostList(urls[i],new 
HELOCallback() {
+                                               public void onHELO( P2PHello 
helo, Object arg )
+                                               {
+                                                       try {
+                                                               
testPING(helo,(int[]) arg);
+                                                               }
+                                                       catch( 
InterruptedException x ) {
+                                                               err("",x);
+                                                               }
+                                               }
+                                               },stats);
+                                       }
+                               System.err.println();
+                               }
+                       else {
+                               System.out.println("WARNING: no HOSTLISTURL 
specified in configuration!");
+                               }
+
+                       System.out.println(stats[2]+" out of "+stats[1]+" peers 
contacted successfully ("+(stats[0] - stats[1])+" times transport 
unavailable).");
+                       }
+               else {
+                       while (count>0 && !failed) {
+                               transports.forEachTransport(new 
TransportCallback() {
+                                       public void callback( Transport t, 
Object data )
+                                       {
+                                               log(Level.INFO,"Test transport 
\""+t.getName()+"\".");
+                                               try {
+                                                       
failed=!testTransport(t);
+                                                       }
+                                               catch( InterruptedException x ) 
{
+                                                       err("Interrupted while 
testing "+t+" !",x);
+                                                       }
+                                       }
+                                       },null);
+                               count--;
+                               }
+                       }
+               return (failed ? 1 : 0);
+       }
+
+       /**
+        * Test the given transport API.
+        * @param t
+        * @return
+        * @throws InterruptedException
+        */
+
+       protected boolean testTransport( Transport t ) throws 
InterruptedException
+       {
+               Session tsession;
+               P2PHello        helo;
+               boolean         success;
+
+               if (t!=null) {
+                       debug("Create HELO.");
+
+                       helo=t.createHELO();
+                       if (helo!=null) {
+                               debug("Connect to HELO.");
+
+                               tsession=t.connect(helo);
+                               if (tsession!=null) {
+                                       // really test it now !
+                                       success=testTransport(tsession,helo);
+
+                                       if (!tsession.unlock()) {
+                                               log(Level.SEVERE,"Could not 
disconnect !");
+                                               success=false;
+                                               }
+                                       }
+                               else {
+                                       log(Level.SEVERE,"Could not connect !");
+                                       success=false;
+                                       }
+                               }
+                       else {
+                               log(Level.SEVERE,"Could not create HELO !");
+                               success=false;
+                               }
+                       }
+               else {
+                       log(Level.SEVERE,"Could not initialize transport !");
+                       success=false;
+                       }
+               return success;
+       }
+
+       protected boolean testTransport( Session tsession, P2PHello helo ) 
throws InterruptedException
+       {
+               ByteBuffer      buf;
+               long            start,end;
+               int                     repeat;
+
+               scheduler=getScheduler();
+
+               buf=ByteBuffer.allocateDirect(testData.length);
+               buf.put(testData);
+
+               repeat=prefs.getInt("TRANSPORT-CHECK","REPEAT",0);
+               if (repeat==0) {
+                       repeat=1;
+                       prefs.setInt("TRANSPORT-CHECK","REPEAT",1);
+                       }
+
+               start=Scheduler.now();
+
+               while (repeat>0) {
+                       received=null;
+
+                       debug("Send data.");
+                       if (!tsession.send(buf)) {
+                               log(Level.SEVERE,"Could not send !");
+                               return false;
+                               }
+
+                       scheduler.addJob(releaseSemaphore,timeout);
+                       semaphore.acquire();
+                       scheduler.suspend();
+                       scheduler.deleteJob(releaseSemaphore);
+                       scheduler.resume();
+
+                       if (received==null) {
+                               log(Level.SEVERE,"Did not receive message 
within "+Scheduler.toSeconds(timeout)+" seconds !");
+                               return false;
+                               }
+
+                       if (!checkOK(received)) {
+                               log(Level.SEVERE,"Message received was invalid 
!");
+                               return false;
+                               }
+
+                       repeat--;
+                       }
+
+               end=Scheduler.now();
+
+               repeat=prefs.getInt("TRANSPORT-CHECK","REPEAT",0);
+               log(Level.INFO,
+                               "Transport 
\""+tsession.getTransport().getName()+"\" okay, "+
+                               Scheduler.toMillis(end-start)+"ms "+
+                               "for "+repeat+" messages "+
+                               "of size "+testData.length+" bytes "+
+                               "("+IOUtils.newSizeFormatter().format(new 
Long((1000*repeat*testData.length)/Scheduler.toMillis(end-start)))+"/s).");
+               return true;
+       }
+
+       protected boolean checkOK( MessagePack rec )
+       {
+               ByteBuffer      buf;
+               int                     i;
+               HostIdentity    myIdentity;
+
+               myIdentity=((CoreService) 
service(CoreService.class)).getIdentity();
+
+               if (rec.isEncrypted()) {
+                       System.out.println(">enc");
+                       return false;
+                       }
+               if (!rec.getSession().getRemote().equals(myIdentity)) {
+                       System.out.println(">sen : "+myIdentity+" : 
"+rec.getSession().getRemote());
+                       return false;
+                       }
+               if (rec.getCRC()!=Crypto.crc32(testData)) {
+                       System.out.println(">crc");
+                       return false;
+                       }
+
+               buf=rec.getMessages();
+               if (buf.position()!=testData.length) {
+                       System.out.println(">pos");
+                       return false;
+                       }
+               for (i=0; i<testData.length && buf.get(i)==testData[i]; i++) {}
+               if (i<testData.length) {
+                       System.out.println(">bytes "+i+" "+testData.length);
+                       }
+               return (i==testData.length);
+       }
+
+       protected void testPING( P2PHello xhelo, int[] stats ) throws 
InterruptedException
+       {
+               Session         tsession;
+               P2PPing         pmsg;
+               P2PHello                helo,myHelo;
+               Transport       t;
+               String          str;
+               int                     reply;
+               boolean         again;
+
+               scheduler=getScheduler();
+
+               if (prefs.testString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES")) 
{
+                       t=transports.getTransport(xhelo);
+                       str=(t!=null ? t.addressToString(xhelo) : null);
+                       System.err.print("\nContacting "+str+".");
+                       }
+               else {
+                       System.err.print(".");
+                       }
+
+               helo=(P2PHello) PersistentHelper.copy(xhelo);
+
+               stats[0]++; /* one more seen */
+               if (!transports.isTransportAvailable(helo.getProtocol())) {
+                       System.err.print(" Transport "+helo.getProtocol()+" not 
available\n");
+                       return;
+                       }
+
+               myHelo=transports.transportCreateHELO(xhelo.getProtocol());
+               if (myHelo==null) {
+                       return;
+                       }
+
+               if (prefs.testString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES")) 
{
+                       System.err.print( ".");
+                       }
+
+               stats[1]++; /* one more with transport 'available' */
+
+               pmsg=new P2PPing();
+               pmsg.setReceiver(helo.getSenderIdentity());
+               pmsg.setChallenge(Crypto.nextInt());
+
+               tsession=transports.transportConnect(helo);
+               if (tsession==null) {
+                       System.err.print(" Connection failed\n");
+                       return;
+                       }
+
+               if (prefs.testString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES")) 
{
+                       System.err.print( ".");
+                       }
+
+               semaphore=new Semaphore(0);
+
+               /* send ping */
+               if (!tsession.send(new Persistent[] { myHelo, pmsg })) {
+                       System.err.print(" Send failed.\n");
+                       tsession.unlock();
+                       return;
+                       }
+
+               if (prefs.testString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES")) 
{
+                       System.err.print( ".");
+                       }
+
+               /* check: received pong? */
+               terminate=false;
+               scheduler.addJob(releaseSemaphoreEvery5S,timeout);
+
+               reply=0;
+               again=true;
+               while (again && !terminate) {
+                       again=false;
+                       semaphore.acquire();
+
+                       if (received!=null) {
+                               P2PMessage                      part;
+                               P2PPong                         pong;
+                               PersistentDecoder       decoder;
+                               Iterator                                iter;
+                               int                                     
pos,plen;
+
+                               again=true;
+                               if 
(!xhelo.getSenderIdentity().equals(received.getSession().getRemote())) {
+                                       if (DEBUG_TRANSPORT_CHECK) {
+                                               
System.err.print(xhelo.getSenderIdentity().getName()+"!="+received.getSession().getRemote().getName());
+                                               }
+                                       received=null;
+                                       continue; /* different peer, ignore */
+                                       }
+
+                               reply = 1;
+
+                               decoder=new PersistentDecoder();
+                               decoder.add(P2PMessage.IS_PONG,P2PPong.class);
+
+                               pos = 0;
+                               iter=received.messages(decoder);
+                               while (iter.hasNext()) {
+                                       part=(P2PMessage) iter.next();
+                                       plen=part.getByteSize();
+
+                                       if (DEBUG_TRANSPORT_CHECK) {
+                                               System.err.print( 
"PRT<"+plen+","+part.getType()+">:"+pos+"@"+received.getSize());
+                                               }
+
+                                       pos+=plen;
+
+                                       if (part instanceof P2PPong) {
+                                               pong=(P2PPong) part;
+                                               if (pong.isCompatible(pmsg)) {
+                                                       if 
(prefs.testString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES")) {
+                                                               
System.err.print( "OK!");
+                                                               }
+                                                       stats[2]++;
+                                                       reply = 2;
+                                                       again=false;
+                                                       break;
+                                                       }
+
+                                               if 
(prefs.testString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES")) {
+                                                       System.err.print("!"); 
/* invalid pong */
+                                                       }
+                                               }
+                                       }
+                               received=null;
+                               }
+                       }
+
+               if (prefs.testString("GNUNET-TRANSPORT-CHECK","VERBOSE","YES")) 
{
+                       if (reply == 1)
+                               System.err.print( " No PONG.");
+                       else if (reply == 0)
+                               System.err.print(" No reply (within "+timeout+" 
ms).");
+                       }
+
+               scheduler.suspend();
+               scheduler.deleteJob(releaseSemaphoreEvery5S);
+               scheduler.resume();
+
+               semaphore=null;
+               received=null;
+
+               tsession.unlock();
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetTransportCheck.class,args);
+       }
+}

Added: freeway/src/org/gnu/freeway/GNUNetUIConfig.java
===================================================================
--- freeway/src/org/gnu/freeway/GNUNetUIConfig.java     2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/GNUNetUIConfig.java     2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,624 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.ui.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.sql.*;
+import java.util.logging.*;
+import javax.swing.*;
+import javax.swing.text.*;
+
+/**
+ *
+ */
+
+public class GNUNetUIConfig extends AbstractClient
+{
+       private Controller      controller;
+       private UIResources     resources;
+       private GWizard         wizard;
+
+//     private boolean         doForce;
+       private Semaphore       sem;
+       private Prefs           prefs;
+
+       private boolean         fromApp;
+       private DirLocation     daemonBaseDirectory;
+       private DirLocation     clientsBaseDirectory;
+       private String          mysqlHost;
+       private String          mysqlUser;
+       private String          mysqlPassword;
+       private boolean         optionOverwrite;
+       private boolean         optionSaveOnly;
+
+       //todo: proposer de telecharger une liste d'hosts sur ovjm.org
+
+
+       protected GNUNetUIConfig()
+       {
+               super("gnunet-ui-config",Utils.makeVersion(1,1));
+               controller=new Controller() {
+                       public Application getApplication()
+                       {
+                               return GNUNetUIConfig.this;
+                       }
+                       };
+               resources=new 
UIResources("gnunet-config.xml",getPreferences().getSystemCache());
+               resources.setGlobalTarget(this);
+               wizard=null;
+
+//             doForce=false;
+               sem=new Semaphore(0);
+               prefs=getPreferences();
+
+               fromApp=false;
+               daemonBaseDirectory=new 
DirLocation(prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.DAEMON_BASEDIR_NAME,Prefs.DAEMON_BASEDIR_DEFAULT));
+               clientsBaseDirectory=new 
DirLocation(prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.CLIENTS_BASEDIR_NAME,Prefs.CLIENTS_BASEDIR_DEFAULT));
+               
mysqlHost=prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_HOST_NAME,Prefs.MYSQL_HOST_DEFAULT);
+               
mysqlUser=prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_USER_NAME,Prefs.MYSQL_USER_DEFAULT);
+               
mysqlPassword=prefs.getGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_PASSWORD_NAME,Prefs.MYSQL_PASSWORD_DEFAULT);
+               optionOverwrite=false;
+               optionSaveOnly=false;
+       }
+
+       public String toString()
+       {
+               return "Configuration graphical tool";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public OptionsParser createParser()
+       {
+               OptionsParser   options;
+
+               options=new OptionsParser("gnunet-ui-config 
[OPTIONS]","Graphical configuration management.");
+               options.setAllowArguments(false);
+               options.addOption(HELP_CONFIG);
+               options.addOption(HELP_HOSTNAME);
+               options.addOption(HELP_LOGLEVEL);
+               options.addOption(HELP_LOGLEVEL_FILE);
+               options.addOption(HELP_VERSION);
+               options.addOption(new Option("force|f","force to reenter all 
configuration information") {
+                       public boolean exec( Command c )
+                       {
+//                             doForce=true;
+                               return true;
+                       }
+                       });
+               return options;
+       }
+
+       public void setFromApp()
+       {
+               fromApp=true;
+       }
+
+       protected boolean checkMySQL( String host, String user, String password 
)
+       {
+               Connection      conn;
+
+               try {
+                       Class.forName("com.mysql.jdbc.Driver");
+                       
conn=DriverManager.getConnection("jdbc:mysql://"+host+"/",user,password);
+                       conn.close();
+                       }
+               catch( SQLException x ) {
+                       err("Unable to connect to MySQL !",x);
+                       return false;
+                       }
+               catch( ClassNotFoundException x ) {
+                       err("Unable to load MySQL driver !",x);
+                       return false;
+                       }
+               return true;
+       }
+
+       public int run()
+       {
+               wizard=new GWizard(controller,"gnunet-config") {
+                       public GWizardPage[] getSteps()
+                       {
+                               return new GWizardPage[] {
+                                       new WelcomeStep(),
+                                       new DaemonBaseStep(),
+                                       new ClientsBaseStep(),
+                                       new MySQLStep(),
+                                       new ConfirmationStep()
+                                       };
+                       }
+
+                       public UIResources getResources()
+                       {
+                               return resources;
+                       }
+
+                       public void doTask()
+                       {
+                               task();
+                       }
+                       };
+               wizard.setTitle("GNUNet config");
+               wizard.display();
+
+               try {
+                       sem.acquire();
+                       }
+               catch( InterruptedException x ) {
+                       }
+               return 0;
+       }
+
+       public void onQuit()
+       {
+               if (fromApp || JOptionPane.showConfirmDialog(
+                               wizard,
+                               "Do you really want to quit ?",
+                               "Exiting...",
+                               JOptionPane.YES_NO_OPTION,
+                               JOptionPane.QUESTION_MESSAGE,
+                               new 
ImageIcon(resources.getImageURL("application.medium.icon"))
+                               )==JOptionPane.YES_OPTION) {
+
+                       wizard.close();
+                       sem.release();
+                       }
+       }
+
+       protected void task()
+       {
+               GProgress       dialog;
+
+               final boolean[] _beurk = new boolean[1];
+
+               _beurk[0]=false;
+
+               dialog=new GProgress(wizard,"gnunet-config-progress") {
+                       public void perform()
+                       {
+                               progress(1,8,"Check parameters...");
+                               if (!checkParams()) {
+                                       return;
+                                       }
+                               Scheduler.sleep(Scheduler.MILLIS_100);
+
+                               progress(2,8,"Store system configuration.");
+                               if (!storeParams()) {
+                                       return;
+                                       }
+                               Scheduler.sleep(Scheduler.MILLIS_100);
+
+                               progress(3,8,"Create daemon base directory...");
+                               if (!createDaemonBase()) {
+                                       return;
+                                       }
+                               Scheduler.sleep(Scheduler.MILLIS_100);
+
+                               progress(4,8,"Create daemon template config. 
file...");
+                               if (!createDaemonTemplate()) {
+                                       return;
+                                       }
+                               Scheduler.sleep(Scheduler.MILLIS_100);
+
+                               progress(5,8,"Create clients base 
directory...");
+                               if (!createClientsBase()) {
+                                       return;
+                                       }
+                               Scheduler.sleep(Scheduler.MILLIS_100);
+
+                               progress(6,8,"Create clients template config. 
file...");
+                               if (!createClientsTemplate()) {
+                                       return;
+                                       }
+                               Scheduler.sleep(Scheduler.MILLIS_100);
+
+                               progress(7,8,"Connect to MySQL...");
+                               if (!checkMySQL()) {
+                                       return;
+                                       }
+                               Scheduler.sleep(Scheduler.MILLIS_100);
+
+                               progress(8,8,"Done !");
+                               Scheduler.sleep(Scheduler.SECS_1);
+
+                               _beurk[0]=true;
+                       }
+                       };
+               dialog.setTitle("Setup");
+               dialog.launch("Please wait while Freeway is being 
configured...\n");
+               if (_beurk[0] && fromApp) {
+                       onQuit();
+                       }
+       }
+
+       protected boolean checkParams()
+       {
+               if (daemonBaseDirectory==null) {
+                       wizard.showMessage("Setup error","You must choose a 
base directory for daemon !");
+                       return false;
+                       }
+               if (!daemonBaseDirectory.exists()) {
+                       wizard.showMessage("Setup error","Invalid daemon base 
directory ("+daemonBaseDirectory.getLabel()+") !");
+                       return false;
+                       }
+               if (clientsBaseDirectory==null) {
+                       wizard.showMessage("Setup error","You must choose a 
base directory for clients !");
+                       return false;
+                       }
+               if (!clientsBaseDirectory.exists()) {
+                       wizard.showMessage("Setup error","Invalid clients base 
directory ("+clientsBaseDirectory.getLabel()+") !");
+                       return false;
+                       }
+               if (!optionSaveOnly) {
+                       if (mysqlHost.length()==0) {
+                               wizard.showMessage("Setup error","You must 
choose an host for MySQL database !");
+                               return false;
+                               }
+                       if (mysqlUser.length()==0) {
+                               wizard.showMessage("Setup error","You must 
choose an user for MySQL database !");
+                               return false;
+                               }
+                       }
+               return true;
+       }
+
+       protected boolean storeParams()
+       {
+               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.DAEMON_BASEDIR_NAME,daemonBaseDirectory.getLabel());
+               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.CLIENTS_BASEDIR_NAME,clientsBaseDirectory.getLabel());
+               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_HOST_NAME,mysqlHost);
+               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_USER_NAME,mysqlUser);
+               
prefs.setGlobalString(Prefs.CONFIG_NODE,Prefs.MYSQL_PASSWORD_NAME,mysqlPassword);
+               return true;
+       }
+
+       protected boolean createDaemonBase()
+       {
+               if (!daemonBaseDirectory.exists()) {
+                       if (!daemonBaseDirectory.create()) {
+                               wizard.showMessage("Setup error","Unable to 
create daemon base directory ("+daemonBaseDirectory.getLabel()+") !");
+                               return false;
+                               }
+                       return true;
+                       }
+               if (!optionOverwrite) {
+                       wizard.showMessage("Setup error","Daemon base directory 
("+daemonBaseDirectory.getLabel()+") already exists.\nPlease check overwrite 
option in order to continue.");
+                       return false;
+                       }
+               return true;
+       }
+
+       protected boolean createDaemonTemplate()
+       {
+               FileLocation    f;
+
+               f=daemonBaseDirectory.getFile("gnunet.conf");
+               if (f.exists()) {
+                       if (!optionOverwrite) {
+                               wizard.showMessage("Setup error","Config. file 
("+f.getLabel()+") already exists.\nPlease check overwrite option in order to 
continue.");
+                               return false;
+                               }
+                       if (!wizard.askMessage("Setup error","Config. file 
("+f.getLabel()+") already exists.\nDo you want really want to overwrite it 
?\n(all modifications will be lost)")) {
+                               return false;
+                               }
+                       }
+               prefs.copyTemplateWithGlobals("gnunet.daemon.template",f);
+               wizard.showMessage("Setup information","Have created daemon 
configuration file.\nYou can customize it by later editing 
\""+f.getLabel()+"\".");
+               return true;
+       }
+
+       protected boolean createClientsBase()
+       {
+               if (!clientsBaseDirectory.exists()) {
+                       if (!clientsBaseDirectory.create()) {
+                               wizard.showMessage("Setup error","Unable to 
create clients base directory ("+clientsBaseDirectory.getLabel()+") !");
+                               return false;
+                               }
+                       return true;
+                       }
+               if (!optionOverwrite) {
+                       wizard.showMessage("Setup error","Clients base 
directory ("+clientsBaseDirectory.getLabel()+") already exists.\nPlease check 
overwrite option in order to continue.");
+                       return false;
+                       }
+               return true;
+       }
+
+       protected boolean createClientsTemplate()
+       {
+               FileLocation    f;
+
+               f=clientsBaseDirectory.getFile("gnunet.conf");
+               if (f.exists()) {
+                       if (!optionOverwrite) {
+                               wizard.showMessage("Setup error","Config. file 
("+f.getLabel()+") already exists.\nPlease check overwrite option in order to 
continue.");
+                               return false;
+                               }
+                       if (!wizard.askMessage("Setup error","Config. file 
("+f.getLabel()+") already exists.\nDo you want really want to overwrite it 
?\n(all modifications will be lost)")) {
+                               return false;
+                               }
+                       }
+               prefs.copyTemplateWithGlobals("gnunet.client.template",f);
+               wizard.showMessage("Setup information","Have created clients 
configuration file.\nYou can customize it by later editing 
\""+f.getLabel()+"\".");
+               return true;
+       }
+
+       protected boolean checkMySQL()
+       {
+               if (!optionSaveOnly && 
!checkMySQL(mysqlHost,mysqlUser,mysqlPassword)) {
+                       wizard.showMessage("Setup error","Unable to connect to 
MySQL database at "+mysqlHost+" (user \""+mysqlUser+"\").\nPlease enter valid 
values and try again later.\n");
+                       return false;
+                       }
+               return true;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public class WelcomeStep extends GWizardPage
+       {
+               private GStyledText     text;
+
+
+               public WelcomeStep()
+               {
+                       super("Welcome");
+               }
+
+               public JComponent createView()
+               {
+                       text=new GStyledText();
+                       StyleConstants.setFontSize(text.style(),13);
+
+                       
StyleConstants.setFontFamily(text.style("fr"),"SansSerif");
+                       StyleConstants.setBold(text.style("fr"),true);
+                       StyleConstants.setItalic(text.style("fr"),true);
+                       StyleConstants.setForeground(text.style("fr"),new 
Color(33,87,136));
+
+                       text.println("Welcome to <fr>Freeway</fr>'s initial 
configuration program.").println();
+                       text.print("First, you will be asked to enter a few 
values to describe the system you use. ");
+                       text.println("Then, the program will try to setup an 
initial configuration with collected data.").println();
+                       text.println("No file operation will be done without 
user's confirmation.");
+                       return text;
+               }
+       }
+
+       public class DaemonBaseStep extends GWizardPage
+       {
+               private GStack          stack;
+               private GStyledText     text;
+               private GFile           file;
+
+
+               public DaemonBaseStep()
+               {
+                       super("Choose daemon base directory");
+               }
+
+               public JComponent createView()
+               {
+                       text=new GStyledText();
+                       
StyleConstants.setFontFamily(text.style("fr"),"SansSerif");
+                       StyleConstants.setBold(text.style("fr"),true);
+                       StyleConstants.setItalic(text.style("fr"),true);
+                       StyleConstants.setForeground(text.style("fr"),new 
Color(33,87,136));
+                       text.print("Choose a directory where <fr>Freeway</fr> 
daemon will store needed files under.");
+
+                       file=new GFile();
+                       file.selectDirectory("Daemon base directory");
+
+                       stack=new GStack();
+                       stack.addWidget(text);
+                       stack.addWidget(file);
+                       return stack;
+               }
+
+               public void updateView()
+               {
+                       file.setSelectedLocation(daemonBaseDirectory);
+               }
+
+               public void leaveView()
+               {
+                       daemonBaseDirectory=(DirLocation) 
file.getSelectedLocation();
+               }
+       }
+
+       public class ClientsBaseStep extends GWizardPage
+       {
+               private GStack          stack;
+               private GStyledText     text;
+               private GFile           file;
+
+
+               public ClientsBaseStep()
+               {
+                       super("Choose client base directory");
+               }
+
+               public JComponent createView()
+               {
+                       text=new GStyledText();
+                       
StyleConstants.setFontFamily(text.style("fr"),"SansSerif");
+                       StyleConstants.setBold(text.style("fr"),true);
+                       StyleConstants.setItalic(text.style("fr"),true);
+                       StyleConstants.setForeground(text.style("fr"),new 
Color(33,87,136));
+                       text.print("Choose a directory where <fr>Freeway</fr>'s 
client applications will store needed files under.");
+
+                       file=new GFile();
+                       file.selectDirectory("Client base directory");
+
+                       stack=new GStack();
+                       stack.addWidget(text);
+                       stack.addWidget(file);
+                       return stack;
+               }
+
+               public void updateView()
+               {
+                       file.setSelectedLocation(clientsBaseDirectory);
+               }
+
+               public void leaveView()
+               {
+                       clientsBaseDirectory=(DirLocation) 
file.getSelectedLocation();
+               }
+       }
+
+       public class MySQLStep extends GWizardPage
+       {
+               private JTextField              hostField;
+               private JTextField              userField;
+               private JPasswordField  passwordField;
+               private GStack                  stack;
+               private GText                   text;
+               private GForm                   form;
+               private JButton                 button;
+
+
+               public MySQLStep()
+               {
+                       super("Setup MySQL database access");
+               }
+
+               public JComponent createView()
+               {
+                       hostField=new JTextField(10);
+                       userField=new JTextField(10);
+                       passwordField=new JPasswordField(10);
+
+                       text=new GText();
+                       text.setText("Enter parameters needed to connect a 
MySQL database that will store exchanged data with others peers.");
+
+                       form=new GForm();
+                       form.addWidget("Host :",hostField);
+                       form.addWidget("User :",userField);
+                       form.addWidget("Password :",passwordField);
+
+                       button=new JButton("Check...");
+                       button.addActionListener(new ActionListener() {
+                               public void actionPerformed( ActionEvent evt )
+                               {
+                                       if 
(checkMySQL(hostField.getText(),userField.getText(),new 
String(passwordField.getPassword()))) {
+                                               wizard.showMessage("MySQL 
check","Successfully established connection to database.");
+                                               }
+                                       else {
+                                               wizard.showMessage("MySQL 
check","Unable to connect to database !\nPlease correct your parameters and try 
again later.");
+                                               }
+                               }
+                               });
+
+                       stack=new GStack();
+                       stack.addWidget(text);
+                       stack.addWidget(form);
+                       stack.addWidget(button);
+                       return stack;
+               }
+
+               public void updateView()
+               {
+                       hostField.setText(mysqlHost);
+                       userField.setText(mysqlUser);
+                       passwordField.setText(mysqlPassword);
+               }
+
+               public void leaveView()
+               {
+                       mysqlHost=hostField.getText();
+                       mysqlUser=userField.getText();
+                       mysqlPassword=new String(passwordField.getPassword());
+               }
+       }
+
+       public class ConfirmationStep extends GWizardPage
+       {
+               private GStyledText     text;
+               private JCheckBox       overwrite;
+               private JCheckBox       saveOnly;
+               private Icon            dot;
+
+
+               public ConfirmationStep()
+               {
+                       super("Confirmation");
+               }
+
+               public JComponent createView()
+               {
+                       dot=new ImageIcon(resources.getImageURL("dot.icon"));
+
+                       overwrite=new JCheckBox();
+                       saveOnly=new JCheckBox();
+
+                       text=new GStyledText();
+                       StyleConstants.setLeftIndent(text.style("ind"),10);
+                       StyleConstants.setSpaceAbove(text.style("ind"),3);
+                       StyleConstants.setSpaceBelow(text.style("ind"),1);
+                       StyleConstants.setForeground(text.style("v"),new 
Color(33,87,136));
+                       
StyleConstants.setFontFamily(text.style("v"),"Monospaced");
+                       return text;
+               }
+
+               public void updateView()
+               {
+                       text.clear();
+                       text.print("Please check information you've entered are 
correct and ");
+                       text.print("choose options you would like to apply. ");
+                       text.println("Then click on Go button to complete 
configuration.");
+                       text.print("<ind>").print(dot).print(" Daemon base 
directory : <v>"+(daemonBaseDirectory!=null ? daemonBaseDirectory.getLabel() : 
"(not set)")).println("</v></ind>");
+                       text.print("<ind>").print(dot).print(" Clients base 
directory : <v>"+(clientsBaseDirectory!=null ? clientsBaseDirectory.getLabel() 
: "(not set)")).println("</v></ind>");
+                       text.print("<ind>").print(dot).print(" MySQL host : 
<v>"+mysqlHost).println("</v></ind>");
+                       text.print("<ind>").print(dot).print(" MySQL user : 
<v>"+mysqlUser).println("</v></ind>");
+                       text.print("<ind>").print(dot).print(" MySQL password : 
<v>"+(mysqlPassword.length()>0 ? "(set)" : "(not set)")).println("</v></ind>");
+                       text.println();
+                       text.print("Overwrite config. files if they already 
exist ? ").println(overwrite);
+                       text.print("Do not try to connect to MySQL, save 
parameters only ").println(saveOnly);
+
+                       overwrite.setSelected(optionOverwrite);
+                       saveOnly.setSelected(optionSaveOnly);
+               }
+
+               public void leaveView()
+               {
+                       optionOverwrite=overwrite.isSelected();
+                       optionSaveOnly=saveOnly.isSelected();
+               }
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static void main( String[] args )
+       {
+               launch(GNUNetUIConfig.class,args);
+       }
+
+       public static void fromApp()
+       {
+               GNUNetUIConfig  config;
+               Logger                  logger;
+
+               JOptionPane.showMessageDialog(null,"Launched application needs 
minimal system configuration\nin order to run properly. Please enter needed 
information\nin wizard that will pop 
up...","Setup",JOptionPane.INFORMATION_MESSAGE);
+
+               try {
+                       config=new GNUNetUIConfig();
+                       config.setFromApp();
+                       config.run();
+                       }
+               catch( Throwable x ) {
+                       logger=Logger.getLogger(GNUNetUIConfig.class.getName());
+                       logger.log(Level.SEVERE,"Unable to run wizard !",x);
+                       }
+       }
+}

Added: freeway/src/org/gnu/freeway/Server.java
===================================================================
--- freeway/src/org/gnu/freeway/Server.java     2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/src/org/gnu/freeway/Server.java     2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,68 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.net.*;
+
+/**
+ *
+ */
+
+public interface Server extends Application
+{
+       public MessagesDispatcher getDispatcher();
+
+       public LocalIdentity getKeys();
+
+       /**
+        * Return wheter or not there is a method handler
+        * registered for a specific Client-Server message type.
+        * @param type the message type
+        * @return true if there is a handler for the type,
+        *      NO if there isn't
+        */
+
+       public boolean isCSHandlerRegistered( int type );
+
+       /**
+        * Register a method as a handler for specific message types.
+        *
+        * @param type the message type
+        * @param c
+        * @param handler the method to call if a message of that type is 
received
+        * @return true on success, false if there is already a handler for 
that type
+        */
+
+       public boolean registerCSHandler( int type, Class c, CSHandler handler 
);
+
+       /**
+        * Remove a method as a handler for specific message types.
+        *
+        * @param type the message type
+        * @param handler the method to call if a message of that type is 
received
+        * @return true on success, false if there is a different handler for 
that type
+        */
+
+       public boolean unregisterCSHandler( int type, CSHandler handler );
+
+       /**
+        * Register a handler to call if any client exits.
+        *
+        * @param callback a method to call with the socket of every client 
that disconnected.
+        * @return true on success, false on error
+        */
+
+       public boolean registerCSExitHandler( ClientExitHandler callback );
+
+       /**
+        * Unregister a handler to call if any client exits.
+        *
+        * @param callback a method to call with the socket of every client 
that disconnected.
+        * @return true on success, false on error
+        */
+
+       public boolean unregisterCSExitHandler( ClientExitHandler callback );
+}

Added: freeway/src/org/gnu/freeway/gnunet-check.c
===================================================================
--- freeway/src/org/gnu/freeway/gnunet-check.c  2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/src/org/gnu/freeway/gnunet-check.c  2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,1356 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2003 Christian Grothoff (and other contributing authors)
+
+     GNUnet 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, or (at your
+     option) any later version.
+
+     GNUnet 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 GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file applications/afs/module/gnunet-check.c
+ * @brief Little tool to do consistency check of the AFS databases.
+ * @author Christian Grothoff
+ *
+ * FIXME: If some database bucket has entries that do not belong
+ * there, the current code will just delete them. It'd be nice if they
+ * could be moved instead.
+ * 
+ **/
+
+#include "gnunet_util.h"
+#include "gnunet_afs_esed2.h"
+
+#include "fileindex.c"
+#include "large_file_support.c"
+#include "manager.c"
+#include "bloomfilter.c"
+
+static DatabaseAPI * dbAPI;
+
+/* configuration: do we fix problems? */
+static int do_fix = YES;
+/* configuration: do we reset bloomfilters? */
+static int do_reset = NO;
+
+/* priority of fixed content */
+static unsigned int fixedPriority;
+/* priority of reindexed content */
+static unsigned int indexPriority;
+
+/* tcp server result: were all the requests satisfied? */
+static int tcp_verifies;
+
+static int be_verbose = NO;
+static int be_quiet = NO;
+
+static void PRINTQ(char * format,
+                  ...) {
+  va_list args;
+  if (be_quiet == YES)
+    return;
+  va_start(args, format);
+  vfprintf(stdout, format, args);
+  va_end(args);
+}
+
+static void PRINTV(char * format,
+                  ...) {
+  va_list args;
+  if (be_verbose == NO)
+    return;
+  va_start(args, format);
+  vfprintf(stdout, format, args);
+  va_end(args);
+}
+
+
+/**
+ * Check that the content at the given offset/file
+ * has the given double hash.
+ **/
+static int checkHashMatch(unsigned short fileNameIndex,
+                         size_t offset,
+                         HashCode160 * chkquery) {
+  CONTENT_Block result;
+  CONTENT_Block eresult;
+  char * fn;
+  HashCode160 hc;
+  HashCode160 dhc;
+  int fileHandle;
+  size_t blen;
+  /* check that the specified file at the specified
+     offset actually contains the content that we
+     are looking for */
+
+  fn = getIndexedFileName(fileNameIndex);
+  if (fn == NULL)
+    return SYSERR;
+  fileHandle = OPEN(fn, O_EXCL, S_IRUSR);
+  if (fileHandle == -1) {
+    LOG(LOG_WARNING, 
+       "WARNING: Could not open file %s (%u).\n",
+       fn,
+       fileNameIndex);    
+    FREE(fn);
+    return SYSERR;
+  }
+  lseek(fileHandle, 
+       offset, SEEK_SET);
+  memset(&result, 
+        0, 
+        sizeof(CONTENT_Block));
+  blen = READ(fileHandle, 
+             &result,
+             sizeof(CONTENT_Block));
+  CLOSE(fileHandle);
+  hash(&result, 
+       blen, 
+       &hc);
+  encryptContent(&result,
+                &hc,
+                &eresult);
+  hash(&eresult,
+       sizeof(CONTENT_Block),
+       &dhc);
+  if (!equalsHashCode160(&dhc,
+                        chkquery)) {
+    LOG(LOG_WARNING, 
+       "WARNING: content found in %s at %d does not match expected hash.\n",
+       fn,
+       offset);    
+    FREE(fn);
+    return SYSERR;
+  } else {
+    FREE(fn);
+    return OK;
+  }
+}
+
+typedef struct {
+  HashCode160 hc;
+  int bucket;
+} RemoveList ;
+
+static RemoveList * removeList = NULL;
+static int removeCount = 0;
+
+/**
+ * We can't remove the bogus content instantly since that would be a
+ * concurrent modification while using the iterator. Thus we remember
+ * the keys to remove and do it later.
+ **/
+static void deferredRemove() {
+  int i;
+  HexName hex;
+
+  for (i=0;i<removeCount;i++)
+    if (OK != removeContent(&removeList[i].hc,
+                           removeList[i].bucket)) {
+      hash2hex(&removeList[i].hc,
+              &hex);
+      PRINTQ("Deferred content removal of %s failed!\n",
+            &hex);
+    }
+  GROW(removeList,
+       removeCount,
+       0);
+}
+
+/**
+ * If we are fixing problems, remove this content and
+ * print the appropriate messages.
+ **/
+static void ifFixRemove(HashCode160 * query, 
+                       int bucket) {
+  if (do_fix == YES) {    
+    GROW(removeList,
+        removeCount,
+        removeCount+1);
+    memcpy(&removeList[removeCount-1].hc,
+          query,
+          sizeof(HashCode160));
+    removeList[removeCount-1].bucket = bucket;
+    PRINTQ("Will fix (deferred).\n");
+  } else
+    PRINTQ("\n");        
+}
+
+/**
+ * This function is called for each entry in the
+ * content/index/lookup database.
+ **/
+static void checkDatabaseContent(HashCode160 * query,
+                                ContentIndex * ce,
+                                int bucket,
+                                void * result,
+                                int len) {
+  HexName hn;
+  
+  hash2hex(query,
+          &hn);  
+
+  if (computeBucketGlobal(query) != (unsigned int)bucket) {
+    PRINTQ("Entry %s is in wrong bucket %d (expected %d). ",
+          (char*)&hn,
+          bucket,
+          computeBucketGlobal(query));
+    ifFixRemove(query,
+               bucket);
+    return;
+  }
+  switch(ntohs(ce->type)) {
+  case LOOKUP_TYPE_CHK:
+    if (len != 0) {
+      if (len != sizeof(CONTENT_Block)) {
+       PRINTQ("Bad content stored for %s (bad length %d). ",
+              (char*)&hn, 
+              len);
+       ifFixRemove(query,
+                   bucket); 
+       break;
+      }
+    } else {
+      if (SYSERR == checkHashMatch(ntohs(ce->fileNameIndex),
+                                  ntohl(ce->fileOffset),
+                                  query)) {
+       PRINTQ("Bad CHK content indexed for %s ",
+              (char*)&hn);
+       ifFixRemove(query,
+                   bucket); 
+       break;
+      }
+    }
+    if (do_reset == YES) {
+       addToBloomfilter(singleBloomFilter,
+                        query);
+    } else {
+      if (testBloomfilter(singleBloomFilter,
+                         query) == NO) {
+       PRINTQ("Bloomfilter test failed for CHK content %s ",
+              (char*)&hn);
+       if (do_fix == YES) {
+         addToBloomfilter(singleBloomFilter,
+                          query);
+         PRINTQ("Fixed.\n");
+       } else
+         PRINTQ("\n"); 
+      }
+    }
+    break;
+  case LOOKUP_TYPE_CHKS:
+    if (len != 0) {
+      if (len != sizeof(CONTENT_Block)) {
+       PRINTQ("Bad content stored for %s (bad length %d) ",
+              (char*)&hn, 
+              len);
+       ifFixRemove(query,
+                   bucket); 
+       break;
+      }
+    } else {
+      if (SYSERR == checkHashMatch(ntohs(ce->fileNameIndex),
+                                  ntohl(ce->fileOffset),
+                                  query)) {
+       PRINTQ("Bad CHKS content indexed for %s ",
+              (char*)&hn);
+       ifFixRemove(query,
+                   bucket);
+       break;
+      }
+    }
+    break;
+  case LOOKUP_TYPE_3HASH:
+    if (do_reset == YES) {
+       addToBloomfilter(singleBloomFilter,
+                        query);
+    } else {
+      if (testBloomfilter(singleBloomFilter,
+                         query) == NO) {
+       PRINTQ("Bloomfilter test failed for 3HASH content %s ",
+              (char*)&hn);
+       if (do_fix == YES) {
+         addToBloomfilter(singleBloomFilter,
+                          query);
+         PRINTQ("Fixed.\n");
+       } else
+         PRINTQ("\n"); 
+      }
+    }
+    break;
+  case LOOKUP_TYPE_SUPER:
+    if (do_reset == YES) {
+       addToBloomfilter(superBloomFilter,
+                        query);
+    } else {
+      if (testBloomfilter(superBloomFilter,
+                         query) == NO) {
+       PRINTQ("Bloomfilter test failed for SUPER hash %s ",
+              (char*)&hn);
+       if (do_fix == YES) {
+         addToBloomfilter(superBloomFilter,
+                          query);
+         PRINTQ("Fixed.\n");
+       } else
+         PRINTQ("\n"); 
+      }
+    }
+    break;
+  case LOOKUP_TYPE_SBLOCK:
+    if (do_reset == YES) {
+       addToBloomfilter(singleBloomFilter,
+                        query);
+    } else {
+      if (testBloomfilter(singleBloomFilter,
+                         query) == NO) {
+        PRINTQ("Bloomfilter test failed for SBLOCK content %s ",
+              (char*)&hn);
+       if (do_fix == YES) {
+         addToBloomfilter(singleBloomFilter,
+                          query);
+         PRINTQ("Fixed.\n");
+       } else
+         PRINTQ("\n"); 
+      }
+    }
+    break;
+  default:
+    PRINTQ("ERROR: unexpected content type %d. ",
+          ntohs(ce->type));
+    ifFixRemove(query,
+               bucket);
+    break;
+  }
+}
+
+/**
+ * Check that for each entry in the contentdatabase
+ * there is an entry in the lookup-database.
+ **/
+static void checkDatabase() {
+  void * iterState;
+  int count;
+  HashCode160 hc;
+  ContentIndex ce;
+  void * data;
+  int len;
+  int bucket;
+  
+  PRINTQ("Checking Content Database\n");
+  count = 0;
+  iterState = makeDatabaseIteratorState();
+  data = NULL;
+  while (OK == databaseIterator(iterState,
+                               &hc,
+                               &ce,
+                               &bucket,
+                               &data,
+                               &len)) {
+    checkDatabaseContent(&hc,
+                        &ce,
+                        bucket,
+                        data,
+                        len);
+    count++;
+    FREENONNULL(data);
+    data = NULL;
+  } 
+  deferredRemove();
+  PRINTQ("\n==> Done checking %d entries in content database.\n", 
+        count);
+}
+
+/**
+ * Process a request to insert content from the client.
+ * @return SYSERR if the TCP connection should be closed, otherwise OK
+ **/
+static int checkInsertCHK(GNUNET_TCP_SOCKET * sock,
+                         AFS_CS_INSERT_CHK * insertRequest) {
+  CONTENT_Block * block;
+  int len;
+  int dup;
+  ContentIndex entry;
+  HashCode160 hc;
+  HexName hn;
+
+  if (ntohs(insertRequest->header.size) != 
+      sizeof(AFS_CS_INSERT_CHK)) {
+    sendTCPResult(sock, SYSERR);
+    return SYSERR;
+  }
+
+  memset(&entry,
+        0,
+        sizeof(ContentIndex));
+
+  block = NULL;
+  hash(&insertRequest->content,
+       sizeof(CONTENT_Block),
+       &hc);
+  hash2hex(&hc,
+          &hn);
+  PRINTV("* %s (ins)\n",
+        (char*)&hn);
+  len = retrieveContent(&hc,
+                       &entry,
+                       (void**)&block,
+                       0,
+                       NO);
+  if(len == sizeof(CONTENT_Block)) 
+    if (0 != memcmp(&insertRequest->content,
+                   block,
+                   sizeof(CONTENT_Block)) )      
+      len = SYSERR;
+  FREENONNULL(block);
+  if (ntohs(entry.type) != LOOKUP_TYPE_CHK) 
+    len = SYSERR;
+  
+  if (len == SYSERR || ntohl(entry.importance)<fixedPriority) {
+    PRINTQ("Content %s %s in database. ",
+          (char*) &hn,
+           (len == SYSERR ? "malformed or missing" : "has low priority"));
+    if (do_fix == YES) {
+      entry.type = htons(LOOKUP_TYPE_CHK); /* CHK or CHKS? How can we tell? 
FIXME! */
+      entry.importance = htonl(fixedPriority); 
+      memcpy(&entry.hash,
+            &hc,
+            sizeof(HashCode160));
+      entry.fileNameIndex = htons(0);
+      entry.fileOffset    = htonl(0);
+      if (OK == insertContent(&entry, 
+                             sizeof(CONTENT_Block),
+                             &insertRequest->content,
+                             NULL, /* sender = localhost */
+                             &dup)) {
+       PRINTQ("Fixed.\n");
+      } else {
+       PRINTQ("WARNING: can not fix (database full?)\n");
+      }
+    } else 
+      PRINTQ("\n");
+  }      
+
+  sendTCPResult(sock, OK);
+  return OK;
+}
+
+/**
+ * Process a request to insert content from the client.
+ * @return SYSERR if the TCP connection should be closed, otherwise OK
+ **/
+static int checkInsert3HASH(GNUNET_TCP_SOCKET * sock,
+                           AFS_CS_INSERT_3HASH * insertRequest) {
+  LOG(LOG_WARNING,
+      "WARNING: did not expect 3HASH insert invocation!\n");
+  sendTCPResult(sock, OK);
+  return OK;
+}
+
+static int checkSuper(GNUNET_TCP_SOCKET * sock,
+                     AFS_CS_INDEX_SUPER * superIndexRequest) {
+  ContentIndex entry;
+  ContentIndex entry2;
+  void * result;
+  int len;  
+  int dup;
+
+  if (ntohs(superIndexRequest->header.size) != 
+      sizeof(AFS_CS_INDEX_SUPER)) {
+    LOG(LOG_WARNING, 
+       "WARNING: super-hash indexing request from client was malformed!\n");
+    return SYSERR;
+  }
+  if (NO == testBloomfilter(superBloomFilter,
+                           &superIndexRequest->superHash)) { 
+    if (do_reset == NO)
+      PRINTQ("Super-Hash not listed in super-hash bloom filter ");
+    if (do_fix == YES) {
+      addToBloomfilter(superBloomFilter,
+                      &superIndexRequest->superHash);
+      if (do_reset == NO)
+        PRINTQ("Fixed.\n");
+    } else
+      if (do_reset == NO)
+        PRINTQ("\n");
+  }
+  entry.type
+    = htons(LOOKUP_TYPE_SUPER);
+  entry.importance
+    = htonl(fixedPriority); 
+  entry.fileNameIndex 
+    = 0; /* database */
+  entry.fileOffset 
+    = 0; /* data/content */
+  memcpy(&entry.hash,
+        &superIndexRequest->superHash,
+        sizeof(HashCode160));
+  result = NULL;
+  memset(&entry2,
+        0,
+        sizeof(ContentIndex));
+  len = retrieveContent(&superIndexRequest->superHash,
+                       &entry2,
+                       &result,
+                       0,
+                       NO);
+  FREENONNULL(result);
+  if (SYSERR == len || ntohl(entry2.importance)<fixedPriority) {
+    HexName expect;
+    
+    hash2hex(&superIndexRequest->superHash,
+            &expect);
+    PRINTQ("Did not find super-hash entry in "
+          "lookup database for hash %s (or had low priority). ",
+          (char*)&expect);    
+    if (do_fix == YES) {
+      if (OK == insertContent(&entry, 
+                             0,
+                             NULL,
+                             NULL,
+                             &dup)) {
+       PRINTQ("Fixed.\n");
+      } else {
+       PRINTQ("Failed to fix.\n");
+      }
+    } else
+      PRINTQ("\n"); 
+  } else {
+    entry2.importance = entry.importance;
+    if (0 != memcmp(&entry, 
+                   &entry2, 
+                   sizeof(ContentIndex))) {
+      HexName have;
+      HexName expect;
+      
+      hash2hex(&entry2.hash,
+              &have);
+      hash2hex(&entry.hash,
+              &expect);
+      PRINTQ("Entry in database for super-hash does not "
+            "match expectations (have: %s, %u, %u, %u; "
+            "expected: %s, %u, %u, %u). ",
+            (char*)&have, 
+            ntohl(entry2.importance),
+            ntohs(entry2.fileNameIndex), 
+            ntohl(entry2.fileOffset),
+            (char*)&expect,
+            ntohl(entry.importance), 
+            ntohs(entry.fileNameIndex), 
+            ntohl(entry.fileOffset));    
+      if (do_fix == YES) {
+       if (OK == insertContent(&entry, 
+                               0,
+                               NULL,
+                               NULL,
+                               &dup)) {
+         PRINTQ("Fixed.\n");
+       } else {
+         PRINTQ("Failed to fix.\n");
+       }
+      } else
+       PRINTQ("\n");
+    }
+  }
+  return sendTCPResult(sock, 
+                      OK);
+}
+
+/**
+ * Process a request to index content from the client.
+ * @return SYSERR if the TCP connection should be closed, otherwise OK
+ **/
+static int checkIndex(GNUNET_TCP_SOCKET * sock,
+                     AFS_CS_INDEX_BLOCK * indexingRequest) {
+  HashCode160 triple;
+  HashCode160 * query;
+  ContentIndex res;
+  HexName hn;
+  void * data;
+  int len;
+  int dup;
+
+  hash2hex(&indexingRequest->contentIndex.hash,
+          &hn);
+  PRINTV("* %s (idx)\n",
+        (char*)&hn);
+  switch (ntohs(indexingRequest->contentIndex.type)) {
+  case LOOKUP_TYPE_3HASH:
+    hash(&indexingRequest->contentIndex.hash,
+        sizeof(HashCode160),
+        &triple);
+    query = &triple;
+    break;
+  case LOOKUP_TYPE_CHK:
+  case LOOKUP_TYPE_CHKS:
+    query = &indexingRequest->contentIndex.hash;
+    break;
+  default:  
+    LOG(LOG_ERROR,
+       "ERROR: Unexpected content index type: %d.\n",
+       ntohs(indexingRequest->contentIndex.type));
+    return SYSERR; 
+  }
+  if (ntohs(indexingRequest->header.size) != 
+      sizeof(AFS_CS_INDEX_BLOCK)) {
+#if PRINT_TCP
+    printf("TCP: WARNING: indexing request malformed!\n");
+#endif
+    sendTCPResult(sock, SYSERR);
+    return SYSERR;
+  }
+#if PRINT_TCP 
+  printf("TCP: received indexing request\n");
+#endif
+  /* check if everything is already in place, and if not and 
+     we are allowed to fix, do the write-actions: */
+  memset(&res,
+        0,
+        sizeof(ContentIndex));
+
+  data = NULL;
+  len = retrieveContent(query,
+                       &res,
+                       &data,
+                       0,
+                       NO);
+  FREENONNULL(data);
+  indexingRequest->contentIndex.importance 
+    = htonl(indexPriority);
+  if ( (len == SYSERR) || 
+       (ntohl(res.importance) < indexPriority)) {
+    PRINTQ("Content %s %s in lookup database. ",
+          (char*) &hn,
+          (len == SYSERR) ? "not indexed" : "had low priority");
+    if (do_fix == YES) {
+      if (SYSERR ==
+         insertContent(&indexingRequest->contentIndex,
+                       0,
+                       NULL,
+                       NULL,
+                       &dup)) {
+       PRINTQ("Could not fix, insertion failed.\n");
+      } else {
+       PRINTQ("Fixed.\n");
+      }
+    } else
+      PRINTQ("\n");
+  } else { /* test if correct */
+    if (0 != memcmp(&res.hash, 
+                   &indexingRequest->contentIndex.hash,
+                   sizeof(HashCode160))) {
+      PRINTQ("Bad value (hash) stored in database ");
+      if (do_fix == YES) {
+       if (SYSERR ==
+           insertContent(&indexingRequest->contentIndex,
+                         0,
+                         NULL,
+                         NULL,
+                         &dup)) {
+         PRINTQ("Could not fix, insertion failed.\n");
+       } else {
+         PRINTQ("Fixed.\n");
+       }
+      } else
+       PRINTQ("\n");
+    }
+  }
+  sendTCPResult(sock, OK);
+  return OK;
+}
+
+
+/**
+ * Process a query to list a file as on-demand encoded from the client.
+ * (code copied from afs/handler.c).
+ *
+ * @return SYSERR if the TCP connection should be closed, otherwise OK
+ **/
+static int csHandleRequestIndexFile(GNUNET_TCP_SOCKET * sock,
+                                   AFS_CS_INDEX_FILE * listFileRequest) {
+  HexName hex;
+  char * filename;
+  char * prefix;
+  int ret;
+
+  if (ntohs(listFileRequest->header.size) != 
+      sizeof(AFS_CS_INDEX_FILE)) {
+    LOG(LOG_WARNING, 
+       "WARNING: file indexing request from client was malformed!\n");
+    return SYSERR;
+  }
+  hash2hex(&listFileRequest->hash,
+          &hex);
+  filename = getConfigurationString("AFS",
+                                   "INDEX-DIRECTORY");
+  if (filename == NULL) {
+    LOG(LOG_WARNING,
+       "WARNING: rejecting content-unindex request, INDEX-DIRECTORY option not 
set!\n");
+    return -1;
+  }
+  prefix = expandFileName(filename);
+  FREE(filename);
+  filename = MALLOC(strlen(prefix) + 42);
+  strcpy(filename, prefix);
+  FREE(prefix);
+  strcat(filename, "/");
+  strcat(filename, (char*) &hex);
+
+  ret = sendTCPResult(sock, 
+                     appendFilename(filename));
+  FREE(filename);
+  return ret;
+}
+
+
+/**
+ * Handle data available on the TCP socket descriptor;
+ * check that the request is already fullfilled.
+ **/
+static void checkProcessor(int * sockptr) {
+  CS_HEADER * hdr;
+  GNUNET_TCP_SOCKET sock;
+  int i;
+  int sockDescriptor;
+
+  sockDescriptor = *sockptr;
+
+  /* register the socket */
+  initGNUnetServerSocket(sockDescriptor,
+                        &sock);
+  while (1) {
+    hdr = NULL;    
+    if (SYSERR == readFromSocket(&sock,
+                                &hdr) )
+      break; /* connection closed */
+    /* demultiplex */
+    switch (ntohs(hdr->tcpType)) {
+    case AFS_CS_PROTO_INDEX_FILE:
+      i = csHandleRequestIndexFile(&sock,
+                                  (AFS_CS_INDEX_FILE*)hdr);
+      break;
+    case AFS_CS_PROTO_UPLOAD_FILE:
+      /* for now: just ignore */
+      i = sendTCPResult(&sock, 
+                       OK);
+      break;
+    case AFS_CS_PROTO_INSERT_3HASH:
+      i = checkInsert3HASH(&sock,
+                          (AFS_CS_INSERT_3HASH*)hdr);
+      break;
+    case AFS_CS_PROTO_INSERT_CHK:
+      i = checkInsertCHK(&sock,
+                        (AFS_CS_INSERT_CHK*)hdr);
+      break;
+    case AFS_CS_PROTO_INDEX_BLOCK:
+      i = checkIndex(&sock,
+                    (AFS_CS_INDEX_BLOCK*) hdr);
+      break;
+    case AFS_CS_PROTO_INDEX_SUPER: 
+      i = checkSuper(&sock,
+                    (AFS_CS_INDEX_SUPER*) hdr);
+      break;
+    default:
+      i = SYSERR;
+      break;
+    } /* end of switch */
+    if (OK != i) {
+      break;
+    }
+    FREE(hdr);
+  }
+  destroySocket(&sock);
+}
+
+/**
+ * Check that the given file is properly indexed
+ * (and fix if appropriate). Also return SYSERR
+ * if the file is gone and should thus be removed
+ * from the list.
+ **/
+int checkIndexedFile(char * name,
+                    int index,
+                    GNUNET_TCP_SOCKET * sock) {
+  int result;
+  Block * top;
+
+  PRINTQ("* %s\n",
+        name);
+  top = insertFile(sock,
+                  name,
+                  NULL,
+                  NULL);
+  if (top != NULL) {
+    top->vtbl->done(top, NULL);
+    result = tcp_verifies;
+  } else
+    result = SYSERR;
+  if (result == SYSERR) {
+    PRINTQ("Problem checking indexing of file %s ",
+          name);
+    if (do_fix == YES) {
+      PRINTQ("Removing file from list.\n");
+      return SYSERR; /* remove file, there was a problem */
+    } else {
+      PRINTQ("\n");
+      return OK;
+    }
+  }
+  return OK;
+}
+
+/**
+ * Check that all files that are listed in
+ * the list of indexed files actually exist
+ * and that they are properly indexed in the
+ * lookup (triple->double hash) database.
+ **/
+static void checkIndexedFileList() {
+  GNUNET_TCP_SOCKET * sock;
+  int count;
+
+  sock = getClientSocket();
+  if (sock == NULL)
+    errexit("FATAL: could not create socket.\n");
+  PRINTQ("Checking indexed files\n");
+  count = forEachIndexedFile((IndexedFileNameCallback)&checkIndexedFile,
+                            sock);
+  PRINTQ("==> Done with %d indexed files.\n",
+        count);
+  releaseClientSocket(sock);
+}
+
+/**
+ * Print a list of the options we offer.
+ **/
+static void printhelp() {
+  static Help help[] = {
+    HELP_CONFIG,
+    { 'a', "all", NULL,
+      "check everything" },
+    { 'D', "data", NULL,
+      "only check the content database" },
+    { 'f', "files", NULL,
+      "only check the indexed files" },
+    HELP_HELP,
+    HELP_LOGLEVEL,
+    { 'n', "nofix", NULL,
+      "do not fix problems, only report" },
+    { 'p', "prio", "PRIORITY",
+      "specifies the priority of the restored content" },
+    { 'q', "quiet", NULL,
+      "be quiet" },
+    { 'r', "reset", NULL,
+      "reset bloom-filters (requires 'a' option, slow)" },
+    { 'u', "update", NULL,
+      "perform database-updates necessary after GNUnet version change" },
+    HELP_VERSION,
+    HELP_VERBOSE,
+    HELP_END,
+  };
+  formatHelp("gnunet-check [OPTIONS]",
+            "Check GNUnet AFS databases.\n"
+            "Never run gnunet-check while gnunetd is running!",
+            help);
+}
+
+/**
+ * Perform option parsing from the command line. 
+ **/
+static int parseCommandLine(int argc, 
+                           char * argv[]) {
+  int c;
+
+  /* set the 'magic' code that indicates that
+     this process is 'gnunetd' (and not any of
+     the user-tools).  Needed such that we use
+     the right configuration file... */
+  FREENONNULL(setConfigurationString("GNUNETD",
+                                    "_MAGIC_",
+                                    "YES"));
+  FREENONNULL(setConfigurationString("GNUNETD",
+                                    "LOGFILE",
+                                    NULL));
+  FREENONNULL(setConfigurationString("GNUNET-INSERT",
+                                    "INDEX-CONTENT",
+                                    "YES"));
+  while (1) {
+    int option_index = 0;
+    static struct GNoption long_options[] = {
+      LONG_DEFAULT_OPTIONS,
+      { "all",     0, 0, 'a' },
+      { "data",    0, 0, 'D' },
+      { "files",   0, 0, 'f' },
+      { "nofix",   0, 0, 'n' },
+      { "prio",    1, 0, 'p' },
+      { "reset",   0, 0, 'r' },
+      { "update",  0, 0, 'u' },
+      { "verbose", 0, 0, 'V' },
+      { "quiet",   0, 0, 'q' },
+      { 0,0,0,0 }
+    };
+    
+    c = GNgetopt_long(argc,
+                     argv, 
+                     "vhdc:nDp:faVqruL:", 
+                     long_options, 
+                     &option_index);    
+    if (c == -1) 
+      break;  /* No more flags to process */
+    if (YES == parseDefaultOptions(c, GNoptarg))
+      continue;    
+    switch(c) {
+    case 'L':
+      FREENONNULL(setConfigurationString("GNUNETD",
+                                        "LOGLEVEL",
+                                        GNoptarg));
+     break;
+    case 'q':
+      be_quiet = YES;
+      break;
+    case 'a':
+      FREENONNULL(setConfigurationString("GNUNET-CHECK",
+                                        "MODE",
+                                        "a"));
+      break;
+    case 'D':
+      FREENONNULL(setConfigurationString("GNUNET-CHECK",
+                                        "MODE",
+                                        "d"));
+      break;
+    case 'f':
+      FREENONNULL(setConfigurationString("GNUNET-CHECK",
+                                        "MODE",
+                                        "f"));
+      break;
+    case 'h': 
+      printhelp(); 
+      return SYSERR;
+    case 'r':
+      FREENONNULL(setConfigurationString("GNUNET-CHECK",
+                                        "RESETBLOOMFILTERS",
+                                        "YES"));
+      do_reset = YES;
+      break;
+    case 'u':
+      FREENONNULL(setConfigurationString("GNUNET-CHECK",
+                                        "UPDATE",
+                                        "YES"));
+      do_reset = YES;
+      break;
+    case 'p': {
+      unsigned int prio;
+      
+      if (1 != sscanf(GNoptarg, "%ud", &prio)) {
+       LOG(LOG_FAILURE,
+           "FAILURE: You must pass a number to the -p option.\n");
+       return SYSERR;
+      }
+      setConfigurationInt("GNUNET-CHECK",
+                         "FIXED-PRIORITY",
+                         prio);
+      break;
+    }
+    case 'n':
+     do_fix = NO;
+      break;
+    case 'v': 
+      printf("GNUnet v%s, gnunet-check v%s\n",
+            VERSION, AFS_VERSION);
+      return SYSERR;
+    case 'V':
+      be_verbose = YES;
+      break;
+    default:
+      printf("Unknown option %c. Aborting.\n"
+            "Use --help to get a list of options.\n",
+            c);
+      return SYSERR;
+    } /* end of parsing commandline */
+  }
+  if (GNoptind < argc) {
+    printf("Invalid arguments: ");
+    while (GNoptind < argc)
+      printf("%s ", argv[GNoptind++]);
+    printf("\nExiting.\n");
+    return SYSERR;
+  }
+  if (do_fix == NO) 
+    PRINTQ("You selected verification only, will not fix problems!\n");
+  return OK;
+}
+
+typedef struct {
+  int fd;
+  PTHREAD_T pt;
+} CSPair;
+
+
+static Semaphore * serverSignal;
+static int listenerFD;
+
+/**
+ * Initialize the TCP port and listen for incoming connections.
+ **/
+static void * tcpListenMain() {
+  CSPair * clients = NULL;
+  int clientsSize = 0;
+
+  int incomingFD;
+  int lenOfIncomingAddr;
+  int listenerPort;
+  struct sockaddr_in serverAddr, clientAddr;
+  const int on = 1;
+
+  listenerPort = getGNUnetPort(); 
+  /* create the socket */
+  if ( (listenerFD = SOCKET(PF_INET, SOCK_STREAM, 0)) < 0) 
+    errexit("Error opening socket. Is gnunetd running?\n");
+ 
+  /* fill in the inet address structure */
+  memset((char *) &serverAddr, 0, sizeof(serverAddr));
+  serverAddr.sin_family 
+    = AF_INET;
+  serverAddr.sin_addr.s_addr
+    = htonl(INADDR_ANY);
+  serverAddr.sin_port   
+    = htons(listenerPort);
+ 
+  if ( SETSOCKOPT(listenerFD, 
+                 SOL_SOCKET, 
+                 SO_REUSEADDR, 
+                 &on, sizeof(on)) < 0 )
+    perror("setsockopt");
+
+  if (BIND(listenerFD, 
+          (struct sockaddr *) &serverAddr,
+          sizeof(serverAddr)) < 0)
+    errexit("Error (%s) binding the TCP listener to port. Is gnunetd 
running?\n",
+           STRERROR(errno));
+  
+  /* start listening for new connections */
+  LISTEN(listenerFD, 1); 
+  SEMAPHORE_UP(serverSignal);
+  /* process incoming data */
+  while (listenerFD != -1) {
+    /* wait for a connection and process it */
+    lenOfIncomingAddr = sizeof(clientAddr);
+    incomingFD = ACCEPT(listenerFD,
+                       (struct sockaddr *)&clientAddr, 
+                       &lenOfIncomingAddr);
+    if (incomingFD < 0) {
+      if (listenerFD != -1)
+       LOG(LOG_ERROR, 
+           "ERROR accepting new connection.\n");
+      continue;
+    }
+    LOG(LOG_DEBUG, 
+       "TCP: starting server\n");
+    GROW(clients,
+        clientsSize,
+        clientsSize+1);
+    clients[clientsSize-1].fd = incomingFD;
+    if ((PTHREAD_CREATE(&clients[clientsSize-1].pt,
+                       (PThreadMain) &checkProcessor, 
+                       (void *)&incomingFD,
+                       16*1024)) != 0) {
+      LOG(LOG_ERROR, 
+         "Error creating thread to handle new incoming connection.\n");    
+      CLOSE(incomingFD);
+      GROW(clients,
+          clientsSize,
+          clientsSize-1);
+    }
+  } /* while (listenerFD != -1) */
+  while (clientsSize > 0) {
+    void * unused;
+
+    SHUTDOWN(clients[clientsSize-1].fd, 2);
+    PTHREAD_JOIN(&clients[clientsSize-1].pt, &unused);
+    GROW(clients,
+        clientsSize,
+        clientsSize-1);
+  }
+  return NULL;
+} 
+
+/**
+ * Maximum length of the name of an indexed file (with path).
+ **/ 
+#define MAX_LINE_SIZE 1024
+
+/**
+ * Update from 0.6.1b to 0.6.2.  Difference is that
+ * now all files listed in the index-list must
+ * be in INDEX-DIRECTORY and have the hash of the
+ * contents for the name.  This code adds the
+ * correct links and updates the list.
+ */
+static int update061b() {
+  char * filename;
+  char * indexDir;
+  FILE * handle;
+  char * result;
+  char * line;
+  char * fil;
+  char * afsdir;
+  int fix_count;
+  char ** lines;
+  int line_count;
+  int i;
+ 
+  afsdir = getFileName("AFS",
+                      "AFSDIR",
+                      "Configuration file must specify filename for"\
+                      " storing AFS data in section"\
+                      " %s under %s.\n");
+  fil = MALLOC(strlen(afsdir)+
+              strlen(DATABASELIST)+2);
+  strcpy(fil, afsdir);
+  mkdirp(fil); /* important: the directory may not exist yet! */
+  strcat(fil, "/");
+  strcat(fil, DATABASELIST);
+  FREE(afsdir);
+
+  handle = FOPEN(fil, "r+");
+  if (handle == NULL) {
+    /* no indexed files, nothing to do! */
+    FREE(fil);
+    return OK;
+  }
+  filename = getConfigurationString("AFS",
+                                   "INDEX-DIRECTORY");
+  if (filename == NULL) {
+    LOG(LOG_WARNING,
+       "WARNING: can not fix indexed content, INDEX-DIRECTORY option not 
set!\n");
+    FREE(fil);
+    return SYSERR;
+  }
+  indexDir = expandFileName(filename);
+  mkdirp(indexDir);
+  FREE(filename);  
+
+
+  fseek(handle, 0, SEEK_SET);
+  line = MALLOC(MAX_LINE_SIZE);
+  result = line;
+  lines = NULL;
+  line_count = 0;
+  fix_count = 0;
+  while (1) {    
+    result = fgets(line, MAX_LINE_SIZE - 1, handle);
+    if (result == NULL)
+      break;
+    GROW(lines,
+        line_count,
+        line_count+1);
+    if (strlen(result) > 1) {
+      lines[line_count-1] = STRDUP(result);
+      if (0 != strncmp(result,
+                      indexDir,
+                      strlen(indexDir))) 
+       fix_count++;
+    }
+  }
+  if (fix_count == 0) {
+    fclose(handle);
+    FREE(indexDir);
+    for (i=0;i<line_count;i++)
+      FREENONNULL(lines[i]);
+    GROW(lines,
+        line_count,
+        0);
+    FREE(fil);
+    FREE(line);
+    FREE(indexDir);
+    return OK;
+  }  
+  fseek(handle, 0, SEEK_SET);
+  truncate(fil, 0);
+  
+  for (i=0;i<line_count;i++) {
+    if ( ( lines[i] != NULL) &&
+        (0 != strncmp(lines[i],
+                      indexDir,
+                      strlen(indexDir))) ) {
+      HashCode160 hc;
+      if (OK != getFileHash(lines[i],
+                           &hc)) {
+       fprintf(handle,
+               "\n");
+      } else {
+       HexName hex;
+       char * lname;
+       hash2hex(&hc,
+                &hex);
+       lname = MALLOC(strlen(indexDir) + sizeof(HexName) + 1);
+       strcpy(lname,
+              indexDir);
+       strcat(lname,
+              "/");
+       strcat(lname,
+              (char*)&hex);
+       if (0 != SYMLINK(lines[i], lname)) {
+         errexit("FATAL: could not create link from %s to %s: %s\n",
+                 lines[i],
+                 lname,
+                 strerror(errno));
+       } else {
+         fprintf(handle,
+                 "%s\n",
+                 lname);
+       }
+       FREE(lname);
+      }
+    } else {
+      fprintf(handle,
+             "%s\n",
+             lines[i] == NULL ? "" : lines[i]);
+    }
+    FREENONNULL(lines[i]);
+  }
+  GROW(lines,
+       line_count,
+       0);
+  FREE(fil);
+  FREE(line);
+  FREE(indexDir);
+  fclose(handle);  
+  return OK;
+}
+
+int main(int argc, char * argv[]) {
+  PTHREAD_T tcpPseudoServer;
+  char * checkString;
+  char check;
+  int i;
+  void * unused;
+  
+  if (SYSERR == initUtil(argc, argv, &parseCommandLine))
+    return 0;
+
+  if (testConfigurationString("GNUNET-CHECK",
+                             "UPDATE",
+                             "YES")) {
+    int * sbit;
+    int version;
+    int val;
+
+    sbit = NULL;
+    if (sizeof(int) == stateReadContent("VERSION",
+                                       (void**)&sbit)) {
+      version = *sbit;
+      FREE(sbit);
+      switch (ntohl(version)) {
+      case 0x061b: /* need to add links for indexed files */
+       printf("Updating from version %x\n",
+              version);
+       if (SYSERR == update061b())
+         errexit("Errors while updating version!\n");
+       /* finally, update version to current */
+       val = htonl(0x0620);
+       stateWriteContent("VERSION",
+                         sizeof(int),
+                         &val);
+       break;
+      case 0x0620:
+       printf("State is current, no update required.\n");
+       break;
+      default:
+       printf("WARNING: unknown GNUnet version %x\n",
+              version);
+      }
+    } else {
+      FREENONNULL(sbit);
+      version = 0; /* first start */
+    }
+  }
+  
+  checkString = getConfigurationString("GNUNET-CHECK", 
+                                      "MODE");
+  if (checkString != NULL)
+    check = checkString[0];
+  else
+    check = 'n';
+  FREENONNULL(checkString);
+  if (check == 'n') {
+    if (testConfigurationString("GNUNET-CHECK",
+                               "UPDATE",
+                               "YES")) {
+      doneUtil();
+      return 0;
+    }
+    fprintf(stderr,
+           "You must choose what to check (specify -D, -f, or -a).\n");
+    doneUtil();
+    return -1;
+  }
+
+  fixedPriority = getConfigurationInt("GNUNET-CHECK",
+                                     "FIXED-PRIORITY");
+  if (fixedPriority <= 0) {
+    LOG(LOG_WARNING, 
+        "WARNING: GNUNET-CHECK/FIXED-PRIORITY in conf either <= 0 or 
missing\n");
+    fixedPriority = 0;
+  }
+
+  indexPriority = getConfigurationInt("GNUNET-INSERT",
+                                     "CONTENT-PRIORITY");
+  if (indexPriority <= 0) {
+    LOG(LOG_WARNING,
+       "WARNING: GNUNET-INSERT/CONTENT-PRIORITY in conf either <= 0 or 
missing\n");
+    indexPriority = 65536;
+  }
+
+  initManager();
+  initFileIndex();
+  initBloomfilters();
+
+  serverSignal = SEMAPHORE_NEW(0);
+  if (0 != PTHREAD_CREATE(&tcpPseudoServer,
+                         (PThreadMain) &tcpListenMain, 
+                         NULL,
+                         16*1024))
+    errexit("FATAL: Could not create tcpServer thread\n");
+  SEMAPHORE_DOWN(serverSignal);
+  SEMAPHORE_FREE(serverSignal);
+
+  if ( (do_reset == YES) && 
+       (check != 'a') ) {
+    errexit("Can't use --reset without -a\n");
+  }
+  if ( (do_reset == YES) && 
+       (check == 'a') &&
+       (do_fix == YES) ) {
+    resetBloomfilter(singleBloomFilter);
+    resetBloomfilter(superBloomFilter);
+  }
+  if ((check == 'a') || (check == 'f'))
+    checkIndexedFileList();
+  if ((check == 'a') || (check == 'd'))
+    checkDatabase(); 
+
+  i = listenerFD;
+  listenerFD = -1;
+  SHUTDOWN(i, 2);
+  CLOSE(i);
+  PTHREAD_JOIN(&tcpPseudoServer, &unused);
+  doneBloomfilters();
+  doneManager();
+  doneFileIndex();
+  doneUtil();
+  return 0;
+}
+
+
+/* end of gnunet-check.c */

Added: freeway/src/org/gnu/freeway/gnunet-convert.c
===================================================================
--- freeway/src/org/gnu/freeway/gnunet-convert.c        2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/gnunet-convert.c        2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,300 @@
+/*
+     This file is part of GNUnet.
+     (C) 2002, 2003 Christian Grothoff (and other contributing authors)
+
+     GNUnet 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, or (at your
+     option) any later version.
+
+     GNUnet 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 GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file applications/afs/module/gnunet-convert.c
+ * @brief Little tool to convert content databases from format to another.
+ *        Use if you change the database manager type or the bucket count.
+ * @author Igor Wronsky
+ * @author Christian Grothoff
+ **/
+
+#include "gnunet_util.h"
+#include "gnunet_afs_esed2.h"
+#include "manager.h"
+#include "bloomfilter.h"
+#include "manager.c"
+#include "bloomfilter.c"
+#include "large_file_support.c"
+#include "fileindex.c"
+  
+static DatabaseAPI * srcHandle;
+static DatabaseAPI * dstHandle;
+
+unsigned int insertedBlocks = 0;
+unsigned int failedBlocks = 0;
+
+static int progressDot = 0;
+static int be_verbose = NO;
+static int be_quiet = NO;
+
+static void addToDestination(HashCode160 * key,
+                            ContentIndex *ce,
+                            void * data,
+                            unsigned int dataLen,
+                            void * unused) {
+  HashCode160 hc;
+  int bucket;
+
+  progressDot++;
+  if ( ((progressDot & 255) == 0) &&
+       (be_quiet == NO) ) {
+    printf(".");
+    fflush(stdout);    
+  }
+
+  switch (ntohs(ce->type)) {
+  case LOOKUP_TYPE_CHK:
+    addToBloomfilter(singleBloomFilter,
+                    &ce->hash);                       
+    break;
+  case LOOKUP_TYPE_3HASH:
+    hash(&ce->hash,
+        sizeof(HashCode160),
+        &hc);
+    addToBloomfilter(singleBloomFilter,
+                    &hc);
+    break;
+  case LOOKUP_TYPE_SUPER:
+    addToBloomfilter(superBloomFilter,
+                    &ce->hash);
+    break;
+  case LOOKUP_TYPE_SBLOCK:
+    addToBloomfilter(singleBloomFilter,
+                    &hc);              
+    break;
+  case LOOKUP_TYPE_CHKS:
+    /* do nothing! */
+    break;
+  default:
+    LOG(LOG_WARNING,
+       "WARNING: encountered unexpected type %d\n",
+       ntohs(ce->type));
+  }
+ 
+  bucket = computeBucket(key,
+                        dstHandle->buckets);
+  if (SYSERR == dstHandle->writeContent(dstHandle->dbHandles[bucket],
+                                       ce,
+                                       dataLen,
+                                       data))
+    failedBlocks++;
+  else
+    insertedBlocks++;  
+  FREENONNULL(data);
+}
+
+/**
+ * Print a list of the options we offer.
+ **/
+static void printhelp() {
+  static Help help[] = {
+    HELP_CONFIG,
+    HELP_HELP,
+    HELP_LOGLEVEL,
+    { 'q', "quiet", NULL,
+      "be quiet" },
+    HELP_VERSION,
+    HELP_VERBOSE,
+    HELP_END,
+  };
+  formatHelp("gnunet-convert [OPTIONS]",
+            "Convert GNUnet AFS database to different QUOTA or database 
type.\n"
+            "Never run gnunet-convert while gnunetd is running!",
+            help);
+}
+
+/**
+ * Perform option parsing from the command line. 
+ **/
+static int parseCommandLine(int argc, 
+                           char * argv[]) {
+  int c;
+
+  FREENONNULL(setConfigurationString("GNUNETD",
+                                    "_MAGIC_",
+                                    "YES"));
+  FREENONNULL(setConfigurationString("GNUNETD",
+                                    "LOGFILE",
+                                    NULL));
+  while (1) {
+    int option_index = 0;
+    static struct GNoption long_options[] = {
+      LONG_DEFAULT_OPTIONS,
+      { "verbose",  0, 0, 'V' },
+      { "quiet",    0, 0, 'q' },
+      { 0,0,0,0 }
+    };
+    
+    c = GNgetopt_long(argc,
+                     argv, 
+                     "vhdc:nVqL:", 
+                     long_options, 
+                     &option_index);    
+    if (c == -1) 
+      break;  /* No more flags to process */
+    if (YES == parseDefaultOptions(c, GNoptarg))
+      continue;    
+    switch(c) {
+    case 'q':
+      be_quiet = YES;
+      break;
+    case 'V':
+      be_verbose = YES;
+      break;
+    case 'v': 
+      printf("GNUnet v%s, gnunet-convert v%s\n",
+            VERSION, 
+            AFS_VERSION);
+      return SYSERR;
+      break;
+    case 'h': 
+      printhelp(); 
+      return SYSERR;
+      break;
+    default:
+      printf("Unknown option %c. Aborting.\n"
+            "Use --help to get a list of options.\n",
+            c);
+      return SYSERR;
+    } /* end of parsing commandline */
+  }
+  if (GNoptind < argc) {
+    printf("Invalid arguments: ");
+    while (GNoptind < argc)
+      printf("%s ", argv[GNoptind++]);
+    printf("\nExiting.\n");
+    return SYSERR;
+  }
+  return OK;
+}
+
+
+
+int main(int argc, 
+        char * argv[]) {
+  char * srcDb;
+  char * dstDb;
+  char * tmp;
+  int entries;
+  int newQuota;
+  int * oldQuota;
+  int ret;
+  unsigned int i;
+
+  if (SYSERR == initUtil(argc, argv, &parseCommandLine))
+    return 0;
+
+  newQuota = getConfigurationInt("AFS",
+                                "DISKQUOTA");
+  if (newQuota == 0)
+    errexit("FATAL: you must specify available diskspace"
+           " in section AFS under DISKQUOTA\n"); 
+  oldQuota = NULL;
+  ret = stateReadContent("AFS-DISKQUOTA",
+                        (void**)&oldQuota);
+  if (ret != sizeof(unsigned int))
+    errexit("FATAL: no conversion possible, no old database known.\n");
+  tmp = NULL;
+  ret = stateReadContent("AFS-DATABASETYPE",
+                        (void**)&tmp);
+  dstDb = getConfigurationString("AFS",
+                                "DATABASETYPE");  
+  if (dstDb == NULL)
+    errexit("FATAL: you must specify a database type in section AFS.\n");
+  if ( (ret == -1) ||
+       ( (strncmp(tmp, dstDb, ret) == 0) &&
+        (newQuota == *oldQuota) ) )
+    errexit("FATAL: you need to specify a different DB type "
+           "(or quota) in gnunet.conf to run gnunet-convert.\n");
+  srcDb = MALLOC(ret+1);
+  memcpy(srcDb, tmp, ret);
+  FREENONNULL(tmp);
+  srcDb[ret] = '\0';
+  /* initialize old DB with old config! */
+  setConfigurationInt("AFS",
+                     "DISKQUOTA",
+                     *oldQuota);
+  FREENONNULL(oldQuota);
+  FREENONNULL(setConfigurationString("AFS",
+                                    "DATABASETYPE",
+                                    srcDb));
+  srcHandle = initializeDatabaseAPI(srcDb);
+
+  /* initialize new DB with new config */
+  stateWriteContent("AFS-DATABASETYPE",
+                   strlen(dstDb),
+                   dstDb);
+  setConfigurationInt("AFS",
+                     "DISKQUOTA",
+                     newQuota);
+  stateWriteContent("AFS-DISKQUOTA",
+                   sizeof(unsigned int),
+                   &newQuota);
+  FREENONNULL(setConfigurationString("AFS",
+                                    "DATABASETYPE",
+                                    dstDb));
+
+  /* FIXME: if the following call fails, we have set the new DB
+     parameters in the state module but the conversion has not been
+     done (and now the user is in deep shit (TM)).  We need to be able
+     to prevent the state module from commiting the changes until we
+     are done with everything.  The best way I can think of is to set
+     a flag in state.c "don't commit", then just record all writes and
+     once the flag is unset, do the writes. -- CG */
+
+  dstHandle = initializeDatabaseAPI(dstDb);
+  initBloomfilters(); /* from afs.c */
+  resetBloomfilter(superBloomFilter);
+  resetBloomfilter(singleBloomFilter);
+
+  /* copy old->new */
+  entries = 0;
+  for (i=0;i<srcHandle->buckets;i++)
+    entries += srcHandle->forEachEntryInDatabase(srcHandle->dbHandles[i],
+                                                &addToDestination, 
+                                                NULL);
+
+  fprintf(stdout,
+         "\n==> Done processing %d entries in index "
+         "(%d converted, %d failed).\n",
+         entries,
+         insertedBlocks,
+         failedBlocks);
+
+  /* close new, then delete old */
+  doneBloomfilters();
+  for (i=0;i<dstHandle->buckets;i++)
+    dstHandle->doneContentDatabase(dstHandle->dbHandles[i]);
+  for (i=0;i<srcHandle->buckets;i++) 
+    srcHandle->deleteDatabase(srcHandle->dbHandles[i]);
+  FREE(srcHandle->dbHandles);
+  FREE(dstHandle->dbHandles);
+  unloadDynamicLibrary(srcHandle->dynamicLibrary);
+  unloadDynamicLibrary(dstHandle->dynamicLibrary);
+  FREE(srcHandle);
+  FREE(dstHandle);
+  doneUtil();
+
+  return 0;
+}
+
+
+/* end of gnunet-convert.c */

Added: freeway/src/org/gnu/freeway/gnunet-delete.c
===================================================================
--- freeway/src/org/gnu/freeway/gnunet-delete.c 2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/src/org/gnu/freeway/gnunet-delete.c 2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,163 @@
+/*
+     This file is part of GNUnet.
+     (C) 2003 Christian Grothoff (and other contributing authors)
+
+     GNUnet 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, or (at your
+     option) any later version.
+
+     GNUnet 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 GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * Tool to delete files that were indexed with gnunet-insert.
+ *
+ * @author Christian Grothoff
+ * @file applications/afs/tools/gnunet-delete.c 
+ **/
+
+#include "gnunet_afs_esed2.h"
+#include "platform.h"
+
+/**
+ * Print progess message.
+ **/
+static void printstatus(ProgressStats * stats,
+                       void * verboselevel) {
+  if (*(int*)verboselevel == YES)
+    printf("%8u of %8u bytes deleted\r",
+          (unsigned int) stats->progress,
+          (unsigned int) stats->filesize);  
+}
+
+/**
+ * Prints the usage information for this command if the user errs.
+ * Aborts the program.
+ **/
+static void printhelp() {
+  static Help help[] = {
+    HELP_CONFIG,
+    { 'f', "file", "NAME",
+      "specify the file to delete from GNUnet (obligatory, file must exist)"} ,
+    HELP_HELP,
+    HELP_HOSTNAME,
+    HELP_LOGLEVEL,
+    HELP_VERSION,
+    HELP_VERBOSE,
+    HELP_END,
+  };
+  formatHelp("gnunet-delete [OPTIONS] -f FILENAME",
+            "Remove file from GNUnet.  The specified file is not removed\n"
+            "from the filesystem but just from the local GNUnet datastore.",
+            help);
+}
+
+static int parseOptions(int argc,
+                       char ** argv) {
+  int c;
+
+  FREENONNULL(setConfigurationString("GNUNET-INSERT",
+                                    "INDEX-CONTENT",
+                                    "YES"));
+  while (1) {
+    int option_index=0;
+    static struct GNoption long_options[] = {
+      LONG_DEFAULT_OPTIONS,
+      { "file",          1, 0, 'f' },
+      { "verbose",       0, 0, 'V' },
+      { 0,0,0,0 }
+    };    
+    c = GNgetopt_long(argc,
+                     argv, 
+                     "vhdc:L:H:Vf:", 
+                     long_options, 
+                     &option_index);    
+    if (c == -1) 
+      break;  /* No more flags to process */
+    if (YES == parseDefaultOptions(c, GNoptarg))
+      continue;
+    switch(c) {
+    case 'V':
+      FREENONNULL(setConfigurationString("GNUNET-INSERT",
+                                        "VERBOSE",
+                                        "YES"));
+      break;
+    case 'f': 
+      FREENONNULL(setConfigurationString("GNUNET-DELETE",
+                                        "FILENAME",
+                                        GNoptarg));
+      break;    
+    case 'v': 
+      printf("GNUnet v%s, gnunet-delete v%s\n",
+            VERSION, 
+            AFS_VERSION);
+      return SYSERR;
+    case 'h': 
+      printhelp(); 
+      return SYSERR;
+    default: 
+      LOG(LOG_FAILURE,
+         "FAILURE: Unknown option %c. Aborting.\n"\
+         "Use --help to get a list of options.\n",
+         c);
+      return SYSERR;
+    } /* end of parsing commandline */
+  } /* while (1) */
+  return OK;
+}
+
+
+/**
+ * The main function to delete files from GNUnet.
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return return 0 for ok, -1 on error
+ **/   
+int main(int argc, char ** argv) {
+  int beVerbose;
+  GNUNET_TCP_SOCKET * sock;
+  int ok;
+  char * filename;
+  
+  if (SYSERR == initUtil(argc, argv, &parseOptions)) 
+    return 0;
+  beVerbose = testConfigurationString("GNUNET-INSERT",
+                                     "VERBOSE",
+                                     "YES");
+
+  filename = getFileName("GNUNET-DELETE",
+                        "FILENAME",
+                        "ERROR: you must specify a filename (option -f)\n");
+  sock = getClientSocket();
+  if (sock == NULL)
+    errexit("FATAL: could not connect to gnunetd.\n");
+  ok = deleteFile(sock,
+                 filename,
+                 &printstatus,
+                 &beVerbose);
+  if (ok != OK) {
+    LOG(LOG_DEBUG,
+       "DEBUG: error in deleteFile\n");
+    printf("Error deleting file %s.\n"
+          "Probably a few blocks were already missing from the database.\n",
+          filename);
+  }
+  releaseClientSocket(sock); 
+  doneUtil();
+  FREE(filename);
+  if (ok == OK)
+    return 0;
+  else 
+    return -1;
+}  
+
+/* end of gnunet-delete.c */

Added: freeway/src/org/gnu/freeway/gnunet-tbench.c
===================================================================
--- freeway/src/org/gnu/freeway/gnunet-tbench.c 2005-01-31 23:47:23 UTC (rev 
136)
+++ freeway/src/org/gnu/freeway/gnunet-tbench.c 2005-02-01 01:07:27 UTC (rev 
137)
@@ -0,0 +1,266 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002 Christian Grothoff (and other contributing authors)
+
+     GNUnet 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, or (at your
+     option) any later version.
+
+     GNUnet 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 GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file applications/tbench/gnunet-tbench.c 
+ * @brief Transport mechanism benchmarking tool
+ * @author Paul Ruth
+ **/
+
+#include "tbench.h"
+#include "platform.h"
+
+#define TBENCH_VERSION "0.0.3"
+
+#define DEFAULT_MESSAGE_SIZE   10
+#define DEFAULT_TIMEOUT                2
+#define DEFAULT_SPACING                0
+
+#define OF_HUMAN_READABLE 0
+#define OF_GNUPLOT_INPUT 1
+
+static int  messageSize = DEFAULT_MESSAGE_SIZE;
+static int  messageCnt  = 1;
+static char messageReceiver[256];
+static int  messageIterations = 1;
+static int  messageTrainSize = 1;
+static int  messageTimeOut = DEFAULT_TIMEOUT;
+static int  messageSpacing = DEFAULT_SPACING;
+static int outputFormat = OF_HUMAN_READABLE;
+
+/**
+ * Parse the options, set the timeout.
+ * @param argc the number of options
+ * @param argv the option list (including keywords)
+ * @return OK on error, SYSERR if we should exit 
+ **/
+static int parseOptions(int argc,
+                       char ** argv) {
+  int option_index;
+  int c;  
+
+  FREENONNULL(setConfigurationString("GNUNETD",
+                                    "LOGFILE",
+                                    NULL));
+  while (1) {
+    static struct GNoption long_options[] = {
+      LONG_DEFAULT_OPTIONS,
+      { "gnuplot", 0, 0, 'g' },
+      { "rec", 1, 0, 'r'},
+      { "msg", 1, 0, 'n'},
+      { "iterations", 1, 0, 'i'},
+      { "timeout", 1, 0, 't' },
+      { "space", 1, 0, 'S' },
+      { "xspace", 1, 0, 'X' },
+      { 0,0,0,0 }
+    };    
+    option_index=0;
+    c = GNgetopt_long(argc,
+                     argv, 
+                     "vhdc:L:H:n:s:r:i:t:S:X:g", 
+                     long_options, 
+                     &option_index);    
+    if (c == -1) 
+      break;  /* No more flags to process*/
+    if (YES == parseDefaultOptions(c, GNoptarg))
+      continue;
+    switch(c) {
+    case 'v': 
+      printf("GNUnet v%s, gnunet-tbench v%s\n",
+            VERSION,
+            TBENCH_VERSION);
+      return SYSERR;
+
+    case 'h': {
+      static Help help[] = {
+       HELP_CONFIG,
+       HELP_HELP,
+       { 'g', "gnuplot", NULL,
+         "output in gnuplot format" },
+       { 'i', "iterations", "ITER",
+         "number of iterations" }, 
+       HELP_LOGLEVEL,  
+       { 'n', "msg", "MESSAGES",
+         "number of messages to use per iteration"},
+       { 'r', "rec", "RECEIVER",
+         "receiver host identifier (HEX file name)" },
+       { 's', "size", "SIZE",
+         "message size" },
+       { 'S', "space", "SPACE",
+         "inter-train message spacing" },
+       { 't', "timeout", "TIMEOUT",
+         "time to wait for the arrival of a response" },
+       HELP_VERSION,
+       { 'X', "xspace", "COUNT",
+         "sleep for SPACE ms after COUNT messages"},
+       HELP_END,
+      };
+      formatHelp("gnunet-chat [OPTIONS]",
+                "Start GNUnet chat client.",
+                help);
+      return SYSERR;
+    }
+    case 's': 
+      if(!sscanf(GNoptarg,"%d",&messageSize)){
+       printf("-s argument not a number\n");
+       exit(1);
+      }
+      break;
+    case 'g': 
+      outputFormat = OF_GNUPLOT_INPUT;
+      break;
+    case 'X':
+      if(!sscanf(GNoptarg,"%d",&messageTrainSize)){
+       printf("-X argument not a number\n");
+       exit(1);
+      }
+      break;
+    case 'n': 
+      if(!sscanf(GNoptarg,"%d",&messageCnt)){
+       printf("-n argument not a number\n");
+       exit(1);
+      }
+      break;
+
+    case 'r': 
+      strncpy(messageReceiver, GNoptarg, strlen(GNoptarg));
+      break;
+
+    case 'i': 
+      if(!sscanf(GNoptarg,"%d",&messageIterations)){
+       printf("-i argument not a number\n");
+       exit(1);
+      }
+      break;
+
+    case 't':
+      if(!sscanf(GNoptarg,"%d",&messageTimeOut)){
+       printf("-t argument not a number\n");
+       exit(1);
+      }
+      break;
+
+    case 'S':
+      if(!sscanf(GNoptarg,"%d",&messageSpacing)){
+       printf("-S argument not a number\n");
+       exit(1);
+      }
+      break;
+
+    default: 
+      LOG(LOG_FAILURE,
+         "FAILURE: Unknown option %c. Aborting.\n"\
+         "Use --help to get a list of options.\n",
+         c);
+      return -1;
+    } /* end of parsing commandline */
+  } /* while (1) */
+  return OK;
+}
+
+/**
+ * Tool to benchmark the performance of the P2P transports.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return return value from gnunetsearch: 0: ok, -1: error
+ **/   
+int main(int argc, char ** argv) {
+  GNUNET_TCP_SOCKET * sock;
+  TBENCH_CS_MESSAGE msg;
+  TBENCH_CS_REPLY * buffer;
+  float messagesPercentLoss;
+
+  if (SYSERR == initUtil(argc, argv, &parseOptions))
+    return 0; /* parse error, --help, etc. */ 
+  sock = getClientSocket();
+  if (sock == NULL)
+    errexit("FATAL: could not connect to gnunetd.\n");
+
+  memset(&msg,
+        0,
+        sizeof(TBENCH_CS_MESSAGE));
+  msg.msgSize     =htons(messageSize);
+  msg.msgCnt      =htons(messageCnt);
+  msg.iterations  =htons(messageIterations);
+  msg.intPktSpace =htons(messageSpacing);
+  msg.trainSize   =htons(messageTrainSize);
+  msg.timeOut     =htonl(messageTimeOut);
+  if (strlen(messageReceiver) != 2*sizeof(HashCode160))
+    errexit("Invalid receiver peer ID specified (%s is not %d character hex 
name)\n",
+           messageReceiver,
+           2*sizeof(HashCode160));
+  hex2hash((HexName*)messageReceiver,
+          &msg.receiverId.hashPubKey);
+  msg.header.size = htons(sizeof(TBENCH_CS_MESSAGE));
+  msg.header.tcpType = htons(TBENCH_CS_PROTO_REQUEST);
+
+  if (SYSERR == writeToSocket(sock,
+                             &msg.header))
+    return -1;
+  
+  buffer = MALLOC(MAX_BUFFER_SIZE);
+  LOG(LOG_DEBUG,
+      "DEBUG: reading from readFromSocket\n");
+  if (OK == readFromSocket(sock, (CS_HEADER**)&buffer)) {
+    if((float)buffer->mean_loss <= 0){
+      messagesPercentLoss = 0.0;
+    } else {
+      messagesPercentLoss = (buffer->mean_loss/((float)htons(msg.msgCnt)));
+    }
+    switch (outputFormat) {
+    case OF_HUMAN_READABLE:
+      printf("Time:\n");
+      printf("\tmax      %d\n",
+            htons(buffer->max_time));
+      printf("\tmin      %d\n",
+            htons(buffer->min_time));
+      printf("\tmean     %f\n",
+            buffer->mean_time);
+      printf("\tvariance %f\n",
+            buffer->variance_time);
+      
+      printf("Loss:\n");
+      printf("\tmax      %d\n",
+            htons(buffer->max_loss));
+      printf("\tmin      %d\n",
+            htons(buffer->min_loss));
+      printf("\tmean     %f\n",
+            buffer->mean_loss);
+      printf("\tvariance %f\n",
+            buffer->variance_loss); 
+      break;
+    case OF_GNUPLOT_INPUT:
+      printf("%f %f\n",
+            buffer->mean_time,
+            1.0-messagesPercentLoss);
+      break;
+    default:
+      printf("WARNING: output format not known, this should not happen.\n");
+    }
+  } else 
+    printf("\nDid not receive the message from gnunetd. Is gnunetd 
running?\n");  
+  FREE(buffer);
+
+  releaseClientSocket(sock);
+  doneUtil();
+  return 0;
+}
+/* end of gnunet-tbench.c */ 

Added: freeway/src/org/gnu/freeway/gnunet-testbed.c
===================================================================
--- freeway/src/org/gnu/freeway/gnunet-testbed.c        2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/gnunet-testbed.c        2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,640 @@
+/*
+     This file is part of GNUnet.
+     (C) 2003, 2004 Christian Grothoff (and other contributing authors)
+
+     GNUnet 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, or (at your
+     option) any later version.
+
+     GNUnet 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 GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file applications/testbed/gnunet-testbed.c 
+ * @brief A Testbed tool for performing distributed experiments
+ * @author Ronaldo Alves Ferreira
+ * @author Christian Grothoff
+ * @author Murali Krishan Ramanathan
+ *
+ * Todo:
+ * - test secure sign-on (and test testbed setup script!)
+ * - allow removing of peers (explicitly AND when peer shuts down!)
+ *   Problem: what happens to the peer-IDs in that case?
+ * - general problem: the way we use tcpio means that any rouge
+ *   testbed-gnunetd can stall gnunet-testbed indefinitely!
+ * - security: limit "exec" to certain processes
+ **/
+
+#include "gnunet_util.h"
+#include "platform.h"
+#include "testbed.h"
+#include "socket.h"
+#include "commands.h"
+#include <signal.h>
+
+#ifndef sighandler_t
+typedef void (*sighandler_t)(int);
+#endif
+
+#define TESTBED_VERSION                "0.0.4"
+#define HELPER                  "==HELPER=="
+
+/* we may want to change SHELL and PORT into values
+   obtained from the configuration... */
+
+#define SHELL  (NULL == getenv("BASH") ? "/bin/bash" : getenv("BASH"))
+
+#define PORT getConfigurationInt("GNUNET-TESTBED","PORT")
+
+/* TB_ALIASES should probably be forced to live somewhere
+   under ~/.gnunet */
+#define TB_ALIASES "/tmp/gnunet-testbed-aliasdefinitions"
+
+
+/**
+ * Name of gnunet-testbed binary.
+ */
+static char * testbedArg0;
+
+
+/* ****************** scriptability *************** */
+
+#ifndef MINGW /* FIXME MINGW */
+
+
+
+/**
+ * Parse the options, set the timeout.
+ *
+ * @param argc the number of options
+ * @param argv the option list (including keywords)
+ * @return OK on error, SYSERR if we should exit 
+ **/
+static int helperParseOptions(int argc, char *argv[]) {
+  int c, option_index;
+  
+  FREENONNULL(setConfigurationString("GNUNETD", 
+                                    "LOGFILE", 
+                                    NULL));
+  while (1) {
+    static struct GNoption long_options[] = {
+      LONG_DEFAULT_OPTIONS,
+      { 0,0,0,0 }
+    };    
+    
+    option_index = 0;
+    c = GNgetopt_long(argc,
+                     argv, 
+                     "vhdc:L:", 
+                     long_options, 
+                     &option_index);    
+    if (c == -1) 
+      break;  /* No more flags to process */
+    if (YES == parseDefaultOptions(c, GNoptarg))
+      continue;
+    switch(c) {
+    case 'v': 
+      printf("GNUnet v%s, gnunet-testbed v%s\n",
+            VERSION,
+            TESTBED_VERSION);
+      return SYSERR;     
+    case 'h': {
+      static Help help[] = {
+       HELP_CONFIG,
+       HELP_HELP,
+       HELP_LOGLEVEL,  
+       HELP_VERSION,
+       HELP_END,
+      };
+      formatHelp("gnunet-testbed ==HELPER== [OPTIONS] [COMMAND]",
+                "Start GNUnet-testbed helper.",
+                help);
+      return SYSERR;
+    }      
+    default: 
+      LOG(LOG_FAILURE,
+         "FAILURE: Unknown option %c. Aborting.\n"             \
+         "Use --help to get a list of options.\n",
+               c);
+      return -1;
+    } /* end of parsing commandline */
+  } /* while (1) */
+  setConfigurationStringList(&argv[GNoptind],
+                            argc - GNoptind);
+  return OK;
+}
+
+
+/**
+ * This is the main method of the helper-process that
+ * is invoked from the bash-process.  Helper encapsulates
+ * the command from the shell in a stream, sends it
+ * over the socket to the main gnunet-testbed process,
+ * retrieves there result and outputs he result back
+ * to bash.
+ */
+static int helper_main(int argc,
+                      char * argv[]) {
+  int    i, retVal, len, res;
+  char  *buf;
+  struct sockaddr_in soaddr;
+  
+  if (SYSERR == initUtil(argc,
+                        argv,
+                        &helperParseOptions))
+    return -1;
+
+  argc = getConfigurationStringList(&argv);  
+  
+  if (argc == 0) {
+    fprintf(stderr,
+           "ERROR: must have at least one argument!\n");
+    return -1;
+  }  
+  sock = SOCKET(PF_INET, 
+               SOCK_STREAM,
+               6); /* 6: TCP */
+  if (sock == -1) {
+    LOG(LOG_FAILURE,
+       "FAILURE: Cannot create socket (%s).\n",
+       STRERROR(errno));
+    return SYSERR;
+  }
+  soaddr.sin_family
+    = AF_INET;
+  soaddr.sin_addr.s_addr
+    = htonl(INADDR_LOOPBACK);
+  soaddr.sin_port 
+    = htons(PORT);
+  res = CONNECT(sock,
+               (struct sockaddr*)&soaddr, 
+               sizeof(soaddr));
+  if ( (res < 0) && 
+       (errno != EINPROGRESS) ) {
+    LOG(LOG_INFO,
+       "INFO: tcpio: Cannot connect to LOOPBACK:%d (%s)\n",
+       PORT,
+       STRERROR(errno));
+    CLOSE(sock);
+    sock = -1;
+    return SYSERR;
+  }
+  
+  /* write command to socket */
+  socketSend(strlen(argv[0]),
+            SOCKET_BEGIN_COMMAND, 
+            argv[0]);
+  FREE(argv[0]);
+  /* write args to socket */
+  for (i=1;i<argc;i++) {
+    socketSend(strlen(argv[i]), 
+              SOCKET_ADD_ARGUMENT, 
+              argv[i]);
+    FREE(argv[i]);
+  }
+  FREE(argv);
+  socketSend(0,
+            SOCKET_END_COMMAND, 
+            NULL);
+  
+  /* read result from socket, print to stderr,  obtain retVal */
+  i = SOCKET_PRINTF;
+  buf = NULL;
+  while (i == SOCKET_PRINTF) {
+    FREENONNULL(buf);
+    buf = NULL;
+    i = readSocket(&buf, &len);
+    if (i == SOCKET_PRINTF)
+      fprintf(stdout, 
+             "%.*s", 
+             (int) len, 
+             buf);
+  }  
+  retVal = *(int*)buf;
+  FREE(buf);  
+  close(sock);
+  return retVal;
+}
+
+/**
+ * A child (the shell) has quit.  So we exit,
+ * too.
+ */
+static void sigChildHandler(int signal,
+                           siginfo_t * info,
+                           void * extra) {
+  do_quit = YES;
+}
+
+/**
+ * This is the "bash" process.  Execs bash.
+ * @returns never
+ */
+static void bash_main() {
+  int   i;
+  FILE *aliases;
+  char * configFile;
+  char *argv[] = {
+    NULL,              /* replaced by SHELL */
+    "--init-file",
+    TB_ALIASES,
+    "-i",
+    NULL,
+  };
+  
+  configFile = getConfigurationString("FILES",
+                                     "gnunet.conf");
+  if (configFile == NULL)
+    errexit("Assertion failed at %s:%d\n",
+           __FILE__, __LINE__);
+  argv[0] = SHELL;
+  aliases = FOPEN(TB_ALIASES, "w+");
+  fprintf(aliases, 
+         "export PS1=\"[GTB]%% \"\n");
+  i=0;
+  while (commands[i].command != NULL) {
+    if (0 == strcmp("exit", commands[i].command)) {
+      fprintf(aliases,
+             "alias exit=\"%s ==HELPER== -c %s exit ; exit\"\n",
+             testbedArg0,
+             configFile);
+    } else {
+      fprintf(aliases,
+             "alias %s=\"%s ==HELPER== -c %s %s\"\n",
+             commands[i].command,
+             testbedArg0,
+             configFile,
+             commands[i].command);
+    }
+    i++;
+  }
+  FREE(configFile);
+  fclose(aliases);
+  doneUtil(); 
+  execvp(SHELL, argv);       
+  fprintf(stderr,
+         "FATAL: could not execute %s: %s\n",
+         SHELL,
+         STRERROR(errno));
+}
+
+/**
+ * Configuration...
+ **/
+static CIDRNetwork * trustedNetworks_ = NULL;
+
+/**
+ * Is this IP labeled as trusted for CS connections?
+ **/
+static int isWhitelisted(IPaddr ip) {   
+  return checkIPListed(trustedNetworks_,
+                      ip);
+}
+
+/**
+ * This is the main method of the server.  It reads
+ * commands from the socket that are created by helper process.
+ * It is the main process that also keeps the state
+ * throughout the session.
+ *
+ * @param bash_pid the process ID of the child that is bash
+ */
+static int server_main(pid_t bash_pid) {
+  int   i, status, ssock, lenOfIncomingAddr;
+  int   secs = 5;
+  const int on = 1;
+  struct sockaddr_in serverAddr, clientAddr;
+  struct sigaction oldAct;
+  struct sigaction newAct;
+  sigset_t set;
+  sigset_t oset;
+
+  
+  /* create the socket */
+ CREATE_SOCKET:
+  while ( (ssock = SOCKET(PF_INET, SOCK_STREAM, 0)) < 0) {
+    LOG(LOG_ERROR, 
+       "ERROR opening socket (%s). No client service"  \
+       "started. Trying again in 30 seconds.\n",
+       STRERROR(errno));
+    sleep(30);
+  }
+  
+  serverAddr.sin_family
+    = AF_INET;
+  serverAddr.sin_addr.s_addr 
+    = htonl(INADDR_ANY);
+  serverAddr.sin_port
+    = htons(PORT);
+  
+  if (SETSOCKOPT(ssock, 
+                SOL_SOCKET,
+                SO_REUSEADDR,
+                &on,
+                sizeof(on)) < 0)
+    perror("setsockopt");
+  
+  /* bind the socket */
+  if (BIND(ssock,
+          (struct sockaddr*)&serverAddr,
+          sizeof(serverAddr)) < 0) {
+    LOG(LOG_ERROR, 
+       "ERROR (%s) binding the TCP listener to "               \
+       "port %d. No proxy service started.\nTrying "           \
+       "again in %d seconds...\n",
+       STRERROR(errno),
+       PORT, 
+       secs);
+    sleep(secs);
+    secs += 5; /* slow progression... */
+    CLOSE(ssock);
+    goto CREATE_SOCKET;
+  }
+  
+  do_quit = NO;
+  /* signal handler is needed if the child did exit 
+     (e.g. with CTRL-D and not with the command 'exit') */
+  newAct.sa_sigaction = &sigChildHandler;
+  sigfillset(&newAct.sa_mask);
+  newAct.sa_flags = SA_NOCLDSTOP | SA_SIGINFO | SA_RESTART;
+  if (0 != sigaction(SIGCHLD,
+                    &newAct,
+                    &oldAct)) 
+    errexit("FATAL: could not install SIGCHLD handler: %s\n",
+           strerror(errno));
+  sigemptyset(&set);
+  sigaddset(&set, SIGCHLD);
+  if (0 != sigprocmask(SIG_UNBLOCK,
+                      &set,
+                      &oset))
+    errexit("FATAL: could not activate SIGCHLD handler: %s\n",
+           strerror(errno));
+
+  LISTEN(ssock, 5);
+  while ( (do_quit == NO) &&
+         (0 == waitpid(bash_pid, 
+                       &status, 
+                       WNOHANG)) ) {
+    int   argc;
+    char *command;
+    char **args;
+    char *buf;
+    unsigned int len;
+    fd_set rset;
+    fd_set wset;
+    fd_set eset;
+    IPaddr ipaddr;
+    
+    lenOfIncomingAddr = sizeof(clientAddr); 
+    /* accept is not interrupted by SIGCHLD,
+       so we must do a select first; yuck. */
+    FD_ZERO(&rset);
+    FD_ZERO(&wset);
+    FD_ZERO(&eset);
+    FD_SET(ssock, &rset);
+    sock = select(ssock+1, &rset, &wset, &eset, NULL);
+    if (sock == -1)
+      continue;
+    sock = ACCEPT(ssock,
+                 (struct sockaddr *)&clientAddr,
+                 &lenOfIncomingAddr);
+    if (sock < 0) {
+      fprintf(stderr,
+             "ACCEPT returned %d: %s\n",
+             sock,
+             strerror(errno));
+      continue;
+    }
+    /* access control! */
+    if (sizeof(struct in_addr) != sizeof(IPaddr))
+      errexit("FATAL: assertion failed at %s:%d\n",
+             __FILE__, __LINE__);
+    memcpy(&ipaddr,
+          &clientAddr.sin_addr,
+          sizeof(struct in_addr));   
+    if (NO == isWhitelisted(ipaddr)) {
+      LOG(LOG_WARNING,
+         "WARNING: Rejected unauthorized connection from %d.%d.%d.%d.\n",
+         PRIP(ntohl(*(int*)&clientAddr.sin_addr)));
+      CLOSE(sock);
+      continue;
+    }
+
+
+    /* read from socket, run reaction,
+       return result value and stdout value;
+       possibly set doExit to 1 to exit */    
+    buf = NULL;
+    if (SOCKET_BEGIN_COMMAND != readSocket(&buf, &len)) {
+      fprintf(stderr,
+             "FATAL: protocol violation on socket. "   \
+             "Expected command.\n");
+      return -1;
+    }
+    command = MALLOC(len+1);
+    memcpy(command, buf, len);
+    command[len] = '\0';    
+    argc = 0;
+    args = NULL;
+    FREE(buf);
+    buf = NULL;
+    while (SOCKET_ADD_ARGUMENT == readSocket(&buf, &len)) {
+      GROW(args, argc, argc+1);
+      args[argc-1] = MALLOC(len+1);
+      memcpy(args[argc-1], buf, len);       
+      args[argc-1][len] = '\0';
+      FREE(buf);
+      buf = NULL;
+    }
+    FREENONNULL(buf);
+    i = 0;
+    while (commands[i].command != NULL) {
+      if (0 == strcmp(commands[i].command, command)) {
+       int ret;
+       ret = commands[i].handler(argc, args);
+       socketSend(sizeof(unsigned int), 
+                  SOCKET_RETVAL,
+                  &ret);
+       break;
+      }
+      i++;
+    }
+    for (i=0;i<argc;i++)
+      FREE(args[i]);
+    GROW(args, argc, 0);
+    if (commands[i].command == NULL) {
+      /* should never happen unless the user
+        plays by hand with the aliases... */
+      i = -1;
+      PRINTF("ERROR: command %s not found!\n",
+            command);
+      socketSend(sizeof(unsigned int), 
+                SOCKET_RETVAL, 
+                &i);
+    }
+    FREE(command);    
+    close(sock);
+    sock = -1;
+  }
+  /* just to be certain, we could have
+     left the main loop due to doExit... */
+  waitpid(bash_pid, 
+         &status, 
+         WNOHANG);
+  /* restore... */
+  if (0 != sigaction(SIGCHLD,
+                    &oldAct,
+                    &newAct)) 
+    LOG(LOG_WARNING,
+       "WARNING: could not restore SIGCHLD handler: %s\n",
+       strerror(errno));
+  return status;
+}
+
+#endif
+
+/* *************** command line options *********** */
+
+
+/**
+ * Parse the options, set the timeout.
+ *
+ * @param argc the number of options
+ * @param argv the option list (including keywords)
+ * @return OK on error, SYSERR if we should exit 
+ **/
+static int parseOptions(int argc, char *argv[]) {
+  int c, option_index;
+  
+  FREENONNULL(setConfigurationString("GNUNETD", "LOGFILE", NULL));
+  while (1) {
+    static struct GNoption long_options[] = {
+      LONG_DEFAULT_OPTIONS,
+      { 0,0,0,0 }
+    };    
+    
+    option_index = 0;
+    c = GNgetopt_long(argc,
+                     argv, 
+                     "vhdc:L:", 
+                     long_options, 
+                     &option_index);    
+    if (c == -1) 
+      break;  /* No more flags to process */
+    if (YES == parseDefaultOptions(c, GNoptarg))
+      continue;
+    switch(c) {
+    case 'v': 
+      printf("GNUnet v%s, gnunet-testbed v%s\n",
+            VERSION,
+            TESTBED_VERSION);
+      return SYSERR;
+      
+    case 'h': {
+      static Help help[] = {
+       HELP_CONFIG,
+       HELP_HELP,
+       HELP_LOGLEVEL,  
+       HELP_VERSION,
+       HELP_END,
+      };
+      formatHelp("gnunet-testbed [OPTIONS]",
+                "Start GNUnet testbed controller.",
+                help);
+      return SYSERR;
+    }      
+    default: 
+      LOG(LOG_FAILURE,
+         "FAILURE: Unknown option %c. Aborting.\n"             \
+         "Use --help to get a list of options.\n",
+               c);
+      return -1;
+    } /* end of parsing commandline */
+  } /* while (1) */
+  return OK;
+}
+
+/* **************** main **************** */
+
+/**
+ * Create a testbed environment with multiple peers to collect 
+ * GNUnet statistics.  Note that the same binary is used for
+ * two distinct purposes.  One is the stateful master process
+ * that maintains the testbed.  A second type of process is
+ * created if HELPER is the first argument.  These processes
+ * are created by the user from the SHELL and they merely serve
+ * to communicate back the user-commands to the master-process.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 on success, -1 on error
+ **/   
+int main(int argc, char *argv[]) {
+#ifndef MINGW /* FIXME MINGW */
+  pid_t pid;
+  char * ch;
+  
+  testbedArg0 = expandFileName(argv[0]);
+  /* first, evaluate if we are the special
+     helper process.  If so, eat HELPER
+     argument and run helper_main */
+  if (argc > 1) {
+    if (strcmp(argv[1], HELPER) == 0) {
+      argv[1] = argv[0];
+      return helper_main(argc -1, &argv[1]);
+    }
+  }
+  
+  if (SYSERR == initUtil(argc, argv, &parseOptions))
+    return -1; 
+
+  ch = getConfigurationString("GNUNET-TESTBED",
+                             "TRUSTED");
+  if (ch == NULL) {
+    trustedNetworks_ = parseRoutes("127.0.0.0/8;"); /* by default, trust 
localhost only */
+  } else {
+    trustedNetworks_ = parseRoutes(ch);    
+    if (trustedNetworks_ == NULL) 
+      errexit("Malformed entry in the configuration in section %s under %s: 
%s\n",
+             "GNUNET-TESTBED",
+             "TRUSTED", 
+             ch); 
+    FREE(ch);
+  }
+  
+  /* we are the main testbed process.  Fork of
+     a shell and start processing from the socket */
+  
+  pid = fork();
+  if (pid < 0)
+    errexit("FATAL: fork failed: %s\n", STRERROR(errno));
+  if (pid == 0) {
+    FREE(trustedNetworks_);
+    bash_main();
+    return 0; /* unreached */
+  } else {
+    int ret;
+    /* run actual main loop */
+    ret = server_main(pid);
+    /* just to be certain */
+    kill(pid, SIGHUP);
+    /* proper shutdown... */
+    doneUtil();
+    FREE(trustedNetworks_);
+    UNLINK(TB_ALIASES);
+    FREE(testbedArg0);
+    return ret;
+  } 
+#endif
+}
+
+/* end of gnunet-testbed.c */ 

Added: freeway/src/org/gnu/freeway/protocol/AbstractProtocol.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/AbstractProtocol.java  2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/AbstractProtocol.java  2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,141 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol;
+
+import org.gnu.freeway.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.transport.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ *
+ */
+
+public abstract class AbstractProtocol extends LoggedObject implements Protocol
+{
+       protected CoreForProtocol               coreAPI;
+
+       private String                          name;
+
+       private CSHandler                       csHandler;
+       private PersistentDecoder               csDecoder;
+       private ClientExitHandler               exitHandler;
+       private P2PHandler                      p2pHandler;
+       private List                                    ids;
+
+
+       protected AbstractProtocol( String str )
+       {
+               super(true);
+               coreAPI=null;
+
+               name=str;
+
+               csHandler=new CSHandler() {
+                       public boolean handle( CSSession client, CSMessage 
message )
+                       {
+                               return onCSMessage(client,message);
+                       }
+                       };
+               csDecoder=new PersistentDecoder();
+               exitHandler=new ClientExitHandler() {
+                       public void handle( CSSession client )
+                       {
+                               onClientExit(client);
+                       }
+                       };
+               p2pHandler=new P2PHandler() {
+                       public boolean handle( Session session, P2PMessage 
message, boolean encrypted )
+                       {
+                               return 
onP2PMessage(session.getRemote(),message);
+                       }
+                       };
+               ids=new ArrayList();
+       }
+
+       public String toString()
+       {
+               return "Abstract protocol [name="+name+"]";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public String getName()
+       {
+               return name;
+       }
+
+       public boolean init( CoreForProtocol capi )
+       {
+               boolean res;
+
+               res=true;
+               coreAPI=capi;
+               if (!((Server) 
coreAPI.getApplication()).registerCSExitHandler(exitHandler)) {
+                       res=false;
+                       }
+               return res;
+       }
+
+       public void done()
+       {
+               int     i;
+
+               for (i=0; i<ids.size(); i++) {
+                       ((Server) 
coreAPI.getApplication()).getDispatcher().unregisterP2PHandler(
+                               ((Integer) ids.get(i)).intValue(),p2pHandler);
+                       }
+
+               int[]   xxx=csDecoder.getIDs();
+               for (i=0; i<xxx.length; i++) {
+                       ((Server) 
coreAPI.getApplication()).unregisterCSHandler(xxx[i],csHandler);
+                       }
+
+               ((Server) 
coreAPI.getApplication()).unregisterCSExitHandler(exitHandler);
+               coreAPI=null;
+       }
+
+       public PersistentDecoder createCSDecoder()
+       {
+               return csDecoder;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       protected boolean addCSHandler( int id, Class c )
+       {
+               log(Level.FINE,"Register c/s handler for type #"+id+" 
("+CSMessage.nameFor(id)+").");
+
+               csDecoder.add(id,c);
+               return ((Server) 
coreAPI.getApplication()).registerCSHandler(id,c,csHandler);
+       }
+
+       protected boolean addP2PHandler( int id, Class c )
+       {
+               ids.add(new Integer(id));
+               return ((Server) 
coreAPI.getApplication()).getDispatcher().registerP2PHandler(id,c,p2pHandler);
+       }
+
+       protected boolean onCSMessage( CSSession client, CSMessage msg )
+       {
+               return false;
+       }
+
+       protected boolean onP2PMessage( HostIdentity sender, P2PMessage msg )
+       {
+               return false;
+       }
+
+       protected void onClientExit( CSSession client )
+       {
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/Protocol.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/Protocol.java  2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/protocol/Protocol.java  2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,19 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.net.*;
+
+/**
+ */
+
+public interface Protocol
+{
+       public boolean init( CoreForProtocol api );
+       public void done();
+
+       public PersistentDecoder createCSDecoder();
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/AFSProtocol.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/AFSProtocol.java   2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/AFSProtocol.java   2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,240 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.*;
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.util.logging.*;
+
+/**
+ * main functions of the anonymous file sharing service
+ *
+ * AFS CORE. This is the code that is plugged into the GNUnet core to
+ * enable Anonymous File Sharing.
+ * support for ESED2 encoding of files
+ */
+
+public class AFSProtocol extends AbstractProtocol
+{
+       /**
+        * Just the version number of the AFS implementation.
+        * History:
+        *
+        * 1.x.x: initial version with triple hash and merkle tree
+        * 2.x.x: root node with mime-type, filename and version number
+        * 2.1.x: combined CHK/3HASH encoding with 25:1 super-nodes
+        * 2.2.x: with directories
+        * 3.0.x: with namespaces
+        */
+
+       public static final int VERSION =       Utils.makeVersion(3,0,4);
+
+       /** */
+       private BloomFilter2    bloomFilter;
+
+       /** */
+       private FileIndex               fileIndex;
+
+       /** */
+       private Policy                  policy;
+
+       /** */
+       private Handler                 handler;
+
+       /** */
+       private Manager                 manager;
+
+       /** */
+       private Routing                 routing;
+
+       /** */
+       private Migration               migration;
+
+       /** */
+       private QueryManager    queryManager;
+
+
+       public AFSProtocol()
+       {
+               super("AFS");
+               bloomFilter=new BloomFilter2();
+               fileIndex=new FileIndex();
+               policy=null;
+               handler=new Handler();
+               manager=new Manager();
+               routing=new Routing();
+               migration=new Migration(manager);
+               queryManager=new QueryManager();
+       }
+
+       public String toString()
+       {
+               return "AFS";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Initialize the AFS module. This method name must match
+        * the library name (libgnunet_XXX => initialize_XXX).
+        * @param capi
+        * @return false on errors
+        */
+
+       public boolean init( CoreForProtocol capi )
+       {
+               Prefs   prefs;
+
+               super.init(capi);
+
+               prefs=capi.getApplication().getPreferences();
+               if (prefs.getInt("AFS","DISKQUOTA",0)<=0) {
+                       log(Level.SEVERE,"You must specify a postive number for 
the DISKQUOTA in section AFS.");
+                       return false;
+                       }
+
+               fileIndex.init(capi);
+
+               policy=new Policy(prefs,capi);
+
+               manager.init(capi);
+               bloomFilter.init(capi);
+               queryManager.init(capi);
+               routing.init(capi);
+               handler.init(capi);
+               migration.init(capi);
+
+               handler.policy=new Policy2(capi);
+               handler.singleBloomFilter=bloomFilter.singleBloomFilter;
+               handler.superBloomFilter=bloomFilter.superBloomFilter;
+               handler.fileIndex=fileIndex;
+               handler.manager=manager;
+               handler.routing=routing;
+
+               routing.policy=policy;
+               routing.manager=manager;
+               routing.queryManager=queryManager;
+               routing.superBloomFilter=bloomFilter.superBloomFilter;
+               routing.singleBloomFilter=bloomFilter.singleBloomFilter;
+               // **** fin beurk
+
+               // p2p handlers
+               addP2PHandler(P2PMessage.IS_QUERY,P2PQuery.class);
+               addP2PHandler(P2PMessage.IS_3HASH_RESULT,P2P3HashResult.class);
+               addP2PHandler(P2PMessage.IS_CHK_RESULT,P2PChkResult.class);
+               addP2PHandler(P2PMessage.IS_NSQUERY,P2PNSQuery.class);
+               
addP2PHandler(P2PMessage.IS_SBLOCK_RESULT,P2PSBlockResult.class);
+
+               // c/s handlers
+               addCSHandler(CSMessage.IS_QUERY,CSQuery.class);
+               addCSHandler(CSMessage.IS_INSERT_CHK,CSInsertChk.class);
+               addCSHandler(CSMessage.IS_INSERT_3HASH,CSInsert3Hash.class);
+               addCSHandler(CSMessage.IS_INDEX_BLOCK,CSIndexBlock.class);
+               addCSHandler(CSMessage.IS_INDEX_FILE,CSIndexFile.class);
+               addCSHandler(CSMessage.IS_INDEX_SUPER,CSIndexSuper.class);
+               addCSHandler(CSMessage.IS_DELETE_CHK,CSDeleteChk.class);
+               addCSHandler(CSMessage.IS_DELETE_3HASH,CSDelete3Hash.class);
+               addCSHandler(CSMessage.IS_UNINDEX_BLOCK,CSUnindexBlock.class);
+               addCSHandler(CSMessage.IS_UNINDEX_FILE,CSUnindexFile.class);
+               addCSHandler(CSMessage.IS_UNINDEX_SUPER,CSUnindexSuper.class);
+               addCSHandler(CSMessage.IS_NSQUERY,CSNSQuery.class);
+               addCSHandler(CSMessage.IS_INSERT_SBLOCK,CSInsertSBlock.class);
+               addCSHandler(CSMessage.IS_UPLOAD_FILE,CSUploadFile.class);
+               addCSHandler(CSMessage.IS_LINK_FILE,CSLinkFile.class);
+               
addCSHandler(CSMessage.IS_GET_AVG_PRIORITY,CSGetAvgPriority.class);
+               return true;
+       }
+
+       public void done()
+       {
+               super.done();
+               bloomFilter.done();
+               migration.done();
+               queryManager.done();
+               routing.done();
+               manager.done();
+               fileIndex.done();
+               policy.doneAnonymityPolicy();
+       }
+
+       protected boolean onCSMessage( CSSession client, CSMessage msg )
+       {
+               if (msg instanceof CSNSQuery) {
+                       return 
handler.csHandleRequestNSQuery(client,(CSNSQuery) msg);
+                       }
+               if (msg instanceof CSInsertSBlock) {
+                       return 
handler.csHandleRequestInsertSBlock(client,(CSInsertSBlock) msg);
+                       }
+               if (msg instanceof CSQuery) {
+                       return handler.csHandleRequestQuery(client,(CSQuery) 
msg);
+                       }
+               if (msg instanceof CSInsertChk) {
+                       return 
handler.csHandleRequestInsertCHK(client,(CSInsertChk) msg);
+                       }
+               if (msg instanceof CSInsert3Hash) {
+                       return 
handler.csHandleRequestInsert3HASH(client,(CSInsert3Hash) msg);
+                       }
+               if (msg instanceof CSIndexBlock) {
+                       return 
handler.csHandleRequestIndexBlock(client,(CSIndexBlock) msg);
+                       }
+               if (msg instanceof CSIndexFile) {
+                       return 
handler.csHandleRequestIndexFile(client,(CSIndexFile) msg);
+                       }
+               if (msg instanceof CSIndexSuper) {
+                       return 
handler.csHandleRequestIndexSuper(client,(CSIndexSuper) msg);
+                       }
+               if (msg instanceof CSDeleteChk) {
+                       return 
handler.csHandleRequestDeleteCHK(client,(CSDeleteChk) msg);
+                       }
+               if (msg instanceof CSDelete3Hash) {
+                       return 
handler.csHandleRequestDelete3HASH(client,(CSDelete3Hash) msg);
+                       }
+               if (msg instanceof CSUnindexBlock) {
+                       return 
handler.csHandleRequestUnindexBlock(client,(CSUnindexBlock) msg);
+                       }
+               if (msg instanceof CSUnindexFile) {
+                       return 
handler.csHandleRequestUnindexFile(client,(CSUnindexFile) msg);
+                       }
+               if (msg instanceof CSUnindexSuper) {
+                       return 
handler.csHandleRequestUnindexSuper(client,(CSUnindexSuper) msg);
+                       }
+               if (msg instanceof CSUploadFile) {
+                       return 
handler.csHandleRequestUploadFile(client,(CSUploadFile) msg);
+                       }
+               if (msg instanceof CSLinkFile) {
+                       return 
handler.csHandleRequestLinkFile(client,(CSLinkFile) msg);
+                       }
+               if (msg instanceof CSGetAvgPriority) {
+                       return 
routing.csHandleRequestAvgPriority(client,(CSGetAvgPriority) msg);
+                       }
+               return false;
+       }
+
+       protected boolean onP2PMessage( HostIdentity sender, P2PMessage msg )
+       {
+               if (msg instanceof P2PNSQuery) {
+                       return handler.handleNSQUERY(sender,msg);
+                       }
+               if (msg instanceof P2PSBlockResult) {
+                       return handler.handleSBLOCK_CONTENT(sender,msg);
+                       }
+               if (msg instanceof P2PQuery) {
+                       return handler.handleQUERY(sender,msg);
+                       }
+               if (msg instanceof P2P3HashResult) {
+                       return handler.handle3HASH_CONTENT(sender,msg);
+                       }
+               if (msg instanceof P2PChkResult) {
+                       return handler.handleCHK_CONTENT(sender,msg);
+                       }
+               return false;
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/BloomFilter2.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/BloomFilter2.java  2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/BloomFilter2.java  2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,107 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+
+import java.nio.*;
+import java.util.logging.*;
+
+/**
+ * Bloomfilter implementation.
+ */
+
+public class BloomFilter2 extends LoggedObject
+{
+       public static final String      BLOOMFILTER1    =       
"content_bloomfilter";
+       public static final String      BLOOMFILTER2    =       
"keyword_bloomfilter";
+
+       /** Filters. */
+       public BloomFilter      superBloomFilter;
+       public BloomFilter      singleBloomFilter;
+
+
+       public BloomFilter2()
+       {
+               super(true);
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public void init( CoreForProtocol capi )
+       {
+               ByteBuffer      buf;
+               String          fn,bf;
+               int                     quota,superbf_size,singlbf_size;
+
+               Statistics              
stats=capi.getApplication().getStatistics();
+               Prefs   prefs=capi.getApplication().getPreferences();
+
+               fn = prefs.getString("AFS","AFSDIR",null);
+               if (fn==null) {
+                       trace("Configuration must specify directory for AFS 
data in section AFS under AFSDIR.");
+                       return;
+                       }
+               new DirLocation(fn).create();
+
+               /* read existing quota, check if it changed */
+               quota = prefs.getInt("AFS","DISKQUOTA",0);
+
+               buf=prefs.getContent("AFS-DISKQUOTA");
+               if (buf==null || buf.capacity()!=4) {
+                       buf=ByteBuffer.allocateDirect(4);
+                       buf.putInt(quota);
+                       prefs.putContent("AFS-DISKQUOTA",buf);
+                       }
+               else if (buf.getInt()!=quota) {
+                       log(Level.SEVERE,"AFS-Quota changed, run gnunet-convert 
!");
+                       return;
+                       }
+               quota = quota * 1024; /* convert to kb */
+               singlbf_size = quota;    /* 8 bit per entry/kb in DB */
+               superbf_size = quota;
+
+               bf=fn+"/"+BLOOMFILTER1;
+               superBloomFilter=BloomFilter.load(stats,bf,superbf_size,5); /* 
approx. 3% false positives at max use */
+
+               bf=fn+"/"+BLOOMFILTER2;
+               singleBloomFilter=BloomFilter.load(stats,bf,singlbf_size,5); /* 
approx. 3% false positives at max use */
+       }
+
+       public void done()
+       {
+               singleBloomFilter.free();
+               superBloomFilter.free();
+       }
+
+       public void bf_deleteEntryCallback( HashCode160 key, ContentIndex ce, 
Object data, int datalen, Object closure )
+       {
+               switch (ce.type) {
+                       case ContentIndex.LOOKUP_TYPE_CHK:
+                       case ContentIndex.LOOKUP_TYPE_3HASH:
+                       case ContentIndex.LOOKUP_TYPE_SBLOCK:
+                               singleBloomFilter.delete(key);
+                               break;
+                       case ContentIndex.LOOKUP_TYPE_SUPER:
+                               superBloomFilter.delete(key);
+                               break;
+                       case ContentIndex.LOOKUP_TYPE_CHKS:
+                               break;
+                       default:
+                               log(Level.WARNING,"Bloom filter notified of 
deletion of unexpected type of content entry: "+ce.type+".");
+                               break;
+                       }
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/DBHandle.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/DBHandle.java      2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/DBHandle.java      2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,170 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.crypto.*;
+
+/**
+ * Handle for a high-level database (mysql, simple)
+ * mysql wrapper
+ */
+
+public interface DBHandle
+{
+       /**
+        * Open the database.
+        *
+        * @param prefs
+        * @param backend       string used to distinguish multiple backends of 
the same type.
+        * @param name          parameter for naming the database configuration 
(e.g. quota)
+        * @return                      the database handle
+        */
+
+       public boolean open( Prefs prefs, String backend, String name );
+
+       /**
+        * Close the database.
+        */
+
+       public void close();
+
+       /**
+        * Remove the database (entirely!). Also implicitly close database.
+        * Close and delete the database.
+        */
+
+       public void drop();
+
+       /**
+        * Read the contents of a bucket to a buffer.
+        * Read the contents of a block to a buffer. In the case of 3HASH
+        * query, readContent must also return the respective 2HASH in
+        * ce.hash [so that hash(ce.hash)==3HASH].
+        *
+        * @param query the query hash (3HASH o CHK)/the hashcode representing 
the entry
+        * @param ce    what to look for (will be modified on return)/the 
meta-data of the entry (set)
+        * @param prio  the amount to change priority of the entry if found/by 
how much should the priority of the content be changed
+        * @return              the content on success, null on failure
+        */
+
+       public byte[] readContent( HashCode160 query, ContentIndex ce, int prio 
);
+
+       /**
+        * Write content to a file. Check for reduncancy and eventually
+        * append.
+        * Write content to the db.  Overwrites existing data.
+        * If ce.type is LOOKUP_TYPE_3HASH, ce.hash will contain
+        * a double hash which must be converted to 3HASH, later to be
+        * retrievable by 3HASH, but the 2HASH must be stored so it can
+        * be retrieved by readContent(). For indexed content,
+        * ce.fileOffset and ce.fileNameIndex must be stored.
+        * Note that block can be null for on-demand encoded content
+        * (in this case, len must also be 0).
+        * Write content to the db.  Overwrites existing data.
+        * If ce.type is LOOKUP_TYPE_3HASH, ce.hash will contain
+        * a double hash which must be converted to 3HASH, later to be
+        * retrievable by 3HASH, but the 2HASH must be stored so it can
+        * be retrieved by readContent(). For indexed content,
+        * ce.fileOffset and ce.fileNameIndex must be stored.
+        * Note that block can be null for on-demand encoded content
+        * (in this case, len must also be 0).
+        *
+        * @param ce information related to the block to store/the meta-data 
for the entry/the meta-data for the entry
+        * @param block the data to store
+        * @param offset offset
+        * @param length the size of the block
+        * @return false on error, true if ok.
+        */
+
+       public boolean writeContent( ContentIndex ce, byte[] block, int offset, 
int length );
+
+       /**
+        * Get the number of entries in the database.
+        * Get the number of entries in the database.
+        *
+        * @return -1 on error, otherwise the number of entries
+        */
+
+       public int countContentEntries();
+
+       /**
+        * Get the lowest priority of content in the DB.
+        * Get the lowest priority of content in the store.
+        * Get the lowest priority value of all content in the store.
+        *
+        * @return the lowest priority
+        */
+
+       public int getMinimumPriority();
+
+       /**
+        * Call a method for each key in the database and
+        * call the callback method on it.
+        * Call a method for each key in the database and
+        * call the callback method on it.
+        *
+        * @param callback the callback method
+        * @param data second argument to all callback calls
+        * @return the number of items stored in the content database
+        */
+
+       public int forEachEntry( EntryCallback callback, Object data );
+
+       /**
+        * Return a random key from the database (just the key, not the
+        * content!).
+        * Get a random content block from MySQL database.
+        * Tries to use indexes efficiently.
+        *
+        * Code supplied by H. Pagenhardt
+        *
+        * @param ce the meta-data of the random content (set)/output 
information about the key
+        * @return true on success, false on error
+        */
+
+       public boolean getRandomContent( ContentIndex ce );
+
+       /**
+        * Delete low-priority content from the database
+        * Deletes some least important content
+        *
+        * @param count the number of entries to delete/the number of 1kb 
blocks to free
+        * @param callback method to call on each deleted entry/method to call 
on each deleted item
+        * @param closure extra argument to callback
+        * @return true on success, false on error
+        */
+
+       public boolean deleteContent( int count, EntryCallback callback, Object 
closure );
+
+       /**
+        * Estimate how many blocks can be stored in the DB
+        * before the quota is reached.
+        * Estimate how many blocks can be stored in the DB
+        * before the quota is reached.
+        *
+        * NOTE: this function can not be performed relying on
+        * Data_length+Index_length from "SHOW TABLE STATUS" because
+        * those values seem not to be decreasing in real time.
+        * On mysql 4.0.16, Avg_row_len seems to be updating in real
+        * time w.r.t. insertions and deletions.
+        *
+        * @param quota the number of kb available for the DB
+        * @return number of blocks left
+        */
+
+       public int estimateAvailableBlocks( int quota );
+
+       /**
+        * Free space in the database by removing an entry.
+        *
+        * @param name the key of the entry to remove/the query of the entry to 
remove/hashcode for the block to be deleted
+        * @return false on error, true if ok.
+        * Free space in the database by removing one block
+        */
+
+       public boolean unlink( HashCode160 name );
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/EntryCallback.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/EntryCallback.java 2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/EntryCallback.java 2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,33 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.crypto.*;
+
+/**
+ *
+ */
+
+public interface EntryCallback
+{
+       /**
+        * Callback function type used by the iterator.  Contains the key,
+        * index information, the block (null if there is no block in the
+        * database), the length of the block and the closure.
+        *
+        * The callback is responsible for freeing data if data is not null.
+        *
+        * Note that the callback function may not perform additional
+        * read, write or delete operations on the database!
+        * @param key
+        * @param ce
+        * @param data
+        * @param dataLen
+        * @param closure
+        */
+
+       public void onEntry( HashCode160 key, ContentIndex ce, Object data, int 
dataLen, Object closure );
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/FileIndex.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/FileIndex.java     2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/FileIndex.java     2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,376 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.io.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * This module is responsible for storing the names
+ * of indexed files.
+ * access to the list of indexed files
+ *
+ * This module is responsible for storing the names
+ * of indexed files. The index for a file is always
+ * >0, since 0 is reserved for "not indexed".
+ */
+
+public class FileIndex extends LoggedObject
+{
+       public static final String      DATABASELIST    =       "database.list";
+
+       /** names of indexed files */
+       private String[]                                indexed_files;
+
+       /** Size of the indexed_files list. */
+       private int                                             
indexed_files_size;
+
+       /** number of files that are indexed */
+       private int                                             
indexed_files_count;
+
+       /** Mutex for synced access to indexed_files */
+       private Sync                                    lock;
+
+       /** stat handle for indexed_files_count */
+       private Stat                            stat_indexed_files_count;
+
+       /** stat handle for total size of indexed files */
+       private Stat                            stat_indexed_files_size;
+
+       /** */
+       private String                                  shared_file_list;
+
+       /** */
+       private Statistics      stats;
+
+       /** */
+       private Prefs   prefs;
+
+
+       public FileIndex()
+       {
+               super(true);
+       }
+
+       public String toString()
+       {
+               return "File index";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Initialize the fileindex module.
+        * @param capi
+        */
+
+       public void init( CoreForProtocol capi )
+       {
+               stats=capi.getApplication().getStatistics();
+               prefs=capi.getApplication().getPreferences();
+
+               shared_file_list = getSharedFileList();
+               stat_indexed_files_count=stats.getHandle("# indexed files");
+               stat_indexed_files_size= stats.getHandle("# size of indexed 
files");
+               lock=new Mutex();
+               if (!scanDatabaseList()) {
+                       trace("Could not initialize file index module !");
+                       }
+       }
+
+       /**
+        * Shutdown the fileindex module.
+        */
+
+       public void done()
+       {
+               indexed_files=null;
+               shared_file_list=null;
+               lock=null;
+       }
+
+       /**
+        * Get the name of the file where we store the
+        * list of indexed files.
+        * @return
+        */
+
+       protected String getSharedFileList()
+       {
+               String  str;
+
+               str=prefs.getString("AFS","AFSDIR",null);
+               if (str==null) {
+                       log(Level.SEVERE,"Configuration file must specify 
filename for storing AFS data in section AFS under AFSDIR.");
+                       return null;
+                       }
+               new DirLocation(str).create();  // important, the directory may 
not exist yet !
+               return new FileLocation(str+"/"+DATABASELIST).getPath();
+       }
+
+       /**
+        * Scan the list of on-demand shared files to initialize indexed_files
+        * @return OK on success, false on error
+        */
+
+       protected boolean scanDatabaseList()
+       {
+               BufferedReader  handle;
+               String                  str;
+               long                    totalSize;
+               List                    list;
+               FileLocation            f;
+
+               try {
+                       lock.acquire();
+                       try {
+                               indexed_files = null;
+                               indexed_files_count = 0;
+                               indexed_files_size = 0;
+                               stat_indexed_files_count.reset();
+                               stat_indexed_files_size.reset();
+                               totalSize = 0;
+
+                               try {
+                                       handle=new BufferedReader(new 
InputStreamReader(new FileInputStream(shared_file_list)));
+                                       try {
+                                               list=new ArrayList();
+                                               for (str=handle.readLine(); 
str!=null; str=handle.readLine()) {
+                                                       if (str.length()>0) {
+                                                               
indexed_files_count++;
+                                                               list.add(str);
+
+                                                               f=new 
FileLocation(str);
+                                                               totalSize += 
f.getSize();
+                                                               }
+                                                       else {
+                                                               list.add(null);
+                                                               }
+                                                       }
+
+                                               if (indexed_files_count == 0) {
+                                                       return true;
+                                                       }
+
+                                               indexed_files_size = 
list.size();
+                                               indexed_files = (String[]) 
list.toArray(new String[list.size()]);
+                                               }
+                                       finally {
+                                               handle.close();
+                                               }
+                                       }
+                               catch( FileNotFoundException x ) {
+                                       // file not found : not an error
+                                       }
+                               catch( IOException x ) {
+                                       err("Could not open 
"+shared_file_list+" !",x);
+                                       return false;
+                                       }
+
+                               
stat_indexed_files_count.set(indexed_files_count);
+                               stat_indexed_files_size.set(totalSize);
+                               }
+                       finally {
+                               lock.release();
+                               }
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       return false;
+                       }
+               return true;
+       }
+
+       /**
+        * Get the name of an indexed file.
+        *
+        * @param index the index of the file (must be strictly positive)
+        * @return the filename
+        */
+
+       public String getIndexedFileName( int index )
+       {
+               if (index<=0 || index>indexed_files_size) {
+                       log(Level.WARNING,"getIndexedFileName called with index 
out of bounds ("+index+")");
+                       return null;
+                       }
+
+               try {
+                       lock.acquire();
+                       try {
+                               return indexed_files[index-1];
+                               }
+                       finally {
+                               lock.release();
+                               }
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       return null;
+                       }
+       }
+
+       /**
+        * Invoke a method on each of the filenames of the indexed files. If
+        * the method returns false, the file is removed from the list of
+        * indexed files!
+        *
+        * @param method the method to invoke for each indexed file
+        * @param data the last argument to method
+        * @return the number of shared files (after changes caused by this 
call)
+        */
+
+       public int forEachIndexedFile( IndexedFileNameCallback method, Object 
data )
+       {
+               PrintWriter     handle;
+               int                     i;
+               boolean         changed,erase;
+
+               try {
+                       lock.acquire();
+                       try {
+                               changed=false;
+                               for (i=0; i<indexed_files_size; i++) {
+                                       if (indexed_files[i] != null) {
+                                               lock.release();
+                                               try {
+                                                       
erase=!method.onFile(indexed_files[i],i+1,data);
+                                                       }
+                                               finally {
+                                                       lock.acquire();
+                                                       }
+
+                                               if (erase) {
+                                                       indexed_files[i]=null;
+                                                       changed=true;
+                                                       }
+                                               }
+                                       }
+
+                               if (changed) {
+                                       /* write changed list to the drive */
+
+                                       try {
+                                               handle = new PrintWriter(new 
OutputStreamWriter(new FileOutputStream(shared_file_list)),true);
+                                               try {
+                                                       for (i=0; 
i<indexed_files_size; i++) {
+                                                               if 
(indexed_files[i]!=null) {
+                                                                       
handle.println(indexed_files[i]);
+                                                                       }
+                                                               else {
+                                                                       
handle.println();
+                                                                       }
+                                                               }
+                                                       }
+                                               finally {
+                                                       handle.close();
+                                                       }
+                                               }
+                                       catch( IOException x ) {
+                                               err("List "+shared_file_list+" 
of directly shared filenames not available !",x);
+                                               return -1;
+                                               }
+                                       }
+                               }
+                       finally {
+                               lock.release();
+                               }
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       return -1;
+                       }
+               return indexed_files_count;
+       }
+
+       /**
+        * Add a name to the list of filenames.
+        *
+        * @param filename the name of the file to add
+        * @return the index of that file in the list in [1,65536], -1 on 
error. <em>NEVER</em> returns 0.
+        */
+
+       public int appendFilename( String filename )
+       {
+               BufferedReader  handle;
+               PrintWriter     out;
+               String          str;
+               int                     pos;
+
+               assert(filename!=null);
+
+               try {
+                       lock.acquire();
+                       try {
+                               pos=0;
+                               filename=new FileLocation(filename).getPath();
+
+                               try {
+                                       handle=new BufferedReader(new 
InputStreamReader(new FileInputStream(shared_file_list)));
+                                       try {
+                                               for (str=handle.readLine(); 
str!=null; str=handle.readLine()) {
+                                                       pos++;
+                                                       if 
(str.equals(filename)) {
+                                                               debug("File 
already at index "+pos+".");
+                                                               return pos;     
// already there !
+                                                               }
+                                                       }
+                                               }
+                                       finally {
+                                               handle.close();
+                                               }
+                                       }
+                               catch( FileNotFoundException x ) {
+                                       // file not found : not an error
+                                       }
+                               catch( IOException x ) {
+                                       err("List "+shared_file_list+" of 
directly shared filenames not available !",x);
+                                       return -1;
+                                       }
+
+                               if (pos > 0xFFFF) {
+                                       log(Level.WARNING,"Too many files 
indexed (limit is 65535).");
+                                       return -1;
+                                       }
+
+                               // not there, append
+                               try {
+                                       out = new PrintWriter(new 
OutputStreamWriter(new FileOutputStream(shared_file_list,true)),true);
+                                       try {
+                                               out.println(filename);
+                                               }
+                                       finally {
+                                               out.close();
+                                               }
+                                       }
+                               catch( IOException x ) {
+                                       err("List "+shared_file_list+" of 
directly shared filenames not available !",x);
+                                       return -1;
+                                       }
+                               }
+                       finally {
+                               lock.release();
+                               }
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       return -1;
+                       }
+
+               scanDatabaseList();
+
+               debug("Added file to index at position "+pos+".");
+
+               return pos; /* return index */
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/Handler.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/Handler.java       2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/Handler.java       2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,897 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import java.util.logging.*;
+
+/**
+ * Handlers for incoming AFS requests (p2p and CS).
+ * Handlers for AFS related messages (CS and p2p).
+ */
+
+public class Handler extends LoggedObject implements AFSConstants
+{
+       private CoreForProtocol coreAPI;
+
+       private Prefs   prefs;
+
+       private Stat    stat_p2p_query_count;
+       private Stat    stat_p2p_superquery_count;
+       private Stat    stat_p2p_chk_replies;
+       private Stat    stat_p2p_3hash_replies;
+       private Stat    stat_cs_query_count;
+       private Stat    stat_cs_insert_chk_count;
+       private Stat    stat_cs_insert_3hash_count;
+       private Stat    stat_cs_index_block_count;
+       private Stat    stat_cs_index_file_count;
+       private Stat    stat_cs_index_super_count;
+       private Stat    stat_cs_delete_chk_count;
+       private Stat    stat_cs_delete_3hash_count;
+       private Stat    stat_cs_unindex_block_count;
+       private Stat    stat_cs_unindex_file_count;
+       private Stat    stat_cs_unindex_super_count;
+       private Stat    stat_cs_upload_file_count;
+       private Stat    stat_cs_insert_sblock_count;
+       private Stat    stat_cs_nsquery_count;
+       private Stat    stat_p2p_nsquery_count;
+       private Stat    stat_p2p_sblock_replies;
+
+       public Policy2          policy;
+       public BloomFilter      singleBloomFilter;
+       public BloomFilter      superBloomFilter;
+       public FileIndex                fileIndex;
+       public Manager          manager;
+       public Routing          routing;
+
+
+       public Handler()
+       {
+               super(true);
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Initialize the handler module. Registers counters
+        * with the statistics module.
+        * @param capi
+        */
+
+       public void init( CoreForProtocol capi )
+       {
+               Statistics      stats;
+
+               coreAPI=capi;
+
+               prefs=capi.getApplication().getPreferences();
+
+               stats=capi.getApplication().getStatistics();
+               stat_p2p_query_count=stats.getHandle("# p2p queries received");
+               stat_p2p_superquery_count=stats.getHandle("# p2p super queries 
received");
+               stat_p2p_chk_replies=stats.getHandle("# p2p CHK content 
received (kb)");
+               stat_p2p_3hash_replies=stats.getHandle("# p2p search results 
received (kb)");
+               stat_cs_query_count=stats.getHandle("# client queries 
received",Stat.VERBOSE);
+               stat_cs_insert_chk_count=stats.getHandle("# client CHK content 
inserted (kb)",Stat.VERBOSE);
+               stat_cs_insert_3hash_count=stats.getHandle("# client 3HASH 
search results inserted (kb)",Stat.VERBOSE);
+               stat_cs_index_block_count=stats.getHandle("# client file index 
requests received",Stat.VERBOSE);
+               stat_cs_index_file_count=stats.getHandle("# file index requests 
received",Stat.VERBOSE);
+               stat_cs_index_super_count=stats.getHandle("# super query index 
requests received",Stat.VERBOSE);
+               stat_cs_delete_chk_count=stats.getHandle("# client CHK content 
deleted (kb)",Stat.VERBOSE);
+               stat_cs_delete_3hash_count=stats.getHandle("# client 3HASH 
search results deleted (kb)",Stat.VERBOSE);
+               stat_cs_unindex_block_count=stats.getHandle("# client file 
unindex requests received",Stat.VERBOSE);
+               stat_cs_unindex_file_count=stats.getHandle("# file unindex 
requests received",Stat.VERBOSE);
+               stat_cs_unindex_super_count=stats.getHandle("# super query 
unindex requests received",Stat.VERBOSE);
+               stat_cs_insert_sblock_count=stats.getHandle("# client SBlock 
insert requests received",Stat.VERBOSE);
+               stat_cs_nsquery_count=stats.getHandle("# client namespace 
queries received",Stat.VERBOSE);
+               stat_cs_upload_file_count=stats.getHandle("# client file upload 
requests",Stat.VERBOSE);
+               stat_p2p_nsquery_count=stats.getHandle("# p2p namespace queries 
received");
+               stat_p2p_sblock_replies=stats.getHandle("# p2p SBlocks 
received");
+       }
+
+       /**
+        * Handle query for content. Depending on how we like the sender,
+        * lookup, forward or even indirect.
+        * @param sender
+        * @param msg
+        * @return
+        */
+
+       public boolean handleQUERY( HostIdentity sender, P2PMessage msg )
+       {
+               int                             qp;
+               P2PQuery        qmsg;
+               int                             queries;
+               int                             ttl;
+               int                             prio;
+               double                  preference;
+
+               queries = (msg.getByteSize() - P2PQuery.SIZE) / 
HashCode160.SIZE;       //todo: AFS_p2p_QUERY.getQueriesCount()
+               if (queries<=0 || (msg.getByteSize()!=P2PQuery.SIZE + queries * 
HashCode160.SIZE) ) {
+                       log(Level.WARNING,"Query received was malformed.");
+                       return false;
+                       }
+               if (queries>1)
+                       stat_p2p_superquery_count.inc();
+               stat_p2p_query_count.inc();
+               qmsg = (P2PQuery) msg;
+
+               debug("Received query "+qmsg.getQuery(0).toHex()+" 
("+queries+") TTL "+qmsg.getTTL()+" PR "+qmsg.getPriority()+" from 
"+sender.getName()+".");
+
+               /* decrement ttl (always) */
+               ttl = qmsg.getTTL();
+               debug("Received query for "+qmsg.getQuery(0).toHex()+" with ttl 
"+ttl+".");
+
+               if (ttl < 0) {
+                       ttl = (int) (ttl - 2*TTL_DECREMENT - 
Crypto.nextLong(TTL_DECREMENT));
+                       if (ttl > 0)
+                               return true; /* just abort */
+               } else
+                       ttl = (int) (ttl - 2*TTL_DECREMENT - 
Crypto.nextLong(TTL_DECREMENT));
+               qp = policy.evaluateQuery(sender,qmsg.getPriority());
+               if ((qp & Policy2.QUERY_DROPMASK) == 0)
+                       return true; /* straight drop. */
+
+               preference=qp & Policy2.QUERY_PRIORITY_BITMASK;
+               if (preference < Policy2.QUERY_BANDWIDTH_VALUE)
+                       preference = Policy2.QUERY_BANDWIDTH_VALUE;
+               coreAPI.preferTrafficFrom(sender,
+                               preference);
+
+               /* adjust priority */
+               prio = qmsg.getPriority();
+               if ( (qp & Policy2.QUERY_PRIORITY_BITMASK) < prio) {
+                       prio = qp & Policy2.QUERY_PRIORITY_BITMASK;
+                       qmsg.setPriorityAndTTL(prio,qmsg.getTTL());
+               }
+               prio = prio / queries; /* effective priority for ttl */
+
+               /* adjust TTL */
+               if ( (ttl > 0) &&
+                               (ttl > (prio+3)*TTL_DECREMENT) )
+                       ttl = (int) ((prio+3)*TTL_DECREMENT); /* bound! */
+               qmsg.setPriorityAndTTL(qmsg.getPriority(),ttl);
+
+               routing.execQuery(qp, qmsg, null);
+               return true;
+       }
+
+       /**
+        * Receive content, do something with it!  There are 3 basic
+        * possiblilities. Either our node did the request and we should send
+        * the result to a client via TCP, or the content was requested by
+        * another node and we forwarded the request (and thus we now have to
+        * fwd the reply) or 3rd somebody just send us some content we did NOT
+        * ask for - and we can choose to store it or just discard it.
+        * @param sender
+        * @param msg
+        * @return
+        */
+
+       public boolean handleCHK_CONTENT( HostIdentity sender, P2PMessage msg )
+       {
+               int                                     prio;
+               HashCode160                     queryHash;
+               ContentIndex            ce=new ContentIndex();
+               P2PChkResult    cmsg;
+               boolean                         ret;
+               double                          preference;
+               boolean[]               dupe=new boolean[1];
+
+               if (msg.getByteSize()!=P2PChkResult.SIZE) {
+                       log(Level.WARNING,"WARNING: CHK content message 
received was malformed");
+                       return false;
+                       }
+               stat_p2p_chk_replies.inc();
+               cmsg = (P2PChkResult) msg;
+               
queryHash=HashCode160.create(PersistentHelper.toBytes(cmsg.result));
+               prio = routing.useContent(sender,queryHash,msg);
+               if (sender == null) /* no migration, this is already content 
from the local node */
+                       return true;
+               preference = prio;
+               prio = policy.evaluateContent(queryHash,prio);
+               if (prio != -1)
+                       preference+=prio;
+               if (preference < Policy2.CONTENT_BANDWIDTH_VALUE)
+                       preference = Policy2.CONTENT_BANDWIDTH_VALUE;
+               coreAPI.preferTrafficFrom(sender,preference);
+
+               if (prio == -1)
+                       return true; /* straight drop */
+               ce.hash=(HashCode160) PersistentHelper.copy(queryHash);         
//todo: copie utile ?
+               ce.importance    = prio;
+               ce.type          = ContentIndex.LOOKUP_TYPE_CHK;
+               ce.fileNameIndex = 0;
+               ce.fileOffset    = 0;
+               ret = manager.insertContent(ce,
+                               ContentBlock.SIZE,
+                               cmsg.result,
+                               sender,
+                               dupe);
+               if (ret && !dupe[0])
+                       singleBloomFilter.add(queryHash);
+               return true;
+       }
+
+       /**
+        * Receive content, do something with it!  There are 3 basic
+        * possiblilities. Either our node did the request and we should send
+        * the result to a client via TCP, or the content was requested by
+        * another node and we forwarded the request (and thus we now have to
+        * fwd the reply) or 3rd somebody just send us some content we did NOT
+        * ask for - and we can choose to store it or just discard it.
+        * @param sender
+        * @param msg
+        * @return
+        */
+
+       public boolean handle3HASH_CONTENT( HostIdentity sender, P2PMessage msg 
)
+       {
+               int                                             prio;
+               P2P3HashResult  cmsg;
+               HashCode160                             tripleHash;
+               ContentIndex                    ce=new ContentIndex();
+               boolean                                 ret;
+               double                                  preference;
+               boolean[]               dupe=new boolean[1];
+
+               if (msg.getByteSize() != P2P3HashResult.SIZE) {
+                       log(Level.WARNING,"WARNING: content message received 
was malformed");
+                       return false;
+                       }
+               stat_p2p_3hash_replies.inc();
+               cmsg = (P2P3HashResult) msg;
+               tripleHash=cmsg.getTripleHash();
+
+               debug("DEBUG: received 3HASH search result for 
"+tripleHash.toHex()+" from peer");
+
+               prio = routing.useContent(sender,tripleHash,msg);
+               if (sender == null) { /* no migration, this is already content 
from the local node */
+                       //fixme: how is it possible to have sender == null ???
+                       debug("Content migration not needed, content is 
local.");
+                       return true;
+                       }
+               preference = prio;
+
+               debug("Content migration with preference "+prio);
+
+               prio = policy.evaluateContent(tripleHash,prio);
+               if (prio != -1)
+                       preference += prio;
+               if (preference < Policy2.CONTENT_BANDWIDTH_VALUE)
+                       preference = Policy2.CONTENT_BANDWIDTH_VALUE;
+               coreAPI.preferTrafficFrom(sender,preference);
+
+               if (prio == -1) {
+                       debug("DEBUG: content not important enough, not 
replicated");
+                       return true; /* straight drop */
+                       }
+               debug("DEBUG: content replicated with total preference "+prio);
+
+               ce.hash=cmsg.getDoubleHash();
+               ce.importance    = prio;
+               ce.type          = ContentIndex.LOOKUP_TYPE_3HASH;
+               ce.fileNameIndex = 0;
+               ce.fileOffset    = 0;
+
+               ret = 
manager.insertContent(ce,ContentBlock.SIZE,cmsg.getResult(),sender,dupe);
+               if (ret && !dupe[0])
+                       singleBloomFilter.add(tripleHash);
+               return true;
+       }
+
+       /**
+        * Process a query from the client. Forwards to the network.
+        * @param sock
+        * @param queryRequest
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestQuery( CSSession sock, CSQuery 
queryRequest )
+       {
+               int                             qp = 
Policy2.QUERY_ANSWER|Policy2.QUERY_FORWARD|Policy2.QUERY_INDIRECT|Policy2.QUERY_PRIORITY_BITMASK;
+               P2PQuery        msg;
+               int                             queries;
+               int                             ttl;
+               boolean                 ret;
+
+               queries = (queryRequest.getByteSize() - CSQuery.SIZE) / 
HashCode160.SIZE;
+               if ( (queries <= 0) || (queryRequest.getByteSize() != 
CSQuery.SIZE + queries * HashCode160.SIZE) ) {
+                       log(Level.WARNING,"Received malformed query from 
client.");
+                       return false;
+                       }
+               stat_cs_query_count.inc();
+
+               debug("Received "+queries+" queries 
("+queryRequest.getQuery(0).toHex()+") with ttl "+queryRequest.getTTL()+" and 
priority "+queryRequest.getPriority()+".");
+
+               msg = new P2PQuery(coreAPI.getIdentity());
+               msg.setQueries(queryRequest.getQueries());
+               /* adjust TTL */
+               ttl = queryRequest.getTTL();
+               if ( (ttl > 0) && (ttl > (msg.getPriority()+8)*TTL_DECREMENT) )
+                       ttl = (int) ((msg.getPriority()+8)*TTL_DECREMENT); /* 
bound! */
+
+               msg.setPriorityAndTTL(queryRequest.getPriority(),ttl);
+
+               ret = routing.execQuery(qp, msg, sock);
+               debug("Executed "+queries+" queries with result "+ret+".");
+               return sock.send(new CSResult(ret));
+       }
+
+       /**
+        * Process a request to insert content from the client.
+        * @param sock
+        * @param insertRequest
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestInsertCHK( CSSession sock, CSInsertChk 
insertRequest )
+       {
+               ContentIndex    entry=new ContentIndex();
+               boolean                 ret;
+               boolean[]               dupe=new boolean[1];
+
+               stat_cs_insert_chk_count.inc();
+
+               
entry.hash=HashCode160.create(PersistentHelper.toBytes(insertRequest.getContent()));
+
+               debug("DEBUG: received CHK insert request for block 
"+entry.hash.toHex());
+
+               entry.type= ContentIndex.LOOKUP_TYPE_CHK;
+               entry.importance= insertRequest.getImportance();
+               entry.fileNameIndex= 0; /* database */
+               entry.fileOffset = 0; /* data/content */
+
+               ret = 
manager.insertContent(entry,ContentBlock.SIZE,insertRequest.getContent(),null,dupe);
+               if (ret && !dupe[0])
+                       singleBloomFilter.add(entry.hash);
+               return sock.send(new CSResult(ret));
+       }
+
+       /**
+        * Process a request to insert content from the client.
+        * @param sock
+        * @param insertRequest
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestInsert3HASH( CSSession sock, 
CSInsert3Hash insertRequest )
+       {
+               ContentIndex    entry=new ContentIndex();
+               HashCode160             tripleHash;
+               boolean                 ret;
+               boolean[]               dupe=new boolean[1];
+
+               stat_cs_insert_3hash_count.inc();
+
+               entry.hash=(HashCode160) 
PersistentHelper.copy(insertRequest.getDoubleHash());  //todo: copie utile ?
+               
tripleHash=HashCode160.create(PersistentHelper.toBytes(insertRequest.getDoubleHash()));
+
+               debug("Received 3HASH insert request for "+tripleHash.toHex()+" 
from client");
+
+               entry.type= ContentIndex.LOOKUP_TYPE_3HASH;
+               entry.importance= insertRequest.getImportance();
+               entry.fileNameIndex= 0; /* database */
+               entry.fileOffset = 0; /* data/content */
+               ret = 
manager.insertContent(entry,ContentBlock.SIZE,insertRequest.getContent(),null,dupe);
+               if (ret && !dupe[0]) {
+                       singleBloomFilter.add(tripleHash);
+                       }
+               return sock.send(new CSResult(ret));
+       }
+
+       /**
+        * Process a request to index content from the client.
+        * @param sock
+        * @param indexingRequest
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestIndexBlock( CSSession sock, CSIndexBlock 
indexingRequest )
+       {
+               boolean[]               dupe=new boolean[1];
+
+               debug("Indexing content 
"+indexingRequest.getContentIndex().hash.toHex()+" at offset 
"+indexingRequest.getContentIndex().fileOffset);
+
+               stat_cs_index_block_count.inc();
+               return sock.send(new 
CSResult(manager.insertContent(indexingRequest.getContentIndex(),0,(byte[]) 
null,null,dupe)));
+       }
+
+       /**
+        * Process a query to list a file as on-demand encoded from the client.
+        * @param sock
+        * @param listFileRequest
+        *
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestIndexFile( CSSession sock, CSIndexFile 
listFileRequest )
+       {
+               DirLocation     dir;
+               String          str;
+               long                    quota,usage;
+               int                     ret;
+
+               stat_cs_index_file_count.inc();
+
+               str = prefs.getString("AFS","INDEX-DIRECTORY",null);
+               if (str == null) {
+                       log(Level.WARNING,"Rejecting content-unindex request, 
INDEX-DIRECTORY option not set !");
+                       return sock.send(CSResult.ERR);
+                       }
+
+               dir=new DirLocation(str);
+               dir.create();
+
+               quota=prefs.getInt("AFS","INDEX-QUOTA",0) * 1024 * 1024;
+               if (quota != 0) {
+                       usage=dir.getSizeWithoutLinks();
+                       if (usage + listFileRequest.filesize > quota) {
+                               log(Level.WARNING,"Rejecting file index 
request, quota exeeded: "+(usage / 1024 / 1024)+" of "+(quota / 1024 / 1024)+" 
(MB)");
+                               return sock.send(CSResult.ERR);
+                               }
+                       }
+
+               str=dir.getPath()+"/"+listFileRequest.hash.toHex();
+               ret = fileIndex.appendFilename(str);
+               if (ret == 0)
+                       ret = -1;
+               return sock.send(new CSResult(ret));
+       }
+
+       /**
+        * Process a client request to upload a file (indexing).
+        * @param sock
+        * @param uploadRequest
+        * @return
+        */
+
+       public boolean csHandleRequestUploadFile( CSSession sock, CSUploadFile 
uploadRequest )
+       {
+               DirLocation     prefix;
+               MappedFile      fd;
+               FileLocation    filename;
+               String          str;
+
+               stat_cs_upload_file_count.inc();
+
+               str=prefs.getString("AFS","INDEX-DIRECTORY",null);
+               if (str==null) {
+                       log(Level.WARNING,"WARNING: rejecting content-upload 
request, INDEX-DIRECTORY option not set!");
+                       return sock.send(CSResult.ERR);
+                       }
+
+               prefix=new DirLocation(str);
+               prefix.create();
+
+               filename=prefix.getFile(uploadRequest.hash.toHex());
+               filename.create();
+
+               fd=filename.open();
+               if (fd==null) {
+                       log(Level.SEVERE,"ERROR: OPEN() failed on "+filename);
+                       return sock.send(CSResult.ERR);
+                       }
+
+               try {
+                       fd.seek(uploadRequest.pos);
+                       if (!fd.writeBytes(uploadRequest.getChunk())) {
+                               return sock.send(CSResult.ERR);
+                               }
+                       }
+               finally {
+                       fd.close();
+                       }
+               return sock.send(new CSResult(uploadRequest.getChunk().length));
+       }
+
+       /**
+        * Process a client request to extend our super-query bloom
+        * filter.
+        * @param sock
+        * @param superIndexRequest
+        * @return
+        */
+
+       public boolean csHandleRequestIndexSuper( CSSession sock, CSIndexSuper 
superIndexRequest )
+       {
+               ContentIndex entry;
+               boolean[]               dupe=new boolean[1];
+
+               stat_cs_index_super_count.inc();
+
+               superBloomFilter.add(superIndexRequest.getSuperHash());
+
+               entry=new ContentIndex();
+               entry.type= ContentIndex.LOOKUP_TYPE_SUPER;
+               entry.importance= superIndexRequest.getImportance();
+               entry.fileNameIndex     = 0; /* database */
+               entry.fileOffset = 0; /* data/content */
+               entry.hash=(HashCode160) 
PersistentHelper.copy(superIndexRequest.getSuperHash());       //todo: copie 
utile ???
+               return sock.send(new 
CSResult(manager.insertContent(entry,0,(byte[]) null,null,dupe)));
+       }
+
+       /**
+        * Process a request from the client to delete content.
+        * @param sock
+        * @param insertRequest
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestDeleteCHK( CSSession sock, CSDeleteChk 
insertRequest )
+       {
+               HashCode160     hc;
+               boolean         ret;
+
+               stat_cs_delete_chk_count.inc();
+
+               
hc=HashCode160.create(PersistentHelper.toBytes(insertRequest.content));
+
+               debug("DEBUG: received CHK remove request for block 
"+hc.toHex());
+
+               ret = manager.removeContent(hc,-1);
+               if (ret)
+                       if (singleBloomFilter.test(hc))
+                               singleBloomFilter.delete(hc);
+               return sock.send(new CSResult(ret));
+       }
+
+       /**
+        * Process a request from the client to delete content.
+        * @param sock
+        * @param insertRequest
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestDelete3HASH( CSSession sock, 
CSDelete3Hash insertRequest )
+       {
+               HashCode160     tripleHash;
+               boolean         ret;
+
+               stat_cs_delete_3hash_count.inc();
+
+               
tripleHash=HashCode160.create(PersistentHelper.toBytes(insertRequest.doubleHash));
+
+               debug("DEBUG: received 3HASH delete request for 
"+tripleHash.toHex()+" from client");
+
+               ret = manager.removeContent(tripleHash,-1);
+               if (ret)
+                       singleBloomFilter.delete(tripleHash);
+
+               return sock.send(new CSResult(ret));
+       }
+
+       /**
+        * Process a request from the client to unindex content.
+        * @param sock
+        * @param indexingRequest
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestUnindexBlock( CSSession sock, 
CSUnindexBlock indexingRequest )
+       {
+               stat_cs_unindex_block_count.inc();
+               return sock.send(new 
CSResult(manager.removeContent(indexingRequest.contentIndex.hash,-1)));
+       }
+
+       /**
+        * Callback used to select the file in the fileindex
+        * that is to be removed.
+        * @param fn
+        * @param i
+        * @param search
+        * @return
+        */
+
+       protected boolean removeMatch( String fn, int i, String search )
+       {
+               return !fn.equals(search);
+       }
+
+       /**
+        * Process a query from the client to remove an on-demand encoded file.
+        * n.b. This function just zeroes the correct row in the list of
+        * on-demand encoded files, if match (deletion is done by 
forEachIndexedFile).
+        * The index of the filename that was removed is returned to the client.
+        *
+        * FIXME: It lookslike if listFileRequest.filename was NOT in 
database.list,
+        * it gets appended to it, removed from it, and client gets a false idx.
+        * This unnecessarily bloats the database.list by one empty line.
+        * @param sock
+        * @param listFileRequest
+        *
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestUnindexFile( CSSession sock, 
CSUnindexFile listFileRequest )
+       {
+               DirLocation     dir;
+               String          str;
+               int                     idx;
+
+               stat_cs_unindex_file_count.inc();
+
+               str=prefs.getString("AFS","INDEX-DIRECTORY",null);
+               if (str==null) {
+                       log(Level.WARNING,"WARNING: rejecting content-unindex 
request, INDEX-DIRECTORY option not set!");
+                       return sock.send(CSResult.ERR);
+                       }
+
+               dir=new DirLocation(str);
+               dir.create();
+
+               str=dir.getPath()+"/"+listFileRequest.hash.toHex();
+               idx=fileIndex.appendFilename(str);
+               if (idx==-1) {
+                       return sock.send(CSResult.ERR);
+                       }
+
+               assert(idx!=0) : "Index can't be null !";
+
+               fileIndex.forEachIndexedFile(new IndexedFileNameCallback() {
+                       public boolean onFile( String fn, int idxx, Object data 
)
+                       {
+                               return removeMatch(fn,idxx,(String) data);
+                       }
+                       },str);
+
+               if (!new FileLocation(str).delete()) {
+                       log(Level.WARNING,"Could not remove indexed file");
+                       idx = -1; /* remove failed!? */
+                       }
+               return sock.send(new CSResult(idx));
+       }
+
+       /**
+        * @param sock
+        * @param linkFileRequest
+        * @return false if the TCP connection should be closed, otherwise true
+        */
+
+       public boolean csHandleRequestLinkFile( CSSession sock, CSLinkFile 
linkFileRequest )
+       {
+               String          filename,tname;
+               DirLocation     prefix;
+               HashCode160     hc;
+               FileLocation    loc;
+               LinkLocation    f;
+
+               /* stat_cs_link_file_count.inc(); */    //todo: statut ???
+
+               tname=linkFileRequest.getPath();
+               loc=new FileLocation(tname);
+               hc=loc.getHash();
+
+               if (hc==null || !hc.equals(linkFileRequest.hash)) {
+                       log(Level.WARNING,"WARNING: file link request "+tname+" 
from client pointed to file with the wrong data !");
+                       return sock.send(CSResult.ERR);
+                       }
+
+               filename=prefs.getString("AFS","INDEX-DIRECTORY",null);
+               if (filename==null) {
+                       log(Level.WARNING,"WARNING: rejecting content-unindex 
request, INDEX-DIRECTORY option not set!");
+                       return sock.send(CSResult.ERR);
+                       }
+
+               prefix=new DirLocation(filename);
+               prefix.create();
+
+               filename=prefix.getPath()+"/"+linkFileRequest.hash.toHex();
+
+               f=new LinkLocation(filename);
+               if (f.setTarget(new FileLocation(tname))) {
+                       if (f.create()) {
+                               return sock.send(CSResult.OKAY);
+                               }
+                       }
+
+               log(Level.WARNING,"Could not create link from \""+tname+"\" to 
\""+f.getLabel()+"\".");
+               return sock.send(CSResult.ERR);
+       }
+
+       /**
+        * Process a client request to limit our super-query bloom
+        * filter.
+        * @param sock
+        * @param superIndexRequest
+        * @return
+        */
+
+       public boolean csHandleRequestUnindexSuper( CSSession sock, 
CSUnindexSuper superIndexRequest )
+       {
+               stat_cs_unindex_super_count.inc();
+
+               superBloomFilter.delete(superIndexRequest.superHash);
+               return sock.send(new 
CSResult(manager.removeContent(superIndexRequest.superHash,-1)));
+       }
+
+       /**
+        * @param sock
+        * @param insertRequest
+        * @return
+        *
+        */
+
+       public boolean csHandleRequestInsertSBlock( CSSession sock, 
CSInsertSBlock insertRequest )
+       {
+               ContentIndex    entry;
+               HashCode160             ns;
+               boolean                 ret;
+               boolean[]               dupe=new boolean[1];
+
+               stat_cs_insert_sblock_count.inc();
+
+               ns=insertRequest.getContent().getNameSpace();
+               debug("Received SBlock for namespace "+ns.toHex()+" with 
routing ID "+insertRequest.getContent().getIdentifier().toHex()+".");
+
+               entry=new ContentIndex();
+               entry.type= ContentIndex.LOOKUP_TYPE_SBLOCK;
+               entry.importance= insertRequest.getImportance();
+               entry.fileNameIndex= 0; /* database */
+               entry.fileOffset = 0; /* data/content */
+               entry.hash=(HashCode160) 
PersistentHelper.copy(insertRequest.getContent().getIdentifier());     //todo: 
copie utile ?
+               dupe[0] = false;
+               ret = 
manager.insertContent(entry,ContentBlock.SIZE,insertRequest.getContent(),null,dupe);
+
+               debug("Received SBlock insert is dupe: "+dupe+" (insert 
"+ret+")");
+
+               if (ret && !dupe[0]) {
+                       
singleBloomFilter.add(insertRequest.getContent().getIdentifier());
+                       }
+               return sock.send(new CSResult(ret));
+       }
+
+       /**
+        * @param sock
+        * @param queryRequest
+        * @return
+        *
+        */
+
+       public boolean csHandleRequestNSQuery( CSSession sock, CSNSQuery 
queryRequest )
+       {
+               int                             qp = 
Policy2.QUERY_ANSWER|Policy2.QUERY_FORWARD|Policy2.QUERY_INDIRECT|Policy2.QUERY_PRIORITY_BITMASK;
+               P2PNSQuery      msg;
+
+               stat_cs_nsquery_count.inc();
+
+               debug("Received NS query 
("+queryRequest.namespace.toHex()+"/"+queryRequest.identifier.toHex()+") with 
ttl "+queryRequest.ttl+" and priority "+queryRequest.priority+".");
+
+               msg = new P2PNSQuery(coreAPI.getIdentity());
+               msg.setPriorityAndTTL(queryRequest.priority,queryRequest.ttl);
+               msg.identifier=(HashCode160) 
PersistentHelper.copy(queryRequest.identifier);    //todo: copie utile ???
+               msg.namespace=(HashCode160) 
PersistentHelper.copy(queryRequest.namespace);      //todo: copie utile ???
+               routing.execQuery(qp, msg, sock);
+               return true;
+       }
+
+       public boolean handleNSQUERY( HostIdentity sender, P2PMessage msg )
+       {
+               int                             qp;
+               P2PNSQuery      qmsg;
+               int ttl;
+               int prio;
+               double preference;
+
+               if (msg.getByteSize() != P2PNSQuery.SIZEX) {
+                       log(Level.WARNING,"WARNING: nsquery received was 
malformed");
+                       return false;
+                       }
+               stat_p2p_nsquery_count.inc();
+               qmsg = (P2PNSQuery) msg;
+               /* decrement ttl */
+               ttl = qmsg.getTTL();
+
+               debug("DEBUG: received NS query for "+qmsg.identifier.toHex()+" 
with ttl "+ttl);
+
+               if (ttl < 0) {
+                       ttl = (int) (ttl - 2*TTL_DECREMENT - 
Crypto.nextLong(TTL_DECREMENT));
+                       if (ttl > 0)
+                               return true; /* just abort */
+                       }
+               else
+                       ttl = (int) (ttl - 2*TTL_DECREMENT - 
Crypto.nextLong(TTL_DECREMENT));
+
+               qp = policy.evaluateQuery(sender,qmsg.getPriority());
+               if ((qp & Policy2.QUERY_DROPMASK) == 0)
+                       return true; /* straight drop. */
+
+               preference =  (qp & Policy2.QUERY_PRIORITY_BITMASK);
+               if (preference < Policy2.QUERY_BANDWIDTH_VALUE)
+                       preference = Policy2.QUERY_BANDWIDTH_VALUE;
+               coreAPI.preferTrafficFrom(sender,preference);
+
+               /* adjust priority */
+               prio = qmsg.getPriority();
+               if ( (qp & Policy2.QUERY_PRIORITY_BITMASK) < prio) {
+                       prio = qp & Policy2.QUERY_PRIORITY_BITMASK;
+                       qmsg.setPriorityAndTTL(prio,qmsg.getTTL());
+               }
+
+               /* adjust TTL */
+               if ( (ttl > 0) &&
+                               (ttl > (prio+3)*TTL_DECREMENT) )
+                       ttl = (int) ((prio+3)*TTL_DECREMENT); /* bound! */
+               qmsg.setPriorityAndTTL(qmsg.getPriority(),ttl);
+
+               routing.execQuery(qp,qmsg, null);
+               return true;
+       }
+
+       /**
+        * @param sender
+        * @param msg
+        * @return
+        *
+        */
+
+       public boolean handleSBLOCK_CONTENT( HostIdentity sender, P2PMessage 
msg )
+       {
+               int                             prio;
+               P2PSBlockResult cmsg;
+               ContentIndex    ce=new ContentIndex();
+               boolean                 ret;
+               double                  preference;
+               boolean[]               dupe=new boolean[1];
+
+               if (msg.getByteSize() != P2PSBlockResult.SIZE) {
+                       log(Level.WARNING,"WARNING: signed content message 
received was malformed");
+                       return false;
+                       }
+               stat_p2p_sblock_replies.inc();
+               cmsg = (P2PSBlockResult) msg;
+
+               if (!cmsg.getResult().verify())
+                       return false;
+               new 
Pseudonym(prefs).addNamespace(cmsg.getResult().getNameSpace());
+
+               debug("DEBUG: received SBLOCK search result for 
"+cmsg.getResult().getIdentifier().toHex()+" from peer");
+
+               prio = 
routing.useContent(sender,cmsg.getResult().getIdentifier(),msg);
+               if (sender == null) { /* no migration, this is already content 
from the local node */
+                       debug("DEBUG: content migration not needed, content is 
local");
+                       return true;
+                       }
+
+               debug("DEBUG: content migration with preference "+prio);
+
+               preference = prio;
+               prio = 
policy.evaluateContent(cmsg.getResult().getIdentifier(),prio);
+               if (prio == -1) {
+                       debug("DEBUG: content not important enough, not 
replicated");
+                       return true; /* straight drop */
+                       }
+
+               debug("DEBUG: content replicated with total preference "+prio);
+
+               if (prio != -1)
+                       preference += prio;
+               if (preference < Policy2.CONTENT_BANDWIDTH_VALUE)
+                       preference = Policy2.CONTENT_BANDWIDTH_VALUE;
+               coreAPI.preferTrafficFrom(sender,preference);
+               ce.hash=(HashCode160) 
PersistentHelper.copy(cmsg.getResult().getIdentifier());  //todo: copie utile 
???
+               ce.importance    = prio;
+               ce.type          = ContentIndex.LOOKUP_TYPE_SBLOCK;
+               ce.fileNameIndex = 0;
+               ce.fileOffset    = 0;
+
+               ret = 
manager.insertContent(ce,ContentBlock.SIZE,cmsg.getResult(),sender,dupe);
+               if (ret && !dupe[0])
+                       singleBloomFilter.add(cmsg.getResult().getIdentifier());
+               return true;
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/IndexedFileNameCallback.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/IndexedFileNameCallback.java       
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/IndexedFileNameCallback.java       
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,23 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+/**
+ *
+ */
+
+public interface IndexedFileNameCallback
+{
+       /**
+        * Callback for each indexed file.
+        *
+        * @param fn the name of the file
+        * @param idx the index of the file
+        * @param data opaque context pointer for the callee
+        * @return false if the file should be removed from the list
+        */
+
+       public boolean onFile( String fn, int idx, Object data );
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/IndirectionTableEntry.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/IndirectionTableEntry.java 
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/IndirectionTableEntry.java 
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,177 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.util.*;
+
+/**
+ * Indirection table entry. Lists what we're looking for,
+ * where to forward it, and how long to keep looking for it.
+ */
+
+public class IndirectionTableEntry extends Object
+{
+       /** what are we waiting for ? */
+       public HashCode160      hash;
+
+       /** Are we limited to a specific namespace ? Non-null if yes. */
+       public HashCode160      namespace;
+
+       /** when can we forget about this entry ? */
+       public long                     ttl;
+
+       /** How much is this query worth to us, that is, how much would this 
node be willing to "pay" for an answer that matches the
+        hash stored in this ITE? (This is NOT the inbound priority, it is the 
trust-adjusted inbound priority <B>divided</B> by the
+        number of queries (for a multi-query)). */
+       public int                      priority;
+
+       /** which replies have we already seen ? hashcodes of the encrypted (!) 
replies that we have forwarded so far */
+       private List                    seen;
+
+       /** How many hosts are waiting for an answer to this query / who are 
these hosts ? */
+       private List                    waiting;
+
+               /** How many tcpsocks are in use ? / local TCP clients to send 
the reply to, null if none */
+       private List                    tcpsocks;
+
+       /** Do we currently have a response in the delay loop (delays are 
introduced to make traffic analysis harder
+        and thus enable anonymity) ? This marker is set to avoid looking up 
content again before the first content
+        exits the delay loop.  Since this *not* looking up content again is 
not externally visible, it is ok to do this
+        optimization to reduce disk accesses (see Mantis bug #407). */
+       public boolean          successful_local_lookup_in_delay_loop;
+
+       /** Avoiding concurrent lookups for the same ITE: semaphore grants 
access to peers to perform a lookup that matches this ITE entry. */
+       public Object           lookup_exclusion;
+
+
+       public IndirectionTableEntry()
+       {
+               super();
+               seen=new ArrayList();
+               waiting=new ArrayList();
+               tcpsocks=new ArrayList();
+               hash=new HashCode160();
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public boolean hasSeen()
+       {
+               return seen.size()>0;
+       }
+
+       public int getSeenCount()
+       {
+               return seen.size();
+       }
+
+       public HashCode160 getSeen( int index )
+       {
+               return ((index>=0 && index<seen.size()) ? (HashCode160) 
seen.get(index) : null);
+       }
+
+       public void addSeen( HashCode160 h )
+       {
+               seen.add(PersistentHelper.copy(h));     //todo: copie utile ???
+       }
+
+       public void clearSeen()
+       {
+               seen.clear();
+       }
+
+       public boolean hasWaitingHost( HostIdentity hi )
+       {
+               return waiting.contains(hi);
+       }
+
+       public boolean hasWaitingHosts()
+       {
+               return waiting.size()>0;
+       }
+
+       public int getWaitingHostsCount()
+       {
+               return waiting.size();
+       }
+
+       public HostIdentity getWaitingHost( int index )
+       {
+               return ((index>=0 && index<waiting.size()) ? (HostIdentity) 
waiting.get(index) : null);
+       }
+
+       public void addWaitingHost( HostIdentity hi )
+       {
+               waiting.add(PersistentHelper.copy(hi)); //todo: copie utile ???
+       }
+
+       public void removeWaitingHost( HostIdentity hi )
+       {
+               while (waiting.remove(hi)) {}
+       }
+
+       public void clearWaitingHosts()
+       {
+               waiting.clear();
+       }
+
+       public boolean hasClients()
+       {
+               return tcpsocks.size()>0;
+       }
+
+       public boolean containsClient( CSSession c )
+       {
+               int     i;
+
+               for (i=0; i<tcpsocks.size(); i++) {
+                       if (tcpsocks.get(i)==c) {
+                               return true;
+                               }
+                       }
+               return false;
+       }
+
+       public int getClientsCount()
+       {
+               return tcpsocks.size();
+       }
+
+       public CSSession getClient( int index )
+       {
+               return ((index>=0 && index<tcpsocks.size()) ? (CSSession) 
tcpsocks.get(index) : null);
+       }
+
+       public void addClient( CSSession c )
+       {
+               tcpsocks.add(c);
+       }
+
+       public void removeClient( CSSession c )
+       {
+               int     i;
+
+               for (i=0; i<tcpsocks.size(); i++) {
+                       if (tcpsocks.get(i)==c) {
+                               tcpsocks.remove(i);
+                               i--;
+                               }
+                       }
+       }
+
+       public void clearClients()
+       {
+               tcpsocks.clear();
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/IterState.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/IterState.java     2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/IterState.java     2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,28 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+/**
+ *
+ */
+
+public class IterState extends Object
+{
+       public boolean          hasNext;
+       public Semaphore                wsem;
+       public Semaphore                sem;
+       public HashCode160      next;
+       public ContentIndex     ce;
+       public int                      bucket;
+       public Object           data;
+       public int                      len;
+       public Task                     db_iterator;
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/LFS.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/LFS.java   2005-01-31 23:47:23 UTC 
(rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/LFS.java   2005-02-01 01:07:27 UTC 
(rev 137)
@@ -0,0 +1,325 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.logging.*;
+
+/**
+ * Support for special handling of very large (3HASH) reply sets.
+ *
+ * The databases (gdbm in particular, but also the others) do not
+ * handle very large entries very well.  This is no problem for CHK,
+ * but there can be several thousand (!)  results for a very popular
+ * keyword, like a mime-type.  These 3HASH codes with more than
+ * VERY_LARGE_SIZE (16) results are thus stored in separate files.
+ *
+ * The reason is, that gdbm would grow quadratic when the file is
+ * build and that it would also be very slow: every read or write to
+ * these very large content entries would require reading and writing
+ * the *entire* 2 MB block (2 MB for 2,000 entries).  This API allows
+ * a random access to one of the results and the use of "append" to
+ * add a single entry.  It also does not suffer from the quadratic
+ * explosion in space consumption that gdbm has.  So essentially, this
+ * is a crapload of code that does not add any real functionality but
+ * overcomes problems with the crude database implementations that we
+ * would have to use otherwise (and that would be really bad for
+ * performance without this).
+ *
+ * Support for special handling of very large (3HASH) reply sets.
+ *
+ * The databases (gdbm in particular, but also the others) do not
+ * handle very large entries very well.  This is no problem for CHK,
+ * but there can be several thousand (!)  results for a very popular
+ * keyword, like a mime-type.  These 3HASH codes with more than
+ * VERY_LARGE_SIZE (16) results are thus stored in separate files.
+ *
+ * The reason is, that gdbm would grow quadratic when the file is
+ * build and that it would also be very slow: every read or write to
+ * these very large content entries would require reading and writing
+ * the *entire* 2 MB block (2 MB for 2,000 entries).  This API allows
+ * a random access to one of the results and the use of "append" to
+ * add a single entry.  It also does not suffer from the quadratic
+ * explosion in space consumption that gdbm has.  So essentially, this
+ * is a crapload of code that does not add any real functionality but
+ * overcomes problems with the crude database implementations that we
+ * would have to use otherwise (and that would be really bad for
+ * performance without this).
+ */
+
+public class LFS extends LoggedObject
+{
+       public static final String      DIR_EXT =       ".lfs";
+
+       private DirLocation     dir;
+       private Object          lock;
+       private StatusCallsService      status;
+
+
+       public LFS()
+       {
+               super(true);
+       }
+
+       public String toString()
+       {
+               return "LFS";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Initialize the storage module.
+        * @param str the name of the directory/file
+        *        containing the content database
+        * @param sc
+        */
+
+       public void init( String str, StatusCallsService sc )
+       {
+               status=sc;
+
+               dir=new DirLocation(str+DIR_EXT);
+               if (!dir.create()) {
+                       log(Level.SEVERE,"Failed to open directory 
"+dir.getLabel()+" !");
+                       return;
+                       }
+
+               log(Level.INFO,"Database directory is located at 
\""+dir.getLabel()+"\".");
+
+               lock=new Object();
+       }
+
+       /**
+        * Remove the lfs database.
+        * Remove the lfs database.
+        */
+
+       public void delete()
+       {
+               if (!dir.delete()) {
+                       log(Level.SEVERE,"Could not remove 
\""+dir.getName()+"\" !");
+                       }
+               dir=null;
+               lock=null;
+       }
+
+       /**
+        * Clean shutdown of the storage module.
+        */
+
+       public void done()
+       {
+               dir=null;
+               lock=null;
+       }
+
+       /**
+        * Read the contents of a bucket to a buffer.
+        * @param query
+        *
+        * @return read blocks on success, null on failure
+        */
+
+       public ContentBlock[] read( HashCode160 query )
+       {
+               ContentBlock[]  blocks;
+               FileChannel             fd;
+               FileLocation                    fil;
+               int                             fsize,i;
+               ByteBuffer              buf;
+
+               fil=dir.getFile(query.toHex());
+               if (fil==null) {
+                       log(Level.WARNING,"File \""+query.toHex()+"\" does not 
exist !");
+                       return null;
+                       }
+
+               blocks=null;
+               synchronized(lock) {
+                       try {
+                               fd=new 
RandomAccessFile(fil.getPath(),"r").getChannel();
+                               try {
+                                       fsize=(int) fd.size();
+                                       if ((fsize % ContentBlock.SIZE)!=0) {
+                                               log(Level.WARNING,"LFS database 
corrupted (file \""+query.toHex()+"\" has bad length), trying to fix.");
+                                               fsize = (fsize / 
ContentBlock.SIZE) * ContentBlock.SIZE;
+                                               fd.truncate(fsize);
+                                               }
+
+                                       buf=ByteBuffer.allocateDirect(fsize);
+                                       if (fd.read(buf)!=fsize) {
+                                               return null;
+                                               }
+                                       buf.flip();
+
+                                       blocks= new 
ContentBlock[fsize/ContentBlock.SIZE];
+                                       for (i=0; i<blocks.length; i++) {
+                                               blocks[i]=new ContentBlock();
+                                               blocks[i].readBytes(buf,new 
ErrorReporter());
+                                               }
+                                       }
+                               finally {
+                                       fd.close();
+                                       }
+                               }
+                       catch( IOException x ) {
+                               err("Failed to read on \""+query.toHex()+"\" 
!",x);
+                               return null;
+                               }
+                       }
+               return blocks;
+       }
+
+       /**
+        * Read one random block from an entry
+        * Read the contents of a bucket to a buffer.
+        *
+        * @param query the hashcode representing the entry
+        * @param prio
+        * @return read blocks on success, null on failure
+        */
+
+       public ContentBlock[] randomRead( HashCode160 query, int prio )
+       {
+               ContentBlock[]  blocks;
+               int[]                   perm;
+               FileChannel             fd;
+               FileLocation                    fil;
+               int                             size,fsize,max,i;
+
+               max = (50-status.getNetworkLoadUp())*(prio+1);
+               if (max <= 0)
+                       max = 1;
+
+               fil=dir.getFile(query.toHex());
+               if (fil==null) {
+                       log(Level.WARNING,"File \""+query.toHex()+"\" does not 
exist !");
+                       return null;
+                       }
+
+               blocks=null;
+               synchronized(lock) {
+                       try {
+                               fd=new 
RandomAccessFile(fil.getPath(),"r").getChannel();
+                               try {
+                                       fsize=(int) fd.size();
+                                       if ((fsize % ContentBlock.SIZE)!=0) {
+                                               log(Level.WARNING,"LFS database 
corrupted (file \""+query.toHex()+"\" has bad length), trying to fix.");
+                                               fsize = (fsize / 
ContentBlock.SIZE) * ContentBlock.SIZE;
+                                               fd.truncate(fsize);
+                                               }
+
+                                       fsize = fsize / ContentBlock.SIZE;
+                                       if (fsize == 0) {
+                                               return null;
+                                               }
+                                       if (max > fsize) {
+                                               max = fsize;
+                                               }
+                                       log(Level.FINEST,"Received query, have 
"+fsize+" results, adding "+max+" to queue.");
+
+                                       blocks=new ContentBlock[max];
+
+                                       perm = Crypto.permute(fsize);
+                                       for (i=0; i<max; i++) {
+                                               blocks[i]=new ContentBlock();
+
+                                               
fd.position(perm[i]*ContentBlock.SIZE);
+
+                                               
size=fd.read(ByteBuffer.wrap(blocks[i].content));
+                                               if (size!=ContentBlock.SIZE) {
+                                                       return null;
+                                                       }
+                                               }
+                                       }
+                               finally {
+                                       fd.close();
+                                       }
+                               }
+                       catch( IOException x ) {
+                               err("Failed to read on \""+query.toHex()+"\" 
!",x);
+                               return null;
+                               }
+                       }
+               return blocks;
+       }
+
+       /**
+        * Append content to file.
+        *
+        * @param query the key for the entry
+        * @param data what to append/the data to store
+        * @return false on error, true if ok.
+        */
+
+       public boolean append( HashCode160 query, ContentBlock data )
+       {
+               FileChannel     fd;
+               FileLocation            fil;
+               int                     offset;
+
+               fil=dir.getFile(query.toHex());
+               fil.create();
+
+               synchronized(lock) {
+                       try {
+                               fd=new 
RandomAccessFile(fil.getPath(),"rw").getChannel();
+                               try {
+                                       fd.position(fd.size());
+                                       offset=(int) fd.position();
+                                       if ((offset % ContentBlock.SIZE)!=0) {
+                                               log(Level.WARNING,"LFS database 
corrupted (file \""+query.toHex()+"\" has bad length), trying to fix.");
+                                               
offset=(offset/ContentBlock.SIZE)*ContentBlock.SIZE;
+                                               fd.position(offset);
+                                               fd.truncate(offset);
+                                               }
+
+                                       fd.write(ByteBuffer.wrap(data.content));
+                                       }
+                               finally {
+                                       fd.close();
+                                       }
+                               }
+                       catch( IOException x ) {
+                               err("Failed to append on \""+query.toHex()+"\" 
!",x);
+                               return false;
+                               }
+                       }
+               return true;
+       }
+
+       /**
+        * Remove an entry.
+        * Free space in the database by removing one file
+        *
+        * @param query the key for the entry/the hashcode representing the 
entry
+        * @return false on error, true if ok.
+        */
+
+       public boolean remove( HashCode160 query )
+       {
+               FileLocation            f;
+
+               f=dir.getFile(query.toHex());
+               if (f==null) {
+                       log(Level.WARNING,"File \""+query.toHex()+"\" does not 
exist !");
+                       return false;
+                       }
+
+               synchronized(lock) {
+                       return f.delete();
+                       }
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/Manager.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/Manager.java       2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/Manager.java       2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,1015 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * This module is responsible to manage content, in particular it needs to 
decide what content to keep.
+ * This module is responsible for content management (what to
+ * keep, what to discard, content ageing, content migration).
+ *
+ * The manager.h header defines the external interface to the
+ * GNUnet databases.  The manager code is responsible for
+ * space management and on-demand encoding of blocks.  The
+ * high-level database abstraction defined in high_backend.h
+ * is responsible for lookup (3HASH and CHK) and block retrieval
+ * (ContentEntries and inserted blocks).
+ */
+
+public class Manager extends LoggedObject
+{
+       public static final String      VLS_DIR =       "large";
+       public static final String      AGEFILE =       "database.age";
+
+       public static final int         DB_DIRTY_AVAILABLE      =       
Integer.MIN_VALUE;
+
+
+       public static final boolean     TRACK_INDEXED_FILES     =       true;
+       public static final String      TRACKFILE                       =       
"indexed_requests.txt";
+
+
+       /** Entry length that indicates that the entry was too large for the 
usual DB and has been stored in a separate file instead. */
+       public static final int VERY_LARGE_FILE =       42;
+
+       /** How large is very large? (number of ContentEntries) Mysql seems to 
have some limit at 16k, so let's pick 15 to be on the good side for sure. */
+       public static final int VERY_LARGE_SIZE =       15;
+
+       /** The current base value for fresh content (used to time-out old 
content). */
+       private int                     MANAGER_age;
+
+       /** Is active migration allowed ? This is about us receiving data from 
the network,
+        actively pushing content out is always ok. */
+       private boolean         useActiveMigration;
+
+       /** Global database handle */
+//     private DatabaseAPI     dbAPI;
+       /** Handle of the database as returned by initContentDatabase() */
+       public DBHandle[]       dbHandles;
+
+       /** The number of buckets */
+       public int                      buckets;
+
+       /** cache estimated available blocks for each bucket */
+       public int[]            dbAvailableBlocks;
+
+       /** Large file handling. */
+       private LFS                     lfs;
+
+       /** Statistics handles */
+       private Stat    stat_handle_lookup_3hash;
+       private Stat    stat_handle_lookup_sblock;
+       private Stat    stat_handle_lookup_chk;
+       private Stat    stat_handle_lookup_ondemand;
+       private Stat    stat_handle_lookup_notfound;
+       private Stat    stat_handle_spaceleft;
+
+       private BloomFilter2    filter2;        //todo: VA PLANTER
+       private FileIndex               fileIndex;      //todo: VA PLANTER
+       private ContentEncoding encoding;       //todo: VA PLANTER
+
+       private Prefs           prefs;
+       private Statistics      stats;
+       private Scheduler               scheduler;
+       private ScheduledTask           reduceTask;
+
+
+       public Manager()
+       {
+               super(true);
+               lfs=new LFS();
+
+               reduceTask=new ScheduledTask("REDUCE-IMPORTANCE",new 
EvalAction(this,"cronReduceImportance"),Scheduler.HOURS_12);
+       }
+
+       public String toString()
+       {
+               return "Manager";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Initialize the manager module.
+        * @param capi
+        */
+
+       public void init( CoreForProtocol capi )
+       {
+               String  dtype,afsdir;
+               int             delta,i;
+
+               prefs=capi.getApplication().getPreferences();
+               stats=capi.getApplication().getStatistics();
+
+               dtype = prefs.getString("AFS","DATABASETYPE",null);
+               initializeDatabaseAPI(dtype);
+               stat_handle_lookup_sblock=stats.getHandle("# lookup (SBlock, 
search results)");
+               stat_handle_lookup_3hash=stats.getHandle("# lookup (3HASH, 
search results)");
+               stat_handle_lookup_chk=stats.getHandle("# lookup (CHK, inserted 
or migrated content)");
+               stat_handle_lookup_ondemand=stats.getHandle("# lookup 
(ONDEMAND, indexed content)");
+               stat_handle_lookup_notfound=stats.getHandle("# lookup (data not 
found)");
+               stat_handle_spaceleft=stats.getHandle("# blocks AFS storage 
left (estimate)");
+
+               MANAGER_age = readAge();
+
+               useActiveMigration= 
prefs.testString("AFS","ACTIVEMIGRATION","YES");
+
+               scheduler=capi.getApplication().getScheduler();
+               scheduler.addJob(reduceTask,Scheduler.HOURS_6);
+
+               delta = estimateGlobalAvailableBlocks();
+               if (delta < 0) {
+                       int[]   perm = Crypto.permute(buckets);
+                       /* we permute to delete content in random order since
+                        users may interrupt the process (in particular at
+                        the beginning) and we want to make sure that the
+                        chances are distributed reasonably at random) */
+                       for (i=0; i<buckets; i++) {
+                               
dbHandles[perm[i]].deleteContent(16-delta/buckets,new EntryCallback() {
+                                       public void onEntry( HashCode160 key, 
ContentIndex ce, Object data, int dataLen, Object closure )
+                                       {
+                                               
filter2.bf_deleteEntryCallback(key,ce,data,dataLen,closure);
+                                       }
+                                       },null);
+                               dbAvailableBlocks[perm[i]]=DB_DIRTY_AVAILABLE;
+                               }
+                       delta = (16-delta/buckets)*buckets;
+                       }
+               stat_handle_spaceleft.set(delta);
+
+               afsdir = prefs.getString("AFS","AFSDIR",null);
+               if (afsdir==null) {
+                       trace("Configuration file must specify directory for 
storing AFS data in section AFS under AFSDIR !");
+                       return;
+                       }
+
+               lfs.init(afsdir+"/"+VLS_DIR,(StatusCallsService) 
capi.service(StatusCallsService.class));
+       }
+
+       /**
+        * Shutdown the manager module.
+        */
+
+       public void done()
+       {
+               int i;
+
+               scheduler.deleteJob(reduceTask);
+
+               for (i=0;i<buckets;i++)
+                       dbHandles[i].close();
+               dbHandles=null;
+               dbAvailableBlocks=null;
+               lfs.done();
+       }
+
+       /**
+        * calculates the global available space using
+        * cached bucket availability estimates
+        * @return
+        */
+
+       protected int estimateGlobalAvailableBlocks()
+       {
+               int i;
+               int ret = 0;
+               int perBucketQuota = prefs.getInt("AFS","DISKQUOTA",0) * 1024 / 
buckets;
+
+               for (i = 0; i < buckets; ++i) {
+                       if (dbAvailableBlocks[i] == DB_DIRTY_AVAILABLE) {
+                               dbAvailableBlocks[i] = 
dbHandles[i].estimateAvailableBlocks(perBucketQuota);
+                               }
+                       ret += dbAvailableBlocks[i];
+                       }
+               return ret;
+       }
+
+       /**
+        * Load the high-level database as specified by
+        * the given dtype.
+        * @param dtype
+        */
+
+       public void initializeDatabaseAPI( String dtype )
+       {
+               DBHandle        dbh;
+               String          odtype;
+               int                     i;
+
+               if (dtype == null) {
+                       log(Level.SEVERE,"AFS/DATABASETYPE not specified in 
config");
+                       return;
+                       }
+
+               odtype=prefs.getContentAsString("AFS-DATABASETYPE");
+               if (odtype==null) {
+                       prefs.putContent("AFS-DATABASETYPE",dtype);
+                       }
+               else if (!odtype.equals(dtype)) {
+                       log(Level.SEVERE,"FATAL: AFS database type was changed, 
run gnunet-convert");
+                       return;
+                       }
+
+               buckets= 4 *prefs.getInt("AFS","DISKQUOTA",0) / 1024; // one 
bucket per 256 MB
+               if (buckets == 0)
+                       buckets = 1; // at least 1 bucket!
+               dbHandles= new DBHandle[buckets];
+               dbAvailableBlocks=new int[buckets];
+
+               for (i=0;i<buckets;i++) {
+                       dbh=(DBHandle) new 
DynamicLibrary("freeway-afs-"+dtype+".jar").load(DBHandle.class,getClass().getClassLoader());
+                       if (dbh==null) {
+                               log(Level.SEVERE,"Failed to initialize AFS 
database "+i+" !");
+                               return;
+                               }
+                       if 
(!dbh.open(prefs,String.valueOf(i),String.valueOf(prefs.getInt("AFS","DISKQUOTA",0))))
 {
+                               dbh.close();
+                               trace("Should not happen !");
+                               return;
+                               }
+                       dbHandles[i]=dbh;
+
+                       if (dbHandles[i] == null) {
+                               log(Level.SEVERE,"Failed to initialize AFS 
database "+i+" !");
+                               return;
+                               }
+                       dbAvailableBlocks[i]=DB_DIRTY_AVAILABLE; /* not yet 
initialized */
+                       }
+       }
+
+       /**
+        * Store content (if the priority is high enough), potentially
+        * discarding less important content. If this method is called
+        * for indexed content, * data should be null and len==0 and
+        * fields of ce filled properly. For 3HASH inserts, 2HASH must
+        * be provided in ce.hash.
+        *
+        * @param ce the content entry describing the content
+        * @param len the length of the data in bytes/the length of the data in 
bytes, either 0 for no data (e.g. on-demand encoding
+        *         of indexed content or CONTENT_Block.SIZE for normal data.
+        * @param data the block itself
+        * @param sender from where does the content come? null for
+        *        from local client./from where does the content come? null for
+        *        from local client.
+        * @param duplicate output param, will be true if content was already 
there
+        * @return true if the block was stored, false if not
+        */
+
+       public boolean insertContent( ContentIndex ce, int len, byte[] data, 
HostIdentity sender, boolean[] duplicate )
+       {
+               byte[]                  old;
+               ContentIndex    oldce;
+               HashCode160             query;
+               int                             avail,importance;
+
+               if (ce.fileNameIndex>0) {
+                       log(Level.FINEST,"Using fileNameIndex 
"+ce.fileNameIndex);
+                       }
+
+               if (len!=0 && len!=ContentBlock.SIZE) {
+                       trace("Unexpected length "+len+" for insertContent !");
+                       return false;
+                       }
+
+               duplicate[0] = false;
+               if (sender!=null && !useActiveMigration) {
+                       return false; // forbidden!
+                       }
+               importance = ce.importance;
+               if (sender!=null && Crypto.nextInt(2 + importance)==0) {
+                       return false; // don't bother...
+                       }
+
+               ce.importance= importance + MANAGER_age;
+               switch (ce.type) {
+                       case ContentIndex.LOOKUP_TYPE_3HASH:
+                               
query=HashCode160.create(PersistentHelper.toBytes(ce.hash));
+                               break;
+                       case ContentIndex.LOOKUP_TYPE_CHK:
+                       case ContentIndex.LOOKUP_TYPE_CHKS:
+                       case ContentIndex.LOOKUP_TYPE_SUPER:
+                       case ContentIndex.LOOKUP_TYPE_SBLOCK:
+                               query=(HashCode160) 
PersistentHelper.copy(ce.hash);
+                               break;
+                       default:
+                               log(Level.WARNING,"Unexpected content type : 
"+ce.type);
+                               return false;
+                       }
+
+               oldce=(ContentIndex) PersistentHelper.copy(ce);
+
+               avail = estimateGlobalAvailableBlocks();
+               if (avail <= 0) {
+                       if (importance + MANAGER_age <= 
computeHighDB(query).getMinimumPriority())
+                               return false; // new content has such a low 
priority that we should not even bother!
+                       computeHighDB(query).deleteContent(16-avail,new 
EntryCallback() {
+                                       public void onEntry( HashCode160 key, 
ContentIndex ce2, Object data2, int dataLen, Object closure )
+                                       {
+                                               
filter2.bf_deleteEntryCallback(key,ce2,data2,dataLen,closure);
+                                       }
+                                       },null);
+                       stat_handle_spaceleft.set(16-avail);
+                       
dbAvailableBlocks[computeBucketGlobal(query)]=DB_DIRTY_AVAILABLE;
+                       }
+               else {
+                       stat_handle_spaceleft.set(avail);
+                       }
+
+               // try to read existing
+               old = computeHighDB(query).readContent(query,oldce,0);
+
+               // add the content
+               switch (ce.type) {
+                       case ContentIndex.LOOKUP_TYPE_3HASH:
+                               if (len != ContentBlock.SIZE ) {
+                                       trace("Unexpected length "+len+" for 
insertContent !");
+                                       return false;
+                                       }
+                               return 
handle3HSBInsert(query,ce,data,(old!=null ? old.length : 
-1),duplicate,len,old,oldce.importance);
+                       case ContentIndex.LOOKUP_TYPE_SBLOCK:
+                               if (len != ContentBlock.SIZE) {
+                                       trace("Unexpected length "+len+" for 
insertContent !");
+                                       return false;
+                                       }
+                               return 
handle3HSBInsert(query,ce,data,(old!=null ? old.length : 
-1),duplicate,len,old,oldce.importance);
+                       case ContentIndex.LOOKUP_TYPE_CHK:
+                       case ContentIndex.LOOKUP_TYPE_CHKS:
+                       case ContentIndex.LOOKUP_TYPE_SUPER:
+                       {
+                               boolean replace = false;
+                               /*
+                                * This is a bit messy. The intended idea is 
that missing blocks
+                                * are always replaced. Indexed blocks are 
replaced only if the
+                                * new one is indexed AND has a higher priority 
than the old one.
+                                * Nonindexed, existing blocks are replaced if 
the size differs OR if new
+                                * is more important OR if new is an indexed 
block. This scheme
+                                * should never replace an indexed block with a 
nonindexed block.
+                                * We are not setting *duplicate=YES in the 
true replace case because
+                                * we don't want the bloomfilters to be 
unnecessarily incremented
+                                * outside insertContent().
+                                */
+                               duplicate[0] = true;
+                               if (old == null) {
+                                       replace = true;
+                                       duplicate[0] = false;
+                                       }
+                               else if (oldce.fileNameIndex > 0) {
+                                       if (ce.fileNameIndex>0 && 
ce.importance>oldce.importance) {
+                                               replace = true;
+                                               }
+                                       else {
+                                               replace = false;
+                                               }
+                                       }
+                               else {
+                                       if ((old!=null ? old.length : -1) != 
len || ce.importance>oldce.importance || ce.fileNameIndex>0) {
+                                               replace = true;
+                                               }
+                                       else {
+                                               replace = false;
+                                               }
+                                       }
+
+                               if (!replace) {
+                                       return true;
+                                       }
+
+                               dbAvailableBlocks[computeBucketGlobal(query)]= 
DB_DIRTY_AVAILABLE;
+                               return 
computeHighDB(query).writeContent(ce,data,0,len);
+                               }
+//                             break;
+                       default:
+                               log(Level.WARNING,"Unexpected content type : 
"+ce.type);
+                               return false;
+                       }
+//             log(Level.SEVERE,"ERROR: insertContent code ended up where it 
never should");
+//             return false;
+       }
+
+       public boolean insertContent( ContentIndex ce, int len, Persistent 
data, HostIdentity sender, boolean[] duplicate )
+       {
+               return 
insertContent(ce,len,PersistentHelper.toBytes(data),sender,duplicate);
+       }
+
+       /**
+        * Locate content. This method locates the data matching the
+        * query.  The data is on-demand encrypted if it is
+        * indexed content or retrieved from the contentdatabase
+        * if it was inserted content.  The ContentIndex entry is
+        * filled with the appropriate values.
+        * Locate content.  This method locates the data matching the content
+        * entry.  The data is on-demand encrypted if it is indexed content or
+        * retrieved from the contentdatabase if it was inserted content.
+        *
+        * @param query         the CHK or the tripleHash key of the conten/the 
query for the content (CHK or 3HASH)
+        * @param ce            the content entry describing what to look 
for/the meta-data for the content
+        * @param prio          the amount to modify the priority of the 
entry/by how much should the priority of the content be changed (if it is 
found)?
+        * @param isLocal       is the request a local request? (true/false)
+        * @return                      the resulting content, null on error
+        */
+
+       public ContentBlock[] retrieveContent( HashCode160 query, ContentIndex 
ce, int prio, boolean isLocal )
+       {
+               ContentBlock[]  result;
+               byte[]                  tmp;
+               int                             len,i;
+
+               tmp=computeHighDB(query).readContent(query,ce,prio);
+               if (tmp==null) {
+                       stat_handle_lookup_notfound.inc();
+                       return null;
+                       }
+
+               if (tmp.length==VERY_LARGE_FILE) {
+                       result=(isLocal ? lfs.read(query) : 
lfs.randomRead(query,prio));
+                       if (result==null) {
+                               return null;
+                               }
+                       }
+               else {
+                       if ((tmp.length % ContentBlock.SIZE)!=0) {
+                               log(Level.SEVERE,"ERROR: retrieved content but 
size is not multiple of 1k!");
+                               return null;
+                               }
+
+                       result=new ContentBlock[tmp.length/ContentBlock.SIZE];
+                       for (i=0; i<result.length; i++) {
+                               result[i]=(ContentBlock) 
PersistentHelper.readFully(ContentBlock.class,ByteBuffer.wrap(tmp,i*ContentBlock.SIZE,ContentBlock.SIZE));
+                               }
+                       }
+
+               if (ce.fileNameIndex == 0) {
+                       switch (ce.type) {
+                               case ContentIndex.LOOKUP_TYPE_CHK:
+                               case ContentIndex.LOOKUP_TYPE_CHKS:
+                                       stat_handle_lookup_chk.inc();
+                                       break;
+                               case ContentIndex.LOOKUP_TYPE_3HASH:
+                                       stat_handle_lookup_3hash.inc();
+                                       break;
+                               case ContentIndex.LOOKUP_TYPE_SBLOCK:
+                                       stat_handle_lookup_sblock.inc();
+                                       break;
+                               case ContentIndex.LOOKUP_TYPE_SUPER:
+                                       // only gnunet-check will be doing 
this, don't bother to keep up stats
+                                       break;
+                               default:
+                                       log(Level.SEVERE,"Manager got 
unexpected content type : "+ce.type);
+                                       break;
+                               }
+                       return result;
+                       }
+
+               log(Level.SEVERE,"Retrieved content but index says on-demand 
encoded !");
+
+
+               stat_handle_lookup_ondemand.inc();
+
+               result=new ContentBlock[1];
+
+               len=encodeOnDemand(ce,result);
+               return (len>=0 ? result : null);
+       }
+
+       /**
+        * Explicitly delete content.  This method is not currently used
+        * (the manager discards data internally if we run out of space)
+        * but it could be used by a "gnunet-remove" application in the
+        * near future.
+        * <p>
+        *
+        * Explicitly remove some content from the database.
+        * Note that if multiple keywords correspond to the query, all are
+        * removed. To selectively remove one keyword, use retrieveContent and
+        * then insertContent if there are multiple results.
+        *
+        * @param query the query that corresponds to the block to remove
+        * @param bucket where to delete, <0 == autocompute/where to delete (<0 
== autocompute)
+        *               >=0 is used by gnunet-check.
+        * @return
+        */
+
+       public boolean removeContent( HashCode160 query, int bucket )
+       {
+               byte[]                  data;
+               ContentIndex    ce;
+               DBHandle                db;
+               boolean                 ok;
+
+               if (bucket < 0)
+                       db = computeHighDB(query);
+               else
+                       db = dbHandles[bucket];
+
+               ce=new ContentIndex();
+               data = db.readContent(query,ce,0);
+               if (data==null) {
+                       log(Level.WARNING,"removeContent ("+query.toHex()+") 
failed, readContent did not find content !");
+                       return false; /* not found! */
+                       }
+               if (data.length == VERY_LARGE_FILE) {
+                       // need to remove from VLS index, too -- this is 
unusual, but we can do it (should currently never happen in practice)
+                       ok = lfs.remove(query);
+                       if (!ok)
+                               log(Level.WARNING,"WARNING: removeContent 
failed on LFS content?");
+                       }
+
+               ok = db.unlink(query);
+               if (ok) {
+                       int delta;
+
+                       dbAvailableBlocks[computeBucketGlobal(query)] = 
DB_DIRTY_AVAILABLE;
+                       delta = estimateGlobalAvailableBlocks();
+                       if (delta < 0)  /* should not happen */
+                               delta = 0;
+                       stat_handle_spaceleft.set(delta);
+                       }
+               return ok;
+       }
+
+       /**
+        * Get some random contet.
+        * Return a random key from the database.
+        * @param ce output information about the key
+        * @return false on error, true if ok.
+        */
+
+       public boolean retrieveRandomContent( ContentIndex ce )
+       {
+               int     bucket;
+
+               bucket=Crypto.nextInt(buckets);
+               if (dbHandles[bucket] == null) {
+                       log(Level.SEVERE,"dbHandle at bucket "+bucket+" is 
null");
+                       return false;
+                       }
+               return dbHandles[bucket].getRandomContent(ce);
+       }
+
+       /**
+        * Iterator over all the queries in the database
+        * as needed by resizeBloomfilter.
+        *
+        * The idea is to use this code in the startup
+        * of the AFS module when the quota/memory limitations
+        * have changed and the bloomfilter needs to be
+        * resized. Note that the iterator is quite costly,
+        * but we can assume that the user is not going to
+        * change the configuration all the time :-).
+        * Iterator over all the queries in the database as needed by
+        * resizeBloomfilter (and gnunet-check).  Typical use:
+        * <code>
+        * state = makeDatabaseIteratorState();
+        * while (databaseIterator(state, x, y, z, t))
+        *   ...do something...
+        * </code>
+        *
+        * @param sss the iterator state as created by
+        *        makeDatabaseIteratorState
+        * @param hc next hash code (set)
+        * @param ce next content index (set)
+        * @param bucket where the data actually was (set)
+        * @param data corresponding data (set)
+        * @param datalen length of data (set)
+        * @return true if the iterator has filled in another element
+        *  from the database, false if there are no more elements
+        */
+
+       public boolean databaseIterator( IterState sss, HashCode160 hc, 
ContentIndex ce, int[] bucket, byte[][] data, int[] datalen )
+       {
+               IterState       st = sss;
+
+               try {
+                       st.sem.acquire();
+                       if (!st.hasNext) {
+                               st.sem=null;
+                               st.wsem=null;
+                               st.db_iterator.join();
+                               return false;
+                               }
+                       hc=(HashCode160) PersistentHelper.copy(st.next);
+                       ce=(ContentIndex) PersistentHelper.copy(st.ce);
+                       bucket[0] = st.bucket;
+                       data[0] = (byte[]) st.data;
+                       datalen[0] = st.len;
+                       st.wsem.release();
+                       return true;
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       return false;
+                       }
+       }
+
+       /**
+        * Create the state required for a database iterator.
+        * Create the state required for a database iterator.  Calling this
+        * method requires to call databaseIterator with the state returned
+        * until "false" is returned.
+        * @return
+        */
+
+       public Object makeDatabaseIteratorState()
+       {
+               IterState  ret;
+
+               ret = new IterState();
+               ret.sem = new Semaphore(0);
+               ret.wsem = new Semaphore(1);
+
+               final IterState _ret = ret;
+
+               ret.db_iterator=new Task("DB-ITER",new AbstractAction() {
+                       public void perform()
+                       {
+                               iterator_helper(_ret);
+                       }
+                       });
+               ret.db_iterator.launch();
+               return ret;
+       }
+
+       /**
+        * Compute the database bucket id (for gnunet-check)
+        * This function is as crazy as it is since RIPE160 hashes do not seem
+        * to be quite random as we may want the to be...  So to get evenly
+        * distributed indices, we have to be a bit tricky. And no, there is
+        * high science but just a bit playing with the formula here.
+        * @param query
+        * @param maxBuckets
+        * @return
+        */
+
+       public int computeBucket( HashCode160 query, int maxBuckets )
+       {
+               HashCode160     qt;
+               long    r;
+
+               qt=HashCode160.create(PersistentHelper.toBytes(query));
+
+               r=((((query.getA()-qt.getA()) ^ (query.getB()-qt.getB()) ^ 
(query.getC()-qt.getC()) ^ (query.getD()-qt.getD()) ^ 
(query.getE()-qt.getE()))) >> 4);
+               r=(r & 0x00000000FFFFFFFFL);
+               return (int) (r % maxBuckets);
+       }
+
+       /**
+        * Use this, if initManager() has been executed and
+        * the global dbAPI has the correct bucket count
+        * @param query
+        * @return
+        */
+
+       public int computeBucketGlobal( HashCode160 query )
+       {
+               return computeBucket(query,
+                               buckets);
+       }
+
+       /**
+        * @param query
+        * @return
+        *
+        */
+
+       protected DBHandle computeHighDB( HashCode160 query )
+       {
+               return dbHandles[computeBucket(query,buckets)];
+       }
+
+       /**
+        * Open the AGE file and return the handle.
+        * @return
+        */
+
+       protected FileLocation getAgeFileHandle()
+       {
+               DirLocation             dir;
+               FileLocation            f;
+
+               dir=prefs.getDirLocation("AFS","AFSDIR");
+               if (dir==null) {
+                       log(Level.SEVERE,"Configuration file must specify 
directory for storage of AFS data in section AFS under AFSDIR.");
+                       return null;
+                       }
+               f=dir.getFile(AGEFILE);
+               f.create();
+               return f;
+       }
+
+       /**
+        * Cron-job that decreases the importance-level of all
+        * files by 1. Runs 'not very often'.
+        */
+
+       public void cronReduceImportance()
+       {
+               FileLocation    f;
+               MappedFile      m;
+
+               log(Level.INFO,"Enter cronReduceImportance");
+
+               MANAGER_age++;
+
+               f=getAgeFileHandle();
+               if (f==null) {
+                       log(Level.WARNING,"Could not open agefile !");
+                       return;
+                       }
+
+               m=f.openNew();
+               m.writeInt(MANAGER_age);
+               m.close();
+
+               log(Level.INFO,"Exit cronReduceImportance");
+       }
+
+       protected int readAge()
+       {
+               FileLocation    f;
+               MappedFile      m;
+               int                     age;
+
+               f=getAgeFileHandle();
+               if (f==null) {
+                       log(Level.WARNING,"Could not open agefile !");
+                       return 0;
+                       }
+
+               m=f.open();
+               age=m.asInt(0);
+               m.close();
+               return age;
+       }
+
+       /**
+        * Encode a block from a file on the drive, put the
+        * result in the result buffer (allocate) and return
+        * the size of the block.
+        * @param ce
+        * @param result
+        * @return
+        */
+
+       protected int encodeOnDemand( ContentIndex ce, ContentBlock[] result )
+       {
+               String fn;
+               int blen;
+               HashCode160 hc;
+               ContentBlock  iobuf;
+               FileChannel     fc;
+
+               // on-demand encoding mechanism
+               fn = fileIndex.getIndexedFileName(ce.fileNameIndex);
+               if (fn == null) {
+                       log(Level.SEVERE,"Database inconsistent! (index points 
to invalid offset ("+ce.fileNameIndex+")");
+                       return -1;
+                       }
+
+               iobuf = new ContentBlock();
+
+               try {
+                       fc=new RandomAccessFile(fn,"r").getChannel();
+
+                       if (TRACK_INDEXED_FILES) {
+                               PrintWriter     fp;
+                               FileLocation    scratch;
+                               DirLocation     afsDir;
+
+                               afsDir=prefs.getDirLocation("AFS","AFSDIR");
+                               if (afsDir!=null) {
+                                       scratch=afsDir.getFile(TRACKFILE);
+
+                                       fp=new PrintWriter(new 
FileOutputStream(scratch.getPath(),true),true);
+                                       fp.println(ce.fileNameIndex+" 
"+Scheduler.toSeconds(Scheduler.now()));
+                                       fp.close();
+                                       }
+                               else {
+                                       log(Level.SEVERE,"Configuration file 
must specify directory for storage of AFS data in section AFS under AFSDIR.");
+                                       }
+                               }
+
+                       try {
+                               fc.position(ce.fileOffset);
+                               if (fc.position()!=ce.fileOffset) {
+                                       log(Level.WARNING,"WARNING: unable to 
seek to "+ce.fileOffset+" in "+fn);
+                                       return -1;
+                                       }
+                               Arrays.fill(iobuf.content,(byte) 0);
+                               blen=fc.read(ByteBuffer.wrap(iobuf.content));
+                               if (blen <= 0) {
+                                       if(blen == 0)
+                                               log(Level.WARNING,"WARNING: 
read 0 bytes from "+fn);
+                                       else
+                                               log(Level.SEVERE,"ERROR: could 
not read file");
+                                       return -1;
+                                       }
+
+                               debug("Read "+blen+" bytes from "+fn+" for 
on-demand encoding at "+ce.fileOffset);
+                               }
+                       finally {
+                               fc.close();
+                               }
+                       }
+               catch( IOException x ) {
+                       err("I/O exception !",x);
+                       return -1;
+                       }
+
+               hc=HashCode160.create(PersistentHelper.toBytes(iobuf),0,blen);
+
+               result[0] = new ContentBlock();
+               if (!encoding.encryptContent(iobuf,hc,result[0])) {
+                       log(Level.SEVERE,"ERROR: encryption of content failed");
+                       return -1;
+                       }
+
+               hc=HashCode160.create(PersistentHelper.toBytes(result[0]));
+               debug("DEBUG: on-demand encoded content has query "+hc.toHex());
+               return ContentBlock.SIZE;
+       }
+
+       protected void iterator_helper_callback( HashCode160 key, ContentIndex 
ce, Object data, int dataLen, IterState sss )
+       {
+               try {
+                       sss.wsem.acquire();
+                       sss.next=(HashCode160) PersistentHelper.copy(key);
+                       sss.ce=(ContentIndex) PersistentHelper.copy(ce);
+                       sss.data = data;
+                       sss.len = dataLen;
+                       sss.sem.release();
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       }
+       }
+
+       /**
+        * Thread that fetches the next entry from the database.
+        * The thread is created by makeDatabaseIteratorState
+        * and exits once we're through the database.
+        * @param sss
+        */
+
+       protected void iterator_helper( IterState sss )
+       {
+               int i;
+
+               try {
+                       sss.hasNext = true;
+                       for (i=0;i<buckets;i++) {
+                               sss.wsem.acquire();
+                               sss.bucket = i;
+                               sss.wsem.release();
+                               dbHandles[i].forEachEntry(new EntryCallback() {
+                                       public void onEntry( HashCode160 key, 
ContentIndex ce, Object data, int dataLen, Object closure )
+                                       {
+                                               
iterator_helper_callback(key,ce,data,dataLen,(IterState) closure);
+                                       }
+                                       },sss);
+                               }
+                       sss.wsem.acquire();
+                       sss.hasNext = false;
+                       sss.sem.release();
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       }
+       }
+
+       protected boolean handleVLSResultSet( HashCode160 query, byte[] data, 
boolean[] duplicate )
+       {
+               ContentBlock[]  blocks;
+               int i,j;
+               int ret;
+
+               blocks=lfs.read(query);
+               if (blocks==null) {
+                       log(Level.WARNING,"lfs database inconsistent, trying to 
fix");
+                       if (computeHighDB(query).unlink(query)) {
+                               
dbAvailableBlocks[computeBucketGlobal(query)]=DB_DIRTY_AVAILABLE;
+                               }
+                       else {
+                               log(Level.WARNING,"Failed to fix lfs database 
inconsistency.");
+                               }
+                       return false;
+                       }
+
+               // check if the content is already present
+               ret=blocks.length;
+               for (i=0; i<ret; i++) {
+                       for (j=0; j<ContentBlock.SIZE && 
data[j]==blocks[i].content[j]; j++) {}
+
+                       if (j==ContentBlock.SIZE) {
+                               duplicate[0] = true;
+                               return true;
+                               }
+                       }
+               return lfs.append(query,(ContentBlock) 
PersistentHelper.readFully(ContentBlock.class,ByteBuffer.wrap(data)));
+       }
+
+       protected boolean migrateToVLS( byte[] old, int oldLen, HashCode160 
query, byte[] data, ContentIndex ce )
+       {
+               int             i;
+               boolean ret;
+               ContentBlock    block;
+
+               ret = true;
+
+               i = 0;
+               while ( (i < oldLen / ContentBlock.SIZE ) && ret) {
+                       block=(ContentBlock) 
PersistentHelper.readFully(ContentBlock.class,ByteBuffer.wrap(old,i*ContentBlock.SIZE,ContentBlock.SIZE));
+                       ret = lfs.append(query,block);
+                       i++;
+                       }
+
+               if (ret) {
+                       block=(ContentBlock) 
PersistentHelper.readFully(ContentBlock.class,ByteBuffer.wrap(data));
+                       ret = lfs.append(query,block);
+                       }
+
+               if (!ret) {
+                       lfs.remove(query);
+                       return ret;
+                       }
+               // put forwarding content (marked by size)
+               
ret=computeHighDB(query).writeContent(ce,data,0,VERY_LARGE_FILE); // data: 
random bits
+               
dbAvailableBlocks[computeBucketGlobal(query)]=DB_DIRTY_AVAILABLE;
+               return ret;
+       }
+
+       /**
+        * 3HASH and SBlock results require special treatment
+        * since multiple results are possible.
+        * @param query
+        * @param ce
+        * @param data
+        * @param oldLen
+        * @param duplicate
+        * @param len
+        * @param old
+        * @param oldImportance
+        * @return
+        */
+
+       protected boolean handle3HSBInsert( HashCode160 query, ContentIndex ce, 
byte[] data, int oldLen, boolean[] duplicate, int len, byte[] old, int 
oldImportance )
+       {
+               boolean ret;
+               byte[]  tmp;
+               int             n,i;
+
+               if (oldLen == -1) {
+                       // no old content, just write
+                       
dbAvailableBlocks[computeBucketGlobal(query)]=DB_DIRTY_AVAILABLE;
+                       return computeHighDB(query).writeContent(ce,data,0,len);
+                       }
+
+               // check if content is ALREADY in VLS store
+               if (oldLen == VERY_LARGE_FILE) {
+                       return handleVLSResultSet(query,data,duplicate);
+                       }
+
+               // Not VLS, check if the content is already present
+               for (n=0; n<oldLen/len; n++) {
+                       for (i=0; i<len && old[len*n+i]==data[i]; i++) {}
+                       if (i==len) {
+                               // content already there, abort
+                               duplicate[0] = true;
+                               return true;
+                               }
+                       }
+
+               // check if we need to *move* the content to VLS store
+               if (oldLen / ContentBlock.SIZE >= VERY_LARGE_SIZE) {
+                       return migrateToVLS(old, oldLen, query, data, ce);
+                       }
+
+               // else: default behavior: append
+
+               tmp = new byte[oldLen + len];
+               System.arraycopy(old,0,tmp,0,oldLen);
+               System.arraycopy(data,0,tmp,oldLen,len);
+               // Discussion: perhaps we should use eg max(a,b)? Otherwise n 
local inserts throws this through the ceiling...
+               // OTOH, if the same block was part of two files, it is really 
twice as important, so adding makes sense in some cases.
+               ce.importance = oldImportance + ce.importance;
+               ret = computeHighDB(query).writeContent(ce,tmp,0,oldLen+len);
+               
dbAvailableBlocks[computeBucketGlobal(query)]=DB_DIRTY_AVAILABLE;
+               return ret;
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/Migration.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/Migration.java     2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/Migration.java     2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,273 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+
+import java.nio.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * This module is responsible for pushing content out
+ * into the network.
+ */
+
+public class Migration extends LoggedObject
+{
+       /** use a 64-entry RCB buffer */
+       public static final int RCB_SIZE        =       128;
+
+       /** */
+       private CoreForProtocol coreAPI;
+
+       /** */
+       private StatusCallsService                      status;
+
+       /** */
+       private Stat            stat_handle_content_pushed;
+
+       /** Semaphore on which the RCB aquire thread waits if the RCB buffer is 
full. */
+       private Semaphore               aquireMoreSignal;
+
+       /** */
+       private Semaphore               doneSignal;
+
+       /** Lock for the RCB buffer. */
+       private Object                  lock;
+
+       /** Buffer with pre-fetched random content for migration. */
+       private ContentIndex[]  randomContentBuffer;
+
+       /** Highest index in RCB that is valid. */
+       private int                             rCBPos;
+
+       /** */
+       private Task                            gather_thread;
+
+       /** */
+       private Manager                 manager;
+
+
+       public Migration( Manager mgr )
+       {
+               super(true);
+               randomContentBuffer=new ContentIndex[RCB_SIZE];
+               manager=mgr;
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Initialize the migration module.
+        * @param capi
+        */
+
+       public void init( CoreForProtocol capi )
+       {
+               Statistics      stats;
+
+               coreAPI=capi;
+
+               stats=capi.getApplication().getStatistics();
+               status=(StatusCallsService) 
capi.service(StatusCallsService.class);
+               stat_handle_content_pushed=stats.getHandle("# kb content pushed 
out as padding",Stat.VERBOSE);
+
+               Arrays.fill(randomContentBuffer,null);
+
+               aquireMoreSignal = new Semaphore(RCB_SIZE);
+               doneSignal = null;
+               lock=new Object();
+
+               gather_thread=new Task("MIGRATION-GATHER",new AbstractAction() {
+                       public void perform()
+                       {
+                               rcbAquire();
+                       }
+                       });
+               gather_thread.launch();
+
+               coreAPI.registerSendCallback(P2PChkResult.SIZE,new 
BufferFillCallback() {
+                       public boolean fillBuffer( HostIdentity receiver, 
ByteBuffer buf )
+                       {
+                               return activeMigrationCallback(receiver,buf);
+                       }
+                       });
+       }
+
+       /**
+        *
+        */
+
+       public void done()
+       {
+               coreAPI.unregisterSendCallback(P2PChkResult.SIZE,new 
BufferFillCallback() {
+                       public boolean fillBuffer( HostIdentity receiver, 
ByteBuffer buf )
+                       {
+                               return activeMigrationCallback(receiver,buf);
+                       }
+                       });
+
+               try {
+                       doneSignal = new Semaphore(0);
+                       aquireMoreSignal.release();
+                       doneSignal.acquire();
+                       aquireMoreSignal=null;
+                       doneSignal=null;
+                       lock=null;
+                       gather_thread.join();
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       }
+       }
+
+       protected void rcbAquire()
+       {
+               ContentIndex    ce,cp;
+               boolean                 ok;
+
+               try {
+                       while (true) {
+                               aquireMoreSignal.acquire();
+                               if (doneSignal != null)
+                                       break;
+
+                               ce=new ContentIndex();
+                               ok = manager.retrieveRandomContent(ce);
+                               if (ok)
+                                       if 
(ce.type==ContentIndex.LOOKUP_TYPE_3HASH || 
ce.type==ContentIndex.LOOKUP_TYPE_SUPER)
+                                               ok = false;     // can not 
migrate these
+                               if (ok) {
+                                       cp=(ContentIndex) 
PersistentHelper.copy(ce);
+                                       synchronized(lock) {
+                                               randomContentBuffer[rCBPos++] = 
cp;
+                                               }
+                                       }
+                               else {
+                                       int load = status.getCPULoad();
+                                       if (load < 10)
+                                               load = 10;
+                                       
Scheduler.sleep(Scheduler.seconds(load/5));     // the higher the load, the 
longer the sleep, but at least 2 seconds
+                                       aquireMoreSignal.release();     // send 
myself signal to go again !
+                                       }
+                               }
+                       doneSignal.release();
+                       }
+               catch( InterruptedException x ) {
+                       err("",x);
+                       }
+       }
+
+       /**
+        * Select content for active migration.  Takes the best match from the
+        * randomContentBuffer (if the RCB is non-empty) and returns it.
+        * @param receiver
+        * @param ce
+        *
+        * @return false if the RCB is empty
+        */
+
+       protected boolean selectMigrationContent( HostIdentity receiver, 
ContentIndex ce )
+       {
+               int dist;
+               int minDist;
+               int minIdx;
+               int i;
+
+               minIdx = -1;
+               minDist = -1;   // max
+
+               synchronized(lock) {
+                       for (i=0;i<rCBPos;i++) {
+                               dist = 
receiver.distance(randomContentBuffer[i].hash);
+                               if (dist < minDist) {
+                                       minIdx = i;
+                                       minDist = dist;
+                                       }
+                               }
+                       if (minIdx == -1) {
+                               return false;
+                               }
+                       ce=(ContentIndex) 
PersistentHelper.copy(randomContentBuffer[minIdx]);
+                       randomContentBuffer[minIdx] = 
randomContentBuffer[--rCBPos];
+                       randomContentBuffer[rCBPos] = null;
+                       }
+               aquireMoreSignal.release();
+               return true;
+       }
+
+       /**
+        * Callback method for pushing content into the network.
+        * The method chooses either a "recently" deleted block
+        * or content that has a hash close to the receiver ID
+        * (randomized to guarantee diversity, unpredictability
+        * etc.).<p>
+        *
+        * @param receiver the receiver of the message
+        * @param buf
+        * @return the number of bytes written to
+        *   that buffer (must be a positive number).
+        */
+
+       protected boolean activeMigrationCallback( HostIdentity receiver, 
ByteBuffer buf )
+       {
+               ContentIndex    ce;
+
+               ce=new ContentIndex();
+               while (buf.remaining()>P2PChkResult.SIZE) {
+                       if (!selectMigrationContent(receiver,ce)) {
+                               return true;    // nothing selected, that's the 
end
+                               }
+
+                       // append it !
+                       if (!buildCHKReply(ce,buf)) {
+                               return false;   // abort early after any error
+                               }
+
+                       stat_handle_content_pushed.inc();
+                       }
+               return true;
+       }
+
+       /**
+        * Build a CHK reply message for some content
+        * selected for migration.
+        * @param ce
+        * @param buf
+        * @return OK on success, false on error
+        */
+
+       protected boolean buildCHKReply( ContentIndex ce, ByteBuffer buf )
+       {
+               ContentBlock[]  data;
+
+               if (ce.type==ContentIndex.LOOKUP_TYPE_3HASH || 
ce.type==ContentIndex.LOOKUP_TYPE_SUPER) {
+                       return false;
+                       }
+
+               data=manager.retrieveContent(ce.hash,ce,0,false);       // low 
prio! & should not matter for CHK anyway
+               if (data==null) {       // can happen if we're concurrently 
inserting, _should be_ rare but is OK !
+                       return false;
+                       }
+               if (data.length != ContentBlock.SIZE) {
+                       log(Level.WARNING,"BuildCHKReply got unsuitable block 
from db (len="+data.length+",type="+ce.type+")");
+                       return false;
+                       }
+               return PersistentHelper.write(data[0],buf);
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/MySQLHandle.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/MySQLHandle.java   2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/MySQLHandle.java   2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,1030 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+import java.sql.*;
+import java.util.logging.*;
+
+/**
+ * Handle for a high-level database (mysql, simple)
+ * mysql wrapper
+ *
+ * API for the "high-level" database libraries.
+ * Equivalent to what is specified in high_backend.h.
+ * A header specifying the interfaces that each (high-level) database backend 
(gdbm, tdb, mysql, etc.) must provide.
+ * Database: MySQL
+ *
+ * HIGHLIGHTS
+ *
+ * Pros
+ * + On up-to-date hardware where mysql can be used comfortably, this
+ *   module will have better performance than the other db choices
+ *   (according to our tests).
+ * + Its often possible to recover the mysql database from internal
+ *   inconsistencies. The other db choices do not support repair
+ *   (gnunet-check cannot fix problems internal to the dbmgr!).
+ *   For example, we have seen several cases where power failure
+ *   has ruined a gdbm database beyond repair.
+ * Cons
+ * - Memory usage (Comment: "I have 1G and it never caused me trouble")
+ * - Manual setup
+ *
+ * MANUAL SETUP INSTRUCTIONS
+ *
+ * 1) in /etc/gnunet.conf, set
+ *    <pre>
+ *
+ *    DATABASETYPE = "mysql"
+ *
+ *    </pre>
+ * 2) Then access mysql as root,
+ *    <pre>
+ *
+ *    # mysql -u root -p
+ *
+ *    </pre>
+ *    and do the following. [You should replace $USER with the username
+ *    that will be running the gnunetd process].
+ *    <pre>
+ *
+         CREATE DATABASE gnunet;
+         GRANT select,insert,update,delete,create,alter,drop
+                ON gnunet.* TO address@hidden;
+         SET PASSWORD FOR address@hidden('$the_password_you_like');
+         FLUSH PRIVILEGES;
+ *
+ *    </pre>
+ * 3) In the $HOME directory of $USER, create a ".my.cnf" file
+ *    with the following lines
+ *    <pre>
+
+         [client]
+         user=$USER
+         password=$the_password_you_like
+
+ *    </pre>
+ *
+ * Thats it. Note that .my.cnf file is a security risk unless its on
+ * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic
+ * link. Even greater security risk can be achieved by setting no
+ * password for $USER.  Luckily $USER has only priviledges to mess
+ * up GNUnet's tables, nothing else (unless you give him more,
+ * of course).<p>
+ *
+ * 4) Still, perhaps you should briefly try if the DB connection
+ *    works. First, login as $USER. Then use,
+ *
+ *    <pre>
+ *    # mysql -u $USER
+ *    mysql> use gnunet
+ *    </pre>
+ *
+ *    If you get the message &quot;Database changed&quot; it probably works.
+ *
+ *    [If you get &quot;ERROR 2002: Can't connect to local MySQL server
+ *     through socket '/tmp/mysql.sock' (2)&quot; it may be resolvable by
+ *     &quot;ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock&quot;
+ *     so there may be some additional trouble depending on your mysql setup.]
+ *
+ * REPAIRING TABLES
+ *
+ * - Its probably healthy to check your tables for inconsistencies
+ *   every now and then.
+ * - If you get odd SEGVs on gnunetd startup, it might be that the mysql
+ *   databases have been corrupted.
+ * - The tables can be verified/fixed in two ways;
+ *   1) by shutting down mysqld (mandatory!) and running
+ *   # myisamchk -r *.MYI
+ *   in /var/lib/mysql/gnunet/ (or wherever the tables are stored).
+ *   Another repair command is "mysqlcheck". The usable command
+ *   may depend on your mysql build/version. Or,
+ *   2) by executing
+ *   mysql> REPAIR TABLE data1024of
+ *   for each table in the gnunet database (USE gnunet; SHOW TABLES;)
+ *
+ * If you have problems related to the mysql module, your best
+ * friend is probably the mysql manual. The first thing to check
+ * is that mysql is basically operational, that you can connect
+ * to it, create tables, issue queries etc.
+ *
+ * Database: MySQL
+ *
+ * NOTE: This db module does NOT work with mysql v3.23.49 due to a bug
+ * in mysql.  All later versions should be fine, including the 4.0.x
+ * series. Current devel version is 4.0.16-log on debian/unstable.
+ *
+ * HIGHLIGHTS
+ *
+ * Pros
+ * + On up-to-date hardware where mysql can be used comfortably, this
+ *   module will have better performance than the other db choices
+ *   (according to our tests).
+ * + Its often possible to recover the mysql database from internal
+ *   inconsistencies. The other db choices do not support repair
+ *   (gnunet-check cannot fix problems internal to the dbmgr!).
+ *   For example, we have seen several cases where power failure
+ *   has ruined a gdbm database beyond repair.
+ * Cons
+ * - Memory usage (Comment: "I have 1G and it never caused me trouble")
+ * - Manual setup
+ *
+ * MANUAL SETUP INSTRUCTIONS
+ *
+ * 1) in /etc/gnunet.conf, set
+ *    <pre>
+ *
+ *    DATABASETYPE = "mysql"
+ *
+ *    </pre>
+ * 2) Then access mysql as root,
+ *    <pre>
+ *
+ *    # mysql -u root -p
+ *
+ *    </pre>
+ *    and do the following. [You should replace $USER with the username
+ *    that will be running the gnunetd process].
+ *    <pre>
+ *
+ CREATE DATABASE gnunet;
+ GRANT select,insert,update,delete,create,alter,drop
+ ON gnunet.* TO address@hidden;
+ SET PASSWORD FOR address@hidden('$the_password_you_like');
+ FLUSH PRIVILEGES;
+ *
+ *    </pre>
+ * 3) In the $HOME directory of $USER, create a ".my.cnf" file
+ *    with the following lines
+ *    <pre>
+
+ [client]
+ user=$USER
+ password=$the_password_you_like
+
+ *    </pre>
+ *
+ * Thats it. Note that .my.cnf file is a security risk unless its on
+ * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic
+ * link. Even greater security risk can be achieved by setting no
+ * password for $USER.  Luckily $USER has only priviledges to mess
+ * up GNUnet's tables, nothing else (unless you give him more,
+ * of course).<p>
+ *
+ * 4) Still, perhaps you should briefly try if the DB connection
+ *    works. First, login as $USER. Then use,
+ *
+ *    <pre>
+ *    # mysql -u $USER
+ *    mysql> use gnunet
+ *    </pre>
+ *
+ *    If you get the message &quot;Database changed&quot; it probably works.
+ *
+ *    [If you get &quot;ERROR 2002: Can't connect to local MySQL server
+ *     through socket '/tmp/mysql.sock' (2)&quot; it may be resolvable by
+ *     &quot;ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock&quot;
+ *     so there may be some additional trouble depending on your mysql setup.]
+ *
+ * REPAIRING TABLES
+ *
+ * - Its probably healthy to check your tables for inconsistencies
+ *   every now and then.
+ * - If you get odd SEGVs on gnunetd startup, it might be that the mysql
+ *   databases have been corrupted.
+ * - The tables can be verified/fixed in two ways;
+ *   1) by shutting down mysqld (mandatory!) and running
+ *   # myisamchk -r *.MYI
+ *   in /var/lib/mysql/gnunet/ (or wherever the tables are stored).
+ *   Another repair command is "mysqlcheck". The usable command
+ *   may depend on your mysql build/version. Or,
+ *   2) by executing
+ *   mysql> REPAIR TABLE data1024of
+ *   for each table in the gnunet database (USE gnunet; SHOW TABLES;)
+ *
+ * EFFICIENCY ISSUES
+ *
+ * If you suffer from too slow index/insert speeds,
+ * you might try to define /etc/gnunet.conf option
+ *
+ *   [AFS]
+ *   MYSQL_DELAYED = YES
+ *
+ * for small efficiency boost. The option will let MySQL bundle multiple
+ * inserts before actually writing them to disk. You shouldn't use this
+ * option unless you're an (my)sql expert and really know what you're doing.
+ * Especially, if you run into any trouble due to this, you're on your own.
+ *
+ * PROBLEMS?
+ *
+ * If you have problems related to the mysql module, your best
+ * friend is probably the mysql manual. The first thing to check
+ * is that mysql is basically operational, that you can connect
+ * to it, create tables, issue queries etc.
+ */
+
+public class MySQLHandle extends LoggedObject implements DBHandle
+{
+       private static long                     ramdomSpentTime;
+       private static int                              randomCalls;
+
+       /** */
+       private Connection      dbf;
+
+       private String  tableName;
+       /** database index */
+//     private int;
+
+       /** total number of databases */
+//     private int;
+
+       /** */
+       private Object          DATABASE_Lock_;
+
+       /** which column contains the Avg_row_length in SHOW TABLE STATUS 
resultset */
+       private int                     avgLength_ID;
+
+       /** use potentially unsafe delayed inserts? */
+       private boolean         useDelayed;
+
+
+       /**
+        * Popularity of _known_ 3hash keywords can be tracked by creating
+        * the following table and enabling TRACK_3HASH_QUERIES. In addition,
+        * you'll have to fill the table with <name,hash> pairs yourself
+        * (not provided). Tracking is not generally recommended as
+        * it may harm your deniability.
+        *
+        USE gnunet;
+        CREATE TABLE `dictionary` (
+        `name` tinyblob NOT NULL,
+        `hash` varchar(40) binary NOT NULL default '',
+        `hits` smallint(5) unsigned NOT NULL default '0',
+        PRIMARY KEY  (`hash`),
+        UNIQUE KEY `unique_name` (`name`(32))
+        ) TYPE=MyISAM
+        *
+        */
+
+       public static final boolean TRACK_3HASH_QUERIES =       false;
+
+
+       public MySQLHandle()
+       {
+               super(true);
+               avgLength_ID=-1;
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public boolean open( Prefs prefs, String backend, String name )
+       {
+               Connection                      conn;
+               Statement                       stmt;
+               ResultSet                       rset;
+               ResultSetMetaData       meta;
+               StringBuffer            sql;
+               boolean                         found;
+               int     i;
+
+               tableName="data"+name+"of"+backend;
+
+               try {
+                       
Class.forName(prefs.getString("AFS","MYSQL_DRIVER",null));
+                       conn=DriverManager.getConnection(
+                               
"jdbc:mysql://"+prefs.getString("AFS","MYSQL_HOST",null)+"/gnunet",
+                               prefs.getString("AFS","MYSQL_USER",null),
+                               prefs.getString("AFS","MYSQL_PASSWORD",null)
+                               );
+                       conn.setAutoCommit(false);
+                       }
+               catch( SQLException x ) {
+                       err("Unable to init MySQL !",x);
+                       return false;
+                       }
+               catch( ClassNotFoundException x ) {
+                       err("Unable to init MySQL !",x);
+                       return false;
+                       }
+
+               dbf=conn;
+
+               useDelayed=prefs.testString("AFS","MYSQL_DELAYED","YES");
+               DATABASE_Lock_=new Object();
+
+               found=false;
+               try {
+                       stmt=dbf.createStatement();
+                       try {
+                               sql=new StringBuffer();
+                               sql.append("CREATE TABLE IF NOT EXISTS 
"+tableName+" (");
+                               sql.append("  hash tinyblob NOT NULL 
default'',");
+                               sql.append("  priority int(11) NOT NULL default 
0,");
+                               sql.append("  type tinyint NOT NULL default 
0,");
+                               sql.append("  fileIndex smallint NOT NULL 
default 0,");
+                               sql.append("  fileOffset int(11) NOT NULL 
default 0,");
+                               sql.append("  doubleHash tinyblob NOT NULL 
default '',");
+                               sql.append("  content mediumblob NOT NULL 
default '',");
+                               sql.append("  PRIMARY KEY (hash(20)),");
+                               sql.append("  KEY priority (priority)");
+                               sql.append(") TYPE=MyISAM");
+                               stmt.executeUpdate(sql.toString());
+
+                               // find out which column contains the avg row 
length field and assume
+                               // that mysqld always gives it in the same 
order across calls :)
+                               sql.setLength(0);
+                               sql.append("SHOW TABLE STATUS ");
+                               sql.append("FROM gnunet ");
+                               sql.append("LIKE '"+tableName+"'");
+
+                               rset=stmt.executeQuery(sql.toString());
+                               if (rset.next()) {
+                                       meta=rset.getMetaData();
+
+                                       for (i=0; i<meta.getColumnCount() && 
!found; i++) {
+                                               if 
(meta.getColumnName(i+1).equals("Avg_row_length")) {
+                                                       avgLength_ID=i;
+                                                       found=true;
+                                                       }
+                                               }
+                                       if (!found) {
+                                               log(Level.SEVERE,"ERROR: mysql 
Avg_row_length not found in SHOW TABLE STATUS");
+                                               return false;
+                                               }
+                                       }
+                               rset.close();
+
+                               if (avgLength_ID == -1) {
+                                       log(Level.SEVERE,"FATAL: could not find 
row avg_row_length");
+                                       return false;
+                                       }
+                               }
+                       finally {
+                               stmt.close();
+                               }
+                       }
+               catch( SQLException x ) {
+                       err("Failed to init !",x);
+                       return false;
+                       }
+               return true;
+       }
+
+       public void close()
+       {
+               DATABASE_Lock_=null;
+               try {
+                       dbf.close();
+                       dbf=null;
+                       }
+               catch( SQLException x ) {
+                       err("Failed to close connection !",x);
+                       }
+       }
+
+       public void drop()
+       {
+               Statement               stmt;
+               StringBuffer    sql;
+
+               try {
+                       sql=new StringBuffer();
+                       sql.append("DROP TABLE "+tableName);
+
+                       stmt=dbf.createStatement();
+                       try {
+                               stmt.executeUpdate(sql.toString());
+                               }
+                       finally {
+                               stmt.close();
+                               }
+                       }
+               catch( SQLException x ) {
+                       err("Failed to close connection !",x);
+                       }
+
+               close();
+       }
+
+       public byte[] readContent( HashCode160 query, ContentIndex ce, int prio 
)
+       {
+               byte[]                  tmp,result;
+               ResultSet               rset;
+               Statement               stmt;
+               StringBuffer    sql;
+               int                             _prio=-1;
+
+               result=null;
+               synchronized(DATABASE_Lock_) {
+                       sql=new StringBuffer();
+                       sql.append("SELECT content, type, priority, doubleHash, 
fileOffset, fileIndex ");
+                       sql.append("FROM "+tableName+" ");
+                       sql.append("WHERE hash='"+escape(query)+"'");
+
+                       try {
+                               
stmt=dbf.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_UPDATABLE);
+                               try {
+                                       rset=stmt.executeQuery(sql.toString());
+
+                                       if (rset.next()) {
+                                               result=rset.getBytes(1);
+
+                                               ce.type = rset.getInt(2);
+                                               ce.importance = rset.getInt(3);
+                                               if 
(ce.type==ContentIndex.LOOKUP_TYPE_3HASH) {
+                                                       tmp=rset.getBytes(4);
+                                                       if (tmp!=null && 
tmp.length==HashCode160.SIZE) {
+                                                               
ce.hash=(HashCode160) 
PersistentHelper.readFully(HashCode160.class,ByteBuffer.wrap(tmp));
+                                                               }
+                                                       }
+                                               else {
+                                                       ce.hash=(HashCode160) 
PersistentHelper.copy(query);
+                                                       }
+                                               ce.fileOffset=rset.getInt(5);
+                                               ce.fileNameIndex=rset.getInt(6);
+
+                                               if (prio != 0) {
+                                                       //todo: debugguer le 
UPDATE qui devrait se faire ICI
+//                                                     
rset.updateInt(3,rset.getInt(3)+prio);
+//                                                     rset.updateRow();
+
+                                                       
_prio=rset.getInt(3)+prio;
+                                                       }
+                                               }
+
+                                       rset.close();
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+
+                               if (TRACK_3HASH_QUERIES) {
+                                       if 
(ce.type==ContentIndex.LOOKUP_TYPE_3HASH) {
+                                               stmt=dbf.createStatement();
+                                               try {
+                                                       
stmt.executeUpdate("UPDATE dictionary SET hits=hits+1 WHERE 
hash='"+escape(query)+"'");
+                                                       }
+                                               finally {
+                                                       stmt.close();
+                                                       }
+                                               }
+                                       }
+
+                               //tempo (a supprimer apres debug)
+                               if (_prio!=0) {
+                                       sql=new StringBuffer();
+                                       sql.append("UPDATE "+tableName+" ");
+                                       sql.append("SET priority="+_prio+" ");
+                                       sql.append("WHERE 
hash='"+escape(query)+"'");
+
+                                       stmt=dbf.createStatement();
+                                       try {
+                                               
stmt.executeUpdate(sql.toString());
+                                               }
+                                       finally {
+                                               stmt.close();
+                                               }
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to read content !",x);
+                               result=null;
+                               }
+                       }
+               return result;
+       }
+
+       public boolean writeContent( ContentIndex ce, byte[] block, int offset, 
int length )
+       {
+               Statement               stmt;
+               HashCode160             tripleHash;
+               StringBuffer    sql;
+               String                  doubleHash,escapedBlock,escapedHash;
+
+               synchronized(DATABASE_Lock_) {
+                       if (ce.type== ContentIndex.LOOKUP_TYPE_3HASH) {
+                               
tripleHash=HashCode160.create(PersistentHelper.toBytes(ce.hash));
+                               escapedHash=escape(tripleHash);
+                               doubleHash = escape(ce.hash);
+                               }
+                       else {
+                               doubleHash = null;
+                               escapedHash=escape(ce.hash);
+                               }
+
+                       escapedBlock=escape(block,offset,length);
+
+                       sql=new StringBuffer();
+                       sql.append("REPLACE "+(useDelayed ? "DELAYED" : "")+" 
INTO "+tableName+" ");
+                       
sql.append("(content,hash,priority,fileOffset,fileIndex,doubleHash,type)");
+                       sql.append(" VALUES (");
+                       sql.append("'"+(length > 0 ? escapedBlock : "")+"',");
+                       sql.append("'"+escapedHash+"',");
+                       sql.append("'"+ce.importance+"',");
+                       sql.append("'"+ce.fileOffset+"',");
+                       sql.append("'"+ce.fileNameIndex+"',");
+                       sql.append("'"+(doubleHash!=null ? doubleHash : 
"")+"',");
+                       sql.append(ce.type);
+                       sql.append(")");
+
+                       try {
+                               stmt=dbf.createStatement();
+                               try {
+                                       stmt.executeUpdate(sql.toString());
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to write content !",x);
+
+                               //todo: a supprimer apres debug
+                               
log(Level.SEVERE,Utils.toString(block,offset,offset+length,"SEQ."));
+                               return false;
+                               }
+                       }
+               return true;
+       }
+
+       /**
+        * Get the number of entries in the database.
+        * Get the number of entries in the database.
+        *
+        * @return -1 on error, otherwise the number of entries
+        */
+
+       public int countContentEntries()
+       {
+               Statement               stmt;
+               ResultSet               rset;
+               StringBuffer    sql;
+               int                             count;
+
+               count=0;
+               synchronized(DATABASE_Lock_) {
+                       sql=new StringBuffer();
+                       sql.append("SELECT count(*) ");
+                       sql.append("FROM "+tableName);
+
+                       try {
+                               stmt=dbf.createStatement();
+                               try {
+                                       rset=stmt.executeQuery(sql.toString());
+                                       if (rset.next()) {
+                                               count=rset.getInt(1);
+                                               }
+                                       rset.close();
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to get minimum priority !",x);
+                               count=-1;
+                               }
+                       }
+               return count;
+       }
+
+       /**
+        * Get the lowest priority of content in the DB.
+        * Get the lowest priority of content in the store.
+        * Get the lowest priority value of all content in the store.
+        *
+        * @return the lowest priority
+        */
+
+       public int getMinimumPriority()
+       {
+               Statement               stmt;
+               ResultSet               rset;
+               StringBuffer    sql;
+               int                             minPrio;
+
+               minPrio=0;
+               synchronized(DATABASE_Lock_) {
+                       sql=new StringBuffer();
+                       sql.append("SELECT MIN(priority) ");
+                       sql.append("FROM "+tableName);
+
+                       try {
+                               stmt=dbf.createStatement();
+                               try {
+                                       rset=stmt.executeQuery(sql.toString());
+                                       if (rset.next()) {
+                                               minPrio=rset.getInt(1);
+                                               }
+                                       rset.close();
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to get minimum priority !",x);
+                               }
+                       }
+               return minPrio;
+       }
+
+       /**
+        * Call a method for each key in the database and
+        * call the callback method on it.
+        * Call a method for each key in the database and
+        * call the callback method on it.
+        *
+        * @param callback the callback method
+        * @param data second argument to all callback calls
+        * @return the number of items stored in the content database
+        */
+
+       public int forEachEntry( EntryCallback callback, Object data )
+       {
+               byte[]                  result,tmp;
+               Statement               stmt;
+               ResultSet               rset;
+               ContentIndex    ce;
+               HashCode160             h;
+               StringBuffer    sql;
+               int                             count;
+
+               count=0;
+               synchronized(DATABASE_Lock_) {
+                       sql=new StringBuffer();
+                       sql.append("SELECT content, type, priority, doubleHash, 
fileOffset, fileIndex, hash ");
+                       sql.append("FROM "+tableName);
+
+                       try {
+                               stmt=dbf.createStatement();
+                               try {
+                                       rset=stmt.executeQuery(sql.toString());
+                                       while (rset.next()) {
+                                               ce=new ContentIndex();
+
+                                               result=rset.getBytes(1);
+                                               ce.type=rset.getInt(2);
+                                               ce.importance=rset.getInt(3);
+                                               if 
(ce.type==ContentIndex.LOOKUP_TYPE_3HASH) {
+                                                       tmp=rset.getBytes(4);
+                                                       if (tmp!=null && 
tmp.length==HashCode160.SIZE) {
+                                                               
ce.hash=(HashCode160) 
PersistentHelper.readFully(HashCode160.class,ByteBuffer.wrap(tmp));
+                                                               }
+                                                       }
+                                               else {
+                                                       tmp=rset.getBytes(7);
+                                                       ce.hash=(HashCode160) 
PersistentHelper.readFully(HashCode160.class,ByteBuffer.wrap(tmp));
+                                                       }
+                                               ce.fileOffset=rset.getInt(5);
+                                               ce.fileNameIndex=rset.getInt(6);
+
+                                               tmp=rset.getBytes(7);
+                                               h=(HashCode160) 
PersistentHelper.readFully(HashCode160.class,ByteBuffer.wrap(tmp));
+
+                                               
callback.onEntry(h,ce,result,(result!=null ? result.length : 0),data);
+                                               count++;
+                                               }
+                                       rset.close();
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to iterate over entries !",x);
+                               count=-1;
+                               }
+                       }
+               return count;
+       }
+
+       /**
+        * Return a random key from the database (just the key, not the
+        * content!).
+        * Get a random content block from MySQL database.
+        * Tries to use indexes efficiently.
+        *
+        * Code supplied by H. Pagenhardt
+        *
+        * @param ce the meta-data of the random content (set)/output 
information about the key
+        * @return true on success, false on error
+        */
+
+       public boolean getRandomContent( ContentIndex ce )
+       {
+               byte[]                  tmp;
+               Statement               stmt;
+               ResultSet               rset;
+               HashCode160             hash;
+               StringBuffer    sql;
+               long                    startTime,endTime;
+               boolean                 found;
+
+               startTime=Scheduler.now();
+
+               synchronized(DATABASE_Lock_) {
+                       found=false;
+
+                       hash=HashCode160.random();
+
+                       sql=new StringBuffer();
+                       sql.append("SELECT hash, type, priority, fileOffset, 
fileIndex ");
+                       sql.append("FROM "+tableName+" ");
+                       sql.append("WHERE hash >= '"+escape(hash)+"' ");
+                       sql.append("AND (type = 
"+ContentIndex.LOOKUP_TYPE_CHK+" OR type = "+ContentIndex.LOOKUP_TYPE_CHKS+") 
");
+                       sql.append("LIMIT 1");
+
+                       try {
+                               stmt=dbf.createStatement();
+                               try {
+                                       rset=stmt.executeQuery(sql.toString());
+
+                                       found=rset.next();
+                                       if (!found) {
+                                               rset.close();
+
+                                               sql.setLength(0);
+                                               sql.append("SELECT 
hash,type,priority,fileOffset,fileIndex ");
+                                               sql.append("FROM "+tableName+" 
");
+                                               sql.append("WHERE hash >= '' ");
+                                               sql.append("AND (type = 
"+ContentIndex.LOOKUP_TYPE_CHK+" OR type = "+ContentIndex.LOOKUP_TYPE_CHKS+") 
");
+                                               sql.append("LIMIT 1");
+
+                                               
rset=stmt.executeQuery(sql.toString());
+                                               found=rset.next();
+                                               }
+
+                                       if (found) {
+                                               tmp=rset.getBytes(1);
+                                               ce.hash=(HashCode160) 
PersistentHelper.readFully(HashCode160.class,ByteBuffer.wrap(tmp));
+                                               ce.type=rset.getInt(2);
+                                               ce.importance=rset.getInt(3);
+                                               ce.fileOffset=rset.getInt(4);
+                                               ce.fileNameIndex=rset.getInt(5);
+                                               }
+
+                                       rset.close();
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to get random content !",x);
+                               found=false;
+                               }
+                       }
+
+               endTime=Scheduler.now();
+               randomCalls++;
+               ramdomSpentTime+=(endTime-startTime);
+               debug("getRandomContent spent total 
"+Scheduler.toMillis(ramdomSpentTime)+"ms / "+randomCalls+" calls.");
+
+               if (!found) {
+                       log(Level.FINEST,"MySQL random didn't find anything !");
+                       }
+               return found;
+       }
+
+       /**
+        * Delete low-priority content from the database
+        * Deletes some least important content
+        *
+        * @param count the number of entries to delete/the number of 1kb 
blocks to free
+        * @param callback method to call on each deleted entry/method to call 
on each deleted item
+        * @param closure extra argument to callback
+        * @return true on success, false on error
+        */
+
+       public boolean deleteContent( int count, EntryCallback callback, Object 
closure )
+       {
+               HashCode160[]   deleteThese;
+               byte[]                  data,tmp;
+               ContentIndex    ce;
+               Statement               stmt;
+               ResultSet               rset;
+               StringBuffer    sql;
+               int                             k;
+
+               synchronized(DATABASE_Lock_) {
+                       try {
+                               stmt=dbf.createStatement();
+                               try {
+                                       // collect hashes to delete
+                                       sql=new StringBuffer();
+                                       sql.append("SELECT hash FROM 
"+tableName+" ");
+                                       sql.append("ORDER BY priority ASC LIMIT 
"+count);
+
+                                       deleteThese=new HashCode160[count];
+
+                                       k=0;
+                                       rset=stmt.executeQuery(sql.toString());
+                                       while (rset.next()) {
+                                               tmp=rset.getBytes(1);
+                                               deleteThese[k++]=(HashCode160) 
PersistentHelper.readFully(HashCode160.class,ByteBuffer.wrap(tmp));
+                                               }
+                                       rset.close();
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+
+                               // delete collected hashes
+                               count=k;
+                               for(k=0; k<count; k++) {
+                                       ce=new ContentIndex();
+
+                                       data=readContent(deleteThese[k],ce,0);
+                                       if (data!=null && callback!=null) {
+                                               
callback.onEntry(deleteThese[k],ce,data,data.length,closure);
+                                               }
+
+                                       sql.setLength(0);
+                                       sql.append("DELETE FROM "+tableName+" 
");
+                                       sql.append("WHERE 
hash='"+escape(deleteThese[k])+"'");
+
+                                       stmt=dbf.createStatement();
+                                       try {
+                                               
stmt.executeUpdate(sql.toString());
+                                               }
+                                       finally {
+                                               stmt.close();
+                                               }
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to delete content !",x);
+                               return false;
+                               }
+                       }
+               return true;
+       }
+
+       /**
+        * Estimate how many blocks can be stored in the DB
+        * before the quota is reached.
+        * Estimate how many blocks can be stored in the DB
+        * before the quota is reached.
+        *
+        * NOTE: this function can not be performed relying on
+        * Data_length+Index_length from "SHOW TABLE STATUS" because
+        * those values seem not to be decreasing in real time.
+        * On mysql 4.0.16, Avg_row_len seems to be updating in real
+        * time w.r.t. insertions and deletions.
+        *
+        * @param quota the number of kb available for the DB
+        * @return number of blocks left
+        */
+
+       public int estimateAvailableBlocks( int quota )
+       {
+               Statement               stmt;
+               ResultSet               rset;
+               StringBuffer    sql;
+               long                    avgRowLen,rowsInTable;
+               int                             kbUsed;
+
+               avgRowLen=-1;
+               rowsInTable=0;
+               synchronized(DATABASE_Lock_) {
+                       try {
+                               stmt=dbf.createStatement();
+                               try {
+                                       // find out average row length in bytes
+                                       // FIXME: probably unnecessary to check 
avg row length every time
+                                       sql=new StringBuffer();
+                                       sql.append("SHOW TABLE STATUS ");
+                                       sql.append("FROM gnunet ");
+                                       sql.append("LIKE '"+tableName+"'");
+
+                                       rset=stmt.executeQuery(sql.toString());
+                                       if (!rset.next()) {
+                                               log(Level.SEVERE,"Unable to 
estimate available blocks (query \""+sql+"\" had no results).");
+                                               return 0;
+                                               }
+
+                                       if 
(avgLength_ID>=rset.getMetaData().getColumnCount() || avgLength_ID<0) {
+                                               log(Level.SEVERE,"Unable to 
estimate available blocks (query \""+sql+"\" had 
"+rset.getMetaData().getColumnCount()+" rows, expected > "+avgLength_ID+").");
+                                               return 0;
+                                               }
+
+                                       avgRowLen=rset.getLong(avgLength_ID+1);
+                                       if (rset.wasNull()) {
+                                               avgRowLen=-1;
+                                               }
+                                       
debug("******************************************* avgRowLen = "+avgRowLen);
+                                       rset.close();
+
+                                       if (avgRowLen<0) {
+                                               log(Level.SEVERE,"FATAL: mysql 
claimed avgRowLen<0 (or failed)");
+                                               return 0;
+                                               }
+
+                                       // find number of entries (rows)
+                                       sql.setLength(0);
+                                       sql.append("SELECT count(*) ");
+                                       sql.append("FROM "+tableName);
+
+                                       rset=stmt.executeQuery(sql.toString());
+
+                                       //todo: if (!rset.next()) {}
+                                       if (rset.next()) {
+                                               rowsInTable=rset.getLong(1);
+                                               }
+                                       rset.close();
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to estimate available blocks !",x);
+                               return 0;
+                               }
+                       }
+
+               kbUsed=(int) ((rowsInTable * avgRowLen) / 1024);
+               debug("Estimate content available 
(q="+quota+",u="+kbUsed+",rem="+(quota-kbUsed)+")");
+               return quota - kbUsed;
+       }
+
+       /**
+        * Free space in the database by removing an entry.
+        *
+        * @param name the key of the entry to remove/the query of the entry to 
remove/hashcode for the block to be deleted
+        * @return false on error, true if ok.
+        * Free space in the database by removing one block
+        */
+
+       public boolean unlink( HashCode160 name )
+       {
+               Statement               stmt;
+               StringBuffer    sql;
+
+               synchronized(DATABASE_Lock_) {
+                       sql=new StringBuffer();
+                       sql.append("DELETE FROM "+tableName+" ");
+                       sql.append("WHERE hash='"+escape(name)+"'");
+
+                       try {
+                               stmt=dbf.createStatement();
+                               try {
+                                       stmt.executeUpdate(sql.toString());
+                                       }
+                               finally {
+                                       stmt.close();
+                                       }
+                               }
+                       catch( SQLException x ) {
+                               err("Failed to unlink "+name.toHex()+" !",x);
+                               return false;
+                               }
+                       }
+               return true;
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static String escape( HashCode160 h )
+       {
+               return escape(PersistentHelper.toBytes(h));
+       }
+
+       public static String escape( byte[] b )
+       {
+               return escape(b,0,b.length);
+       }
+
+       public static String escape( byte[] b, int offset, int length )
+       {
+               StringBuffer    buf;
+               int                             i;
+               char                    c;
+
+               buf=new StringBuffer();
+               for (i=0; i<length; i++) {
+                       c=(char) (b[offset+i] & 0x000000ff);
+                       switch (c) {
+                               case '\'': buf.append("''"); break;
+                               case '\\': buf.append("\\\\"); break;
+                               default: buf.append(c); break;
+                               }
+                       }
+               return buf.toString();
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/Policy2.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/Policy2.java       2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/Policy2.java       2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,117 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+
+/**
+ * Policy interface. This is the interface to the C part of the policy.
+ * resource allocation (storage space, routing) implementation
+ */
+
+public class Policy2 extends Object
+{
+       /** Drop the query if & with this bitmask is 0 */
+       public static final int QUERY_DROPMASK  =       0x00FF0000;
+
+       /** Send answer if local files match */
+       public static final int QUERY_ANSWER    =       0x00020000;
+
+       /** Forward the query, priority is encoded in QUERY_PRIORITY_BITMASK */
+       public static final int QUERY_FORWARD   =       0x00040000;
+
+       /** Indirect the query (use this as the originating node) */
+       public static final int QUERY_INDIRECT  =       0x00080000;
+
+       /** Maximum priority to use (apply this bitmask to the QueryPolicy) */
+       public static final int QUERY_PRIORITY_BITMASK  =       0x0000FFFF;
+
+       /** Bandwidth value of an (effectively) 0-priority query. */
+       public static final double      QUERY_BANDWIDTH_VALUE   =       0.01;
+
+       /** Bandwidth value of a 0-priority content (must be fairly high 
compared to query since content is
+        typically significantly larger -- and more valueable since it can take 
many queries to get one piece of content). */
+       public static final double      CONTENT_BANDWIDTH_VALUE =       0.8;
+
+       private CoreForProtocol coreAPI;
+
+
+       public Policy2( CoreForProtocol capi )
+       {
+               super();
+               coreAPI=capi;
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * A query has been received. The question is, if it should be forwarded
+        * and if with which priority. Routing decisions(to whom) are to be 
taken elsewhere.
+        * <p>
+        *
+        * @param sender the host sending us the query
+        * @param priority the priority the query had when it came in, may be 
an arbitrary number if the
+        *        sender is malicious! Cap by trustlevel first!
+        * @return binary encoding: QUERY_XXXX constants
+        */
+
+       public int evaluateQuery( HostIdentity sender, int priority )
+       {
+               int netLoad = ((StatusCallsService) 
coreAPI.service(StatusCallsService.class)).getNetworkLoadUp();
+
+               if (netLoad < 50)
+                       return 0 /* minimum priority */ |
+                       QUERY_ANSWER | QUERY_FORWARD | QUERY_INDIRECT;
+               /* charge! */
+               priority = - coreAPI.changeTrust(sender, -priority);
+               if (netLoad < 100 + priority)
+                       return ((priority) & QUERY_DROPMASK) |
+                       QUERY_ANSWER | QUERY_FORWARD | QUERY_INDIRECT;
+               else if (netLoad < 100 + 10 * priority)
+                       return ((priority) & QUERY_DROPMASK) |
+                       QUERY_ANSWER | QUERY_FORWARD;
+               else if (netLoad < 100)
+                       return ((priority) & QUERY_DROPMASK) | QUERY_ANSWER;
+               else
+                       return 0; /* drop entirely */
+       }
+
+       /**
+        * Some content dropped by. We may want to store it locally, or not.
+        * The policy adjusts the priority and returns the effective
+        * importance for the content.
+        *
+        * @param hc the query
+        * @param priority of the original query
+        * @return -1 if the content should be dropped, the
+        *   priority for keeping it otherwise/-1 if the content should not be 
replicated,
+        *   otherwise the new priority for the lookup database
+        */
+
+       public int evaluateContent( HashCode160 hc, int priority )
+       {
+               int distance;
+               int j;
+
+               distance = coreAPI.getIdentity().distance(hc);
+               /* compute 'log' of distance */
+               j = 16;
+               while (distance > 0) {
+                       distance = distance>>1;
+                       j--;
+               }
+               if (j < 0)
+                       return -1;
+               return priority * j;
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/QueryManager.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/QueryManager.java  2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/QueryManager.java  2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,694 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+
+/**
+ * The query manager is responsible for queueing queries
+ * forwarding of queries
+ *
+ * The query manager is responsible for queueing queries.  Queued
+ * queries are used to fill buffers (instead of using noise). The QM
+ * is also responsible for selecting the initial set of nodes that
+ * will receive the query. For a good choice, it keeps track of which
+ * nodes were recently hot in answering queries. Some randomness is
+ * preserved to ensure that we potentially find a better path.<p>
+ *
+ * Routing is an incredibly hard problem, so please consider
+ * consulting with other gnunet-developers before making any
+ * significant changes here, even if you have CVS write access.
+ */
+
+public class QueryManager extends LoggedObject implements AFSConstants
+{
+       /** Set to 'YES' to play with 0.6.2b (and earlier) behavior. */
+       private static final boolean    TRADITIONAL_SELECTION   =       false;
+
+       /** of how many outbound queries do we simultaneously keep track ? */
+       public static final int QUERY_RECORD_COUNT      =       512;
+
+       public static final double      FINAL_GOAL      =       3.0;
+
+       /** how many peers should be selected on average? */
+       public static final double      SELECT_GOAL     =       2.0;
+
+       /** How much is a query worth 'in general' (even if there is no trust 
relationship between the peers !).
+        Multiplied by the number of queries in the request.  20 is for '20 
bytes / hash', so this is kind of the base unit. */
+       public static final int BASE_QUERY_PRIORITY     =       20;
+
+       /** Array of the queries we are currently sending out. */
+       private QueryRecord[]   queries;
+       private int                             zePos;
+
+       /** Mutex for all query manager structures. */
+       private Object                  queryManagerLock;
+
+       private int             Xaverage        = 0;
+       private double  Xweight = 4.0;
+       private double  Yweight = 4.0;
+       private Scheduler               scheduler;
+       private ScheduledTask           ageTask;
+       private CoreForProtocol coreAPI;
+
+       /** Linked list tracking reply statistics.  Synchronize access using 
the queryManagerLock! */
+       private ReplyTrackData  rtdList;
+
+
+       public QueryManager()
+       {
+               super(true);
+               queries=new QueryRecord[QUERY_RECORD_COUNT];
+               ageTask=new ScheduledTask("AGE-RTD",new 
EvalAction(this,"ageRTD"),Scheduler.MINUTES_2);
+       }
+
+       public String toString()
+       {
+               return "Query manager";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Initialize the query management.
+        * @param capi
+        */
+
+       public void init( CoreForProtocol capi )
+       {
+               int     i;
+
+               coreAPI=capi;
+               scheduler=capi.getApplication().getScheduler();
+
+               for (i=0;i<QUERY_RECORD_COUNT;i++) {
+                       queries[i]=new QueryRecord();
+                       queries[i].expires = 0; /* all expired */
+                       queries[i].msg = null;
+               }
+               queryManagerLock = coreAPI.getConnectionModuleLock();
+               coreAPI.registerSendCallback(P2PQuery.SIZE+HashCode160.SIZE,new 
BufferFillCallback() {
+                       public boolean fillBuffer( HostIdentity receiver, 
ByteBuffer buf )
+                       {
+                               return fillInQuery(receiver,buf);
+                       }
+               });
+
+               scheduler.addJob(ageTask,Scheduler.MINUTES_2);
+       }
+
+       /**
+        * Shutdown query management.
+        */
+
+       public void done()
+       {
+               int     i;
+
+               scheduler.deleteJob(ageTask);
+
+               for (i=0; i<QUERY_RECORD_COUNT; i++) {
+                       queries[i]=null;
+                       }
+
+               
coreAPI.unregisterSendCallback(P2PQuery.SIZE+HashCode160.SIZE,new 
BufferFillCallback() {
+                       public boolean fillBuffer( HostIdentity receiver, 
ByteBuffer buf )
+                       {
+                               return fillInQuery(receiver,buf);
+                       }
+               });
+       }
+
+       /**
+        * Take a query and forward it to the appropriate number of nodes 
(depending on load, queue, etc).
+        *
+        * @param msg   the query
+        * @param origin        where did the query come from?
+        * @param client        where did the query come from? (if it was a 
client)
+        */
+
+       public void forwardQuery( P2PQuery msg, HostIdentity origin, CSSession 
client )
+       {
+               long now;
+               QueryRecord  qr;
+               QueryRecord             dummy=new QueryRecord();
+               long oldestTime;
+               long expirationTime;
+               int oldestIndex;
+               int i;
+               boolean noclear = false;
+
+               debug("DEBUG: forwarding query for "+msg.getQuery(0).toHex()+" 
with ttl "+msg.getTTL());
+
+               now=Scheduler.now();
+
+               synchronized(queryManagerLock) {
+                       oldestIndex = -1;
+                       expirationTime = now + msg.getTTL();
+                       oldestTime = expirationTime;
+
+                       for (i=0; i<QUERY_RECORD_COUNT; i++) {
+                               if (queries[i].expires<oldestTime) {
+                                       oldestTime=queries[i].expires;
+                                       oldestIndex=i;
+                                       }
+
+                               if (queries[i].msg==null) {
+                                       continue;
+                                       }
+
+                               if (    queries[i].msg.sameQueries(msg)) {
+                                       /* We have exactly this query pending 
already. Replace existing query! */
+
+                                       oldestIndex = i;
+                                       if ( (queries[i].expires > now - 4 * 
TTL_DECREMENT) && /* not long expired */ (Crypto.nextInt(4) != 0) ) {
+                                               /* do not clear the bitmap 
describing which peers we have
+                                                forwarded the query to 
already; but do this only with high
+                                                probability since we may want 
to try again if the query is
+                                                retransmitted lots (this can 
happen if this is the only
+                                                query; we may forward it to 
all connected peers and get no
+                                                reply.  If the initiator keeps 
retrying, we want to
+                                                eventually forward it again.
+
+                                                Note that the initial 
probability here (0.6.0/0.6.1) was
+                                                very low (1:64), which is far 
too low considering that the
+                                                clients do an exponential 
back-off.  The rule is a pure
+                                                optimization, and as such the 
probability that we
+                                                eventually forward must be 
significant.  25% seems to work
+                                                better... (extra-note: in 
small testbeds, the problem
+                                                is bigger than in a larger 
network where the case that
+                                                a query stays in the QM 
indefinitely might be much more
+                                                rare; so don't just trust a 
micro-scale benchmark when
+                                                trying to figure out an 
'optimal' threshold). */
+                                               noclear = true;
+
+                                               debug("DEBUG: QM noclear rule 
applied!\n");
+                                               }
+                                       break; /* this is it, do not scan for 
other 'oldest' entries */
+                                       }
+                               }
+
+                       if (oldestIndex == -1) {
+                               debug("DEBUG: keeping track of 
"+QUERY_RECORD_COUNT+" queries already, will not manage this one");
+                               qr = dummy;
+                               }
+                       else {
+                               qr = queries[oldestIndex];
+                               qr.msg = null;
+                               }
+                       qr.expires = expirationTime;
+                       qr.transmissionCount = 0;
+                       qr.msg=(P2PQuery) PersistentHelper.copy(msg);
+
+                       if (!noclear) {
+                               qr.clearBits();
+                               qr.noTarget=(origin != null ? origin : 
coreAPI.getIdentity());
+                               qr.localClient=client;
+                               qr.totalDistance=0;
+
+                               if (TRADITIONAL_SELECTION) {
+                                       
qr.activeConnections=coreAPI.forAllConnectedNodes(new PerNodeCallback() {
+                                               public void callback( 
HostIdentity identity, Object data )
+                                               {
+                                                       
selectActiveNodes(identity,(QueryRecord) data);
+                                               }
+                                               },qr);
+
+                                       if (qr.activeConnections>0) {
+                                               selectActiveNodes(null, qr); /* 
give SAN chance to adjust weight at the end of the iteration! */
+
+                                               for 
(i=BITMAP_SIZE*4/qr.activeConnections;i>=0;i--) {
+                                                       
qr.setBit(Crypto.nextInt(BITMAP_SIZE)*8); /* select 4 random nodes */
+                                                       }
+
+                                               
coreAPI.forAllConnectedNodes(new PerNodeCallback() {
+                                                       public void callback( 
HostIdentity identity, Object data )
+                                                       {
+                                                               
selectRandomNodes(identity,(QueryRecord) data);
+                                                       }
+                                                       },qr);
+                                               }
+                                       }
+                               else {
+                                       qr.rankings = new int[8*BITMAP_SIZE];
+                                       
qr.activeConnections=coreAPI.forAllConnectedNodes(new PerNodeCallback() {
+                                               public void callback( 
HostIdentity identity, Object data )
+                                               {
+                                                       
newSelectCode(identity,(QueryRecord) data);
+                                               }
+                                               },qr);
+
+                                       /* actual selection, proportional to 
rankings assigned by newSelectCode ... */
+                                       {
+                                               int j;
+                                               long rankingSum = 0;
+                                               for (i=0;i<8*BITMAP_SIZE;i++)
+                                                       rankingSum += 
qr.rankings[i];
+
+                                               if ( (rankingSum != 0) && /* 
doppelt haelt besser */ (qr.activeConnections > 0) ) {
+                                                       /* select 4 peers for 
forwarding */
+                                                       for (i=0;i<4;i++) {
+                                                               long sel;
+                                                               long pos;
+                                                               sel = 
Crypto.nextLong(rankingSum);
+                                                               pos = 0;
+                                                               for 
(j=0;j<8*BITMAP_SIZE;j++) {
+                                                                       pos += 
qr.rankings[j];
+                                                                       if (pos 
> sel) {
+                                                                               
qr.setBit(j);
+                                                                               
break;
+                                                                               
}
+                                                                       }
+                                                               }
+                                                       }
+                                               else {
+                                                       /* no bias available, 
go random! */
+                                                       if 
(qr.activeConnections > 0) {
+                                                               for 
(i=4*BITMAP_SIZE*8/qr.activeConnections-1;i>=0;i--) {
+                                                                       
qr.setBit(Crypto.nextInt(BITMAP_SIZE)*8); /* select 4 random nodes */
+                                                                       }
+                                                               }
+                                                       }
+                                       }
+
+                                       qr.rankings = null;
+                                       }
+                               /* now forward to a couple of selected nodes */
+                               coreAPI.forAllConnectedNodes(new 
PerNodeCallback() {
+                                       public void callback( HostIdentity 
identity, Object data )
+                                       {
+                                               
sendToSelected(identity,(QueryRecord) data);
+                                       }
+                                       },qr);
+                               }
+                       }
+       }
+
+       /**
+        * Stop transmitting a certain query (we don't route it anymore or we 
have learned the answer).
+        * @param query
+        */
+
+       public void dequeueQuery( HashCode160 query )
+       {
+               int                     i,j;
+               QueryRecord     qr;
+
+               synchronized(queryManagerLock) {
+                       for (i=0;i<QUERY_RECORD_COUNT;i++) {
+                               qr = queries[i];
+                               if( qr.msg != null ) {
+                                       for 
(j=NUMBER_OF_QUERIES(qr.msg)-1;j>=0;j--) {
+                                               if 
(query.equals(qr.msg.getQuery(j))) {
+                                                       qr.expires = 0; /* 
expire NOW! */
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /**
+        * How many queries are in the given query (header given).
+        * @param p
+        * @return
+        */
+
+       protected int NUMBER_OF_QUERIES( Persistent p )
+       {
+               return ((p.getByteSize()-P2PQuery.SIZE)/HashCode160.SIZE);
+       }
+
+       /**
+        * Map the id to an index into the bitmap array.
+        * @param id
+        * @return
+        */
+
+       protected int getIndex( HostIdentity id )
+       {
+               int index;
+
+               index = coreAPI.computeIndex(id);
+               if (index > 8*BITMAP_SIZE)
+                       index = index & (8*BITMAP_SIZE-1);
+               return index;
+       }
+
+       /**
+        * Callback method for filling buffers. This method is invoked by the
+        * core if a message is about to be send and there is space left for a
+        * 3QUERY.  We then search the pending queries and fill one (or more)
+        * in if possible.
+        *
+        * Note that the same query is not transmitted twice to a peer and that
+        * queries are not queued more frequently than 2 TTL_DECREMENT.
+        *
+        * @param receiver the receiver of the message
+        * @param buf
+        * @return the number of bytes written to
+        *   that buffer (must be a positive number).
+        */
+
+       protected boolean fillInQuery( HostIdentity receiver, ByteBuffer buf )
+       {
+               long    now;
+               int             start,delta;
+
+               now=Scheduler.now();
+               synchronized(queryManagerLock) {
+                       start = zePos;
+                       delta = 0;
+                       while (buf.remaining()>P2PQuery.SIZE+HashCode160.SIZE) {
+                               if (queries[zePos].expires>now &&
+                                               
!queries[zePos].getBit(getIndex(receiver)) &&
+                                               buf.remaining()>= 
queries[zePos].msg.getByteSize()
+                               ) {
+
+                                       debug("Adding 
"+NUMBER_OF_QUERIES(queries[zePos].msg)+" queries 
("+queries[zePos].msg.getQuery(0).toHex()+") to outbound buffer of 
"+receiver.getName());
+
+                                       
queries[zePos].setBit(getIndex(receiver));
+                                       if 
(!PersistentHelper.write(queries[zePos].msg,buf)) {
+                                               return false;
+                                       }
+                                       queries[zePos].sendCount++;
+                                       delta += 
queries[zePos].msg.getByteSize();
+                               }
+                               zePos++;
+                               if (zePos >= QUERY_RECORD_COUNT)
+                                       zePos = 0;
+                               if (zePos == start)
+                                       break;
+                       }
+               }
+               return true;
+       }
+
+       /**
+        * A "PerNodeCallback" method that selects the most
+        * active nodes for forwarding (with some randomness).
+        *
+        * Also computes the sum of the distances of the
+        * other node IDs as a side-effect.
+        * @param id
+        * @param qr
+        */
+
+       protected void selectActiveNodes( HostIdentity id, QueryRecord qr )
+       {
+               int trf;
+
+               if (id==null) {
+                       // special call for weight adjustment
+                       
Xweight=Xweight/Math.sqrt((qr.transmissionCount+1.0)/(SELECT_GOAL+1.0));
+                       return;
+               }
+
+               trf = coreAPI.queryBPMfromPeer(id);
+               Xaverage  = (Xaverage * 15 + trf) / 16; /* approximate average 
over time...*/
+
+               debug("Selecting from active nodes "+id.getName()+" as 
rand("+(trf+1)+") > rand("+(Xaverage+1)+")*"+Xweight+".");
+
+               /* Forward the query to peers that have on average lots of 
bandwidth
+                assigned to them (and are thus recently very productive...) */
+               if (Crypto.nextInt(trf+1)>Crypto.nextInt(Xaverage+1)*Xweight) {
+                       qr.setBit(getIndex(id));
+                       qr.transmissionCount++;
+
+                       debug("Node selected for forwarding due to activity: 
"+id.getName()+".");
+               }
+               else {
+                       qr.totalDistance+=id.distance(qr.msg.getQuery(0));
+               }
+       }
+
+       /**
+        * A "PerNodeCallback" method that selects some
+        * random nodes (biased according to proximity).
+        * @param id
+        * @param qr
+        */
+
+       protected void selectRandomNodes( HostIdentity id, QueryRecord qr )
+       {
+               int avgDist;
+               int peerDist;
+
+               if (id == null) {
+                       Yweight = Yweight / Math.sqrt( 
(qr.transmissionCount+1.0) / (FINAL_GOAL+1.0) );
+                       return;
+               }
+
+               if (qr.totalDistance==0 || qr.activeConnections==0) {
+                       return; /* activeConnections should never be 0, if 
totalDistance is 0, this is caused by us selectAcitveNodes selecting all nodes 
already */
+               }
+
+               if (qr.getBit(getIndex(id))) {
+                       return;
+               }
+
+               avgDist = (int) (qr.totalDistance / qr.activeConnections);
+               peerDist = id.distance(qr.msg.getQuery(0));
+
+               debug("Selecting at random from active nodes "+id.getName()+" 
using rand("+(peerDist+1)+")*"+qr.transmissionCount+"*"+Yweight+" < 
rand("+(avgDist+1)+").");
+
+               /* Select 2 random nodes for forwarding. Give preference
+                to nodes that are close.  Division by 4 to ensure
+                that we are in the range of a signed int. */
+               if (Crypto.nextInt(1+peerDist) * qr.transmissionCount * Yweight 
< Crypto.nextInt(1+avgDist) ) {
+                       debug("Node selected for forwarding from random set: 
"+id.getName()+".");
+
+                       qr.setBit(getIndex(id));
+                       qr.transmissionCount++;
+               }
+       }
+
+       protected void newSelectCode( HostIdentity id, QueryRecord qr )
+       {
+               ReplyTrackData  pos;
+               ResponseList  rp;
+               int ranking = 0;
+               int distance;
+
+               pos = rtdList;
+               while (pos != null) {
+                       if ((qr.localClient==null && 
pos.queryOrigin.equals(qr.noTarget)) || qr.localClient == pos.localQueryOrigin) 
{
+                               break;
+                               }
+                       pos=pos.next;
+                       }
+
+               if (pos != null) {
+                       rp = pos.responseList;
+                       while (rp != null) {
+                               if (rp.responder.equals(id)) {
+                                       break;
+                                       }
+                               rp = rp.next;
+                               }
+
+                       if (rp != null) {
+                               if (rp.responseCount < 0xFFFF)
+                                       ranking = 0x7FFF * rp.responseCount;
+                               else
+                                       ranking = 0x7FFFFFF;
+                               }
+                       }
+
+               distance=id.distance(qr.msg.getQuery(0));
+               if (distance <= 0)
+                       distance = 1;
+
+               ranking += 0xFFFF / (1 + Crypto.nextInt(distance));
+               ranking += Crypto.nextInt(0xFF); /* small random chance for 
everyone */
+               qr.rankings[getIndex(id)]=ranking;
+       }
+
+       /**
+        * A "PerNodeCallback" method that forwards
+        * the query to the selected nodes.
+        * @param id
+        * @param qr
+        */
+
+       protected void sendToSelected( HostIdentity id, QueryRecord qr )
+       {
+               if (id.equals(qr.noTarget)) {
+                       return;
+                       }
+
+               if (qr.getBit(getIndex(id))) {
+                       debug("Queueing query "+qr.msg.getQuery(0).toHex()+" in 
buffer of selected node "+id.getName()+".");
+
+                       coreAPI.sendToNode(id,
+                                       qr.msg,
+                                       BASE_QUERY_PRIORITY 
*(qr.msg.getPriority()*2+NUMBER_OF_QUERIES(qr.msg)),
+                                       (int) TTL_DECREMENT);
+                       }
+       }
+
+       /**
+        * Cron job that ages the RTD data and that frees memory for entries 
that reach 0.
+        */
+
+       public void ageRTD()
+       {
+               ReplyTrackData  pos;
+               ReplyTrackData  prev;
+               ResponseList  rpos;
+               ResponseList  rprev;
+
+               synchronized(queryManagerLock) {
+                       prev = null;
+                       pos = rtdList;
+                       while (pos != null) {
+                               /* after 10 minutes, always discard everything 
*/
+                               if (pos.lastReplyReceived < 
Scheduler.toSeconds(Scheduler.now()) - 600) {
+                                       while (pos.responseList != null) {
+                                               rpos = pos.responseList;
+                                               pos.responseList = rpos.next;
+                                       }
+                               }
+                               /* otherwise, age reply counts */
+                               rprev = null;
+                               rpos = pos.responseList;
+                               while (rpos != null) {
+                                       rpos.responseCount = rpos.responseCount 
/ 2;
+                                       if (rpos.responseCount == 0) {
+                                               if (rprev == null)
+                                                       pos.responseList = 
rpos.next;
+                                               else
+                                                       rprev.next = rpos.next;
+                                               if (rprev == null)
+                                                       rpos = pos.responseList;
+                                               else
+                                                       rpos = rprev.next;
+                                               continue;
+                                       }
+                               }
+                               /* if we have no counts for a peer anymore,
+                                free pos entry */
+                               if (pos.responseList == null) {
+                                       if (prev == null)
+                                               rtdList = pos.next;
+                                       else
+                                               prev.next = pos.next;
+                                       if (prev == null)
+                                               pos = rtdList;
+                                       else
+                                               pos = prev.next;
+                                       continue;
+                               }
+                               prev = pos;
+                               pos = pos.next;
+                               }
+                       }
+       }
+
+       /**
+        * We received a reply from 'responder' to a query received from
+        * 'origin' (or 'localOrigin').  Update reply track data!
+        *
+        * @param origin only valid if localOrigin == null
+        * @param localOrigin origin if query was initiated by local client
+        * @param responder peer that send the reply
+        */
+
+       public void updateResponseData( HostIdentity origin, CSSession 
localOrigin, HostIdentity responder )
+       {
+               ReplyTrackData  pos;
+               ReplyTrackData  prev;
+               ResponseList  rpos;
+               ResponseList  rprev;
+
+               if (responder == null)
+                       return; /* we don't track local responses */
+
+               synchronized(queryManagerLock) {
+                       pos = rtdList;
+                       prev = null;
+                       while (pos != null) {
+                               if (pos.localQueryOrigin==localOrigin && 
(localOrigin!=null || origin.equals(pos.queryOrigin))) {
+                                       break; /* found */
+                                       }
+                               prev = pos;
+                               pos = pos.next;
+                       }
+                       if (pos == null) {
+                               pos = new ReplyTrackData();
+                               pos.next = null;
+                               pos.localQueryOrigin = localOrigin;
+                               if (localOrigin == null)
+                                       pos.queryOrigin = origin;
+                               pos.responseList = null;
+                               if (prev == null)
+                                       rtdList = pos;
+                               else
+                                       prev.next = pos;
+                       }
+                       pos.lastReplyReceived=(int) 
Scheduler.toSeconds(Scheduler.now());
+                       rpos = pos.responseList;
+                       rprev = null;
+                       while (rpos != null) {
+                               if (responder.equals(rpos.responder)) {
+                                       rpos.responseCount++;
+                                       return;
+                                       }
+                               rprev = rpos;
+                               rpos = rpos.next;
+                               }
+
+                       rpos = new ResponseList();
+                       rpos.responseCount = 1;
+                       rpos.responder = responder;
+                       rpos.next = null;
+                       if (rprev == null)
+                               pos.responseList = rpos;
+                       else
+                               rprev.next = rpos;
+                       }
+       }
+}
+
+/**
+ * Linked list of peer ids with number of replies received.
+ */
+
+class ResponseList extends Object
+{
+       public HostIdentity     responder;
+       public int                      responseCount;
+       public ResponseList     next;
+}
+
+/**
+ * Structure for tracking from which peer we got valueable replies for which 
clients / other peers.
+ */
+
+class ReplyTrackData extends Object
+{
+       /** For which client does this entry track replies ? Only valid if 
localQueryOrigin == null! */
+       public HostIdentity             queryOrigin;
+
+       /** For which client does this entry track replies ? */
+       public CSSession                localQueryOrigin;
+
+       /** Time at which we received the last reply for this client (in 
seconds). Used to discard old entries eventually. */
+       public int                              lastReplyReceived;
+
+       /** Linked list of peers that responded, with number of responses. */
+       public ResponseList             responseList;
+
+       /** Linked list. */
+       public ReplyTrackData           next;
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/QueryRecord.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/QueryRecord.java   2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/QueryRecord.java   2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,91 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.protocol.afs.esed2.*;
+
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.CSSession;
+
+import java.util.*;
+
+/**
+ * In this struct, we store information about a
+ * query that is being send from the local node to
+ * optimize the sending strategy.
+ */
+
+public class QueryRecord extends Object implements AFSConstants
+{
+       /** How often did we send this query so far ? */
+       public int                              sendCount;
+
+       /** The message that we are sending. */
+       public P2PQuery msg;
+
+       /** Bit-map marking the hostIndices (computeIndex) of nodes that have 
received this query already.
+        Note that the bit-map has a maximum size, if the index is 
out-of-bounds, it is hashed into
+        the smaller size of the bitmap. There may thus be nodes with identical 
indices, in that case, only one of
+        the nodes will receive the query. */
+       public byte[]                   bitmap;
+
+       /** When do we stop forwarding (!) this query ? */
+       public long                             expires;
+
+       /** How many nodes were connected when we initated sending this query ? 
*/
+       public int                              activeConnections;
+
+       /** What is the total distance of the query to the connected nodes ? */
+       public long                             totalDistance;
+
+       /** To how many peers has / will this query be transmitted ? */
+       public int                              transmissionCount;
+
+       /** To which peer will we never send this message ? */
+       public HostIdentity             noTarget;
+
+       /** Sender identity, for a local client. */
+       public CSSession                localClient;
+
+       /** How important would it be to send the message to all peers in this 
bucket ? */
+       public int[]                            rankings;
+
+
+       public QueryRecord()
+       {
+               super();
+               bitmap=new byte[BITMAP_SIZE];
+               msg=new P2PQuery();
+       }
+
+       public String toString()
+       {
+               return "Query record";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public boolean getBit( int bit )
+       {
+               byte    theBit;
+
+               theBit=(byte) (1 << (bit & 7));
+               return (bitmap[bit>>3] & theBit)!=0;
+       }
+
+       public void setBit( int bit )
+       {
+               byte    theBit;
+
+               theBit=(byte) (1 << (bit & 7));
+               bitmap[bit>>3] |= theBit;
+       }
+
+       public void clearBits()
+       {
+               Arrays.fill(bitmap,(byte) 0);
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/Routing.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/Routing.java       2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/Routing.java       2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,1335 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs;
+
+import org.gnu.freeway.*;
+import org.gnu.freeway.protocol.afs.esed2.*;
+import org.gnu.freeway.server.*;
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+import java.util.logging.*;
+
+/**
+ * Routing interface. This is the interface that does the routing.
+ * routing of AFS queries and replies
+ *
+ * The routing code is responsible for deciding which replies
+ * need to be forwarded to which peers. While the querymanager
+ * decides where to forward queries, it needs to negotiate with
+ * the routing code which queries can be forwarded since we may
+ * not be able to keep track of all queries.
+ */
+
+public class Routing extends LoggedObject implements AFSConstants
+{
+       private static final boolean    DEBUG_WRITE_INDTABLE    =       true;
+
+       /** How much is a response worth 'in general'. Since replies are 
roughly 1k and should be much (factor of 4)
+        preferred over queries (which have a base priority of 20, which yields 
a base unit of roughly 1 per byte).
+        Thus if we set this value to 4092 we'd rather send a reply instead of 
a query unless the queries have
+        (on average) a priority that is more than double the reply priority 
(note that querymanager multiplies the
+        query priority with 2 to compute the scheduling priority). */
+
+       public static final int BASE_REPLY_PRIORITY     =       4092;
+
+       /**
+        * minimum indirection table size, defaults to 8192 entries, reduce if
+        * you have very little memory, enlarge if you start to overflow often
+        * and have memory available.<p>
+        *
+        * If the average query lives for say 1 minute (10 hops), and you have
+        * a 56k connection (= 420 kb/minute, or approximately 8000
+        * queries/minute) the maximum reasonable routing table size would
+        * thus be 8192 entries.  Every entry takes about 68 bytes.<p>
+        *
+        * The larger the value is that you pick here, the greater your
+        * anonymity can become.  It also can improve your download speed.<p>
+        *
+        * Memory consumption:
+        * <ul>
+        * <li>8192 => 560k indirection table => approx. 6 MB gnunetd</li>
+        * <li>65536 => 4456k indirection table => approx. 10 MB gnuentd</li>
+        * </ul>
+        * <p>
+        * THE VALUE YOU PICK MUST BE A POWER OF 2, for example:
+        * 128, 256, 512, 1024, 2048, 4092, 8192, 16384, 32768, 65536
+        */
+
+       public static final int MIN_INDIRECTION_TABLE_SIZE      =       8192;
+
+       /**
+        * Under certain cirumstances, two peers can interlock in their
+        * routing such that both have a slot that is blocked exactly until
+        * the other peer will make that slot available.  This is the
+        * probability that one will give in.  And yes, it's a hack.  It
+        * may not be needed anymore once we add collision-resistance to
+        * the routing hash table.
+        */
+
+       public static final int TIE_BREAKER_CHANCE      =       4;
+
+       /** ITE modes for addToSlot. */
+       public static final int ITE_REPLACE     =       0;
+       public static final int ITE_GROW        =       1;
+
+       /** Size of the indirection table specified in gnunet.conf */
+       private int     indirectionTableSize;
+
+       /** The routing table. This table has entries for all queries that we 
have recently send out.
+        It helps GNUnet to route the replies back to the respective sender. */
+
+       private IndirectionTableEntry[] ROUTING_indTable_;
+
+       /** Stats handle for how much content replies we have send back to 
clients. */
+       private Stat    stat_cs_reply_content_out;
+
+       /** Stats handles about incoming blocks */
+       private Stat    stat_content_in_ok;
+       private Stat    stat_content_in_dupe;
+       private Stat    stat_content_in_orphan;
+       private Stat    stat_routingFull;
+       private Stat    stat_routingReplaced;
+       private Stat    stat_routingPresent;
+       private Stat    stat_p2p_query_out;
+       private Stat    stat_concurrent_route_replacement;
+       private Stat    stat_delaytime_route_replacement;
+
+       private int                     random_qsel;
+
+       private CoreForProtocol         coreAPI;
+       private Prefs   prefs;
+       private Statistics              stats;
+       private Scheduler                       scheduler;
+       private int             round = 0;
+
+       public Policy           policy;
+       public Manager          manager;
+       public QueryManager     queryManager;
+       public BloomFilter      superBloomFilter;
+       public BloomFilter      singleBloomFilter;
+
+       private ScheduledTask           writeTask;
+
+
+       public Routing()
+       {
+               super(true);
+               coreAPI=null;
+
+               writeTask=new ScheduledTask("WRITE-ID-TABLE",new 
EvalAction(this,"writeIDtable"),Scheduler.MINUTES_1);
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       /**
+        * This function will write numeric entries of the indirectiontable
+        * to a textfile. With idtablesize of (8192*8), it will generate
+        * >1200 kb per run. The output will not be an accurate snapshot
+        * of the idtable at any moment as the locking is done on per-entry
+        * basis. Naturally this function might also twist the routing
+        * itself a little by locking the entries. The hope is that analyzing
+        * this data in eg octave or matlab might help understand the
+        * routing behaviour better. Or not.
+        */
+
+       public void writeIDtable()
+       {
+               IndirectionTableEntry           ite;
+               MappedFile                              fp;
+               FileLocation                            f;
+               DirLocation                             dir;
+               long                                            now;
+               int                                             i;
+
+               now=Scheduler.now();
+
+               dir=prefs.getDirLocation("","GNUNETD_HOME");
+               if (dir==null) {
+                       dir=new DirLocation("~");
+                       }
+
+               f=dir.getFile("gn_idstats.txt");
+               f.create();
+
+               fp=f.open();
+               fp.seekEnd();
+
+               for(i=0; i<indirectionTableSize; i++) {
+                       ite=ROUTING_indTable_[i];
+                       synchronized(ite.lookup_exclusion) {
+                               fp.writeString(round+" "+i+" 
"+(ite.namespace!=null ? 1 : 0)+" "+
+                                       (ite.ttl == 0 ? 0 : 
Scheduler.toSeconds(ite.ttl-now))+" "+ite.priority+" "+
+                                       ite.getSeenCount()+" 
"+ite.getWaitingHostsCount()+" "+ite.getClientsCount()+"\n");
+                               }
+                       }
+
+               fp.close();
+               round++;
+       }
+
+       /**
+        * Initialize routing module.
+        * Initialize routing module (initializes indirection table)
+        * @param capi
+        */
+
+       public void init( CoreForProtocol capi )
+       {
+               int i;
+
+               coreAPI=capi;
+               prefs=capi.getApplication().getPreferences();
+               stats=capi.getApplication().getStatistics();
+               scheduler=capi.getApplication().getScheduler();
+
+               random_qsel = Crypto.nextInt(HashCode160.SIZE/4);
+               stat_cs_reply_content_out=stats.getHandle("# kb downloaded by 
clients",Stat.VERBOSE);
+               stat_delaytime_route_replacement=stats.getHandle("# routing 
entry replaced during delaytime",Stat.VERBOSE);
+               stat_concurrent_route_replacement=stats.getHandle("# routing 
entry replaced during lookup",Stat.VERBOSE);
+
+               stat_content_in_ok=stats.getHandle("# kb ok content in");
+               stat_content_in_dupe=stats.getHandle("# kb dupe content in");
+               stat_content_in_orphan=stats.getHandle("# kb orphan or pushed 
content in");
+               stat_routingFull=stats.getHandle("# routing table full");
+               stat_routingReplaced=stats.getHandle("# routing table entry 
replaced");
+               stat_routingPresent=stats.getHandle("# routing table entry 
already in place");
+               stat_p2p_query_out=stats.getHandle("# p2p queries sent");
+               indirectionTableSize 
=prefs.getInt("AFS","INDIRECTIONTABLESIZE",0);
+               if (indirectionTableSize < MIN_INDIRECTION_TABLE_SIZE)
+                       indirectionTableSize = MIN_INDIRECTION_TABLE_SIZE;
+               i = 1;
+               while (i < indirectionTableSize)
+                       i*=2;
+               indirectionTableSize = i; // make sure it's a power of 2
+
+               debug("Set indirection table size to 
"+indirectionTableSize+".");
+
+               ROUTING_indTable_= new 
IndirectionTableEntry[indirectionTableSize];
+               for (i=0;i<indirectionTableSize;i++) {
+                       ROUTING_indTable_[i]=new IndirectionTableEntry();
+                       ROUTING_indTable_[i].namespace = null;
+                       ROUTING_indTable_[i].ttl = 0; // expired / free
+                       
ROUTING_indTable_[i].successful_local_lookup_in_delay_loop = false;
+                       ROUTING_indTable_[i].lookup_exclusion=new Object();
+                       }
+               ((Server) coreAPI.getApplication()).registerCSExitHandler(new 
ClientExitHandler() {
+                       public void handle( CSSession client )
+                       {
+                               cancelTCP_routing(client);
+                       }
+                       });
+
+               if (DEBUG_WRITE_INDTABLE) {
+                       scheduler.addJob(writeTask,0);
+                       }
+       }
+
+       /**
+        * Shutdown the routing module.
+        */
+
+       public void done()
+       {
+               ((Server) coreAPI.getApplication()).unregisterCSExitHandler(new 
ClientExitHandler() {
+                       public void handle( CSSession client )
+                       {
+                               cancelTCP_routing(client);
+                       }
+                       });
+               ROUTING_indTable_=null;
+
+               if (DEBUG_WRITE_INDTABLE) {
+                       scheduler.deleteJob(writeTask);
+                       }
+       }
+
+       /**
+        * Print the current routing table.
+        * Print the routing table.
+        */
+
+       public void printRoutingTable()
+       {
+               int i;
+               IndirectionTableEntry  ite;
+               long now;
+
+               now=Scheduler.now();
+               log(Level.INFO,"Routing TABLE:");
+               for (i=0;i<indirectionTableSize;i++) {
+                       ite = ROUTING_indTable_[i];
+                       synchronized(ite.lookup_exclusion) {
+                               // if (ite.ttl >= now)
+                               log(Level.FINEST,i+": hash "+ite.hash.toHex()+" 
ttl "+Scheduler.toSeconds(ite.ttl - now)+"s hostsWaiting 
"+ite.getWaitingHostsCount()+" prio "+ite.priority+" seenIndex: 
"+ite.getSeenCount());
+                               }
+                       }
+       }
+
+       /**
+        * Execute the query. <p>
+        *
+        * Execute means to test if we can route the query (or, in the case
+        * of a multi-query, any of the sub-queries). If yes, we lookup the
+        * content locally and potentially route it deferred. Regardless if
+        * the content was found or not, the queries that we can route are
+        * forwarded to other peers (by the querymanager code).<p>
+        *
+        * The decision if we can route is made by "needsForwarding". Note that
+        * queries that we are already routing do not "need forwarding". If
+        * we do route the query, execQuery decides if we are going to do source
+        * rewriting or not.<p>
+        *
+        * If we route a query, execSingleQuery will use the bloom filters and
+        * the databases to locate the content and queue a cron job that will
+        * pass the response to "useContent" as if it came from another peer.
+        * Note that if the query originated from a local client, the response
+        * is instant (no cron job scheduled).
+        *
+        * @param qp the polciy (priority) for the query
+        * @param msg the query message (with host identity for the reply)
+        * @param sock the TCP socket to send the answer to if it is
+        *        a query from the local host, otherwise null.
+        * @return true if the query was routed (at least in part), false if it 
was dropped
+        */
+
+       public boolean execQuery( int qp, P2PQuery msg, CSSession sock )
+       {
+               HostIdentity  sender;
+               HostIdentity senderCpy;
+               int prio;
+               int count;
+               int routeCount;
+
+               count = (msg.getByteSize()-P2PQuery.SIZE) / HashCode160.SIZE;
+               prio = msg.getPriority() / count; // per-query priority
+
+               // source rewriting (or not...)
+               if (sock == null) {
+                       if (msg.getReturnTo().equals(coreAPI.getIdentity()))
+                               return false; // A to B, B sends back to A 
without (!) source rewriting, in this case, A must just drop
+                       senderCpy=(HostIdentity) 
PersistentHelper.copy(msg.getReturnTo());      //todo: copie utile ???
+                       sender = senderCpy;
+               } else {
+                       sender = null;
+                       senderCpy=(HostIdentity) 
PersistentHelper.copy(coreAPI.getIdentity());  //todo: copie utile ???
+               }
+               if ((qp & Policy2.QUERY_INDIRECT) != 0) {
+                       msg.setReturnTo((HostIdentity) 
PersistentHelper.copy(coreAPI.getIdentity()));   //todo: copie utile ???
+                       }
+               else {
+                       msg.setPriorityAndTTL(0,msg.getTTL());
+                       }
+
+               debug("Received "+count+"-query "+msg.getQuery(0).toHex()+" 
with ttl "+msg.getTTL()+" and priority "+msg.getPriority()+".");
+
+               if (msg instanceof P2PNSQuery) {
+                       if 
(execNSQuery(sender,sock,prio,msg.getTTL(),((P2PNSQuery) 
msg).identifier,((P2PNSQuery) msg).namespace))
+                               routeCount = 2; // NAMESPACE + IDENTIFIER!
+                       else
+                               routeCount = 0;
+                       }
+               else {
+                       if (count > 1) { // MULTI-QUERY, take apart for 
individual routing, but reassemble for forwarding
+                               int i;
+                               boolean superBF;
+
+                               superBF = 
superBloomFilter.test(msg.getQuery(0));
+                               routeCount = 1;
+                               for (i=1;i<count;i++) {
+                                       if 
(execSingleQuery(sender,sock,prio,msg.getTTL(),msg.getQuery(i),superBF)) {
+                                               // route this query !
+                                               
msg.setQuery(routeCount,msg.getQuery(i));
+                                               routeCount++;
+                                               }
+                                       }
+                               if (routeCount == 1)
+                                       routeCount = 0; // nothing to forward
+                               }
+                       else { // single query or 3hash search
+                               if 
(execSingleQuery(sender,sock,prio,msg.getTTL(),msg.getQuery(0),false))
+                                       routeCount = 1;
+                               else
+                                       routeCount = 0;
+                               }
+                       }
+
+               if (routeCount >= 1) {
+                       stat_p2p_query_out.add(routeCount);
+                       queryManager.forwardQuery(msg,((sock == null) ? sender 
: null),sock);
+
+                       debug("Slots free in routing table for "+((sock==null) 
? "remote" : "LOCAL")+
+                               " query "+msg.getQuery(0).toHex()+"; forwarded 
"+routeCount+" out of "+count+" queries.");
+                       return true;
+                       }
+
+               debug("0 slots free in routing table for "+((sock==null) ? 
"remote" : "LOCAL")+
+                       " query "+msg.getQuery(0).toHex()+" with "+count+" hash 
codes, none forwarded.");
+               return false;
+       }
+
+       /**
+        * Content has arrived. We must decide if we want to
+        *   a) forward it to our clients
+        *   b) indirect it to other nodes.
+        * The routing module should know what to do.
+        *
+        * This method checks the routing table if we have a matching route and 
if yes queues the reply.
+        * It also makes sure that we do not send the same reply back on the 
same route more than once.
+        *
+        * @param hostId        who sent the message
+        * @param queryHash     the hashcode from the query
+        * @param msg           the p2p message we received, good for 
indirecting, must potentially be turned into the adequate CS message.
+        * @return                      how good this content was (priority of 
the original request)
+        */
+
+       public int useContent( HostIdentity hostId, HashCode160 queryHash, 
P2PMessage msg )
+       {
+               int i;
+               ContentBlock  content;
+               HashCode160 contentHC;
+               IndirectionTableEntry  ite;
+               int prio = -1;
+
+               //log(Level.FINEST,"DEBUG: useContent - prints routing table");
+               //printRoutingTable();
+
+               debug("Received content "+queryHash.toHex()+" from peer 
"+((hostId == null) ? "self" : hostId.getName())+".");
+
+               ite = ROUTING_indTable_[computeRoutingIndex(queryHash)];
+
+               synchronized(ite.lookup_exclusion) {
+                       if (!ite.hash.equals(queryHash) ) {
+                               stat_content_in_orphan.inc();
+                               debug("No matching query pending for content 
"+queryHash.toHex()+" (not indirected).");
+                               return 0; // no indirection pending: was useless
+                               }
+
+                       if (msg instanceof P2P3HashResult) {
+                               content=new ContentBlock(((P2P3HashResult) 
msg).getResult());
+                               if (ite.namespace != null) {
+                                       return 0;
+                                       }
+                               }
+                       else if (msg instanceof P2PChkResult) {
+                               queryManager.dequeueQuery(ite.hash);
+                               content = ((P2PChkResult)msg).result;
+                               if (ite.namespace != null) {
+                                       return 0;
+                                       }
+
+                               // remove the sender from the waiting list (if 
the sender was waiting for a response)
+                               if (hostId != null) {
+                                       ite.removeWaitingHost(hostId);
+                                       }
+                               }
+                       else if (msg instanceof P2PSBlockResult) {
+                               content=(ContentBlock) 
PersistentHelper.readFully(ContentBlock.class,PersistentHelper.toBuffer(((P2PSBlockResult)msg).getResult()));
+                               if (ite.namespace == null) {
+                                       return 0;
+                                       }
+                               HashCode160 hc;
+                               
hc=((P2PSBlockResult)msg).getResult().getNameSpace();
+                               if (! ite.namespace.equals(hc) ) {
+                                       return 0;
+                                       }
+                               }
+                       else {
+                               log(Level.WARNING,"Unexpected p2p result : 
"+msg);
+                               return 0;
+                               }
+
+                       
contentHC=HashCode160.create(PersistentHelper.toBytes(content));
+
+                       for (i=0;i<ite.getSeenCount();i++) {
+                               if (contentHC.equals(ite.getSeen(i))) {
+                                       stat_content_in_dupe.inc();
+                                       debug("Content is not new (slot: 
"+computeRoutingIndex(queryHash)+").");
+                                       return 0; // seen before, useless
+                                       }
+                               }
+                       // new reply, adjust credits !
+                       if (hostId != null) // if we are the sender, hostId 
will be null
+                               coreAPI.changeTrust(hostId, ite.priority);
+                       prio = ite.priority;
+                       ite.priority = 0; // no priority for further replies, 
because we don't get paid for those...
+
+                       debug("Indirecting new content matching query 
"+ite.hash.toHex()+".");
+
+                       for (i=0; i<ite.getClientsCount(); i++) {
+                               
queryManager.updateResponseData(null,ite.getClient(i),hostId);
+                               }
+
+                       for (i=0; i<ite.getWaitingHostsCount(); i++) {
+                               
queryManager.updateResponseData(ite.getWaitingHost(i),null,hostId);
+                               }
+
+                       sendReply(ite,msg);
+                       ite.addSeen(contentHC);
+                       stat_content_in_ok.inc();
+                       }
+               return prio;
+       }
+
+       /**
+        * Compute the hashtable index of a host id.
+        * @param query
+        * @return
+        */
+
+       protected int computeRoutingIndex( HashCode160 query )
+       {
+               int     res;
+
+               switch (random_qsel) {
+                       case 0: res=query.getA(); break;
+                       case 1: res=query.getB(); break;
+                       case 2: res=query.getC(); break;
+                       case 3: res=query.getD(); break;
+                       default: res=query.getE(); break;
+                       }
+               res=(res & (indirectionTableSize-1));
+               if (res>=indirectionTableSize) {
+                       trace("Indirection table size not power of 2 ? 
("+indirectionTableSize+")");
+                       }
+               return res;
+       }
+
+       /**
+        * Queue a CHK reply with cron to simulate
+        * another peer returning the response with
+        * some latency (and then route as usual).
+        *
+        * @param sender the next hop
+        * @param result the content that was found
+        */
+
+       protected void queueCHKReply( HostIdentity sender, ContentBlock result )
+       {
+               final P2PChkResult      _msg;
+               IndirectionTableEntry   ite;
+               HashCode160                             hc;
+
+               hc=HashCode160.create(PersistentHelper.toBytes(result));
+
+               ite=ROUTING_indTable_[computeRoutingIndex(hc)];
+               if (!ite.hash.equals(hc)) {
+                       debug("Concurrent route replacement : "+hc.toHex()+".");
+
+                       stat_concurrent_route_replacement.inc();
+                       return;
+                       }
+               if (ite.successful_local_lookup_in_delay_loop) {
+                       debug("Unexpected concurrent CHK lookup of 
"+hc.toHex()+".");
+                       return; // wow, really bad concurrent DB lookup and 
processing for the same query.  Well, at least we should not also queue the 
delayed reply twice...
+                       }
+               ite.successful_local_lookup_in_delay_loop = true;
+
+               _msg=new P2PChkResult();
+               _msg.result=(ContentBlock) PersistentHelper.copy(result);       
//todo: copie utile ???
+
+               // delay reply, delay longer if we are busy (makes it harder to 
predict / analyze, too).
+               scheduler.addJob(new ScheduledTask("DELAYED-REPLY",new 
AbstractAction() {
+                       public void perform()
+                       {
+                               HashCode160                             hc2;
+                               IndirectionTableEntry           ite2;
+
+                               
hc2=HashCode160.create(PersistentHelper.toBytes(_msg.result));
+
+                               ite2 = 
ROUTING_indTable_[computeRoutingIndex(hc2)];
+                               synchronized(ite2.lookup_exclusion) {
+                                       if (hc2.equals(ite2.hash)) {
+                                               
ite2.successful_local_lookup_in_delay_loop = false;
+                                               }
+                                       else {
+                                               
stat_delaytime_route_replacement.inc();
+                                               }
+                                       }
+                               useContent(null,hc2,_msg);
+                       }
+                       }),Crypto.nextLong(TTL_DECREMENT));
+       }
+
+       /**
+        * Queue an SBLOCK reply with cron to simulate
+        * another peer returning the response with
+        * some latency (and then route as usual).
+        *
+        * @param sender the next hop
+        * @param result the content that was found
+        */
+
+       protected void queueSBLOCKReply( HostIdentity sender, EncryptedSBlock 
result )
+       {
+               final P2PSBlockResult   _msg;
+
+               _msg=new P2PSBlockResult(result);
+
+               // delay reply, delay longer if we are busy (makes it harder to 
predict / analyze, too).
+               scheduler.addJob(new ScheduledTask("SBLOCK-REPLY",new 
AbstractAction() {
+                       public void perform()
+                       {
+                               
useContent(null,_msg.getResult().getIdentifier(),_msg);
+                       }
+                       }),Crypto.nextLong(TTL_DECREMENT));
+       }
+
+       /**
+        * Queue a 3Hash reply with cron to simulate
+        * another peer returning the response with
+        * some latency (and then route as usual).
+        *
+        * @param sender the next hop
+        * @param hc the double (!) hash
+        * @param result the content that was found
+        */
+
+       protected void queue3HashReply( HostIdentity sender, HashCode160 hc, 
ContentBlock result )
+       {
+               final P2P3HashResult    _msg;
+
+               _msg=new P2P3HashResult(hc,result);
+
+               // delay reply, delay longer if we are busy (makes it harder to 
predict / analyze, too).
+               scheduler.addJob(new ScheduledTask("3HASH-REPLY",new 
AbstractAction() {
+                       public void perform()
+                       {
+                               useContent(null,_msg.getTripleHash(),_msg);
+                       }
+                       }),Crypto.nextLong(TTL_DECREMENT));
+       }
+
+       /**
+        * Hand a CHK reply to the client.
+        * @param sock the client socket
+        * @param result the response
+        */
+
+       protected void tellClientCHKReply( CSSession sock, ContentBlock result )
+       {
+               CSResultChk  reply;
+               HashCode160 hc;
+
+               hc=HashCode160.create(PersistentHelper.toBytes(result));
+
+               debug("Sending client response to CHK query "+hc.toHex()+".");
+
+               reply = new CSResultChk();
+               reply.result=(ContentBlock) PersistentHelper.copy(result);      
//todo: copie utile ???
+
+               stat_cs_reply_content_out.inc();
+
+               sock.send(reply);
+       }
+
+       /**
+        * Hand an SBLOCK reply to the client.
+        * @param sock the client socket
+        * @param result the response
+        */
+
+       protected void tellClientSBLOCKReply( CSSession sock, EncryptedSBlock 
result )
+       {
+               CSResultSBlock  reply;
+
+               reply=new CSResultSBlock(result);
+
+               stat_cs_reply_content_out.inc();
+
+               sock.send(reply);
+       }
+
+       /**
+        * Hand a 3Hash reply to the client.
+        * @param sock the client socket
+        * @param hc the double hash
+        * @param result the response
+        */
+
+       protected void tellClient3HashReply( CSSession sock, HashCode160 hc, 
ContentBlock result )
+       {
+               CSResult3Hash  reply;
+
+               reply = new CSResult3Hash(hc,result);
+
+               stat_cs_reply_content_out.inc();
+
+               sock.send(reply);
+       }
+
+       /**
+        * Add an entry to the routing table. The lock on the ite
+        * must be held and is being released.
+        *
+        * @param mode replace or extend an existing entry?
+        * @param ite slot in the routing table that is manipulated
+        * @param query the query to look for
+        * @param namespace the namespace to look in (null for global namespace)
+        * @param ttl how long to keep the new entry, relative ttl
+        * @param priority how important is the new entry
+        * @param sender for which node is the entry (null for local client)
+        * @param sock for which local client is the entry (null for peer)
+        * @return true if sock or sender was added, false if both are null or 
existed already
+        *            in the queue
+        */
+
+       protected boolean addToSlot( int mode, IndirectionTableEntry ite, 
HashCode160 query, HashCode160 namespace, int ttl, int priority, HostIdentity 
sender, CSSession sock )
+       {
+               long    now;
+               boolean ret = false;
+
+               // namespace handling: always override with the new value 
(query collisions are supposed to be 'impossible',
+               // so this should always be correct.  Either we replace the 
existing slot with something new, or it
+               // should not make a difference since the old and the new 
namespace will be the same.
+               if (ite.namespace != null) {
+                       if (namespace == null) {
+                               ite.namespace = null;
+                       } else {
+                               ite.namespace=(HashCode160) 
PersistentHelper.copy(namespace);   //todo: copie utile ???
+                       }
+               } else {
+                       if (namespace != null) {
+                               ite.namespace=(HashCode160) 
PersistentHelper.copy(namespace);   //todo: copie utile ???
+                       }
+               }
+               now=Scheduler.now();
+               if (mode == ITE_REPLACE) {
+                       ite.clearSeen();
+                       if (query.equals(ite.hash)) {
+                               stat_routingPresent.inc();
+                               ite.ttl = now + ttl;
+                               ite.priority = priority;
+                               }
+                       else {
+                               if (ite.hasClients() && sender==null && 
!ite.hasSeen()) {
+                                       debug("Replacing local query 
"+query.toHex()+" without results with foreign query !");
+                                       }
+
+                               ite.successful_local_lookup_in_delay_loop = 
false;
+                               // different request, flush pending queues
+                               stat_routingReplaced.inc();
+                               queryManager.dequeueQuery(ite.hash);
+                               ite.hash=(HashCode160) 
PersistentHelper.copy(query);    //todo: copie utile ???
+                               ite.clearWaitingHosts();
+                               ite.clearClients();
+                               ite.ttl = now + ttl;
+                               ite.priority = priority;
+                       }
+               } else { // GROW mode
+                       if (!query.equals(ite.hash)) {
+                               trace("Assert failed !");
+                               return false;
+                               }
+                       if (sender != null) {
+                               if (ite.hasWaitingHost(sender)) {
+                                       sender=null;
+                                       }
+                               }
+                       stat_routingPresent.inc();
+
+                       if (sock!=null && ite.containsClient(sock)) {
+                               sock=null;
+                               }
+
+                       if ( (sock == null) &&
+                                       (sender == null) ) {
+                               return ret; // already there!
+                       }
+                       // extend lifetime
+                       if (ite.ttl < now + ttl)
+                               ite.ttl = now + ttl;
+                       ite.priority += priority;
+                       }
+
+               if (sock!=null) {
+                       if (ite.containsClient(sock)) {
+                               sock=null;
+                               }
+
+                       if (sock != null) {
+                               ite.addClient(sock);
+                               ite.clearSeen(); // new listener, flush "seen" 
list
+                               ret = true;
+                               }
+                       }
+
+               if (sender!=null && ite.hasWaitingHost(sender)) {
+                       sender=null;
+                       }
+
+               if (sender!=null) {
+                       ite.addWaitingHost(sender);
+                       ret = true;
+                       // again: new listener, flush seen list
+                       ite.clearSeen();
+                       }
+               return ret;
+       }
+
+       /**
+        * Find out, if this query is already pending. If the ttl of
+        * the new query is higher than the ttl of an existing query,
+        * false is returned since we should re-send the query.<p>
+        *
+        * If true is returned, the slot is also marked as used by
+        * the query and the sender (HostId or socket) is added.<p>
+        *
+        * This method contains a heuristic that attempts to do its best to
+        * route queries without getting too many cycles, send a query and
+        * then drop it from the routing table without sending a response,
+        * etc.  Before touching this code, definitely consult Christian
+        * (address@hidden) who has put more bugs in these five lines
+        * of code than anyone on this planet would think is possible.
+        *
+        *
+        * @param query the hash to look for
+        * @param namespace the namespace to look in, null for the global 
namespace
+        * @param ttl how long would the new query last
+        * @param priority the priority of the query
+        * @param sender which peer transmitted the query? (null for this peer)
+        * @param sock which client transmitted the query? (null for other peer)
+        * @param isRouted set to true if we can route this query, false if we 
can not
+        * @param doForward is set to true if we should forward the query, 
false if not
+        * @return a case ID for debugging
+        */
+
+       protected int needsForwarding( HashCode160 query, HashCode160 
namespace, int ttl, int priority, HostIdentity sender, CSSession sock, 
boolean[] isRouted, boolean[] doForward )
+       {
+               IndirectionTableEntry  ite;
+               long now;
+
+               now=Scheduler.now();
+               ite = ROUTING_indTable_[computeRoutingIndex(query)];
+               // released either in here or by addToSlot!
+
+               if ( ( ite.ttl < now - TTL_DECREMENT * 10) &&
+                               ( ttl > - TTL_DECREMENT * 5) ) {
+                       addToSlot(ITE_REPLACE, ite, query, namespace, ttl, 
priority, sender, sock);
+                       isRouted[0] = true;
+                       doForward[0] = true;
+                       return 21;
+                       }
+               if (ttl<0 && query.equals(ite.hash)) {
+                       // if ttl is "expired" and we have the exact query 
pending, route replies but do NOT forward _again_!
+
+                       debug("GROW: ttl < 0 and existing query is equal 
("+ttl+", "+(ite.ttl-now)+").");
+
+                       addToSlot(ITE_GROW, ite, query, namespace, ttl, 
priority, sender, sock);
+                       // don't go again, we are not even going to reset the 
seen list, so why bother looking locally again, if we would find
+                       //something, the seen list would block sending the 
reply anyway since we're not resetting that (ttl too small!)!
+                       isRouted[0] = false;
+                       doForward[0] = false;
+                       return 0;
+               }
+
+               if ( (ite.ttl + (TTL_DECREMENT * coreAPI.estimateNetworkSize()) 
<
+                               (now + ttl)) &&
+                               (ite.ttl < now) ) {
+                       // expired AND is significantly (!) longer expired than 
new query
+
+                       debug("REPLACE and reset SEEN: existing query expired 
and older than new query ("+ttl+", "+(ite.ttl-now)+").");
+
+                       // previous entry relatively expired, start using the 
slot -- and kill the old seen list!
+                       ite.clearSeen();
+                       if ( query.equals(ite.hash) &&
+                                       (ite. 
successful_local_lookup_in_delay_loop) ) {
+                               isRouted[0] = false;
+                               doForward[0] = false;
+                               addToSlot(ITE_GROW, ite, query, namespace, ttl, 
priority, sender, sock);
+                               return 1;
+                               }
+                       isRouted[0] = true;
+                       doForward[0] = true;
+                       addToSlot(ITE_REPLACE, ite, query, namespace, ttl, 
priority, sender, sock);
+                       return 2;
+                       }
+
+               if (query.equals(ite.hash) ) {
+                       if (!ite.hasSeen()) {
+                               // can not tell if CHK/3HASH/NSQUERY
+                               if (ite.ttl + TTL_DECREMENT < (now + ttl)) { // 
ttl of new is SIGNIFICANTLY     longer?
+                                       // query again
+
+                                       debug("REPLACE (seen was empty): 
existing query and TTL higher ("+(ite.ttl-now)+", "+ttl+").");
+
+                                       addToSlot(ITE_REPLACE, ite, query, 
namespace, ttl, priority, sender, sock);
+                                       if 
(ite.successful_local_lookup_in_delay_loop) {
+                                               isRouted[0] = false; // don't 
go again, we are already processing a local lookup!
+                                               doForward[0] = false;
+                                               return 3;
+                                               }
+                                       isRouted[0] = true;
+                                       doForward[0] = true;
+                                       return 4;
+                                       }
+
+                               // new TTL is lower than the old one, thus just 
wait for the reply that may come back
+
+                               debug("GROW - equal existing query exists 
without replies ("+(ite.ttl-now)+", "+ttl+").");
+
+                               if (addToSlot(ITE_GROW, ite, query, namespace, 
ttl, priority, sender, sock)) {
+                                       if 
(ite.successful_local_lookup_in_delay_loop) {
+                                               isRouted[0] = false; // don't 
go again, we are already processing a local lookup!
+                                               doForward[0] = false;
+                                               return 5;
+                                               }
+                                       isRouted[0] = true;
+                                       doForward[0] = false;
+                                       return 6;
+                                       }
+
+                               // same query with _higher_ TTL has already 
been processed FOR THE SAME recipient! Do NOT do
+                               // the lookup *again*.
+                               isRouted[0] = false;
+                               doForward[0] = false;
+                               return 7;
+                               }
+                       // ok, seen reply before, can judge type of query!
+
+                       // pending == new!
+                       if ( ite.hash.equals(ite.getSeen(0)) &&
+                                       (ite.namespace == null) ) { // CHK
+                               if (ite.ttl < (now + ttl)) { // ttl of new is 
longer?
+                                       // go again
+                                       ite.clearSeen();
+
+                                       debug("REPLACE and reset SEEN: existing 
query equal but we've seen the response already ("+(ite.ttl-now)+", "+ttl+").");
+
+                                       addToSlot(ITE_REPLACE, ite, query, 
namespace, ttl, priority, sender, sock);
+                                       if 
(ite.successful_local_lookup_in_delay_loop) {
+                                               isRouted[0] = false; // don't 
go again, we are already processing a local lookup!
+                                               doForward[0] = false;
+                                               return 8;
+                                               }
+                                       isRouted[0] = true;
+                                       // only forward if new TTL is 
significantly higher
+                                       if (ite.ttl + TTL_DECREMENT < (now + 
ttl))
+                                               doForward[0] = true;
+                                       else
+                                               doForward[0] = false;
+                                       return 9;
+                                       }
+
+                               // new TTL is lower than the old one, thus just 
wait for the reply that may come back
+                               debug("GROW - equal existing query exists 
without replies ("+(ite.ttl-now)+", "+ttl+").");
+
+                               if (addToSlot(ITE_GROW, ite, query, namespace, 
ttl, priority, sender, sock)) {
+                                       if 
(ite.successful_local_lookup_in_delay_loop) {
+                                               isRouted[0] = false;
+                                               doForward[0] = false;
+                                               return 10;
+                                               }
+                                       isRouted[0] = true;
+                                       doForward[0] = false;
+                                       return 11;
+                                       }
+                               isRouted[0] = false;
+                               doForward[0] = false;
+                               return 12;
+                               }
+
+                       // 3HASH or SQUERY, multiple results possible!
+                       // It's a pending 3HASH or SQUERY that can have 
multiple replies.  Do not re-send, just forward the
+                       // answers that we get from now on to this additional 
receiver
+                       boolean isttlHigher;
+
+                       debug("GROW - equal existing query exists without 
replies ("+(ite.ttl-now)+", "+ttl+").");
+
+                       if (ite.ttl <  now+ttl)
+                               isttlHigher = false;
+                       else
+                               isttlHigher = true;
+                       if (addToSlot(ITE_GROW, ite, query, namespace, ttl, 
priority, sender, sock)) {
+                               isRouted[0] = true;
+                               doForward[0] = false;
+                               return 13;
+                               }
+                       // receiver is the same as the one that already got the 
answer, do not bother to do this again,
+                       // IF the TTL is not higher!
+                       isRouted[0] = isttlHigher;
+                       doForward[0] = false;
+                       return 14;
+                       }
+               // a different query that is expired a bit longer is using the 
slot; but if it is a CHK query that has received
+               // a response already, we can eagerly throw it out anyway, 
since the request has been satisfied completely
+               if ( (ite.ttl + TTL_DECREMENT < (now + ttl) ) &&
+                               (ite.ttl < now) &&
+                               (ite.getSeenCount() == 1) &&
+                               (ite.namespace == null) &&
+                               (ite.hash.equals(ite.getSeen(0))) ) {
+                       // is CHK and we have seen the answer, get rid of it 
early
+
+                       debug("CHK "+ite.hash.toHex()+" with reply already 
seen, replacing eagerly ("+(ite.ttl-now)+", "+ttl+").");
+
+                       addToSlot(ITE_REPLACE, ite, query, namespace, ttl, 
priority, sender, sock);
+                       isRouted[0] = true;
+                       doForward[0] = true;
+                       return 15;
+               }
+               // Another still valid query is using the slot.  Now we need a 
_really_ good reason to discard it...
+               if (ttl < 0) {
+                       isRouted[0] = false;
+                       doForward[0] = false;
+                       return 16; // if new ttl is "expired", don't bother 
with priorities
+               }
+
+               // Finally try to find a _strong_ reason looking at 
priority/ttl relationships to replace the existing query. A low ttl with high
+               // priority should be preferred, so we do a 
cross-multiplication (!). Also, we want a _strong_ reason, so we add a "magic" 
factor
+               // of 10 for the additional work that the replacement would 
make (the network needs a certain amount of resilience to changes in
+               // the routing table, otherwise it might happen that query A 
replaces query B which replaces query A which could happen so
+               // quickly that no response to either query ever makes it 
through...
+
+               if ( ((ite.ttl - now) * priority) >
+                                10 * (ttl * ite.priority) ) {
+
+                       debug("Priority of new query is much higher, overriding 
("+(ite.ttl-now)+", "+ttl+").");
+
+                       addToSlot(ITE_REPLACE, ite, query, namespace, ttl, 
priority, sender, sock);
+                       isRouted[0] = true;
+                       doForward[0] = true;
+                       return 17;
+               }
+
+               if (Crypto.nextInt(TIE_BREAKER_CHANCE) == 0) {
+                       debug("TIE-BREAKER.  Overriding ("+(ite.ttl-now)+", 
"+ttl+").");
+
+                       addToSlot(ITE_REPLACE, ite, query, namespace, ttl, 
priority, sender, sock);
+                       isRouted[0] = true;
+                       doForward[0] = true;
+                       return 20;
+                       }
+
+               // sadly, the slot is busy with something else; we can not even 
add ourselves to the reply set
+               stat_routingFull.inc();
+               isRouted[0] = false;
+               doForward[0] = false;
+
+               debug("Existing "+(!ite.hasClients() ? "remote" : "LOCAL")+
+                       " query "+ite.hash.toHex()+" 
("+computeRoutingIndex(ite.hash)+") is more important (EP: "+
+                       ite.priority+", ET: "+(ite.ttl-now)+"; NP: 
"+priority+", NT: "+ttl+")");
+               return 18;
+       }
+
+       /**
+        * Send a reply to a host.  Distinguishes between local and remote
+        * delivery, converts the reply into the appropriate format and sends
+        * it out.
+        *
+        * @param ite the matching slot in the indirection table
+        * @param msg the message to route
+        */
+
+       protected void sendReply( IndirectionTableEntry ite, P2PMessage msg )
+       {
+               int j;
+               int maxDelay;
+               long now;
+
+               now=Scheduler.now();
+               if (now < ite.ttl)
+                       maxDelay = (int) (ite.ttl - now);
+               else
+                       maxDelay = (int) TTL_DECREMENT; // for expired queries
+
+               // send to peers
+               for (j=0; j<ite.getWaitingHostsCount(); j++) {
+                       
coreAPI.sendToNode(ite.getWaitingHost(j),msg,BASE_REPLY_PRIORITY 
*(ite.priority+1),maxDelay);// weigh priority
+                       }
+
+               for (j=0; j<ite.getClientsCount(); j++) {
+                       if (msg instanceof P2P3HashResult) {
+                               tellClient3HashReply(ite.getClient(j),
+                                               ((P2P3HashResult) 
msg).getDoubleHash(),
+                                               new 
ContentBlock(((P2P3HashResult) msg).getResult())
+                                               );
+                               }
+                       else if (msg instanceof P2PChkResult) {
+                               
tellClientCHKReply(ite.getClient(j),((P2PChkResult)msg).result);
+                               }
+                       else if (msg instanceof P2PSBlockResult) {
+                               
tellClientSBLOCKReply(ite.getClient(j),((P2PSBlockResult) msg).getResult());
+                               }
+                       else {
+                               log(Level.WARNING,"Unexpected p2p result : 
"+msg);
+                               }
+                       }
+       }
+
+       /**
+        * TCP connection is shut down, cancel all replies to that client.
+        * @param sock
+        */
+
+       protected void cancelTCP_routing( CSSession sock )
+       {
+               IndirectionTableEntry   ite;
+               int                                             i;
+
+               for (i=0; i<indirectionTableSize; i++) {
+                       ite=ROUTING_indTable_[i];
+                       synchronized(ite.lookup_exclusion) {
+                               ite.removeClient(sock);
+                               }
+                       }
+       }
+
+       /**
+        * Execute a single query. Tests if the query can be routed. If yes,
+        * the query is added to the routing table and the content is looked
+        * for locally. If the content is available locally, a deferred
+        * response is simulated with a cron job and the local content is
+        * marked as valueable. The method returns true if the query should
+        * subsequently be routed to other peers.
+        *
+        * @param sender next hop in routing of the reply
+        * @param sock client socket if we are ultimate receiver
+        * @param prio the effective priority of the query
+        * @param ttl the relative ttl of the query
+        * @param query the query itself
+        * @param superHash true if the super-hash test has indicated that we#
+        *        have a reply locally available
+        * @return true if the query should be routed further, false if not.
+        */
+
+       protected boolean execSingleQuery( HostIdentity sender, CSSession sock, 
int prio, int ttl, HashCode160 query, boolean superHash )
+       {
+               ContentIndex                    ce=new ContentIndex();
+               ContentBlock[]                  result;
+               int                                             len;
+               boolean[]                               isRouted=new boolean[1];
+               boolean[]                               doForward=new 
boolean[1];
+               IndirectionTableEntry   ite;
+               int                                             nfCase,i,rcount;
+               HashCode160                             hc;
+
+               ite = ROUTING_indTable_[computeRoutingIndex(query)];
+               synchronized(ite.lookup_exclusion) {
+                       nfCase = needsForwarding(query,
+                                       null,
+                                       ttl,
+                                       prio,
+                                       sender,
+                                       sock,
+                                       isRouted,
+                                       doForward);
+
+                       debug("Needs forwarding decided for "+((sock == null) ? 
"remote" : "LOCAL")+
+                               " query "+query.toHex()+" 
("+computeRoutingIndex(query)+", ttl "+ttl+
+                               ", pri "+prio+"): case "+nfCase+" 
("+(doForward[0] ? "FWD" : "")+", "+(isRouted[0] ? "ROUTE" : "")+")");
+
+                       if ( (sender != null) && !isRouted[0]) {
+                               return false; // if we can't route, forwarding 
never makes any sense
+                       }
+
+                       if (!superHash && !singleBloomFilter.test(query)) {
+                               return doForward[0]; // content not available 
locally,  just route
+                               }
+
+                       result = manager.retrieveContent(query,ce,prio,sender 
== null);
+                       if (result==null) {
+                               return doForward[0]; // bloomfilter was wrong, 
content not there
+                               }
+
+                       len=result.length;
+                       if (len == ContentBlock.SIZE) {
+                               
hc=HashCode160.create(PersistentHelper.toBytes(result[0]));
+                               if (ite.hasSeen()) {
+                                       if (hc.equals(ite.getSeen(0))) {
+                                               log(Level.SEVERE,"Lookup 
produced result already seen. Case: "+nfCase+".");
+                                               }
+                                       }
+                               }
+
+                       if (sender != null) {
+                               if (ce.type == ContentIndex.LOOKUP_TYPE_3HASH) {
+                                       if 
(!policy.checkAnonymityPolicy(CSMessage.IS_RESULT_3HASH,P2P3HashResult.SIZE)) {
+                                               return doForward[0]; // policy 
says: no direct response, but routing is ok!
+                                               }
+                                       }
+                               else {
+                                       if 
(!policy.checkAnonymityPolicy(CSMessage.IS_RESULT_CHK,P2PChkResult.SIZE)) {
+                                               return doForward[0]; // policy 
says: no direct response, but routing is ok
+                                               }
+                                       }
+                               }
+
+                       switch (ce.type) {
+                               case ContentIndex.LOOKUP_TYPE_CHK:
+                               case ContentIndex.LOOKUP_TYPE_CHKS:
+                                       if (len != ContentBlock.SIZE) {
+                                               log(Level.WARNING,"Local CHK 
content had bad size : "+len+".");
+                                               break;
+                                               }
+                                       if (sock != null) {
+                                               
tellClientCHKReply(sock,result[0]);
+                                               doForward[0]=false; // purely 
local handling!
+                                               }
+                                       if (sender!=null) {
+                                               queueCHKReply(sender,result[0]);
+                                               }
+                                       doForward[0]=false; // we have the one 
and only answer
+                                       break;
+
+                               case ContentIndex.LOOKUP_TYPE_3HASH:
+                                       byte[]  
tmp=PersistentHelper.toBytes(result[0]);
+                                       ContentBlock    res;
+
+                                       rcount = len / ContentBlock.SIZE;
+                                       if (rcount * ContentBlock.SIZE != len) {
+                                               log(Level.WARNING,"Database 
returned a 3HASH result that is not multiple of 1k ("+len+") ! Database 
corrupted ?");
+                                               break;
+                                               }
+
+                                       if (sock!=null) {
+                                               for (i=0; i<rcount; i++) {
+                                                       res=(ContentBlock) 
PersistentHelper.readFully(ContentBlock.class,ByteBuffer.wrap(tmp,i*ContentBlock.SIZE,ContentBlock.SIZE));
+                                                       
tellClient3HashReply(sock,ce.hash,res);
+                                                       }
+                                               }
+
+                                       if (sender!=null) {
+                                               for (i=0; i<rcount; i++) {
+                                                       res=(ContentBlock) 
PersistentHelper.readFully(ContentBlock.class,ByteBuffer.wrap(tmp,i*ContentBlock.SIZE,ContentBlock.SIZE));
+                                                       
queue3HashReply(sender,ce.hash,res);
+                                                       }
+                                               }
+                                       break;
+
+                               default:
+                                       log(Level.FINEST,"Query lookup produced 
unexpected type "+ce.type+" !");
+                                       break;
+                               }
+                       }
+               return doForward[0];
+       }
+
+       /**
+        * Execute a namespace query. Tests if the query can be routed. If yes,
+        * the query is added to the routing table and the content is looked
+        * for locally. If the content is available locally, a deferred
+        * response is simulated with a cron job and the local content is
+        * marked as valueable. The method returns true if the query should
+        * subsequently be routed to other peers.
+        *
+        * @param sender next hop in routing of the reply
+        * @param sock client socket if we are ultimate receiver
+        * @param prio the effective priority of the query
+        * @param ttl the relative ttl of the query
+        * @param query the query itself
+        * @param namespace for which namespace
+        * @return true if the query should be routed further, false if not.
+        */
+
+       protected boolean execNSQuery( HostIdentity sender, CSSession sock, int 
prio, int ttl, HashCode160 query, HashCode160 namespace )
+       {
+               ContentIndex                    ce=new ContentIndex();
+               ContentBlock[]                  result;
+               int                                             len;
+               HashCode160                             hc;
+               boolean[]                               isRouted=new boolean[1];
+               boolean[]                               doForwarding=new 
boolean[1];
+               int                                             k;
+               IndirectionTableEntry   ite;
+
+               debug("Received NS query for 
"+namespace.toHex()+"/"+query.toHex()+".");
+
+               ite = ROUTING_indTable_[computeRoutingIndex(query)];
+               synchronized(ite.lookup_exclusion) {
+                       
needsForwarding(query,namespace,ttl,prio,sender,sock,isRouted,doForwarding);
+                       }
+               if (!isRouted[0]) {
+                       return false;
+                       }
+               if (!singleBloomFilter.test(query)) {
+                       debug("Bloomfilter test says content not available 
locally.");
+                       return doForwarding[0]; // content not available 
locally, just route
+                       }
+
+               result=manager.retrieveContent(query,ce,prio,sender == null);
+               if (result==null) {
+                       debug("Bloomfilter test wrong, DB lookup failed.");
+                       return doForwarding[0]; // bloomfilter was wrong, 
content not there
+                       }
+
+               len=result.length;
+               if (ce.type != ContentIndex.LOOKUP_TYPE_SBLOCK) {
+                       return doForwarding[0];
+                       }
+
+               if (sender != null) {
+                       if 
(!policy.checkAnonymityPolicy(CSMessage.IS_RESULT_SBLOCK,P2PSBlockResult.SIZE)) 
{
+                               debug("Anonymity policy denies reply at this 
time.");
+                               return doForwarding[0]; // policy says: no 
direct response, but routing is ok
+                               }
+                       }
+
+               if (0!=(len % ContentBlock.SIZE)) {
+                       log(Level.WARNING,"Local SBLOCK content had bad size 
"+len+".");
+                       return doForwarding[0];
+                       }
+
+               EncryptedSBlock sblock;
+               byte[]  tmp;
+
+               for (k=(len/ContentBlock.SIZE)-1; k>=0; k--) {
+                       tmp=PersistentHelper.toBytes(result[k]);
+                       sblock=(EncryptedSBlock) 
PersistentHelper.readFully(EncryptedSBlock.class,ByteBuffer.wrap(tmp,k*ContentBlock.SIZE,ContentBlock.SIZE));
+
+                       hc=sblock.getNameSpace();
+                       if (! namespace.equals(hc)) {
+                               log(Level.WARNING,"WARNING: namespace mismatch 
(should be rare but can theoretically happen).");
+                               return doForwarding[0];
+                               }
+                       if (sender != null) {
+                               queueSBLOCKReply(sender,sblock);
+                               }
+                       if (sock != null) {
+                               tellClientSBLOCKReply(sock,sblock);
+                               doForwarding[0] = false;
+                               }
+                       }
+               return doForwarding[0];
+       }
+
+       /**
+        * Handle query for current average routing priority.
+        *
+        * @param sock
+        * @param msg
+        * @return
+        */
+
+       public boolean csHandleRequestAvgPriority( CSSession sock, 
CSGetAvgPriority msg )
+       {
+               int i;
+               IndirectionTableEntry  ite;
+               int j = 0;
+               long priSum = 0;
+
+               for (i=0; i<MIN_INDIRECTION_TABLE_SIZE; i++) {
+                       ite = ROUTING_indTable_[i];
+                       synchronized(ite.lookup_exclusion) {
+                               if (ite.ttl!=0 && ite.hasWaitingHosts() && 
!ite.hasClients() ) {
+                                       /* only count entries that do NOT 
correspond to local requests in any way... */
+                                       priSum += ite.priority;
+                                       j++;
+                                       }
+                               }
+                       }
+               if (j > 0)
+                       priSum = priSum / j;
+               return sock.send(new CSResult((int) priSum));
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/esed2/AFSConstants.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/esed2/AFSConstants.java    
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/esed2/AFSConstants.java    
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,87 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs.esed2;
+
+import org.gnu.freeway.util.*;
+
+/**
+ *
+ */
+
+public interface AFSConstants
+{
+       public static final String      GNUNET_URI_PREFIX_AFS   =       
"gnunet://afs/";
+
+       /* major/minor format versions (current) */
+       public static final int ROOT_MINOR_VERSION              =       0;
+       public static final int ROOT_MAJOR_VERSION              =       1;
+
+       /* major/minor format versions (current) */
+       public static final int SBLOCK_MINOR_VERSION    =       0;
+       public static final int SBLOCK_MAJOR_VERSION    =       2;
+
+       /** Fixed SBlock updateInterval codes. Positive values are interpreted 
as durations (in seconds) for periodical updates. */
+       public static final int SBLOCK_UPDATE_SPORADIC  =       -1;
+       public static final int SBLOCK_UPDATE_NONE              =       0;
+
+
+       /** Size of the Blocks we slice file data into (DBlocks and IBlocks). 
Never change this ! */
+       public static final int CONTENT_SIZE    =       1024;
+
+
+       /** Block is freshly created, nothing has been done. */
+       public static final int BLOCK_CREATED                           =       
0;
+
+       /** We know the correct block data and is is on the drive (and in 
memory if data != null) */
+       public static final int BLOCK_PRESENT                           =       
1;
+
+       /** We do not know the correct data, but we have not done a request yet.
+        It may be that we can construct the data from the children (if they 
are present). */
+       public static final int BLOCK_NOT_PRESENT                       =       
2;
+
+       /** We have a request pending for this block (either with the parent if 
parent != null)
+        or a direct request if parent == null. */
+       public static final int BLOCK_PENDING                           =       
3;
+
+       /** This block is present and all children (transitively) are also 
present. */
+       public static final int BLOCK_CHILDREN_PRESENT          =       4;
+
+       /** This iblock has a super-query pending. */
+       public static final int BLOCK_SUPERQUERY_PENDING        =       5;
+
+       /** This block is done (about to be freed). */
+       public static final int BLOCK_DONE                                      
=       6;
+
+       /** This block shall not be freed, even if all children are dead. */
+       public static final int BLOCK_PERSISTENT                        =       
7;
+
+
+       /** by which amount do we decrement the TTL for simple forwarding / 
indirection of the query; in milli-seconds.
+        Set somewhat in accordance to your network latency (above the time 
it'll take you to send a packet and get a reply). */
+       public static final long        TTL_DECREMENT   =       
Scheduler.SECS_5;
+
+       /** Highest TTL allowed ? (equivalent of 25-50 HOPS distance !) */
+       public static final long        MAX_TTL                 =       (100 * 
TTL_DECREMENT);
+
+       /** After how many retries do we print a warning ? */
+       public static final int         MAX_TRIES               =       50;
+
+       /* what is the context in which a root-node was discovered? */
+       public static final int DIR_CONTEXT_SEARCH              =       1;
+       public static final int DIR_CONTEXT_INSERT              =       2;
+       public static final int DIR_CONTEXT_DIRECTORY   =       4;
+       public static final int DIR_CONTEXT_INSERT_SB   =       8;
+
+       public static final int DIR_CONTEXT_ALL                 =       
(DIR_CONTEXT_SEARCH|DIR_CONTEXT_INSERT|DIR_CONTEXT_DIRECTORY|DIR_CONTEXT_INSERT_SB);
+
+       /* see also: http://www.w3.org/TR/PNG#R.PNG-file-signature */
+       public static final String      GNUNET_DIRECTORY_MAGIC  =       
"\211GND\r\n\032\n";
+       public static final String      GNUNET_DIRECTORY_EXT    =       ".gnd";
+       public static final String      GNUNET_DIRECTORY_MIME   =       
"application/gnunet-directory";
+
+       /** default size of the query record bitmap: 16 byte = 128 bit */
+       public static final int BITMAP_SIZE     =       16;
+
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/esed2/AFSUtils.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/esed2/AFSUtils.java        
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/esed2/AFSUtils.java        
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,121 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs.esed2;
+
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ *
+ */
+
+public class AFSUtils extends Object
+{
+       private static Logger   logger;
+
+       static {
+               logger=Logger.getLogger(AFSUtils.class.getName());
+               }
+
+
+       /**
+        * Parse the keywords (join at spaces, separate at AND).
+        * @param keywords      the list of keywords
+        * @return                      the hashcodes of the keywords
+        */
+
+       public static HashCode160[] parseKeywords( String[] keywords )
+       {
+               HashCode160[]   h;
+               List                    list;
+               StringBuffer    buf;
+               String                  str;
+               int                             i;
+
+               list=new ArrayList();
+
+               buf=new StringBuffer();
+               for (i=0; i<keywords.length; i++) {
+                       buf.setLength(0);
+                       while (i<keywords.length && (!keywords[i].equals("AND") 
|| i==keywords.length-1)) {
+                               buf.append(keywords[i++]);
+                               buf.append(" ");
+                               }
+
+                       if (buf.length()>0) {
+                               buf.setLength(buf.length()-1);
+                               list.add(buf.toString());
+                               }
+                       }
+
+               h=new HashCode160[list.size()];
+               for (i=0; i<h.length; i++) {
+                       str=(String) list.get(i);
+
+                       logger.log(Level.FINEST,"Keyword : \""+str+"\"");
+                       h[i]=HashCode160.create(str);
+                       }
+               return h;
+       }
+
+       /**
+        * Build an initial set of query messages from the list of keywords.
+        *
+        * @param keywords      the keywords (or keys)
+        * @return                      the resulting query messages
+        */
+
+       public static CSQuery[] buildMessages( HashCode160[] keywords )
+       {
+               HashCode160     doubleHash;
+               CSQuery[]       messages;
+               int                     i;
+
+               messages=new CSQuery[keywords.length];
+               for (i=0; i<messages.length; i++) {
+                       messages[i]=new CSQuery();
+                       messages[i].setPriorityAndTTL(
+                               5+Crypto.nextInt(20),
+                               (int) 
(AFSConstants.TTL_DECREMENT*4+Crypto.nextInt((int) 
Scheduler.seconds(messages.length*5)))
+                               );
+
+                       
doubleHash=HashCode160.create(PersistentHelper.toBytes(keywords[i]));
+                       
messages[i].addQuery(HashCode160.create(PersistentHelper.toBytes(doubleHash)));
+                       }
+               return messages;
+       }
+
+       public static String get( ByteBuffer buf, int len )
+       {
+               byte[]  b;
+               int             n;
+
+               b=new byte[len];
+               buf.get(b);
+
+               for (n=0; n<b.length && b[n]!=0; n++) {}
+               return new String(b,0,n);
+       }
+
+       public static void put( String str, ByteBuffer buf, int len )
+       {
+               byte[]  b;
+               int             n;
+
+               b=str.getBytes();
+               n=Math.min(b.length,len-1);
+
+               buf.put(b,0,n);
+               while (n<len) {
+                       buf.put((byte) 0);
+                       n++;
+                       }
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/esed2/Block.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/esed2/Block.java   2005-01-31 
23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/esed2/Block.java   2005-02-01 
01:07:27 UTC (rev 137)
@@ -0,0 +1,552 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs.esed2;
+
+import org.gnu.freeway.util.*;
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * Shared structure used in the internal objectish representation
+ * of all blocks (DBlocks and IBlocks) in the merkle-tree.
+ * Merkle-tree-CHK file encoding for anonymous file sharing
+ *
+ * Note that the current implementation no longer uses the exact
+ * scheme from the ESED paper. Extensive documentation is forthcoming,
+ * for now see http://www.ovmj.org/GNUnet/encoding.php3
+ */
+
+public abstract class Block extends LoggedObject implements AFSConstants
+{
+       /** The parent node in the file-tree, null for the node on top of the 
file-tree. */
+       private IBlock                  parent;
+
+       /** The total size of the file. */
+       private int                             filesize;
+
+       /** Position of the block relative to the beginning of the file. */
+       private int                             pos;
+
+       /** How many bytes in data are actual data (not padding)? Set to 0 to 
indicate that the download of this block is complete. */
+       private int                             len;
+
+       /** Pointer to the data of this block, null if the data is not yet 
available. */
+       private Persistent              data;
+
+       /** Hashes of the plaintext block (key) and the encrypted block 
(query). */
+       private ChkHashes               chk;
+
+       /** See BLOCK_XXX constants. */
+       private int                             status;
+
+
+       protected Block( int size, int length )
+       {
+               super(true);
+               parent=null;
+               filesize=size;
+               pos=0;
+               len=length;
+               data=null;
+               chk=null;
+               status=BLOCK_CREATED;
+
+               assert(length>0 && length<=ContentBlock.SIZE) : "Invalid block 
size ("+length+").";
+       }
+
+       protected Block( Block b, int offset, int length )
+       {
+               this(b.filesize,length);
+               parent=(IBlock) b;
+               pos=offset;
+       }
+
+       protected Block( Block b )
+       {
+               super(true);
+               filesize=b.filesize;
+               pos=b.pos;
+               chk=(ChkHashes) PersistentHelper.copy(b.chk);
+               len=b.len;
+               data=PersistentHelper.copy(b.data);
+               parent=b.parent;
+               status=b.status;
+       }
+
+       public String toString()
+       {
+               return "Block";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public int getDataLength()
+       {
+               return len;
+       }
+
+       public boolean hasData()
+       {
+               return data!=null;
+       }
+
+       public byte[] getRawData()
+       {
+               //todo: bufferiser
+               return (data!=null ? PersistentHelper.toBytes(data) : new 
byte[] {});
+       }
+
+       public int getDataCRC()
+       {
+               return Crypto.crc32(getRawData(),0,len);
+       }
+
+       public Persistent getData()
+       {
+               return data;
+       }
+
+       public Persistent getData( Class c )
+       {
+               //todo: optimiser
+               return 
PersistentHelper.readFully(c,ByteBuffer.wrap(getRawData()));
+       }
+
+       public void setData( Persistent p )
+       {
+               data=p;
+               //todo: len par rapport a p.getByteSize() ???
+       }
+
+       public void clearData()
+       {
+               data=null;
+       }
+
+       protected boolean loadData( NodeContext nc, boolean warning )
+       {
+               int     n;
+               ContentBlock    tmp;
+
+               tmp=new ContentBlock();
+
+               n=nc.ioc.read(getDepth(),pos,tmp.content,len);
+//debug("... load data (pos="+pos+",len="+len+") = "+n);
+               if (n!=len) {
+                       if (warning) {
+                               log(Level.WARNING,"Read from file did not 
return expected size "+len+", but "+n+".");
+                               }
+                       return false;
+                       }
+               data=tmp;
+               return true;
+       }
+
+       public boolean writeData( NodeContext nc )
+       {
+               int     n;
+
+               n=nc.ioc.write(getDepth(),pos,getRawData(),len);
+               if (n!=len) {
+                       log(Level.SEVERE,"Writing to file failed 
("+len+","+n+") !");
+                       return false;
+                       }
+               return true;
+       }
+
+       public IBlock getParent()
+       {
+               return parent;
+       }
+
+       public void detach()
+       {
+               parent=null;
+       }
+
+       public boolean checkTopCRC( int crc )
+       {
+               return Crypto.crc32(getRawData(),0,len)==crc;
+       }
+
+       public HashCode160 getKey()
+       {
+               return chk.key;
+       }
+
+       public HashCode160 getQuery()
+       {
+               return chk.query;
+       }
+
+       public void setKeyAndQuery( ChkHashes c )
+       {
+               chk=(ChkHashes) PersistentHelper.copy(c);
+       }
+
+       public void setKeyAndQuery( FileIdentifier fid )
+       {
+               chk=new ChkHashes();
+               chk.query=fid.getFileQuery();
+               chk.key=fid.getFileKey();
+       }
+
+       public ChkHashes getKeyAndQuery()
+       {
+               return chk;
+       }
+
+       public boolean isStatus( int s )
+       {
+               return status==s;
+       }
+
+       public int getStatus()
+       {
+               return status;
+       }
+
+       public void setStatus( int s )
+       {
+               status=s;
+       }
+
+       public abstract int getDepth();
+
+       public int getFilePosition()
+       {
+               return pos;
+       }
+
+       public int getFileSize()
+       {
+               return filesize;
+       }
+
+       /**
+        * Encrypt this block and initialize
+        * this.chk and return the encrpyted data (edata)
+        * @return
+        */
+
+       protected ContentBlock encrypt()
+       {
+               ContentBlock    edata;
+               byte[]                  bdata;
+
+               bdata=getRawData();
+//System.out.println("CHK="+chk+" len = "+len);
+               chk=new ChkHashes();
+               chk.key=HashCode160.create(bdata,0,len);
+
+               Arrays.fill(bdata,len,ContentBlock.SIZE,(byte) 0);
+               edata = new ContentBlock();
+               if (!new ContentEncoding().encryptContent(bdata,chk.key,edata)) 
{
+                       trace("Encryption failed !?");
+                       return null;
+                       }
+               
chk.query=HashCode160.create(PersistentHelper.toBytes(edata),0,ContentBlock.SIZE);
+               return edata;
+       }
+
+       /**
+        * This block has received a CHK reply for a block. Decrypt.
+        *
+        * @param query the query for which reply is the answer
+        * @param reply the reply
+        * @return OK if the reply was valid, false on error
+        */
+
+       protected boolean receivedChk( HashCode160 query, CSResultChk reply )
+       {
+               byte[]          tmp;
+               HashCode160     hc;
+
+               assert(chk.query.equals(query)) : "invoked with reply for a 
different block. This should not be.";
+
+               tmp=reply.decrypt(chk.key);
+               if (tmp==null) {
+                       trace("Decryption failed !?");
+                       return false;
+                       }
+               setData(new ContentBlock(tmp));
+
+               hc=HashCode160.create(getRawData(),0,len);
+               if (!chk.key.equals(hc)) {
+                       data = null;
+                       log(Level.SEVERE,"Decrypted content does not match key. 
This is either a bug or a maliciously inserted file. Download aborted.");
+                       return false;
+                       }
+               return true;
+       }
+
+       /**
+        * Delete a block (send appropriate message to gnunetd).
+        *
+        * @param nc the context
+        * @param sock the socket to talk to gnunetd
+        * @return OK on success, false on error
+        */
+
+       public boolean delete( NodeContext nc, CSSession sock )
+       {
+               ContentBlock            edata;
+               CSUnindexBlock  request;
+               CSResult                        rv;
+
+               edata = encrypt();
+               if (sock == null) {
+                       return true;    // fake insert only
+                       }
+
+               if (nc.index != 0) {
+                       request=new CSUnindexBlock();
+                       request.contentIndex.importance= nc.priority;
+                       request.contentIndex.type= 
ContentIndex.LOOKUP_TYPE_CHKS;
+                       request.contentIndex.fileNameIndex= nc.index;
+                       request.contentIndex.fileOffset= pos;
+                       request.contentIndex.hash=(HashCode160) 
PersistentHelper.copy(chk.query);
+                       if (!sock.send(request)) {
+                               log(Level.WARNING,"Could not send unindex 
information to gnunetd. Is gnunetd running ?");
+                               return false;
+                               }
+
+                       rv=(CSResult) sock.receive(CSResult.class);
+                       if (rv==null) {
+                               log(Level.WARNING,"Server did not send 
confirmation of deletion.");
+                               return false;
+                               }
+                       if (!rv.isOkay()) {
+                               log(Level.WARNING,"Server could not perform 
unindexing (content already removed ?).");
+                               return false;
+                               }
+                       return true;
+                       }
+               return deleteCHKBlock(sock,edata,nc.priority);
+       }
+
+       /**
+        * Insert a CHK block (insert, not index!)
+        *
+        * @param eblock the block to insert
+        * @param priority the priority to use
+        * @param sock the socket to talk to gnunetd
+        * @return OK on success, false on error
+        */
+
+       protected boolean insertCHKBlock( CSSession sock, ContentBlock eblock, 
int priority )
+       {
+               CSInsertChk     request;
+               CSResult                rv;
+
+               if (sock == null)
+                       return true;    // fake insert
+
+               request = new CSInsertChk(priority,eblock.content);
+
+               if (!sock.send(request)) {
+                       log(Level.WARNING,"Could not send index information to 
gnunetd. Is gnunetd running ?");
+                       return false;
+                       }
+
+               rv=(CSResult) sock.receive(CSResult.class);
+               if (rv==null) {
+                       log(Level.WARNING,"Server did not send confirmation of 
insertion.");
+                       return false;
+                       }
+               if (!rv.isOkay()) {
+                       log(Level.WARNING,"Server could not perform 
insertion.");
+                       return false;
+                       }
+               return true;
+       }
+
+       /**
+        * Delete a CHK block.
+        *
+        * @param eblock the block to insert
+        * @param priority the priority to use
+        * @param sock the socket to talk to gnunetd
+        * @return OK on success, false on error
+        */
+
+       protected boolean deleteCHKBlock( CSSession sock, ContentBlock eblock, 
int priority )
+       {
+               CSDeleteChk     request;
+               CSResult                rv;
+
+               if (sock == null)
+                       return true;    // fake insert
+
+               request =new CSDeleteChk();
+               request.importance = priority;
+               
System.arraycopy(eblock.content,0,request.content,0,ContentBlock.SIZE);
+
+               if (!sock.send(request)) {
+                       log(Level.WARNING,"Could not send delete information to 
gnunetd. Is gnunetd running ?");
+                       return false;
+                       }
+
+               rv=(CSResult) sock.receive(CSResult.class);
+               if (rv==null) {
+                       log(Level.WARNING,"Server did not send confirmation of 
deletion.");
+                       return false;
+                       }
+
+               if (!rv.isOkay()) {
+                       log(Level.WARNING,"Server could not perform deletion.");
+                       return false;
+                       }
+               return true;
+       }
+
+       /**
+        * Send a single query via the RequestManager to gnunetd.
+        *
+        * @param rm the rm used to issue the query
+        * @param receiver the receiver to call on the reply
+        * @param nc the context
+        * @param query the query to perform
+        */
+
+       protected void issueQuery( RequestManager rm, Listener receiver, 
NodeContext nc, HashCode160 query )
+       {
+               CSQuery msg;
+
+               msg = new CSQuery();
+               msg.setPriorityAndTTL(1,1);
+               msg.addQuery(query);
+
+debug("issueQuery +++ CSQuery (2): "+msg);
+
+               rm.request(this,receiver,nc,msg);
+       }
+
+       /**
+        * Print the block summary (for debugging)
+        * @param indent
+        */
+
+       public abstract void print( int indent );
+
+       /**
+        * Free the associated resources of this Block. DOES ALSO free the
+        * memory occupied by the Block struct itself!
+        *
+        * @param rm reference to the RequestManager for requests
+        */
+
+       public void destroy( RequestManager rm )
+       {
+               /* better make sure that we have no request pending... */
+               if (rm != null) {       /* rm == null for gnunet-insert! */
+                       rm.assertDead(this);
+                       if (rm.top == this) {
+                               rm.top=null;
+                               }
+                       }
+
+               if (parent != null) {
+                       if (parent.childrenDestroyed(this)) {
+                               parent.destroy(rm);
+                               }
+                       }
+               data=null;
+       }
+
+       /**
+        * Check if this block is already present, if yes, loads it.
+        * @param nc the context
+        * @return YES if the block is present, NO if not
+        */
+
+       public abstract boolean check( NodeContext nc );
+
+       /**
+        * Download this node (and the children below). Note that the
+        * processing is asynchronous until the pmodel is called with position
+        * == total (and thus no more requests are pending) or the request
+        * manager is aborted by the user.
+        * @param nc the context
+        * @param rm the request manager
+        */
+
+       public abstract void download( NodeContext nc, RequestManager rm );
+
+       /**
+        * Insert the current block into the network. Implementations
+        * are also responsible for updating the corresponding fields
+        * of the parent node (of course, except if the parent is
+        * null in the case of the top-node in the tree).<p>
+        * Inner nodes first call the respective inserter methods for
+        * their children.<p>
+        *
+        * Insert a block (send appropriate message to gnunetd).
+        * This method encrypts the block and then sends an
+        * index or insertion request to gnunetd, depending on
+        * the configuration.
+        *
+        * @param nc the node context/the context (gives us the priority)
+        * @param sock the socket to use to talk to the core/the socket to talk 
to gnunetd, null if
+        *        we just do a "fake" insert to compute the tree in memory
+        * @return OK on success, false on error
+        */
+
+       public boolean insert( NodeContext nc, CSSession sock )
+       {
+               ContentBlock    edata;
+               CSIndexBlock    request;
+               CSResult                rv;
+               ContentIndex    index;
+
+               edata = encrypt();
+               if (sock == null) {
+                       return true;    // fake insert only
+                       }
+
+               if (nc.index != 0) {
+                       index=new ContentIndex();
+                       index.importance=nc.priority;
+                       index.type=ContentIndex.LOOKUP_TYPE_CHKS;
+                       index.fileNameIndex=nc.index;
+                       index.fileOffset=pos;
+                       index.hash=(HashCode160) 
PersistentHelper.copy(chk.query);
+
+                       request=new CSIndexBlock(index);
+                       if (!sock.send(request)) {
+                               log(Level.WARNING,"Could not send index 
information to gnunetd. Is gnunetd running ?");
+                               return false;
+                               }
+                       rv=(CSResult) sock.receive(CSResult.class);
+                       if (rv==null) {
+                               log(Level.WARNING,"Server did not send 
confirmation of insertion.");
+                               return false;
+                               }
+                       if (!rv.isOkay()) {
+                               log(Level.WARNING,"Server could not perform 
indexing.");
+                               return false;
+                               }
+                       return true;
+                       }
+               return insertCHKBlock(sock,edata,nc.priority);
+       }
+
+       public abstract boolean receive( HashCode160 query, CSResultChk reply, 
RequestManager rm, NodeContext nc );
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public static Block create( int size )
+       {
+               assert(size>0) : "size ("+size+") not allowed to be <= 0";
+
+               return (size>ContentBlock.SIZE ? (Block) new IBlock(size) : 
(Block) new DBlock(size));
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/esed2/CSDelete3Hash.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/esed2/CSDelete3Hash.java   
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/esed2/CSDelete3Hash.java   
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,75 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs.esed2;
+
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+
+/**
+ * Structure for an incoming request messages from the local TCP link
+ * to add content to the node.
+ */
+
+public class CSDelete3Hash extends CSMessage
+{
+       public static final int SIZE    =       
8+HashCode160.SIZE+ContentBlock.SIZE;
+
+       /** The (initial) priority of the data. */
+       public int                              importance;
+
+       /** The doubleHash of the plaintext. */
+       public HashCode160              doubleHash;
+
+       /** The data to insert */
+       public ContentBlock             content;
+
+
+       public CSDelete3Hash()
+       {
+               super(IS_DELETE_3HASH);
+               importance=0;
+               doubleHash=new HashCode160();
+               content=new ContentBlock();
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public int getByteSize()
+       {
+               return SIZE;
+       }
+
+       public void readBytes( ByteBuffer buf, ErrorReporter err )
+       {
+               int     size,type;
+
+               size=buf.getShort() & 0x0000ffff;
+               err.reportIf(size!=SIZE,"bad size");
+
+               type=buf.getShort() & 0x0000ffff;
+               err.reportIf(type!=IS_DELETE_3HASH,"bad type !");
+
+               importance=buf.getInt();
+               doubleHash.readBytes(buf,err);
+               content.readBytes(buf,err);
+       }
+
+       public void writeBytes( ByteBuffer buf )
+       {
+               buf.putShort((short) SIZE);
+               buf.putShort((short) IS_DELETE_3HASH);
+               buf.putInt(importance);
+               doubleHash.writeBytes(buf);
+               content.writeBytes(buf);
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/esed2/CSDeleteChk.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/esed2/CSDeleteChk.java     
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/esed2/CSDeleteChk.java     
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,68 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs.esed2;
+
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+
+/**
+ * Structure for an incoming request messages from the local TCP link
+ * to add content to the node.
+ */
+
+public class CSDeleteChk extends CSMessage
+{
+       public static final int SIZE    =       8+ContentBlock.SIZE;
+
+       /** The (initial) priority of the data */
+       public int                      importance;
+
+       /** The data to insert */
+       public ContentBlock     content;
+
+
+       public CSDeleteChk()
+       {
+               super(IS_DELETE_CHK);
+               importance=0;
+               content=new ContentBlock();
+       }
+
+       public String toString()
+       {
+               return "xxx";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public int getByteSize()
+       {
+               return SIZE;
+       }
+
+       public void readBytes( ByteBuffer buf, ErrorReporter err )
+       {
+               int     size,type;
+
+               size=buf.getShort() & 0x0000ffff;
+               err.reportIf(size!=SIZE,"bad size");
+
+               type=buf.getShort() & 0x0000ffff;
+               err.reportIf(type!=IS_DELETE_CHK,"bad type !");
+
+               importance=buf.getInt();
+               content.readBytes(buf,err);
+       }
+
+       public void writeBytes( ByteBuffer buf )
+       {
+               buf.putShort((short) SIZE);
+               buf.putShort((short) IS_DELETE_CHK);
+               buf.putInt(importance);
+               content.writeBytes(buf);
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/esed2/CSGetAvgPriority.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/esed2/CSGetAvgPriority.java        
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/esed2/CSGetAvgPriority.java        
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,53 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs.esed2;
+
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+
+/**
+ */
+
+public class CSGetAvgPriority extends CSMessage
+{
+       public static final int SIZE            =       4;
+
+
+       public CSGetAvgPriority()
+       {
+               super(IS_GET_AVG_PRIORITY);
+       }
+
+       public String toString()
+       {
+               return "Get average priority message";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public int getByteSize()
+       {
+               return SIZE;
+       }
+
+       public void readBytes( ByteBuffer buf, ErrorReporter err )
+       {
+               int     size,type;
+
+               size=buf.getShort() & 0x0000ffff;
+               err.reportIf(size!=SIZE,"invalid size !");
+
+               type=buf.getShort() & 0x0000ffff;
+               err.reportIf(type!=IS_GET_AVG_PRIORITY,"invalid type !");
+       }
+
+       public void writeBytes( ByteBuffer buf )
+       {
+               buf.putShort((short) SIZE);
+               buf.putShort((short) IS_GET_AVG_PRIORITY);
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexBlock.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexBlock.java    
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexBlock.java    
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,73 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs.esed2;
+
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+
+/**
+ * Structure for an incoming request messages from the local TCP link
+ * to add content to the INDEX of the node.
+ */
+
+public class CSIndexBlock extends CSMessage
+{
+       public static final int SIZE    =       4+ContentIndex.SIZE;
+
+       /** indexing information */
+       private ContentIndex    contentIndex;
+
+
+       public CSIndexBlock()
+       {
+               super(IS_INDEX_BLOCK);
+               contentIndex=new ContentIndex();
+       }
+
+       public CSIndexBlock( ContentIndex idx )
+       {
+               this();
+               contentIndex=idx;
+       }
+
+       public String toString()
+       {
+               return "Client/server index block 
[contentIndex="+contentIndex+"]";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public ContentIndex getContentIndex()
+       {
+               return contentIndex;
+       }
+
+       public int getByteSize()
+       {
+               return SIZE;
+       }
+
+       public void readBytes( ByteBuffer buf, ErrorReporter err )
+       {
+               int     size,type;
+
+               size=buf.getShort() & 0x0000ffff;
+               err.reportIf(size!=SIZE,"bad size");
+
+               type=buf.getShort() & 0x0000ffff;
+               err.reportIf(type!=IS_INDEX_BLOCK,"bad type !");
+
+               contentIndex.readBytes(buf,err);
+       }
+
+       public void writeBytes( ByteBuffer buf )
+       {
+               buf.putShort((short) SIZE);
+               buf.putShort((short) IS_INDEX_BLOCK);
+               contentIndex.writeBytes(buf);
+       }
+}

Added: freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexFile.java
===================================================================
--- freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexFile.java     
2005-01-31 23:47:23 UTC (rev 136)
+++ freeway/src/org/gnu/freeway/protocol/afs/esed2/CSIndexFile.java     
2005-02-01 01:07:27 UTC (rev 137)
@@ -0,0 +1,79 @@
+/**
+ * @PROJECT_INFO@
+ */
+
+package org.gnu.freeway.protocol.afs.esed2;
+
+import org.gnu.freeway.util.crypto.*;
+import org.gnu.freeway.util.io.*;
+import org.gnu.freeway.util.net.*;
+
+import java.nio.*;
+
+/**
+ * Structure for an incoming request messages from the local TCP link
+ * to add a filename to the list of directly shared files
+ */
+
+public class CSIndexFile extends CSMessage
+{
+       public static final int SIZE            =       8+HashCode160.SIZE;
+
+       /** Size of the file in bytes. */
+       public long                     filesize;
+
+       /** RIPE160 hash of the entire file (to avoid duplicates !). */
+       public HashCode160      hash;
+
+
+       public CSIndexFile()
+       {
+               super(IS_INDEX_FILE);
+               filesize=0;
+               hash=new HashCode160();
+       }
+
+       public CSIndexFile( FileLocation f )
+       {
+               this();
+               filesize=f.getSize();
+               hash=f.getHash();
+       }
+
+       public String toString()
+       {
+               return "Client/server index file [filesize="+filesize+", 
hash="+hash+"]";
+       }
+
+
+       
////////////////////////////////////////////////////////////////////////////////////////////////
+
+       public int getByteSize()
+       {
+               return SIZE;
+       }
+
+       public void readBytes( ByteBuffer buf, ErrorReporter err )
+       {
+               int     size,type;
+
+               size=buf.getShort() & 0x0000ffff;
+               err.reportIf(size!=SIZE,"bad size !");
+
+               type=buf.getShort() & 0x0000ffff;
+               err.reportIf(type!=IS_INDEX_FILE,&quo