X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fibex%2Fmail%2FMessage.java;h=7b8ba4f176080aa59f671241245e2840a9e0de4b;hb=7b9bfcdbcf31da075cc0e8195a294964e8023fe1;hp=882ca9fe699e9b8530569832122bf8aabd324f8f;hpb=440e9bee20802bfbf97061b01f950448d3baf8f5;p=org.ibex.mail.git diff --git a/src/org/ibex/mail/Message.java b/src/org/ibex/mail/Message.java index 882ca9f..7b8ba4f 100644 --- a/src/org/ibex/mail/Message.java +++ b/src/org/ibex/mail/Message.java @@ -13,8 +13,9 @@ import java.util.*; import java.net.*; import java.io.*; -// FIXME: messages must NEVER contain 8-bit binary data; this is a violation of IMAP -// FIXME: RFC822 1,000-char limit per line [soft line limit (suggested): 78 chars / hard line limit: 998 chars] +// FIXME: body constraints (how to enforce?) +// - messages must NEVER contain 8-bit binary data; this is a violation of IMAP +// - RFC822 1,000-char limit per line [soft line limit (suggested): 78 chars / hard line limit: 998 chars] // FEATURE: PGP-signature-parsing // FEATURE: mailing list header parsing (?) @@ -43,12 +44,13 @@ public class Message extends MIME.Part { public static Message newMessage(Fountain in) throws Malformed { return new Message(in); } + /* public Message reply(Fountain in, Address from, boolean includeReInSubject) throws Malformed { - /* Address to = null; if (to==null) to = Address.parse(headers.get("reply-to")); if (to==null) to = Address.parse(headers.get("from")); if (to==null) to = envelopeFrom; + if (to==null) throw new Malformed("cannot reply to a message without a return address"); Message ret = newMessage(in, from, to); ret.headers.put("In-Reply-To", messageid); String references = headers.get("references"); @@ -56,10 +58,8 @@ public class Message extends MIME.Part { if (includeReInSubject && subject!=null && !subject.toLowerCase().trim().startsWith("re:")) headers.put("subject", "Re: "+subject); return ret; - */ - // FIXME - return null; } + */ // FIXME //public static Message newMessage(Headers headers, Fountain body, Address from, Address to) throws Malformed { @@ -90,6 +90,7 @@ public class Message extends MIME.Part { private Message(Fountain in) throws Malformed { super(in); + this.envelopeTo = headers.get("Envelope-To") != null ? Address.parse(headers.get("Envelope-To")) : null; this.envelopeFrom = headers.get("Return-Path") != null ? Address.parse(headers.get("Return-Path")) : null; this.to = headers.get("To") != null ? Address.parse(headers.get("To")) : this.envelopeTo; @@ -100,21 +101,52 @@ public class Message extends MIME.Part { this.cc = Address.list(headers.get("Cc")); this.bcc = Address.list(headers.get("Bcc")); this.date = parseDate(headers.get("Date")) == null ? new Date() : parseDate(headers.get("Date")); + + // reenable this once whitelisting is moved out of javascript + //if (this.messageid==null) + //throw new RuntimeException("every RFC2822 message must have a Message-ID: header"); + + /* + // synthesize a message-id if not provided + this.messageid = headers.get("Message-Id") == null ? generateFreshMessageId(sha1(in.getStream())) : headers.get("Message-Id"); + if (headers.get("Message-Id") == null) { + headers = headers.set("Message-Id", this.messageid); + Log.warn(Message.class, "synthesizing message-id for " + summary()); + } + */ + this.arrival = this.date; // FIXME wrong; grab this from traces? } + /* + private static String sha1(Stream stream) { + SHA1 sha1 = new SHA1(); + byte[] b = new byte[1024]; + while(true) { + int numread = stream.read(b, 0, b.length); + if (numread == -1) break; + sha1.update(b, 0, numread); + } + byte[] results = new byte[sha1.getDigestSize()]; + sha1.doFinal(results, 0); + return new String(Encode.toBase64(results)); + } + */ + // Helpers ///////////////////////////////////////////////////////////////////////////// // http://www.jwz.org/doc/mid.html private static final Random random = new Random(); public static String generateFreshMessageId() { + return generateFreshMessageId(Base36.encode(System.currentTimeMillis())+'.'+ + Base36.encode(random.nextLong())); + } + public static String generateFreshMessageId(String seed) { StringBuffer ret = new StringBuffer(); ret.append('<'); - ret.append(Base36.encode(System.currentTimeMillis())); - ret.append('.'); - ret.append(Base36.encode(random.nextLong())); - ret.append('.'); + ret.append(seed); + ret.append('@'); try { ret.append(InetAddress.getLocalHost().getHostName()); } catch (UnknownHostException e) { /* DELIBERATE */ } ret.append('>'); return ret.toString(); @@ -141,6 +173,7 @@ public class Message extends MIME.Part { }); String error = + "\r\n"+ "Hi. This is the Ibex Mail Server. I'm afraid I wasn't able to deliver\r\n"+ "your message to the following addresses. This is a permanent error;\r\n"+ "I've given up. Sorry it didn't work out\r\n."+ @@ -152,7 +185,7 @@ public class Message extends MIME.Part { "\r\n"; try { - return newMessage(new Fountain.Concatenate(new Fountain.StringFountain(h.getString()+"\r\n"+error), getBody())); + return newMessage(Fountain.Util.concat(h, Fountain.Util.create(error), getBody())); } catch (Message.Malformed e) { Log.error(this, "caught Message.Malformed in Message.bounce(); this should never happen"); Log.error(this, e); @@ -160,8 +193,8 @@ public class Message extends MIME.Part { } } - public String toString() { throw new RuntimeException("Message.toString() called"); } - public String summary() { return "[" + envelopeFrom + " -> " + envelopeTo + "] " + subject; } + public String toString() { throw new RuntimeException("Message.toString() called"); } + public final String summary() { return "[" + envelopeFrom + " -> " + envelopeTo + "] " + subject; } public static class Malformed extends MailException { public Malformed(String s) { super(s); } } }