dcc
vipul
spamAssassin
+ vacation
target.
dead -- drops the message on the floor; it vanishes without a trace
dir[path] -- uses the directory [path] as a naive file-based storage area
send -- sends the outgoing message via smtp
bounce(message) -- bounces the message
- vacation
darcs(repo)
procmail(procmailrc)
lmtp(path)
public void dump(OutputStream os) throws IOException {
Writer w = new OutputStreamWriter(os);
w.write(allHeaders);
+ w.write("X-IbexMail-EnvelopeFrom: " + envelopeFrom + "\r\n");
+ w.write("X-IbexMail-EnvelopeTo: "); for(int i=0; i<envelopeTo.length; i++) w.write(envelopeTo[i] + " "); w.write("\r\n");
w.write("\r\n");
w.write(body);
w.flush();
}
if (s.indexOf(':') == -1) throw new Malformed("Header line does not contain colon: " + s);
key = s.substring(0, s.indexOf(':'));
- for(int i=0; i<s.length(); i++)
- if (s.charAt(i) < 33 || s.charAt(i) > 126)
- throw new Malformed("Header key contains invalid character \"" + s.charAt(i) + "\"");
- String val = s.substring(0, s.indexOf(':'));
+ for(int i=0; i<key.length(); i++)
+ if (key.charAt(i) < 33 || key.charAt(i) > 126)
+ throw new Malformed("Header key \""+key+"\" contains invalid character \"" + key.charAt(i) + "\"");
+ String val = s.substring(s.indexOf(':') + 1).trim();
while(Character.isSpace(val.charAt(0))) val = val.substring(1);
if (key.startsWith("Resent-")) {
if (key.startsWith("Resent-From")) resent.addElement(new Hashtable());
}
this.date = (Date)headers.get("Date");
- this.to = new Address((String)headers.get("To"));
- this.from = new Address((String)headers.get("From"));
- this.replyto = new Address((String)headers.get("Reply-To"));
+ this.to = new Address((String)headers.get("To")); // FIXME what if null?
+ this.from = headers.get("From") == null ? envelopeFrom : new Address((String)headers.get("From"));
+ this.replyto = headers.get("Reply-To") == null ? null : new Address((String)headers.get("Reply-To"));
this.subject = (String)headers.get("Subject");
this.messageid = (String)headers.get("Message-Id");
if (headers.get("Cc") != null) {
try {
conn.setSoTimeout(5 * 60 * 1000);
StringBuffer logMessage = new StringBuffer();
- String conversationId = getConversation();
- Log.setThreadAnnotation("[conversation/" + conversationId + "] ");
+ String cid = getConversation();
+ Log.setThreadAnnotation("[conversation " + cid + "] ");
InetSocketAddress remote = (InetSocketAddress)conn.getRemoteSocketAddress();
- Log.info(this, "connection from " + remote.getHostName() + ":" + remote.getPort() +
- " (" + remote.getAddress() + ")");
- PrintWriter logf =
- new PrintWriter(new OutputStreamWriter(new FileOutputStream(convdir + File.separatorChar + conversationId)));
+ Log.info(this, "connection from "+remote.getHostName()+":"+remote.getPort()+" ("+remote.getAddress()+")");
+ PrintWriter logf = new PrintWriter(new OutputStreamWriter(new FileOutputStream(convdir+File.separatorChar+cid)));
try {
return handleRequest(new LoggedLineReader(new InputStreamReader(conn.getInputStream()), logf),
new LoggedPrintWriter(new OutputStreamWriter(conn.getOutputStream()), logf));
- } catch(Throwable t) {
- Log.warn(this, t);
- } finally {
- logf.close();
- Log.setThreadAnnotation("");
+ } catch(Throwable t) { Log.warn(this, t);
+ } finally { logf.close(); Log.setThreadAnnotation("");
}
- } catch (Exception e) {
- Log.error(this, e);
- }
+ } catch (Exception e) { Log.error(this, e); }
return false;
}
} else {
ret = new InetAddress[attr.size()];
NamingEnumeration ne = attr.getAll();
- for(int i=0; ne.hasMore(); i++) ret[i] = (InetAddress)ne.next();
+ for(int i=0; ne.hasMore(); i++) {
+ String mx = (String)ne.next();
+ // FIXME we should be sorting here
+ mx = mx.substring(mx.indexOf(" ") + 1);
+ if (mx.charAt(mx.length() - 1) == '.') mx = mx.substring(0, mx.length() - 1);
+ ret[i] = InetAddress.getByName(mx);
+ }
}
} catch (Exception e) {
Log.warn(SMTP.class, "couldn't find MX host for " + hostName + " due to");
import java.text.*;
// FIXME: appallingly inefficient
-public class FileSystem {
+public class FileSystem extends Target {
private static final String STORAGE_ROOT =
System.getProperty("ibex.mail.root", File.separatorChar + "var" + File.separatorChar + "org.ibex.mail");
}
}
+ public void accept(Message m) throws IOException { add(m); }
public FileSystem slash(String name) throws IOException {
throw new Error(this.getClass().getName() + " does not support the slash() method"); }
public int[] list() { throw new Error(this.getClass().getName() + " does not support the list() method"); }
public Message[] query(int maxResults) {
throw new Error(this.getClass().getName() + " does not support the query() method"); }
+ public static class Mailbox extends FileSystem {
+ String user;
+ private static Hashtable cache = new Hashtable();
+ public static Mailbox getForUser(String user) {
+ Mailbox ret = (Mailbox)cache.get(user);
+ if (ret == null) ret = new Mailbox(user);
+ return ret;
+ }
+ Mailbox(String user) { this.user = user; }
+ public FileSystem slash(String name) throws IOException {
+ throw new Error(this.getClass().getName() + " does not support the slash() method"); }
+ public synchronized int add(Message message) throws IOException {
+ FileOutputStream fos = new FileOutputStream("/var/mail/" + user, true);
+ PrintWriter pw = new PrintWriter(new OutputStreamWriter(fos));
+ pw.println("From " + message.envelopeFrom);
+ pw.flush();
+ message.dump(fos);
+ fos.close();
+ return -1;
+ }
+ }
+
/** a fast-write, slow-read place to stash all messages we touch -- in case of a major f*ckup */
public static class Transcript extends FileSystem {
private String path;
// FIXME: this should extend org.ibex.core.Ibex
public static class ScriptEnv extends JS {
+ private static PropertyFile prefs;
+ static {
+ try {
+ prefs = new PropertyFile(new File("/etc/org.ibex.mail.properties"));
+ } catch (IOException e) {
+ Log.error(ScriptEnv.class, e);
+ }
+ }
+
/** lets us put multi-level get/put/call keys all in the same method */
private class Sub extends JS {
String key;
if (name.equals("log.info")) { return METHOD; }
if (name.equals("log.warn")) { return METHOD; }
if (name.equals("log.error")) { return METHOD; }
+ if (name.equals("mail")) { return getSub("mail"); }
+ if (name.equals("mail.my")) { return getSub("mail.my"); }
+ if (name.equals("mail.my.prefs")) { return prefs; }
+ if (name.equals("mail.my.mailbox")) { return FileSystem.Mailbox.getForUser("megacz"); }
return super.get(name);
}