propagate from branch 'i2p.i2p.zzz.test' (head 8424049f1510c378ac5c6d74a51fcc914f6082f5)
to branch 'i2p.i2p' (head d14d24978b11daeff7d37002b7ac3ec5b5535475)
30
Slackware/README
Normal file
@ -0,0 +1,30 @@
|
||||
ou will need atleast monotone > = 0.41 to get the most recent build source
|
||||
and connect it to an already running i2p router.
|
||||
|
||||
OR:
|
||||
|
||||
You may download the actual "stable" source from
|
||||
http://code.google.com/p/i2p/downloads/list
|
||||
|
||||
You will need to follwing tools to build the i2p and i2p-base packages:
|
||||
|
||||
bash >= 3.1.017
|
||||
requiredbuilder >= 0.16.3 ( http://www.stabellini.net/requiredbuilder.html )
|
||||
jre >= 6u11
|
||||
jdk >= 6u11
|
||||
apache-ant >= 1.7.1
|
||||
perl >= 5.10.0
|
||||
python >= 2.5.2
|
||||
|
||||
Reccomended:
|
||||
monotone >= 0.41 ( http://pkgs.dr.ea.ms )
|
||||
|
||||
See also:
|
||||
|
||||
i2p/readme.txt
|
||||
|
||||
AND
|
||||
|
||||
i2p-base/readme.txt
|
||||
|
||||
for information and handy tips.
|
8
Slackware/i2p-base/build.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<project basedir="." default="slackpkg">
|
||||
<target name="slackpkg">
|
||||
<echo message="Building Slackware package." />
|
||||
<exec executable="./i2p-base.SlackBuild">
|
||||
</exec>
|
||||
</target>
|
||||
</project>
|
45
Slackware/i2p-base/doinst.sh
Normal file
@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
touch /etc/rc.d/rc.local
|
||||
touch /etc/rc.d/rc.local_shutdown
|
||||
|
||||
I2PRCA=`grep -c /etc/rc.d/rc.local -e i2p`
|
||||
I2PRCB=`grep -c /etc/rc.d/rc.local_shutdown -e i2p`
|
||||
|
||||
echo
|
||||
|
||||
if [ $I2PRCA -eq 0 ] ; then
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
|
||||
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
|
||||
echo "fi" >> /etc/rc.d/rc.local
|
||||
echo "/etc/rc.d/rc.local modified."
|
||||
else
|
||||
echo "/etc/rc.d/rc.local looks OK"
|
||||
fi
|
||||
|
||||
if [ $I2PRCB -eq 0 ] ; then
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
|
||||
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "fi" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "/etc/rc.d/rc.local_shutdown modified."
|
||||
else
|
||||
echo "/etc/rc.d/rc.local_shutdown looks OK"
|
||||
fi
|
||||
|
||||
if [ -f /etc/rc.d/rc.i2p ] ; then
|
||||
if [ -x /etc/rc.d/rc.i2p ] ; then
|
||||
chmod +x /etc/rc.d/rc.i2p.new
|
||||
fi
|
||||
echo
|
||||
echo "It apears that you already have /etc/rc.d/rc.i2p"
|
||||
echo "You may wish to replace it with /etc/rc.d/rc.i2p.new"
|
||||
echo
|
||||
else
|
||||
mv /etc/rc.d/rc.i2p.new /etc/rc.d/rc.i2p
|
||||
echo
|
||||
echo "Installation finished. The i2p start/stop script has been"
|
||||
echo "installed on /etc/rc.d directory. You should chmod +x"
|
||||
echo '/etc/rc.d/rc.i2p to start it on boot.'
|
||||
echo
|
||||
fi
|
||||
|
||||
exit
|
42
Slackware/i2p-base/i2p-base.SlackBuild
Normal file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
# Heavily based on the Slackware 12.1 SlackBuild
|
||||
# Slackware build script for i2p
|
||||
|
||||
# PLEASE READ THIS:
|
||||
# Probably you will never have to update i2p packages with upgradepkg,
|
||||
# just because i2p have an auto-update function.
|
||||
# How to start i2p:
|
||||
# After installpkg command, doinst.sh will execute a postinstallation script
|
||||
# needed by i2p. After that you have to chmod +x /etc/rc.d/rc.i2p and start
|
||||
# i2p service with /etc/rc.d/rc.i2p start.
|
||||
# Now tell your browser to user this proxy: localhost on port 4444 and open
|
||||
# this page: http://localhost:7657/index.jsp
|
||||
# Here you can configure i2p, watch network status and navigate anonimously.
|
||||
# It's suggested to subscribe to various dns host, like i2host.i2p
|
||||
# For any additional information, visit i2host.i2p and forum.i2p
|
||||
|
||||
CWD=$(pwd)
|
||||
TMP=/tmp
|
||||
PKG=/$TMP/package-base-i2p
|
||||
rm -rf $PKG
|
||||
mkdir -p $PKG
|
||||
# put here installation dir, without first and last /
|
||||
# es: usr/local
|
||||
NAME=i2p-base
|
||||
VERSION=0.0.1
|
||||
BUILD=1sim
|
||||
ARCH=noarch
|
||||
INSTALL_DIR=opt
|
||||
cd $PKG
|
||||
chown -R root:root .
|
||||
|
||||
mkdir -p $PKG/etc/rc.d
|
||||
mkdir -p $PKG/install
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/i2prouter|g" $CWD/rc.i2p_def > $PKG/etc/rc.d/rc.i2p.new
|
||||
chmod 644 $PKG/etc/rc.d/rc.i2p.new
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/|g" $CWD/doinst.sh > $PKG/install/doinst.sh
|
||||
cat $CWD/slack-desc > $PKG/install/slack-desc
|
||||
|
||||
cd $PKG
|
||||
requiredbuilder -v -y -s $CWD $PKG
|
||||
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.tgz
|
27
Slackware/i2p-base/rc.i2p_def
Normal file
@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
# Start/stop i2p service.
|
||||
|
||||
i2p_start() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory start )"
|
||||
}
|
||||
|
||||
i2p_stop() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory stop )"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start')
|
||||
i2p_start
|
||||
;;
|
||||
'stop')
|
||||
i2p_stop
|
||||
;;
|
||||
'restart')
|
||||
i2p_stop
|
||||
i2p_start
|
||||
;;
|
||||
*)
|
||||
echo "usage $0 start|stop|restart"
|
||||
;;
|
||||
esac
|
||||
|
10
Slackware/i2p-base/readme.txt
Normal file
@ -0,0 +1,10 @@
|
||||
An rc file called rc.i2p has been placed into the /etc/rc.d directory.
|
||||
If you want to change installation dir, change the variable INSTALL_DIR
|
||||
on base-i2p.SlackBuild and rebuild the package. You also will need to do the
|
||||
same for the i2p package.
|
||||
|
||||
The install script will insert everything needed into /etc/rc.d/rc.local and
|
||||
into /etc/rc.d/rc.local_shutdown automatically.
|
||||
|
||||
If you want to start I2P at boot you have to chmod +x /etc/rc.d/rc.i2p
|
||||
|
19
Slackware/i2p-base/slack-desc
Normal file
@ -0,0 +1,19 @@
|
||||
# HOW TO EDIT THIS FILE:
|
||||
# The "handy ruler" below makes it easier to edit a package description. Line
|
||||
# up the first '|' above the ':' following the base package name, and the '|' on
|
||||
# the right side marks the last column you can put a character in. You must make
|
||||
# exactly 11 lines for the formatting to be correct. It's also customary to
|
||||
# leave one space after the ':'.
|
||||
|
||||
|-----handy-ruler------------------------------------------------------|
|
||||
base-i2p: base-i2p (I2P anonymizing network base config files)
|
||||
base-i2p:
|
||||
base-i2p: I2P is an anonymizing network, offering a simple layer that
|
||||
base-i2p: identity-sensitive applications can use to securely communicate. All
|
||||
base-i2p: data is wrapped with several layers of encryption, and the network is
|
||||
base-i2p: both distributed and dynamic, with no trusted parties.
|
||||
base-i2p: Many applications are available that interface with I2P, including
|
||||
base-i2p: mail, peer-peer file sharing, IRC chat, and others.
|
||||
base-i2p:
|
||||
base-i2p: This package provides the startup files.
|
||||
base-i2p:
|
1
Slackware/i2p-base/slack-required
Normal file
@ -0,0 +1 @@
|
||||
bash >= 3.1.017
|
8
Slackware/i2p/build.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<project basedir="." default="slackpkg">
|
||||
<target name="slackpkg">
|
||||
<echo message="Building Slackware package." />
|
||||
<exec executable="./i2p.SlackBuild">
|
||||
</exec>
|
||||
</target>
|
||||
</project>
|
67
Slackware/i2p/doinst.sh
Normal file
@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
|
||||
INST_DIR=directory
|
||||
|
||||
( cd install
|
||||
|
||||
echo
|
||||
for i in *.config ; {
|
||||
if [ -f $INST_DIR/$i ] ; then
|
||||
echo "Please check ${INST_DIR}${i}, as there is a new version."
|
||||
cp $i $INST_DIR/$i.new
|
||||
else
|
||||
cp $i $INST_DIR/$i
|
||||
fi
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
( cd $INST_DIR
|
||||
if [ -f blocklist.txt ] ; then
|
||||
echo "Please check ${INST_DIR}blocklist.txt, as there is a new version."
|
||||
else
|
||||
mv blocklist.txt.new blocklist.txt
|
||||
fi
|
||||
)
|
||||
|
||||
( cd $INST_DIR/eepsite
|
||||
if [ -f jetty.xml ] ; then
|
||||
rm jetty.xml.new
|
||||
else
|
||||
mv jetty.xml.new jetty.xml
|
||||
fi
|
||||
)
|
||||
|
||||
( cd $INST_DIR/eepsite/docroot
|
||||
if [ -f index.html ] ; then
|
||||
rm index.html.new
|
||||
else
|
||||
mv index.html.new index.html
|
||||
fi
|
||||
if [ -f favicon.ico ] ; then
|
||||
rm favicon.ico.new
|
||||
else
|
||||
mv favicon.ico.new favicon.ico
|
||||
fi
|
||||
)
|
||||
|
||||
echo
|
||||
echo "FINISHING I2P INSTALLATION. PLEASE WAIT."
|
||||
|
||||
cd $INST_DIR
|
||||
sh postinstall.sh || (
|
||||
echo "ERROR: failed execution of postinstall.sh. Please"
|
||||
echo "cd into i2p installation directory and run "
|
||||
echo "postinstall.sh manually with ./postinstall.sh"
|
||||
exit 1
|
||||
)
|
||||
|
||||
sleep 10
|
||||
|
||||
sh i2prouter stop || exit 1
|
||||
|
||||
echo
|
||||
echo "Installation finished."
|
||||
echo
|
||||
|
||||
exit
|
88
Slackware/i2p/i2p.SlackBuild
Executable file
@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
# Heavily based on the Slackware 12.1 SlackBuild
|
||||
# Slackware build script for i2p
|
||||
|
||||
# PLEASE READ THIS:
|
||||
# Probably you will never have to update i2p packages with upgradepkg,
|
||||
# just because i2p have an auto-update function.
|
||||
# How to start i2p:
|
||||
# After installpkg command, doinst.sh will execute a postinstallation script
|
||||
# needed by i2p. After that you have to chmod +x /etc/rc.d/rc.i2p and start
|
||||
# i2p service with /etc/rc.d/rc.i2p start.
|
||||
# Now tell your browser to user this proxy: localhost on port 4444 and open
|
||||
# this page: http://localhost:7657/index.jsp
|
||||
# Here you can configure i2p, watch network status and navigate anonimously.
|
||||
# It's suggested to subscribe to various dns host, like i2host.i2p
|
||||
# For any additional information, visit i2host.i2p and forum.i2p
|
||||
|
||||
BUILD=1sim
|
||||
|
||||
# put here installation dir, without first and last /
|
||||
# es: usr/local
|
||||
INSTALL_DIR=opt
|
||||
NAME=i2p
|
||||
ARCH=noarch
|
||||
|
||||
|
||||
#
|
||||
# This mess is here due to the totally moronic way i2p does versioning.
|
||||
# We correct it here.
|
||||
#
|
||||
ROUTER=$(echo -ne "_")$(cat ../../router/java/src/net/i2p/router/RouterVersion.java | grep -e "public final static long BUILD" | cut -f2 -d"=" | cut -f1 -d";" | sed -re "s/ //g")
|
||||
if [ "$ROUTER" == "_" ] ; then
|
||||
ROUTER="_0"
|
||||
fi
|
||||
|
||||
#
|
||||
# That was the easy one, now for the tough one.
|
||||
#
|
||||
|
||||
CORE=$(cat ../../core/java/src/net/i2p/CoreVersion.java | grep -e "public final static String VERSION" | cut -f2 -d'"' | sed -re "s/ //g")
|
||||
CORE1=$(echo -n $CORE.x.x | sed -re "s/(.*)\.(.*)\.(.*)\.(.*)/\1/")
|
||||
CORE2=$(echo -n $CORE.x | sed -re "s/(.*)\.(.*)\.(.*)\.(.*)/\1/")
|
||||
|
||||
if [ "$CORE.x.x" == "$CORE1" ] ; then
|
||||
CORE=$(echo -ne $CORE".0.0")
|
||||
fi
|
||||
if [ "$CORE.x" == "$CORE2" ] ; then
|
||||
CORE=$(echo -ne $CORE".0")
|
||||
fi
|
||||
|
||||
VERSION=$(echo $CORE$ROUTER)
|
||||
#
|
||||
# Whew!
|
||||
# OK, let's build i2p
|
||||
#
|
||||
|
||||
CWD=$(pwd)
|
||||
TMP=/tmp
|
||||
|
||||
PKG=$TMP/package-i2p
|
||||
rm -rf $PKG
|
||||
mkdir -p $PKG
|
||||
|
||||
cd $CWD/../../
|
||||
|
||||
ant distclean
|
||||
ant dist
|
||||
|
||||
|
||||
tar xjvf i2p.tar.bz2 -C $TMP
|
||||
|
||||
cd $TMP/i2p
|
||||
chown -R root:root .
|
||||
|
||||
mkdir -p $PKG/$INSTALL_DIR/
|
||||
cp -a ../i2p $PKG/$INSTALL_DIR/
|
||||
|
||||
mkdir -p $PKG/install
|
||||
mv $PKG/$INSTALL_DIR/i2p/*.config $PKG/install
|
||||
mv $PKG/$INSTALL_DIR/i2p/blocklist.txt $PKG/$INSTALL_DIR/i2p/blocklist.txt.new
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml.new
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html.new
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico.new
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/|g" $CWD/doinst.sh > $PKG/install/doinst.sh
|
||||
cat $CWD/slack-desc > $PKG/install/slack-desc
|
||||
cd $PKG
|
||||
requiredbuilder -v -y -s $CWD $PKG
|
||||
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.tgz
|
47
Slackware/i2p/readme.txt
Normal file
@ -0,0 +1,47 @@
|
||||
Building:
|
||||
The i2p package will be installed in /opt/i2p
|
||||
|
||||
If you want to change installation dir, change the variable INSTALL_DIR
|
||||
on i2p.SlackBuild and rebuild the package. You will also need to do the same
|
||||
in the base-i2p package.
|
||||
|
||||
Installation and Upgrade:
|
||||
Probably you will never have to update i2p packages. However if you do,
|
||||
be sure to installpkg first, then removepkg or custom config files can
|
||||
be lost with upgradepkg. I2P has an auto-update function. However using
|
||||
installpkg then removepkg lowers the demand on the I2P network as a
|
||||
whole, and is by far faster.
|
||||
|
||||
After installpkg command, doinst.sh will execute a postinstallation script
|
||||
needed by I2P. Be sure to also install the base-i2p package.
|
||||
|
||||
Optional:
|
||||
|
||||
chmod +x /etc/rc.d/rc.i2p only if you want it to start on boot and stop on
|
||||
shutdown.
|
||||
|
||||
How to start I2P:
|
||||
|
||||
Start I2P service with-
|
||||
sh /etc/rc.d/rc.i2p start
|
||||
|
||||
Now tell your browser to user this proxy: localhost on port 4444 and open
|
||||
this page: http://localhost:7657/index.jsp
|
||||
Here you can configure I2P, watch network status and navigate anonimously.
|
||||
It's suggested to subscribe to various addressbook hosts so that you can
|
||||
get to the many available eepsites and other service on I2P. These are not
|
||||
set up by default for security reasons.
|
||||
|
||||
Please see the faqs on http://www.i2p2.i2p/ or http://www.i2p2.de/ on how
|
||||
to subscribe to the various addressbook services.
|
||||
|
||||
To stop I2P:
|
||||
/etc/rc.d/rc.i2p stop
|
||||
|
||||
|
||||
For any additional information:
|
||||
|
||||
Within I2P- http://www.i2p2.i2p/, http://forum.i2p/, http://zzz.i2p
|
||||
|
||||
Internet (not reccomended!) - http://www.i2p2.de/, http://forum.i2p2.de/
|
||||
|
19
Slackware/i2p/slack-desc
Normal file
@ -0,0 +1,19 @@
|
||||
# HOW TO EDIT THIS FILE:
|
||||
# The "handy ruler" below makes it easier to edit a package description. Line
|
||||
# up the first '|' above the ':' following the base package name, and the '|' on
|
||||
# the right side marks the last column you can put a character in. You must make
|
||||
# exactly 11 lines for the formatting to be correct. It's also customary to
|
||||
# leave one space after the ':'.
|
||||
|
||||
|-----handy-ruler----------------------------------------------------------|
|
||||
i2p: i2p (an anonymizing network)
|
||||
i2p:
|
||||
i2p: I2P is an anonymizing network, offering a simple layer that
|
||||
i2p: identity-sensitive applications can use to securely communicate. All
|
||||
i2p: data is wrapped with several layers of encryption, and the network is
|
||||
i2p: both distributed and dynamic, with no trusted parties.
|
||||
i2p: Many applications are available that interface with I2P, including
|
||||
i2p: mail, peer-peer file sharing, IRC chat, and others.
|
||||
i2p: WARNING: To upgrade installpkg FIRST _THEN_ removepkg.
|
||||
i2p: For more information, see: http://www.i2p2.de/
|
||||
i2p:
|
2
Slackware/i2p/slack-required
Normal file
@ -0,0 +1,2 @@
|
||||
glibc >= 2.7-i486-17 | glibc-solibs >= 2.7-i486-17
|
||||
perl >= 5.10.0-i486-1
|
14
apps/BOB/bob.config
Normal file
@ -0,0 +1,14 @@
|
||||
#bob.config
|
||||
#Tue Dec 30 00:00:00 UTC 2008
|
||||
# Please leave this file here for testing.
|
||||
# Thank you,
|
||||
# Sponge
|
||||
i2cp.tcp.port=7654
|
||||
BOB.host=localhost
|
||||
inbound.lengthVariance=0
|
||||
i2cp.messageReliability=BestEffort
|
||||
BOB.port=45067
|
||||
outbound.length=1
|
||||
inbound.length=1
|
||||
outbound.lengthVariance=0
|
||||
i2cp.tcp.host=localhost
|
@ -1,3 +1,4 @@
|
||||
compile.on.save=false
|
||||
do.depend=false
|
||||
do.jar=true
|
||||
javac.debug=true
|
||||
|
@ -1,5 +1,11 @@
|
||||
application.title=BOB
|
||||
application.vendor=root
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=false
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=8
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=8
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project
|
||||
build.classes.dir=${build.dir}/classes
|
||||
build.classes.excludes=**/*.java,**/*.form
|
||||
# This directory is removed when the project is cleaned:
|
||||
@ -30,13 +36,31 @@ file.reference.mstreaming.jar-1=../ministreaming/java/build/mstreaming.jar
|
||||
file.reference.NetBeansProjects-i2p.i2p=../i2p.i2p/
|
||||
file.reference.streaming.jar=../../bob/i2p/i2p.i2p/build/streaming.jar
|
||||
file.reference.streaming.jar-1=../streaming/java/build/streaming.jar
|
||||
file.reference.wrapper-freebsd=../../installer/lib/wrapper/freebsd/
|
||||
file.reference.wrapper-linux=../../installer/lib/wrapper/linux/
|
||||
file.reference.wrapper-linux64=../../installer/lib/wrapper/linux64/
|
||||
file.reference.wrapper-macosx=../../installer/lib/wrapper/macosx/
|
||||
file.reference.wrapper-solaris=../../installer/lib/wrapper/solaris/
|
||||
file.reference.wrapper-win32=../../installer/lib/wrapper/win32/
|
||||
file.reference.wrapper.jar=../../installer/lib/wrapper/linux/wrapper.jar
|
||||
file.reference.wrapper.jar-1=../../installer/lib/wrapper/freebsd/wrapper.jar
|
||||
file.reference.wrapper.jar-2=../../installer/lib/wrapper/linux64/wrapper.jar
|
||||
file.reference.wrapper.jar-3=../../installer/lib/wrapper/macosx/wrapper.jar
|
||||
file.reference.wrapper.jar-4=../../installer/lib/wrapper/solaris/wrapper.jar
|
||||
file.reference.wrapper.jar-5=../../installer/lib/wrapper/win32/wrapper.jar
|
||||
includes=**
|
||||
jar.compress=false
|
||||
javac.classpath=\
|
||||
${file.reference.i2p.jar-1}:\
|
||||
${file.reference.i2ptunnel.jar}:\
|
||||
${file.reference.mstreaming.jar-1}:\
|
||||
${file.reference.streaming.jar-1}
|
||||
${file.reference.streaming.jar-1}:\
|
||||
${file.reference.wrapper.jar-1}:\
|
||||
${file.reference.wrapper.jar}:\
|
||||
${file.reference.wrapper.jar-2}:\
|
||||
${file.reference.wrapper.jar-3}:\
|
||||
${file.reference.wrapper.jar-4}:\
|
||||
${file.reference.wrapper.jar-5}
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
@ -58,6 +82,12 @@ javadoc.splitindex=true
|
||||
javadoc.use=true
|
||||
javadoc.version=false
|
||||
javadoc.windowtitle=
|
||||
jnlp.codebase.type=local
|
||||
jnlp.codebase.url=file:/root/NetBeansProjects/i2p.i2p/apps/BOB/dist/
|
||||
jnlp.descriptor=application
|
||||
jnlp.enabled=false
|
||||
jnlp.offline-allowed=false
|
||||
jnlp.signed=false
|
||||
main.class=net.i2p.BOB.Main
|
||||
manifest.file=manifest.mf
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
|
@ -114,6 +114,18 @@ public class BOB {
|
||||
public final static String PROP_BOB_HOST = "BOB.host";
|
||||
private static int maxConnections = 0;
|
||||
private static NamedDB database;
|
||||
private static Properties props = new Properties();
|
||||
|
||||
|
||||
/**
|
||||
* Log a warning
|
||||
*
|
||||
* @param arg
|
||||
*/
|
||||
public static void info(String arg) {
|
||||
System.out.println("INFO:" + arg);
|
||||
_log.info(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a warning
|
||||
@ -121,7 +133,7 @@ public class BOB {
|
||||
* @param arg
|
||||
*/
|
||||
public static void warn(String arg) {
|
||||
System.out.println(arg);
|
||||
System.out.println("WARNING:" + arg);
|
||||
_log.warn(arg);
|
||||
}
|
||||
|
||||
@ -131,7 +143,7 @@ public class BOB {
|
||||
* @param arg
|
||||
*/
|
||||
public static void error(String arg) {
|
||||
System.out.println(arg);
|
||||
System.out.println("ERROR: " + arg);
|
||||
_log.error(arg);
|
||||
}
|
||||
|
||||
@ -147,7 +159,6 @@ public class BOB {
|
||||
// Set up all defaults to be passed forward to other threads.
|
||||
// Re-reading the config file in each thread is pretty damn stupid.
|
||||
// I2PClient client = I2PClientFactory.createClient();
|
||||
Properties props = new Properties();
|
||||
String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "bob.config");
|
||||
|
||||
// This is here just to ensure there is no interference with our threadgroups.
|
||||
@ -202,12 +213,13 @@ public class BOB {
|
||||
props.store(fo, configLocation);
|
||||
fo.close();
|
||||
} catch(IOException ioe) {
|
||||
warn("IOException on BOB config file " + configLocation + ", " + ioe);
|
||||
error("IOException on BOB config file " + configLocation + ", " + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
try {
|
||||
warn("BOB is now running.");
|
||||
info("BOB is now running.");
|
||||
ServerSocket listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST)));
|
||||
Socket server;
|
||||
|
||||
@ -220,7 +232,7 @@ public class BOB {
|
||||
t.start();
|
||||
}
|
||||
} catch(IOException ioe) {
|
||||
warn("IOException on socket listen: " + ioe);
|
||||
error("IOException on socket listen: " + ioe);
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public class DoCMDS implements Runnable {
|
||||
|
||||
// FIX ME
|
||||
// I need a better way to do versioning, but this will do for now.
|
||||
public static final String BMAJ = "00", BMIN = "00", BREV = "01", BEXT = "-D";
|
||||
public static final String BMAJ = "00", BMIN = "00", BREV = "03", BEXT = "";
|
||||
public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT;
|
||||
private Socket server;
|
||||
private Properties props;
|
||||
@ -89,6 +89,7 @@ public class DoCMDS implements Runnable {
|
||||
private static final String C_setkeys = "setkeys";
|
||||
private static final String C_setnick = "setnick";
|
||||
private static final String C_show = "show";
|
||||
private static final String C_show_props = "showprops";
|
||||
private static final String C_start = "start";
|
||||
private static final String C_status = "status";
|
||||
private static final String C_stop = "stop";
|
||||
@ -113,6 +114,7 @@ public class DoCMDS implements Runnable {
|
||||
{C_setkeys, C_setkeys + " BASE64_keypair * Sets the keypair for the current nickname."},
|
||||
{C_setnick, C_setnick + " nickname * Create a new nickname."},
|
||||
{C_show, C_show + " * Display the status of the current nickname."},
|
||||
{C_show_props, C_show_props + " * Display the properties of the current nickname."},
|
||||
{C_start, C_start + " * Start the current nickname tunnel."},
|
||||
{C_status, C_status + " nickname * Display status of a nicknamed tunnel."},
|
||||
{C_stop, C_stop + " * Stops the current nicknamed tunnel."},
|
||||
@ -135,6 +137,7 @@ public class DoCMDS implements Runnable {
|
||||
C_setkeys + " " +
|
||||
C_setnick + " " +
|
||||
C_show + " " +
|
||||
C_show_props + " " +
|
||||
C_start + " " +
|
||||
C_status + " " +
|
||||
C_stop + " " +
|
||||
@ -152,9 +155,10 @@ public class DoCMDS implements Runnable {
|
||||
*/
|
||||
DoCMDS(Socket server, Properties props, NamedDB database, Log _log) {
|
||||
this.server = server;
|
||||
this.props = new Properties(props);
|
||||
this.props = new Properties();
|
||||
this.database = database;
|
||||
this._log = _log;
|
||||
Lifted.copyProperties(props, this.props);
|
||||
}
|
||||
|
||||
private void rlock() throws Exception {
|
||||
@ -288,6 +292,31 @@ public class DoCMDS implements Runnable {
|
||||
runlock(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump properties information from the database
|
||||
*
|
||||
* @param out
|
||||
* @param info
|
||||
* @throws Exception
|
||||
*/
|
||||
private void propprint(PrintStream out, NamedDB info) throws Exception {
|
||||
try {
|
||||
rlock(info);
|
||||
} catch (Exception e) {
|
||||
throw new Exception(e);
|
||||
}
|
||||
try {
|
||||
|
||||
trypnt(out, info, P_PROPERTIES);
|
||||
out.println();
|
||||
} catch (Exception e) {
|
||||
runlock(info);
|
||||
throw new Exception(e);
|
||||
}
|
||||
|
||||
runlock(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print information on a specific record, indicated by NamedDB
|
||||
* @param out
|
||||
@ -369,8 +398,10 @@ public class DoCMDS implements Runnable {
|
||||
// Get input from the client
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
|
||||
PrintStream out = new PrintStream(server.getOutputStream());
|
||||
quit: {
|
||||
die: {
|
||||
quit:
|
||||
{
|
||||
die:
|
||||
{
|
||||
prikey = new ByteArrayOutputStream();
|
||||
out.println("BOB " + BOBversion);
|
||||
out.println("OK");
|
||||
@ -750,7 +781,8 @@ die: {
|
||||
nickinfo.add(P_QUIET, Boolean.FALSE);
|
||||
nickinfo.add(P_INHOST, "localhost");
|
||||
nickinfo.add(P_OUTHOST, "localhost");
|
||||
Properties Q = new Properties(props);
|
||||
Properties Q = new Properties();
|
||||
Lifted.copyProperties(this.props, Q);
|
||||
Q.setProperty("inbound.nickname", Arg);
|
||||
Q.setProperty("outbound.nickname", Arg);
|
||||
nickinfo.add(P_PROPERTIES, Q);
|
||||
@ -1184,6 +1216,43 @@ die: {
|
||||
}
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_show_props)) {
|
||||
// Get the current options properties
|
||||
if (ns) {
|
||||
out.print("OK");
|
||||
try {
|
||||
rlock();
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
}
|
||||
|
||||
try {
|
||||
propprint(out, nickinfo);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
runlock();
|
||||
} catch (Exception ee) {
|
||||
break die;
|
||||
}
|
||||
|
||||
out.println(); // this will cause an IOE if IOE
|
||||
break die;
|
||||
}
|
||||
|
||||
try {
|
||||
runlock();
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
nns(out);
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_start)) {
|
||||
// Start the tunnel, if we have all the information
|
||||
if (ns && dk && (ip || op)) {
|
||||
|
@ -70,7 +70,7 @@ public class I2Plistener implements Runnable {
|
||||
boolean g = false;
|
||||
I2PSocket sessSocket = null;
|
||||
|
||||
serverSocket.setSoTimeout(1000);
|
||||
serverSocket.setSoTimeout(100);
|
||||
database.getReadLock();
|
||||
info.getReadLock();
|
||||
if(info.exists("INPORT")) {
|
||||
@ -107,32 +107,31 @@ public class I2Plistener implements Runnable {
|
||||
// System.out.println("Exception " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// System.out.println("I2Plistener: Close");
|
||||
try {
|
||||
serverSocket.close();
|
||||
} catch(I2PException e) {
|
||||
// nop
|
||||
}
|
||||
|
||||
while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish
|
||||
// System.out.println("STOP Thread count " + Thread.activeCount());
|
||||
try {
|
||||
Thread.sleep(1000); //sleep for 1000 ms (One second)
|
||||
} catch(Exception e) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
||||
// System.out.println("STOP Thread count " + Thread.activeCount());
|
||||
// need to kill off the socket manager too.
|
||||
I2PSession session = socketManager.getSession();
|
||||
if(session != null) {
|
||||
// System.out.println("I2Plistener: destroySession");
|
||||
try {
|
||||
session.destroySession();
|
||||
} catch(I2PSessionException ex) {
|
||||
// nop
|
||||
}
|
||||
// System.out.println("destroySession Thread count " + Thread.activeCount());
|
||||
}
|
||||
// System.out.println("I2Plistener: Waiting for children");
|
||||
while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish
|
||||
try {
|
||||
Thread.sleep(100); //sleep for 100 ms (One tenth second)
|
||||
} catch(Exception e) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
||||
// System.out.println("I2Plistener: Done.");
|
||||
}
|
||||
}
|
||||
|
@ -119,20 +119,26 @@ die: {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
||||
// System.out.println("I2PtoTCP: Going away...");
|
||||
} catch(Exception e) {
|
||||
// System.out.println("I2PtoTCP: Owch! damn!");
|
||||
break die;
|
||||
}
|
||||
} // die
|
||||
try {
|
||||
// System.out.println("I2PtoTCP: Close I2P");
|
||||
I2P.close();
|
||||
} catch(Exception e) {
|
||||
tell = false;
|
||||
}
|
||||
//System.out.println("I2PtoTCP: Closed I2P");
|
||||
try {
|
||||
// System.out.println("I2PtoTCP: Close sock");
|
||||
sock.close();
|
||||
} catch(Exception e) {
|
||||
tell = false;
|
||||
}
|
||||
// System.out.println("I2PtoTCP: Done");
|
||||
|
||||
}
|
||||
}
|
||||
|
56
apps/BOB/src/net/i2p/BOB/Lifted.java
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Sets of "friendly" utilities to make life easier.
|
||||
* Any "Lifted" code will apear here, and credits given.
|
||||
* It's better to "Lift" a small chunk of "free" code than add in piles of
|
||||
* code we don't need, and don't want.
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class Lifted {
|
||||
|
||||
/**
|
||||
* Copy a set of properties from one Property to another.
|
||||
* Lifted from Apache Derby code svn repository.
|
||||
* Liscenced as follows:
|
||||
* http://svn.apache.org/repos/asf/db/derby/code/trunk/LICENSE
|
||||
*
|
||||
* @param src_prop Source set of properties to copy from.
|
||||
* @param dest_prop Dest Properties to copy into.
|
||||
*
|
||||
**/
|
||||
public static void copyProperties(Properties src_prop, Properties dest_prop) {
|
||||
for (Enumeration propertyNames = src_prop.propertyNames();
|
||||
propertyNames.hasMoreElements();) {
|
||||
Object key = propertyNames.nextElement();
|
||||
dest_prop.put(key, src_prop.get(key));
|
||||
}
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.util.Log;
|
||||
import org.tanukisoftware.wrapper.WrapperManager;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -64,6 +65,7 @@ public class MUXlisten implements Runnable {
|
||||
MUXlisten(NamedDB database, NamedDB info, Log _log) throws I2PException, IOException, RuntimeException {
|
||||
int port = 0;
|
||||
InetAddress host = null;
|
||||
this.tg = null;
|
||||
this.database = database;
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
@ -72,7 +74,10 @@ public class MUXlisten implements Runnable {
|
||||
this.info.getReadLock();
|
||||
N = this.info.get("NICKNAME").toString();
|
||||
prikey = new ByteArrayInputStream((byte[])info.get("KEYS"));
|
||||
Properties Q = (Properties)info.get("PROPERTIES");
|
||||
// Make a new copy so that anything else won't muck with our database.
|
||||
Properties R = (Properties)info.get("PROPERTIES");
|
||||
Properties Q = new Properties();
|
||||
Lifted.copyProperties(R, Q);
|
||||
this.database.releaseReadLock();
|
||||
this.info.releaseReadLock();
|
||||
|
||||
@ -207,10 +212,13 @@ die: {
|
||||
break die;
|
||||
}
|
||||
} // die
|
||||
|
||||
// wait for child threads and thread groups to die
|
||||
// System.out.println("MUXlisten: waiting for children");
|
||||
while(tg.activeCount() + tg.activeGroupCount() != 0) {
|
||||
tg.interrupt(); // unwedge any blocking threads.
|
||||
try {
|
||||
Thread.sleep(1000); //sleep for 1000 ms (One second)
|
||||
Thread.sleep(100); //sleep for 100 ms (One tenth second)
|
||||
} catch(InterruptedException ex) {
|
||||
// nop
|
||||
}
|
||||
@ -219,11 +227,24 @@ die: {
|
||||
// Zap reference to the ThreadGroup so the JVM can GC it.
|
||||
tg = null;
|
||||
} catch(Exception e) {
|
||||
// System.out.println("MUXlisten: Caught an exception" + e);
|
||||
break quit;
|
||||
}
|
||||
} // quit
|
||||
socketManager.destroySocketManager();
|
||||
// This is here to catch when something fucks up REALLY bad.
|
||||
if(tg != null) {
|
||||
System.out.println("BOB: MUXlisten: Something fucked up REALLY bad!");
|
||||
System.out.println("BOB: MUXlisten: Please email the following dump to sponge@mail.i2p");
|
||||
WrapperManager.requestThreadDump();
|
||||
System.out.println("BOB: MUXlisten: Something fucked up REALLY bad!");
|
||||
System.out.println("BOB: MUXlisten: Please email the above dump to sponge@mail.i2p");
|
||||
}
|
||||
// zero out everything, just incase.
|
||||
try {
|
||||
socketManager.destroySocketManager();
|
||||
} catch(Exception e) {
|
||||
// nop
|
||||
}
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
@ -236,7 +257,20 @@ die: {
|
||||
}
|
||||
wunlock();
|
||||
} catch(Exception e) {
|
||||
return;
|
||||
}
|
||||
// This is here to catch when something fucks up REALLY bad.
|
||||
if(tg != null) {
|
||||
while(tg.activeCount() + tg.activeGroupCount() != 0) {
|
||||
tg.interrupt(); // unwedge any blocking threads.
|
||||
try {
|
||||
Thread.sleep(100); //sleep for 100 ms (One tenth second)
|
||||
} catch(InterruptedException ex) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
tg.destroy();
|
||||
// Zap reference to the ThreadGroup so the JVM can GC it.
|
||||
tg = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@ -91,12 +90,16 @@ public class TCPio implements Runnable {
|
||||
* the stream has been reached.
|
||||
*
|
||||
*/
|
||||
// System.out.println("TCPio: End Of Stream");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// System.out.println("TCPio: RUNNING = false");
|
||||
} catch(Exception e) {
|
||||
// Eject!!! Eject!!!
|
||||
// System.out.println("TCPio: Caught an exception " + e);
|
||||
return;
|
||||
}
|
||||
// System.out.println("TCPio: Leaving.");
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,6 @@ public class TCPlistener implements Runnable {
|
||||
tgwatch = 2;
|
||||
}
|
||||
try {
|
||||
// System.out.println("Starting thread count " + Thread.activeCount());
|
||||
Socket server = new Socket();
|
||||
listener.setSoTimeout(1000);
|
||||
info.releaseReadLock();
|
||||
@ -87,7 +86,6 @@ public class TCPlistener implements Runnable {
|
||||
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||
info.releaseReadLock();
|
||||
database.releaseReadLock();
|
||||
// System.out.println("Thread count " + Thread.activeCount());
|
||||
try {
|
||||
server = listener.accept();
|
||||
g = true;
|
||||
@ -102,8 +100,13 @@ public class TCPlistener implements Runnable {
|
||||
g = false;
|
||||
}
|
||||
}
|
||||
//System.out.println("TCPlistener: destroySession");
|
||||
listener.close();
|
||||
} catch(IOException ioe) {
|
||||
try {
|
||||
listener.close();
|
||||
} catch(IOException e) {
|
||||
}
|
||||
// Fatal failure, cause a stop event
|
||||
database.getReadLock();
|
||||
info.getReadLock();
|
||||
@ -120,17 +123,6 @@ public class TCPlistener implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("STOP!");
|
||||
|
||||
while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish
|
||||
// System.out.println("STOP Thread count " + Thread.activeCount());
|
||||
try {
|
||||
Thread.sleep(1000); //sleep for 1000 ms (One second)
|
||||
} catch(Exception e) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
// System.out.println("STOP Thread count " + Thread.activeCount());
|
||||
// need to kill off the socket manager too.
|
||||
I2PSession session = socketManager.getSession();
|
||||
if(session != null) {
|
||||
@ -139,8 +131,16 @@ public class TCPlistener implements Runnable {
|
||||
} catch(I2PSessionException ex) {
|
||||
// nop
|
||||
}
|
||||
// System.out.println("destroySession Thread count " + Thread.activeCount());
|
||||
}
|
||||
//System.out.println("TCPlistener: Waiting for children");
|
||||
while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish
|
||||
try {
|
||||
Thread.sleep(100); //sleep for 100 ms (One tenth second)
|
||||
} catch(Exception e) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
//System.out.println("TCPlistener: Done.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,7 @@ public class TCPtoI2P implements Runnable {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
// System.out.println("TCPtoI2P: Going away...");
|
||||
|
||||
} catch(I2PException e) {
|
||||
Emsg("ERROR " + e.toString(), out);
|
||||
@ -169,14 +170,17 @@ public class TCPtoI2P implements Runnable {
|
||||
} catch(IOException ioe) {
|
||||
}
|
||||
try {
|
||||
// System.out.println("TCPtoI2P: Close I2P");
|
||||
I2P.close();
|
||||
} catch(Exception e) {
|
||||
}
|
||||
|
||||
try {
|
||||
// System.out.println("TCPtoI2P: Close sock");
|
||||
sock.close();
|
||||
} catch(Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// System.out.println("TCPtoI2P: Done.");
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,347 +0,0 @@
|
||||
/*
|
||||
* bogobot - A simple join/part stats logger bot for I2P IRC.
|
||||
*
|
||||
* Bogobot.java
|
||||
* 2004 The I2P Project
|
||||
* http://www.i2p.net
|
||||
* This code is public domain.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import org.apache.log4j.DailyRollingFileAppender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
import org.jibble.pircbot.IrcException;
|
||||
import org.jibble.pircbot.NickAlreadyInUseException;
|
||||
import org.jibble.pircbot.PircBot;
|
||||
import org.jibble.pircbot.User;
|
||||
|
||||
/**
|
||||
* TODO 0.5 Add multi-server capability.
|
||||
*
|
||||
* @author hypercubus, oOo
|
||||
* @version 0.4
|
||||
*/
|
||||
public class Bogobot extends PircBot {
|
||||
|
||||
private static final String INTERVAL_DAILY = "daily";
|
||||
private static final String INTERVAL_MONTHLY = "monthly";
|
||||
private static final String INTERVAL_WEEKLY = "weekly";
|
||||
|
||||
private boolean _isIntentionalDisconnect = false;
|
||||
private long _lastUserlistCommandTimestamp = 0;
|
||||
private Logger _logger = Logger.getLogger(Bogobot.class);
|
||||
|
||||
private int _currentAutoRoundTripTag = 0;
|
||||
private long _lastAutoRoundTripSentTime = 0;
|
||||
private Timer _tickTimer;
|
||||
|
||||
private String _configFile;
|
||||
|
||||
private String _botPrimaryNick;
|
||||
private String _botSecondaryNick;
|
||||
private String _botNickservPassword;
|
||||
private String _botUsername;
|
||||
private String _ownerPrimaryNick;
|
||||
private String _ownerSecondaryNick;
|
||||
private String _botShutdownPassword;
|
||||
private String _ircChannel;
|
||||
private String _ircServer;
|
||||
private int _ircServerPort;
|
||||
private boolean _isLoggerEnabled;
|
||||
private String _loggedHostnamePattern;
|
||||
private boolean _isUserlistCommandEnabled;
|
||||
private String _logFilePrefix;
|
||||
private String _logFileRotationInterval;
|
||||
private long _commandAntiFloodInterval;
|
||||
private String _userlistCommandTrigger;
|
||||
private boolean _isRoundTripDelayEnabled;
|
||||
private int _roundTripDelayPeriod;
|
||||
|
||||
class BogobotTickTask extends TimerTask {
|
||||
private Bogobot _caller;
|
||||
|
||||
public BogobotTickTask(Bogobot caller) {
|
||||
_caller = caller;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
_caller.onTick();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfigFile(String configFileName) {
|
||||
|
||||
_configFile = configFileName;
|
||||
|
||||
Properties config = new Properties();
|
||||
FileInputStream fis = null;
|
||||
|
||||
try {
|
||||
fis = new FileInputStream(configFileName);
|
||||
config.load(fis);
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("Error loading configuration file");
|
||||
System.exit(2);
|
||||
|
||||
} finally {
|
||||
if (fis != null) try {
|
||||
fis.close();
|
||||
} catch (IOException ioe) { // nop
|
||||
}
|
||||
}
|
||||
|
||||
_botPrimaryNick = config.getProperty("botPrimaryNick", "somebot");
|
||||
_botSecondaryNick = config.getProperty("botSecondaryNick", "somebot_");
|
||||
_botNickservPassword = config.getProperty("botNickservPassword", "");
|
||||
_botUsername = config.getProperty("botUsername", "somebot");
|
||||
|
||||
_ownerPrimaryNick = config.getProperty("ownerPrimaryNick", "somenick");
|
||||
_ownerSecondaryNick = config.getProperty("ownerSecondaryNick", "somenick_");
|
||||
|
||||
_botShutdownPassword = config.getProperty("botShutdownPassword", "take off eh");
|
||||
|
||||
_ircChannel = config.getProperty("ircChannel", "#i2p-chat");
|
||||
_ircServer = config.getProperty("ircServer", "irc.postman.i2p");
|
||||
_ircServerPort = Integer.parseInt(config.getProperty("ircServerPort", "6668"));
|
||||
|
||||
_isLoggerEnabled = Boolean.valueOf(config.getProperty("isLoggerEnabled", "true")).booleanValue();
|
||||
_loggedHostnamePattern = config.getProperty("loggedHostnamePattern", "");
|
||||
_logFilePrefix = config.getProperty("logFilePrefix", "irc.postman.i2p.i2p-chat");
|
||||
_logFileRotationInterval = config.getProperty("logFileRotationInterval", INTERVAL_DAILY);
|
||||
|
||||
_isRoundTripDelayEnabled = Boolean.valueOf(config.getProperty("isRoundTripDelayEnabled", "false")).booleanValue();
|
||||
_roundTripDelayPeriod = Integer.parseInt(config.getProperty("roundTripDelayPeriod", "300"));
|
||||
|
||||
_isUserlistCommandEnabled = Boolean.valueOf(config.getProperty("isUserlistCommandEnabled", "true")).booleanValue();
|
||||
_userlistCommandTrigger = config.getProperty("userlistCommandTrigger", "!who");
|
||||
_commandAntiFloodInterval = Long.parseLong(config.getProperty("commandAntiFloodInterval", "60"));
|
||||
}
|
||||
|
||||
public Bogobot(String configFileName) {
|
||||
|
||||
loadConfigFile(configFileName);
|
||||
|
||||
this.setName(_botPrimaryNick);
|
||||
this.setLogin(_botUsername);
|
||||
_tickTimer = new Timer();
|
||||
_tickTimer.scheduleAtFixedRate(new BogobotTickTask(this), 1000, 10 * 1000);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Bogobot bogobot;
|
||||
|
||||
if (args.length > 1) {
|
||||
System.err.println("Too many arguments, the only allowed parameter is configuration file name");
|
||||
System.exit(3);
|
||||
}
|
||||
if (args.length == 1) {
|
||||
bogobot = new Bogobot(args[0]);
|
||||
} else {
|
||||
bogobot = new Bogobot("bogobot.config");
|
||||
}
|
||||
|
||||
bogobot.setVerbose(true);
|
||||
|
||||
if (bogobot._isLoggerEnabled)
|
||||
bogobot.initLogger();
|
||||
|
||||
bogobot.connectToServer();
|
||||
}
|
||||
|
||||
protected void onTick() {
|
||||
// Tick about once every ten seconds
|
||||
|
||||
if (this.isConnected() && _isRoundTripDelayEnabled) {
|
||||
if( ( (System.currentTimeMillis() - _lastAutoRoundTripSentTime) >= (_roundTripDelayPeriod * 1000) ) && (this.getOutgoingQueueSize() == 0) ) {
|
||||
// Connected, sending queue is empty and last RoundTrip is more then 5 minutes old -> Send a new one
|
||||
_currentAutoRoundTripTag ++;
|
||||
_lastAutoRoundTripSentTime = System.currentTimeMillis();
|
||||
sendNotice(this.getNick(),"ROUNDTRIP " + _currentAutoRoundTripTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onDisconnect() {
|
||||
|
||||
if (_isIntentionalDisconnect)
|
||||
System.exit(0);
|
||||
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " quits *** " + this.getName() + " *** (Lost connection)");
|
||||
|
||||
try {
|
||||
Thread.sleep(60000);
|
||||
} catch (InterruptedException e) {
|
||||
// No worries.
|
||||
}
|
||||
connectToServer();
|
||||
}
|
||||
|
||||
protected void onJoin(String channel, String sender, String login, String hostname) {
|
||||
|
||||
if (_isLoggerEnabled) {
|
||||
if (sender.equals(this.getName())) {
|
||||
|
||||
_logger.info(System.currentTimeMillis() + " joins *** " + _botPrimaryNick + " ***");
|
||||
|
||||
} else {
|
||||
|
||||
String prependedHostname = "@" + hostname;
|
||||
if (prependedHostname.endsWith(_loggedHostnamePattern)) {
|
||||
_logger.info(System.currentTimeMillis() + " joins " + sender);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onMessage(String channel, String sender, String login, String hostname, String message) {
|
||||
message = message.replaceFirst("<.+?> ", "");
|
||||
if (_isUserlistCommandEnabled && message.equals(_userlistCommandTrigger)) {
|
||||
|
||||
if (System.currentTimeMillis() - _lastUserlistCommandTimestamp < _commandAntiFloodInterval * 1000)
|
||||
return;
|
||||
|
||||
Object[] users = getUsers(_ircChannel);
|
||||
String output = "Userlist for " + _ircChannel + ": ";
|
||||
|
||||
for (int i = 0; i < users.length; i++)
|
||||
output += "[" + ((User) users[i]).getNick() + "] ";
|
||||
|
||||
sendMessage(_ircChannel, output);
|
||||
_lastUserlistCommandTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPart(String channel, String sender, String login, String hostname) {
|
||||
|
||||
if (_isLoggerEnabled) {
|
||||
if (sender.equals(this.getName())) {
|
||||
_logger.info(System.currentTimeMillis() + " parts *** " + _botPrimaryNick + " ***");
|
||||
} else {
|
||||
String prependedHostname = "@" + hostname;
|
||||
if (prependedHostname.endsWith(_loggedHostnamePattern)) {
|
||||
_logger.info(System.currentTimeMillis() + " parts " + sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void onPrivateMessage(String sender, String login, String hostname, String message) {
|
||||
/*
|
||||
* Nobody else except the bot's owner can shut it down, unless of
|
||||
* course the owner's nick isn't registered and someone's spoofing it.
|
||||
*/
|
||||
if ((sender.equals(_ownerPrimaryNick) || sender.equals(_ownerSecondaryNick)) && message.equals(_botShutdownPassword)) {
|
||||
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " quits *** " + this.getName() + " ***");
|
||||
|
||||
_isIntentionalDisconnect = true;
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {
|
||||
String prependedHostname = "@" + sourceHostname;
|
||||
|
||||
if (sourceNick.equals(_botPrimaryNick))
|
||||
changeNick(_botPrimaryNick);
|
||||
|
||||
if (_isLoggerEnabled) {
|
||||
if (prependedHostname.endsWith(_loggedHostnamePattern)) {
|
||||
_logger.info(System.currentTimeMillis() + " quits " + sourceNick + " " + reason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void connectToServer() {
|
||||
|
||||
int loginAttempts = 0;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
connect(_ircServer, _ircServerPort);
|
||||
break;
|
||||
} catch (NickAlreadyInUseException e) {
|
||||
if (loginAttempts == 1) {
|
||||
System.out.println("Sorry, the primary and secondary bot nicks are already taken. Exiting.");
|
||||
System.exit(1);
|
||||
}
|
||||
loginAttempts++;
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e1) {
|
||||
// Hmph.
|
||||
}
|
||||
|
||||
if (getName().equals(_botPrimaryNick))
|
||||
setName(_botSecondaryNick);
|
||||
else
|
||||
setName(_botPrimaryNick);
|
||||
|
||||
continue;
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error during login: ");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (IrcException e) {
|
||||
System.out.println("Error during login: ");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
joinChannel(_ircChannel);
|
||||
}
|
||||
|
||||
protected void onNotice(String sourceNick, String sourceLogin, String sourceHostname, String target, String notice) {
|
||||
|
||||
if (sourceNick.equals("NickServ") && (notice.indexOf("/msg NickServ IDENTIFY") >= 0) && (_botNickservPassword != "")) {
|
||||
sendRawLineViaQueue("NICKSERV IDENTIFY " + _botNickservPassword);
|
||||
}
|
||||
|
||||
if (sourceNick.equals(getNick()) && notice.equals( "ROUNDTRIP " + _currentAutoRoundTripTag)) {
|
||||
int delay = (int)((System.currentTimeMillis() - _lastAutoRoundTripSentTime) / 100);
|
||||
// sendMessage(_ircChannel, "Round-trip delay = " + (delay / 10.0f) + " seconds");
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " roundtrip " + delay);
|
||||
}
|
||||
}
|
||||
|
||||
private void initLogger() {
|
||||
|
||||
String logFilePath = "logs" + File.separator + _logFilePrefix;
|
||||
DailyRollingFileAppender rollingFileAppender = null;
|
||||
|
||||
if (!(new File("logs").exists()))
|
||||
(new File("logs")).mkdirs();
|
||||
|
||||
try {
|
||||
|
||||
if (_logFileRotationInterval.equals("monthly"))
|
||||
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-MM'.log'");
|
||||
else if (_logFileRotationInterval.equals("weekly"))
|
||||
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-ww'.log'");
|
||||
else
|
||||
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-MM-dd'.log'");
|
||||
|
||||
rollingFileAppender.setThreshold(Level.INFO);
|
||||
_logger.addAppender(rollingFileAppender);
|
||||
} catch (IOException ex) {
|
||||
System.out.println("Error: Couldn't create or open an existing log file. Exiting.");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,353 +0,0 @@
|
||||
/*
|
||||
* bogoparser - A simple logfile analyzer for bogobot.
|
||||
*
|
||||
* Bogoparser.java
|
||||
* 2004 The I2P Project
|
||||
* http://www.i2p.net
|
||||
* This code is public domain.
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author hypercubus
|
||||
* @version 0.4
|
||||
*/
|
||||
public class Bogoparser {
|
||||
|
||||
private static void displayUsageAndExit() {
|
||||
System.out.println("\r\nUsage:\r\n\r\n java Bogoparser [--by-duration] <logfile>\r\n");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Bogoparser bogoparser;
|
||||
|
||||
if (args.length < 1 || args.length > 2)
|
||||
displayUsageAndExit();
|
||||
|
||||
if (args.length == 2) {
|
||||
if (!args[0].equals("--by-duration"))
|
||||
displayUsageAndExit();
|
||||
bogoparser = new Bogoparser(args[1], true);
|
||||
}
|
||||
|
||||
if (args.length == 1)
|
||||
bogoparser = new Bogoparser(args[0], false);
|
||||
}
|
||||
|
||||
private Bogoparser(String logfile, boolean sortByDuration) {
|
||||
|
||||
ArrayList sortedSessions;
|
||||
|
||||
if (sortByDuration) {
|
||||
sortedSessions = sortSessionsByDuration(calculateSessionDurations(sortSessionsByTime(readLogfile(logfile))));
|
||||
formatAndOutputByDuration(sortedSessions);
|
||||
} else {
|
||||
sortedSessions = calculateSessionDurations(sortSessionsByQuitReason(sortSessionsByNick(sortSessionsByTime(readLogfile(logfile)))));
|
||||
formatAndOutput(sortedSessions);
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList calculateSessionDurations(ArrayList sortedSessionsByQuitReasonOrDuration) {
|
||||
|
||||
ArrayList calculatedSessionDurations = new ArrayList();
|
||||
|
||||
for (int i = 0; i+1 < sortedSessionsByQuitReasonOrDuration.size(); i += 2) {
|
||||
|
||||
String joinsEntry = (String) sortedSessionsByQuitReasonOrDuration.get(i);
|
||||
String[] joinsEntryFields = joinsEntry.split(" ");
|
||||
|
||||
String quitsEntry = (String) sortedSessionsByQuitReasonOrDuration.get(i+1);
|
||||
Pattern p = Pattern.compile("^([^ ]+) [^ ]+ ([^ ]+) (.*)$");
|
||||
Matcher m = p.matcher(quitsEntry);
|
||||
|
||||
if (m.matches()) {
|
||||
|
||||
String currentJoinTime = joinsEntryFields[0];
|
||||
String currentNick = m.group(2);
|
||||
String currentQuitReason = m.group(3);
|
||||
String currentQuitTime = m.group(1);
|
||||
long joinsTimeInMilliseconds;
|
||||
long quitsTimeInMilliseconds;
|
||||
long sessionLengthInMilliseconds;
|
||||
|
||||
joinsTimeInMilliseconds = Long.parseLong(currentJoinTime);
|
||||
quitsTimeInMilliseconds = Long.parseLong(currentQuitTime);
|
||||
sessionLengthInMilliseconds = quitsTimeInMilliseconds - joinsTimeInMilliseconds;
|
||||
|
||||
String hours = "" + sessionLengthInMilliseconds/1000/60/60;
|
||||
String minutes = "" + (sessionLengthInMilliseconds/1000/60)%60;
|
||||
|
||||
if (hours.length() < 2)
|
||||
hours = "0" + hours;
|
||||
|
||||
if (hours.length() < 3)
|
||||
hours = "0" + hours;
|
||||
|
||||
if (minutes.length() < 2)
|
||||
minutes = "0" + minutes;
|
||||
|
||||
int columnPadding = 19-currentNick.length();
|
||||
String columnPaddingString = " ";
|
||||
|
||||
for (int j = 0; j < columnPadding; j++)
|
||||
columnPaddingString = columnPaddingString + " ";
|
||||
|
||||
calculatedSessionDurations.add(sessionLengthInMilliseconds + " " + currentNick + columnPaddingString + " online " + hours + " hours " + minutes + " minutes " + currentQuitReason);
|
||||
} else {
|
||||
System.out.println("\r\nError: Unexpected entry in logfile: " + quitsEntry);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
return calculatedSessionDurations;
|
||||
}
|
||||
|
||||
private void formatAndOutput(ArrayList sortedSessions) {
|
||||
|
||||
String quitReason = null;
|
||||
|
||||
for (int i = 0; i < sortedSessions.size(); i++) {
|
||||
|
||||
String entry = (String) sortedSessions.get(i);
|
||||
Pattern p = Pattern.compile("^[\\d]+ ([^ ]+ +online [\\d]+ hours [\\d]+ minutes) (.*)$");
|
||||
Matcher m = p.matcher(entry);
|
||||
|
||||
if (m.matches()) {
|
||||
|
||||
if (quitReason == null) {
|
||||
quitReason = m.group(2);
|
||||
System.out.println("\r\nQUIT: " + ((m.group(2).equals("")) ? "No Reason Given" : quitReason) + "\r\n");
|
||||
}
|
||||
|
||||
String tempQuitReason = m.group(2);
|
||||
String tempSession = m.group(1);
|
||||
|
||||
if (tempQuitReason.equals(quitReason)) {
|
||||
System.out.println(" " + tempSession);
|
||||
} else {
|
||||
quitReason = null;
|
||||
i -= 1;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
System.out.println("\r\nError: Unexpected entry in logfile: " + entry);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
System.out.println("\r\n");
|
||||
}
|
||||
|
||||
private void formatAndOutputByDuration(ArrayList sortedSessions) {
|
||||
System.out.println("\r\n");
|
||||
|
||||
for (int i = 0; i < sortedSessions.size(); i++) {
|
||||
String[] columns = ((String) sortedSessions.get(i)).split(" ", 2);
|
||||
System.out.println(columns[1]);
|
||||
}
|
||||
|
||||
System.out.println("\r\n");
|
||||
}
|
||||
|
||||
private ArrayList readLogfile(String logfile) {
|
||||
|
||||
ArrayList log = new ArrayList();
|
||||
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(logfile)));
|
||||
|
||||
for (String line; (line = in.readLine()) != null; )
|
||||
log.add(line);
|
||||
|
||||
in.close();
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("\r\nError: Can't find logfile '" + logfile + "'.\r\n");
|
||||
System.exit(1);
|
||||
|
||||
} catch (IOException e) {
|
||||
System.out.println("\r\nError: Can't read logfile '" + logfile + "'.\r\n");
|
||||
System.exit(1);
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs an odd-even transposition sort.
|
||||
*/
|
||||
private ArrayList sortSessionsByDuration(ArrayList calculatedSessionDurations) {
|
||||
|
||||
for (int i = 0; i < calculatedSessionDurations.size()/2; i++) {
|
||||
for (int j = 0; j+1 < calculatedSessionDurations.size(); j += 2) {
|
||||
|
||||
String[] currentDurationString = ((String) calculatedSessionDurations.get(j)).split(" ", 2);
|
||||
long currentDuration = Long.parseLong(currentDurationString[0]);
|
||||
String[] nextDurationString = ((String) calculatedSessionDurations.get(j+1)).split(" ", 2);
|
||||
long nextDuration = Long.parseLong(nextDurationString[0]);
|
||||
|
||||
if (currentDuration > nextDuration) {
|
||||
calculatedSessionDurations.add(j, calculatedSessionDurations.get(j+1));
|
||||
calculatedSessionDurations.remove(j+2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 1; j+1 < calculatedSessionDurations.size(); j += 2) {
|
||||
|
||||
String[] currentDurationString = ((String) calculatedSessionDurations.get(j)).split(" ", 2);
|
||||
long currentDuration = Long.parseLong(currentDurationString[0]);
|
||||
String[] nextDurationString = ((String) calculatedSessionDurations.get(j+1)).split(" ", 2);
|
||||
long nextDuration = Long.parseLong(nextDurationString[0]);
|
||||
|
||||
if (currentDuration > nextDuration) {
|
||||
calculatedSessionDurations.add(j, calculatedSessionDurations.get(j+1));
|
||||
calculatedSessionDurations.remove(j+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return calculatedSessionDurations;
|
||||
}
|
||||
|
||||
private ArrayList sortSessionsByNick(ArrayList sortedSessionsByTime) {
|
||||
|
||||
ArrayList sortedSessionsByNick = new ArrayList();
|
||||
|
||||
while (sortedSessionsByTime.size() != 0) {
|
||||
|
||||
String entry = (String) sortedSessionsByTime.get(0);
|
||||
String[] entryFields = entry.split(" ");
|
||||
String currentNick = entryFields[2];
|
||||
|
||||
sortedSessionsByNick.add(entry);
|
||||
sortedSessionsByNick.add(sortedSessionsByTime.get(1));
|
||||
sortedSessionsByTime.remove(0);
|
||||
sortedSessionsByTime.remove(0);
|
||||
for (int i = 0; i+1 < sortedSessionsByTime.size(); i += 2) {
|
||||
|
||||
String nextEntry = (String) sortedSessionsByTime.get(i);
|
||||
String[] nextEntryFields = nextEntry.split(" ");
|
||||
|
||||
if (nextEntryFields[2].equals(currentNick)) {
|
||||
sortedSessionsByNick.add(nextEntry);
|
||||
sortedSessionsByNick.add(sortedSessionsByTime.get(i+1));
|
||||
sortedSessionsByTime.remove(i);
|
||||
sortedSessionsByTime.remove(i);
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sortedSessionsByNick;
|
||||
}
|
||||
|
||||
private ArrayList sortSessionsByQuitReason(ArrayList sortedSessionsByNick) {
|
||||
|
||||
ArrayList sortedSessionsByQuitReason = new ArrayList();
|
||||
|
||||
while (sortedSessionsByNick.size() != 0) {
|
||||
|
||||
String entry = (String) sortedSessionsByNick.get(1);
|
||||
Pattern p = Pattern.compile("^[^ ]+ [^ ]+ [^ ]+ (.*)$");
|
||||
Matcher m = p.matcher(entry);
|
||||
|
||||
if (m.matches()) {
|
||||
|
||||
String currentQuitReason = m.group(1);
|
||||
|
||||
sortedSessionsByQuitReason.add(sortedSessionsByNick.get(0));
|
||||
sortedSessionsByQuitReason.add(entry);
|
||||
sortedSessionsByNick.remove(0);
|
||||
sortedSessionsByNick.remove(0);
|
||||
for (int i = 0; i+1 < sortedSessionsByNick.size(); i += 2) {
|
||||
|
||||
String nextEntry = (String) sortedSessionsByNick.get(i+1);
|
||||
Pattern p2 = Pattern.compile("^[^ ]+ [^ ]+ [^ ]+ (.*)$");
|
||||
Matcher m2 = p2.matcher(nextEntry);
|
||||
|
||||
if (m2.matches()) {
|
||||
|
||||
String nextQuitReason = m2.group(1);
|
||||
|
||||
if (nextQuitReason.equals(currentQuitReason)) {
|
||||
sortedSessionsByQuitReason.add(sortedSessionsByNick.get(i));
|
||||
sortedSessionsByQuitReason.add(nextEntry);
|
||||
sortedSessionsByNick.remove(i);
|
||||
sortedSessionsByNick.remove(i);
|
||||
i -= 2;
|
||||
}
|
||||
} else {
|
||||
System.out.println("\r\nError: Unexpected entry in logfile: " + nextEntry);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println("\r\nError: Unexpected entry in logfile: " + entry);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
return sortedSessionsByQuitReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sessions terminated with "parts" messages instead of "quits" are filtered
|
||||
* out.
|
||||
*/
|
||||
private ArrayList sortSessionsByTime(ArrayList log) {
|
||||
|
||||
ArrayList sortedSessionsByTime = new ArrayList();
|
||||
|
||||
mainLoop:
|
||||
while (log.size() > 0) {
|
||||
|
||||
String entry = (String) log.get(0);
|
||||
String[] entryFields = entry.split(" ");
|
||||
|
||||
if (entryFields[1].equals("quits") && !entryFields[1].equals("joins")) {
|
||||
/*
|
||||
* Discard entry. The specified log either doesn't contain
|
||||
* the corresponding "joins" time for this quit entry or the
|
||||
* entry is a "parts" or unknown message, and in both cases
|
||||
* the entry's data is useless.
|
||||
*/
|
||||
log.remove(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 1; i < log.size(); i++) { // Find corresponding "quits" entry.
|
||||
|
||||
String tempEntry = (String) log.get(i);
|
||||
String[] tempEntryFields = tempEntry.split(" ");
|
||||
|
||||
if (tempEntryFields[2].equals(entryFields[2])) { // Check if the nick fields for the two entries match.
|
||||
if (!tempEntryFields[1].equals("quits")) {
|
||||
if (tempEntryFields[1].equals("joins")) { // Don't discard a subsequent "joins" entry.
|
||||
log.remove(0);
|
||||
continue mainLoop;
|
||||
}
|
||||
log.remove(i);
|
||||
continue;
|
||||
}
|
||||
sortedSessionsByTime.add(entry);
|
||||
sortedSessionsByTime.add(tempEntry);
|
||||
log.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Discard "joins" entry. The specified log doesn't contain the
|
||||
* corresponding "quits" time for this entry so the entry's
|
||||
* data is useless.
|
||||
*/
|
||||
|
||||
log.remove(0);
|
||||
}
|
||||
|
||||
return sortedSessionsByTime;
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* ============================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
* ============================================================================
|
||||
*
|
||||
* Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if any, must
|
||||
* include the following acknowledgment: "This product includes software
|
||||
* developed by the Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowledgment may appear in the software itself, if
|
||||
* and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "log4j" and "Apache Software Foundation" must not be used to
|
||||
* endorse or promote products derived from this software without prior
|
||||
* written permission. For written permission, please contact
|
||||
* apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache", nor may
|
||||
* "Apache" appear in their name, without prior written permission of the
|
||||
* Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
|
||||
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* on behalf of the Apache Software Foundation. For more information on the
|
||||
* Apache Software Foundation, please see <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
@ -1,340 +0,0 @@
|
||||
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.
|
@ -1 +0,0 @@
|
||||
java -cp .;log4j-1.2.8.jar;pircbot.jar Bogobot
|
@ -1,101 +0,0 @@
|
||||
#####
|
||||
# Bogobot user configuration
|
||||
#####
|
||||
|
||||
###
|
||||
# The bot's nick and backup nick. You will probably want to register these with
|
||||
# the IRC server's NickServ.(a NickServ interface is forthcoming).
|
||||
#
|
||||
botPrimaryNick=somebot
|
||||
botSecondaryNick=somebot_
|
||||
|
||||
###
|
||||
# The bot's password required by Nickserv service's identify command.
|
||||
# You have to register the nickname yourself first, the bot will not.
|
||||
#
|
||||
botNickservPassword=
|
||||
|
||||
###
|
||||
# The bot's username. Appears in the whois replies
|
||||
#
|
||||
botUsername=somebot
|
||||
|
||||
#####
|
||||
# The bot owner's nick and backup nick. One of these must match the owner's
|
||||
# currently-used nick or else remote shutdown will not be possible. You will
|
||||
# probably want to register these with the IRC server's NickServ.
|
||||
#
|
||||
ownerPrimaryNick=somenick
|
||||
ownerSecondaryNick=somenick_
|
||||
|
||||
###
|
||||
# The bot will disconnect and shut down when sent this password via private
|
||||
# message (aka query) from either of the owner nicks specified above. DO NOT USE
|
||||
# THIS DEFAULT VALUE!
|
||||
#
|
||||
botShutdownPassword=take off eh
|
||||
|
||||
###
|
||||
# The server, channel, and port the bot will connect to.
|
||||
#
|
||||
ircChannel=#i2p-chat
|
||||
ircServer=irc.duck.i2p
|
||||
ircServerPort=6668
|
||||
|
||||
###
|
||||
# Set to "true" to enable logging, else "false" (but don't use quotation marks).
|
||||
#
|
||||
isLoggerEnabled=true
|
||||
|
||||
###
|
||||
# Restrict logging of joins and parts on the user hostname.
|
||||
# Leave empty to log all of them
|
||||
# Prepend with a @ for a perfect match
|
||||
# Otherwise, specify the required end of the user hostname
|
||||
#
|
||||
loggedHostnamePattern=@free.duck.i2p
|
||||
|
||||
###
|
||||
# The prefix to be used for the filenames of logs.
|
||||
#
|
||||
logFilePrefix=irc.duck.i2p.i2p-chat
|
||||
|
||||
###
|
||||
# How often the logs should be rotated. Either "daily", "weekly", or "monthly"
|
||||
# (but don't use quotation marks).
|
||||
#
|
||||
logFileRotationInterval=daily
|
||||
|
||||
###
|
||||
# Set to "true" to enable the regular round-trip delay computation,
|
||||
# else "false" (but don't use quotation marks).
|
||||
#
|
||||
isRoundTripDelayEnabled=false
|
||||
|
||||
###
|
||||
# How often should the round-trip delay be recorded.
|
||||
# (in seconds)
|
||||
#
|
||||
roundTripDelayPeriod=300
|
||||
|
||||
###
|
||||
# Set to "true" to enable the userlist command, else "false" (but don't use
|
||||
# quotation marks).
|
||||
#
|
||||
isUserlistCommandEnabled=true
|
||||
|
||||
###
|
||||
# The userlist trigger command to listen for. It is a good idea to prefix
|
||||
# triggers with some non-alphanumeric character in order to avoid accidental
|
||||
# trigger use during normal channel conversation. In most cases you will
|
||||
# probably want to choose a unique trigger here that no other bots in the
|
||||
# channel will respond to.
|
||||
#
|
||||
userlistCommandTrigger=!who
|
||||
|
||||
###
|
||||
# The number of seconds to rest after replying to a userlist command issued by
|
||||
# a user in the channel. The bot will ignore subsequent userlist commands during
|
||||
# this period. This helps prevent flooding.
|
||||
#
|
||||
commandAntiFloodInterval=60
|
@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
java -cp .:log4j-1.2.8.jar:pircbot.jar Bogobot
|
@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ********************************************************** -->
|
||||
<!-- bogobot - A simple join/part stats logger bot for I2P IRC. -->
|
||||
<!-- -->
|
||||
<!-- build-eclipse.xml -->
|
||||
<!-- 2004 The I2P Project -->
|
||||
<!-- http://www.i2p.net -->
|
||||
<!-- This code is public domain. -->
|
||||
<!-- -->
|
||||
<!-- authors: hypercubus, oOo -->
|
||||
<!-- version 0.4 -->
|
||||
<!-- ********************************************************** -->
|
||||
|
||||
<project basedir="." default="dist" name="Bogobot">
|
||||
|
||||
<!-- init:
|
||||
Create distribution directory if missing and initialize time stamp for
|
||||
archive naming -->
|
||||
<target name="init">
|
||||
<mkdir dir="dist" />
|
||||
<tstamp>
|
||||
<format pattern="yyyy-MM-dd" property="DSTAMP" />
|
||||
</tstamp>
|
||||
</target>
|
||||
|
||||
<!-- dist.bin:
|
||||
Create the binary distribution archive -->
|
||||
<target depends="init" description="Create the binary distribution archive" name="dist.bin">
|
||||
<zip destfile="dist/Bogobot_${DSTAMP}.zip">
|
||||
<zipfileset dir="${basedir}" includes="bogobot.bat bogobot.config Bogobot.class bogobot.sh Bogoparser.class LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- dist.source:
|
||||
Create the source distribution archive -->
|
||||
<target depends="init" description="Create the source distribution archive" name="dist.source">
|
||||
<zip destfile="dist/Bogobot_source_${DSTAMP}.zip">
|
||||
<zipfileset dir="${basedir}" includes="bogobot.bat bogobot.config Bogobot.java bogobot.sh Bogoparser.java build.xml build_eclipse.xml LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- dist:
|
||||
Create both the binary and source distribution archives -->
|
||||
<target depends="dist.bin,dist.source" description="Create both the binary and source distribution archives" name="dist">
|
||||
<echo message="Successfully created binary and source distribution archives in directory 'dist'." />
|
||||
</target>
|
||||
|
||||
<!-- clean:
|
||||
Delete all class files and temporary directories -->
|
||||
<target description="Delete all class files and temporary directories" name="clean">
|
||||
<delete>
|
||||
<fileset dir="${basedir}" includes="**/*.class" />
|
||||
</delete>
|
||||
<echo message="Clean successful." />
|
||||
</target>
|
||||
|
||||
</project>
|
@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ********************************************************** -->
|
||||
<!-- bogobot - A simple join/part stats logger bot for I2P IRC. -->
|
||||
<!-- -->
|
||||
<!-- build.xml -->
|
||||
<!-- 2004 The I2P Project -->
|
||||
<!-- http://www.i2p.net -->
|
||||
<!-- This code is public domain. -->
|
||||
<!-- -->
|
||||
<!-- authors: hypercubus, oOo -->
|
||||
<!-- version 0.4 -->
|
||||
<!-- ********************************************************** -->
|
||||
|
||||
<project basedir="." default="compile" name="Bogobot">
|
||||
|
||||
<!-- init:
|
||||
Create distribution directory if missing and initialize time stamp for
|
||||
archive naming -->
|
||||
<target name="init">
|
||||
<mkdir dir="dist" />
|
||||
<tstamp>
|
||||
<format pattern="yyyy-MM-dd" property="DSTAMP" />
|
||||
</tstamp>
|
||||
</target>
|
||||
|
||||
<!-- compile:
|
||||
Compile source code -->
|
||||
<target depends="init" description="Compile source code" name="compile">
|
||||
<javac classpath="${basedir};log4j-1.2.8.jar;pircbot.jar" source="1.4" srcdir="." />
|
||||
</target>
|
||||
|
||||
<!-- dist.bin:
|
||||
Create the binary distribution archive -->
|
||||
<target depends="init,compile" description="Create the binary distribution archive" name="dist.bin">
|
||||
<zip destfile="dist/Bogobot_${DSTAMP}.zip">
|
||||
<zipfileset dir="${basedir}" includes="bogobot.bat bogobot.config Bogobot.class Bogobot$BogobotTickTask.class bogobot.sh Bogoparser.class LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- dist.source:
|
||||
Create the source distribution archive -->
|
||||
<target depends="init" description="Create the source distribution archive" name="dist.source">
|
||||
<zip destfile="dist/Bogobot_source_${DSTAMP}.zip">
|
||||
<zipfileset dir="${basedir}" includes="bogobot.bat bogobot.config Bogobot.java bogobot.sh Bogoparser.java build.xml build_eclipse.xml LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- dist:
|
||||
Create both the binary and source distribution archives -->
|
||||
<target depends="dist.bin,dist.source" description="Create both the binary and source distribution archives" name="dist">
|
||||
<echo message="Successfully created binary and source distribution archives in directory 'dist'." />
|
||||
</target>
|
||||
|
||||
<!-- clean:
|
||||
Delete all class files and temporary directories -->
|
||||
<target description="Delete all class files and temporary directories" name="clean">
|
||||
<delete>
|
||||
<fileset dir="${basedir}" includes="**/*.class" />
|
||||
</delete>
|
||||
<echo message="Clean successful." />
|
||||
</target>
|
||||
|
||||
</project>
|
@ -1 +0,0 @@
|
||||
This is JDOM 1.0 from http://jdom.org/, released under an Apache style license
|
@ -1,236 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Ports + Ant = Pants, a simple Ant-based package manager
|
||||
|
||||
free (adj.): unencumbered; not under the control of others
|
||||
|
||||
Written by smeghead in 2005 and released into the public domain with no
|
||||
warranty of any kind, either expressed or implied. It probably won't make
|
||||
your computer catch on fire, or eat your children, but it might. Use at your
|
||||
own risk.
|
||||
-->
|
||||
|
||||
<project basedir="." default="help" name="pants-interface">
|
||||
|
||||
<!-- .......................... Global Properties .......................... -->
|
||||
|
||||
|
||||
|
||||
<!-- ........................... Internal Tasks ............................ -->
|
||||
|
||||
<target name="-fetchCvs" unless="cvs.source.available" if="using.cvs">
|
||||
<cvs compressionlevel="${cvs.compression.level}"
|
||||
date="${cvs.date}"
|
||||
dest="./distfiles/cvs-src/${pbuild}"
|
||||
failonerror="true"
|
||||
package="${cvs.package}"
|
||||
passfile="${cvs.passfile}"
|
||||
port="${cvs.port}"
|
||||
cvsRoot="${cvs.root}"
|
||||
cvsRsh="${cvs.rsh}"
|
||||
tag="${cvs.tag}"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="-fetchPackage" unless="using.cvs">
|
||||
<get src="${package.url}"
|
||||
verbose="true"
|
||||
dest="./distfiles"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="-init">
|
||||
<!--
|
||||
TODO: Create dist/ and working/ folders for each pbuild subdir in case
|
||||
they've been wiped.
|
||||
-->
|
||||
<loadproperties srcfile="world" />
|
||||
<taskdef name="mergetypedproperties"
|
||||
classname="net.i2p.pants.MergeTypedPropertiesTask"
|
||||
classpath="./lib/pants.jar"
|
||||
/>
|
||||
<mergetypedproperties input="./pbuilds/${pbuild}/pbuild.properties"
|
||||
output="./pbuilds/${pbuild}/merged-properties.temp"
|
||||
booleanList="version.latest.find.regex.canonicaleq, version.latest.find.regex.caseinsensitive, version.latest.find.regex.comments, version.latest.find.regex.dotall, version.latest.find.regex.multiline, version.latest.find.regex.unicodecase, version.latest.find.regex.unixlines"
|
||||
stringList="cvs.compression.level, cvs.date, cvs.package, cvs.passfile, cvs.port, cvs.root, cvs.rsh, cvs.tag, package.url, version.latest, version.latest.find.url, version.latest.find.regex"
|
||||
/>
|
||||
<loadproperties srcfile="./pbuilds/${pbuild}/merged-properties.temp" />
|
||||
<delete file="./pbuilds/${pbuild}/merged-properties.temp" />
|
||||
<!--
|
||||
If '-Dpbuild={name}' isn't specified, the 'build', 'fetch', 'update'
|
||||
and 'version' commands should default to 'world' behavior.
|
||||
-->
|
||||
<antcall target="-setWorld" />
|
||||
<condition property="using.cvs">
|
||||
<or>
|
||||
<equals arg1="CVS" arg2="${version.using.${pbuild}}" />
|
||||
<equals arg1="cvs" arg2="${version.using.${pbuild}}" />
|
||||
</or>
|
||||
</condition>
|
||||
<!--
|
||||
If 'version.recommended' isn't defined in pbuild.properties, default
|
||||
to latest available version.
|
||||
-->
|
||||
</target>
|
||||
|
||||
<target name="-setWorld" unless="pbuild">
|
||||
<property name="pbuild" value="world" />
|
||||
</target>
|
||||
|
||||
<target name="-unpackTarBz2">
|
||||
<untar src="${pbuild.package}"
|
||||
compression="bzip2"
|
||||
dest="./${pbuild}/working"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="-unpackTarGzip">
|
||||
<untar src="${pbuild.package}"
|
||||
compression="gzip"
|
||||
dest="./${pbuild}/working"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="-unpackZip">
|
||||
<unzip src="${pbuild.package}" dest="./${pbuild}/working" />
|
||||
</target>
|
||||
|
||||
<target name="-updateCvs" if="using.cvs">
|
||||
<cvs command="update -d"
|
||||
compressionlevel="${compression.level}"
|
||||
date="${cvs.date}"
|
||||
dest="./distfiles/cvs-src"
|
||||
failonerror="true"
|
||||
package="${cvs.package}"
|
||||
passfile="${cvs.passfile}"
|
||||
port="${cvs.port}"
|
||||
cvsRoot="${cvs.root}"
|
||||
cvsRsh="${cvs.rsh}"
|
||||
tag="${cvs.tag}"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="-updateConfirm" if="confirm.update" unless="no.prompts">
|
||||
<input validargs="y,Y,n,N"
|
||||
defaultvalue="n"
|
||||
addproperty="confirm.update.answer">
|
||||
You currently have the recommended version installed. A newer
|
||||
version will be installed if you continue and this may break some
|
||||
applications which depend on this package. Are you sure you want
|
||||
to update? [y/N]
|
||||
</input>
|
||||
<condition property="abort.update">
|
||||
<or>
|
||||
<equals arg1="n" arg2="${confirm.update.answer}" />
|
||||
<equals arg1="N" arg2="${confirm.update.answer}" />
|
||||
</or>
|
||||
</condition>
|
||||
<fail if="abort.update">Update aborted.</fail>
|
||||
</target>
|
||||
|
||||
<target name="-versionLatest">
|
||||
<get src="${version.latest.find.url}"
|
||||
dest="version.latest.in.temp"
|
||||
verbose="true"
|
||||
/>
|
||||
<taskdef name="match"
|
||||
classname="net.i2p.pants.MatchTask"
|
||||
classpath="./lib/pants.jar"
|
||||
/>
|
||||
<match input="version.latest.in.temp"
|
||||
output="version.latest.parsed.temp"
|
||||
regex="${version.latest.find.regex}"
|
||||
canonicaleq="${version.latest.find.regex.canonicaleq}"
|
||||
caseinsensitive="${version.latest.find.regex.caseinsensitive}"
|
||||
comments="${version.latest.find.regex.comments}"
|
||||
dotall="${version.latest.find.regex.dotall}"
|
||||
multiline="${version.latest.find.regex.multiline}"
|
||||
unicodecase="${version.latest.find.regex.unicodecase}"
|
||||
unixlines="${version.latest.find.regex.unixlines}"
|
||||
/>
|
||||
<loadproperties srcFile="version.latest.parsed.temp" />
|
||||
<delete file="version.latest.in.temp" />
|
||||
<delete file="version.latest.parsed.temp" />
|
||||
<property name="version.latest" value="${group.1}" />
|
||||
</target>
|
||||
|
||||
<target name="-versionRecommended">
|
||||
<property name="version.recommended" value="x" />
|
||||
</target>
|
||||
|
||||
<target name="-versionUsing">
|
||||
<property name="version.using" value="x" />
|
||||
</target>
|
||||
|
||||
<!-- .......................... Public Interface ........................... -->
|
||||
|
||||
<target name="build" depends="-init,fetch"
|
||||
description="Build a pbuild and its dependencies">
|
||||
<ant antfile="pbuild.xml" dir="./pbuilds/${pbuild}" target="clean" />
|
||||
<ant antfile="pbuild.xml" dir="./pbuilds/${pbuild}" target="build" />
|
||||
<!--
|
||||
Perform a 'clean' on the target first (but not 'distclean')
|
||||
-->
|
||||
</target>
|
||||
|
||||
<target name="fetch" depends="-init"
|
||||
description="Get package only">
|
||||
<antcall target="-fetchPackage" />
|
||||
<antcall target="-fetchCvs" />
|
||||
<copydir dest="./pbuilds/${pbuild}/working"
|
||||
src="./distfiles/cvs-src/${pbuild}"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="help"
|
||||
description="Display usage synopsis">
|
||||
<echo>
|
||||
Pants usage:
|
||||
|
||||
ant [--usejikes] [-Dpbuild={name}] [-Dpbuild.version={version}]
|
||||
[-D{property}={value}] [-Dno.prompts=true] build | fetch |
|
||||
help | install | uninstall | update | version
|
||||
|
||||
build Build a pbuild and its dependencies
|
||||
fetch Get package only
|
||||
help Display usage synopsis
|
||||
install Fetch, build and install a pbuild
|
||||
uninstall Uninstall a pbuild
|
||||
update Update pbuild(s) to the latest version(s)
|
||||
version Display pbuild version information
|
||||
</echo>
|
||||
</target>
|
||||
|
||||
<!--
|
||||
Install recommended version by default unless 'version' property is set.
|
||||
Do not install if package is already installed.
|
||||
-->
|
||||
<target name="install" depends="-init, build"
|
||||
description="Install a pbuild">
|
||||
<ant antfile="pbuild.xml" dir="./pbuilds/${pbuild}" target="dist" />
|
||||
<ant antfile="pbuild.xml" dir="./pbuilds/${pbuild}"
|
||||
target="distclean"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="uninstall" depends="-init"
|
||||
description="Uninstall a pbuild" />
|
||||
|
||||
<target name="update" depends="-init"
|
||||
description="Update pbuild(s) to the latest version(s)">
|
||||
<condition property="${confirm.update}">
|
||||
<equals arg1="${version.using}" arg2="${version.recommended}" />
|
||||
</condition>
|
||||
<antcall target="-updateConfirm" />
|
||||
</target>
|
||||
|
||||
<target name="version"
|
||||
depends="-init, -versionRecommended, -versionUsing, -versionLatest"
|
||||
description="Display pbuild version information">
|
||||
<echo message="Latest version: ${version.recommended}" />
|
||||
<echo message="Latest version: ${version.using}" />
|
||||
<echo message="Latest version: ${version.latest}" />
|
||||
</target>
|
||||
|
||||
</project>
|
@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="build" name="build-pants">
|
||||
|
||||
<target name="build"
|
||||
description="Build the source">
|
||||
<mkdir dir="./java/build"/>
|
||||
<javac srcdir="./java/src" source="1.3" target="1.3" deprecation="on" destdir="./java/build" />
|
||||
</target>
|
||||
|
||||
<target name="clean"
|
||||
description="Remove all object files">
|
||||
<delete dir="./java/build" />
|
||||
<delete dir="./java/jartemp" />
|
||||
</target>
|
||||
|
||||
<target name="dist" depends="build, jar"
|
||||
description="Create the jar and copy it to ../lib">
|
||||
<copy todir="../lib" file="./java/build/pants.jar" />
|
||||
</target>
|
||||
|
||||
<target name="distclean" depends="clean"
|
||||
description="Remove the jar and all object files" >
|
||||
<delete file="../lib/pants.jar" />
|
||||
</target>
|
||||
|
||||
<target name="jar">
|
||||
<delete dir="./java/jartemp" />
|
||||
<mkdir dir="./java/jartemp" />
|
||||
<copy todir="./java/jartemp">
|
||||
<fileset dir="./java/build" includes="**/*.class" />
|
||||
</copy>
|
||||
<jar basedir="./java/jartemp" jarfile="./java/build/pants.jar">
|
||||
<manifest>
|
||||
<section name="net.i2p.pants">
|
||||
<attribute name="Implementation-Title" value="Pants" />
|
||||
<attribute name="Implementation-Version" value="0.0.1" />
|
||||
<attribute name="Implementation-Vendor" value="I2P" />
|
||||
<attribute name="Implementation-Vendor-Id" value="I2P" />
|
||||
<attribute name="Implementation-URL" value="http://www.i2p.net" />
|
||||
</section>
|
||||
</manifest>
|
||||
</jar>
|
||||
<delete dir="./java/jartemp" />
|
||||
</target>
|
||||
</project>
|
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* Ports + Ant = Pants, a simple Ant-based package manager
|
||||
*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
*
|
||||
* Written by smeghead in 2005 and released into the public domain with no
|
||||
* warranty of any kind, either expressed or implied. It probably won't make
|
||||
* your computer catch on fire, or eat your children, but it might. Use at your
|
||||
* own risk.
|
||||
*/
|
||||
|
||||
package net.i2p.pants;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.Task;
|
||||
|
||||
/**
|
||||
* <p>Custom Ant task for matching the contents of a file against a given
|
||||
* regular expression and writing any matching groups to a file in
|
||||
* <code>java.util.Properties</code> format.
|
||||
* </p>
|
||||
* <p>Each key in the properties file is named after the number corresponding to
|
||||
* its matching group and its value is the contents of the matching group.
|
||||
* </p>
|
||||
* <p>Regular expressions passed to this task must conform to the specification
|
||||
* used by Sun's <code>java.util.regex</code> package and thus are mostly
|
||||
* compatible with Perl 5 regular expressions.
|
||||
* </p>
|
||||
* <p>When calling the <code>match</code> task, the attributes
|
||||
* <code>input</code>, <code>output</code>, and <code>regex</code> are required.
|
||||
* </p>
|
||||
* <p>Optional boolean attributes may be used to toggle various modes for the
|
||||
* regular expression engine (all are set to <code>false</code> by default):
|
||||
* </p>
|
||||
* <table>
|
||||
* <tr><td><code>canonicaleq</code></td><td>Enable canonical equivalence</td></tr>
|
||||
* <tr><td><code>caseinsensitive</code></td><td>Enable case-insensitive matching</td></tr>
|
||||
* <tr><td><code>comments</code></td><td>Permit whitespace and comments in pattern</td></tr>
|
||||
* <tr><td><code>dotall</code></td><td>Enable dotall mode</td></tr>
|
||||
* <tr><td><code>multiline</code></td><td>Enable multi-line mode</td></tr>
|
||||
* <tr><td><code>unicodecase</code></td><td>Enable Unicode-aware case folding</td></tr>
|
||||
* <tr><td><code>unixlines</code></td><td>Enable Unix lines mode</td></tr>
|
||||
* </table>
|
||||
* <p>There is one additional optional boolean attribute,
|
||||
* <code>failOnNoMatch</code>. If this attribute is <code>true</code> it causes
|
||||
* the <code>match</code> task to throw a
|
||||
* <code>org.apache.tools.ant.BuildException</code> and fail if no matches for
|
||||
* the regular expression are found. The default value is <code>false</code>,
|
||||
* meaning a failed match will simply result in a warning message to
|
||||
* <code>STDERR</code> and an empty (0 byte) <code>output</code> file being
|
||||
* created.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h4>Example</h4>
|
||||
* </p>
|
||||
* <p>Contents of input file <code>letter.txt</code>:
|
||||
* <pre>
|
||||
* Dear Alice,
|
||||
*
|
||||
* How's about you and me gettin' together for some anonymous foo action?
|
||||
*
|
||||
* Kisses,
|
||||
* Bob
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>Ant <code>match</code> task and a <code>taskdef</code> defining it:
|
||||
* <pre>
|
||||
* <taskdef name="match" classname="net.i2p.pants.MatchTask" classpath="../../lib/pants.jar" />
|
||||
* <match input="letter.txt"
|
||||
* output="matches.txt"
|
||||
* regex="about (\S*?) and (\S*?) .+anonymous (\S*?)"
|
||||
* />
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>Contents of properties file <code>matches.txt</code> written by this task:
|
||||
* <pre>
|
||||
* group.0=about you and me gettin' together for some anonymous foo
|
||||
* group.1=you
|
||||
* group.2=me
|
||||
* group.3=foo
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>These values can be loaded from <code>matches.txt</code> into Ant
|
||||
* properties like so:
|
||||
* <pre>
|
||||
* <loadproperties srcFile="matches.txt" />
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author smeghead
|
||||
*/
|
||||
public class MatchTask extends Task {
|
||||
|
||||
private boolean _failOnNoMatch;
|
||||
private String _inputFile;
|
||||
private String _outputFile;
|
||||
private String _regex;
|
||||
private int _regexFlags;
|
||||
|
||||
public void execute() throws BuildException {
|
||||
int charRead = 0;
|
||||
FileReader fileReader = null;
|
||||
FileWriter fileWriter = null;
|
||||
Matcher matcher = null;
|
||||
Pattern pattern = null;
|
||||
PrintWriter printWriter = null;
|
||||
StringBuffer text = new StringBuffer();
|
||||
|
||||
if (_inputFile == null)
|
||||
throw new BuildException("Error: 'match' task requires 'input' attribute");
|
||||
|
||||
if (_outputFile == null)
|
||||
throw new BuildException("Error: 'match' task requires 'output' attribute");
|
||||
|
||||
if (_regex == null)
|
||||
throw new BuildException("Error: 'match' task requires 'regex' attribute");
|
||||
|
||||
pattern = Pattern.compile(_regex, _regexFlags);
|
||||
|
||||
try {
|
||||
fileReader = new FileReader(_inputFile);
|
||||
|
||||
while ((charRead = fileReader.read()) != -1)
|
||||
text.append((char) charRead);
|
||||
|
||||
fileReader.close();
|
||||
matcher = pattern.matcher(text);
|
||||
|
||||
if (matcher.find()) {
|
||||
printWriter = new PrintWriter(new FileWriter(_outputFile));
|
||||
|
||||
for (int i = 0; i <= matcher.groupCount(); i++)
|
||||
printWriter.println("group." + Integer.toString(i) + "=" + matcher.group(i));
|
||||
|
||||
printWriter.flush();
|
||||
printWriter.close();
|
||||
} else {
|
||||
if (_failOnNoMatch) {
|
||||
throw new BuildException("Error: No matches found in " + _inputFile);
|
||||
} else {
|
||||
System.err.println("Warning: No matches found in " + _inputFile);
|
||||
// Create 0 byte output file.
|
||||
fileWriter = new FileWriter(_outputFile);
|
||||
fileWriter.close();
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
throw new BuildException("File " + _inputFile + " not found", fnfe);
|
||||
} catch (IOException ioe) {
|
||||
throw new BuildException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCanonicalEq(boolean enableCanonicalEq) {
|
||||
if (enableCanonicalEq)
|
||||
_regexFlags |= Pattern.CANON_EQ;
|
||||
}
|
||||
|
||||
public void setCaseInsensitive(boolean enableCaseInsensitive) {
|
||||
if (enableCaseInsensitive)
|
||||
_regexFlags |= Pattern.CASE_INSENSITIVE;
|
||||
}
|
||||
|
||||
public void setComments(boolean enableComments) {
|
||||
if (enableComments)
|
||||
_regexFlags |= Pattern.COMMENTS;
|
||||
}
|
||||
|
||||
public void setDotall(boolean enableDotall) {
|
||||
if (enableDotall)
|
||||
_regexFlags |= Pattern.DOTALL;
|
||||
}
|
||||
|
||||
public void setFailOnNoMatch(boolean failOnNoMatch) {
|
||||
_failOnNoMatch = failOnNoMatch;
|
||||
}
|
||||
|
||||
public void setInput(String inputFile) {
|
||||
_inputFile = inputFile;
|
||||
}
|
||||
|
||||
public void setMultiLine(boolean enableMultiLine) {
|
||||
if (enableMultiLine)
|
||||
_regexFlags |= Pattern.MULTILINE;
|
||||
}
|
||||
|
||||
public void setOutput(String outputFile) {
|
||||
_outputFile = outputFile;
|
||||
}
|
||||
|
||||
public void setRegex(String regex) {
|
||||
_regex = regex;
|
||||
}
|
||||
|
||||
public void setUnicodeCase(boolean enableUnicodeCase) {
|
||||
if (enableUnicodeCase)
|
||||
_regexFlags |= Pattern.UNICODE_CASE;
|
||||
}
|
||||
|
||||
public void setUnixLines(boolean enableUnixLines) {
|
||||
if (enableUnixLines)
|
||||
_regexFlags |= Pattern.UNIX_LINES;
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Ports + Ant = Pants, a simple Ant-based package manager
|
||||
*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
*
|
||||
* Written by smeghead in 2005 and released into the public domain with no
|
||||
* warranty of any kind, either expressed or implied. It probably won't make
|
||||
* your computer catch on fire, or eat your children, but it might. Use at your
|
||||
* own risk.
|
||||
*/
|
||||
|
||||
package net.i2p.pants;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.Task;
|
||||
|
||||
/**
|
||||
* <p>Custom Ant task for loading properties from a
|
||||
* <code>java.util.Properties</code> file then merging them with lists of
|
||||
* expected properties. When an expected property is found in the properties
|
||||
* file it is set to the value given for it in the file. If an expected property
|
||||
* from a list isn't found in the properties file its value will be set to "" or
|
||||
* "false", depending on the property's data type.
|
||||
* </p>
|
||||
* <p>A property's data type is determined by membership in one of two lists
|
||||
* which can be passed into an instance of this class: a string-typed list and a
|
||||
* boolean-typed list. Values for string-typed properties may be any valid
|
||||
* string accepted by <code>java.util.Properties</code>, and values for
|
||||
* boolean-typed properties must be either "false" or "true".
|
||||
* </p>
|
||||
* <p>Lists holding more than one property must be comma-delimited.
|
||||
* </p>
|
||||
* <p>The output of this class is a temporary <code>java.util.Properties</code>
|
||||
* file which is suitable for reading by the standard Ant
|
||||
* <code>loadproperties</code> task.
|
||||
* </p>
|
||||
* <p>Note that if any properties in the given lists have already been defined
|
||||
* before the <code>mergetypedproperties</code> task is called, their values
|
||||
* cannot be changed since Ant properties are immutable.
|
||||
* </p>
|
||||
* <h4>Example</h4>
|
||||
* </p>
|
||||
* <p>Contents of a properties file <code>my.properties</code>:
|
||||
* <pre>
|
||||
* some.property.exists=true
|
||||
* hasValue=false
|
||||
* some.property=this is a value
|
||||
* property0=bork bork
|
||||
* propertyX=this property wasn't passed in a list
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>Ant <code>mergetypedproperties</code> task and a <code>taskdef</code>
|
||||
* defining it:
|
||||
* <pre>
|
||||
* <taskdef name="mergetypedproperties" classname="net.i2p.pants.MergeTypedPropertiesTask" classpath="../../lib/pants.jar" />
|
||||
* <mergetypedproperties input="my.properties"
|
||||
* output="merged-properties.temp"
|
||||
* booleanList="some.property.exists,is.valid,hasValue"
|
||||
* stringList="some.property,another.property,property0"
|
||||
* />
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>Contents of properties file <code>merged-properties.temp</code> written by this task:
|
||||
* <pre>
|
||||
* some.property.exists=true
|
||||
* is.valid=false
|
||||
* hasValue=false
|
||||
* some.property=this is a value
|
||||
* another.property=
|
||||
* property0=bork bork
|
||||
* propertyX=this property wasn't passed in a list
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>If you don't want this task's output to include properties which weren't
|
||||
* in the lists of expected properties, you can set the attribute
|
||||
* <code>onlyExpected</code> to <code>true</code>. In the example, this would
|
||||
* result in the file <code>merged-properties.temp</code> containing only the
|
||||
* following properties:
|
||||
* <pre>
|
||||
* some.property.exists=true
|
||||
* is.valid=false
|
||||
* hasValue=false
|
||||
* some.property=this is a value
|
||||
* another.property=
|
||||
* property0=bork bork
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author smeghead
|
||||
*/
|
||||
public class MergeTypedPropertiesTask extends Task {
|
||||
|
||||
private String _booleanList = "";
|
||||
private String _inputFile;
|
||||
private boolean _onlyExpected;
|
||||
private String _outputFile;
|
||||
private Properties _propertiesIn = new Properties();
|
||||
private Properties _propertiesOut = new Properties();
|
||||
private String _stringList = "";
|
||||
|
||||
public void execute() throws BuildException {
|
||||
StringTokenizer strtokBoolean = new StringTokenizer(_booleanList, ",");
|
||||
StringTokenizer strtokString = new StringTokenizer(_stringList, ",");
|
||||
String property = "";
|
||||
|
||||
if (_inputFile == null)
|
||||
throw new BuildException("Error: 'mergetypedproperties' task requires 'input' attribute");
|
||||
|
||||
if (_outputFile == null)
|
||||
throw new BuildException("Error: 'mergetypedproperties' task requires 'output' attribute");
|
||||
|
||||
// Add some type-checking on the list elements
|
||||
|
||||
try {
|
||||
_propertiesIn.load(new FileInputStream(_inputFile));
|
||||
|
||||
while (strtokBoolean.hasMoreTokens())
|
||||
_propertiesOut.setProperty(strtokBoolean.nextToken().trim(), "false");
|
||||
|
||||
while (strtokString.hasMoreTokens())
|
||||
_propertiesOut.setProperty(strtokString.nextToken().trim(), "");
|
||||
|
||||
for (Enumeration enumm = _propertiesIn.elements(); enumm.hasMoreElements(); ) {
|
||||
property = (String) enumm.nextElement();
|
||||
|
||||
if (_onlyExpected && !_propertiesOut.containsKey(property))
|
||||
continue;
|
||||
else
|
||||
_propertiesOut.setProperty(property, _propertiesIn.getProperty(property));
|
||||
}
|
||||
|
||||
_propertiesOut.store(new FileOutputStream(_inputFile), "This is a temporary file. It is safe to delete it.");
|
||||
} catch (IOException ioe) {
|
||||
throw new BuildException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBooleanList(String booleanList) {
|
||||
_booleanList = booleanList;
|
||||
}
|
||||
|
||||
public void setInput(String inputFile) {
|
||||
_inputFile = inputFile;
|
||||
}
|
||||
|
||||
public void setOnlyExpected(boolean onlyExpected) {
|
||||
_onlyExpected = onlyExpected;
|
||||
}
|
||||
|
||||
public void setOutput(String outputFile) {
|
||||
_outputFile = outputFile;
|
||||
}
|
||||
|
||||
public void setStringList(String stringList) {
|
||||
_stringList = stringList;
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
What is Pants?
|
||||
--------------
|
||||
|
||||
Pants is an Apache Ant-based package manager for the management of 3rd party
|
||||
dependencies in Java development projects. It's loosely modeled after
|
||||
FreeBSD's Ports and Gentoo Linux's Portage, with two major differences:
|
||||
|
||||
* Pants isn't intended for system-wide package management. It's tailored for
|
||||
per-project 3rd party package management. You will typically have one
|
||||
Pants repository per project and each repository will be located somewhere
|
||||
under your project's root directory. If you're familiar with Ports or
|
||||
Portage, a Pants repository is roughly analogous to /usr/ports or
|
||||
/usr/portage.
|
||||
|
||||
* Pants is extremely portable. It goes anywhere Apache Ant goes.
|
||||
|
||||
Pants takes a modular approach to the standard Ant buildfile, breaking it
|
||||
into 3 files for functionality and convenience:
|
||||
|
||||
1. The Pants public interface, pants/build.xml, provides a single consistent
|
||||
way to access and manipulate dependency packages and relieves some of the
|
||||
developer's burden by providing implementations for some frequently-used
|
||||
and complex Ant operations.
|
||||
|
||||
2. pbuild.xml is a specially-structured and slimmed-down Ant buildfile in
|
||||
which you implement custom handling for a package your project depends
|
||||
on. This is known as the "pbuild" and is roughly analogous to a FreeBSD
|
||||
port or a Gentoo ebuild. A fairly explanatory template for pbuilds,
|
||||
pbuild.template.xml, is provided.
|
||||
|
||||
3. pbuild.properties contains those properties for a specific pbuild which
|
||||
are most likely to change over time. It uses the java.util.Properties
|
||||
format which is more human-friendly for hand-editing than Ant/XML. A
|
||||
fairly explanatory template, pbuild.template.properties, is provided.
|
||||
|
||||
There is one more file that completes the Pants system: the metadata file
|
||||
pants/world is a database for keeping track of all packages managed by Pants
|
||||
for your project.
|
||||
|
||||
Pants automatically handles versioning for your project's dependency
|
||||
packages and keeps track of their recommended versions, currently used
|
||||
versions, and latest available versions. This makes it extremely simple for
|
||||
project developers to switch back and forth between different versions of a
|
||||
dependency, and makes it just as easy to update a dependency. You can even
|
||||
update all your project's Pants-managed packages with a single command.
|
||||
|
||||
Pbuilds are designed to automatically handle the downloading, building,
|
||||
repackaging and deployment of source archives, binary archives, and CVS
|
||||
sources, all in a manner that's completely transparent to the project
|
||||
developer. Pbuilds currently support tar + gzip, tar + bzip2, and zip
|
||||
archives.
|
||||
|
||||
Because it is based on Ant, Pants integrates very well with Ant buildfiles
|
||||
and will fit easily into your project's Ant build framework. However, its
|
||||
interface is simple enough to be called just as easily by more traditional
|
||||
build systems such as GNU Make.
|
||||
|
||||
|
||||
Why Should I Use Pants?
|
||||
-----------------------
|
||||
|
||||
There are many applications for Pants, but a few use cases should best serve
|
||||
to illustrate its usefulness:
|
||||
|
||||
1. You have a project that you ship with several 3rd party libraries but the
|
||||
versions you're using are stale. With a single command, Pants can
|
||||
automatically discover the latest release versions for all of these, then
|
||||
download, build, and place the fresh libraries where your project's main
|
||||
build system expects them to be at build time.
|
||||
|
||||
2. You want to test multiple versions of a 3rd party library against your
|
||||
project. Pants only requires you to issue a single command to switch
|
||||
library versions, so can spend more time testing and less time hunting
|
||||
packages down, unpackaging them, symlinking, etc.
|
||||
|
||||
3. Pants is public domain. You can ship it with your project if you need to
|
||||
without having to worry about petty intellectual property or licensing
|
||||
issues.
|
||||
|
||||
|
||||
Minimum Requirements
|
||||
--------------------
|
||||
|
||||
* Apache Ant 1.6.2 or higher is recommended
|
||||
|
||||
* Any Java runtime and operating system that will run Ant
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Not finished yet.
|
||||
|
||||
|
||||
Why the Silly Name?
|
||||
-------------------
|
||||
|
||||
Ports + Ant = Pants. Any other explanation is purely a product of your
|
||||
twisted imagination.
|
||||
|
||||
|
||||
Miscellaneous Pocket Fluff
|
||||
--------------------------
|
||||
|
||||
Author: smeghead <smeghead@i2pmail.org> <smeghead@mail.i2p>
|
||||
|
||||
License: No license necessary. This work is released into the public domain.
|
||||
|
||||
Price: Free! But if you really appreciate Pants, or you're just a sicko,
|
||||
please send me a picture of your worst or most unusual pair of
|
||||
pants so I can add it to the Whirling Hall of Pants on pants.i2p,
|
||||
the official Pants eepsite (that's an anonymous website on I2P--see
|
||||
http://www.i2p.net for more information).
|
||||
|
||||
|
||||
$Id$
|
@ -1,110 +0,0 @@
|
||||
# The properties defined in this file can be overridden on the command line by
|
||||
# passing them in as parameters like so:
|
||||
#
|
||||
# ant -Dpbuild=myapp -Dversion.recommended=2.0.5 install
|
||||
#
|
||||
# *** DO NOT DEFINE A PROPERTY BUT LEAVE ITS VALUE BLANK. PANTS WILL BREAK! ***
|
||||
|
||||
|
||||
# Recommended Package Version
|
||||
#
|
||||
# Set this property's value to the package version you want Pants to use for the
|
||||
# pbuild by default. The version string specified must match the version
|
||||
# substring from the package's filename if the filename contains a version
|
||||
# number.
|
||||
#
|
||||
# Comment out this property to force use of the latest available version.
|
||||
#
|
||||
# If the pbuild is CVS-based rather than package-based, this property must be
|
||||
# set to 'CVS'.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# version.recommended=2.0.4
|
||||
|
||||
|
||||
# Latest Package Version
|
||||
#
|
||||
# There are currently two ways to inform Pants of the latest version number for
|
||||
# your package.
|
||||
#
|
||||
# Method 1: Manually modify the property 'version.latest' to reflect the latest
|
||||
# version number.
|
||||
#
|
||||
# Method 2: Provide a URL for a page on the package's website and a regular
|
||||
# expression with which to parse it in order to extract the version
|
||||
# number of the latest available package. For this you must define the
|
||||
# properties 'version.latest.find.url', 'version.latest.find.regex',
|
||||
# and any regular expression engine mode flags needed. The pattern
|
||||
# defined must have exactly one capturing group to encapsulate the
|
||||
# version string, otherwise the operation will fail.
|
||||
#
|
||||
# You may use both methods, in which case the version number specified by Method
|
||||
# 1 will be used as the fallback value if Method 2 for some reason is
|
||||
# unsuccessful.
|
||||
#
|
||||
# If neither method is enabled here or they fail to return a valid value to
|
||||
# Pants, the 'ant update' operation for this pbuild may exit ungracefully unless
|
||||
# the pbuild is CVS-based (none of the version.latest.* properties are used by
|
||||
# CVS-based pbuilds).
|
||||
#
|
||||
# The following is a list of boolean properties for optional mode flags used by
|
||||
# the regular expression engine. Set a value of "true" for any you wish to use.
|
||||
#
|
||||
# version.latest.find.regex.canonicaleq - Enable canonical equivalence
|
||||
# version.latest.find.regex.caseinsensitive - Enable case-insensitive matching
|
||||
# version.latest.find.regex.comments - Permit whitespace and comments
|
||||
# version.latest.find.regex.dotall - Enable dotall mode
|
||||
# version.latest.find.regex.multiline - Enable multi-line mode
|
||||
# version.latest.find.regex.unicodecase - Enable Unicode-aware case folding
|
||||
# version.latest.find.regex.unixlines - Enable Unix lines mode
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# version.latest=5.1.2
|
||||
# version.latest.find.url=http://sourceforge.net/projects/jetty/
|
||||
# version.latest.find.regex=Stable.+?Jetty-(.+?)</A>
|
||||
|
||||
|
||||
# Package URL
|
||||
#
|
||||
# Specify the URL pointing to the pbuild's package from here. The token
|
||||
# '${pbuild.version}' if used will automatically be expanded to the appropriate
|
||||
# version string.
|
||||
#
|
||||
# The package URL property is not used by CVS-based pbuilds.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# package.url=ftp://borkbork.se/bork-${pbuild.version}.tar.bz2
|
||||
# package.url=http://bork.borkbork.se/bork-${pbuild.version}-src.tar.gz
|
||||
|
||||
|
||||
# CVS Repository
|
||||
#
|
||||
# The values expected for CVS properties here are the same as those expected by
|
||||
# their corresponding Apache Ant 'Cvs' task attributes. For details see:
|
||||
#
|
||||
# http://ant.apache.org/manual/CoreTasks/cvs.html
|
||||
#
|
||||
# Not all of the 'Cvs' task's attributes have corresponding Pants properties.
|
||||
# The following is a list of all valid CVS properties for Pants (and their
|
||||
# default values if applicable):
|
||||
#
|
||||
# cvs.compression.level
|
||||
# cvs.date
|
||||
# cvs.package
|
||||
# cvs.passfile=~/.cvspass
|
||||
# cvs.port=2401
|
||||
# cvs.root
|
||||
# cvs.rsh
|
||||
# cvs.tag
|
||||
#
|
||||
# Of these, only the 'cvs.root' property is required for CVS-based pbuilds.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# cvs.root=:pserver:anoncvs@borkbork.se:/cvsroot/bork
|
||||
# cvs.rsh=ssh
|
||||
# cvs.package=borkbork
|
||||
|
@ -1,69 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
This is a template for Pants pbuilds. Pbuilds use standard Apache Ant syntax.
|
||||
For each target in the Public Interface section you must provide either an
|
||||
implementation or a stub. You may also add your own custom tasks and
|
||||
properties to this file. Be careful that none of your custom properties'
|
||||
names clash with the properties defined in pants/build.xml.
|
||||
-->
|
||||
|
||||
<project basedir="." default="build" name="name-of-pbuild-here">
|
||||
|
||||
<!-- ....................... Begin Public Interface ........................ -->
|
||||
|
||||
<!--
|
||||
When this target is called, the pbuild's sources and/or binaries have
|
||||
already been extracted/copied by Pants into the pbuild's working/
|
||||
subdirectory. This target must prepare those sources and/or binaries in
|
||||
the working/ subdirectory into deployable form, for example by building
|
||||
all necessary classes and jar files.
|
||||
|
||||
This target must not create or modify any files outside the pbuild's
|
||||
working/ subdirectory. (An automatic sandboxing mechanism should be added
|
||||
to Pants at some point.) It is however acceptable for a task called by
|
||||
'builddep' to modify files outside of this pbuild's working/ directory.
|
||||
-->
|
||||
<target name="build" depends="builddep" />
|
||||
|
||||
<!--
|
||||
Use this to call targets from other pbuilds, Ant buildfiles, Makefiles,
|
||||
etc. which perform tasks this pbuild's 'build' target depends on. If other
|
||||
pbuilds are called here, they must be called through the Pants interface
|
||||
or else it may leave Pants in an inconsistent state.
|
||||
|
||||
Most pbuilds probably won't need to implement this target.
|
||||
-->
|
||||
<target name="builddep" />
|
||||
|
||||
<!--
|
||||
This target must undo the actions performed by the 'build' target.
|
||||
-->
|
||||
<target name="clean" depends="depclean" />
|
||||
|
||||
<!--
|
||||
If the 'builddep' target is implemented, this target must be implemented
|
||||
to undo its actions.
|
||||
-->
|
||||
<target name="depclean" />
|
||||
|
||||
<!--
|
||||
This target must copy all deployable files generated by the 'build' target
|
||||
into the pbuild's dist/ subdirectory (for use by other pbuilds or Ant
|
||||
processes) or to their final deployment locations outside the pants/
|
||||
directory hierarchy. Note that the latter may require the user to gain
|
||||
superuser/admin privileges.
|
||||
-->
|
||||
<target name="dist" depends="build" />
|
||||
|
||||
<!--
|
||||
This target must remove all files from the pbuild's dist/ subdirectory
|
||||
and final deployment locations, reversing the actions of the 'dist'
|
||||
target. Note that removal of files from their final deployment locations
|
||||
may require the user to gain superuser/admin privileges.
|
||||
-->
|
||||
<target name="distclean" depends="clean" />
|
||||
|
||||
<!-- ........................ End Public Interface ......................... -->
|
||||
|
||||
</project>
|
@ -1,112 +0,0 @@
|
||||
# The properties defined in this file can be overridden on the command line by
|
||||
# passing them in as parameters like so:
|
||||
#
|
||||
# ant -Dpbuild=myapp -Dversion.recommended=2.0.5 install
|
||||
#
|
||||
# *** DO NOT DEFINE A PROPERTY BUT LEAVE ITS VALUE BLANK. PANTS WILL BREAK! ***
|
||||
|
||||
|
||||
# Recommended Package Version
|
||||
#
|
||||
# Set this property's value to the package version you want Pants to use for the
|
||||
# pbuild by default. The version string specified must match the version
|
||||
# substring from the package's filename if the filename contains a version
|
||||
# number.
|
||||
#
|
||||
# Comment out this property to force use of the latest available version.
|
||||
#
|
||||
# If the pbuild is CVS-based rather than package-based, this property must be
|
||||
# set to 'CVS'.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# version.recommended=2.0.4
|
||||
version.recommended=CVS
|
||||
|
||||
# Latest Package Version
|
||||
#
|
||||
# There are currently two ways to inform Pants of the latest version number for
|
||||
# your package.
|
||||
#
|
||||
# Method 1: Manually modify the property 'version.latest' to reflect the latest
|
||||
# version number.
|
||||
#
|
||||
# Method 2: Provide a URL for a page on the package's website and a regular
|
||||
# expression with which to parse it in order to extract the version
|
||||
# number of the latest available package. For this you must define the
|
||||
# properties 'version.latest.find.url', 'version.latest.find.regex',
|
||||
# and any regular expression engine mode flags needed. The pattern
|
||||
# defined must have exactly one capturing group to encapsulate the
|
||||
# version string, otherwise the operation will fail.
|
||||
#
|
||||
# You may use both methods, in which case the version number specified by Method
|
||||
# 1 will be used as the fallback value if Method 2 for some reason is
|
||||
# unsuccessful.
|
||||
#
|
||||
# If neither method is enabled here or they fail to return a valid value to
|
||||
# Pants, the 'ant update' operation for this pbuild may exit ungracefully unless
|
||||
# the pbuild is CVS-based (none of the version.latest.* properties are used by
|
||||
# CVS-based pbuilds).
|
||||
#
|
||||
# The following is a list of boolean properties for optional mode flags used by
|
||||
# the regular expression engine. Set a value of "true" for any you wish to use.
|
||||
#
|
||||
# version.latest.find.regex.canonicaleq - Enable canonical equivalence
|
||||
# version.latest.find.regex.caseinsensitive - Enable case-insensitive matching
|
||||
# version.latest.find.regex.comments - Permit whitespace and comments
|
||||
# version.latest.find.regex.dotall - Enable dotall mode
|
||||
# version.latest.find.regex.multiline - Enable multi-line mode
|
||||
# version.latest.find.regex.unicodecase - Enable Unicode-aware case folding
|
||||
# version.latest.find.regex.unixlines - Enable Unix lines mode
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# version.latest=5.1.2
|
||||
# version.latest.find.url=http://sourceforge.net/projects/jetty/
|
||||
# version.latest.find.regex=Stable.+?Jetty-(.+?)</A>
|
||||
|
||||
|
||||
# Package URL
|
||||
#
|
||||
# Specify the URL pointing to the pbuild's package from here. The token
|
||||
# '${pbuild.version}' if used will automatically be expanded to the appropriate
|
||||
# version string.
|
||||
#
|
||||
# The package URL property is not used by CVS-based pbuilds.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# package.url=ftp://borkbork.se/bork-${pbuild.version}.tar.bz2
|
||||
# package.url=http://bork.borkbork.se/bork-${pbuild.version}-src.tar.gz
|
||||
|
||||
|
||||
# CVS Repository
|
||||
#
|
||||
# The values expected for CVS properties here are the same as those expected by
|
||||
# their corresponding Apache Ant 'Cvs' task attributes. For details see:
|
||||
#
|
||||
# http://ant.apache.org/manual/CoreTasks/cvs.html
|
||||
#
|
||||
# Not all of the 'Cvs' task's attributes have corresponding Pants properties.
|
||||
# The following is a list of all valid CVS properties for Pants (and their
|
||||
# default values if applicable):
|
||||
#
|
||||
# cvs.compression.level
|
||||
# cvs.date
|
||||
# cvs.package
|
||||
# cvs.passfile=~/.cvspass
|
||||
# cvs.port=2401
|
||||
# cvs.root
|
||||
# cvs.rsh
|
||||
# cvs.tag
|
||||
#
|
||||
# Of these, only the 'cvs.root' property is required for CVS-based pbuilds.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# cvs.root=:pserver:anoncvs@borkbork.se:/cvsroot/bork
|
||||
# cvs.rsh=ssh
|
||||
# cvs.package=borkbork
|
||||
cvs.root=:ext:anoncvs@savannah.gnu.org:/cvsroot/gnu-crypto
|
||||
cvs.rsh=ssh
|
||||
cvs.package=gnu-crypto
|
@ -1,127 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="build" name="fortuna-pbuild">
|
||||
|
||||
<property name="gnucrypt.base.dir" value="./working/gnu-crypto" />
|
||||
<property name="gnucrypt.etc.dir" value="${gnucrypt.base.dir}/etc" />
|
||||
<property name="gnucrypt.lib.dir" value="${gnucrypt.base.dir}/lib" />
|
||||
<property name="gnucrypt.object.dir" value="${gnucrypt.base.dir}/classes" />
|
||||
<property name="gnucrypt.base.crypto.object.dir" value="${gnucrypt.object.dir}/gnu/crypto" />
|
||||
<property name="gnucrypt.cipher.object.dir" value="${gnucrypt.base.crypto.object.dir}/cipher" />
|
||||
<property name="gnucrypt.hash.object.dir" value="${gnucrypt.base.crypto.object.dir}/hash" />
|
||||
<property name="gnucrypt.prng.object.dir" value="${gnucrypt.base.crypto.object.dir}/prng" />
|
||||
|
||||
<patternset id="fortuna.files">
|
||||
<include name="${gnucrypt.base.crypto.object.dir}/Registry.class" />
|
||||
<include name="${gnucrypt.prng.object.dir}/Fortuna*.class" />
|
||||
<include name="${gnucrypt.prng.object.dir}/BasePRNG.class" />
|
||||
<include name="${gnucrypt.prng.object.dir}/RandomEventListener.class" />
|
||||
<include name="${gnucrypt.prng.object.dir}/IRandom.class" />
|
||||
<include name="${gnucrypt.cipher.object.dir}/CipherFactory.class" />
|
||||
<include name="${gnucrypt.cipher.object.dir}/IBlockCipher.class" />
|
||||
<include name="${gnucrypt.hash.object.dir}/HashFactory.class" />
|
||||
<include name="${gnucrypt.hash.object.dir}/IMessageDigest.class" />
|
||||
</patternset>
|
||||
|
||||
<!--
|
||||
Add this when Fortuna tests are added to GNU Crypto, else write some
|
||||
-->
|
||||
<target name="-test" />
|
||||
|
||||
<!-- ....................... Begin Public Interface ........................ -->
|
||||
|
||||
<!--
|
||||
When this target is called, the pbuild's sources and/or binaries have
|
||||
already been extracted/copied by Pants into the pbuild's working/
|
||||
subdirectory. This target must prepare those sources and/or binaries in
|
||||
the working/ subdirectory into deployable form, for example by building
|
||||
all necessary classes and jar files.
|
||||
|
||||
This target must not create or modify any files outside the pbuild's
|
||||
working/ subdirectory. (An automatic sandboxing mechanism should be added
|
||||
to Pants at some point.) It is however acceptable for a task called by
|
||||
'builddep' to modify files outside of this pbuild's working/ directory.
|
||||
-->
|
||||
<target name="build" depends="builddep">
|
||||
<delete dir="./working/build" />
|
||||
<delete dir="./working/jartemp" />
|
||||
<mkdir dir="./working/build" />
|
||||
<mkdir dir="./working/jartemp/${gnucrypt.object.dir}" />
|
||||
<copy todir="./working/jartemp">
|
||||
<fileset dir=".">
|
||||
<patternset refid="fortuna.files" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<jar basedir="./working/jartemp/${gnucrypt.object.dir}" jarfile="./working/build/fortuna.jar">
|
||||
<manifest>
|
||||
<section name="fortuna">
|
||||
<attribute name="Implementation-Title" value="I2P Custom GNU Crypto Fortuna Library" />
|
||||
<attribute name="Implementation-Version" value="CVS HEAD" />
|
||||
<attribute name="Implementation-Vendor" value="Free Software Foundation" />
|
||||
<attribute name="Implementation-Vendor-Id" value="FSF" />
|
||||
<attribute name="Implementation-URL" value="http://www.gnu.org/software/gnu-crypto" />
|
||||
</section>
|
||||
</manifest>
|
||||
</jar>
|
||||
<delete dir="./working/jartemp" />
|
||||
</target>
|
||||
|
||||
<!--
|
||||
Use this to call targets from other pbuilds, Ant buildfiles, Makefiles,
|
||||
etc. which perform tasks this pbuild's 'build' target depends on. If other
|
||||
pbuilds are called here, they must be called through the Pants interface
|
||||
or else it may leave Pants in an inconsistent state.
|
||||
|
||||
Most pbuilds probably won't need to implement this target.
|
||||
-->
|
||||
<target name="builddep">
|
||||
<ant dir="${gnucrypt.base.dir}" target="jar" />
|
||||
</target>
|
||||
|
||||
<!--
|
||||
This target must undo the actions performed by the 'build' target.
|
||||
-->
|
||||
<target name="clean" depends="depclean">
|
||||
<delete dir="./working/jartemp" />
|
||||
</target>
|
||||
|
||||
<!--
|
||||
If the 'builddep' target is implemented, this target must be implemented
|
||||
to undo its actions.
|
||||
-->
|
||||
<target name="depclean">
|
||||
<!--
|
||||
Annoyingly the GNU Crypto distclean task called here doesn't clean
|
||||
*all* derived files from java/gnu-crypto/lib like it should (because
|
||||
a couple of lines are commented out).....
|
||||
-->
|
||||
<ant dir="${gnucrypt.base.dir}" target="distclean" />
|
||||
<!--
|
||||
.....and so we mop up the rest ourselves.
|
||||
-->
|
||||
<delete dir="${gnucrypt.lib.dir}" />
|
||||
</target>
|
||||
|
||||
<!--
|
||||
This target must copy all deployable files generated by the 'build' target
|
||||
into the pbuild's dist/ subdirectory (for use by other pbuilds or Ant
|
||||
processes) or to their final deployment locations outside the pants/
|
||||
directory hierarchy. Note that the latter may require the user to gain
|
||||
superuser/admin privileges.
|
||||
-->
|
||||
<target name="dist" depends="build">
|
||||
<copy todir="./dist/fortuna.jar" file="./working/build/fortuna.jar" />
|
||||
</target>
|
||||
|
||||
<!--
|
||||
This target must remove all files from the pbuild's dist/ subdirectory
|
||||
and final deployment locations, reversing the actions of the 'dist'
|
||||
target. Note that removal of files from their final deployment locations
|
||||
may require the user to gain superuser/admin privileges.
|
||||
-->
|
||||
<target name="distclean" depends="clean">
|
||||
<delete file="./dist/fortuna.jar" />
|
||||
</target>
|
||||
|
||||
<!-- ........................ End Public Interface ......................... -->
|
||||
|
||||
</project>
|
@ -1,112 +0,0 @@
|
||||
# The properties defined in this file can be overridden on the command line by
|
||||
# passing them in as parameters like so:
|
||||
#
|
||||
# ant -Dpbuild=myapp -Dversion.recommended=2.0.5 install
|
||||
#
|
||||
# *** DO NOT DEFINE A PROPERTY BUT LEAVE ITS VALUE BLANK. PANTS WILL BREAK! ***
|
||||
|
||||
|
||||
# Recommended Package Version
|
||||
#
|
||||
# Set this property's value to the package version you want Pants to use for the
|
||||
# pbuild by default. The version string specified must match the version
|
||||
# substring from the package's filename if the filename contains a version
|
||||
# number.
|
||||
#
|
||||
# Comment out this property to force use of the latest available version.
|
||||
#
|
||||
# If the pbuild is CVS-based rather than package-based, this property must be
|
||||
# set to 'CVS'.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# version.recommended=2.0.4
|
||||
version.recommended=5.1.2
|
||||
|
||||
# Latest Package Version
|
||||
#
|
||||
# There are currently two ways to inform Pants of the latest version number for
|
||||
# your package.
|
||||
#
|
||||
# Method 1: Manually modify the property 'version.latest' to reflect the latest
|
||||
# version number.
|
||||
#
|
||||
# Method 2: Provide a URL for a page on the package's website and a regular
|
||||
# expression with which to parse it in order to extract the version
|
||||
# number of the latest available package. For this you must define the
|
||||
# properties 'version.latest.find.url', 'version.latest.find.regex',
|
||||
# and any regular expression engine mode flags needed. The pattern
|
||||
# defined must have exactly one capturing group to encapsulate the
|
||||
# version string, otherwise the operation will fail.
|
||||
#
|
||||
# You may use both methods, in which case the version number specified by Method
|
||||
# 1 will be used as the fallback value if Method 2 for some reason is
|
||||
# unsuccessful.
|
||||
#
|
||||
# If neither method is enabled here or they fail to return a valid value to
|
||||
# Pants, the 'ant update' operation for this pbuild may exit ungracefully unless
|
||||
# the pbuild is CVS-based (none of the version.latest.* properties are used by
|
||||
# CVS-based pbuilds).
|
||||
#
|
||||
# The following is a list of boolean properties for optional mode flags used by
|
||||
# the regular expression engine. Set a value of "true" for any you wish to use.
|
||||
#
|
||||
# version.latest.find.regex.canonicaleq - Enable canonical equivalence
|
||||
# version.latest.find.regex.caseinsensitive - Enable case-insensitive matching
|
||||
# version.latest.find.regex.comments - Permit whitespace and comments
|
||||
# version.latest.find.regex.dotall - Enable dotall mode
|
||||
# version.latest.find.regex.multiline - Enable multi-line mode
|
||||
# version.latest.find.regex.unicodecase - Enable Unicode-aware case folding
|
||||
# version.latest.find.regex.unixlines - Enable Unix lines mode
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# version.latest=5.1.2
|
||||
# version.latest.find.url=http://sourceforge.net/projects/jetty/
|
||||
# version.latest.find.regex=Stable.+?Jetty-(.+?)</A>
|
||||
version.latest=5.1.2
|
||||
version.latest.find.url=http://sourceforge.net/projects/jetty/
|
||||
version.latest.find.regex=Stable.+?Jetty-(.+?)</A>
|
||||
|
||||
# Package URL
|
||||
#
|
||||
# Specify the URL pointing to the pbuild's package from here. The token
|
||||
# '${pbuild.version}' if used will automatically be expanded to the appropriate
|
||||
# version string.
|
||||
#
|
||||
# The package URL property is not used by CVS-based pbuilds.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# package.url=ftp://borkbork.se/bork-${pbuild.version}.tar.bz2
|
||||
# package.url=http://bork.borkbork.se/bork-${pbuild.version}-src.tar.gz
|
||||
package.url=http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-${pbuild.version}.zip
|
||||
|
||||
# CVS Repository
|
||||
#
|
||||
# The values expected for CVS properties here are the same as those expected by
|
||||
# their corresponding Apache Ant 'Cvs' task attributes. For details see:
|
||||
#
|
||||
# http://ant.apache.org/manual/CoreTasks/cvs.html
|
||||
#
|
||||
# Not all of the 'Cvs' task's attributes have corresponding Pants properties.
|
||||
# The following is a list of all valid CVS properties for Pants (and their
|
||||
# default values if applicable):
|
||||
#
|
||||
# cvs.compression.level
|
||||
# cvs.date
|
||||
# cvs.package
|
||||
# cvs.passfile=~/.cvspass
|
||||
# cvs.port=2401
|
||||
# cvs.root
|
||||
# cvs.rsh
|
||||
# cvs.tag
|
||||
#
|
||||
# Of these, only the 'cvs.root' property is required for CVS-based pbuilds.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# cvs.root=:pserver:anoncvs@borkbork.se:/cvsroot/bork
|
||||
# cvs.rsh=ssh
|
||||
# cvs.package=borkbork
|
||||
|
@ -1,89 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="jetty">
|
||||
|
||||
<!-- make this generic, place variables in properties file -->
|
||||
|
||||
<target name="all" depends="build"
|
||||
description="Run the build target" />
|
||||
|
||||
<target name="assignProperties" if="group.0">
|
||||
<property name="latest.jetty.version" value="${group.1}" />
|
||||
<available property="jetty.package.available" file="jetty-${latest.jetty.version}.zip" />
|
||||
<available property="jetty.package.unpacked.available" file="jettypkg/jetty-${latest.jetty.version}" />
|
||||
<echo message="Properties assigned" />
|
||||
</target>
|
||||
|
||||
<target name="build" depends="init, unpackJettyPackage" if="latest.jetty.version"
|
||||
description="Download latest Jetty package and copy needed libs to jettylib/">
|
||||
<property name="unpack.dir" value="jettypkg/jetty-${latest.jetty.version}" />
|
||||
<copy todir="jettylib" overwrite="true" file="${unpack.dir}/ext/ant.jar" />
|
||||
<copy todir="jettylib" overwrite="true" file="${unpack.dir}/ext/jasper-compiler.jar" />
|
||||
<copy todir="jettylib" overwrite="true" file="${unpack.dir}/ext/jasper-runtime.jar" />
|
||||
<copy todir="jettylib" overwrite="true" file="${unpack.dir}/ext/xercesImpl.jar" />
|
||||
<copy todir="jettylib" overwrite="true" file="${unpack.dir}/ext/xml-apis.jar" />
|
||||
<copy todir="jettylib" overwrite="true" file="${unpack.dir}/extra/lib/org.mortbay.jetty-jdk1.2.jar" />
|
||||
<copy todir="jettylib" overwrite="true" file="${unpack.dir}/lib/javax.servlet.jar" />
|
||||
<copy todir="jettylib" overwrite="true" file="${unpack.dir}/lib/org.mortbay.jetty.jar" />
|
||||
<copy todir="jettylib" overwrite="true">
|
||||
<fileset dir="${unpack.dir}/ext" includes="xmlParserAPIs*.jar" />
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="builddep"
|
||||
description="Build the custom helper Ant task for this buildfile">
|
||||
<mkdir dir="java/build"/>
|
||||
<javac srcdir="./java/src" source="1.3" target="1.3" deprecation="on" destdir="./java/build" />
|
||||
</target>
|
||||
|
||||
<target name="clean"
|
||||
description="Remove temp files and zip only; jettypkg/ requires manual deletion">
|
||||
<echo message="Not actually deleting the Jetty package directory since it's so large" />
|
||||
<delete>
|
||||
<fileset dir="." includes="*.zip jettytemp.html parsed.temp" />
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<target name="cleandep"
|
||||
description="Remove custom helper Ant task">
|
||||
<delete dir="java/build" />
|
||||
</target>
|
||||
|
||||
<target name="compile" />
|
||||
|
||||
<target name="distclean" depends="clean"
|
||||
description="Remove temp files, zip and jettylib/ contents" >
|
||||
<delete>
|
||||
<fileset dir="jettylib" includes="*.jar"/>
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<target name="fetchJettyPackage" if="latest.jetty.version" unless="jetty.package.available">
|
||||
<echo message="The Jetty libs are not necessary for using I2P, but are used by some" />
|
||||
<echo message="applications on top of I2P such as the routerconsole." />
|
||||
<get src="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-${latest.jetty.version}.zip" verbose="true" dest="jetty-${latest.jetty.version}.zip" />
|
||||
</target>
|
||||
|
||||
<target name="init" depends="builddep">
|
||||
<echo message="Checking SourceForge for latest Jetty version....." />
|
||||
<get src="http://sourceforge.net/projects/jetty/" dest="jettytemp.html" verbose="true" />
|
||||
<taskdef name="match" classname="net.i2p.pants.MatchTask" classpath="../../lib/pants.jar" />
|
||||
<match input="jettytemp.html"
|
||||
output="parsed.temp"
|
||||
regex="Stable.+?Jetty-(.+?)</A>"
|
||||
/>
|
||||
<loadproperties srcFile="parsed.temp" />
|
||||
<antcall target="assignProperties" />
|
||||
</target>
|
||||
|
||||
<target name="jar" />
|
||||
|
||||
<target name="showlatest" depends="init"
|
||||
description="Display latest version number for Jetty">
|
||||
<echo message="Latest Jetty version: ${latest.jetty.version}" />
|
||||
</target>
|
||||
|
||||
<target name="unpackJettyPackage" depends="fetchJettyPackage" if="latest.jetty.version" unless="jetty.package.unpacked.available">
|
||||
<mkdir dir="jettypkg" />
|
||||
<unzip src="jetty-${latest.jetty.version}.zip" dest="jettypkg" />
|
||||
</target>
|
||||
</project>
|
@ -1,2 +0,0 @@
|
||||
version.using.fortuna=CVS
|
||||
version.using.jetty=5.1.2
|
Before Width: | Height: | Size: 32 KiB |
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Q System Diagrams</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Q Diagrams</h1>
|
||||
Informal system diagrams of Q network, hubs and clients.
|
||||
<center>
|
||||
<hr>
|
||||
<img src="overall.jpg">
|
||||
<hr>
|
||||
<img src="client.jpg">
|
||||
<hr>
|
||||
<img src="hub.jpg">
|
||||
</center>
|
||||
<hr>
|
||||
|
||||
<address><a href="mailto:aum@mail.i2p">aum</a></address>
|
||||
<!-- Created: Sat Apr 16 17:24:02 NZST 2005 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Mon Apr 18 14:06:02 NZST 2005
|
||||
<!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 27 KiB |
@ -1,80 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Quartermaster - I2P Distributed File Store</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<h1>Quartermaster<br>an I2P Distributed File Store</h1>
|
||||
|
||||
<h3>STATUS<h3>
|
||||
<i>Whole new (incompatible) version currently in development;
|
||||
ETA for release approx 4-7 days;
|
||||
view screenshots <a href="screenshots.html">here</a>
|
||||
</i>
|
||||
<br>
|
||||
<hr>
|
||||
|
||||
<small>
|
||||
<a href="manual/index.html">User Manual</a> |
|
||||
<a href="spec/index.html">Protocol Spec</a> |
|
||||
<a href="metadata.html">Metadata Spec</a> |
|
||||
<a href="diagrams.html">Q Pr0n (diagrams)</a> |
|
||||
<a href="api/index.html">API Spec</a> |
|
||||
<a href="qnoderefs.txt">qnoderefs.txt</a> |
|
||||
Full Download |
|
||||
Updated jar
|
||||
</small>
|
||||
</center>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Intro</h2>
|
||||
|
||||
Quartermaster, or Q for short, is a distributed file storage framework for I2P.
|
||||
|
||||
<h2>Features</h2>
|
||||
|
||||
<ul>
|
||||
<li>Now features 'QSites' - the Q equivalent of Freenet freesites,
|
||||
static websites which are retrievable even if author is offline</li>
|
||||
<li>Easy web interface - interact with Q (and view/insert QSites)
|
||||
from your web browser</li>
|
||||
<li>Maximum expectations of content retrievability</li>
|
||||
<li>Content security akin to Freenet CHK and SSK keys</li>
|
||||
<li>Powerful, flexible search engine</li>
|
||||
<li>Comfortably accommodates both permanent and transient
|
||||
nodes without significant network disruption (for instance,
|
||||
no flooding of the I2P network with futile
|
||||
calls to offline nodes)</li>
|
||||
<li>Rapid query resolution, due to distributed catalogue
|
||||
mirroring which eliminates all in-network query traffic</li>
|
||||
<li>Modular, extensible architecture</li>
|
||||
<li>Simple interfaces for 3rd-party app developers</li>
|
||||
<li>Is custom-designed and built around I2P, so no duplication of
|
||||
I2P's encryption/anonymity features</li>
|
||||
<li>Simple XML-RPC interface for all inter-node communication, makes it easy to
|
||||
implement user-level clients in any language; also allows alternative
|
||||
implementations of core server and/or client nodes.</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Status</h2>
|
||||
|
||||
Q is presently under development, and a test release is expected soon.
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Architecture</h2>
|
||||
|
||||
Refer to the <a href="spec/index.html">Protocol Specification</a> for more information.
|
||||
|
||||
<hr>
|
||||
<!-- Created: Sat Mar 26 11:09:12 NZST 2005 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Mon Apr 18 18:55:19 NZST 2005
|
||||
<!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
@ -1,805 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Q User/Programmer Manual</title>
|
||||
<style type="text/css">
|
||||
<!--
|
||||
td { vertical-align: top; }
|
||||
code { font-family: courier, monospace; font-weight: bold }
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial, helvetica, sans-serif">
|
||||
<center>
|
||||
<h1>Q User/Programmer Manual</h1>
|
||||
|
||||
<i>A brief but hopefully easy guide to installing and using the Q distributed file
|
||||
store within the I2P network</i>
|
||||
|
||||
<br><br>
|
||||
<i>(Return to <a href="../index.html">Q Homepage</a>)</i>
|
||||
<br>
|
||||
<br>
|
||||
<small>
|
||||
<a href="#intro">Introduction</a> |
|
||||
<a href="#checklist">Checklist</a> |
|
||||
<a href="#serverorclient">Server?orClient?</a> |
|
||||
<a href="#walkthrough">Walkthrough</a> |
|
||||
<a href="#server">Server Nodes</a> |
|
||||
<a href="#qmgr">About QMgr</a> |
|
||||
<a href="#contact">Contact us</a>
|
||||
</small>
|
||||
</center>
|
||||
|
||||
<a name="intro"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>1. Introduction</h2>
|
||||
|
||||
<blockquote>
|
||||
Q is a distributed Peer2Peer file storage/retrieval network that aims to deliver optimal
|
||||
performance by respecting the properties of the I2P network.<br>
|
||||
<br>
|
||||
This manual serves as a 'walkthrough' guide, to take you through the steps from initial
|
||||
download, to everyday usage. It also provides information for the benefit of higher-level
|
||||
client application authors.
|
||||
</blockquote>
|
||||
|
||||
<a name="checklist"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>2. Preliminary Checklist</h2>
|
||||
|
||||
<blockquote>
|
||||
OK, we assume here that you've already cracked the tarball, and are looking at
|
||||
the distribution files.<br>
|
||||
<br>
|
||||
In order to get Q set up and running, you'll need:
|
||||
<ol>
|
||||
<li>An I2P router installed, set up and (permanently or transiently) running</li>
|
||||
<li>Your system shell set up with at the environment variables:
|
||||
<ul>
|
||||
<li><b>CLASSPATH</b> - this should include:
|
||||
<ul>
|
||||
<li>The regular I2P jar files and 3rd party support jar files (eg <b>i2p.jar</b>,
|
||||
<b>i2ptunnel.jar</b>, <b>streaming.jar</b>,
|
||||
<b>mstreaming.jar</b>, <b>jbigi.jar</b>)</li>
|
||||
<li>Apache's XML-RPC support jarfile - included in this Q distro as
|
||||
<b>xmlrpc.jar</b></li>
|
||||
<li>Aum's jarfile <b>aum.jar</b>, which includes Q and all needed support code</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>PATH</b> - your execution search path <b><i>must</i></b> include the directory
|
||||
in which your main java VM execution program (<b>java</b>, or on windows systems,
|
||||
<b>java.exe</b>) resides.<br>
|
||||
<b>NOTE</b> - if <b>java[.exe]</b> is not on your <b>PATH</b>, then Q <i>will
|
||||
not run</i>.</li>
|
||||
</ul>
|
||||
</ol>
|
||||
</blockquote>
|
||||
|
||||
<a name="serverorclient"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>3. Q Server or Q Client?</h2>
|
||||
|
||||
<blockquote>
|
||||
Nearly everyone will want to run a <b>Q Client Node</b>.<br>
|
||||
<Br>
|
||||
It is only client nodes which provide users with full access to the Q network.<br>
|
||||
<br>
|
||||
However, if you have a (near-) permanently running I2P Router, and you're a kind and
|
||||
generous soul, you might <i>also</i> be willing to run a <b>Q Server Node</b> in addition
|
||||
to your <b>Q Client Node</b>.<br>
|
||||
<br>
|
||||
If you do choose to run a server node, you'll be expected to keep it running as near as
|
||||
possible to 24/7. While transience of client nodes - frequent entering and leaving the
|
||||
Q network - causes little or no disruption, transience of server nodes can significantly
|
||||
impair Q's usability for everyone, particularly if this transience occurs frequently amongst
|
||||
more than the smallest percentage of the server node pool.<br>
|
||||
<br>
|
||||
Until you're feeling well "settled in" with Q, your best approach is to just run a
|
||||
client node for now, and add a server node later when you feel ready.<br>
|
||||
</blockquote>
|
||||
|
||||
<a name="walkthrough"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>4. Q Walkthrough</h2>
|
||||
|
||||
<h3>4.1. Introduction</h3>
|
||||
|
||||
<blockquote>
|
||||
This chapter discusses the deployment and usage of a Q Client Node, and will take you
|
||||
through the steps of:
|
||||
<ol>
|
||||
<li>Double-checking that you've met the installation requirements</li>
|
||||
<li>Launching a Q Client Node</li>
|
||||
<li>Verifying that your Q Client Node is running</li>
|
||||
<li>If your node fails to launch, figuring out why</li>
|
||||
<li>Importing one or more noderefs into your node</li>
|
||||
<li>Observing that your node is discovering other nodes on the network</li>
|
||||
<li>Observing that your node is discovering content on the network</li>
|
||||
<li>Searching for items of content that match chosen criteria</li>
|
||||
<li>Retrieving stuff from the network</li>
|
||||
<li>Inserting stuff to the network</li>
|
||||
<li>Shutting down your client node</li>
|
||||
</ol>
|
||||
Setup and running of Q Server Nodes will be discussed in a later chapter.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.2. Verify Your Q Installation Is Correct</h3>
|
||||
|
||||
<blockquote>
|
||||
Ensure that all the needed I2P jarfiles, as well as <b>xmlrpc.jar</b> and
|
||||
Q's very own <b>aum.jar</b> are correctly listed in your <b>CLASSPATH</b> environment
|
||||
varaible, and your main java launcher is correctly listed in your <b>PATH</b> environment
|
||||
variable.<br>
|
||||
<br>
|
||||
Typically, you will likely copy the jarfiles <b>aum.jar</b> and <b>xmlrpc.jar</b>
|
||||
into the <b>lib/</b> subdirectory of your I2P router installation, along with all
|
||||
the other I2P jar files. Wherever you choose to put these files, make sure they're
|
||||
correctly listed in your <b>CLASSPATH</b>.
|
||||
<br>
|
||||
Also, you'll want to add execute permission to your <b>qmgr</b> (or <b>qmgr.bat</b>)
|
||||
wrapper script, and copy it into one of the directories listed in your <b>PATH</b>
|
||||
environment variable.<br>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.3. Get Familiar With qmgr</h3>
|
||||
|
||||
<blockquote>
|
||||
<b>qmgr</b> (or <b>qmgr.bat</b>) is a convenience wrapper script to save your
|
||||
sore fingers from needless typing. It's just a wrapper which passes arguments
|
||||
to the java command <b><code>java net.i2p.aum.q.QMgr</code></b><br>
|
||||
<br>
|
||||
You can verify you've set up qmgr correctly with the command:
|
||||
<blockquote><code><pre>
|
||||
qmgr help</pre></code></blockquote>
|
||||
This displays a brief summary of qmgr commands. On the other hand, the command:
|
||||
<blockquote><code><pre>
|
||||
qmgr help verbose</pre></code></blockquote>
|
||||
floods your terminal window with a detailed explanation of all the qmgr commands
|
||||
and their arguments.<br>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.4. Running A Q Client Node For The First Time</h3>
|
||||
|
||||
<blockquote>
|
||||
Provided you've successfully completed the preliminaries, you can launch your
|
||||
Q Client Node with the command:
|
||||
<blockquote><code><pre>
|
||||
qmgr start</pre></code></blockquote>
|
||||
|
||||
All going well, you should have a Q Client Node now running in background.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.5. Verify that your Q Client Node is actually Running</h3>
|
||||
|
||||
<blockquote>
|
||||
After typed the <b>qmgr start</b> command, you will see little or no
|
||||
evidence that Q is actually running.<br>
|
||||
<br>
|
||||
You can test if the node is actually up by typing the command:
|
||||
<blockquote><code><pre>
|
||||
qmgr status</pre></code></blockquote>
|
||||
If your Q Client Node is running, this <b>status</b> command should produce
|
||||
something like:
|
||||
<blockquote><code><pre>
|
||||
Pinging node at '/home/myusername/.quartermaster_client'...
|
||||
Node Ping:
|
||||
status=ok
|
||||
numPeers=0
|
||||
dest=-3LQaE215uIYwl-DsirnzXGQBI31EZQj9u~xx45E823WqjN5i2Umi37GPFTWc8KyislDjF37J7jy5newLUp-qrDpY7BZum3bRyTXo3Udl8a3sUjuu4qR5oBEWFfoghQiqDGYDQyJV9Rtz7DEGaKHGlhtoGsAYRXGXEa8a43T2llqZx2fqaXs~836g8t6sLZjryA5A9fpq98nE5lT0hcTalPieFpluJVairZREXpUiAUmGHG7wAIjF6iszXLEHSZ8Qc622Xgwy0d1yrPojL2yhZ64o05aueYcr~xNCiFxYoHyEJO3XYmkx~q-W-mzS3nn6pRevRda74MnX1~3fFDZ0u~OG6cLZoFkWgnxrwrWGFUUVMR87Yz251xMCKJAX6zErcoGjGFpqGZsWxl4~yq7yfkjPnq3GuTxp2cB75bRAOZRIAieqBOVJDEodFYW5amCinu4AxYE7G1ezz4ghqHFe~0yaAdO74Q1XoUny138YT6P33oNOOlISO1cAAAA
|
||||
uptime=4952
|
||||
load=0.0
|
||||
id=6LVZ9-~GgJJ52WUF1fLHt3UnH50TnXSoPQXy7WZ4GA=
|
||||
numLocalItems=47
|
||||
numRemoteItems=2173</pre></code></blockquote>
|
||||
|
||||
If you see something like this, then smile, because Q is now up on your system.<br>
|
||||
<br>
|
||||
If the node launch failed, you might see something like:
|
||||
<blockquote><code><pre>
|
||||
Pinging node at '/home/myusername/.quartermaster_client'...
|
||||
java.io.IOException: Connection refused
|
||||
at org.apache.xmlrpc.XmlRpcClient$Worker.execute(Unknown Source)
|
||||
at org.apache.xmlrpc.XmlRpcClient.execute(Unknown Source)
|
||||
at net.i2p.aum.q.QMgr.doStatus(QMgr.java:310)
|
||||
at net.i2p.aum.q.QMgr.execute(QMgr.java:813)
|
||||
at net.i2p.aum.q.QMgr.main(QMgr.java:869)
|
||||
Failed to ping node</pre></code></blockquote>
|
||||
This indicates that your Q client node has either crashed, or failed to launch in the
|
||||
first place.<br>
|
||||
<br>
|
||||
If you're having trouble like this, you might like to try running your Q client node
|
||||
in foreground, instead of spawning it off into background.<br>
|
||||
<br>
|
||||
The command to run a Q client node in foreground is:
|
||||
<blockquote><code><pre>
|
||||
qmgr foreground</pre></code></blockquote>
|
||||
You should see some meaningless startup messages, and no return to your shell prompt.<br>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.6. Diversion - Q Storage Directories</h3>
|
||||
|
||||
<blockquote>
|
||||
By default, when you run a Q Client Node, it creates a datastore directory tree
|
||||
at <b>~/.quartermaster_client</b>. (Windows users note - you'll find this directory
|
||||
wherever your user home directory is - this depends on what version of Windows
|
||||
you have installed).<br>
|
||||
<br>
|
||||
Within this directory tree, you should see a file called <b>node.log</b>, which
|
||||
will contain various debug log messages, and can help you to rectify any problems
|
||||
with your Q installation. If you hit a wall and can't rectify the problems
|
||||
yourself, you should send this file to the Q author (aum).<br>
|
||||
<br>
|
||||
It's possible to run your Q node from another directory, by passing that directory
|
||||
as a <b>-dir <path></b> argument to the
|
||||
<b>qmgr</b> <b>start</b>, <b>foreground</b> and <b>stop</b>
|
||||
commands. See <b>qmgr help verbose</b> for more information.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.7. Importing a Noderef</h3>
|
||||
|
||||
<blockquote>
|
||||
Note from the prior <b>qmgr status</b> command the line:
|
||||
<blockquote><code><pre>
|
||||
numPeers=0</pre></code></blockquote>
|
||||
This means that your Q client node is running standalone, and doesn't have any contact
|
||||
with any Q network. As such, your node is effectively useless. We need to hook up
|
||||
your node with other nodes in the Q network.<br>
|
||||
<br>
|
||||
Q doesn't ship with any means for new client nodes to automatically connect to any Q
|
||||
server nodes. This is deliberate.<br>
|
||||
<br>
|
||||
In all likelihood, there will be one 'main' Q network running within I2P, largely
|
||||
based around the author's own Q server node, and most people will likely want to
|
||||
use this Q network. But the author doesn't want to stop other people running their
|
||||
own private Q networks, for whatever purpose has meaning for them.
|
||||
|
||||
<blockquote><i><small>
|
||||
<hr>
|
||||
This is especially relevant for Q as opposed to Freenet. With Freenet, there's
|
||||
no way for a user to know of the existence of any item of content without
|
||||
first being given its 'key'. However, since Q works with published catalogs,
|
||||
any user can know everything that's available on a Q network, which might
|
||||
not be desirable to those wishing to share content in a private situation.<br>
|
||||
<Br>
|
||||
The Q author anticipates, and warmly supports, people running their own
|
||||
private Q networks within I2P, in addition to accessing the mainstream
|
||||
'official' Q network.<br>
|
||||
<br>
|
||||
The way Q is designed and implemented, there is no way for anyone, including
|
||||
Q's author, to know of the existence of anyone else's private Q network.
|
||||
It is beyond the author's control, (and thus arguably the author's
|
||||
legal responsibility), what private Q networks people set up, and what
|
||||
kind of content is trafficked on these networks. This claim of plausible
|
||||
deniability on the part of Q's author parallels that of a hardware retailer
|
||||
denying responsibility for what people do with tools that they purchase.
|
||||
<hr>
|
||||
</small>
|
||||
</i></blockquote>
|
||||
|
||||
Ok, getting back on topic - your brand new virgin Q client node is useless and lonely,
|
||||
and desperately needs some Q server nodes to talk to. So let's hook up your node to
|
||||
the mainstream Q network.<br>
|
||||
<br>
|
||||
You'll need to get one or more 'noderefs' for Q server nodes.<br>
|
||||
<br>
|
||||
There's nothing fancy about a Q noderef. It's just a regular I2P 'destination', with
|
||||
which your Q Client Node can connect with a Q Server Node.<br>
|
||||
<br>
|
||||
A 'semi-official' list of noderefs for the mainstream Q network can be downloaded
|
||||
from the url: <a href="http://aum.i2p/q/qnoderefs.txt">http://aum.i2p/q/qnoderefs.txt</a>.<br>
|
||||
<br>
|
||||
Download this file, save it as (say) <b>qnoderefs.txt</b>. (Alternatively, if you're
|
||||
wanting to subscribe into a private Q network, then get a noderef for at least one
|
||||
of that network's server nodes from someone on that network who trusts you).<br>
|
||||
<br>
|
||||
Import these noderefs into your Q client node via the command:
|
||||
<blockquote><code><pre>
|
||||
qmgr addref qnoderefs.txt</pre></code></blockquote>
|
||||
If all goes well, you should see no output from this command, or (possibly) a brief
|
||||
line or two suggesting success.<br>
|
||||
<br>
|
||||
Your client node is now subscribed into the Q network of your choice. Verify this
|
||||
with the command:
|
||||
<blockquote><code><pre>
|
||||
qmgr status</pre></code></blockquote>
|
||||
In the output from that command, you should see the <b>numPeers=</b> line showing at least
|
||||
1 peer.<br>
|
||||
<br>
|
||||
If there is more than one Q Server Node on the Q network you've just subscribed to,
|
||||
then your local node should sooner or later discover all these server nodes, and
|
||||
the <b>numPeers</b> value should increase over time.<br>
|
||||
<br>
|
||||
<blockquote>
|
||||
<hr>
|
||||
While Q is in its early development and testing stages, the author may abdicate
|
||||
the mainstream Q network, and publish nodrefs for a whole new mainstream Q network.
|
||||
This will especially happen if the author makes any substantial changes to the
|
||||
inter-node protocol, and/or releases incompatible new versions of Q client/server
|
||||
nodes. Remember that
|
||||
<a href="http://aum.i2p/q/qnoderefs.txt">http://aum.i2p/q/qnoderefs.txt</a> will
|
||||
serve as the authoritative source for noderefs for the mainstream Q network within
|
||||
the mainstream I2P network.
|
||||
<hr>
|
||||
</blockquote>
|
||||
|
||||
When your client node gets its noderefs to a Q network, it will periodically,
|
||||
from then on, retrieve differential peer list and catalog updates from servers
|
||||
it knows about.<br>
|
||||
<br>
|
||||
Even if you only feed your client just one ref for a single server node, it will
|
||||
in time discover all other operating server nodes on that Q network, and will
|
||||
build up a full local catalog of everything that's available on that Q network.<br>
|
||||
<br>
|
||||
Provided that your client is running ok, and has been fed with at least one
|
||||
ref for a live Q network that contains content, then over time, successive:
|
||||
<blockquote><code><pre>
|
||||
qmgr status</pre></code></blockquote>
|
||||
commands should report increasing values in the fields:
|
||||
<ul>
|
||||
<li><b>numPeers</b> - number of peers this client node knows about</li>
|
||||
<li><b>numLocalItems</b> - number of locally stored content items, ie items
|
||||
which you have either inserted to, or retrieved from, your client node</li>
|
||||
<li><b>numRemoteItems</b> - number of unique data items which are available
|
||||
on remote server nodes in the Q network, and which can be retrieved through
|
||||
your local client node.</li>
|
||||
</ul>
|
||||
|
||||
<blockquote>
|
||||
<hr>
|
||||
|
||||
<h4>4.7.1. One Big Warning</h4>
|
||||
|
||||
If you are participating in more than one distinct Q network, then <b>do not</b>
|
||||
insert noderefs for different networks into the same running instance of a
|
||||
local Q client, unless you don't plan on inserting content via that client.<br>
|
||||
<Br>
|
||||
For instance, let's say you are participating in two different Q networks:
|
||||
<ul>
|
||||
<li>The 'mainstream' Q netowrk</li>
|
||||
<li>A secret Q network - "My friends' teen angst diaries"</li>
|
||||
</ul>
|
||||
If you get a noderef for both these networks, and insert both of these into the
|
||||
same running Q client node, then this local client node will be transparently
|
||||
connected to both networks.<br>
|
||||
<br>
|
||||
If you only ever plan on retrieving content, and never inserting content, this
|
||||
won't be a problem, except that you won't be able to tell which content
|
||||
resides on the mainstream Q network, and which resides in the secret Q network.<br>
|
||||
<Br>
|
||||
The big problem arises from inserting content. Whenever you insert data through this
|
||||
'contaminated'
|
||||
Q client node, this node picks 3 different servers to which upload a copy of this
|
||||
data. You won't have any control over whether the data gets inserted to the mainstream
|
||||
Q network, or your secret Q network. You might insert something sensitive, intending it
|
||||
to go only into the secret Q network, where in fact it also ends up in the mainstream
|
||||
network, with consequences you might not want.
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.8. Content Data and Metadata</h3>
|
||||
|
||||
<blockquote>
|
||||
Whenever content gets stored on Q, it is actually stored as two separate items:
|
||||
<ul>
|
||||
<li>The <b>raw data</b> - whether a text file, or the raw bytes of image files,
|
||||
audio files etc</li>
|
||||
<li>The <b>metadata</b>, which contains human-readable and machine-readable
|
||||
descriptions of the data</li>
|
||||
</ul>
|
||||
Metadata consists of a set of <b>category=value</b> pairs.<br>
|
||||
<br>
|
||||
Confused yet? Don't worry, I'm confused as well. Let's illustrate this with an
|
||||
example of metadata for an MP3 audio recording:
|
||||
<ul>
|
||||
<li>title=Fight_Last_Thursday.mp3</li>
|
||||
<li>type=audio</li>
|
||||
<li>mimetype=audio/mpeg</li>
|
||||
<li>abstract=upcoming single recorded in our garage last April</li>
|
||||
<li>keywords=grunge,country,indie</li>
|
||||
<li>artist=Ring of Fire</li>
|
||||
<li>size=4379443</li>
|
||||
<li>contact=ring-of-fire@mail.i2p</li>
|
||||
<li>key=blah37blah24-yada23hfhyada</li>
|
||||
</ul>
|
||||
All metadata categories are optional. In fact, you can insert content with no metadata
|
||||
at all.<br>
|
||||
<br>
|
||||
If you fail to provide metadata when inserting an item, a blank set of metadata will
|
||||
be created with at least the following categories:
|
||||
<ul>
|
||||
<li><b>key</b> - the derived key, under which the item will later be retrievable
|
||||
by yourself and others</li>
|
||||
<li><b>title</b> - if not provided at insert time, this will be set to the key</li>
|
||||
<li><b>size</b> - size of the item's raw data, in bytes</li>
|
||||
</ul>
|
||||
Within Q, there is a convention to supply a minimal amount of metadata. While this
|
||||
is not expected or enforced, including all these categories is most strongly
|
||||
recommended. These core categories are:
|
||||
<ul>
|
||||
<li><b>title</b> - a meaningful title for the data item, consisting only of characters
|
||||
which are legal in filenames on all platforms, and which ends with a file extension.</li>
|
||||
<li><b>type</b> - one of a superset of eMule classifiers, such as:
|
||||
<ul>
|
||||
<li><b>text</b> - plain text</li>
|
||||
<li><b>html</b> - HTML content</li>
|
||||
<li><b>image</b> - content is in an image format, such as .png, .jpg, .gif etc</li>
|
||||
<li><b>audio</b> - content is an audio sample, such as .ogg, .mp3, .wav etc</li>
|
||||
<li><b>video</b> - due to the sheer size of video files, and Q's present design,
|
||||
it's unlikely people will be inserting video content anytime soon (unless it's
|
||||
very short)</li>
|
||||
<li><b>archive</b> - packed file collections, such as .tar.gz, .zip, .rar etc</li>
|
||||
<li><b>misc</b> - content does not fit into any of the above categories</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>mimetype</b> - not as important as the <b>type</b> category, but providing
|
||||
this category in your metadata is still strongly encouraged. Value for this category
|
||||
should be one of the standard mimetypes, eg <b>text/html</b>, <b>audio/ogg</b> etc.</li>
|
||||
<li><b>abstract</b> - a short description (<255 characters), intended for human reading</li>
|
||||
<li><b>keywords</b> - a comma-separated list of keywords, intended for
|
||||
machine-readability, should be all lowercase, no spaces</li>
|
||||
</ul>
|
||||
Note that you can supply extra metadata categories in addition to the above, and that
|
||||
people searching for content can search on these extra categories if they know about
|
||||
them.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.9. Searching For Content</h3>
|
||||
|
||||
<blockquote>
|
||||
As mentioned earlier - in constrast with Freenet, local Q nodes build up a complete
|
||||
catalog of all available content on whatever Q network they are connected to.<br>
|
||||
<br>
|
||||
This is a design decision, based on the choice to eliminate query traffic.<br>
|
||||
<br>
|
||||
The author hopes that this will result in a distributed storage network with a
|
||||
high retrievability guarantee, in contrast with freenet which offers no such
|
||||
guarantee.<br>
|
||||
<br>
|
||||
With Freenet, you only ever know of the existence of something if someone tells
|
||||
you about it.<br>
|
||||
<br>
|
||||
But with Q, your local client node builds up a global catalog of everything that's
|
||||
available within the whole network.<br>
|
||||
<br>
|
||||
The QMgr client has a command for searching your Q client node:
|
||||
<blockquote><code><pre>
|
||||
qmgr search -m category1=pattern1 category2=pattern2 ...</pre></code></blockquote>
|
||||
For example:
|
||||
<blockquote><code><pre>
|
||||
qmgr search -m type=audio artist=Mozart keywords=symphony</pre></code></blockquote>
|
||||
or:
|
||||
<blockquote><code><pre>
|
||||
qmgr search -m type=text title="bible|biblical|(Nag Hammadi)" keywords="apocrypha|Magdalene"</pre></code></blockquote>
|
||||
As implied in the latter example, search patterns are regular expressions. This example will
|
||||
locate all text items, whose <b>title</b> metadata category contains one of <b>bible</b>, <b>biblical</b> or <b>Nag Hammadi</b>, <i>and</i> whose <b>keywords</b> category contains either
|
||||
or both the words <b>apocrypha</b> or <b>Magdalene</b>.<br>
|
||||
<br>
|
||||
Please use the search function carefully, otherwise (if and when Q usage grows) you
|
||||
could be inundated with thousands or even millions of entries.<br>
|
||||
<br>
|
||||
If a search turns up nothing, qmgr will simply exit. But if it turns up one or more items,
|
||||
it will the items out one at a time, with the key first, then each metadata entry
|
||||
on an indented line following.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.10. Retrieving Content</h3>
|
||||
|
||||
<blockquote>
|
||||
Now, we're actually going to retrieve something.<br>
|
||||
<br>
|
||||
Presumably, after following the previous section, you will have seen one or more search
|
||||
results come up, with the 'keys' under which the items can be accessed.<br>
|
||||
<br>
|
||||
Now, choose one of the keys, preferably for a short text item. Try either of the following
|
||||
commands:
|
||||
<blockquote><code><pre>
|
||||
qmgr get <keystring> something.txt</pre></code></blockquote>
|
||||
<i>or</i>:
|
||||
<blockquote><code><pre>
|
||||
qmgr get <keystring> > something.txt</pre></code></blockquote>
|
||||
(both have the same effect - the first one explicitly writes to the named file, the second
|
||||
one dumps the raw data to stdout, which we shell-redirect into the file.<br>
|
||||
<br>
|
||||
<b><i>Note - redirection of fetched data to a file via shell is not working at present. Use only
|
||||
the first form till we fix the bug.</i></b>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.11. Inserting Content</h3>
|
||||
|
||||
<blockquote>
|
||||
Our last example in this walkthrough relates to inserting content.<br>
|
||||
<br>
|
||||
Firstly, create a small text file with 2-3 lines of text, and save it as (say)
|
||||
myqinsert.txt.<br>
|
||||
<br>
|
||||
Now, think of some metadata to insert along with the file. Or, you can just use
|
||||
the set:
|
||||
<blockquote><code><pre>
|
||||
type=text
|
||||
keywords=test
|
||||
abstract=My simple test of inserting into Q
|
||||
title=myqinsert.txt</pre></code></blockquote>
|
||||
|
||||
Now, let's insert the file. Ensure your Q client node is running, then type:
|
||||
<blockquote><code><pre>
|
||||
qmgr put myqinsert.txt -m type=text keywords=test title="myqinsert.txt" \
|
||||
abstract="My simple test of inserting into Q"</pre></code></blockquote>
|
||||
If all went well, this command should produce half a line of gibberish, followed
|
||||
immediately by your shell prompt, eg:
|
||||
<blockquote><code><pre>
|
||||
aRoFC~9MU~pM2C-uCTDBp5B7j79spFD8gUeu~BNkUf0=<b>$</b>
|
||||
</pre></code></blockquote>
|
||||
The '$' at the end is your shell prompt, and all the characters before it are the 'key'
|
||||
which was derived from the content you just inserted.<br>
|
||||
<br>
|
||||
To avoid the hassle of copying/pasting the key, you could just add output redirection
|
||||
to the above command, eg:
|
||||
<blockquote><code><pre>
|
||||
qmgr put myqinsert.txt -m type=text keywords=test title="myqinsert.txt" \
|
||||
abstract="My simple test of inserting into Q" \
|
||||
> myqinsert.key</pre></code></blockquote>
|
||||
This will cause the generated key to be written safe and sound into the file
|
||||
<b>myqinsert.key</b>.<br>
|
||||
<br>
|
||||
You can verify that this insert worked by a 'get' command, as in:
|
||||
<blockquote><code><pre>
|
||||
qmgr get `cat myqinsert.key` somefilename.ext</pre></code></blockquote>
|
||||
(Note that this won't work on windows because the DOS shell is irredeemably brain-damaged. If
|
||||
you're using Windows, you <b>will</b> have to cut/paste the key.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>4.12. Shutting Down your Node</h3>
|
||||
|
||||
<blockquote>
|
||||
If you've worked through to here, then congratulations! You've got your Q Client Node set up
|
||||
and working, and ready to meet all your distributed file storage and retrieval needs.<br>
|
||||
<br>
|
||||
You can leave your client node running 24/7 if you want. In fact, we recommend you keep your
|
||||
client node running as much of the time as possible, so that you get prompt catalog updates,
|
||||
and can more quickly stay in touch with new content.<br>
|
||||
<br>
|
||||
However, if you need to shut down your node, the command for doing this is:
|
||||
<blockquote><code><pre>
|
||||
qmgr stop</pre></code></blockquote>
|
||||
This command will take a while to complete (since the node has to wait for the I2P
|
||||
java shutdown hooks to complete before it can rest in peace). But once your node is
|
||||
shut down, you can start it up again at any time and pick up where you left off.
|
||||
</blockquote>
|
||||
|
||||
<a name="server"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>5. Running a Q Server Node</h2>
|
||||
|
||||
<h3>5.1. Introduction</h3>
|
||||
<blockquote>
|
||||
This section describes the requirements for, and procedures involved with, running
|
||||
a Q Server Node.<br>
|
||||
<br>
|
||||
We'll use a similar 'walkthrough' style to that which we used in the previous section
|
||||
on client nodes.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>5.2. Requirements and Choices</h3>
|
||||
<blockquote>
|
||||
Running a Q server is a generous thing to do, and helps substantially with making
|
||||
Q work at its best for everyone. However, please do make sure you can meet some
|
||||
basic requirements:
|
||||
<ul>
|
||||
<li>You are running a permanent (24/7) I2P Router, on a box with at least (say)
|
||||
98% uptime.</li>
|
||||
<li>You have a little bandwidth to spare, and don't mind the extra memory, disk and
|
||||
CPU-usage footprint of running a fulltime Q server node</li>
|
||||
<li>You have already been able to successfully run a Q client node.</li>
|
||||
</ul>
|
||||
Also, please decide whether you want your server node to contribute to the mainstream
|
||||
Q network, or whether you want to create your own private Q network, or join someone
|
||||
else's private network. Your contribution will be most appreciated, though, if you
|
||||
can run a server within the mainstream Q network.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>5.3. Starting Your Server Node</h3>
|
||||
|
||||
<blockquote>
|
||||
Starting up a Q Server node is very similar to starting up a Q client node, except
|
||||
that with the qmgr command line, you must put the keyword arg <b>server</b> before the
|
||||
command word. So the command is:
|
||||
<blockquote><code><pre>
|
||||
qmgr server start</pre></code></blockquote>
|
||||
Similar to Q client nodes, you can check the status of a running Q server node with
|
||||
the command:
|
||||
<blockquote><code><pre>
|
||||
qmgr server status</pre></code></blockquote>
|
||||
(Note that this command will take longer to complete than with client nodes, because
|
||||
the communication passes through a multi-hop I2P tunnel, rather than just through
|
||||
localhost TCP).<br>
|
||||
<br>
|
||||
If the status command succeeds, then you'll know your new Q Server Node is happily
|
||||
running in background.
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>5.4. Joining A Q Network</h3>
|
||||
|
||||
<blockquote>
|
||||
When a Q Server node starts up for the first time, it is in a private network
|
||||
all by itself.<br>
|
||||
<br>
|
||||
If you want to link your server into an existing Q network, you'll have to add a
|
||||
noderef for at least one other server on that network. The command to do this
|
||||
is similar to that for subscribing a client node to a network:
|
||||
<blockquote><code><pre>
|
||||
qmgr server addref <noderef-file></pre></code></blockquote>
|
||||
where <noderef-file> is a file into which you've saved the noderef for
|
||||
the network you want to join.
|
||||
<blockquote>
|
||||
<hr><i><small>
|
||||
Recall from the section on client nodes that the authoritative noderefs
|
||||
for the mainstream Q network can be downloaded from
|
||||
<a href="http://aum.i2p/q/qnoderefs.txt">http://aum.i2p/q/qnoderefs.txt</a>.
|
||||
</small></i><hr>
|
||||
</blockquote>
|
||||
After you've added the noderef, subsequent <b>qmgr server status</b> commands
|
||||
should show <b>numPeers</b> having a value of at least 1 (and growing, as more
|
||||
server nodes come online in the mainstream Q network.)
|
||||
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>5.5. Private Networks - Exporting Your Server's Noderef</h3>
|
||||
|
||||
<blockquote>
|
||||
If you're planning to start your own private Q network, and want to include other
|
||||
server operators in this network, then you'll have to export your server's noderef
|
||||
and make it available to the others you want to invite into your network.<br>
|
||||
<br>
|
||||
The command to export your Q Server noderef is:
|
||||
<blockquote><code><pre>
|
||||
qmgr server getref <noderef-file></pre></code></blockquote>
|
||||
This will extract the <i>I2P Destination</i> of your running server node, and
|
||||
write it into <noderef-file>. You can then privately share this file with
|
||||
others who you want to invite into your private network. Each recipient of
|
||||
this file will do a <b>qmgr server addref <noderef-file></b> command
|
||||
to import your ref into their servers.<br>
|
||||
<br>
|
||||
Don't forget that if you're running, or participating in, a private Q network, then
|
||||
you'll need to run a separate client for accessing this network, separate from any
|
||||
mainstream Q network client you may already be running.<br>
|
||||
<br>
|
||||
To start this extra client, you'll have to choose a directory where you want this
|
||||
client to reside, a port number you want your client to listen on locally for
|
||||
user commands, and run the command:
|
||||
<blockquote><code><pre>
|
||||
qmgr -dir /path/to/my/new/client -port <portnum> start</pre></code></blockquote>
|
||||
You need the <b>-port <portnum></b> command, because otherwise it'll fail
|
||||
to launch (if you already have a client node running off the mainstream Q network).<br>
|
||||
<br>
|
||||
This will create, and launch, a new instance of a Q client, accessing your private
|
||||
Q network. Don't forget to import your server's noderef into this client. Also,
|
||||
note that you'll have to use this same <b>-port <portnum></b> argument when
|
||||
doing any operation on this client instance, such as get, put, status, search.
|
||||
|
||||
</blockquote>
|
||||
|
||||
<a name="qmgr"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>6. About the qmgr Utility</h2>
|
||||
|
||||
qmgr (or, to people fluent in Java, <b>net.i2p.aum.q.QMgr</b>), is just one simple
|
||||
Q client application, that happens to be bundled in with the Q distro.<br>
|
||||
<br>
|
||||
It is by no means the only, or even main facility for accessing the Q network. We
|
||||
anticipate that folks will write all manner of client apps, including fancy GUI
|
||||
apps.<br>
|
||||
<br>
|
||||
Anyway, qmgr does give you a rudimentary yet workable client for basic access
|
||||
to the Q network. Until fancy apps get written, qmgr will have to do.<br>
|
||||
<br>
|
||||
Don't forget that qmgr has very detailed inbuilt help. Run:
|
||||
<blockquote><code><pre>
|
||||
qmgr help</pre></code></blockquote>
|
||||
for a quick help summary, or:
|
||||
<blockquote><code><pre>
|
||||
qmgr help verbose</pre></code></blockquote>
|
||||
for the 'War and Peace' treatise.<br>
|
||||
<br>
|
||||
<blockquote><hr>
|
||||
One crucial concept to remember with qmgr is that client and server node instances
|
||||
are uniquely identified by the directories at which they reside. If you are running
|
||||
multiple server and/or client instances, you can specify an instance with the
|
||||
<b>-dir <dirpath></b> option - see the help for details.
|
||||
<hr></blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
One last note - we strongly discourage any writing of client apps that spawn a qmgr
|
||||
process, pass it arguments and parse its results. This is most definitely a path to
|
||||
pain, since qmgr's shell interface is subject to radical change at any time without
|
||||
notice.<br>
|
||||
<br>
|
||||
qmgr is for human usage, or at most, inclusion in init/at/cron scripts. Please respect
|
||||
this.<br>
|
||||
<br>
|
||||
If you want to write higher-level clients, your best course of action is to use the
|
||||
official client api library, which we anticipate will have versions available in
|
||||
Java, Python, Perl and C++. If you want to write in another language, such as
|
||||
OCaml, Scheme etc, then the existing api lib implementations should serve as an excellent
|
||||
reference to support you in writing a native port for your own language.
|
||||
|
||||
<a name="contact"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>8. Contacting the Author</h2>
|
||||
|
||||
I am <b>aum</b>, and can be reached as <b>aum</b> on in-I2P IRC networks, and also
|
||||
at the in-I2P email address of <b>aum@mail.i2p</b>.<br>
|
||||
<br>
|
||||
|
||||
<hr>
|
||||
|
||||
<center>
|
||||
Return to <a href="../index.html">Q Homepage</a><br>
|
||||
<br>
|
||||
<small>
|
||||
<a href="#intro">Introduction</a> |
|
||||
<a href="#checklist">Checklist</a> |
|
||||
<a href="#serverorclient">Server?orClient?</a> |
|
||||
<a href="#walkthrough">Walkthrough</a> |
|
||||
<a href="#server">Server Nodes</a> |
|
||||
<a href="#qmgr">About QMgr</a> |
|
||||
<a href="#contact">Contact us</a>
|
||||
</small>
|
||||
</center>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Created: Fri Apr 1 11:03:27 NZST 2005 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Sun Apr 3 20:06:53 NZST 2005
|
||||
<!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
@ -1,23 +0,0 @@
|
||||
|
||||
rise on each hit:
|
||||
|
||||
dy = (1 - y) / kRise
|
||||
|
||||
fall after each time unit:
|
||||
|
||||
dy = y / kFall
|
||||
|
||||
fall after time dt:
|
||||
|
||||
dy = - y ** - (dt / kFall)
|
||||
|
||||
after the next hit:
|
||||
|
||||
y = y - y ** (- dt / kFall) + (1 - y) / kRise
|
||||
|
||||
first attempt at a load measurement algorithm:
|
||||
- kFall is an arbitrary constant which dictates decay rate of load
|
||||
in the absence of hits
|
||||
- kRise is another constant which dictates rise of load with each hit
|
||||
- dt is the time between each hit
|
||||
|
@ -1,372 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Q Metadata Specification</title>
|
||||
|
||||
<style type="text/css">
|
||||
<!--
|
||||
td { vertical-align: top; }
|
||||
code { font-family: courier, monospace; font-weight: bolder; font-size:smaller }
|
||||
-->
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Q Metadata Specification</h1>
|
||||
|
||||
<h2>1. Introduction</h2>
|
||||
|
||||
This document lists the standard metadata keys for Q data items,
|
||||
discussing the rules of metadata insertion, processing and validation.<br>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>1.1. Definitions</h3>
|
||||
|
||||
To avoid confusions in terminology, this document will strictly abide the following definitions:
|
||||
<br>
|
||||
<br>
|
||||
<table width=80% cellspacing=0 cellpadding=4 border=1 align=center>
|
||||
<tr style="font-weight: bold">
|
||||
<td>Term</td>
|
||||
<td>Definition</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>key</code></td>
|
||||
<td>A metadata category name, technically a <code>key</code> as the word is used with
|
||||
Java <code>Hashtable</code> and Python <code>dict</code> objects.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>uri</code></td>
|
||||
<td>A Uniform Resource Indicator for an item of content stored within the Q network.<br>
|
||||
Q URIs have the form: <code>Q:<basename>[,<cryptoKey>][<path>]</code>
|
||||
<br>
|
||||
<br>
|
||||
Some examples:
|
||||
<ul>
|
||||
<li><code>Q:fhvnr3HFSK234khsf90sdh42fsh</code> (a plain hash uri, no cryptoKey)</li>
|
||||
<li><code>Q:e54fhjeo39schr2kcy4osEH478D/files/johnny.mp3</code> (a secure space URI,
|
||||
no cryptoKey)</li>
|
||||
<li><code>Q:vhfh4se987WwfkhwWFEwkh3234S,47fhh2dkhseiyu</code> (a plain hash URI, with
|
||||
a cryptoKey)</li>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>basename</code></td>
|
||||
<td>The basic element of a Q uri. This will be a base64-encoded hash - refer below to
|
||||
URI calculation procedures</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>cryptoKey</code></td>
|
||||
<td>An optional session encryption key for the stored data, encoded as base64.
|
||||
This affords some protection to server node operators, and gives them a level
|
||||
of plausible deniability for whatever gets stored in their server's
|
||||
datastore without their direct human awareness.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>path</code></td>
|
||||
<td>Whever an item of content is inserted in <code>secure space</code> mode, this path
|
||||
serves as a pseudo-pathname, and is conceptually similar to the <code>path</code>
|
||||
component in (for example) standard HTTP URLs
|
||||
<code>http://<domainname>[:<port>][<path>]</code>, such as
|
||||
<code>http://slashdot.org/faq/editorial.shtml</code> (whose <code>path</code>
|
||||
is <code>/faq/editorial.shtml</code>).<br>
|
||||
<br>
|
||||
Paths, if not empty, should contain a leading slash ("/").
|
||||
If an application specifies a non-empty <code>path</code> that doesn't begin with a
|
||||
leading '/', a '/' will be automatically prepended by the receiving node.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>plain hash</code></td>
|
||||
<td>A mode of inserting items, whereby the security of the resulting URI comes from
|
||||
computing the URI from a hash of the item's data and metadata (and imposing a
|
||||
mathematical barrier against spoofing content under a given URI). Corresponds to
|
||||
Freenet's <code>CHK@</code> keys.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>secure space</code></td>
|
||||
<td>A mode of inserting items where the security of the URI is based not on a hash of the
|
||||
item's data and metadata (as with <code>plain hash</code> mode),
|
||||
but on the <code>privateKey</code> provided by the
|
||||
application, and a content signature created from that private key.
|
||||
Corresponds to Freenet's <code>SSK@</code> keys. Within a secure space, you
|
||||
can insert any number of items under different pseudo-pathnames (as is the case
|
||||
with Freenet SSK keys).
|
||||
</li>
|
||||
</table>
|
||||
|
||||
<br><br>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>2.1. Keys Inserted By Application Before sending <code>putItem</code> RPCs</h3>
|
||||
|
||||
As the heading suggests, this is a list of metadata keys which should be inserted by a
|
||||
Q application prior to invoking a <code>putItem</code> RPC on the local Q client node.<br>
|
||||
<br>
|
||||
<table width=80% cellspacing=0 cellpadding=4 border=1 align=center>
|
||||
<tr style="font-weight: bold">
|
||||
<td>Key</td>
|
||||
<td>Data Type</td>
|
||||
<td>Description</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>title</code></td>
|
||||
<td>String</td>
|
||||
<td>Optional but strongly recommended. A free-text short description of the item,
|
||||
should be less than 80 characters. The idea is that applications should
|
||||
support a 'view' of catalogue data that shows item titles. (Prior Q convention of
|
||||
titles expressed as valid filename syntax has been abandoned).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>path</code></td>
|
||||
<td>String</td>
|
||||
<td>Optional but strongly recommended.
|
||||
A virtual 'pathname' for the item, which should be in valid *nix
|
||||
absolute pathname syntax (beginning with '/', containing no '//', consisting
|
||||
only of alphanumerics, '-', '_', '.' and '/'.<br>
|
||||
<br>
|
||||
In Q web interfaces, the <code>filename</code> component of this path will
|
||||
serve as the recommended filename when downloading/saving the item.<br>
|
||||
<br>
|
||||
If the application also provides a
|
||||
<code>privateKey</code> key, the path
|
||||
is used in conjunction with the private key to generate <code>publicKey</code>
|
||||
and <code>signature</code> keys (see below), and ultimately the final <code>uri</code>
|
||||
under which the item can be retrieved by others.<br>
|
||||
<br>
|
||||
Refer also to <code>mimetype</code> below.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>encrypt</code></td>
|
||||
<td>String</td>
|
||||
<td>Optional. If this key is present, and has a value "1", "yes" or "true",
|
||||
this indicates that the application wishes the data to be stored on servers in
|
||||
encrypted form.<br>
|
||||
<br>
|
||||
If this key is present and set to a positive value, the Q node, on receiving the
|
||||
<code>putItem</code> RPC, will:
|
||||
<ol>
|
||||
<li>Generate a random symmetric encryption key</li>
|
||||
<li>Encrypt the item's data using this encryption key</li>
|
||||
<li>Delete the <code>encrypt</code> key from the metadata</li>
|
||||
<li>Enclose a base64 representation of this encryption key in the RPC response
|
||||
it sends back to the application (embedded in the <code>uri</code></li>
|
||||
</ol>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>type</code></td>
|
||||
<td>String</td>
|
||||
<td>Optional but strongly recommended. A standard ed2k specifier, one of <code>text html image
|
||||
audio video archive other</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>mimetype</code></td>
|
||||
<td>String</td>
|
||||
<td>Optional but moderately recommended. Mimetype designation of data, eg <code>text/html</code>,
|
||||
<code>image/jpeg</code> etc. If not specified, an attempt will be made to guess
|
||||
a mometype from the value of the <code>path</code> key. If this attempt fails, then
|
||||
this key will be set to <code>application/x-octet-stream</code> by the node receiving
|
||||
the <code>putItem</code> RPC.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>keywords</code></td>
|
||||
<td>String</td>
|
||||
<td>Optional but moderately recommended.
|
||||
A set of keywords, under which the inserting app would like this item to be
|
||||
discoverable. Keywords should be entirely lower case and comma-separated. Content
|
||||
inserts should consider keywords carefully, and only use space characters inside
|
||||
keywords when necessary (eg, for flagging a distinctive phrase containing very
|
||||
common words).</td>
|
||||
<tr>
|
||||
<td><code>privateKey</code></td>
|
||||
<td>String</td>
|
||||
<td>Optional. A Base64-encoded signing private key, in cases where the application wishes
|
||||
to insert an item in <code>signed space</code> mode. This can be accompanied by another key,
|
||||
<code>path</code>, indicating a 'path' within the signed space. If 'path'
|
||||
is not given, it will default to '/'.<br>
|
||||
<br>
|
||||
Either way, when a node receives a
|
||||
<code>putItem</code> RPC containing a <code>privateKey</code> in its metadata,
|
||||
it removes this key and replaces it with <code>publicKey</code> and
|
||||
<code>signature</code>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>path</code></td>
|
||||
<td>String</td>
|
||||
<td>Optional. The virtual pathname, within signed space, under which to store the item.
|
||||
This gets ignored and deleted unless the application also provides a
|
||||
<code>privateKey</code> as well. But if the private key is given, the path
|
||||
is used in conjunction with the private key to generate <code>publicKey</code>
|
||||
and <code>signature</code> keys (see below).<br>
|
||||
<code>path</code> should be a 'unix-style pathname', ie, containing only slashes
|
||||
as (pseudo) directory delimiters, and alphanumeric, '-', '_' and '.' characters,
|
||||
and preferably ending in a meaningful file extension such as <code>.html</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>expiry</code></td>
|
||||
<td>int</td>
|
||||
<td>Unixtime at which the inserted item should expire. When this expiry time
|
||||
is reached, the item won't necessarily be deleted straight away, but may
|
||||
be deleted whenever a node's data store is full.<br>
|
||||
<br>
|
||||
If this is not provided, it will default to a given duration according to
|
||||
the client node's configuration.<br>
|
||||
<br>
|
||||
If it is provided, by an application, then the client node will transparently
|
||||
generate the required 'rent payment' before caching the data item and uploading
|
||||
it to servers.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br><br>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>2.2. Keys Inserted By Node Upon Receipt Of <code>putItem</code> RPC</h3>
|
||||
|
||||
<table width=80% cellspacing=0 cellpadding=4 border=1 align=center>
|
||||
<tr style="font-weight: bold">
|
||||
<td>Key</td>
|
||||
<td>Data Type</td>
|
||||
<td>Description</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>size</code></td>
|
||||
<td>Integer</td>
|
||||
<td>Size of the data to be inserted, in bytes.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>dataHash</code></td>
|
||||
<td>String</td>
|
||||
<td>base64-encoded SHA256 hash of data.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>uri</code></td>
|
||||
<td>String</td>
|
||||
<td>This depends on whether the item is being inserted in <i>plain</i> or
|
||||
<i>signed space</i> mode.<br>
|
||||
<br>
|
||||
If inserting in <i>plain</i> mode, then the uri is in the form
|
||||
<code>Q:somebase64hash</code>, where the hash is computed according to
|
||||
the <a href="#plainhash">plain hash calculation procedure</a>.<br>
|
||||
<br>
|
||||
If inserting in <i>signed space</i> mode, then the uri will be in the form
|
||||
<code>Q:somebase64hash/path.ext</code>, where the hash is computed as per
|
||||
the <a href="#signedhash">signed space hash calculation procedure</a>, and
|
||||
the <code>/path.ext</code> is the verbatim value of the app-supplied
|
||||
<code>path</code> key.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>publicKey</code></td>
|
||||
<td>String</td>
|
||||
<td>Base64-encoded signing public key. In cases where app provides
|
||||
<code>privateKey</code>,
|
||||
a node will derive the signing public key from the private key,
|
||||
delete the private key from the metadata, and replace it with its corresponding
|
||||
public key
|
||||
key.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>signature</code></td>
|
||||
<td>String</td>
|
||||
<td>Base64-encoded signature of <code>path+dataHash</code>, created using
|
||||
the app-provided <code>privateKey</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>rent</code></td>
|
||||
<td>String</td>
|
||||
<td>A rent payment for the data's accommodation on the server.<br>
|
||||
Intention is to support a variety of payment tokens. Initially, the
|
||||
only acceptable form of payment will be a hashcash-like token,
|
||||
in the form <code>hashcash:base64string</code>. The <code>hashcash:</code>
|
||||
prefix indicates that this payment is in hashcash currency, in which case
|
||||
the <code>base64String</code> should decode to a 16-byte string whose
|
||||
SHA256 hash partially collides with <code>dataHash</code>.
|
||||
The greater the number of bits in the collision,
|
||||
the longer the data's accommodation will be 'paid up for'.<br>
|
||||
<br>
|
||||
If this key is already present, a Q node will verify the hashcash,
|
||||
and adjust the <code>expiry</code> key value to the time the item's accommodation
|
||||
is paid up till.<br>
|
||||
<br>
|
||||
If the key is not present:
|
||||
<ul>
|
||||
<li>A client node will generate a value for this key with enough collision bits
|
||||
to pay the accommodation up till the given app-specified <code>expiry</code> date.</li>
|
||||
<li>A server node will grant temporary free accommodation, and adjust the <code>expiry</code>
|
||||
key to the end of the free accommodation period.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br><br>
|
||||
|
||||
<a name="plainhash"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>3. URI Determination Procedures</h2>
|
||||
|
||||
<h3>3.1. Plain Hash URI Calculation Procedure</h3>
|
||||
|
||||
When items are inserted in <code>plain</code> mode, the final URI is determined from
|
||||
a hash of the data and metadata. Security of the item is based on the mathematical difficulty
|
||||
of creating an arbitrary data+metadata set whose hash collides with the target URI.<br>
|
||||
<br>
|
||||
Specifically, the recipe for calculating plain hash URIs is:
|
||||
<ol>
|
||||
<li>If the key <code>size</code> is missing, set this to the size of the data,
|
||||
in bytes</li>
|
||||
<li>If the key <code>dataHash</code> is missing, set this to the base64-encoded
|
||||
SHA256(data)</li>
|
||||
<li>If the key <code>title</code> is missing, set this to the value of <code>dataHash</code></li>
|
||||
<li>From the metadata, create a set of strings, each in the form <code>key=value</code>,
|
||||
where each line contains a metadata <code>key</code> and its <code>value</code>, and
|
||||
is terminated by an ASCII linefeed (\n, 0x10).</li>
|
||||
<li>Ensure that key <code>uri</code> is omitted</li>
|
||||
<li>Sort the strings into ascending ASCII sort order</li>
|
||||
<li>Concatenate the strings together into one big string</li>
|
||||
<li>Calculate the SHA256 hash of this string</li>
|
||||
<li>Encode the hash into Base64</li>
|
||||
<li>Prepend the string <code>Q:</code> to this</li>
|
||||
</ol>
|
||||
|
||||
<a name="signedhash"/>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>3.2. Signed Space URI Calculation Procedure</h3>
|
||||
|
||||
This is much simpler than determining plain hash URI, since the security of the URI
|
||||
is based not on hashes of data and metadata, but on the cryptographic <code>privateKey</code>
|
||||
given by the application.<br>
|
||||
<br>
|
||||
Calculation recipe for Signed Space URIs is:
|
||||
<ol>
|
||||
<li>Calculate the SHA256 hash of the private key's binary data (not its base64 representation)</li>
|
||||
<li>Encode this hash into base64, dropping any trailing '=' characters</li>
|
||||
<li>Append to this the value of metadata item <code>path</code> (recall that <code>path</code>,
|
||||
if not empty, must begin with a '/')</li>
|
||||
<li>Prepend the string <code>Q:</code> to this</li>
|
||||
</ol>
|
||||
The resulting URI then is in the form <code>Q:pubkeyHash/path.ext</code>
|
||||
|
||||
<hr>
|
||||
<!-- Created: Tue Apr 5 00:56:45 NZST 2005 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Wed Apr 6 00:36:37 NZST 2005
|
||||
<!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 36 KiB |
@ -1 +0,0 @@
|
||||
rxvXpHKfWGWsql4PJaHglAERSUYyrdKKAzK6jPHT4QXRf9jgcVd4mInq0j6H4inVOzT9dG4L6c9GrlQwe4ysUm5jSTyZemxiZpQDCAazsoRzNDv6gevA40J6uGl10JtVtOjqXW8Ej0JUKubz88g~ogPb1h4Xibc-RrtqrvsJebg5xYFkLlnr7DxDtiWzIMRSZ9Ri2P~eq0SwZzd81tvASPj5fb3nySHeABAuY8HrNu0gqRLjeayDpd3OK1ogrxf1lMvfutn5pnLrlVcvKHa~6rNWWGSulsuEYWtpUd4Itj9aKqIgF9ES7RF77Z73W1f6NRTHO48ZLyLLaKVLjDIsHQP-0mOevszcPjFWtheqRKvT2D28WEMpVC-mPtfw91BkdgBa3pwWhwG~7KIhvWhGs8bj2NOKkqrwYU7xhNVaHdDDkzv4gsweCutHNiiCF~4yL54WzCIfSKDjcHjQxxVkh2NKeaItzgw9E~mPAKNZD22X~2oAuuL9i~0lldEV1ddUAAAA
|
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 98 KiB |
@ -1,23 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Q Screenshots</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Q Screenshots</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="screenshot-search.jpg">Search Screen</li>
|
||||
<li><a href="screenshot-qsite.jpg">QSite Insertion Form</li>
|
||||
<li><a href="screenshot-iewarn.jpg">Q Security Features</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
<address><a href="mailto:aum@mail.i2p">aum</a></address>
|
||||
<!-- Created: Sat Apr 16 17:24:02 NZST 2005 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Mon Apr 18 14:06:02 NZST 2005
|
||||
<!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
@ -1,90 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="aum">
|
||||
<!-- Written to assume that classpath is rooted in the current directory. -->
|
||||
<!-- So this should be OK if you make this script in the root of a filesystem. -->
|
||||
<!-- If not, just change src.dir to be the root of your sources' package tree -->
|
||||
<!-- and use e.g. View over a Filesystem to mount that subdirectory with all capabilities. -->
|
||||
<!-- The idea is that both Ant and NetBeans have to know what the package root is -->
|
||||
<!-- for the classes in your application. -->
|
||||
|
||||
<!-- Don't worry if you don't know the Ant syntax completely or need help on some tasks! -->
|
||||
<!-- The standard Ant documentation can be downloaded from AutoUpdate and -->
|
||||
<!-- and then you can access the Ant manual in the online help. -->
|
||||
|
||||
<target name="init">
|
||||
<property location="build" name="classes.dir"/>
|
||||
<property location="src" name="src.dir"/>
|
||||
<property location="doc/q/api" name="javadoc.dir"/>
|
||||
<property name="project.name" value="${ant.project.name}"/>
|
||||
<property location="${project.name}.jar" name="jar"/>
|
||||
<property location="q.war" name="war"/>
|
||||
</target>
|
||||
|
||||
<target name="builddep">
|
||||
<ant dir="../../i2ptunnel/java/" target="build" />
|
||||
<!-- i2ptunnel builds ministreaming and core -->
|
||||
</target>
|
||||
|
||||
<target depends="init,builddep" name="compile">
|
||||
<!-- Both srcdir and destdir should be package roots. -->
|
||||
<mkdir dir="${classes.dir}"/>
|
||||
<javac debug="true"
|
||||
deprecation="true"
|
||||
destdir="${classes.dir}"
|
||||
srcdir="${src.dir}"
|
||||
classpath="xmlrpc.jar:../../../core/java/build/i2p.jar:../../ministreaming/java/build/mstreaming.jar:../../i2ptunnel/java/build/i2ptunnel.jar" >
|
||||
<!-- To add something to the classpath: -->
|
||||
<!-- <classpath><pathelement location="${mylib}"/></classpath> -->
|
||||
<!-- To exclude some files: -->
|
||||
<!-- <exclude name="com/foo/SomeFile.java"/><exclude name="com/foo/somepackage/"/> -->
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target depends="init,compile" name="jar">
|
||||
<!-- To make a standalone app, insert into <jar>: -->
|
||||
<!-- <manifest><attribute name="Main-Class" value="com.foo.Main"/></manifest> -->
|
||||
<!-- <jar basedir="${classes.dir}" compress="true" jarfile="${jar}"> -->
|
||||
<jar compress="true" jarfile="${jar}">
|
||||
<!-- <jar basedir="." compress="true" jarfile="${jar}" includes="**/*.class,doc/**/*.html"> -->
|
||||
<fileset dir="${classes.dir}"/>
|
||||
<fileset dir="." includes="qresources/**"/>
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.aum.q.QMgr"/>
|
||||
<attribute name="Class-Path" value="i2p.jar xmlrpc.jar mstreaming.jar streaming.jar jbigi.jar"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target depends="init,compile" name="war">
|
||||
<!-- To make a standalone app, insert into <jar>: -->
|
||||
<!-- <manifest><attribute name="Main-Class" value="com.foo.Main"/></manifest> -->
|
||||
<war compress="true" jarfile="${war}" webxml="web.xml">
|
||||
<!-- <fileset file="build/net/i2p/aum/q/QConsole.class"/> -->
|
||||
<classes dir="build" includes="**/QConsole.class"/>
|
||||
<classes dir="build" includes="**/HTML/**"/>
|
||||
<!-- <fileset includes="**/HTML/*.class"/> -->
|
||||
<lib file="xmlrpc.jar"/>
|
||||
</war>
|
||||
</target>
|
||||
|
||||
<target depends="init,jar,war" description="Build everything." name="all"/>
|
||||
|
||||
<target depends="init" description="Javadoc for my API." name="javadoc">
|
||||
<mkdir dir="${javadoc.dir}"/>
|
||||
<javadoc destdir="${javadoc.dir}" packagenames="*">
|
||||
<sourcepath>
|
||||
<pathelement location="${src.dir}"/>
|
||||
</sourcepath>
|
||||
<sourcepath>
|
||||
<pathelement location="/java/xmlrpc-1.2-b1/src/java"/>
|
||||
</sourcepath>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
<target depends="init" description="Clean all build products." name="clean">
|
||||
<delete dir="${classes.dir}"/>
|
||||
<delete dir="${javadoc.dir}"/>
|
||||
<delete file="${jar}"/>
|
||||
</target>
|
||||
|
||||
</project>
|
@ -1,10 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading">Item Not Found</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=center>Failed to retrieve item:<br>
|
||||
<code><tmpl_var 404_uri></code>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,27 +0,0 @@
|
||||
<TABLE align="center" class="mainpaneitem">
|
||||
<TR>
|
||||
<TD class="formHeading">About Q</TD>
|
||||
</tr>
|
||||
<tr class="formBody">
|
||||
<TD align=center>
|
||||
<p>Version
|
||||
<tmpl_if version>
|
||||
<tmpl_var version></p>
|
||||
<tmpl_else>
|
||||
0.0.1
|
||||
</tmpl_if>
|
||||
<p>Designed and engineered by <a href="mailto:aum@mail.i2p">aum</a></p>
|
||||
|
||||
<p>Copyright © 2005 by aum.
|
||||
<br>Released under the
|
||||
<br>GNU Lesser General Public License</p>
|
||||
|
||||
<p style="font-size: smaller; font-style: italic">
|
||||
Many thanks to jrandom, smeghead and frosk<br>
|
||||
for their patient and knowledgeable support<br>
|
||||
in helping this python programmer<br>
|
||||
get partly proficient in java.</p>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
@ -1,40 +0,0 @@
|
||||
<table align="center" class="mainpaneitem" width=80%>
|
||||
<tr>
|
||||
<td class="formHeading">Add Hub Noderef</td>
|
||||
</tr>
|
||||
|
||||
<form action="/tools" method="POST" class="formBody">
|
||||
|
||||
<input type="hidden" name="cmd" value="addref">
|
||||
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table width=70%>
|
||||
<tr>
|
||||
<td>
|
||||
In order for your node to join a Q network, it must have a ref to at
|
||||
least one of the running Q Hubs. You need to get a Q Hub noderef and
|
||||
paste it here.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center>
|
||||
<textarea name="noderef" cols=40 rows=6></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="center">
|
||||
<input type="submit" name="submit" value="Add Hub Noderef!">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</form>
|
||||
|
||||
</table>
|
||||
|
@ -1,29 +0,0 @@
|
||||
<table align="center" class="mainpaneitem" width=80%>
|
||||
<tr>
|
||||
<td class="formHeading" colspan=2>Critical Anonymity Alert!</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table cellspacing=0 cellpadding=5 align=center border=1>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<p>You are attempting to view a QSite via the Internet Explorer web browser.
|
||||
</p>
|
||||
<p>We have blocked the connection to protect your anonymity.
|
||||
</p>
|
||||
<p>As a matter of policy, Q does not support QSite browsing via Microsoft
|
||||
Internet Explorer (MSIE), because of that browser's abysmal track record with
|
||||
regard to security. If we did allow you to browse Q via MSIE, it would
|
||||
be easy for a malicious QSite author to embed hostile content which
|
||||
undermines your computer's security and compromises your anonymity.
|
||||
</p>
|
||||
<p>If you want to surf I2P QSites, you'll need to use a more secure web
|
||||
browser such as <a href="http://www.mozilla.org">Mozilla or Firefox</a>.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,52 +0,0 @@
|
||||
<table align="center" class="mainpaneitem" width=80%>
|
||||
<tr>
|
||||
<td class="formHeading" colspan=2>Critical Anonymity Alert!</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table cellspacing=0 cellpadding=5 align=center border=1>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<p>You are attempting to view a QSite via an unprotected link.
|
||||
</p>
|
||||
<p>We have blocked the connection to protect your anonymity. If we don't
|
||||
do this, then a malicious QSite author can insert content into the QSite
|
||||
which triggers oubound hits to arbitrary servers on the mainstream web,
|
||||
which in turn can easily reveal a lot of personal information about you
|
||||
and the QSite you are accessing.
|
||||
</p>
|
||||
<p>If you want to browse QSites with your web browser with greater safety,
|
||||
you'll have to follow these simple steps:
|
||||
</p>
|
||||
<ol>
|
||||
<li>Edit your I2P <code>hosts.txt</code> file and add the following entry
|
||||
(all on one line):
|
||||
<blockquote><code><textarea rows=5 cols=50>q.i2p=<tmpl_var dest></textarea></code><blockquote>
|
||||
(and make sure you do NOT reveal this entry to anyone else)
|
||||
</li>
|
||||
<li>Configure one of your web browsers to use the proxy server:
|
||||
<blockquote><code>localhost:4444</code></blockquote>
|
||||
(or whatever address you have configured your I2P EEProxy to listen on,
|
||||
if you've changed it)<br><br>
|
||||
</li>
|
||||
<li>Start up the browser you have just configured, and enter the web address:
|
||||
<blockquote><code>http://q.i2p</code></blockquote>
|
||||
</li>
|
||||
</ol>
|
||||
<p>Even if you do this, you still won't have a 100% guarantee of anonymity, since
|
||||
a malicious QSite author can send code to your browser which exploits a vulnerability
|
||||
in the browser to compromise your anonymity (eg, accessing third party cookies, executing
|
||||
arbitrary code, accessing your local filesystem, uploading compromising information
|
||||
about you to hostile I2P EEPsites etc). But you can relax (somewhat) in the knowledge
|
||||
that such attacks are much more difficult, particularly if you use a decent web browser.
|
||||
</p>
|
||||
<p>Thank you for your co-operation. We wish you happy and safe browsing.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,9 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading">Q Downloads</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Not implemented yet</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -1,28 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading">Generate New Keypair</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
Click the button to generate a new keypair for
|
||||
future inserts of signed space keys.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="center">
|
||||
<form action="/tools" method="POST" class="formBody">
|
||||
<input type="hidden" name="cmd" value="genkeys">
|
||||
<input type="submit" name="submit" value="Generate Keys!">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
@ -1,32 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td colspan=2 class="formHeading">Your New Keys</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="center" colspan=2>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
Please save these keys in a safe place,
|
||||
preferably on an encrypted partition:
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Public Key: </td>
|
||||
<td>
|
||||
<input readonly type="text" size=32 style="font-family: courier, monospace" value="<tmpl_var publickey>">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Private Key: </td>
|
||||
<td><input readonly type="text" size=32 style="font-family: courier, monospace" value="<tmpl_var privatekey>"></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
@ -1,15 +0,0 @@
|
||||
<table align="center" class="mainpaneitem" border=0>
|
||||
<TR>
|
||||
<TD class="formHeading" colspan="3">Retrieve Content</TD>
|
||||
</tr>
|
||||
<tr class="formBody">
|
||||
<form action="/home" method="POST">
|
||||
<input type="hidden" name="cmd" value="get">
|
||||
|
||||
<TD>URI:</TD>
|
||||
<td><INPUT type="text" name="uri" value="Q:" size="60" maxlength="128"></td>
|
||||
<td><INPUT type="submit" name="submit" value="Retrieve it"></td>
|
||||
|
||||
</form>
|
||||
</TR>
|
||||
</table>
|
@ -1,11 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading">Q Help</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Not written yet
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -1,34 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading" colspan=2>Current Background Jobs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<tmpl_if items>
|
||||
|
||||
<table cellspacing=0 cellpadding=5 align=center border=1>
|
||||
|
||||
<tr>
|
||||
<td><b>Secs From Now</b></td>
|
||||
<td><b>Description</b></td>
|
||||
</tr>
|
||||
|
||||
<tmpl_loop items>
|
||||
<tr>
|
||||
<td><tmpl_var future></td>
|
||||
<td><tmpl_var description></td>
|
||||
</tr>
|
||||
</tmpl_loop>
|
||||
|
||||
</table>
|
||||
|
||||
<tmpl_else>
|
||||
|
||||
<tr><td colspan=2 align=center><i>(No current jobs)</i></td></tr>
|
||||
|
||||
</tmpl_if>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,122 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<TITLE>Q Web Interface</TITLE>
|
||||
<style type="text/css">
|
||||
<!--
|
||||
body { font-family: helvetica, arial, sans-serif; background-color: #000080 }
|
||||
td { }
|
||||
code { font-family: courier, monospace; font-weight: bolder; font-size:smaller }
|
||||
.logocell {
|
||||
border-color: #ffe000;
|
||||
border-width: 1px;
|
||||
border-top-style:none;
|
||||
border-bottom-style:solid;
|
||||
border-left-style:none;
|
||||
border-right-style:none;
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
color: #f0f0ff;
|
||||
}
|
||||
.tabcell {
|
||||
font-weight: bold;
|
||||
background-color: #fffff0;
|
||||
padding:5px;
|
||||
border-color:#ffe000;
|
||||
border-width: 1px;
|
||||
border-top-style:solid;
|
||||
border-bottom-style:none;
|
||||
border-left-style:solid;
|
||||
border-right-style:solid;
|
||||
}
|
||||
.tabcell_inactive {
|
||||
background-color: #f0f0ff;
|
||||
padding:5px;
|
||||
border-color:#ffe000;
|
||||
border-width: 1px;
|
||||
border-top-style:solid;
|
||||
border-bottom-style:solid;
|
||||
border-left-style:solid;
|
||||
border-right-style:solid;
|
||||
}
|
||||
.tablink {
|
||||
font-size: smaller;
|
||||
text-decoration: none;
|
||||
}
|
||||
.mainpane { border-color:#ffe000;
|
||||
border-width: 1px;
|
||||
border-top-style:none;
|
||||
border-bottom-style:solid;
|
||||
border-left-style:solid;
|
||||
border-right-style:solid;
|
||||
}
|
||||
|
||||
.mainpaneitem1 { border-style:solid; border-color:#0000ff; border-width: thin; }
|
||||
|
||||
.mainpaneitem { border-style:solid;
|
||||
border-color:#0000ff;
|
||||
border-width: thin;
|
||||
background-color: #f0f0ff;
|
||||
}
|
||||
|
||||
.formHeading { font-size:larger; font-weight: bolder; text-align:center; }
|
||||
|
||||
.btn1 { font-weight: bold;
|
||||
}
|
||||
|
||||
input1 { background-color: #fffff0;
|
||||
color: #000080;
|
||||
|
||||
}
|
||||
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
<body bgcolor="#ffffff">
|
||||
<TABLE width="99%" height=99% align="center" cellspacing="0" cellpadding="0" border=0>
|
||||
<TR>
|
||||
<TD>
|
||||
<table width="100%" cellspacing=0 cellpadding=0>
|
||||
<tr>
|
||||
<td>
|
||||
<table align=right cellspacing=0 cellpadding=0 border=0>
|
||||
<tr>
|
||||
<tmpl_loop tabs>
|
||||
<td class=<tmpl_if active>"tabcell"<tmpl_else>"tabcell_inactive"</tmpl_if>>
|
||||
<a class="tablink" href="/<tmpl_var name>"><tmpl_var label></a>
|
||||
</td>
|
||||
</tmpl_loop>
|
||||
|
||||
<tmpl_if _ignore>
|
||||
<TD class="tabcell_inactive">
|
||||
<a class="tablink" href="/status">Status</a>
|
||||
</TD>
|
||||
<TD class="tabcell">
|
||||
<a class="tablink" href="/settings">Settings</a>
|
||||
</TD>
|
||||
</tmpl_if>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<TD width=100% class="logocell">
|
||||
Q <tmpl_var nodeType> Node
|
||||
</TD>
|
||||
</TR>
|
||||
</table>
|
||||
</TD> </TR>
|
||||
<tr height=99% bgcolor="#fffff0">
|
||||
<TD class="mainpane">
|
||||
<br>
|
||||
<center>
|
||||
<tmpl_loop items>
|
||||
<br>
|
||||
<tmpl_var item>
|
||||
<br>
|
||||
</tmpl_loop>
|
||||
</center>
|
||||
</TD>
|
||||
</tr>
|
||||
</TABLE>
|
||||
</body>
|
||||
</html>
|
@ -1,29 +0,0 @@
|
||||
<table align="center" class="mainpaneitem" width=80%>
|
||||
<tr>
|
||||
<td class="formHeading" colspan=2>Critical Anonymity Alert!</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table cellspacing=0 cellpadding=5 align=center border=1>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<p>You are attempting to view a QSite via the Internet Explorer web browser.
|
||||
</p>
|
||||
<p>We have blocked the connection to protect your anonymity.
|
||||
</p>
|
||||
<p>As a matter of policy, Q does not support QSite browsing via Microsoft
|
||||
Internet Explorer (MSIE), because of that browser's abysmal track record with
|
||||
regard to security. If we did allow you to browse Q via MSIE, it would
|
||||
be easy for a malicious QSite author to embed hostile content which
|
||||
undermines your computer's security and compromises your anonymity.
|
||||
</p>
|
||||
<p>If you want to surf I2P QSites, you'll need to use a more secure web
|
||||
browser such as <a href="http://www.mozilla.org">Mozilla or Firefox</a>.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,10 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading">Error Inserting <tmpl_if is_site>QSite<tmpl_else>Item</tmpl_if></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=center>Your insert failed because:<br>
|
||||
<code><tmpl_var error></code>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,139 +0,0 @@
|
||||
<TABLE align="center" class="mainpaneitem" width=90% >
|
||||
<TR>
|
||||
<TD class="formHeading" colspan="2">Insert Content</TD>
|
||||
</tr>
|
||||
|
||||
<TR>
|
||||
<TD colspan="2" align=center><a href="/insert?mode=site">Insert A QSite Instead</a></TD>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<form method="POST" ENCTYPE="multipart/form-data" action="/insert" class="formBody">
|
||||
<!-- <form method="POST" action="/insert" class="formBody"> -->
|
||||
|
||||
<input type=hidden name="cmd" value="put">
|
||||
|
||||
<tr>
|
||||
<td valign=top>Type: </td>
|
||||
<td style="font-size:smaller">
|
||||
<input type="radio" name="type" value="text">Text
|
||||
<input type="radio" name="type" value="html">HTML
|
||||
<input type="radio" name="type" value="image">Image
|
||||
<input type="radio" name="type" value="audio">Audio
|
||||
<input type="radio" name="type" value="video">Video
|
||||
<input type="radio" name="type" value="archive">Archive
|
||||
<input type="radio" name="type" value="other" checked>Other
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Title: </TD>
|
||||
<td>
|
||||
<input type="text" name="title" size="60" maxlength="58">
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(A short descriptive title for this item)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Path: </TD>
|
||||
<td>
|
||||
<input type="text" name="path" size="60" maxlength="128">
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(If you're inserting in plain-hash mode, this should be a suggested
|
||||
filename for people to save the item as when downloading it; If you're
|
||||
inserting in signed-space mode, this can be a longer pathname)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Mimetype: </TD>
|
||||
<td>
|
||||
<input type="text" name="mimetype" size="40" maxlength="40">
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(Leave blank unless you know exactly what this means)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Keywords: </TD>
|
||||
<td>
|
||||
<input type="text" name="keywords" size="60" maxlength="80">
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(Comma-separated list of short descriptive keywords)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Abstract: </TD>
|
||||
<td>
|
||||
<textarea name="abstract" cols="50" rows="2"></textarea>
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(A short descriptive summary for the item, preferably no
|
||||
longer than 256 characters)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>File: </TD>
|
||||
<td>
|
||||
<INPUT type="file" name="data" size="40" maxlength="128">
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(Leave this blank if you are entering the raw data in the text box below)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Private Key: </TD>
|
||||
<td>
|
||||
<INPUT type="text" name="privkey" size="30" maxlength="60">
|
||||
<div style="font-size: smaller; font-style: italic">
|
||||
(Only if inserting in signed space mode)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD colspan=2 align=center>
|
||||
<INPUT class="btn" type="submit" name="submit" value="Insert it">
|
||||
</TD>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top>Raw Data:</td>
|
||||
<td>
|
||||
<div style="font-size: smaller; font-style:italic">
|
||||
(You may enter the raw data here as text instead of selecting a
|
||||
file above)
|
||||
</div>
|
||||
<textarea name="rawdata" cols=60 rows=16></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
</TABLE>
|
@ -1,10 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading"><tmpl_if is_site>QSite<tmpl_else>Item</tmpl_if> Inserted Successfully</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=center>Item URI:<br>
|
||||
<code><input type="text" size=60 readonly value="<tmpl_var uri>"></code>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,101 +0,0 @@
|
||||
<table align="center" class="mainpaneitem" width=90% >
|
||||
<TR>
|
||||
<TD class="formHeading" colspan="2">Insert A QSite</TD>
|
||||
</tr>
|
||||
|
||||
<TR>
|
||||
<TD colspan="2" align=center><a href="/insert?mode=file">Insert A Single File Instead</a></TD>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<form method="POST" action="/insert" class="formBody">
|
||||
<!-- <form method="POST" action="/insert" class="formBody"> -->
|
||||
|
||||
<input type=hidden name="cmd" value="putsite">
|
||||
<input type=hidden name="type" value="qsite">
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Name: </TD>
|
||||
<td>
|
||||
<input type="text" name="name" size="32" maxlength="50">
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(A short name for the QSite - should contain only alphanumerics, '-', and '_';
|
||||
should definitely <i>not</i> contain '/', ':', '\', ' ' etc)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Private Key: </TD>
|
||||
<td>
|
||||
<INPUT type="text" name="privkey" size="30" maxlength="60">
|
||||
<div style="font-size: smaller; font-style: italic">
|
||||
(Mandatory - if you don't have a signed-space keypair, get one by
|
||||
clicking on <b>Tools</b>)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Directory: </TD>
|
||||
<td>
|
||||
<INPUT type="text" name="dir" size="60" maxlength="128">
|
||||
<div style="font-size: smaller; font-style: italic">
|
||||
(Absolute directory path where the QSite's files reside)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Title: </TD>
|
||||
<td>
|
||||
<input type="text" name="title" size="60" maxlength="58">
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(A short descriptive title for this QSite)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Keywords: </TD>
|
||||
<td>
|
||||
<input type="text" name="keywords" size="60" maxlength="80">
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(Comma-separated list of short descriptive keywords)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD valign=top>Abstract: </TD>
|
||||
<td>
|
||||
<textarea name="abstract" cols="50" rows="2"></textarea>
|
||||
<div style="font-style: italic; font-size: smaller">
|
||||
(A short descriptive summary for the QSite, preferably no
|
||||
longer than 256 characters)
|
||||
</div>
|
||||
</td>
|
||||
</TR>
|
||||
|
||||
<tr><td colspan=2><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD colspan=2 align=center>
|
||||
<INPUT class="btn" type="submit" name="submit" value="Insert it">
|
||||
</TD>
|
||||
</tr>
|
||||
|
||||
</form>
|
||||
|
||||
</table>
|
@ -1,76 +0,0 @@
|
||||
<TABLE align="center" class="mainpaneitem">
|
||||
<TR>
|
||||
<TD class="formHeading" colspan="3">Search For Content</TD>
|
||||
</tr>
|
||||
|
||||
<form method="GET" action="/search" class="formBody">
|
||||
|
||||
<input type=hidden name=cmd value="search">
|
||||
|
||||
<tr>
|
||||
<td valign=top>Type: </td>
|
||||
<td style="font-size:smaller" colspan=2>
|
||||
<input type="radio" name="type" value="any" checked>ANY
|
||||
<input type="radio" name="type" value="qsite">QSite
|
||||
<input type="radio" name="type" value="text">Text
|
||||
<input type="radio" name="type" value="html">HTML
|
||||
<input type="radio" name="type" value="image">Image
|
||||
<br>
|
||||
<input type="radio" name="type" value="audio">Audio
|
||||
<input type="radio" name="type" value="video">Video
|
||||
<input type="radio" name="type" value="archive">Archive
|
||||
<input type="radio" name="type" value="other">Other
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Title: </td>
|
||||
<td><input type="text" name="title" size="60" value="<tmpl_var title>" maxlength="128"></td>
|
||||
<td><input type="checkbox" name="title_re" <tmpl_if title_re>checked</tmpl_if>>regexp</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<TD>Path: </TD>
|
||||
<td><INPUT type="text" name="path" size="60" value="<tmpl_var title>" maxlength="128"></td>
|
||||
<td><input type="checkbox" name="path_re" <tmpl_if path_re>checked</tmpl_if>>regexp</td>
|
||||
</TR>
|
||||
|
||||
<tr>
|
||||
<TD>Mimetype: </TD>
|
||||
<td><INPUT type="text" name="mimetype" size="40" maxlength="40" value="<tmpl_var mimetype>"></td>
|
||||
<td><input type="checkbox" name="mimetype_re" <tmpl_if mimetype_re>checked</tmpl_if>>regexp</td>
|
||||
</TR>
|
||||
|
||||
<tr>
|
||||
<TD>Keywords: </TD>
|
||||
<td><INPUT type="text" name="keywords" size="60" maxlength="80" value="<tmpl_var keywords>"></td>
|
||||
<td><input type="checkbox" name="keywords_re" <tmpl_if keywords_re>checked</tmpl_if>>regexp</td>
|
||||
</TR>
|
||||
|
||||
<tr>
|
||||
<TD>Summary: </TD>
|
||||
<td><textarea name="summary" cols="50" rows=2><tmpl_var summary></textarea></td>
|
||||
<td><input type="checkbox" name="summary_re" <tmpl_if summary_re>checked</tmpl_if>>regexp</td>
|
||||
</TR>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
Search Mode:
|
||||
</td>
|
||||
<td>
|
||||
<input type=radio name="searchmode" value="and" checked>AND
|
||||
<input type=radio name="searchmode" value="or">OR
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan=3><hr></td></tr>
|
||||
|
||||
<tr>
|
||||
<TD colspan=3 align=center>
|
||||
<INPUT class="btn" type="submit" name="submit" value="Search!">
|
||||
</TD>
|
||||
</tr>
|
||||
|
||||
</form>
|
||||
|
||||
</TABLE>
|
@ -1,27 +0,0 @@
|
||||
<table align="center" class="mainpaneitem" <tmpl_if results>width="95%"</tmpl_if>>
|
||||
<tr>
|
||||
<td class="formHeading" colspan=2>Search Results</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-style: italic" align="center"><tmpl_var numresults> items found</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="90%">
|
||||
<table cellspacing=0 cellpadding=5 align=center border=0 width=95%>
|
||||
<tmpl_loop results>
|
||||
<tr>
|
||||
<td>
|
||||
<div style="font-size: larger"><a href="/<tmpl_var uri>"><tmpl_var title></a></div>
|
||||
<tmpl_if abstract>
|
||||
<div style="font-style: italic"><tmpl_var abstract></div>
|
||||
</tmpl_if>
|
||||
<div style="font-size: smaller; color: #008000;"><tmpl_var uri></div>
|
||||
<div style="font-size:smaller;"><tmpl_var type> (<tmpl_var mimetype>) <tmpl_var size> bytes</div>
|
||||
<div/>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,9 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading">Q Settings</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Not implemented yet</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -1,24 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading" colspan=2>Q Node Status</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table cellspacing=0 cellpadding=5 align=center border=1>
|
||||
|
||||
<tr>
|
||||
<td><b>Item</b></td>
|
||||
<td><b>Value</b></td>
|
||||
</tr>
|
||||
|
||||
<tmpl_loop items>
|
||||
<tr>
|
||||
<td><tmpl_var key></td>
|
||||
<td><tmpl_var value></td>
|
||||
</tr>
|
||||
</tmpl_loop>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@ -1,6 +0,0 @@
|
||||
<table align="center" class="mainpaneitem">
|
||||
<tr>
|
||||
<td class="formHeading">Q Tools</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* HTML.Template: A module for using HTML Templates with java
|
||||
*
|
||||
* Copyright (c) 2002 Philip S Tellis (philip.tellis@iname.com)
|
||||
*
|
||||
* This module is free software; you can redistribute it
|
||||
* and/or modify it under the terms of either:
|
||||
*
|
||||
* a) the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 1, or (at your option)
|
||||
* any later version, or
|
||||
*
|
||||
* b) the "Artistic License" which comes with this module.
|
||||
*
|
||||
* 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 either the GNU General Public License or the
|
||||
* Artistic License for more details.
|
||||
*
|
||||
* You should have received a copy of the Artistic License
|
||||
* with this module, in the file ARTISTIC. If not, I'll be
|
||||
* glad to provide one.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Modified by David McNab (david@rebirthing.co.nz) to allow nesting of
|
||||
* templates (ie, passing a child Template object as a value argument
|
||||
* to a .setParam() invocation on a parent Template object).
|
||||
*
|
||||
*/
|
||||
|
||||
package HTML.Tmpl.Element;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Vector;
|
||||
|
||||
import HTML.Template;
|
||||
|
||||
public class Conditional extends Element
|
||||
{
|
||||
private boolean control_val = false;
|
||||
private Vector [] data;
|
||||
|
||||
public Conditional(String type, String name)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if(type.equalsIgnoreCase("if"))
|
||||
this.type="if";
|
||||
else if(type.equalsIgnoreCase("unless"))
|
||||
this.type="unless";
|
||||
else
|
||||
throw new IllegalArgumentException(
|
||||
"Unrecognised type: " + type);
|
||||
|
||||
this.name = name;
|
||||
this.data = new Vector[2];
|
||||
this.data[0] = new Vector();
|
||||
}
|
||||
|
||||
public void addBranch() throws IndexOutOfBoundsException
|
||||
{
|
||||
if(data[1] != null)
|
||||
throw new IndexOutOfBoundsException("Already have two branches");
|
||||
|
||||
if(data[0] == null)
|
||||
data[0] = new Vector();
|
||||
else if(data[1] == null)
|
||||
data[1] = new Vector();
|
||||
}
|
||||
|
||||
public void add(String text)
|
||||
{
|
||||
if(data[1] != null)
|
||||
data[1].addElement(text);
|
||||
else
|
||||
data[0].addElement(text);
|
||||
}
|
||||
|
||||
public void add(Element node)
|
||||
{
|
||||
if(data[1] != null)
|
||||
data[1].addElement(node);
|
||||
else
|
||||
data[0].addElement(node);
|
||||
}
|
||||
|
||||
public void setControlValue(Object control_val)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this.control_val = process_var(control_val);
|
||||
}
|
||||
|
||||
public String parse(Hashtable params)
|
||||
{
|
||||
if(!params.containsKey(this.name))
|
||||
this.control_val = false;
|
||||
else
|
||||
setControlValue(params.get(this.name));
|
||||
|
||||
StringBuffer output = new StringBuffer();
|
||||
|
||||
Enumeration de;
|
||||
if(type.equals("if") && control_val ||
|
||||
type.equals("unless") && !control_val)
|
||||
de = data[0].elements();
|
||||
else if(data[1] != null)
|
||||
de = data[1].elements();
|
||||
else
|
||||
return "";
|
||||
|
||||
while(de.hasMoreElements()) {
|
||||
Object e = de.nextElement();
|
||||
String eType = e.getClass().getName();
|
||||
if(eType.endsWith(".String"))
|
||||
output.append((String)e);
|
||||
else if (eType.endsWith(".Template"))
|
||||
output.append(((Template)e).output());
|
||||
else
|
||||
output.append(((Element)e).parse(params));
|
||||
}
|
||||
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
public String typeOfParam(String param)
|
||||
throws NoSuchElementException
|
||||
{
|
||||
for(int i=0; i<data.length; i++)
|
||||
{
|
||||
if(data[i] == null)
|
||||
continue;
|
||||
for(Enumeration e = data[i].elements();
|
||||
e.hasMoreElements();)
|
||||
{
|
||||
Object o = e.nextElement();
|
||||
if(o.getClass().getName().endsWith(".String"))
|
||||
continue;
|
||||
if(((Element)o).Name().equals(param))
|
||||
return ((Element)o).Type();
|
||||
}
|
||||
}
|
||||
throw new NoSuchElementException(param);
|
||||
}
|
||||
|
||||
private boolean process_var(Object control_val)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
String control_class = "";
|
||||
|
||||
if(control_val == null)
|
||||
return false;
|
||||
|
||||
control_class=control_val.getClass().getName();
|
||||
if(control_class.indexOf(".") > 0)
|
||||
control_class = control_class.substring(
|
||||
control_class.lastIndexOf(".")+1);
|
||||
|
||||
if(control_class.equals("String")) {
|
||||
return !(((String)control_val).equals("") ||
|
||||
((String)control_val).equals("0"));
|
||||
} else if(control_class.equals("Vector")) {
|
||||
return !((Vector)control_val).isEmpty();
|
||||
} else if(control_class.equals("Boolean")) {
|
||||
return ((Boolean)control_val).booleanValue();
|
||||
} else if(control_class.equals("Integer")) {
|
||||
return (((Integer)control_val).intValue() != 0);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unrecognised type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* HTML.Template: A module for using HTML Templates with java
|
||||
*
|
||||
* Copyright (c) 2002 Philip S Tellis (philip.tellis@iname.com)
|
||||
*
|
||||
* This module is free software; you can redistribute it
|
||||
* and/or modify it under the terms of either:
|
||||
*
|
||||
* a) the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 1, or (at your option)
|
||||
* any later version, or
|
||||
*
|
||||
* b) the "Artistic License" which comes with this module.
|
||||
*
|
||||
* 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 either the GNU General Public License or the
|
||||
* Artistic License for more details.
|
||||
*
|
||||
* You should have received a copy of the Artistic License
|
||||
* with this module, in the file ARTISTIC. If not, I'll be
|
||||
* glad to provide one.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
package HTML.Tmpl.Element;
|
||||
import java.util.Hashtable;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public abstract class Element
|
||||
{
|
||||
protected String type;
|
||||
protected String name="";
|
||||
|
||||
public abstract String parse(Hashtable params);
|
||||
public abstract String typeOfParam(String param)
|
||||
throws NoSuchElementException;
|
||||
|
||||
public void add(String data){}
|
||||
public void add(Element node){}
|
||||
|
||||
public boolean contains(String param)
|
||||
{
|
||||
try {
|
||||
return (typeOfParam(param) != null?true:false);
|
||||
} catch(NoSuchElementException nse) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public final String Type()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public final String Name()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* HTML.Template: A module for using HTML Templates with java
|
||||
*
|
||||
* Copyright (c) 2002 Philip S Tellis (philip.tellis@iname.com)
|
||||
*
|
||||
* This module is free software; you can redistribute it
|
||||
* and/or modify it under the terms of either:
|
||||
*
|
||||
* a) the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 1, or (at your option)
|
||||
* any later version, or
|
||||
*
|
||||
* b) the "Artistic License" which comes with this module.
|
||||
*
|
||||
* 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 either the GNU General Public License or the
|
||||
* Artistic License for more details.
|
||||
*
|
||||
* You should have received a copy of the Artistic License
|
||||
* with this module, in the file ARTISTIC. If not, I'll be
|
||||
* glad to provide one.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package HTML.Tmpl.Element;
|
||||
|
||||
public class If extends Conditional
|
||||
{
|
||||
public If(String control_var) throws IllegalArgumentException
|
||||
{
|
||||
super("if", control_var);
|
||||
}
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
/*
|
||||
* HTML.Template: A module for using HTML Templates with java
|
||||
*
|
||||
* Copyright (c) 2002 Philip S Tellis (philip.tellis@iname.com)
|
||||
*
|
||||
* This module is free software; you can redistribute it
|
||||
* and/or modify it under the terms of either:
|
||||
*
|
||||
* a) the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 1, or (at your option)
|
||||
* any later version, or
|
||||
*
|
||||
* b) the "Artistic License" which comes with this module.
|
||||
*
|
||||
* 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 either the GNU General Public License or the
|
||||
* Artistic License for more details.
|
||||
*
|
||||
* You should have received a copy of the Artistic License
|
||||
* with this module, in the file ARTISTIC. If not, I'll be
|
||||
* glad to provide one.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package HTML.Tmpl.Element;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Vector;
|
||||
|
||||
public class Loop extends Element
|
||||
{
|
||||
private boolean loop_context_vars=false;
|
||||
private boolean global_vars=false;
|
||||
|
||||
private Vector control_val = null;
|
||||
private Vector data;
|
||||
|
||||
public Loop(String name)
|
||||
{
|
||||
this.type = "loop";
|
||||
this.name = name;
|
||||
this.data = new Vector();
|
||||
}
|
||||
|
||||
public Loop(String name, boolean loop_context_vars)
|
||||
{
|
||||
this(name);
|
||||
this.loop_context_vars=loop_context_vars;
|
||||
}
|
||||
|
||||
public Loop(String name, boolean loop_context_vars, boolean global_vars)
|
||||
{
|
||||
this(name);
|
||||
this.loop_context_vars=loop_context_vars;
|
||||
this.global_vars=global_vars;
|
||||
}
|
||||
|
||||
public void add(String text)
|
||||
{
|
||||
data.addElement(text);
|
||||
}
|
||||
|
||||
public void add(Element node)
|
||||
{
|
||||
data.addElement(node);
|
||||
}
|
||||
|
||||
public void setControlValue(Vector control_val)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this.control_val = process_var(control_val);
|
||||
}
|
||||
|
||||
public String parse(Hashtable p)
|
||||
{
|
||||
if(!p.containsKey(this.name))
|
||||
this.control_val = null;
|
||||
else {
|
||||
Object o = p.get(this.name);
|
||||
if(!o.getClass().getName().endsWith(".Vector") &&
|
||||
!o.getClass().getName().endsWith(".List"))
|
||||
throw new ClassCastException(
|
||||
"Attempt to set <tmpl_loop> with a non-list. tmpl_loop=" + this.name);
|
||||
setControlValue((Vector)p.get(this.name));
|
||||
}
|
||||
|
||||
if(control_val == null)
|
||||
return "";
|
||||
|
||||
StringBuffer output = new StringBuffer();
|
||||
Enumeration iterator = control_val.elements();
|
||||
|
||||
boolean first=true;
|
||||
boolean last=false;
|
||||
boolean inner=false;
|
||||
boolean odd=true;
|
||||
int counter=1;
|
||||
|
||||
while(iterator.hasMoreElements()) {
|
||||
Hashtable params = (Hashtable)iterator.nextElement();
|
||||
|
||||
if(params==null)
|
||||
params = new Hashtable();
|
||||
|
||||
if(global_vars) {
|
||||
for(Enumeration e = p.keys(); e.hasMoreElements();) {
|
||||
Object key = e.nextElement();
|
||||
if(!params.containsKey(key))
|
||||
params.put(key, p.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
if(loop_context_vars) {
|
||||
if(!iterator.hasMoreElements())
|
||||
last=true;
|
||||
inner = !first && !last;
|
||||
|
||||
params.put("__FIRST__", first?"1":"");
|
||||
params.put("__LAST__", last?"1":"");
|
||||
params.put("__ODD__", odd?"1":"");
|
||||
params.put("__INNER__", inner?"1":"");
|
||||
params.put("__COUNTER__", "" + (counter++));
|
||||
}
|
||||
|
||||
Enumeration de = data.elements();
|
||||
while(de.hasMoreElements()) {
|
||||
|
||||
Object e = de.nextElement();
|
||||
if(e.getClass().getName().indexOf("String")>-1)
|
||||
output.append((String)e);
|
||||
else
|
||||
output.append(((Element)e).parse(params));
|
||||
}
|
||||
first = false;
|
||||
odd = !odd;
|
||||
}
|
||||
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
public String typeOfParam(String param)
|
||||
throws NoSuchElementException
|
||||
{
|
||||
for(Enumeration e = data.elements(); e.hasMoreElements();)
|
||||
{
|
||||
Object o = e.nextElement();
|
||||
if(o.getClass().getName().endsWith(".String"))
|
||||
continue;
|
||||
if(((Element)o).Name().equals(param))
|
||||
return ((Element)o).Type();
|
||||
}
|
||||
throw new NoSuchElementException(param);
|
||||
}
|
||||
|
||||
private Vector process_var(Vector control_val)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
String control_class = "";
|
||||
|
||||
if(control_val == null)
|
||||
return null;
|
||||
|
||||
control_class=control_val.getClass().getName();
|
||||
|
||||
if(control_class.indexOf("Vector") > -1) {
|
||||
if(control_val.isEmpty())
|
||||
return null;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unrecognised type");
|
||||
}
|
||||
|
||||
return control_val;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* HTML.Template: A module for using HTML Templates with java
|
||||
*
|
||||
* Copyright (c) 2002 Philip S Tellis (philip.tellis@iname.com)
|
||||
*
|
||||
* This module is free software; you can redistribute it
|
||||
* and/or modify it under the terms of either:
|
||||
*
|
||||
* a) the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 1, or (at your option)
|
||||
* any later version, or
|
||||
*
|
||||
* b) the "Artistic License" which comes with this module.
|
||||
*
|
||||
* 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 either the GNU General Public License or the
|
||||
* Artistic License for more details.
|
||||
*
|
||||
* You should have received a copy of the Artistic License
|
||||
* with this module, in the file ARTISTIC. If not, I'll be
|
||||
* glad to provide one.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package HTML.Tmpl.Element;
|
||||
|
||||
public class Unless extends Conditional
|
||||
{
|
||||
public Unless(String control_var) throws IllegalArgumentException
|
||||
{
|
||||
super("unless", control_var);
|
||||
}
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* HTML.Template: A module for using HTML Templates with java
|
||||
*
|
||||
* Copyright (c) 2002 Philip S Tellis (philip.tellis@iname.com)
|
||||
*
|
||||
* This module is free software; you can redistribute it
|
||||
* and/or modify it under the terms of either:
|
||||
*
|
||||
* a) the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 1, or (at your option)
|
||||
* any later version, or
|
||||
*
|
||||
* b) the "Artistic License" which comes with this module.
|
||||
*
|
||||
* 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 either the GNU General Public License or the
|
||||
* Artistic License for more details.
|
||||
*
|
||||
* You should have received a copy of the Artistic License
|
||||
* with this module, in the file ARTISTIC. If not, I'll be
|
||||
* glad to provide one.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Modified by David McNab (david@rebirthing.co.nz) to allow nesting of
|
||||
* templates (ie, passing a child Template object as a value argument
|
||||
* to a .setParam() invocation on a parent Template object).
|
||||
*/
|
||||
|
||||
package HTML.Tmpl.Element;
|
||||
import java.util.Hashtable;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import HTML.Template;
|
||||
import HTML.Tmpl.Util;
|
||||
|
||||
public class Var extends Element
|
||||
{
|
||||
public static final int ESCAPE_NONE = 0;
|
||||
public static final int ESCAPE_URL = 1;
|
||||
public static final int ESCAPE_HTML = 2;
|
||||
public static final int ESCAPE_QUOTE = 4;
|
||||
|
||||
public Var(String name, int escape, Object default_value)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this(name, escape);
|
||||
this.default_value = stringify(default_value);
|
||||
}
|
||||
|
||||
public Var(String name, int escape)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if(name == null)
|
||||
throw new IllegalArgumentException("tmpl_var must have a name");
|
||||
this.type = "var";
|
||||
this.name = name;
|
||||
this.escape = escape;
|
||||
}
|
||||
|
||||
public Var(String name, String escape)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this(name, escape, null);
|
||||
}
|
||||
|
||||
public Var(String name, String escape, Object default_value)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this(name, ESCAPE_NONE, default_value);
|
||||
|
||||
if(escape.equalsIgnoreCase("html"))
|
||||
this.escape = ESCAPE_HTML;
|
||||
else if(escape.equalsIgnoreCase("url"))
|
||||
this.escape = ESCAPE_URL;
|
||||
else if(escape.equalsIgnoreCase("quote"))
|
||||
this.escape = ESCAPE_QUOTE;
|
||||
}
|
||||
|
||||
public Var(String name, boolean escape)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this(name, escape?ESCAPE_HTML:ESCAPE_NONE);
|
||||
}
|
||||
|
||||
public String parse(Hashtable params)
|
||||
{
|
||||
String value = null;
|
||||
|
||||
if(params.containsKey(this.name))
|
||||
value = stringify(params.get(this.name));
|
||||
else
|
||||
value = this.default_value;
|
||||
|
||||
if(value == null)
|
||||
return "";
|
||||
|
||||
if(this.escape == ESCAPE_HTML)
|
||||
return Util.escapeHTML(value);
|
||||
else if(this.escape == ESCAPE_URL)
|
||||
return Util.escapeURL(value);
|
||||
else if(this.escape == ESCAPE_QUOTE)
|
||||
return Util.escapeQuote(value);
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
public String typeOfParam(String param)
|
||||
throws NoSuchElementException
|
||||
{
|
||||
throw new NoSuchElementException(param);
|
||||
}
|
||||
|
||||
private String stringify(Object o)
|
||||
{
|
||||
if(o == null)
|
||||
return null;
|
||||
|
||||
String cname = o.getClass().getName();
|
||||
if(cname.endsWith(".String"))
|
||||
return (String)o;
|
||||
else if(cname.endsWith(".Integer"))
|
||||
return ((Integer)o).toString();
|
||||
else if(cname.endsWith(".Boolean"))
|
||||
return ((Boolean)o).toString();
|
||||
else if(cname.endsWith(".Date"))
|
||||
return ((java.util.Date)o).toString();
|
||||
else if(cname.endsWith(".Vector"))
|
||||
throw new ClassCastException("Attempt to set <tmpl_var> with a non-scalar. Var name=" + this.name);
|
||||
else if(cname.endsWith(".Template"))
|
||||
return ((Template)o).output();
|
||||
else
|
||||
throw new ClassCastException("Unknown object type: " + cname);
|
||||
}
|
||||
|
||||
// Private data starts here
|
||||
private int escape=ESCAPE_NONE;
|
||||
private String default_value=null;
|
||||
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* HTML.Template: A module for using HTML Templates with java
|
||||
*
|
||||
* Copyright (c) 2002 Philip S Tellis (philip.tellis@iname.com)
|
||||
*
|
||||
* This module is free software; you can redistribute it
|
||||
* and/or modify it under the terms of either:
|
||||
*
|
||||
* a) the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 1, or (at your option)
|
||||
* any later version, or
|
||||
*
|
||||
* b) the "Artistic License" which comes with this module.
|
||||
*
|
||||
* 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 either the GNU General Public License or the
|
||||
* Artistic License for more details.
|
||||
*
|
||||
* You should have received a copy of the Artistic License
|
||||
* with this module, in the file ARTISTIC. If not, I'll be
|
||||
* glad to provide one.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
package HTML.Tmpl;
|
||||
|
||||
/**
|
||||
* Pre-parse filters for HTML.Template templates.
|
||||
* <p>
|
||||
* The HTML.Tmpl.Filter interface allows you to write Filters
|
||||
* for your templates. The filter is called after the template
|
||||
* is read and before it is parsed.
|
||||
* <p>
|
||||
* You can use a filter to make changes in the template file before
|
||||
* it is parsed by HTML.Template, so for example, use it to replace
|
||||
* constants, or to translate your own tags to HTML.Template tags.
|
||||
* <p>
|
||||
* A common usage would be to do what you think you're doing when you
|
||||
* do <code><TMPL_INCLUDE file="<TMPL_VAR name="the_file">"></code>:
|
||||
* <p>
|
||||
* myTemplate.tmpl:
|
||||
* <pre>
|
||||
* <TMPL_INCLUDE file="<%the_file%>">
|
||||
* </pre>
|
||||
* <p>
|
||||
* myFilter.java:
|
||||
* <pre>
|
||||
* class myFilter implements HTML.Tmpl.Filter
|
||||
* {
|
||||
* private String myFile;
|
||||
* private int type=SCALAR
|
||||
*
|
||||
* public myFilter(String myFile) {
|
||||
* this.myFile = myFile;
|
||||
* }
|
||||
*
|
||||
* public int format() {
|
||||
* return this.type;
|
||||
* }
|
||||
*
|
||||
* public String parse(String t) {
|
||||
* // replace all <%the_file%> with myFile
|
||||
* return t;
|
||||
* }
|
||||
*
|
||||
* public String [] parse(String [] t) {
|
||||
* throw new UnsupportedOperationException();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* myClass.java:
|
||||
* <pre>
|
||||
* Hashtable params = new Hashtable();
|
||||
* params.put("filename", "myTemplate.tmpl");
|
||||
* params.put("filter", new myFilter("myFile.tmpl"));
|
||||
* Template t = new Template(params);
|
||||
* </pre>
|
||||
*
|
||||
* @author Philip S Tellis
|
||||
* @version 0.0.1
|
||||
*/
|
||||
public interface Filter
|
||||
{
|
||||
/**
|
||||
* Tells HTML.Template to call the parse(String) method of this filter.
|
||||
*/
|
||||
public final static int SCALAR=1;
|
||||
|
||||
/**
|
||||
* Tells HTML.Template to call the parse(String []) method of this
|
||||
* filter.
|
||||
*/
|
||||
public final static int ARRAY=2;
|
||||
|
||||
/**
|
||||
* Tells HTML.Template what kind of filter this is.
|
||||
* Should return either SCALAR or ARRAY to indicate which parse method
|
||||
* must be called.
|
||||
*
|
||||
* @return the values SCALAR or ARRAY indicating which parse method
|
||||
* is to be called
|
||||
*/
|
||||
public int format();
|
||||
|
||||
/**
|
||||
* parses the template as a single string, and returns the parsed
|
||||
* template as a single string.
|
||||
* <p>
|
||||
* Should throw an UnsupportedOperationException if it isn't implemented
|
||||
*
|
||||
* @param t a string containing the entire template
|
||||
*
|
||||
* @return a string containing the template after you've parsed it
|
||||
*
|
||||
* @throws UnsupportedOperationException if this method isn't
|
||||
* implemented
|
||||
*/
|
||||
public String parse(String t);
|
||||
|
||||
/**
|
||||
* parses the template as an array of strings, and returns the parsed
|
||||
* template as an array of strings.
|
||||
* <p>
|
||||
* Should throw an UnsupportedOperationException if it isn't implemented
|
||||
*
|
||||
* @param t an array of strings containing the template - one line
|
||||
* at a time
|
||||
*
|
||||
* @return an array of strings containing the parsed template -
|
||||
* one line at a time
|
||||
*
|
||||
* @throws UnsupportedOperationException if this method isn't
|
||||
* implemented
|
||||
*/
|
||||
public String [] parse(String [] t);
|
||||
}
|
||||
|