summaryrefslogtreecommitdiff
path: root/src/org/noreply/fancydress/directory
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/noreply/fancydress/directory')
-rw-r--r--src/org/noreply/fancydress/directory/Directory.java230
-rw-r--r--src/org/noreply/fancydress/directory/IncomingMMTPSection.java14
-rw-r--r--src/org/noreply/fancydress/directory/Server.java64
-rw-r--r--src/org/noreply/fancydress/directory/ServerDescriptor.java72
4 files changed, 308 insertions, 72 deletions
diff --git a/src/org/noreply/fancydress/directory/Directory.java b/src/org/noreply/fancydress/directory/Directory.java
index f2eda8c..ff0cfdf 100644
--- a/src/org/noreply/fancydress/directory/Directory.java
+++ b/src/org/noreply/fancydress/directory/Directory.java
@@ -25,6 +25,12 @@ import java.util.*;
*/
public class Directory {
/**
+ * directory version we understand.
+ */
+
+ private static final String DIRECTORY_VERSION = "0.2";
+
+ /**
* Hash holding all Servers.
*
* This hash holds all Servers. Since nickname are to be treaded case
@@ -37,35 +43,27 @@ public class Directory {
private Hashtable byName;
/**
- * Possibly add a new server descriptor to the directory.
+ * Useable servers.
*
- * This method adds a server desccriptor to the directory if it
- * - conforms to the syntax specified.
- * - the server is not yet known or it's identity key matches the key of the already known ServerDescriptor.
+ * A server is useable if it understands PacketVersions that we understand
+ * and has a serverdescriptor that is useable right now.
+ */
+ private Server[] useableServers;
+
+ /**
+ * Recommended servers.
+ */
+ private Server[] recommendedServers;
+
+ /*
+ * matrix of friends.
*
- * @param server a DirectoryMessage consisting of one of more sections. At 'Server' section needs to be present.
- * @throws Mix3BadServerFormatException if a section is syntactially invalid and the error cannot be ignored.
- * @throws Mix3BadServerSignatureException if the server descriptor's signature is invalid.
+ * (a, b) are friends, if a can send messages to b.
*/
- private void addServerDescriptor(DirectoryMessage server) throws Mix3BadServerFormatException, Mix3BadServerSignatureException {
- try {
- ServerDescriptor sd = new ServerDescriptor(server);
- String key = sd.getNickname().toLowerCase();
- if (byName.containsKey(key)) {
- Server s = (Server) byName.get(key);
- try {
- s.addDescriptor(sd);
- } catch (Mix3BadServerFormatException e) {
- System.err.println("Ignoring Descriptor with different identity for "+key);
- }
- } else {
- Server s = new Server(sd);
- byName.put(key, s);
- }
- } catch (Mix3BadServerUnrecognizedVersionException e) {
- System.err.println("Ignoring unregonized version");
- }
- }
+ /*
+ private boolean[][] friends;
+ */
+
/**
* Create a directory from an entire DirectoryMessage.
@@ -82,11 +80,87 @@ public class Directory {
*/
public Directory(DirectoryMessage m, boolean checkDirectorySignature) throws
Mix3BadDirectorySignatureException,
+ Mix3BadDirectoryFormatException,
Mix3BadServerFormatException,
Mix3BadServerSignatureException
{
byName = new Hashtable();
+
+ parseDirectory(m, checkDirectorySignature);
+
+
+ Collection all = byName.values();
+ ArrayList useable = new ArrayList();
+ for (Iterator i = all.iterator(); i.hasNext(); ) {
+ Server s = (Server) i.next();
+ if (s.isUseable())
+ useable.add(s);
+ }
+ useableServers = (Server[]) useable.toArray( new Server[useable.size()] );
+
+
+ ArrayList recommended = new ArrayList();
+ for (int i=0; i<useableServers.length; i++)
+ if (useableServers[i].isRecommended())
+ recommended.add(useableServers[i]);
+ recommendedServers = (Server[]) recommended.toArray( new Server[recommended.size()] );
+ }
+
+
+
+ /**
+ * Possibly add a new server descriptor to the directory.
+ *
+ * This method adds a server desccriptor to the directory if it
+ * - conforms to the syntax specified.
+ * - the server is not yet known or it's identity key matches the key of the already known ServerDescriptor.
+ *
+ * @param server a DirectoryMessage consisting of one of more sections. At 'Server' section needs to be present.
+ * @throws Mix3BadServerFormatException if a section is syntactially invalid and the error cannot be ignored.
+ * @throws Mix3BadServerSignatureException if the server descriptor's signature is invalid.
+ */
+ private void addServerDescriptor(DirectoryMessage server) throws Mix3BadServerFormatException, Mix3BadServerSignatureException {
+ ServerDescriptor sd;
+ try {
+ sd = new ServerDescriptor(server);
+ } catch (Mix3BadServerUnrecognizedVersionException e) {
+ System.err.println("Ignoring unregonized version");
+ return;
+ }
+ String key = sd.getNickname().toLowerCase();
+ if (byName.containsKey(key)) {
+ Server s = (Server) byName.get(key);
+ try {
+ s.addDescriptor(sd);
+ } catch (Mix3BadServerFormatException e) {
+ System.err.println("Ignoring Descriptor with different identity for "+key);
+ }
+ } else {
+ Server s = new Server(sd);
+ byName.put(key, s);
+ }
+ }
+
+
+ private void parseDirectory(DirectoryMessage m, boolean checkDirectorySignature) throws
+ Mix3BadDirectorySignatureException,
+ Mix3BadDirectoryFormatException,
+ Mix3BadServerFormatException,
+ Mix3BadServerSignatureException
+ {
+ DirectorySection directorySection = m.getSection("Directory");
+ if (directorySection == null)
+ throw new Mix3BadDirectoryFormatException("No Directory section found.");
+
+ DirectoryEntry versionEntry = directorySection.getEntry("Version");
+ if (versionEntry == null)
+ throw new Mix3BadDirectoryFormatException("No Version in Directory section found.");
+ if (! versionEntry.getValue().equals(DIRECTORY_VERSION))
+ throw new Mix3BadDirectoryFormatException("Directory Version "+versionEntry+" not recognized.");
+
+ /* FIXME: check validity (date range) */
+
if (checkDirectorySignature)
checkSignature(m);
DirectoryMessage server = null;
@@ -102,27 +176,38 @@ public class Directory {
}
if (server != null)
addServerDescriptor(server);
+
+ DirectoryEntry recommendedServersEntry = directorySection.getEntry("Recommended-Servers");
+ if (recommendedServersEntry == null)
+ throw new Mix3BadDirectorySignatureException("No Recommended-Servers in Directory section found.");
+ String[] recommendedServers = Util.tokenize( recommendedServersEntry.getValue(), ',');
+ for (int i=0; i<recommendedServers.length; i++) {
+ Server s = getServer(recommendedServers[i]);
+ if (s == null)
+ throw new Mix3BadDirectoryFormatException("Unkown nickname '"+recommendedServers[i]+"'in Recommended-Servers");
+ s.setRecommended();
+ }
}
/* FIXME: known directory servers should be passed as arguments */
/**
* Check the signature of a type III directory.
*/
- private void checkSignature(DirectoryMessage m) throws Mix3BadDirectorySignatureException {
+ private void checkSignature(DirectoryMessage m) throws Mix3BadDirectorySignatureException, Mix3BadDirectoryFormatException {
/* FIXME: handle more than one signature block,
*/
DirectorySection signatureSection = m.getSection("Signature");
if (signatureSection == null)
- throw new Mix3BadDirectorySignatureException("No Signature section found.");
+ throw new Mix3BadDirectoryFormatException("No Signature section found.");
DirectoryEntry signatureEntry = signatureSection.getEntry("DirectorySignature");
if (signatureEntry == null)
- throw new Mix3BadDirectorySignatureException("No DirectorySignature in Signature section found.");
+ throw new Mix3BadDirectoryFormatException("No DirectorySignature in Signature section found.");
DirectoryEntry identityEntry = signatureSection.getEntry("DirectoryIdentity");
if (identityEntry == null)
- throw new Mix3BadDirectorySignatureException("No DirectoryIdentity in Signature section found.");
+ throw new Mix3BadDirectoryFormatException("No DirectoryIdentity in Signature section found.");
byte[] signature = Base64.decode(signatureEntry.getValue());
byte[] identity = Base64.decode(identityEntry.getValue());
@@ -131,7 +216,6 @@ public class Directory {
cleanedDirectory.blindValue("Signature","DirectoryDigest");
cleanedDirectory.blindValue("Signature","DirectorySignature");
- /* FIXME: what if identity is no valid key? */
RSAPublicKey identityKey = new RSAPublicKey(identity);
boolean verifies;
try {
@@ -145,6 +229,9 @@ public class Directory {
/**
* Get a server by nickname.
+ *
+ * @param name nickname of the requested server
+ * @return server specified by the nickname or null if no such server exists
*/
public Server getServer(String name) {
String key = name.toLowerCase();
@@ -152,4 +239,85 @@ public class Directory {
return (Server) byName.get(key);
return null;
}
+
+ /*
+ * Get current server descriptor of useable servers.
+ *
+ * A server is useable if it understands PacketVersions that we understand
+ * and has a serverdescriptor that is useable right now.
+ *
+ * @return server descriptor of useable servers
+ */
+ /*
+ private Server[] getUseableServers() {
+ return useableServers;
+ }
+ */
+
+ /**
+ * Get server descriptor of all recommended servers that are useable.
+ *
+ * @return server descriptor recommended servers
+ * @see #getUseableServers
+ */
+ public Server[] getRecommendedServers() {
+ return recommendedServers;
+ }
+
+ /**
+ * Check if server a can talk to server b.
+ *
+ * A server can talk to another one if they have MMTP/Outgoing and
+ * MMTP/Incoming sections respectively and speak a common MMTP version.
+ *
+ * FIXME: check Allow/Deny ACLs
+ *
+ * @param a server a
+ * @param b server b
+ * @return whether a can send messages to b
+ */
+ public boolean areFriends(Server a, Server b) {
+ ServerDescriptor aa,bb;
+
+ try {
+ aa = a.getDescriptor();
+ } catch (Mix3NoServerDescriptorException e) {
+ throw new Error(a.getNickname()+" should have a valid ServerDescriptor.", e);
+ }
+ try {
+ bb = b.getDescriptor();
+ } catch (Mix3NoServerDescriptorException e) {
+ throw new Error(b.getNickname()+" should have a valid ServerDescriptor.", e);
+ }
+
+ OutgoingMMTPSection out = aa.getOutgoingMMTPSection();
+ IncomingMMTPSection in = bb.getIncomingMMTPSection();
+
+ if (out == null || in == null)
+ return false;
+ String[] inP = in.getProtocols();
+ String[] outP = out.getProtocols();
+ for (int i=0; i<inP.length; i++)
+ for (int o=0; o<outP.length; o++)
+ if (inP[i].equals(outP[o]))
+ return true;
+ return false;
+ }
+
+ /*
+ * Build a matrix of friends.
+ *
+ * (a, b) are friends, if a can send messages to b.
+ */
+ /*
+ private void buildFriendsMatrix() {
+ friends = new boolean[useableServers.length][useableServers.length];
+ for (int i=0; i<useableServers.length; i++)
+ for (int j=0; j<useableServers.length; j++)
+ if (i==j)
+ friends[i][j] = true;
+ else
+ friends[i][j] = areFriends(useableServers[i], useableServers[j]);
+ }
+ */
}
diff --git a/src/org/noreply/fancydress/directory/IncomingMMTPSection.java b/src/org/noreply/fancydress/directory/IncomingMMTPSection.java
index 92e17d7..bf9682f 100644
--- a/src/org/noreply/fancydress/directory/IncomingMMTPSection.java
+++ b/src/org/noreply/fancydress/directory/IncomingMMTPSection.java
@@ -19,6 +19,11 @@ import java.net.UnknownHostException;
* @see ServerDescriptor
*/
public class IncomingMMTPSection {
+ /*
+ปญญญญญญญ * version we understand.
+ปญญญญญญญ */
+ private static final String VERSION = "0.1";
+
private String name;
/* Required */
@@ -26,7 +31,7 @@ public class IncomingMMTPSection {
private InetAddress ip;
private String hostname;
private int port;
- private String protocols;
+ private String[] protocols;
/**
* Construct an Incoming/MMTP section.
@@ -53,7 +58,7 @@ public class IncomingMMTPSection {
if (entryVersion == null)
throw new Mix3BadServerFormatException("Version not in " + name + " section");
version = entryVersion.getValue();
- if (! version.equals("0.1"))
+ if (! version.equals(VERSION))
/* We have to ignore unknown Versions */
throw new Mix3BadServerUnrecognizedVersionException("Unrecognized " + name + " Version "+version);
@@ -98,7 +103,7 @@ public class IncomingMMTPSection {
if (port < 0 || port > 65535)
throw new Mix3BadServerFormatException("Port is not in TCP/IP port range in " + name + " section");
- protocols = entryProtocols.getValue();
+ protocols = Util.tokenize(entryProtocols.getValue(), ',');
}
public InetAddress getIP() {
@@ -110,4 +115,7 @@ public class IncomingMMTPSection {
public int getPort() {
return port;
}
+ public String[] getProtocols() {
+ return protocols;
+ }
}
diff --git a/src/org/noreply/fancydress/directory/Server.java b/src/org/noreply/fancydress/directory/Server.java
index c4052d9..45ca720 100644
--- a/src/org/noreply/fancydress/directory/Server.java
+++ b/src/org/noreply/fancydress/directory/Server.java
@@ -35,6 +35,11 @@ public class Server {
ArrayList descriptors;
/**
+ * whether or not this node is recommended.
+ */
+ boolean recommended;
+
+ /**
* Construct a Server from a given ServerDescriptor.
*
* @param descriptor a ServerDescriptor.
@@ -46,6 +51,51 @@ public class Server {
descriptors = new ArrayList();
descriptors.add(descriptor);
+ recommended = false;
+ }
+
+ /**
+ * Set this node recommended.
+ *
+ * This is done by the Directory according to the recommended-servers list.
+ *
+ * @see Directory
+ */
+ public void setRecommended() {
+ recommended = true;
+ }
+
+ /**
+ * Get whether or not this node recommended.
+ *
+ * @return whether or not this node is recommended
+ */
+ public boolean isRecommended() {
+ return recommended;
+ }
+
+ /**
+ * Get whether or not this node is useable.
+ *
+ * A server is useable if it understands PacketVersions that we speak,
+ * has a serverdescriptor that is useable right now, and this SD has
+ * an Incoming/MMTP section.
+ *
+ * @return whether or not this node is useable
+ */
+ public boolean isUseable() {
+ ServerDescriptor sd;
+ try {
+ sd = getDescriptor();
+ } catch (Mix3NoServerDescriptorException e) {
+ return false;
+ }
+ String[] pv = sd.getPacketVersions(); /* getPacketVersions only returns packet versions that we understand */
+ if (pv.length == 0)
+ return false;
+ if (sd.getIncomingMMTPSection() == null)
+ return false;
+ return true;
}
/**
@@ -77,11 +127,21 @@ public class Server {
}
/**
+ * Get the nickname of this server.
+ *
+ * @return nickname
+ */
+ public String getNickname() {
+ return nickname;
+ }
+
+ /**
* get the the currently valid server descriptor.
*
* @return current server descriptor
+ * @throws Mix3NoServerDescriptorException if there is no valid server descriptor
*/
- public ServerDescriptor getDescriptor() throws Mix3Exception {
+ public ServerDescriptor getDescriptor() throws Mix3NoServerDescriptorException {
ServerDescriptor result = null;
Date now = new Date();
@@ -93,7 +153,7 @@ public class Server {
result = desc;
}
if (result == null)
- throw new Mix3Exception("No valid server descriptor found.");
+ throw new Mix3NoServerDescriptorException("No valid server descriptor found.");
return result;
}
}
diff --git a/src/org/noreply/fancydress/directory/ServerDescriptor.java b/src/org/noreply/fancydress/directory/ServerDescriptor.java
index 020d31b..4c0cba1 100644
--- a/src/org/noreply/fancydress/directory/ServerDescriptor.java
+++ b/src/org/noreply/fancydress/directory/ServerDescriptor.java
@@ -23,6 +23,11 @@ import java.text.ParseException;
* @see Server
*/
public class ServerDescriptor {
+ /*
+ปญญญญญญญ * descriptor version we understand.
+ปญญญญญญญ */
+ private static final String DESCRIPTOR_VERSION = "0.2";
+
/* Required */
private String descriptorVersion;
private String nickname;
@@ -46,7 +51,7 @@ public class ServerDescriptor {
private String whyInsecure;
private IncomingMMTPSection incomingMMTPSection;
- private Object outgoingMMTPSection;
+ private OutgoingMMTPSection outgoingMMTPSection;
private DeliveryMBOXSection deliveryMBOXSection;
private DeliverySMTPSection deliverySMTPSection;
private Object deliveryFragmentedSection;
@@ -82,6 +87,11 @@ public class ServerDescriptor {
incomingMMTPSection = section == null ? null : new IncomingMMTPSection(section);
} catch (Mix3BadServerFormatException e) { System.err.println(e); };
+ section = m.getSection("Outgoing/MMTP");
+ try {
+ outgoingMMTPSection = section == null ? null : new OutgoingMMTPSection(section);
+ } catch (Mix3BadServerFormatException e) { System.err.println(e); };
+
section = m.getSection("Delivery/MBOX");
try {
deliveryMBOXSection = section == null ? null : new DeliveryMBOXSection(section);
@@ -120,46 +130,18 @@ public class ServerDescriptor {
* Whitespace is trimmed off each Packet-Version.
*
* @param s the comma separated list of Packet-Versions
- * @param onlySupported only include Packet-Versions that we can handle
* @return array of Packet-Versions.
*/
- public static String[] parsePacketVersions(String s, boolean onlySupported) {
+ public static String[] parsePacketVersions(String s) {
ArrayList versions = new ArrayList();
int indexFrom = 0;
int indexOf;
- while ((indexOf = s.indexOf(',', indexFrom)) != -1) {
- String v = s.substring(indexFrom, indexOf).trim();
- if (!v.equals("") && (Packet.isPacketVersionSupported(v) || !onlySupported ))
- versions.add( v );
- indexFrom = indexOf + 1;
- }
- String v = s.substring(indexFrom).trim();
- if (!v.equals("") && (Packet.isPacketVersionSupported(v) || !onlySupported ))
- versions.add( v );
-
- String[] result = new String[versions.size()];
- for (int i=0; i<result.length; i++)
- result[i] = (String) versions.get(i);
-
- return result;
- }
- /**
- * Tokenize a Packet-Versions string into single Packet-Versions.
- *
- * The Packet-Versions is a comma separated list of Packet-Versions.
- * This method parses a Packet-Versions value and returns an array of
- * Strings, holding one Packet-Version each.
- *
- * Whitespace is trimmed off each Packet-Version.
- *
- * Only Packet-Versions that we know to handle are included n the result.
- *
- * @param s the comma separated list of Packet-Versions
- * @return array of Packet-Versions.
- */
- public static String[] parsePacketVersions(String s) {
- return parsePacketVersions(s, true);
+ String[] tokens = Util.tokenize(s, ',');
+ for (int i=0; i<tokens.length; i++)
+ if (Packet.isPacketVersionSupported(tokens[i]))
+ versions.add( tokens[i] );
+ return (String[]) versions.toArray( new String[versions.size()] );
}
/**
@@ -173,7 +155,7 @@ public class ServerDescriptor {
if (entryDescriptorVersion == null)
throw new Mix3BadServerFormatException("Descriptor-Version not in Server Descriptor");
descriptorVersion = entryDescriptorVersion.getValue();
- if (! descriptorVersion.equals("0.2"))
+ if (! descriptorVersion.equals(DESCRIPTOR_VERSION))
/* We have to ignore unknown Descriptor-Versions */
throw new Mix3BadServerUnrecognizedVersionException("Unrecognized Descriptor-Version "+descriptorVersion);
@@ -319,6 +301,15 @@ public class ServerDescriptor {
}
/**
+ * Get this server descriptor's supported packet versions.
+ *
+ * @return supported packet versions
+ */
+ public String[] getPacketVersions() {
+ return packetVersions;
+ }
+
+ /**
* Get the date after which this server descriptor is valid.
*
* @return date after which this server descriptor is valid
@@ -354,4 +345,13 @@ public class ServerDescriptor {
return incomingMMTPSection;
}
+ /**
+ * Get the Outgoing/MMTP section.
+ *
+ * @return this server descriptor's Outgoing/MMTP section
+ */
+ public OutgoingMMTPSection getOutgoingMMTPSection() {
+ return outgoingMMTPSection;
+ }
+
}