imported ragnarok's MIT licensed addressbook-2.0.2
This commit is contained in:
32
apps/addressbook/README.txt
Normal file
32
apps/addressbook/README.txt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
addressbook v2.0.2 - A simple name resolution mechanism for I2P
|
||||||
|
|
||||||
|
addressbook is a simple implementation of subscribable address books for I2P.
|
||||||
|
Addresses are stored in userhosts.txt and a second copy of the address book is
|
||||||
|
placed on your eepsite as hosts.txt.
|
||||||
|
|
||||||
|
subscriptions.txt contains a list of urls to check for new addresses.
|
||||||
|
Since the urls are checked in order, and conflicting addresses are not added,
|
||||||
|
addressbook.subscriptions can be considered to be ranked in order of trust.
|
||||||
|
|
||||||
|
The system created by addressbook is similar to the early days of DNS,
|
||||||
|
when everyone ran a local name server. The major difference is the lack of
|
||||||
|
authority. Name cannot be guaranteed to be globally unique, but in practise
|
||||||
|
they probably will be, for a variety of social reasons.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
************
|
||||||
|
|
||||||
|
i2p with a running http proxy
|
||||||
|
|
||||||
|
Installation and Usage
|
||||||
|
**********************
|
||||||
|
|
||||||
|
1. Unzip addressbook-%ver.zip into your i2p directory.
|
||||||
|
2. Restart your router.
|
||||||
|
|
||||||
|
The addressbook daemon will automatically run while the router is up.
|
||||||
|
|
||||||
|
Aside from the daemon itself, the other elements of the addressbook interface
|
||||||
|
are the config.txt, myhosts.txt, and subscriptions.txt files found in the addressbook
|
||||||
|
directory. Those files are largely self-documenting, so if you want to know what they
|
||||||
|
do, just read them.
|
46
apps/addressbook/build.xml
Normal file
46
apps/addressbook/build.xml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project name="addressbook" default="war" basedir=".">
|
||||||
|
|
||||||
|
<property name="src" value="java/src/addressbook"/>
|
||||||
|
<property name="build" value="build"/>
|
||||||
|
<property name="dist" location="dist"/>
|
||||||
|
<property name="jar" value="addressbook.jar"/>
|
||||||
|
<property name="war" value="addressbook.war"/>
|
||||||
|
<property name="servlet" value="../jetty/jettylib/javax.servlet.jar"/>
|
||||||
|
|
||||||
|
<target name="init">
|
||||||
|
<mkdir dir="${build}"/>
|
||||||
|
<mkdir dir="${dist}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="clean">
|
||||||
|
<delete dir="${build}"/>
|
||||||
|
<delete dir="${dist}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="distclean" depends="clean" />
|
||||||
|
|
||||||
|
<target name="compile" depends="init">
|
||||||
|
<javac srcdir="${src}" destdir="${build}" classpath="${servlet}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="jar" depends="compile">
|
||||||
|
<jar basedir="${build}" destfile="${dist}/${jar}">
|
||||||
|
<manifest>
|
||||||
|
<attribute name="Main-Class" value="addressbook.Daemon"/>
|
||||||
|
</manifest>
|
||||||
|
</jar>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="war" depends="compile">
|
||||||
|
<mkdir dir="${dist}/tmp"/>
|
||||||
|
<mkdir dir="${dist}/tmp/WEB-INF"/>
|
||||||
|
<mkdir dir="${dist}/tmp/WEB-INF/classes"/>
|
||||||
|
<copy todir="${dist}/tmp/WEB-INF/classes">
|
||||||
|
<fileset dir="${build}"/>
|
||||||
|
</copy>
|
||||||
|
<war basedir="${dist}/tmp" webxml="web.xml" destfile="${dist}/${war}"/>
|
||||||
|
<delete dir="${dist}/tmp"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
</project>
|
43
apps/addressbook/config.txt
Normal file
43
apps/addressbook/config.txt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# This is the configuration file for addressbook.
|
||||||
|
#
|
||||||
|
# Options
|
||||||
|
# *******
|
||||||
|
# All paths are realitive to i2p/addressbook. Default value for
|
||||||
|
# each option is given in parentheses.
|
||||||
|
#
|
||||||
|
# proxy_host The hostname of your I2P http proxy.
|
||||||
|
# (localhost)
|
||||||
|
#
|
||||||
|
# proxy_port The port of your I2P http proxy. (4444)
|
||||||
|
#
|
||||||
|
# master_addressbook The path to your master address book, used for local
|
||||||
|
# changes only. (myhosts.txt)
|
||||||
|
#
|
||||||
|
# router_addressbook The path to the address book used by the router.
|
||||||
|
# Contains the addresses from your master address book
|
||||||
|
# and your subscribed address books. (../userhosts.txt)
|
||||||
|
#
|
||||||
|
# published_addressbook The path to the copy of your address book made
|
||||||
|
# available on i2p. (../eepsite/docroot/hosts.txt)
|
||||||
|
#
|
||||||
|
# log The path to your addressbook log. (log.txt)
|
||||||
|
#
|
||||||
|
# subscriptions The path to your subscription file. (subscriptions.txt)
|
||||||
|
#
|
||||||
|
# etags The path to the etags header storage file. (etags)
|
||||||
|
#
|
||||||
|
# last_modified The path to the last-modified header storage file.
|
||||||
|
# (last_modified)
|
||||||
|
#
|
||||||
|
# update_delay The time (in hours) between each update. (1)
|
||||||
|
|
||||||
|
proxy_host=localhost
|
||||||
|
proxy_port=4444
|
||||||
|
master_addressbook=myhosts.txt
|
||||||
|
router_addressbook=../userhosts.txt
|
||||||
|
published_addressbook=../eepsite/docroot/hosts.txt
|
||||||
|
log=log.txt
|
||||||
|
subscriptions=subscriptions.txt
|
||||||
|
etags=etags
|
||||||
|
last_modified=last_modified
|
||||||
|
update_delay=1
|
246
apps/addressbook/java/src/addressbook/AddressBook.java
Normal file
246
apps/addressbook/java/src/addressbook/AddressBook.java
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An address book for storing human readable names mapped to base64 i2p
|
||||||
|
* destinations. AddressBooks can be created from local and remote files, merged
|
||||||
|
* together, and written out to local files.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AddressBook {
|
||||||
|
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
private Map addresses;
|
||||||
|
|
||||||
|
private boolean modified;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an AddressBook from the contents of the Map addresses.
|
||||||
|
*
|
||||||
|
* @param addresses
|
||||||
|
* A Map containing human readable addresses as keys, mapped to
|
||||||
|
* base64 i2p destinations.
|
||||||
|
*/
|
||||||
|
public AddressBook(Map addresses) {
|
||||||
|
this.addresses = addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an AddressBook from the contents of the file at url. If the
|
||||||
|
* remote file cannot be read, construct an empty AddressBook
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* A URL pointing at a file with lines in the format "key=value",
|
||||||
|
* where key is a human readable name, and value is a base64 i2p
|
||||||
|
* destination.
|
||||||
|
*/
|
||||||
|
public AddressBook(URL url) {
|
||||||
|
this.location = url.getHost();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.addresses = ConfigParser.parse(url);
|
||||||
|
} catch (IOException exp) {
|
||||||
|
this.addresses = new HashMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an AddressBook from the Subscription subscription. If the
|
||||||
|
* address book at subscription has not changed since the last time it was
|
||||||
|
* read or cannot be read, return an empty AddressBook.
|
||||||
|
*
|
||||||
|
* @param subscription
|
||||||
|
* A Subscription instance pointing at a remote address book.
|
||||||
|
*/
|
||||||
|
public AddressBook(Subscription subscription) {
|
||||||
|
this.location = subscription.getLocation();
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL(subscription.getLocation());
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url
|
||||||
|
.openConnection();
|
||||||
|
if (subscription.getEtag() != null) {
|
||||||
|
connection.addRequestProperty("If-None-Match", subscription
|
||||||
|
.getEtag());
|
||||||
|
}
|
||||||
|
if (subscription.getLastModified() != null) {
|
||||||
|
connection.addRequestProperty("If-Modified-Since", subscription
|
||||||
|
.getLastModified());
|
||||||
|
}
|
||||||
|
connection.connect();
|
||||||
|
if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
|
||||||
|
connection.disconnect();
|
||||||
|
this.addresses = new HashMap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (connection.getHeaderField("ETag") != null) {
|
||||||
|
subscription.setEtag(connection.getHeaderField("ETag"));
|
||||||
|
}
|
||||||
|
if (connection.getHeaderField("Last-Modified") != null) {
|
||||||
|
subscription.setLastModified(connection
|
||||||
|
.getHeaderField("Last-Modified"));
|
||||||
|
}
|
||||||
|
} catch (IOException exp) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.addresses = ConfigParser.parse(new URL(subscription
|
||||||
|
.getLocation()));
|
||||||
|
} catch (IOException exp) {
|
||||||
|
this.addresses = new HashMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an AddressBook from the contents of the file at file. If the
|
||||||
|
* file cannot be read, construct an empty AddressBook
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* A File pointing at a file with lines in the format
|
||||||
|
* "key=value", where key is a human readable name, and value is
|
||||||
|
* a base64 i2p destination.
|
||||||
|
*/
|
||||||
|
public AddressBook(File file) {
|
||||||
|
this.location = file.toString();
|
||||||
|
try {
|
||||||
|
this.addresses = ConfigParser.parse(file);
|
||||||
|
} catch (IOException exp) {
|
||||||
|
this.addresses = new HashMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a Map containing the addresses in the AddressBook.
|
||||||
|
*
|
||||||
|
* @return A Map containing the addresses in the AddressBook, where the key
|
||||||
|
* is a human readable name, and the value is a base64 i2p
|
||||||
|
* destination.
|
||||||
|
*/
|
||||||
|
public Map getAddresses() {
|
||||||
|
return this.addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the location of the file this AddressBook was constructed from.
|
||||||
|
*
|
||||||
|
* @return A String representing either an abstract path, or a url,
|
||||||
|
* depending on how the instance was constructed.
|
||||||
|
*/
|
||||||
|
public String getLocation() {
|
||||||
|
return this.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a string representation of the contents of the AddressBook.
|
||||||
|
*
|
||||||
|
* @return A String representing the contents of the AddressBook.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return this.addresses.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge this AddressBook with AddressBook other, writing messages about new
|
||||||
|
* addresses or conflicts to log. Addresses in AddressBook other that are
|
||||||
|
* not in this AddressBook are added to this AddressBook. In case of a
|
||||||
|
* conflict, addresses in this AddressBook take precedence
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* An AddressBook to merge with.
|
||||||
|
* @param log
|
||||||
|
* The log to write messages about new addresses or conflicts to.
|
||||||
|
*/
|
||||||
|
public void merge(AddressBook other, Log log) {
|
||||||
|
Iterator otherIter = other.addresses.keySet().iterator();
|
||||||
|
|
||||||
|
while (otherIter.hasNext()) {
|
||||||
|
String otherKey = (String) otherIter.next();
|
||||||
|
String otherValue = (String) other.addresses.get(otherKey);
|
||||||
|
|
||||||
|
if (otherValue.length() >= 516) {
|
||||||
|
if (this.addresses.containsKey(otherKey)) {
|
||||||
|
if (!this.addresses.get(otherKey).equals(otherValue)
|
||||||
|
&& log != null) {
|
||||||
|
log.append("Conflict for " + otherKey + " from "
|
||||||
|
+ other.location
|
||||||
|
+ ". Destination in remote address book is "
|
||||||
|
+ otherValue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.addresses.put(otherKey, otherValue);
|
||||||
|
this.modified = true;
|
||||||
|
if (log != null) {
|
||||||
|
log.append("New address " + otherKey
|
||||||
|
+ " added to address book.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge this AddressBook with other, without logging.
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* An AddressBook to merge with.
|
||||||
|
*/
|
||||||
|
public void merge(AddressBook other) {
|
||||||
|
this.merge(other, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the contents of this AddressBook out to the File file. If the file
|
||||||
|
* cannot be writen to, this method will silently fail.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* The file to write the contents of this AddressBook too.
|
||||||
|
*/
|
||||||
|
public void write(File file) {
|
||||||
|
if (this.modified) {
|
||||||
|
try {
|
||||||
|
ConfigParser.write(this.addresses, file);
|
||||||
|
} catch (IOException exp) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write this AddressBook out to the file it was read from. Requires that
|
||||||
|
* AddressBook was constructed from a file on the local filesystem. If the
|
||||||
|
* file cannot be writen to, this method will silently fail.
|
||||||
|
*/
|
||||||
|
public void write() {
|
||||||
|
this.write(new File(this.location));
|
||||||
|
}
|
||||||
|
}
|
188
apps/addressbook/java/src/addressbook/ConfigParser.java
Normal file
188
apps/addressbook/java/src/addressbook/ConfigParser.java
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class providing methods to parse and write files in config file
|
||||||
|
* format, and subscription file format.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*/
|
||||||
|
public class ConfigParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip the comments from a String. Lines that begin with '#' and ';' are
|
||||||
|
* considered comments, as well as any part of a line after a '#'.
|
||||||
|
*
|
||||||
|
* @param inputLine
|
||||||
|
* A String to strip comments from.
|
||||||
|
* @return A String without comments, but otherwise identical to inputLine.
|
||||||
|
*/
|
||||||
|
public static String stripComments(String inputLine) {
|
||||||
|
if (inputLine.startsWith(";")) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (inputLine.split("#").length > 0) {
|
||||||
|
return inputLine.split("#")[0];
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a Map using the contents of BufferedReader input. input must have
|
||||||
|
* a single key, value pair on each line, in the format: key=value. Lines
|
||||||
|
* starting with '#' or ';' are considered comments, and ignored. Lines that
|
||||||
|
* are obviously not in the format key=value are also ignored.
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
* A BufferedReader with lines in key=value format to parse into
|
||||||
|
* a Map.
|
||||||
|
* @return A Map containing the key, value pairs from input.
|
||||||
|
* @throws IOException
|
||||||
|
* if the BufferedReader cannot be read.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static Map parse(BufferedReader input) throws IOException {
|
||||||
|
Map result = new HashMap();
|
||||||
|
String inputLine;
|
||||||
|
inputLine = input.readLine();
|
||||||
|
while (inputLine != null) {
|
||||||
|
inputLine = ConfigParser.stripComments(inputLine);
|
||||||
|
String[] splitLine = inputLine.split("=");
|
||||||
|
if (splitLine.length == 2) {
|
||||||
|
result.put(splitLine[0].trim(), splitLine[1].trim());
|
||||||
|
}
|
||||||
|
inputLine = input.readLine();
|
||||||
|
}
|
||||||
|
input.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a Map using the contents of the file at url. See
|
||||||
|
* parseBufferedReader for details of the input format.
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* A url pointing to a file to parse.
|
||||||
|
* @return A Map containing the key, value pairs from url.
|
||||||
|
* @throws IOException
|
||||||
|
* if url cannot be read.
|
||||||
|
*/
|
||||||
|
public static Map parse(URL url) throws IOException {
|
||||||
|
InputStream urlStream;
|
||||||
|
urlStream = url.openConnection().getInputStream();
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(urlStream));
|
||||||
|
return ConfigParser.parse(br);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a Map using the contents of the File file. See parseBufferedReader
|
||||||
|
* for details of the input format.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* A File to parse.
|
||||||
|
* @return A Map containing the key, value pairs from file.
|
||||||
|
* @throws IOException
|
||||||
|
* if file cannot be read.
|
||||||
|
*/
|
||||||
|
public static Map parse(File file) throws IOException {
|
||||||
|
FileInputStream fileStream;
|
||||||
|
fileStream = new FileInputStream(file);
|
||||||
|
BufferedReader br = new BufferedReader(
|
||||||
|
new InputStreamReader(fileStream));
|
||||||
|
return ConfigParser.parse(br);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a List where each element is a line from the File file.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* A File to parse.
|
||||||
|
* @return A List consisting of one element for each line in file.
|
||||||
|
* @throws IOException
|
||||||
|
* if file cannot be read.
|
||||||
|
*/
|
||||||
|
public static List parseSubscriptions(File file) throws IOException {
|
||||||
|
FileInputStream fileStream = new FileInputStream(file);
|
||||||
|
BufferedReader br = new BufferedReader(
|
||||||
|
new InputStreamReader(fileStream));
|
||||||
|
List result = new LinkedList();
|
||||||
|
String inputLine = br.readLine();
|
||||||
|
while (inputLine != null) {
|
||||||
|
inputLine = ConfigParser.stripComments(inputLine);
|
||||||
|
if (inputLine.trim().length() > 0) {
|
||||||
|
result.add(inputLine.trim());
|
||||||
|
}
|
||||||
|
inputLine = br.readLine();
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write contents of Map hash to BufferedWriter output. Output is written
|
||||||
|
* with one key, value pair on each line, in the format: key=value.
|
||||||
|
*
|
||||||
|
* @param hash
|
||||||
|
* A Map to write to output.
|
||||||
|
* @param output
|
||||||
|
* A BufferedWriter to write the Map to.
|
||||||
|
* @throws IOException
|
||||||
|
* if the BufferedWriter cannot be written to.
|
||||||
|
*/
|
||||||
|
public static void write(Map hash, BufferedWriter output)
|
||||||
|
throws IOException {
|
||||||
|
Iterator keyIter = hash.keySet().iterator();
|
||||||
|
|
||||||
|
while (keyIter.hasNext()) {
|
||||||
|
String key = (String) keyIter.next();
|
||||||
|
output.write(key + "=" + (String) hash.get(key));
|
||||||
|
output.newLine();
|
||||||
|
}
|
||||||
|
output.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write contents of Map hash to the file at location. Output is written
|
||||||
|
* with one key, value pair on each line, in the format: key=value.
|
||||||
|
*
|
||||||
|
* @param hash
|
||||||
|
* A Map to write to file.
|
||||||
|
* @param file
|
||||||
|
* A File to write the Map to.
|
||||||
|
* @throws IOException
|
||||||
|
* if file cannot be written to.
|
||||||
|
*/
|
||||||
|
public static void write(Map hash, File file) throws IOException {
|
||||||
|
ConfigParser.write(hash,
|
||||||
|
new BufferedWriter(new FileWriter(file, false)));
|
||||||
|
}
|
||||||
|
}
|
143
apps/addressbook/java/src/addressbook/Daemon.java
Normal file
143
apps/addressbook/java/src/addressbook/Daemon.java
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main class of addressbook. Performs updates, and runs the main loop.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Daemon {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the router and published address books using remote data from the
|
||||||
|
* subscribed address books listed in subscriptions.
|
||||||
|
*
|
||||||
|
* @param master
|
||||||
|
* The master AddressBook. This address book is never
|
||||||
|
* overwritten, so it is safe for the user to write to.
|
||||||
|
* @param router
|
||||||
|
* The router AddressBook. This is the address book read by
|
||||||
|
* client applications.
|
||||||
|
* @param published
|
||||||
|
* The published AddressBook. This address book is published on
|
||||||
|
* the user's eepsite so that others may subscribe to it.
|
||||||
|
* @param subscriptions
|
||||||
|
* A SubscriptionList listing the remote address books to update
|
||||||
|
* from.
|
||||||
|
* @param log
|
||||||
|
* The log to write changes and conflicts to.
|
||||||
|
*/
|
||||||
|
public static void update(AddressBook master, AddressBook router,
|
||||||
|
File published, SubscriptionList subscriptions, Log log) {
|
||||||
|
String routerLocation = router.getLocation();
|
||||||
|
master.merge(router);
|
||||||
|
Iterator iter = subscriptions.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
master.merge((AddressBook) iter.next(), log);
|
||||||
|
}
|
||||||
|
master.write(new File(routerLocation));
|
||||||
|
master.write(published);
|
||||||
|
subscriptions.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run an update, using the Map settings to provide the parameters.
|
||||||
|
*
|
||||||
|
* @param settings
|
||||||
|
* A Map containg the parameters needed by update.
|
||||||
|
* @param home
|
||||||
|
* The directory containing addressbook's configuration files.
|
||||||
|
*/
|
||||||
|
public static void update(Map settings, String home) {
|
||||||
|
File masterFile = new File(home, (String) settings
|
||||||
|
.get("master_addressbook"));
|
||||||
|
File routerFile = new File(home, (String) settings
|
||||||
|
.get("router_addressbook"));
|
||||||
|
File published = new File(home, (String) settings
|
||||||
|
.get("published_addressbook"));
|
||||||
|
File subscriptionFile = new File(home, (String) settings
|
||||||
|
.get("subscriptions"));
|
||||||
|
File logFile = new File(home, (String) settings.get("log"));
|
||||||
|
File etagsFile = new File(home, (String) settings.get("etags"));
|
||||||
|
File lastModifiedFile = new File(home, (String) settings
|
||||||
|
.get("last_modified"));
|
||||||
|
|
||||||
|
AddressBook master = new AddressBook(masterFile);
|
||||||
|
AddressBook router = new AddressBook(routerFile);
|
||||||
|
SubscriptionList subscriptions = new SubscriptionList(subscriptionFile,
|
||||||
|
etagsFile, lastModifiedFile);
|
||||||
|
Log log = new Log(logFile);
|
||||||
|
|
||||||
|
Daemon.update(master, router, published, subscriptions, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the settings, set the proxy, then enter into the main loop. The main
|
||||||
|
* loop performs an immediate update, and then an update every number of
|
||||||
|
* hours, as configured in the settings file.
|
||||||
|
*
|
||||||
|
* @param args
|
||||||
|
* Command line arguments. If there are any arguments provided,
|
||||||
|
* the first is taken as addressbook's home directory, and the
|
||||||
|
* others are ignored.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String settingsLocation = "config.txt";
|
||||||
|
Map settings = new HashMap();
|
||||||
|
String home;
|
||||||
|
if (args.length > 0) {
|
||||||
|
home = args[0];
|
||||||
|
} else {
|
||||||
|
home = ".";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
settings = ConfigParser.parse(new File(home, settingsLocation));
|
||||||
|
} catch (IOException exp) {
|
||||||
|
System.out.println("Could not load " + settingsLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.setProperty("proxySet", "true");
|
||||||
|
System.setProperty("http.proxyHost", (String) settings
|
||||||
|
.get("proxy_host"));
|
||||||
|
System.setProperty("http.proxyPort", (String) settings
|
||||||
|
.get("proxy_port"));
|
||||||
|
long delay = Long.parseLong((String) settings.get("update_delay"));
|
||||||
|
if (delay < 1) {
|
||||||
|
delay = 1;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
Daemon.update(settings, home);
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay * 60 * 60 * 1000);
|
||||||
|
} catch (InterruptedException exp) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
apps/addressbook/java/src/addressbook/DaemonThread.java
Normal file
53
apps/addressbook/java/src/addressbook/DaemonThread.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A thread that waits five minutes, then runs the addressbook daemon.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DaemonThread extends Thread {
|
||||||
|
|
||||||
|
private String[] args;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a DaemonThread with the command line arguments args.
|
||||||
|
* @param args
|
||||||
|
* A String array to pass to Daemon.main().
|
||||||
|
*/
|
||||||
|
public DaemonThread(String[] args) {
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Runnable#run()
|
||||||
|
*/
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(5 * 60 * 1000);
|
||||||
|
} catch (InterruptedException exp) {
|
||||||
|
}
|
||||||
|
Daemon.main(this.args);
|
||||||
|
}
|
||||||
|
}
|
76
apps/addressbook/java/src/addressbook/Log.java
Normal file
76
apps/addressbook/java/src/addressbook/Log.java
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple log with automatic time stamping.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Log {
|
||||||
|
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a Log instance that writes to the File file.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* A File for the log to write to.
|
||||||
|
*/
|
||||||
|
public Log(File file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write entry to a new line in the log, with appropriate time stamp.
|
||||||
|
*
|
||||||
|
* @param entry
|
||||||
|
* A String containing a message to append to the log.
|
||||||
|
*/
|
||||||
|
public void append(String entry) {
|
||||||
|
try {
|
||||||
|
BufferedWriter bw = new BufferedWriter(new FileWriter(this.file,
|
||||||
|
true));
|
||||||
|
String timestamp = new Date().toString();
|
||||||
|
bw.write(timestamp + " -- " + entry);
|
||||||
|
bw.newLine();
|
||||||
|
bw.close();
|
||||||
|
} catch (IOException exp) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the File that the Log is writing to.
|
||||||
|
*
|
||||||
|
* @return The File that the log is writing to.
|
||||||
|
*/
|
||||||
|
public File getFile() {
|
||||||
|
return this.file;
|
||||||
|
}
|
||||||
|
}
|
58
apps/addressbook/java/src/addressbook/Servlet.java
Normal file
58
apps/addressbook/java/src/addressbook/Servlet.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
import javax.servlet.GenericServlet;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.ServletConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper for addressbook to allow it to be started as a web application.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Servlet extends GenericServlet {
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||||
|
*/
|
||||||
|
public void service(ServletRequest request, ServletResponse response) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
|
||||||
|
*/
|
||||||
|
public void init(ServletConfig config) {
|
||||||
|
try {
|
||||||
|
super.init(config);
|
||||||
|
} catch (ServletException exp) {
|
||||||
|
}
|
||||||
|
String[] args = new String[1];
|
||||||
|
args[0] = config.getInitParameter("home");
|
||||||
|
DaemonThread thread = new DaemonThread(args);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
apps/addressbook/java/src/addressbook/Subscription.java
Normal file
105
apps/addressbook/java/src/addressbook/Subscription.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A subscription to a remote address book.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Subscription {
|
||||||
|
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
private String etag;
|
||||||
|
|
||||||
|
private String lastModified;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a Subscription pointing to the address book at location, that
|
||||||
|
* was last read at the time represented by etag and lastModified.
|
||||||
|
*
|
||||||
|
* @param location
|
||||||
|
* A String representing a url to a remote address book.
|
||||||
|
* @param etag
|
||||||
|
* The etag header that we recieved the last time we read this
|
||||||
|
* subscription.
|
||||||
|
* @param lastModified
|
||||||
|
* the last-modified header we recieved the last time we read
|
||||||
|
* this subscription.
|
||||||
|
*/
|
||||||
|
public Subscription(String location, String etag, String lastModified) {
|
||||||
|
this.location = location;
|
||||||
|
this.etag = etag;
|
||||||
|
this.lastModified = lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the location this Subscription points at.
|
||||||
|
*
|
||||||
|
* @return A String representing a url to a remote address book.
|
||||||
|
*/
|
||||||
|
public String getLocation() {
|
||||||
|
return this.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the etag header that we recieved the last time we read this
|
||||||
|
* subscription.
|
||||||
|
*
|
||||||
|
* @return A String containing the etag header.
|
||||||
|
*/
|
||||||
|
public String getEtag() {
|
||||||
|
return this.etag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the etag header.
|
||||||
|
*
|
||||||
|
* @param etag
|
||||||
|
* A String containing the etag header.
|
||||||
|
*/
|
||||||
|
public void setEtag(String etag) {
|
||||||
|
this.etag = etag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the last-modified header that we recieved the last time we read
|
||||||
|
* this subscription.
|
||||||
|
*
|
||||||
|
* @return A String containing the last-modified header.
|
||||||
|
*/
|
||||||
|
public String getLastModified() {
|
||||||
|
return this.lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the last-modified header.
|
||||||
|
*
|
||||||
|
* @param lastModified
|
||||||
|
* A String containing the last-modified header.
|
||||||
|
*/
|
||||||
|
public void setLastModified(String lastModified) {
|
||||||
|
this.lastModified = lastModified;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An iterator over the subscriptions in a SubscriptionList. Note that this iterator
|
||||||
|
* returns AddressBook objects, and not Subscription objects.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*/
|
||||||
|
public class SubscriptionIterator implements Iterator {
|
||||||
|
|
||||||
|
private Iterator subIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a SubscriptionIterator using the Subscriprions in List subscriptions.
|
||||||
|
*
|
||||||
|
* @param subscriptions
|
||||||
|
* List of Subscription objects that represent address books.
|
||||||
|
*/
|
||||||
|
public SubscriptionIterator(List subscriptions) {
|
||||||
|
this.subIterator = subscriptions.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.util.Iterator#hasNext()
|
||||||
|
*/
|
||||||
|
public boolean hasNext() {
|
||||||
|
return subIterator.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.util.Iterator#next()
|
||||||
|
*/
|
||||||
|
public Object next() {
|
||||||
|
Subscription sub = (Subscription) subIterator.next();
|
||||||
|
return new AddressBook(sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.util.Iterator#remove()
|
||||||
|
*/
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
127
apps/addressbook/java/src/addressbook/SubscriptionList.java
Normal file
127
apps/addressbook/java/src/addressbook/SubscriptionList.java
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ragnarok
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package addressbook;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of Subscriptions loaded from a file.
|
||||||
|
*
|
||||||
|
* @author Ragnarok
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SubscriptionList {
|
||||||
|
|
||||||
|
private List subscriptions;
|
||||||
|
|
||||||
|
private File etagsFile;
|
||||||
|
|
||||||
|
private File lastModifiedFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a SubscriptionList using the urls from locationsFile and, if
|
||||||
|
* available, the etags and last-modified headers loaded from etagsFile and
|
||||||
|
* lastModifiedFile.
|
||||||
|
*
|
||||||
|
* @param locationsFile
|
||||||
|
* A file containing one url on each line.
|
||||||
|
* @param etagsFile
|
||||||
|
* A file containg the etag headers used for conditional GET. The
|
||||||
|
* file is in the format "url=etag".
|
||||||
|
* @param lastModifiedFile
|
||||||
|
* A file containg the last-modified headers used for conditional
|
||||||
|
* GET. The file is in the format "url=leastmodified".
|
||||||
|
*/
|
||||||
|
public SubscriptionList(File locationsFile, File etagsFile,
|
||||||
|
File lastModifiedFile) {
|
||||||
|
this.subscriptions = new LinkedList();
|
||||||
|
this.etagsFile = etagsFile;
|
||||||
|
this.lastModifiedFile = lastModifiedFile;
|
||||||
|
List locations;
|
||||||
|
Map etags;
|
||||||
|
Map lastModified;
|
||||||
|
String location;
|
||||||
|
try {
|
||||||
|
locations = ConfigParser.parseSubscriptions(locationsFile);
|
||||||
|
} catch (IOException exp) {
|
||||||
|
locations = new LinkedList();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
etags = ConfigParser.parse(etagsFile);
|
||||||
|
} catch (IOException exp) {
|
||||||
|
etags = new HashMap();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
lastModified = ConfigParser.parse(lastModifiedFile);
|
||||||
|
} catch (IOException exp) {
|
||||||
|
lastModified = new HashMap();
|
||||||
|
}
|
||||||
|
Iterator iter = locations.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
location = (String) iter.next();
|
||||||
|
subscriptions.add(new Subscription(location, (String) etags
|
||||||
|
.get(location), (String) lastModified.get(location)));
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = this.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an iterator over the AddressBooks represented by the Subscriptions
|
||||||
|
* in this SubscriptionList.
|
||||||
|
*
|
||||||
|
* @return A SubscriptionIterator.
|
||||||
|
*/
|
||||||
|
public SubscriptionIterator iterator() {
|
||||||
|
return new SubscriptionIterator(this.subscriptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the etag and last-modified headers for each Subscription to files.
|
||||||
|
*/
|
||||||
|
public void write() {
|
||||||
|
Iterator iter = this.subscriptions.iterator();
|
||||||
|
Subscription sub;
|
||||||
|
Map etags = new HashMap();
|
||||||
|
Map lastModified = new HashMap();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
sub = (Subscription) iter.next();
|
||||||
|
if (sub.getEtag() != null) {
|
||||||
|
etags.put(sub.getLocation(), sub.getEtag());
|
||||||
|
}
|
||||||
|
if (sub.getLastModified() != null) {
|
||||||
|
lastModified.put(sub.getLocation(), sub.getLastModified());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ConfigParser.write(etags, this.etagsFile);
|
||||||
|
ConfigParser.write(lastModified, this.lastModifiedFile);
|
||||||
|
} catch (IOException exp) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
apps/addressbook/myhosts.txt
Normal file
10
apps/addressbook/myhosts.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# addressbook master address book. Addresses placed in this file take precidence
|
||||||
|
# over those in the router address book and in remote address books. If changes
|
||||||
|
# are made to this file, they will be reflected in the router address book and
|
||||||
|
# published address book after the next update.
|
||||||
|
#
|
||||||
|
# Do not make changes directly to the router address book, as they could be lost
|
||||||
|
# during an update.
|
||||||
|
#
|
||||||
|
# This file takes addresses in the hosts.txt format, i.e.
|
||||||
|
# example.i2p=somereallylongbase64thingAAAA
|
7
apps/addressbook/subscriptions.txt
Normal file
7
apps/addressbook/subscriptions.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Subscription list for addressbook
|
||||||
|
#
|
||||||
|
# Each entry is an absolute url to a file in hosts.txt format.
|
||||||
|
# Since the list is checked in order, url's should be listed in order of trust.
|
||||||
|
#
|
||||||
|
http://dev.i2p/i2p/hosts.txt
|
||||||
|
http://duck.i2p/hosts.txt
|
16
apps/addressbook/web.xml
Normal file
16
apps/addressbook/web.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE web-app
|
||||||
|
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
|
||||||
|
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
|
||||||
|
|
||||||
|
<web-app>
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>addressbook</servlet-name>
|
||||||
|
<servlet-class>addressbook.Servlet</servlet-class>
|
||||||
|
<init-param>
|
||||||
|
<param-name>home</param-name>
|
||||||
|
<param-value>./addressbook</param-value>
|
||||||
|
</init-param>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
</web-app>
|
Reference in New Issue
Block a user