summaryrefslogtreecommitdiff
path: root/src/org/noreply/fancydress/directory
diff options
context:
space:
mode:
authorPeter Palfrader <peter@palfrader.org>2003-10-09 11:41:45 +0000
committerPeter Palfrader <peter@palfrader.org>2003-10-09 11:41:45 +0000
commit566d17f731637df6828bdf32502a0fb123882dbe (patch)
treefc09fdfb90953134fa1d25f73367307502348a22 /src/org/noreply/fancydress/directory
parent018eea460ee32df1b70c40c2eca05f06c06daca5 (diff)
Initial import
Diffstat (limited to 'src/org/noreply/fancydress/directory')
-rw-r--r--src/org/noreply/fancydress/directory/DeliveryMBOXSMTPSection.java97
-rw-r--r--src/org/noreply/fancydress/directory/DeliveryMBOXSection.java27
-rw-r--r--src/org/noreply/fancydress/directory/DeliverySMTPSection.java27
-rw-r--r--src/org/noreply/fancydress/directory/Directory.java156
-rw-r--r--src/org/noreply/fancydress/directory/IncomingMMTPSection.java102
-rw-r--r--src/org/noreply/fancydress/directory/Server.java86
-rw-r--r--src/org/noreply/fancydress/directory/ServerDescriptor.java319
-rw-r--r--src/org/noreply/fancydress/directory/parser/DirectoryEntry.java82
-rw-r--r--src/org/noreply/fancydress/directory/parser/DirectoryLexer.flex40
-rw-r--r--src/org/noreply/fancydress/directory/parser/DirectoryLexer.java546
-rw-r--r--src/org/noreply/fancydress/directory/parser/DirectoryMessage.java130
-rw-r--r--src/org/noreply/fancydress/directory/parser/DirectoryParser.cup141
-rw-r--r--src/org/noreply/fancydress/directory/parser/DirectoryParser.java477
-rw-r--r--src/org/noreply/fancydress/directory/parser/DirectorySection.java129
-rw-r--r--src/org/noreply/fancydress/directory/parser/DirectorySymbols.java22
15 files changed, 2381 insertions, 0 deletions
diff --git a/src/org/noreply/fancydress/directory/DeliveryMBOXSMTPSection.java b/src/org/noreply/fancydress/directory/DeliveryMBOXSMTPSection.java
new file mode 100644
index 0000000..7eaf2bd
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/DeliveryMBOXSMTPSection.java
@@ -0,0 +1,97 @@
+package org.noreply.fancydress.directory;
+
+import org.noreply.fancydress.directory.parser.*;
+import org.noreply.fancydress.misc.Util;
+import org.noreply.fancydress.status.*;
+import java.util.*;
+import java.text.ParseException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Base class for both DeliveryMBOXSection and DeliverySMTP Section.
+ *
+ * This is a base class for the DeliveryMBOXSection and the DeliverySMTP class.
+ * Since both are very similar it makes sense to pool their functionality into
+ * a single class from which both inheritate.
+ *
+ * @see ServerDescriptor
+ */
+public class DeliveryMBOXSMTPSection {
+ private String name;
+
+ /* Required */
+ /**
+ * The version number of this section.
+ */
+ private String version;
+ /**
+ * The maximum message size (in Kb) that is accepted at this node.
+ */
+ private int maximumSize;
+ /**
+ * Whether this exit node allows user supplied From: lines.
+ */
+ private boolean allowFrom;
+
+ /**
+ * Construct a Delivery/MBOX or Delivery/SMTP section.
+ *
+ * @param section the section to parse.
+ * @throws Mix3BadServerUnrecognizedVersionException if the Version in the section is not recognized.
+ * @throws Mix3BadServerFormatException if the Section is syntactially invalid.
+ */
+ public DeliveryMBOXSMTPSection(DirectorySection section)
+ throws Mix3BadServerFormatException
+ {
+ name = section.getName();
+ parseDeliveryMBOXSMTPSection(section);
+ }
+
+ /**
+ * Parse a Delivery/MBOX or the Delivery/SMTP section.
+ *
+ * @param section the section to parse.
+ * @throws Mix3BadServerUnrecognizedVersionException if the Version in the section is not recognized.
+ * @throws Mix3BadServerFormatException if the Section is syntactially invalid.
+ */
+ private void parseDeliveryMBOXSMTPSection(DirectorySection section) throws Mix3BadServerFormatException {
+ /* Check Version */
+ DirectoryEntry entryVersion = section.getEntry("Version");
+ if (entryVersion == null)
+ throw new Mix3BadServerFormatException("Version not in " + name + " section");
+ version = entryVersion.getValue();
+ if (! version.equals("0.1"))
+ /* We have to ignore unknown Versions */
+ throw new Mix3BadServerUnrecognizedVersionException("Unrecognized " + name + " Version "+version);
+
+ /* mandatory entries */
+ DirectoryEntry entryMaximumSize = section.getEntry("Maximum-size");
+ DirectoryEntry entryAllowFrom = section.getEntry("Allow-From");
+
+ /* FIXME
+ if (entryMaximumSize == null)
+ throw new Mix3BadServerFormatException("Maximum-size not in " + name + " section");
+ */
+ if (entryAllowFrom == null)
+ throw new Mix3BadServerFormatException("Allow-From not in " + name + " section");
+
+
+ /* FIXME
+ try {
+ Integer p = new Integer(entryMaximumSize.getValue());
+ maximumSize = p.intValue();
+ } catch (NumberFormatException e) {
+ throw new Mix3BadServerFormatException("Maximum-size is not a valid integer in " + name + " section", e);
+ };
+ if (maximumSize < 32)
+ throw new Mix3BadServerFormatException("Maximum-size is smaller than 32 in " + name + " section");
+ */
+
+ try {
+ allowFrom = Util.parseBoolean(entryAllowFrom.getValue());
+ } catch (ParseException e) {
+ throw new Mix3BadServerFormatException("Allow-From is not a valid boolean in " + name + " section", e);
+ };
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/DeliveryMBOXSection.java b/src/org/noreply/fancydress/directory/DeliveryMBOXSection.java
new file mode 100644
index 0000000..9a913e8
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/DeliveryMBOXSection.java
@@ -0,0 +1,27 @@
+package org.noreply.fancydress.directory;
+
+import org.noreply.fancydress.directory.parser.*;
+import org.noreply.fancydress.status.*;
+
+/**
+ * This class holds the information supplied in a Delivery/MBOX section of a
+ * server descriptor.
+ *
+ * @see ServerDescriptor
+ */
+public class DeliveryMBOXSection extends DeliveryMBOXSMTPSection {
+
+ /**
+ * Construct a Delivery/MBOX section
+ *
+ * @param section the section to parse.
+ * @throws Mix3BadServerUnrecognizedVersionException if the Version in the section is not recognized.
+ * @throws Mix3BadServerFormatException if the Section is syntactially invalid.
+ */
+ public DeliveryMBOXSection(DirectorySection section)
+ throws Mix3BadServerFormatException
+ {
+ // FIXME: assert that the section's name is Delivery/MBOX
+ super(section);
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/DeliverySMTPSection.java b/src/org/noreply/fancydress/directory/DeliverySMTPSection.java
new file mode 100644
index 0000000..e09c884
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/DeliverySMTPSection.java
@@ -0,0 +1,27 @@
+package org.noreply.fancydress.directory;
+
+import org.noreply.fancydress.directory.parser.*;
+import org.noreply.fancydress.status.*;
+
+/**
+ * This class holds the information supplied in a Delivery/SMTP section of a
+ * server descriptor.
+ *
+ * @see ServerDescriptor
+ */
+public class DeliverySMTPSection extends DeliveryMBOXSMTPSection {
+
+ /**
+ * Construct a Delivery/SMTP section
+ *
+ * @param section the section to parse.
+ * @throws Mix3BadServerUnrecognizedVersionException if the Version in the section is not recognized.
+ * @throws Mix3BadServerFormatException if the Section is syntactially invalid.
+ */
+ public DeliverySMTPSection(DirectorySection section)
+ throws Mix3BadServerFormatException
+ {
+ // FIXME: assert that the section's name is Delivery/SMTP
+ super(section);
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/Directory.java b/src/org/noreply/fancydress/directory/Directory.java
new file mode 100644
index 0000000..d5f940b
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/Directory.java
@@ -0,0 +1,156 @@
+package org.noreply.fancydress.directory;
+
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.noreply.fancydress.directory.parser.*;
+import org.noreply.fancydress.misc.Util;
+import org.noreply.fancydress.crypto.*;
+import org.noreply.fancydress.status.*;
+import java.util.*;
+
+/**
+ * This class represents a type III Directory.
+ *
+ * A directory holds information about the state of a type III network, like
+ * recommended servers, which servers exist, their keys, etc.
+ *
+ * FIXME:
+ * This whole flex and cup thing was just a nice way to try these tools.
+ * Eventually this should be rewritten to a simple parser in Java itself.
+ * Writing it should be pretty straight forward and cut down the
+ * dependencies.
+ *
+ * @see Server
+ */
+public class Directory {
+ /**
+ * Hash holding all Servers.
+ *
+ * This hash holds all Servers. Since nickname are to be treaded case
+ * insensitive the hash's keys are the lowercased nicknames of the Servers.
+ *
+ * All values in this hash are instances of Server.
+ *
+ * @see Server
+ */
+ private Hashtable byName;
+
+ /**
+ * 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 {
+ 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");
+ }
+ }
+
+ /**
+ * Create a directory from an entire DirectoryMessage.
+ *
+ * This constructor builds up the directory from the message
+ * <code>m</code>. It optionally checks the directory's signature and
+ * splits the message into single server descriptors to load them.
+ *
+ * @param m the directory message
+ * @param checkDirectorySignature whether or not to check the directory's signature
+ * @throws Mix3BadDirectorySignatureException if the directory's signature is invalid.
+ * @throws Mix3BadServerSignatureException if a server descriptor's signature is invalid.
+ * @throws Mix3BadServerFormatException if a section is syntactially invalid and the error cannot be ignored.
+ */
+ public Directory(DirectoryMessage m, boolean checkDirectorySignature) throws
+ Mix3BadDirectorySignatureException,
+ Mix3BadServerFormatException,
+ Mix3BadServerSignatureException
+ {
+ byName = new Hashtable();
+
+ if (checkDirectorySignature)
+ checkSignature(m);
+ DirectoryMessage server = null;
+ for (Iterator i = m.getSectionsIterator(); i.hasNext(); ) {
+ DirectorySection section = (DirectorySection) i.next();
+ if (section.getName().equals("Server")) {
+ if (server != null)
+ addServerDescriptor(server);
+ server = new DirectoryMessage();
+ }
+ if (server != null)
+ server.addSection(section);
+ }
+ if (server != null)
+ addServerDescriptor(server);
+
+ System.out.println(byName);
+ }
+
+ /* FIXME: known directory servers should be passed as arguments */
+ /**
+ * Check the signature of a type III directory.
+ */
+ private void checkSignature(DirectoryMessage m) throws Mix3BadDirectorySignatureException {
+ /* FIXME: handle more than one signature block,
+ */
+
+ DirectorySection signatureSection = m.getSection("Signature");
+ if (signatureSection == null)
+ throw new Mix3BadDirectorySignatureException("No Signature section found.");
+
+ DirectoryEntry signatureEntry = signatureSection.getEntry("DirectorySignature");
+ if (signatureEntry == null)
+ throw new Mix3BadDirectorySignatureException("No DirectorySignature in Signature section found.");
+
+ DirectoryEntry identityEntry = signatureSection.getEntry("DirectoryIdentity");
+ if (identityEntry == null)
+ throw new Mix3BadDirectorySignatureException("No DirectoryIdentity in Signature section found.");
+
+ byte[] signature = Base64.decode(signatureEntry.getValue());
+ byte[] identity = Base64.decode(identityEntry.getValue());
+
+ DirectoryMessage cleanedDirectory = new DirectoryMessage(m);
+ cleanedDirectory.blindValue("Signature","DirectoryDigest");
+ cleanedDirectory.blindValue("Signature","DirectorySignature");
+
+ /* FIXME: what if identity is no valid key? */
+ RSAPublicKey identityKey = new RSAPublicKey(identity);
+ boolean verifies;
+ try {
+ verifies = identityKey.verify(signature, Util.toOctets(cleanedDirectory.toString()));
+ } catch (InvalidCipherTextException e) {
+ throw new Mix3BadDirectorySignatureException("Directory signature has invalid format.", e);
+ };
+ if (!verifies)
+ throw new Mix3BadDirectorySignatureException("Directory signature does not verify.");
+ }
+
+ /**
+ * Get a server by nickname.
+ */
+ public Server getServer(String name) {
+ String key = name.toLowerCase();
+ if (byName.containsKey(key))
+ return (Server) byName.get(key);
+ return null;
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/IncomingMMTPSection.java b/src/org/noreply/fancydress/directory/IncomingMMTPSection.java
new file mode 100644
index 0000000..28511b2
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/IncomingMMTPSection.java
@@ -0,0 +1,102 @@
+package org.noreply.fancydress.directory;
+
+import org.bouncycastle.util.encoders.Base64;
+import org.noreply.fancydress.directory.parser.*;
+import org.noreply.fancydress.misc.Util;
+import org.noreply.fancydress.crypto.*;
+import org.noreply.fancydress.status.*;
+import java.util.*;
+import java.text.ParseException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/* FIXME: parse allow/deny ACLs */
+
+/**
+ * Represent an Incoming/MMTP section of a server descriptor.
+ *
+ * @see ServerDescriptor
+ */
+public class IncomingMMTPSection {
+ private String name;
+
+ /* Required */
+ private String version;
+ private InetAddress ip;
+ private String hostname;
+ private int port;
+ private String protocols;
+
+ /**
+ * Construct an Incoming/MMTP section.
+ *
+ * @param section the section to parse.
+ * @throws Mix3BadServerFormatException if the Section is syntactially invalid.
+ */
+ public IncomingMMTPSection(DirectorySection section)
+ throws Mix3BadServerFormatException
+ {
+ name = section.getName();
+ parseIncomingMMTPSection(section);
+ }
+
+ /**
+ * Parse an Incoming/MMTP section.
+ *
+ * @param section the section to parse.
+ * @throws Mix3BadServerFormatException if the Section is syntactially invalid.
+ */
+ private void parseIncomingMMTPSection(DirectorySection section) throws Mix3BadServerFormatException {
+ /* Check Version */
+ DirectoryEntry entryVersion = section.getEntry("Version");
+ if (entryVersion == null)
+ throw new Mix3BadServerFormatException("Version not in " + name + " section");
+ version = entryVersion.getValue();
+ if (! version.equals("0.1"))
+ /* We have to ignore unknown Versions */
+ throw new Mix3BadServerUnrecognizedVersionException("Unrecognized " + name + " Version "+version);
+
+ /* mandatory entries */
+ DirectoryEntry entryIP = section.getEntry("IP");
+ DirectoryEntry entryHostname = section.getEntry("Hostname");
+ DirectoryEntry entryPort = section.getEntry("Port");
+ DirectoryEntry entryProtocols = section.getEntry("Protocols");
+
+ /* check if mandatory entries are available */
+ if (entryIP == null)
+ throw new Mix3BadServerFormatException("IP not in " + name + " section");
+ /* FIXME: spec is changing from IP to hostname, for now, hostname is not used */
+ /*
+ if (entryHostname == null)
+ throw new Mix3BadServerFormatException("Hostname not in " + name + " section");
+ */
+ if (entryPort == null)
+ throw new Mix3BadServerFormatException("Port not in " + name + " section");
+ if (entryProtocols == null)
+ throw new Mix3BadServerFormatException("Protocols not in " + name + " section");
+
+
+ try {
+ ip = InetAddress.getByName(entryIP.getValue());
+ } catch (UnknownHostException e) {
+ throw new Mix3BadServerFormatException("IP is not a valid IP adress in " + name + " section", e);
+ }
+ if (!ip.getHostAddress().equals(entryIP.getValue()))
+ throw new Mix3BadServerFormatException(
+ "parsed IP to string does not match its directory representation in " + name + " section: "+
+ ip.getHostAddress() + " vs. " + entryIP.getValue());
+
+ hostname = entryHostname == null ? null : entryHostname.getValue(); /* FIXME */
+
+ try {
+ Integer p = new Integer(entryPort.getValue());
+ port = p.intValue();
+ } catch (NumberFormatException e) {
+ throw new Mix3BadServerFormatException("Port is not a valid integer in " + name + " section", e);
+ };
+ if (port < 0 || port > 65535)
+ throw new Mix3BadServerFormatException("Port is not in TCP/IP port range in " + name + " section");
+
+ protocols = entryProtocols.getValue();
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/Server.java b/src/org/noreply/fancydress/directory/Server.java
new file mode 100644
index 0000000..e3bb355
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/Server.java
@@ -0,0 +1,86 @@
+package org.noreply.fancydress.directory;
+
+import org.noreply.fancydress.misc.Util;
+import org.noreply.fancydress.status.*;
+import org.noreply.fancydress.crypto.*;
+import java.util.*;
+
+/**
+ * This class represents a server, pooling one or more server descriptors into one class.
+ *
+ * @see ServerDescriptor
+ */
+public class Server {
+ /**
+ * Nickname of the server.
+ *
+ * Note that all nickname comparisons need to be done in a case insensitive way.
+ */
+ String nickname;
+
+ /**
+ * The asn1 representation of the server's identity key.
+ */
+ byte[] identity;
+
+ /**
+ * The hash of <code>identity</code>, which is the node's keyid
+ */
+ byte[] keyid;
+
+ /**
+ * A list of one of more server descriptors.
+ */
+ ArrayList descriptors;
+
+ /**
+ * Construct a Server from a given ServerDescriptor.
+ *
+ * @param descriptor a ServerDescriptor.
+ */
+ public Server(ServerDescriptor descriptor) {
+ nickname = descriptor.getNickname();
+ identity = descriptor.getIdentity();
+ keyid = CryptoPrimitives.hash(identity);
+
+ descriptors = new ArrayList();
+ descriptors.add(descriptor);
+ }
+
+ /**
+ * Add a ServerDescriptor to this Server.
+ *
+ * @param descriptor a ServerDescriptor to add.
+ * @throws Mix3BadServerFormatException if the nickname or the identity key do not match this server's nickname or identity key.
+ */
+ public void addDescriptor(ServerDescriptor descriptor) throws Mix3BadServerFormatException {
+
+ if (!nickname.equalsIgnoreCase(descriptor.getNickname()))
+ /* This indicates an error in whoever called us */
+ throw new Error("Nickname does not match.");
+
+ if (!Util.equal(identity, descriptor.getIdentity()))
+ /* While this might happen. In this case this ServerDesc should be ignored */
+ throw new Mix3BadServerFormatException("Identity does not match.");
+
+ descriptors.add(descriptor);
+ }
+
+ /**
+ * Get the keyid (hash of the identity key) of this Server.
+ *
+ * @return keyid
+ */
+ public byte[] getKeyID() {
+ return keyid;
+ }
+
+ /**
+ * get the first server descriptor (needs fixing).
+ *
+ * @return first server descriptor
+ */
+ public ServerDescriptor getDescriptor() { /* FIXME */
+ return (ServerDescriptor) descriptors.get(0);
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/ServerDescriptor.java b/src/org/noreply/fancydress/directory/ServerDescriptor.java
new file mode 100644
index 0000000..06cf2d6
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/ServerDescriptor.java
@@ -0,0 +1,319 @@
+package org.noreply.fancydress.directory;
+
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.noreply.fancydress.directory.parser.*;
+import org.noreply.fancydress.misc.Util;
+import org.noreply.fancydress.crypto.*;
+import org.noreply.fancydress.status.*;
+import org.noreply.fancydress.type3.*;
+import java.util.*;
+import java.text.ParseException;
+
+/**
+ * A single Server Descriptor of a type III node.
+ *
+ * This class holds all information of a single server descriptor. It may also
+ * hold subsections like Incoming/MMTP or Delivery/MBOX if such sections exist
+ * in this server descriptor.
+ *
+ * An instance of Server pools ServerDescriptors of a single node.
+ *
+ * @see Server
+ */
+public class ServerDescriptor {
+ /* Required */
+ private String descriptorVersion;
+ private String nickname;
+ private byte[] identity;
+ private RSAPublicKey identityKey;
+ private byte[] identityDigest;
+ private byte[] digest;
+ private byte[] signature;
+ private Date published;
+ private Date validAfter;
+ private Date validUntil;
+ private RSAPublicKey packetKey;
+ private String[] packetVersions;
+
+ /* Optional */
+ private String contact;
+ private String contactFingerprint;
+ private String comments;
+ private String software;
+ private Boolean secureConfiguration;
+ private String whyInsecure;
+
+ private IncomingMMTPSection IncomingMMTPSection;
+ private Object OutgoingMMTPSection;
+ private DeliveryMBOXSection DeliveryMBOXSection;
+ private DeliverySMTPSection DeliverySMTPSection;
+ private Object DeliveryFragmentedSection;
+
+
+ /**
+ * Construct a ServerDescriptor instance from the message in m.
+ *
+ * This constructor builds up a ServerDescriptor from the message
+ * <code>m</code> which contains a single server descriptor.
+ *
+ * The DirectoryMessage needs to have a 'Server' section.
+ *
+ * @param server a DirectoryMessage consisting of one of more sections.
+ * @throws Mix3BadServerFormatException if a section is syntactially invalid and the error cannot be ignored.
+ * @throws Mix3BadServerSignatureException if the server descriptor's signature is invalid.
+ */
+ public ServerDescriptor(DirectoryMessage m)
+ throws Mix3BadServerFormatException, Mix3BadServerSignatureException
+ {
+ DirectorySection serverSection = m.getSection("Server");
+ if (serverSection == null)
+ throw new Mix3BadServerFormatException("No Server section found.");
+
+ parseServerSection(serverSection);
+ identityKey = new RSAPublicKey(identity);
+ identityDigest = CryptoPrimitives.hash(identity);
+ checkSignature(m);
+
+ DirectorySection section;
+ section = m.getSection("Incoming/MMTP");
+ try {
+ IncomingMMTPSection = section == null ? null : new IncomingMMTPSection(section);
+ } catch (Mix3BadServerFormatException e) { System.err.println(e); };
+
+ section = m.getSection("Delivery/MBOX");
+ try {
+ DeliveryMBOXSection = section == null ? null : new DeliveryMBOXSection(section);
+ } catch (Mix3BadServerFormatException e) { System.err.println(e); };
+
+ section = m.getSection("Delivery/SMTP");
+ try {
+ DeliverySMTPSection = section == null ? null : new DeliverySMTPSection(section);
+ } catch (Mix3BadServerFormatException e) { System.err.println(e); };
+ }
+
+
+ /**
+ * Check if <code>s</code> is a valid nickname.
+ *
+ * @throws Mix3BadServerFormatException if <code>s</code> is not a valid nickame
+ */
+ private static void checkSyntaxNickname(String s) throws Mix3BadServerFormatException {
+ for (int i=0; i<s.length(); i++) {
+ char c = s.charAt(i);
+ if (!((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' || c == '@' || c == '-'))
+ throw new Mix3BadServerFormatException("Illegal characters in nickname: "+c);
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @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) {
+ ArrayList versions = new ArrayList();
+ int indexFrom = 0;
+ int indexOf;
+
+ while ((indexOf = s.indexOf(',', indexFrom)) != -1) {
+ String v = s.substring(indexFrom, indexOf).trim();
+ if (Packet.isPacketVersionSupported(v) || !onlySupported )
+ versions.add( v );
+ indexFrom = indexOf + 1;
+ }
+ String v = s.substring(indexFrom).trim();
+ if (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);
+ }
+
+ /**
+ * Parse the Server section.
+ *
+ * @throws Mix3BadServerFormatException if the section is syntactially invalid.
+ */
+ private void parseServerSection(DirectorySection serverSection) throws Mix3BadServerFormatException {
+ /* Check Descriptor-Version */
+ DirectoryEntry entryDescriptorVersion = serverSection.getEntry("Descriptor-Version");
+ if (entryDescriptorVersion == null)
+ throw new Mix3BadServerFormatException("Descriptor-Version not in Server Descriptor");
+ descriptorVersion = entryDescriptorVersion.getValue();
+ if (! descriptorVersion.equals("0.2"))
+ /* We have to ignore unknown Descriptor-Versions */
+ throw new Mix3BadServerUnrecognizedVersionException("Unrecognized Descriptor-Version "+descriptorVersion);
+
+ /* Do nickname now so we can refer to it in exceptions */
+ DirectoryEntry entryNickname = serverSection.getEntry("Nickname");
+ if (entryNickname == null) throw new Mix3BadServerFormatException("Nickname not in Server Descriptor");
+ nickname = entryNickname.getValue();
+ checkSyntaxNickname(nickname); /* Throws Mix3BadServerFormatException unless valid */
+
+ /* mandatory entries */
+ DirectoryEntry entryIdentity = serverSection.getEntry("Identity");
+ DirectoryEntry entryDigest = serverSection.getEntry("Digest");
+ DirectoryEntry entrySignature = serverSection.getEntry("Signature");
+ DirectoryEntry entryPublished = serverSection.getEntry("Published");
+ DirectoryEntry entryValidAfter = serverSection.getEntry("Valid-After");
+ DirectoryEntry entryValidUntil = serverSection.getEntry("Valid-Until");
+ DirectoryEntry entryPacketKey = serverSection.getEntry("Packet-Key");
+ DirectoryEntry entryPacketFormats = serverSection.getEntry("Packet-Formats"); /* FIXME: will go away */
+ DirectoryEntry entryPacketVersions = serverSection.getEntry("Packet-Versions");
+
+ /* optional entries */
+ DirectoryEntry entryContact = serverSection.getEntry("Contact");
+ DirectoryEntry entryContactFingerprint = serverSection.getEntry("Contact-Fingerprint");
+ DirectoryEntry entryComments = serverSection.getEntry("Comments");
+ DirectoryEntry entrySoftware = serverSection.getEntry("Software");
+ DirectoryEntry entrySecureConfiguration = serverSection.getEntry("Secure-Configuration");
+ DirectoryEntry entryWhyInsecure = serverSection.getEntry("Why-Insecure");
+
+ /* check if mandatory entries are available */
+ if (entryIdentity == null)
+ throw new Mix3BadServerFormatException("Identity not in Server Descriptor for "+nickname);
+ if (entryDigest == null)
+ throw new Mix3BadServerFormatException("Digest not in Server Descriptor for "+nickname);
+ if (entrySignature == null)
+ throw new Mix3BadServerFormatException("Signature not in Server Descriptor for "+nickname);
+ if (entryPublished == null)
+ throw new Mix3BadServerFormatException("Published not in Server Descriptor for "+nickname);
+ if (entryValidAfter == null)
+ throw new Mix3BadServerFormatException("Valid-After not in Server Descriptor for "+nickname);
+ if (entryValidUntil == null)
+ throw new Mix3BadServerFormatException("Valid-Until not in Server Descriptor for "+nickname);
+ if (entryPacketKey == null)
+ throw new Mix3BadServerFormatException("Packet-Key not in Server Descriptor for "+nickname);
+ if (entryPacketVersions == null && entryPacketFormats == null) /* FIXME */
+ throw new Mix3BadServerFormatException("Packet-Versions not in Server Descriptor for "+nickname);
+
+ identity = Base64.decode(entryIdentity.getValue());
+ digest = Base64.decode(entryDigest.getValue());
+ signature = Base64.decode(entrySignature.getValue());
+ published = Util.parseDate(entryPublished.getValue());
+ validAfter = Util.parseDate(entryValidAfter.getValue());
+ validUntil = Util.parseDate(entryValidUntil.getValue());
+ packetKey = new RSAPublicKey(Base64.decode(entryPacketKey.getValue()));
+ packetVersions = parsePacketVersions( entryPacketVersions == null ? entryPacketFormats.getValue()
+ : entryPacketVersions.getValue() /* FIXME */ );
+
+ if (published == null)
+ throw new Mix3BadServerFormatException("Cannot parse Published: "+entryPublished.getValue()+" for "+nickname);
+ if (validAfter == null)
+ throw new Mix3BadServerFormatException("Cannot parse Valid-After: "+entryValidAfter.getValue()+" for "+nickname);
+ if (validUntil == null)
+ throw new Mix3BadServerFormatException("Cannot parse Valid-Until: "+entryValidUntil.getValue()+" for "+nickname);
+
+
+ /* optional values */
+ contact = entryContact == null ? null : entryContact.getValue();
+ if (contact != null && contact.length() > 128)
+ throw new Mix3BadServerFormatException("Contact is too long for "+nickname);
+
+ contactFingerprint = entryContactFingerprint == null ? null : entryContactFingerprint.getValue();
+ if (contactFingerprint != null && contactFingerprint.length() > 128)
+ throw new Mix3BadServerFormatException("Contact-Fingerprint is too long for "+nickname);
+
+ comments = entryComments == null ? null : entryComments.getValue();
+ if (comments != null && comments.length() >= 1024)
+ throw new Mix3BadServerFormatException("Comments is too long for "+nickname);
+
+ software = entrySoftware == null ? null : entrySoftware.getValue();
+ try {
+ secureConfiguration = entrySecureConfiguration == null ? null :
+ new Boolean(Util.parseBoolean(entrySecureConfiguration.getValue()));
+ } catch (ParseException e) {
+ throw new Mix3BadServerFormatException("Cannot parse SecureConfiguration for "+nickname, e);
+ };
+ whyInsecure = entryWhyInsecure == null ? null : entryWhyInsecure.getValue();
+ }
+
+ /**
+ * Check the signature of the server descriptor in <code>m</code>.
+ *
+ * @param m the ServerDescriptor to check
+ * @throws Mix3BadServerSignatureException if the signature is invalid.
+ */
+ private void checkSignature(DirectoryMessage m) throws Mix3BadServerSignatureException {
+ DirectoryMessage cleanedDescriptor = new DirectoryMessage(m);
+ cleanedDescriptor.blindValue("Server","Digest");
+ cleanedDescriptor.blindValue("Server","Signature");
+
+ boolean verifies;
+ try {
+ verifies = identityKey.verify(signature, Util.toOctets(cleanedDescriptor.toString()));
+ } catch (InvalidCipherTextException e) {
+ throw new Mix3BadServerSignatureException("Server signature has invalid format.", e);
+ };
+ if (!verifies)
+ throw new Mix3BadServerSignatureException("Server signature does not verify.");
+ }
+
+ /**
+ * Get this server descriptor's nickname.
+ *
+ * @return nickname of the server
+ */
+ public String getNickname() {
+ return nickname;
+ }
+
+ /**
+ * Get this server descriptor's identity key.
+ *
+ * @return asn1 encoded identity key of the server
+ */
+ public byte[] getIdentity() {
+ return identity;
+ }
+
+ /**
+ * Get this server descriptor's identity key.
+ *
+ * @return identity key of the server
+ */
+ public RSAPublicKey getIdentityKey() {
+ return identityKey;
+ }
+
+ /**
+ * Get this server descriptor's packet key.
+ *
+ * @return packet key of this server descriptor
+ */
+ public RSAPublicKey getPacketKey() {
+ return packetKey;
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/parser/DirectoryEntry.java b/src/org/noreply/fancydress/directory/parser/DirectoryEntry.java
new file mode 100644
index 0000000..c9e4e50
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/parser/DirectoryEntry.java
@@ -0,0 +1,82 @@
+package org.noreply.fancydress.directory.parser;
+
+/**
+ * Hold one key/value pair in a directory.
+ *
+ * This class holds one key/value pair in a directory. The
+ * values themselves are still Strings, not parsed into
+ * dates or octet strings.
+ *
+ * A <code>DirectoySection</code> is made up of entries like this.
+ *
+ * @see org.noreply.fancydress.directory.Directory
+ * @see DirectoryParser
+ * @see DirectoryMessage
+ * @see DirectorySection
+ */
+public class DirectoryEntry {
+ private String name;
+ private String value;
+
+ /**
+ * Default constructor.
+ *
+ * Creates a new DirectoryEntry.
+ *
+ * @param name name of the entry.
+ * @param value value of the entry.
+ */
+ public DirectoryEntry(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * Creates a new DirectoryEntry copying the data from <code>entry</code>
+ *
+ * @param entry entry to copy
+ */
+ public DirectoryEntry(DirectoryEntry entry) {
+ this.name = new String(entry.name);
+ this.value = new String(entry.value);
+ }
+
+ /**
+ * Blint this value in order to verify or create a signature.
+ */
+ public void blindValue() {
+ value = "";
+ };
+
+ /**
+ * Returns a string representation of the directory.
+ *
+ * @return a string representation of the object.
+ */
+ public String toString() {
+ if (value.equals(""))
+ return new String(name+":");
+ else
+ return new String(name+": "+value);
+ }
+
+ /**
+ * Returns the name of this section.
+ *
+ * @return name of this section.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of this section.
+ *
+ * @return value of this section.
+ */
+ public String getValue() {
+ return value;
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/parser/DirectoryLexer.flex b/src/org/noreply/fancydress/directory/parser/DirectoryLexer.flex
new file mode 100644
index 0000000..91462a7
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/parser/DirectoryLexer.flex
@@ -0,0 +1,40 @@
+package org.noreply.fancydress.directory.parser;
+
+import java_cup.runtime.*;
+
+%%
+
+%class DirectoryLexer
+
+%public
+%line
+%column
+%cupsym DirectorySymbols
+%cup
+
+%{
+ private Symbol symbol(int type) {
+ return new Symbol(type, yyline, yycolumn);
+ }
+
+ private Symbol symbol(int type, Object value) {
+ return new Symbol(type, yyline, yycolumn, value);
+ }
+%}
+
+Space = [ \t]+
+Identifier = ([!-9] | [;-Z] | \\ | \^ | [_-~])+
+
+%%
+
+<YYINITIAL> {
+ {Space} { return symbol(DirectorySymbols.SPACE, new String(yytext())); }
+ "[" { return symbol(DirectorySymbols.LEFT_BRACKET, new String(yytext())); }
+ "]" { return symbol(DirectorySymbols.RIGHT_BRACKET, new String(yytext())); }
+ "\n" { return symbol(DirectorySymbols.NL); }
+ "\r" { return symbol(DirectorySymbols.CR); }
+ ":" { return symbol(DirectorySymbols.COLON, new String(yytext())); }
+ {Identifier} { return symbol(DirectorySymbols.IDENTIFIER, new String(yytext())); }
+}
+
+[^] { throw new Error("Illegal character <"+yytext()+">"); }
diff --git a/src/org/noreply/fancydress/directory/parser/DirectoryLexer.java b/src/org/noreply/fancydress/directory/parser/DirectoryLexer.java
new file mode 100644
index 0000000..8026ccd
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/parser/DirectoryLexer.java
@@ -0,0 +1,546 @@
+/* The following code was generated by JFlex 1.3.5 on 05.10.03 01:55 */
+
+package org.noreply.fancydress.directory.parser;
+
+import java_cup.runtime.*;
+
+
+/**
+ * This class is a scanner generated by
+ * <a href="http://www.jflex.de/">JFlex</a> 1.3.5
+ * on 05.10.03 01:55 from the specification file
+ * <tt>file:/home/weasel/projects/fancydress/src/org/noreply/fancydress/directory/parser/DirectoryLexer.flex</tt>
+ */
+public class DirectoryLexer implements java_cup.runtime.Scanner {
+
+ /** This character denotes the end of file */
+ final public static int YYEOF = -1;
+
+ /** initial size of the lookahead buffer */
+ final private static int YY_BUFFERSIZE = 16384;
+
+ /** lexical states */
+ final public static int YYINITIAL = 0;
+
+ /**
+ * Translates characters to character classes
+ */
+ final private static char [] yycmap = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 0, 0, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0
+ };
+
+ /**
+ * Translates a state to a row index in the transition table
+ */
+ final private static int yy_rowMap [] = {
+ 0, 8, 16, 24, 8, 8, 8, 8, 8
+ };
+
+ /**
+ * The packed transition table of the DFA (part 0)
+ */
+ final private static String yy_packed0 =
+ "\1\2\1\3\1\4\1\5\1\6\1\7\1\10\1\11"+
+ "\11\0\1\3\10\0\1\4\5\0";
+
+ /**
+ * The transition table of the DFA
+ */
+ final private static int yytrans [] = yy_unpack();
+
+
+ /* error codes */
+ final private static int YY_UNKNOWN_ERROR = 0;
+ final private static int YY_ILLEGAL_STATE = 1;
+ final private static int YY_NO_MATCH = 2;
+ final private static int YY_PUSHBACK_2BIG = 3;
+
+ /* error messages for the codes above */
+ final private static String YY_ERROR_MSG[] = {
+ "Unkown internal scanner error",
+ "Internal error: unknown state",
+ "Error: could not match input",
+ "Error: pushback value was too large"
+ };
+
+ /**
+ * YY_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
+ */
+ private final static byte YY_ATTRIBUTE[] = {
+ 0, 9, 1, 1, 9, 9, 9, 9, 9
+ };
+
+ /** the input device */
+ private java.io.Reader yy_reader;
+
+ /** the current state of the DFA */
+ private int yy_state;
+
+ /** the current lexical state */
+ private int yy_lexical_state = YYINITIAL;
+
+ /** this buffer contains the current text to be matched and is
+ the source of the yytext() string */
+ private char yy_buffer[] = new char[YY_BUFFERSIZE];
+
+ /** the textposition at the last accepting state */
+ private int yy_markedPos;
+
+ /** the textposition at the last state to be included in yytext */
+ private int yy_pushbackPos;
+
+ /** the current text position in the buffer */
+ private int yy_currentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int yy_startRead;
+
+ /** endRead marks the last character in the buffer, that has been read
+ from input */
+ private int yy_endRead;
+
+ /** number of newlines encountered up to the start of the matched text */
+ private int yyline;
+
+ /** the number of characters up to the start of the matched text */
+ private int yychar;
+
+ /**
+ * the number of characters from the last newline up to the start of the
+ * matched text
+ */
+ private int yycolumn;
+
+ /**
+ * yy_atBOL == true <=> the scanner is currently at the beginning of a line
+ */
+ private boolean yy_atBOL = true;
+
+ /** yy_atEOF == true <=> the scanner is at the EOF */
+ private boolean yy_atEOF;
+
+ /** denotes if the user-EOF-code has already been executed */
+ private boolean yy_eof_done;
+
+ /* user code: */
+ private Symbol symbol(int type) {
+ return new Symbol(type, yyline, yycolumn);
+ }
+
+ private Symbol symbol(int type, Object value) {
+ return new Symbol(type, yyline, yycolumn, value);
+ }
+
+
+ /**
+ * Creates a new scanner
+ * There is also a java.io.InputStream version of this constructor.
+ *
+ * @param in the java.io.Reader to read input from.
+ */
+ public DirectoryLexer(java.io.Reader in) {
+ this.yy_reader = in;
+ }
+
+ /**
+ * Creates a new scanner.
+ * There is also java.io.Reader version of this constructor.
+ *
+ * @param in the java.io.Inputstream to read input from.
+ */
+ public DirectoryLexer(java.io.InputStream in) {
+ this(new java.io.InputStreamReader(in));
+ }
+
+ /**
+ * Unpacks the split, compressed DFA transition table.
+ *
+ * @return the unpacked transition table
+ */
+ private static int [] yy_unpack() {
+ int [] trans = new int[32];
+ int offset = 0;
+ offset = yy_unpack(yy_packed0, offset, trans);
+ return trans;
+ }
+
+ /**
+ * Unpacks the compressed DFA transition table.
+ *
+ * @param packed the packed transition table
+ * @return the index of the last entry
+ */
+ private static int yy_unpack(String packed, int offset, int [] trans) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ value--;
+ do trans[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /**
+ * Refills the input buffer.
+ *
+ * @return <code>false</code>, iff there was new input.
+ *
+ * @exception IOException if any I/O-Error occurs
+ */
+ private boolean yy_refill() throws java.io.IOException {
+
+ /* first: make room (if you can) */
+ if (yy_startRead > 0) {
+ System.arraycopy(yy_buffer, yy_startRead,
+ yy_buffer, 0,
+ yy_endRead-yy_startRead);
+
+ /* translate stored positions */
+ yy_endRead-= yy_startRead;
+ yy_currentPos-= yy_startRead;
+ yy_markedPos-= yy_startRead;
+ yy_pushbackPos-= yy_startRead;
+ yy_startRead = 0;
+ }
+
+ /* is the buffer big enough? */
+ if (yy_currentPos >= yy_buffer.length) {
+ /* if not: blow it up */
+ char newBuffer[] = new char[yy_currentPos*2];
+ System.arraycopy(yy_buffer, 0, newBuffer, 0, yy_buffer.length);
+ yy_buffer = newBuffer;
+ }
+
+ /* finally: fill the buffer with new input */
+ int numRead = yy_reader.read(yy_buffer, yy_endRead,
+ yy_buffer.length-yy_endRead);
+
+ if (numRead < 0) {
+ return true;
+ }
+ else {
+ yy_endRead+= numRead;
+ return false;
+ }
+ }
+
+
+ /**
+ * Closes the input stream.
+ */
+ final public void yyclose() throws java.io.IOException {
+ yy_atEOF = true; /* indicate end of file */
+ yy_endRead = yy_startRead; /* invalidate buffer */
+
+ if (yy_reader != null)
+ yy_reader.close();
+ }
+
+
+ /**
+ * Closes the current stream, and resets the
+ * scanner to read from a new input stream.
+ *
+ * All internal variables are reset, the old input stream
+ * <b>cannot</b> be reused (internal buffer is discarded and lost).
+ * Lexical state is set to <tt>YY_INITIAL</tt>.
+ *
+ * @param reader the new input stream
+ */
+ final public void yyreset(java.io.Reader reader) throws java.io.IOException {
+ yyclose();
+ yy_reader = reader;
+ yy_atBOL = true;
+ yy_atEOF = false;
+ yy_endRead = yy_startRead = 0;
+ yy_currentPos = yy_markedPos = yy_pushbackPos = 0;
+ yyline = yychar = yycolumn = 0;
+ yy_lexical_state = YYINITIAL;
+ }
+
+
+ /**
+ * Returns the current lexical state.
+ */
+ final public int yystate() {
+ return yy_lexical_state;
+ }
+
+
+ /**
+ * Enters a new lexical state
+ *
+ * @param newState the new lexical state
+ */
+ final public void yybegin(int newState) {
+ yy_lexical_state = newState;
+ }
+
+
+ /**
+ * Returns the text matched by the current regular expression.
+ */
+ final public String yytext() {
+ return new String( yy_buffer, yy_startRead, yy_markedPos-yy_startRead );
+ }
+
+
+ /**
+ * Returns the character at position <tt>pos</tt> from the
+ * matched text.
+ *
+ * It is equivalent to yytext().charAt(pos), but faster
+ *
+ * @param pos the position of the character to fetch.
+ * A value from 0 to yylength()-1.
+ *
+ * @return the character at position pos
+ */
+ final public char yycharat(int pos) {
+ return yy_buffer[yy_startRead+pos];
+ }
+
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ final public int yylength() {
+ return yy_markedPos-yy_startRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning.
+ *
+ * In a wellformed scanner (no or only correct usage of
+ * yypushback(int) and a match-all fallback rule) this method
+ * will only be called with things that "Can't Possibly Happen".
+ * If this method is called, something is seriously wrong
+ * (e.g. a JFlex bug producing a faulty scanner etc.).
+ *
+ * Usual syntax/scanner level error handling should be done
+ * in error fallback rules.
+ *
+ * @param errorCode the code of the errormessage to display
+ */
+ private void yy_ScanError(int errorCode) {
+ String message;
+ try {
+ message = YY_ERROR_MSG[errorCode];
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ message = YY_ERROR_MSG[YY_UNKNOWN_ERROR];
+ }
+
+ throw new Error(message);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number the number of characters to be read again.
+ * This number must not be greater than yylength()!
+ */
+ private void yypushback(int number) {
+ if ( number > yylength() )
+ yy_ScanError(YY_PUSHBACK_2BIG);
+
+ yy_markedPos -= number;
+ }
+
+
+ /**
+ * Contains user EOF-code, which will be executed exactly once,
+ * when the end of file is reached
+ */
+ private void yy_do_eof() throws java.io.IOException {
+ if (!yy_eof_done) {
+ yy_eof_done = true;
+ yyclose();
+ }
+ }
+
+
+ /**
+ * Resumes scanning until the next regular expression is matched,
+ * the end of input is encountered or an I/O-Error occurs.
+ *
+ * @return the next token
+ * @exception IOException if any I/O-Error occurs
+ */
+ public java_cup.runtime.Symbol next_token() throws java.io.IOException {
+ int yy_input;
+ int yy_action;
+
+ // cached fields:
+ int yy_currentPos_l;
+ int yy_startRead_l;
+ int yy_markedPos_l;
+ int yy_endRead_l = yy_endRead;
+ char [] yy_buffer_l = yy_buffer;
+ char [] yycmap_l = yycmap;
+
+ int [] yytrans_l = yytrans;
+ int [] yy_rowMap_l = yy_rowMap;
+ byte [] yy_attr_l = YY_ATTRIBUTE;
+
+ while (true) {
+ yy_markedPos_l = yy_markedPos;
+
+ boolean yy_r = false;
+ for (yy_currentPos_l = yy_startRead; yy_currentPos_l < yy_markedPos_l;
+ yy_currentPos_l++) {
+ switch (yy_buffer_l[yy_currentPos_l]) {
+ case '\u000B':
+ case '\u000C':
+ case '\u0085':
+ case '\u2028':
+ case '\u2029':
+ yyline++;
+ yycolumn = 0;
+ yy_r = false;
+ break;
+ case '\r':
+ yyline++;
+ yycolumn = 0;
+ yy_r = true;
+ break;
+ case '\n':
+ if (yy_r)
+ yy_r = false;
+ else {
+ yyline++;
+ yycolumn = 0;
+ }
+ break;
+ default:
+ yy_r = false;
+ yycolumn++;
+ }
+ }
+
+ if (yy_r) {
+ // peek one character ahead if it is \n (if we have counted one line too much)
+ boolean yy_peek;
+ if (yy_markedPos_l < yy_endRead_l)
+ yy_peek = yy_buffer_l[yy_markedPos_l] == '\n';
+ else if (yy_atEOF)
+ yy_peek = false;
+ else {
+ boolean eof = yy_refill();
+ yy_markedPos_l = yy_markedPos;
+ yy_buffer_l = yy_buffer;
+ if (eof)
+ yy_peek = false;
+ else
+ yy_peek = yy_buffer_l[yy_markedPos_l] == '\n';
+ }
+ if (yy_peek) yyline--;
+ }
+ yy_action = -1;
+
+ yy_startRead_l = yy_currentPos_l = yy_currentPos =
+ yy_startRead = yy_markedPos_l;
+
+ yy_state = yy_lexical_state;
+
+
+ yy_forAction: {
+ while (true) {
+
+ if (yy_currentPos_l < yy_endRead_l)
+ yy_input = yy_buffer_l[yy_currentPos_l++];
+ else if (yy_atEOF) {
+ yy_input = YYEOF;
+ break yy_forAction;
+ }
+ else {
+ // store back cached positions
+ yy_currentPos = yy_currentPos_l;
+ yy_markedPos = yy_markedPos_l;
+ boolean eof = yy_refill();
+ // get translated positions and possibly new buffer
+ yy_currentPos_l = yy_currentPos;
+ yy_markedPos_l = yy_markedPos;
+ yy_buffer_l = yy_buffer;
+ yy_endRead_l = yy_endRead;
+ if (eof) {
+ yy_input = YYEOF;
+ break yy_forAction;
+ }
+ else {
+ yy_input = yy_buffer_l[yy_currentPos_l++];
+ }
+ }
+ int yy_next = yytrans_l[ yy_rowMap_l[yy_state] + yycmap_l[yy_input] ];
+ if (yy_next == -1) break yy_forAction;
+ yy_state = yy_next;
+
+ int yy_attributes = yy_attr_l[yy_state];
+ if ( (yy_attributes & 1) == 1 ) {
+ yy_action = yy_state;
+ yy_markedPos_l = yy_currentPos_l;
+ if ( (yy_attributes & 8) == 8 ) break yy_forAction;
+ }
+
+ }
+ }
+
+ // store back cached position
+ yy_markedPos = yy_markedPos_l;
+
+ switch (yy_action) {
+
+ case 5:
+ { return symbol(DirectorySymbols.RIGHT_BRACKET, new String(yytext())); }
+ case 10: break;
+ case 1:
+ { throw new Error("Illegal character <"+yytext()+">"); }
+ case 11: break;
+ case 4:
+ { return symbol(DirectorySymbols.LEFT_BRACKET, new String(yytext())); }
+ case 12: break;
+ case 8:
+ { return symbol(DirectorySymbols.COLON, new String(yytext())); }
+ case 13: break;
+ case 7:
+ { return symbol(DirectorySymbols.CR); }
+ case 14: break;
+ case 6:
+ { return symbol(DirectorySymbols.NL); }
+ case 15: break;
+ case 3:
+ { return symbol(DirectorySymbols.IDENTIFIER, new String(yytext())); }
+ case 16: break;
+ case 2:
+ { return symbol(DirectorySymbols.SPACE, new String(yytext())); }
+ case 17: break;
+ default:
+ if (yy_input == YYEOF && yy_startRead == yy_currentPos) {
+ yy_atEOF = true;
+ yy_do_eof();
+ { return new java_cup.runtime.Symbol(DirectorySymbols.EOF); }
+ }
+ else {
+ yy_ScanError(YY_NO_MATCH);
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/src/org/noreply/fancydress/directory/parser/DirectoryMessage.java b/src/org/noreply/fancydress/directory/parser/DirectoryMessage.java
new file mode 100644
index 0000000..81ce6e2
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/parser/DirectoryMessage.java
@@ -0,0 +1,130 @@
+package org.noreply.fancydress.directory.parser;
+
+import java.util.*;
+
+/**
+ * Hold all sections and entries that are in a directory.
+ *
+ * This class holds all sections and entries of a directory. All data
+ * are stored in sections, which in turn hold entries of key:value pairs.
+ *
+ * The values themselves are not yet parsed, nor is the content
+ * cryptographically verified.
+ *
+ * The <code>DirectoryParser</code> returns an object of this class.
+ *
+ * @see org.noreply.fancydress.directory.Directory
+ * @see DirectoryParser
+ * @see DirectorySection
+ * @see DirectoryEntry
+ */
+public class DirectoryMessage implements Cloneable {
+ /**
+ * List of directory sections
+ */
+ private ArrayList sections;
+
+ /**
+ * Default constructor.
+ *
+ * Creates a new DirectoryMessage, adding <code>section</code> to
+ * the section list.
+ *
+ * @param section First section of the directory. It is used directly, not copied.
+ */
+ public DirectoryMessage(DirectorySection section) {
+ this();
+ sections.add(section);
+ }
+
+ /**
+ * Emty constructor.
+ *
+ * Creates a new DirectoryMessage.
+ */
+ public DirectoryMessage() {
+ sections = new ArrayList();
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * Creates a new DirectoryMessage copying all values (recursively) from
+ * <code>message</code>.
+ *
+ * @param message message to copy from.
+ */
+ public DirectoryMessage(DirectoryMessage message) {
+ this();
+ for (Iterator i = message.sections.iterator(); i.hasNext(); )
+ sections.add(new DirectorySection((DirectorySection)i.next()));
+ }
+
+ /**
+ * Add a section to this message.
+ *
+ * @param section Section to add. It is used directly, not copied.
+ */
+ public void addSection(DirectorySection section) {
+ sections.add(section);
+ }
+
+ /**
+ * Blind a value in order to verify or create a signature.
+ *
+ * @param section Section in which to blind the entry named.
+ * @param entry Entry to blind.
+ * @return The number of entries blinded.
+ */
+ public int blindValue(String section, String entry) {
+ int count = 0;
+ for (Iterator i = sections.iterator(); i.hasNext(); ) {
+ DirectorySection s = (DirectorySection) i.next();
+ if (s.getName().equals(section))
+ count += s.blindValue(entry);
+ };
+ return count;
+ }
+
+ /**
+ * Return the first section with that name
+ *
+ * @param section Section to return.
+ * @return first DirectorySection that matches the name or null.
+ */
+ public DirectorySection getSection(String section) {
+ int count = 0;
+ for (Iterator i = sections.iterator(); i.hasNext(); ) {
+ DirectorySection s = (DirectorySection) i.next();
+ if (s.getName().equals(section))
+ return s;
+ };
+ return null;
+ }
+
+ /**
+ * Return an iterator over the sections.
+ *
+ * @return Iterator over sections.
+ */
+ public Iterator getSectionsIterator() {
+ return sections.iterator();
+ }
+
+ /**
+ * Returns a string representation of the directory.
+ *
+ * This representation can be parsed again using the directory parser.
+ *
+ * @return a string representation of the object.
+ */
+ public String toString() {
+ StringBuffer strbuf = new StringBuffer();
+
+ for (Iterator i = sections.iterator(); i.hasNext(); ) {
+ Object o = i.next();
+ strbuf.append(o.toString());
+ }
+ return strbuf.toString();
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/parser/DirectoryParser.cup b/src/org/noreply/fancydress/directory/parser/DirectoryParser.cup
new file mode 100644
index 0000000..1aed682
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/parser/DirectoryParser.cup
@@ -0,0 +1,141 @@
+package org.noreply.fancydress.directory.parser;
+
+import java_cup.runtime.*;
+
+parser code {:
+ /* FIXME */
+ /* Change the method report_error so it will display the line and
+ column of where the error occurred in the input as well as the
+ reason for the error which is passed into the method in the
+ String 'message'. */
+ public void report_error(String message, Object info) {
+
+ /* Create a StringBuffer called 'm' with the string 'Error' in it. */
+ StringBuffer m = new StringBuffer("Error");
+
+ /* Check if the information passed to the method is the same
+ type as the type java_cup.runtime.Symbol. */
+ if (info instanceof java_cup.runtime.Symbol) {
+ /* Declare a java_cup.runtime.Symbol object 's' with the
+ information in the object info that is being typecasted
+ as a java_cup.runtime.Symbol object. */
+ java_cup.runtime.Symbol s = ((java_cup.runtime.Symbol) info);
+
+ /* Check if the line number in the input is greater or
+ equal to zero. */
+ if (s.left >= 0) {
+ /* Add to the end of the StringBuffer error message
+ the line number of the error in the input. */
+ m.append(" in line "+(s.left+1));
+ /* Check if the column number in the input is greater
+ or equal to zero. */
+ if (s.right >= 0)
+ /* Add to the end of the StringBuffer error message
+ the column number of the error in the input. */
+ m.append(", column "+(s.right+1));
+ }
+ }
+
+ /* Add to the end of the StringBuffer error message created in
+ this method the message that was passed into this method. */
+ m.append(" : "+message);
+
+ /* Print the contents of the StringBuffer 'm', which contains
+ an error message, out on a line. */
+ System.err.println(m);
+ }
+
+ /* Change the method report_fatal_error so when it reports a fatal
+ error it will display the line and column number of where the
+ fatal error occurred in the input as well as the reason for the
+ fatal error which is passed into the method in the object
+ 'message' and then exit.*/
+ public void report_fatal_error(String message, Object info) {
+ report_error(message, info);
+ System.exit(1);
+ }
+:};
+
+terminal NL, CR;
+terminal String SPACE, IDENTIFIER, LEFT_BRACKET, RIGHT_BRACKET, COLON;
+
+non terminal DirectoryEntry Entry;
+non terminal DirectorySection Section;
+non terminal DirectoryMessage Message;
+non terminal String Header;
+non terminal String OptValue, Value, NonSpaceValueChar, ValueChar, NonSpaceValue;
+non terminal String OptSpace;
+non terminal String EndOfLine, OptSpaceEndOfLine;
+
+start with Message;
+
+ Message ::=
+ Section:s
+ {: RESULT = new DirectoryMessage(s); :}
+ |
+ Message:m Section:s
+ {: m.addSection(s); RESULT = m; :}
+ ;
+ Section ::=
+ Header:h
+ {: RESULT = new DirectorySection(h); :}
+ |
+ Section:s Entry:e
+ {: s.addEntry(e); RESULT = s; :}
+ ;
+ Header ::=
+ LEFT_BRACKET IDENTIFIER:i RIGHT_BRACKET OptSpace EndOfLine
+ {: RESULT = i; :}
+ ;
+ Entry ::=
+ IDENTIFIER:i COLON SPACE OptValue:v EndOfLine
+ {: RESULT = new DirectoryEntry(i, v.trim()); :}
+ ;
+
+ OptValue ::=
+ Value:v OptSpace
+ {: RESULT = v; :}
+ |
+ {: RESULT = new String(""); :}
+ ;
+ Value ::=
+ NonSpaceValue:v
+ {: RESULT = v; :}
+ |
+ Value:v1 SPACE:c NonSpaceValue:v2
+ {: RESULT = new String(v1+c+v2); :}
+ ;
+ NonSpaceValue ::=
+ NonSpaceValueChar:c
+ {: RESULT = c; :}
+ |
+ NonSpaceValue:v NonSpaceValueChar:c
+ {: RESULT = new String(v+c); :}
+ ;
+ NonSpaceValueChar ::=
+ IDENTIFIER:c
+ {: RESULT = c; :}
+ |
+ COLON:c
+ {: RESULT = c; :}
+ |
+ LEFT_BRACKET:c
+ {: RESULT = c; :}
+ |
+ RIGHT_BRACKET:c
+ {: RESULT = c; :}
+ ;
+
+
+ OptSpace ::=
+ SPACE
+ |
+ ;
+
+ EndOfLine ::=
+ NL
+ |
+ CR
+ |
+ CR NL
+ ;
diff --git a/src/org/noreply/fancydress/directory/parser/DirectoryParser.java b/src/org/noreply/fancydress/directory/parser/DirectoryParser.java
new file mode 100644
index 0000000..2fa66ea
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/parser/DirectoryParser.java
@@ -0,0 +1,477 @@
+
+//----------------------------------------------------
+// The following code was generated by CUP v0.10k
+// Sun Oct 05 01:55:08 CEST 2003
+//----------------------------------------------------
+
+package org.noreply.fancydress.directory.parser;
+
+import java_cup.runtime.*;
+
+/** CUP v0.10k generated parser.
+ * @version Sun Oct 05 01:55:08 CEST 2003
+ */
+public class DirectoryParser extends java_cup.runtime.lr_parser {
+
+ /** Default constructor. */
+ public DirectoryParser() {super();}
+
+ /** Constructor which sets the default scanner. */
+ public DirectoryParser(java_cup.runtime.Scanner s) {super(s);}
+
+ /** Production table. */
+ protected static final short _production_table[][] =
+ unpackFromStrings(new String[] {
+ "\000\026\000\002\002\004\000\002\005\003\000\002\005" +
+ "\004\000\002\004\003\000\002\004\004\000\002\006\007" +
+ "\000\002\003\007\000\002\007\004\000\002\007\002\000" +
+ "\002\010\003\000\002\010\005\000\002\013\003\000\002" +
+ "\013\004\000\002\011\003\000\002\011\003\000\002\011" +
+ "\003\000\002\011\003\000\002\014\003\000\002\014\002" +
+ "\000\002\015\003\000\002\015\003\000\002\015\004" });
+
+ /** Access to production table. */
+ public short[][] production_table() {return _production_table;}
+
+ /** Parse-action table. */
+ protected static final short[][] _action_table =
+ unpackFromStrings(new String[] {
+ "\000\040\000\004\010\005\001\002\000\006\002\042\010" +
+ "\005\001\002\000\004\007\034\001\002\000\010\002\000" +
+ "\007\011\010\000\001\002\000\010\002\ufffe\007\ufffe\010" +
+ "\ufffe\001\002\000\010\002\ufffd\007\ufffd\010\ufffd\001\002" +
+ "\000\004\012\012\001\002\000\004\006\013\001\002\000" +
+ "\016\004\ufff9\005\ufff9\007\021\010\020\011\015\012\022" +
+ "\001\002\000\020\004\ufff8\005\ufff8\006\ufff8\007\021\010" +
+ "\020\011\015\012\022\001\002\000\020\004\ufff1\005\ufff1" +
+ "\006\ufff1\007\ufff1\010\ufff1\011\ufff1\012\ufff1\001\002\000" +
+ "\010\004\uffef\005\uffef\006\030\001\002\000\020\004\ufff6" +
+ "\005\ufff6\006\ufff6\007\ufff6\010\ufff6\011\ufff6\012\ufff6\001" +
+ "\002\000\020\004\ufff2\005\ufff2\006\ufff2\007\ufff2\010\ufff2" +
+ "\011\ufff2\012\ufff2\001\002\000\020\004\ufff4\005\ufff4\006" +
+ "\ufff4\007\ufff4\010\ufff4\011\ufff4\012\ufff4\001\002\000\020" +
+ "\004\ufff3\005\ufff3\006\ufff3\007\ufff3\010\ufff3\011\ufff3\012" +
+ "\ufff3\001\002\000\006\004\025\005\026\001\002\000\010" +
+ "\002\ufffb\007\ufffb\010\ufffb\001\002\000\010\002\uffee\007" +
+ "\uffee\010\uffee\001\002\000\012\002\uffed\004\027\007\uffed" +
+ "\010\uffed\001\002\000\010\002\uffec\007\uffec\010\uffec\001" +
+ "\002\000\016\004\ufff0\005\ufff0\007\021\010\020\011\015" +
+ "\012\022\001\002\000\006\004\ufffa\005\ufffa\001\002\000" +
+ "\020\004\ufff7\005\ufff7\006\ufff7\007\021\010\020\011\015" +
+ "\012\022\001\002\000\020\004\ufff5\005\ufff5\006\ufff5\007" +
+ "\ufff5\010\ufff5\011\ufff5\012\ufff5\001\002\000\004\011\035" +
+ "\001\002\000\010\004\uffef\005\uffef\006\036\001\002\000" +
+ "\006\004\ufff0\005\ufff0\001\002\000\006\004\025\005\026" +
+ "\001\002\000\010\002\ufffc\007\ufffc\010\ufffc\001\002\000" +
+ "\010\002\uffff\007\011\010\uffff\001\002\000\004\002\001" +
+ "\001\002" });
+
+ /** Access to parse-action table. */
+ public short[][] action_table() {return _action_table;}
+
+ /** <code>reduce_goto</code> table. */
+ protected static final short[][] _reduce_table =
+ unpackFromStrings(new String[] {
+ "\000\040\000\010\004\005\005\003\006\006\001\001\000" +
+ "\006\004\040\006\006\001\001\000\002\001\001\000\004" +
+ "\003\007\001\001\000\002\001\001\000\002\001\001\000" +
+ "\002\001\001\000\002\001\001\000\012\007\022\010\015" +
+ "\011\016\013\013\001\001\000\004\011\032\001\001\000" +
+ "\002\001\001\000\004\014\030\001\001\000\002\001\001" +
+ "\000\002\001\001\000\002\001\001\000\002\001\001\000" +
+ "\004\015\023\001\001\000\002\001\001\000\002\001\001" +
+ "\000\002\001\001\000\002\001\001\000\006\011\016\013" +
+ "\031\001\001\000\002\001\001\000\004\011\032\001\001" +
+ "\000\002\001\001\000\002\001\001\000\004\014\036\001" +
+ "\001\000\002\001\001\000\004\015\037\001\001\000\002" +
+ "\001\001\000\004\003\007\001\001\000\002\001\001" });
+
+ /** Access to <code>reduce_goto</code> table. */
+ public short[][] reduce_table() {return _reduce_table;}
+
+ /** Instance of action encapsulation class. */
+ protected CUP$DirectoryParser$actions action_obj;
+
+ /** Action encapsulation object initializer. */
+ protected void init_actions()
+ {
+ action_obj = new CUP$DirectoryParser$actions(this);
+ }
+
+ /** Invoke a user supplied parse action. */
+ public java_cup.runtime.Symbol do_action(
+ int act_num,
+ java_cup.runtime.lr_parser parser,
+ java.util.Stack stack,
+ int top)
+ throws java.lang.Exception
+ {
+ /* call code in generated class */
+ return action_obj.CUP$DirectoryParser$do_action(act_num, parser, stack, top);
+ }
+
+ /** Indicates start state. */
+ public int start_state() {return 0;}
+ /** Indicates start production. */
+ public int start_production() {return 0;}
+
+ /** <code>EOF</code> Symbol index. */
+ public int EOF_sym() {return 0;}
+
+ /** <code>error</code> Symbol index. */
+ public int error_sym() {return 1;}
+
+
+
+ /* FIXME */
+ /* Change the method report_error so it will display the line and
+ column of where the error occurred in the input as well as the
+ reason for the error which is passed into the method in the
+ String 'message'. */
+ public void report_error(String message, Object info) {
+
+ /* Create a StringBuffer called 'm' with the string 'Error' in it. */
+ StringBuffer m = new StringBuffer("Error");
+
+ /* Check if the information passed to the method is the same
+ type as the type java_cup.runtime.Symbol. */
+ if (info instanceof java_cup.runtime.Symbol) {
+ /* Declare a java_cup.runtime.Symbol object 's' with the
+ information in the object info that is being typecasted
+ as a java_cup.runtime.Symbol object. */
+ java_cup.runtime.Symbol s = ((java_cup.runtime.Symbol) info);
+
+ /* Check if the line number in the input is greater or
+ equal to zero. */
+ if (s.left >= 0) {
+ /* Add to the end of the StringBuffer error message
+ the line number of the error in the input. */
+ m.append(" in line "+(s.left+1));
+ /* Check if the column number in the input is greater
+ or equal to zero. */
+ if (s.right >= 0)
+ /* Add to the end of the StringBuffer error message
+ the column number of the error in the input. */
+ m.append(", column "+(s.right+1));
+ }
+ }
+
+ /* Add to the end of the StringBuffer error message created in
+ this method the message that was passed into this method. */
+ m.append(" : "+message);
+
+ /* Print the contents of the StringBuffer 'm', which contains
+ an error message, out on a line. */
+ System.err.println(m);
+ }
+
+ /* Change the method report_fatal_error so when it reports a fatal
+ error it will display the line and column number of where the
+ fatal error occurred in the input as well as the reason for the
+ fatal error which is passed into the method in the object
+ 'message' and then exit.*/
+ public void report_fatal_error(String message, Object info) {
+ report_error(message, info);
+ System.exit(1);
+ }
+
+}
+
+/** Cup generated class to encapsulate user supplied action code.*/
+class CUP$DirectoryParser$actions {
+ private final DirectoryParser parser;
+
+ /** Constructor */
+ CUP$DirectoryParser$actions(DirectoryParser parser) {
+ this.parser = parser;
+ }
+
+ /** Method with the actual generated action code. */
+ public final java_cup.runtime.Symbol CUP$DirectoryParser$do_action(
+ int CUP$DirectoryParser$act_num,
+ java_cup.runtime.lr_parser CUP$DirectoryParser$parser,
+ java.util.Stack CUP$DirectoryParser$stack,
+ int CUP$DirectoryParser$top)
+ throws java.lang.Exception
+ {
+ /* Symbol object for return from actions */
+ java_cup.runtime.Symbol CUP$DirectoryParser$result;
+
+ /* select the action based on the action number */
+ switch (CUP$DirectoryParser$act_num)
+ {
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 21: // EndOfLine ::= CR NL
+ {
+ String RESULT = null;
+
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(11/*EndOfLine*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 20: // EndOfLine ::= CR
+ {
+ String RESULT = null;
+
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(11/*EndOfLine*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 19: // EndOfLine ::= NL
+ {
+ String RESULT = null;
+
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(11/*EndOfLine*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 18: // OptSpace ::=
+ {
+ String RESULT = null;
+
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(10/*OptSpace*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 17: // OptSpace ::= SPACE
+ {
+ String RESULT = null;
+
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(10/*OptSpace*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 16: // NonSpaceValueChar ::= RIGHT_BRACKET
+ {
+ String RESULT = null;
+ int cleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int cright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String c = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = c;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(7/*NonSpaceValueChar*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 15: // NonSpaceValueChar ::= LEFT_BRACKET
+ {
+ String RESULT = null;
+ int cleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int cright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String c = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = c;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(7/*NonSpaceValueChar*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 14: // NonSpaceValueChar ::= COLON
+ {
+ String RESULT = null;
+ int cleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int cright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String c = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = c;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(7/*NonSpaceValueChar*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 13: // NonSpaceValueChar ::= IDENTIFIER
+ {
+ String RESULT = null;
+ int cleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int cright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String c = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = c;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(7/*NonSpaceValueChar*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 12: // NonSpaceValue ::= NonSpaceValue NonSpaceValueChar
+ {
+ String RESULT = null;
+ int vleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left;
+ int vright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).right;
+ String v = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).value;
+ int cleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int cright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String c = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = new String(v+c);
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(9/*NonSpaceValue*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 11: // NonSpaceValue ::= NonSpaceValueChar
+ {
+ String RESULT = null;
+ int cleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int cright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String c = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = c;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(9/*NonSpaceValue*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 10: // Value ::= Value SPACE NonSpaceValue
+ {
+ String RESULT = null;
+ int v1left = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-2)).left;
+ int v1right = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-2)).right;
+ String v1 = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-2)).value;
+ int cleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left;
+ int cright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).right;
+ String c = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).value;
+ int v2left = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int v2right = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String v2 = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = new String(v1+c+v2);
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(6/*Value*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 9: // Value ::= NonSpaceValue
+ {
+ String RESULT = null;
+ int vleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int vright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String v = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = v;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(6/*Value*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 8: // OptValue ::=
+ {
+ String RESULT = null;
+ RESULT = new String("");
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(5/*OptValue*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 7: // OptValue ::= Value OptSpace
+ {
+ String RESULT = null;
+ int vleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left;
+ int vright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).right;
+ String v = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).value;
+ RESULT = v;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(5/*OptValue*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 6: // Entry ::= IDENTIFIER COLON SPACE OptValue EndOfLine
+ {
+ DirectoryEntry RESULT = null;
+ int ileft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-4)).left;
+ int iright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-4)).right;
+ String i = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-4)).value;
+ int vleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left;
+ int vright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).right;
+ String v = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).value;
+ RESULT = new DirectoryEntry(i, v.trim());
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(1/*Entry*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-4)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 5: // Header ::= LEFT_BRACKET IDENTIFIER RIGHT_BRACKET OptSpace EndOfLine
+ {
+ String RESULT = null;
+ int ileft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-3)).left;
+ int iright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-3)).right;
+ String i = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-3)).value;
+ RESULT = i;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(4/*Header*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-4)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 4: // Section ::= Section Entry
+ {
+ DirectorySection RESULT = null;
+ int sleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left;
+ int sright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).right;
+ DirectorySection s = (DirectorySection)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).value;
+ int eleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int eright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ DirectoryEntry e = (DirectoryEntry)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ s.addEntry(e); RESULT = s;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(2/*Section*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 3: // Section ::= Header
+ {
+ DirectorySection RESULT = null;
+ int hleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int hright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ String h = (String)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = new DirectorySection(h);
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(2/*Section*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 2: // Message ::= Message Section
+ {
+ DirectoryMessage RESULT = null;
+ int mleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left;
+ int mright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).right;
+ DirectoryMessage m = (DirectoryMessage)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).value;
+ int sleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int sright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ DirectorySection s = (DirectorySection)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ m.addSection(s); RESULT = m;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(3/*Message*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 1: // Message ::= Section
+ {
+ DirectoryMessage RESULT = null;
+ int sleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left;
+ int sright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right;
+ DirectorySection s = (DirectorySection)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).value;
+ RESULT = new DirectoryMessage(s);
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(3/*Message*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ return CUP$DirectoryParser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 0: // $START ::= Message EOF
+ {
+ Object RESULT = null;
+ int start_valleft = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left;
+ int start_valright = ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).right;
+ DirectoryMessage start_val = (DirectoryMessage)((java_cup.runtime.Symbol) CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).value;
+ RESULT = start_val;
+ CUP$DirectoryParser$result = new java_cup.runtime.Symbol(0/*$START*/, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DirectoryParser$stack.elementAt(CUP$DirectoryParser$top-0)).right, RESULT);
+ }
+ /* ACCEPT */
+ CUP$DirectoryParser$parser.done_parsing();
+ return CUP$DirectoryParser$result;
+
+ /* . . . . . .*/
+ default:
+ throw new Exception(
+ "Invalid action number found in internal parse table");
+
+ }
+ }
+}
+
diff --git a/src/org/noreply/fancydress/directory/parser/DirectorySection.java b/src/org/noreply/fancydress/directory/parser/DirectorySection.java
new file mode 100644
index 0000000..f27ee86
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/parser/DirectorySection.java
@@ -0,0 +1,129 @@
+package org.noreply.fancydress.directory.parser;
+
+import java.util.*;
+
+/**
+ * Hold entries of a directory section.
+ *
+ * This class holds all entries of a directory section. All entries are
+ * key:value pairs.
+ *
+ * The values themselves are not yet parsed, nor is the content
+ * cryptographically verified.
+ *
+ * A <code>DirectoryMessage</code> is made up of instances of this class.
+ *
+ * @see org.noreply.fancydress.directory.Directory
+ * @see DirectoryParser
+ * @see DirectoryMessage
+ * @see DirectoryEntry
+ */
+public class DirectorySection {
+ /**
+ * name of this section
+ */
+ private String name;
+ /**
+ * List of entries
+ */
+ private ArrayList entries;
+
+ /**
+ * Default constructor.
+ *
+ * Creates a new DirectorySection with the name passed as parameter.
+ *
+ * @param name name of this section
+ */
+ public DirectorySection(String name) {
+ this.name = name;
+ entries = new ArrayList();
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * Creates a new DirectorySection copying all values (recursively) from
+ * <code>section</code>.
+ *
+ * @param section section to copy from.
+ */
+ public DirectorySection(DirectorySection section) {
+ name = new String(section.name);
+ entries = new ArrayList();
+ for (Iterator i = section.entries.iterator(); i.hasNext(); )
+ entries.add(new DirectoryEntry((DirectoryEntry)i.next()));
+ }
+
+ /**
+ * Add an entry to this section.
+ *
+ * @param entry Entry to add. It is used directly, not copied.
+ */
+ public void addEntry(DirectoryEntry entry) {
+ entries.add(entry);
+ }
+
+ /**
+ * Blint a value in order to verify or create a signature.
+ *
+ * @param entry Entry to blind.
+ * @return The number of entries blinded.
+ */
+ public int blindValue(String entry) {
+ int count = 0;
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ DirectoryEntry e = (DirectoryEntry) i.next();
+ if (e.getName().equals(entry)) {
+ e.blindValue();
+ count ++;
+ }
+ }
+
+ return count;
+ }
+
+ /**
+ * Return the first entry with that name
+ *
+ * @param entry Entry to return.
+ * @return first DirectoryEntry that matches the name or null.
+ */
+ public DirectoryEntry getEntry(String entry) {
+ int count = 0;
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ DirectoryEntry e = (DirectoryEntry) i.next();
+ if (e.getName().equals(entry))
+ return e;
+ };
+ return null;
+ }
+
+
+ /**
+ * Returns a string representation of this section.
+ *
+ * @return a string representation of the object.
+ */
+ public String toString() {
+ StringBuffer strbuf = new StringBuffer();
+ strbuf.append("[");
+ strbuf.append(name);
+ strbuf.append("]\n");
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ Object o = i.next();
+ strbuf.append(o.toString());
+ strbuf.append("\n");
+ }
+ return strbuf.toString();
+ }
+
+ /**
+ * Returns the name of this section.
+ *
+ * @return name of this section.
+ */
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/org/noreply/fancydress/directory/parser/DirectorySymbols.java b/src/org/noreply/fancydress/directory/parser/DirectorySymbols.java
new file mode 100644
index 0000000..481ad2f
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/parser/DirectorySymbols.java
@@ -0,0 +1,22 @@
+
+//----------------------------------------------------
+// The following code was generated by CUP v0.10k
+// Sun Oct 05 01:55:07 CEST 2003
+//----------------------------------------------------
+
+package org.noreply.fancydress.directory.parser;
+
+/** CUP generated class containing symbol constants. */
+public class DirectorySymbols {
+ /* terminals */
+ public static final int CR = 3;
+ public static final int COLON = 8;
+ public static final int EOF = 0;
+ public static final int RIGHT_BRACKET = 7;
+ public static final int NL = 2;
+ public static final int error = 1;
+ public static final int SPACE = 4;
+ public static final int IDENTIFIER = 5;
+ public static final int LEFT_BRACKET = 6;
+}
+