static { new Thread() { public void run() { Outgoing.runq(); } }.start(); }
+ public static class SMTPException extends MailException {
+ int code;
+ String message;
+ public SMTPException(String s) {
+ code = Integer.parseInt(s.substring(0, s.indexOf(' ')));
+ message = s.substring(s.indexOf(' ')+1);
+ }
+ public String toString() { return "SMTP " + code + ": " + message; }
+ public String getMessage() { return toString(); }
+ }
+
// Server //////////////////////////////////////////////////////////////////////////////
public static class Server implements Worker {
public void handleRequest(Connection conn) {
- Log.error(this, "accepted...");
conn.setTimeout(5 * 60 * 1000);
+ conn.setNewline("\r\n");
conn.println("220 " + conn.vhost + " SMTP " + this.getClass().getName());
Address from = null;
Vector to = new Vector();
String body = buf.toString();
Message m = null;
for(int i=0; i<to.size(); i++) {
- m = new Message(new Stream(body), new Message.Envelope(from, (Address)to.elementAt(i), new Date()));
- if (!m.envelope.to.isLocal()) Outgoing.accept(m);
+ m = Message.newMessage(new Stream(body), from, (Address)to.elementAt(i));
+ if (!m.envelopeTo.isLocal()) Outgoing.accept(m);
else Target.root.accept(m);
}
if (m != null) Log.info(SMTP.class, "accepted message: " + m.summary());
conn.close();
return;
}
- } else { conn.println("500 unrecognized command"); }
- } catch (Message.Malformed e) { conn.println("501 " + e.toString()); /* FIXME could be wrong code */ }
+ } else { conn.println("500 unrecognized command"); }
+ } catch (Message.Malformed e) { conn.println("501 " + e.toString()); }
}
}
public static boolean attempt(Message m) throws IOException {
InetAddress[] mx = getMailExchangerIPs(m.envelope.to.host);
if (mx.length == 0) {
- Log.warn(SMTP.Outgoing.class, "could not resolve " + m.envelope.to.host + "; bouncing it\n" + m.summary());
- accept(m.bounce("could not resolve " + m.envelope.to.host));
+ Log.warn(SMTP.Outgoing.class, "could not resolve " + m.envelopeTo.host + "; bouncing it\n" + m.summary());
+ accept(m.bounce("could not resolve " + m.envelopeTo.host));
return true;
}
if (new Date().getTime() - m.envelope.arrival.getTime() > 1000 * 60 * 60 * 24 * 5) {
private static void check(String s, Connection conn) {
while (s.charAt(3) == '-') s = conn.readln();
- if (s.startsWith("4")||s.startsWith("5")) throw new MailException(s);
+ if (s.startsWith("4")||s.startsWith("5")) throw new SMTPException(s);
}
private static boolean attempt(final Message m, final InetAddress mx) {
boolean accepted = false;
Connection conn = null;
try {
- Log.info(SMTP.Outgoing.class, "connecting to " + mx + "...");
+ Log.note("connecting to " + mx + "...");
conn = new Connection(new Socket(mx, 25), InetAddress.getLocalHost().getHostName());
+ conn.setNewline("\r\n");
conn.setTimeout(60 * 1000);
- Log.info(SMTP.Outgoing.class, " connected");
+ Log.note(" connected");
check(conn.readln(), conn); // banner
conn.println("HELO " + conn.vhost); check(conn.readln(), conn);
conn.println("MAIL FROM:<" + m.envelope.from.user + "@" + m.envelope.from.host+">"); check(conn.readln(), conn);
conn.println(m.toString());
conn.println(".");
check(conn.readln(), conn);
- Log.info(SMTP.Outgoing.class, " success: message accepted by " + mx);
+ Log.warn(SMTP.Outgoing.class, "success: " + mx + " accepted " + m.summary());
accepted = true;
conn.close();
} catch (Exception e) {
public void init(final Prevayler prevayler) throws IOException {
dir.mkdirs();
+ long time = System.currentTimeMillis();
Log.info(this, "initializing maildir " + dir.getParent());
// Drop entries whose files have vanished
}
// Take a snapshot for posterity
- Log.info(this, " done initializing maildir " + dir.getParent());
+ if (System.currentTimeMillis() - time > 1000 * 5)
+ Log.info(this, " done initializing maildir " + dir.getParent());
new Thread() { public void run() {
try { prevayler.takeSnapshot(); } catch (Exception e) { Log.error(this, e); } } }.start();
}
public static Transaction create(File f) throws IOException {
final boolean seen = f.lastModified() == MAGIC_DATE;
- Log.error(Entry.class, "create with seen = " + seen);
final String name = f.getName();
final byte[] header = new MIME.Headers(new Stream(new FileInputStream(f)), true).toString().getBytes();
return new Transaction() {
public int uidNext() { return cache.uidNext(); }
public synchronized void add(Message message, int flags) {
- Log.info(path, message.summary());
try {
String name, fullname; File target, f;
for(int i = cache.uidNext(); ; i++) {
if ((flags & Mailbox.Flag.SEEN) == Mailbox.Flag.SEEN) f.setLastModified(MAGIC_DATE);
prevayler.execute(Cache.Entry.create(f));
} catch (IOException e) { throw new MailException.IOException(e); }
+ Log.info(this, path + " <= " + message.summary());
}
private class Iterator extends Mailbox.Default.Iterator {