sources := $(shell find src -name \*.java)
sources += upstream/org.ibex.crypto/src/org/ibex/crypto/Base36.java
+upstream/org.ibex.crypto/src/org/ibex/crypto/Base36.java: .download_org.ibex.crypto
+
.download_org.ibex.%:
@echo -e "\033[1mfetching repository org.ibex.$*\033[0m"
@mkdir -p upstream; cd upstream; rm -rf org.ibex.$*; rm -rf org.ibex.$*_*
@cd upstream; darcs get --verbose --partial --repo-name=org.ibex.$* http://$*.ibex.org
@touch $@
-.build_org.ibex.%:
+.build_org.ibex.%: .download_org.ibex.%
@echo -e "\033[1mbuilding repository org.ibex.$*\033[0m"
@cd upstream/org.ibex.$*; make compile
@touch $@
--- /dev/null
+package org.ibex.mail;
+import org.ibex.crypto.*;
+import org.ibex.js.*;
+import org.ibex.util.*;
+import org.ibex.mail.protocol.*;
+import java.util.*;
+import java.net.*;
+import java.io.*;
+
+public class Address extends JSReflection {
+ public final String user;
+ public final String host;
+ public final String description;
+ public Address(String user, String host, String description) {this.user=user;this.host=host;this.description=description;}
+ public Address(String s) throws Address.Malformed {
+ s = s.trim();
+ if (s.indexOf('<') != -1) {
+ if (s.indexOf('>') == -1) { throw new Malformed("found open-angle-bracket (<) but not close-angle-bracket (>)"); }
+ description = s.substring(0, s.indexOf('<')) + s.substring(s.indexOf('>') + 1);
+ s = s.substring(s.indexOf('<') + 1, s.indexOf('>'));
+ } else {
+ description = "";
+ }
+ if (s.indexOf('@') == -1) { throw new Malformed("no @-sign in email address"); }
+ user = s.substring(0, s.indexOf('@'));
+ host = s.substring(s.indexOf('@')+1);
+ }
+ public String coerceToString() { return toString(); }
+ public String toString() { return description.equals("") ? (user +"@"+ host) : description+" <" + user +"@"+ host + ">"; }
+ public static class Malformed extends MailException.Malformed { public Malformed(String s) { super(s); } }
+}
public class MailException extends Exception {
+ public MailException() { }
+ public MailException(String s) { super(s); }
public static class MailboxFull extends MailException { }
+ public static class Malformed extends MailException { public Malformed(String s) { super(s); } }
public static class RelayingDenied extends MailException { }
public static class IOException extends MailException {
// FIXME: fill in stack trace
import java.net.*;
import java.io.*;
-// FIXME MIME: RFC2045, 2046, 2049
// NOTE: always use Win32 line endings
// hard line limit: 998 chars
// soft line limit (suggested): 78 chars
// body needs CRLF; one or the other alone is not acceptable
// date/time parsing: see 3.3
+// FEATURE: MIME RFC2045, 2046, 2049
// FEATURE: PGP-signature-parsing
// FEATURE: mailing list header parsing
// FEATURE: delivery status notification (and the sneaky variety)
public final Hashtable headers; // hash of headers (not including resent's and traces)
public final String body; // entire body
- // parsed header fields
public final Date date;
public final Address to;
public final Address from; // if multiple From entries, this is sender
public final Address[] cc;
public final Address[] bcc;
public final Hashtable[] resent;
- public final Trace[] traces;
+ public Trace[] traces;
- // envelope fields
public final Address envelopeFrom;
public final Address[] envelopeTo;
- public void dump(OutputStream os) {
- Log.error(this, "not implemented");
+ public void dump(OutputStream os) throws IOException {
+ Writer w = new OutputStreamWriter(os);
+ w.write(allHeaders);
+ w.write("\r\n");
+ w.write(body);
+ w.flush();
}
public static class StoredMessage extends Message {
- public StoredMessage(/*ReadStream rs*/SMTP.LineReader rs, boolean dotTerminatedLikeSMTP) throws IOException {
- super(rs, dotTerminatedLikeSMTP); uid = -1; }
- public final int uid;
+ public int uid;
public boolean deleted = false;
public boolean read = false;
public boolean answered = false;
- public String dumpStoredForm() { throw new Error("StoredMessage.dumpStoredForm() not implemented"); };
- public static StoredMessage undump(InputStream os) {
- Log.error(StoredMessage.class, "not implemented");
- return null;
- }
+ public StoredMessage(LineReader rs) throws IOException, MailException.Malformed { super(rs); }
}
- public static class Address extends JSReflection {
- public String coerceToString() { return toString(); }
- public String toString() {
- if (description == null || description.equals("")) return user +"@"+ host;
- return description + " " + "<" + user +"@"+ host + ">";
- }
- public final String user;
- public final String host;
- public final String description;
- public Address(String user, String host, String description) {
- this.user = user; this.host = host; this.description = description;
- }
- public Address(String s) {
- s = s.trim();
- String descrip = null;
- if (s.indexOf('<') != -1) {
- if (s.indexOf('>') == -1) { /* FIXME */ }
- descrip = s.substring(0, s.indexOf('<')) + s.substring(s.indexOf('>') + 1);
- s = s.substring(s.indexOf('<') + 1, s.indexOf('>'));
+ public class Trace {
+ final String returnPath;
+ final Element[] elements;
+ public Trace(LineReader lr) throws Trace.Malformed, IOException {
+ String retPath = lr.readLine();
+ if (!retPath.startsWith("Return-Path:")) throw new Trace.Malformed("trace did not start with Return-Path header");
+ returnPath = retPath.substring(12).trim();
+ Vec el = new Vec();
+ while(true) {
+ String s = lr.readLine();
+ if (s == null) break;
+ if (!s.startsWith("Received:")) { lr.pushback(s); break; }
+ s = s.substring(9).trim();
+ el.addElement(new Element(s));
}
- if (s.indexOf('@') == -1) { /* FIXME */ }
- description = descrip;
- user = s.substring(0, s.indexOf('@'));
- host = s.substring(s.indexOf('@')+1);
+ elements = new Element[el.size()];
+ el.copyInto(elements);
}
- }
-
- public class Trace {
- String returnPath = null;
- Element[] elements;
public class Element {
- // FIXME final
- String fromDomain;
- String fromIP;
- String toDomain;
- String forWhom;
- Date date;
+ String fromDomain;
+ String fromIP;
+ String toDomain;
+ String forWhom;
+ Date date;
+ public Element(String fromDomain, String fromIP, String toDomain, String forWhom, Date date) {
+ this.fromDomain=fromDomain; this.fromIP=fromIP; this.toDomain=toDomain; this.forWhom=forWhom; this.date=date; }
+ public Element(String s) throws Trace.Malformed {
+ StringTokenizer st = new StringTokenizer(s);
+ if (!st.nextToken().equals("FROM")) throw new Trace.Malformed("trace did note have a FROM element: " + s);
+ fromDomain = st.nextToken();
+ if (!st.nextToken().equals("BY")) throw new Trace.Malformed("trace did note have a BY element: " + s);
+ toDomain = st.nextToken();
+ // FIXME not done yet
+ }
}
+ public class Malformed extends Message.Malformed { public Malformed(String s) { super(s); } }
}
- // FIXME: support dotTerminatedLikeSMTP
- public Message(/*ReadStream rs*/SMTP.LineReader rs, boolean dotTerminatedLikeSMTP) throws IOException {
+ public static class Malformed extends MailException.Malformed { public Malformed(String s) { super(s); } }
+ public Message(LineReader rs) throws IOException, Malformed {
String key = null;
StringBuffer all = new StringBuffer();
- String lastKey = null;
replyto = null;
subject = null;
messageid = null;
for(String s = rs.readLine(); s != null && !s.equals(""); s = rs.readLine()) {
all.append(s);
all.append("\r\n");
- if (Character.isSpace(s.charAt(0))) {
- if (lastKey == null) { /* FIXME */ }
- headers.put(lastKey, headers.get(lastKey) + s);
+ if (s.length() == 0 || Character.isSpace(s.charAt(0))) {
+ if (key == null) throw new Malformed("Message began with a blank line; no headers");
+ headers.put(key, headers.get(key) + s);
continue;
}
- if (s.indexOf(':') == -1) {
- /* FIXME */
- break;
- }
-
- lastKey = key = s.substring(0, s.indexOf(':'));
+ if (s.indexOf(':') == -1) throw new Malformed("Header line does not contain colon: " + s);
+ key = s.substring(0, s.indexOf(':'));
String val = s.substring(0, s.indexOf(':') + 1);
while(Character.isSpace(val.charAt(0))) val = val.substring(1);
if (headers.get(key) != null)
if (key.startsWith("Resent-")) {
// FIXME: multi-resent headers
+
} else if (key.startsWith("Return-Path:")) {
- // FIXME: parse traces, see RFC2821, section 4.4
- } else if (key.startsWith("Recieved:")) {
- // FIXME: parse traces, see RFC2821, section 4.4
+ rs.pushback(s);
+ Trace t = new Trace(rs);
+ Trace[] newTraces = new Trace[traces == null ? 1 : traces.length + 1];
+ if (traces != null) System.arraycopy(traces, 0, newTraces, 0, traces.length);
+ traces = newTraces;
+ traces[traces.length-1] = t;
+
} else {
// just append it to the previous one; valid for Comments/Keywords
val = headers.get(key) + " " + val;
}
allHeaders = all.toString();
-
StringBuffer body = new StringBuffer();
- for(String s = rs.readLine();; s = rs.readLine()) {
- if (s == null || (dotTerminatedLikeSMTP && s.equals("."))) break;
- body.append(s);
- }
-
+ for(String s = rs.readLine();; s = rs.readLine()) { if (s == null) break; else body.append(s + "\r\n"); }
this.body = body.toString();
}
import java.io.*;
public class Incoming {
-
- protected void accept(Message m) throws IOException {
- MessageStore.transcript.add((Message.StoredMessage)m); // currently, we write all inbound messages to the transcript
+ protected void accept(Message m) throws IOException, MailException {
+ MessageStore.transcript.add(m); // currently, we write all inbound messages to the transcript
Target.root.accept(m);
}
-
}
import java.net.*;
import java.io.*;
import java.util.*;
+import java.text.*;
public class SMTP extends MessageProtocol {
- public static void main(String[] s) throws IOException {
+ public static String convdir = null;
+ public static void main(String[] s) throws Exception {
+ String logto = System.getProperty("ibex.mail.root", File.separatorChar + "var" + File.separatorChar + "org.ibex.mail");
+ logto += File.separatorChar + "log";
+ Log.file(logto);
+ convdir = System.getProperty("ibex.mail.root", File.separatorChar + "var" + File.separatorChar + "org.ibex.mail");
+ convdir += File.separatorChar + "conversation";
+ new File(convdir).mkdirs();
SMTP smtp = new SMTP();
- ServerSocket ss = new ServerSocket(1025);
- Socket sock = ss.accept();
- smtp.handle(sock);
+ int port = Integer.parseInt(System.getProperty("ibex.mail.port", "25"));
+ Log.info(SMTP.class, "binding to port " + port + "...");
+ ServerSocket ss = new ServerSocket(port);
+ Log.info(SMTP.class, "listening for connections...");
+ while(true) {
+ final Socket sock = ss.accept();
+ new Thread() { public void run() { smtp.handle(sock); } }.start();
+ }
}
- public SMTP() {/* setProtocolName("SMTP"); */}
- public void handle(Socket s) throws IOException { new Listener(s).handleRequest(); }
+ //public SMTP() { setProtocolName("SMTP"); }
//public ServerRequest createRequest(Connection conn) { return new Listener((TcpConnection)conn); }
+ public void handle(Socket s) { new Listener(s, "megacz.com").handleRequest(); }
+
public static class Outgoing {
// recommended retry interval is 30 minutes
// give up after 4-5 days
}
}
- public static class LineReader extends InputStreamReader {
- public LineReader(InputStream r) { super(r); }
- public String readLine() throws IOException {
- StringBuffer ret = new StringBuffer();
- while(true) {
- int c = read();
- if (c == -1) throw new EOFException();
- if (c == '\n') return ret.toString();
- if (c == '\r') continue; //return ret.toString();
- ret.append((char)c);
- }
- }
- }
+ private static String lastTime = null;
+ private static int lastCounter = 0;
private class Listener extends Incoming /*implements ServerRequest*/ {
- //TcpConnection conn;
Socket conn;
- //public Listener(TcpConnection conn) { this.conn = conn; conn.getSocket().setSoTimeout(5 * 60 * 1000); }
- public Listener(Socket conn) throws IOException { this.conn = conn; conn.setSoTimeout(5 * 60 * 1000); }
+ String vhost;
public void init() { }
+ public Listener(Socket conn, String vhost) { this.vhost = vhost; this.conn = conn; }
- public boolean handleRequest() throws IOException {
- //ReadStream rs = conn.getReadStream();
- //WriteStream ws = conn.getWriteStream();
- LineReader rs = new LineReader(conn.getInputStream());
- PrintWriter ws = new PrintWriter(new OutputStreamWriter(conn.getOutputStream()));
+ //TcpConnection conn;
+ //public Listener(TcpConnection conn) { this.conn = conn; conn.getSocket().setSoTimeout(5 * 60 * 1000); }
+ public boolean handleRequest() {
+ try {
+ conn.setSoTimeout(5 * 60 * 1000);
+ StringBuffer logMessage = new StringBuffer();
+ String time = new SimpleDateFormat("yy.MMM.dd-hh:mm:ss").format(new Date());
+ synchronized (SMTP.class) {
+ if (lastTime != null && lastTime.equals(time)) {
+ time += "." + (++lastCounter);
+ } else {
+ lastTime = time;
+ }
+ }
+ String conversationId = time;
+ Log.setThreadAnnotation("[conversation/" + conversationId + "] ");
+ 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)));
+ 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 (Exception e) {
+ Log.error(this, e);
+ }
+ return false;
+ }
- // FIXME
- //ws.setNewLineString("\r\n");
+ private class LoggedLineReader extends LineReader {
+ PrintWriter log;
+ public LoggedLineReader(Reader r, PrintWriter log) { super(r); this.log = log; }
+ public String readLine() throws IOException {
+ String s = super.readLine();
+ if (s != null) { log.println("C: " + s); log.flush(); }
+ return s;
+ }
+ }
- ws.println("220 " + /*conn.getVirtualHost()*/ "megacz.com" + " ESMTP " + this.getClass().getName());
- ws.flush();
+ private class LoggedPrintWriter extends PrintWriter {
+ PrintWriter log;
+ public LoggedPrintWriter(Writer w, PrintWriter log) { super(w); this.log = log; }
+ public void println(String s) {
+ log.println("S: " + s);
+ super.println(s);
+ flush();
+ }
+ }
- Message.Address from = null;
+ public boolean handleRequest(LineReader rs, PrintWriter ws) throws IOException, MailException {
+ //ReadStream rs = conn.getReadStream();
+ //WriteStream ws = conn.getWriteStream();
+ //ws.setNewLineString("\r\n");
+ ws.println("220 " + vhost + " ESMTP " + this.getClass().getName());
+ Address from = null;
Vector to = new Vector();
- // 551 = no, i won't forward that
- // 452 = mailbox full
- // see 4.4 for trace info
while(true) {
String command = rs.readLine();
- // FIXME: validate the HELO domain argument
- // (double check against other end of connection? must not reject though)
- if (command.toUpperCase().startsWith("HELO")) {
- ws.println("250 HELO " + /*conn.getVirtualHost()*/("megacz.com"));
- ws.flush();
+ String c = command.toUpperCase();
+ if (c.startsWith("HELO")) {
+ ws.println("250 HELO " + vhost);
from = null;
to = new Vector();
- } else if (command.toUpperCase().startsWith("EHLO")) {
- ws.println("250-" + /*conn.getVirtualHost()*/("megacz.com"));
+ } else if (c.startsWith("EHLO")) {
+ ws.println("250-" + vhost);
ws.println("250-SIZE");
ws.println("250 PIPELINING");
- ws.flush();
from = null;
to = new Vector();
- } else if (command.toUpperCase().startsWith("RSET")) {
+ } else if (c.startsWith("RSET")) {
from = null;
to = new Vector();
ws.println("250 reset ok");
- ws.flush();
- } else if (command.toUpperCase().startsWith("MAIL FROM:")) {
+ } else if (c.startsWith("MAIL FROM:")) {
command = command.substring(10).trim();
- if(command.indexOf(' ') != -1) command = command.substring(0, command.indexOf(' '));
- from = new Message.Address(command);
+ from = new Address(command);
ws.println("250 " + from + " is syntactically correct");
- ws.flush();
- } else if (command.toUpperCase().startsWith("RCPT TO:")) {
+ } else if (c.startsWith("RCPT TO:")) {
if (from == null) {
ws.println("503 MAIL FROM must precede RCPT TO");
- ws.flush();
continue;
}
+ // FIXME: 551 = no, i won't forward that
command = command.substring(9).trim();
if(command.indexOf(' ') != -1) command = command.substring(0, command.indexOf(' '));
- Message.Address addr = new Message.Address(command);
+ Address addr = new Address(command);
to.addElement(addr);
ws.println("250 " + addr + " is syntactically correct");
- ws.flush();
- } else if (command.toUpperCase().startsWith("DATA")) {
- if (from == null) { ws.println("503 MAIL FROM command must precede DATA"); ws.flush(); continue; }
- if (to == null) { ws.println("503 RCPT TO command must precede DATA"); ws.flush(); continue; }
+ } else if (c.startsWith("DATA")) {
+ if (from == null) { ws.println("503 MAIL FROM command must precede DATA"); continue; }
+ if (to == null) { ws.println("503 RCPT TO command must precede DATA"); continue; }
ws.println("354 Enter message, ending with \".\" on a line by itself");
- ws.flush();
StringBuffer data = new StringBuffer();
// move this into the Message class
boolean good = false;
try {
- good = true;
- Message m = new Message(rs, true);
- accept(m);
- } finally {
- //ws.println("251 user not local; will forward");
- if (good) { ws.println("250 OK message accepted for delivery"); ws.flush(); }
- else { /* FIXME */ }
+ accept(new Message(new DotTerminatedLineReader(rs)));
+ } catch (MailException.Malformed mfe) {
+ ws.println("501 " + mfe.toString()); break;
+ } catch (MailException.MailboxFull mbf) {
+ ws.println("452 " + mbf);
+ } catch (IOException ioe) {
+ ws.println("554 " + ioe.toString()); break;
}
+ ws.println("250 message accepted"); break;
- } else if (command.toUpperCase().startsWith("HELP")) {
- ws.println("214 sorry, you are beyond help. please see a trained professional.");
- ws.flush();
-
- } else if (command.toUpperCase().startsWith("VRFY")) { // FIXME, see code 252
- } else if (command.toUpperCase().startsWith("EXPN")) { ws.println("550 EXPN not available"); ws.flush();
- } else if (command.toUpperCase().startsWith("NOOP")) { ws.println("250 OK"); ws.flush();
- } else if (command.toUpperCase().startsWith("QUIT")) {
- ws.println("221 " + /*conn.getVirtualHost()*/("megacz.com") + " closing connection");
- ws.flush();
- break;
-
- } else {
- ws.println("500 unrecognized command");
- ws.flush();
+ } else if (c.startsWith("HELP")) { ws.println("214 you are beyond help. see a trained professional.");
+ } else if (c.startsWith("VRFY")) { ws.println("252 We don't VRFY; proceed anyway");
+ } else if (c.startsWith("EXPN")) { ws.println("550 EXPN not available");
+ } else if (c.startsWith("NOOP")) { ws.println("250 OK");
+ } else if (c.startsWith("QUIT")) { ws.println("221 " + vhost + " closing connection"); break;
+ } else { ws.println("500 unrecognized command");
}
}
- return false; // FIXME: what does this mean?
+ return false; // always tell resin to close the connection
+ }
+ }
+
+ private static class DotTerminatedLineReader extends LineReader {
+ private final LineReader r;
+ private boolean done = false;
+ public DotTerminatedLineReader(LineReader r) { super(null); this.r = r; }
+ public String readLine() throws IOException {
+ if (done) return null;
+ String s = r.readLine();
+ if (s.equals(".")) { done = true; return null; }
+ if (s.startsWith(".")) return s.substring(1);
+ return s;
}
}
}
// FIXME: appallingly inefficient
public class MessageStore {
- private static final String STORAGE_ROOT = System.getProperty("ibex.mail.root",
- File.separatorChar + "var" + File.separatorChar + "org.ibex.mail");
+ private static final String STORAGE_ROOT =
+ System.getProperty("ibex.mail.root", File.separatorChar + "var" + File.separatorChar + "org.ibex.mail");
//public final FileBased root = new FileBased(STORAGE_ROOT + File.separatorChar);
- public static FileBased transcript = null;
+ public static Transcript transcript = null;
static {
try {
- transcript = new FileBased(STORAGE_ROOT + File.separatorChar + "transcript");
+ transcript = new Transcript(STORAGE_ROOT + File.separatorChar + "transcript");
} catch (Exception e) {
e.printStackTrace();
}
public MessageStore 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 int add(Message.StoredMessage message) throws IOException {
+ public int add(Message message) throws IOException {
throw new Error(this.getClass().getName() + " does not support the add() method"); }
public Message.StoredMessage get(int messagenum) throws IOException {
throw new Error(this.getClass().getName() + " does not support the get() method"); }
throw new Error(this.getClass().getName() + " does not support the query() method"); }
/** a fast-write, slow-read place to stash all messages we touch -- in case of a major f*ckup */
- public static class Transcript {
+ public static class Transcript extends MessageStore {
private String path;
public Transcript(String path) throws IOException { new File(this.path = path).mkdirs(); }
private static String lastTime = null;
private static int lastCounter = 0;
/** returns a message identifier */
- public synchronized int add(Message.StoredMessage message) throws IOException {
- File today = new File(path + File.separatorChar + (new SimpleDateFormat("yyyyy.MMMMM.dd").format(new Date())));
+ public synchronized int add(Message message) throws IOException {
+ File today = new File(path + File.separatorChar + (new SimpleDateFormat("yy-MMM-dd").format(new Date())));
today.mkdirs();
- String time = new SimpleDateFormat("").format(new Date("hh.mm.ss"));
+ String time = new SimpleDateFormat("HH:mm:ss").format(new Date());
synchronized (Transcript.class) {
if (lastTime != null && lastTime.equals(time)) {
time += "." + (++lastCounter);
}
File target = new File(today.getPath() + File.separatorChar + time + ".txt");
- String msg = message.dumpStoredForm();
OutputStream os = new FileOutputStream(target);
- os.write(msg.getBytes("UTF-8")); // FIXME: right?
+ message.dump(os);
os.close();
return -1; // FIXME
}
}
/** returns a message identifier */
- public synchronized int add(Message.StoredMessage message) throws IOException {
+ public synchronized int add(Message message) throws IOException {
int[] all = list();
int max = 0;
for(int i=0; i<all.length; i++) max = Math.max(max, all[i]);
public Message.StoredMessage get(int messagenum) throws IOException {
File f = new File(path + File.separatorChar + messagenum + ".");
if (!f.exists()) throw new FileNotFoundException(f.toString());
- return Message.StoredMessage.undump(new FileInputStream(f));
+ try {
+ Message.StoredMessage ret = new Message.StoredMessage(new LineReader(new InputStreamReader(new FileInputStream(f))));
+ // FIXME: set answered/read/etc here
+ return ret;
+ } catch (MailException.Malformed malf) {
+ Log.error(this, "This should never happen");
+ Log.error(this, malf);
+ return null;
+ }
}
// query types: stringmatch (headers, body), header element, deletion status, date range, message size
public static Script root = null;
static {
try {
- root = new Script(System.getProperty("ibex.mail.conf", File.separatorChar + "etc" + File.separatorChar + "org.ibex.mail.conf"));
+ root = new Script(System.getProperty("ibex.mail.conf",
+ File.separatorChar + "etc" + File.separatorChar + "org.ibex.mail.conf"));
} catch (Exception e) {
e.printStackTrace();
}
final JS js;
public Script(String filePath) throws JSExn, IOException {
- js = JS.fromReader(filePath, 0, new InputStreamReader(new FileInputStream(filePath))); }
+ js = JS.cloneWithNewParentScope(JS.fromReader(filePath, 0, new InputStreamReader(new FileInputStream(filePath))),
+ new ScriptScope(null)); }
+
+ private static class ScriptScope extends JSScope {
+ Message m;
+ ScriptEnv env = new ScriptEnv();
+ public ScriptScope(Message m) { super(null); this.m = m; }
+ public Object get(Object o) {
+ if (o.equals("m")) return m;
+ if (o.equals("ibex")) return env;
+ return null;
+ }
+ }
public void accept(Message m) throws IOException {
try {
// currently, we write all inbound messages to the transcript
// FIXME
- //MessageStore.transcript.add(m);
Object ret = js.call(m, null, null, null, 1);
if (ret instanceof Target) {
((Target)ret).accept(m);
// FIXME: return value?
((Filter)ret).process(m);
} else {
- throw new IOException("configuration script returned a " + ret.getClass().getName());
+ if (ret == null) throw new IOException("configuration script returned null");
+ else throw new IOException("configuration script returned a " + ret.getClass().getName());
}
} catch (JSExn e) {
e.printStackTrace();
/** base class for mail message "destinations" */
public class Target {
public static final Target root = Script.root;
- public void accept(Message m) throws IOException { /* FIXME */ }
+ public void accept(Message m) throws IOException, MailException { /* FIXME */ }
}