diff options
Diffstat (limited to 'src/org/noreply/fancydress/directory')
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; + } + } |