diff --git a/apps/addressbook/README.txt b/apps/addressbook/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..dfeec5f529995979704b2f683cb01b8b59494a3d --- /dev/null +++ b/apps/addressbook/README.txt @@ -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. \ No newline at end of file diff --git a/apps/addressbook/build.xml b/apps/addressbook/build.xml new file mode 100644 index 0000000000000000000000000000000000000000..a8edbbc8f9f171559a51562c3f498a8ee5e00b82 --- /dev/null +++ b/apps/addressbook/build.xml @@ -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> diff --git a/apps/addressbook/config.txt b/apps/addressbook/config.txt new file mode 100644 index 0000000000000000000000000000000000000000..53e03127e9920ddace6d802b39bc1a9a96658641 --- /dev/null +++ b/apps/addressbook/config.txt @@ -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 diff --git a/apps/addressbook/java/src/addressbook/AddressBook.java b/apps/addressbook/java/src/addressbook/AddressBook.java new file mode 100644 index 0000000000000000000000000000000000000000..4261f2d56e1cb5613d821c8003f3c64cbc768df5 --- /dev/null +++ b/apps/addressbook/java/src/addressbook/AddressBook.java @@ -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)); + } +} \ No newline at end of file diff --git a/apps/addressbook/java/src/addressbook/ConfigParser.java b/apps/addressbook/java/src/addressbook/ConfigParser.java new file mode 100644 index 0000000000000000000000000000000000000000..7ae0aa1326cb286bb638e8d7abd214965a550602 --- /dev/null +++ b/apps/addressbook/java/src/addressbook/ConfigParser.java @@ -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))); + } +} \ No newline at end of file diff --git a/apps/addressbook/java/src/addressbook/Daemon.java b/apps/addressbook/java/src/addressbook/Daemon.java new file mode 100644 index 0000000000000000000000000000000000000000..ae1d8040f1b833609edd737f4b14dd0a2086138c --- /dev/null +++ b/apps/addressbook/java/src/addressbook/Daemon.java @@ -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) { + } + } + } +} \ No newline at end of file diff --git a/apps/addressbook/java/src/addressbook/DaemonThread.java b/apps/addressbook/java/src/addressbook/DaemonThread.java new file mode 100644 index 0000000000000000000000000000000000000000..efc3ab61d65922a3acaeda6ee649b7897463778e --- /dev/null +++ b/apps/addressbook/java/src/addressbook/DaemonThread.java @@ -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); + } +} \ No newline at end of file diff --git a/apps/addressbook/java/src/addressbook/Log.java b/apps/addressbook/java/src/addressbook/Log.java new file mode 100644 index 0000000000000000000000000000000000000000..3f9cfec382f0166f0f46ecd4db870291eab798f6 --- /dev/null +++ b/apps/addressbook/java/src/addressbook/Log.java @@ -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; + } +} \ No newline at end of file diff --git a/apps/addressbook/java/src/addressbook/Servlet.java b/apps/addressbook/java/src/addressbook/Servlet.java new file mode 100644 index 0000000000000000000000000000000000000000..4826c9ed990782f6fa8c1992b79d0a17b2a72d7b --- /dev/null +++ b/apps/addressbook/java/src/addressbook/Servlet.java @@ -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(); + } + +} \ No newline at end of file diff --git a/apps/addressbook/java/src/addressbook/Subscription.java b/apps/addressbook/java/src/addressbook/Subscription.java new file mode 100644 index 0000000000000000000000000000000000000000..1847535a965ce4aaa2235d5073873666f435584f --- /dev/null +++ b/apps/addressbook/java/src/addressbook/Subscription.java @@ -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; + } +} \ No newline at end of file diff --git a/apps/addressbook/java/src/addressbook/SubscriptionIterator.java b/apps/addressbook/java/src/addressbook/SubscriptionIterator.java new file mode 100644 index 0000000000000000000000000000000000000000..fecbb5c324feae5330e43e9f4c225cb3c1d08165 --- /dev/null +++ b/apps/addressbook/java/src/addressbook/SubscriptionIterator.java @@ -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(); + } +} \ No newline at end of file diff --git a/apps/addressbook/java/src/addressbook/SubscriptionList.java b/apps/addressbook/java/src/addressbook/SubscriptionList.java new file mode 100644 index 0000000000000000000000000000000000000000..95f51483284e8180782217654ab8603dc0e53d9f --- /dev/null +++ b/apps/addressbook/java/src/addressbook/SubscriptionList.java @@ -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) { + } + } +} \ No newline at end of file diff --git a/apps/addressbook/myhosts.txt b/apps/addressbook/myhosts.txt new file mode 100644 index 0000000000000000000000000000000000000000..680d4204bbc0cc3b1ad9be78f1144f04d18a48c0 --- /dev/null +++ b/apps/addressbook/myhosts.txt @@ -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 diff --git a/apps/addressbook/subscriptions.txt b/apps/addressbook/subscriptions.txt new file mode 100644 index 0000000000000000000000000000000000000000..62741055bda5031ab5ad79ccf391184799e4043e --- /dev/null +++ b/apps/addressbook/subscriptions.txt @@ -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 diff --git a/apps/addressbook/web.xml b/apps/addressbook/web.xml new file mode 100644 index 0000000000000000000000000000000000000000..22d0d7d23a13894066c17cd075e429cb498fda11 --- /dev/null +++ b/apps/addressbook/web.xml @@ -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> \ No newline at end of file