add org.ibex.mail.VERP
[org.ibex.mail.git] / src / org / ibex / mail / Script.java
index 332aa99..9459c1f 100644 (file)
@@ -13,6 +13,16 @@ import java.io.*;
 import java.util.*;
 import java.text.*;
 
+// FIXME: check for binaries (razor, clamassassin, etc) and complain if not present
+
+//
+//  - better matching syntax:
+//  - src-ip
+//  - from *@foo.com
+//  - list-id
+//      - ==> {discard, refuse, bounce}
+//
+
 public class Script extends JS.Obj implements Target {
 
     private static final JS.Method METHOD = new JS.Method();
@@ -62,7 +72,7 @@ public class Script extends JS.Obj implements Target {
         this.m = m;
         try {
             Object ret = js.call(null, new JS[] { m });
-            Log.debug(this, "configuration script returned " + ret);
+            Log.warn(this, "configuration script returned " + ret);
             if (ret == null) throw new IOException("configuration script returned null");
             while (ret instanceof JSReflection.Wrapper) ret = ((JSReflection.Wrapper)ret).unwrap();
             if (ret instanceof Target)      ((Target)ret).accept(m);
@@ -125,6 +135,12 @@ public class Script extends JS.Obj implements Target {
            case "mail.drop": return METHOD;
            case "mail.razor": return getSub("mail.razor");
             case "mail.razor.check": return METHOD;
+           case "mail.clamav": return getSub("mail.clamav");
+            case "mail.clamav.check": return METHOD;
+           case "mail.procmail": /* FEATURE */ return null;
+           case "mail.vacation": /* FEATURE */ return null;
+           case "mail.verp": return getSub("mail.verp");
+           case "mail.verp.check": return METHOD;
            case "mail.dcc": return getSub("mail.dcc");
             case "mail.dcc.check": return METHOD;
             case "mail.bounce": return METHOD;
@@ -137,8 +153,8 @@ public class Script extends JS.Obj implements Target {
             } catch (IOException e) { throw new JSExn(e.toString()); }
             case "mail.whitelist": return JSReflection.wrap(org.ibex.mail.SMTP.whitelist);
             case "mail.my.mailbox":
-                Mailbox root = FileBasedMailbox.getFileBasedMailbox(Mailbox.STORAGE_ROOT, true);
-                return root.slash("user", true).slash("megacz", true);
+                MailTree root = FileBasedMailbox.getFileBasedMailbox(Mailbox.STORAGE_ROOT, true);
+                return (JS)root.slash("user", true).slash("megacz", true);
             case "mail.list": return METHOD;
                 //#end
                 return super.get(name);
@@ -158,11 +174,11 @@ public class Script extends JS.Obj implements Target {
                 }
                 if (name.equals("mail.shell")) {
                     // FIXME: EEEEEVIL!
-                    Log.warn("dbug", args[0].getClass().getName());
-                    Log.warn("dbug", args[1].getClass().getName());
-                    final Process p = Runtime.getRuntime().exec(JSU.toString(args[1]));
-                    Message m = (Message)args[0];
-                    new Thread() {
+                    Log.warn("dbug", a.getClass().getName());
+                    Log.warn("dbug", b.getClass().getName());
+                    Message m = (Message)b;
+                    final Process p = Runtime.getRuntime().exec(JSU.toString(a));
+                    Main.threadPool.start(new Runnable() {
                         public void run() {
                             try {
                                 BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
@@ -171,10 +187,16 @@ public class Script extends JS.Obj implements Target {
                                     Log.warn("shell", s);
                             } catch (Exception e) { e.printStackTrace(); }
                         }
-                    }.start();
+                    });
                     OutputStream os = p.getOutputStream();
                     Stream stream = new Stream(os);
-                    m.getStream().transcribe(stream);
+
+                    // why do I need to go via an sb here?
+                    StringBuffer sb = new StringBuffer();
+                    m.getBody().getStream().transcribe(sb);
+                    stream.println(sb.toString());
+
+                    stream.flush();
                     stream.close();
                     p.waitFor();
                     return null;
@@ -183,15 +205,15 @@ public class Script extends JS.Obj implements Target {
                 if (name.equals("mail.send") || name.equals("send") || name.equals("mail.attempt") || name.equals("attempt")) {
                     boolean attempt = name.equals("mail.attempt") || name.equals("attempt");
                     JS m = (JS)a;
-                    StringBuffer headers = new StringBuffer();
                     String body = "";
                     Address from = null, to = null, envelopeFrom = null, envelopeTo = null;
                     JS.Enumeration e = m.keys();
+                    Headers headers = new Headers();
                     for(; e.hasNext();) {
                         JS key = (JS)e.next();
                         JS val = m.get(key) == null ? null : m.get(key);
                         if ("body".equalsIgnoreCase(JSU.toString(key))) body = JSU.toString(val);
-                        else headers.append(JSU.toString(key) + ": " + JSU.toString(val) + "\r\n");
+                        else headers = new Headers(headers, new String[] { JSU.toString(key), JSU.toString(val) });
                         if ("from".equalsIgnoreCase(JSU.toString(key))) from = Address.parse(JSU.toString(val));
                         if ("to".equalsIgnoreCase(JSU.toString(key))) to = Address.parse(JSU.toString(val));
                         if ("envelopeFrom".equalsIgnoreCase(JSU.toString(key))) envelopeFrom = Address.parse(JSU.toString(val));
@@ -200,12 +222,7 @@ public class Script extends JS.Obj implements Target {
                     if (envelopeTo == null) envelopeTo = to;
                     if (envelopeFrom == null) envelopeFrom = from;
                     Message message =
-                        Message.newMessage(Fountain.Util.concat(Fountain.Util.create(headers.toString()),
-                                                                Fountain.Util.create("\r\n"),
-                                                                Fountain.Util.create(body)),
-                                           envelopeFrom,
-                                           envelopeTo
-                                           );
+                        Message.newMessageFromHeadersAndBody(headers, Fountain.Util.create(body), envelopeFrom, envelopeTo);
                     
                     boolean ok = false;
                     try {
@@ -226,13 +243,58 @@ public class Script extends JS.Obj implements Target {
                    ((Message)args[0]).getStream().transcribe(new Stream(p.getOutputStream()), true);
                    return JSU.N(p.waitFor());
                }
+                if (name.equals("mail.clamav.check")) {
+                    // FIXME: this is returning "is-virus-laden" when clamdscan is unhappy -- BAD!
+                    // should use error code: 0=clean, 1=virus, 2=malfunction
+                   Process p = Runtime.getRuntime().exec("clamdscan - --stdout --quiet");
+                   ((Message)args[0]).getStream().transcribe(new Stream(p.getOutputStream()), true);
+                   int result = p.waitFor();
+                    if (result==0) return JSU.N(0);
+                    StringBuffer ret = new StringBuffer();
+                    new Stream(p.getInputStream()).transcribe(ret);
+                    return JSU.S(ret.toString());
+               }
+                if (name.equals("mail.verp.check")) {
+                    String ret = VERP.verpVerify(Address.parse(JSU.toString(a)), "SECRET".getBytes(), 0);
+                    return ret==null ? null : JSU.S(ret);
+                }
                 if (name.equals("mail.dcc.check")) {
                    Process p = Runtime.getRuntime().exec(new String[] { "dccproc", "-H" });
                    ((Message)args[0]).getStream().transcribe(new Stream(p.getOutputStream()), true);
                    StringBuffer ret = new StringBuffer();
                    new Stream(p.getInputStream()).transcribe(ret);
                    p.waitFor();
-                   return JSU.S(ret.toString());
+                    String result = ret.toString();
+                    Log.warn("dcc", ((Message)args[0]).summary() + ":\n  " + result);
+                    int body = 0;
+                    int fuz1 = 0;
+                    int fuz2 = 0;
+                    int i_body = result.indexOf("Body=");
+                    int i_fuz1 = result.indexOf("Fuz1=");
+                    int i_fuz2 = result.indexOf("Fuz2=");
+                    if (i_body != -1) try {
+                        String s = result.substring(i_body+5);
+                        if (s.indexOf(' ') != -1) s = s.substring(0, s.indexOf(' '));
+                        if (s.indexOf('\n') != -1) s = s.substring(0, s.indexOf('\n'));
+                        body = s.trim().equals("many") ? 999 : Integer.parseInt(s.trim());
+                    } catch (Exception e) { Log.error("", e); }
+                    if (i_fuz1 != -1) try {
+                        String s = result.substring(i_fuz1+5);
+                        if (s.indexOf(' ') != -1) s = s.substring(0, s.indexOf(' '));
+                        if (s.indexOf('\n') != -1) s = s.substring(0, s.indexOf('\n'));
+                        fuz1 = s.trim().equals("many") ? 999 : Integer.parseInt(s.trim());
+                    } catch (Exception e) { Log.error("", e); }
+                    if (i_fuz2 != -1) try {
+                        String s = result.substring(i_fuz2+5);
+                        if (s.indexOf(' ') != -1) s = s.substring(0, s.indexOf(' '));
+                        if (s.indexOf('\n') != -1) s = s.substring(0, s.indexOf('\n'));
+                        fuz2 = s.trim().equals("many") ? 999 : Integer.parseInt(s.trim());
+                    } catch (Exception e) { Log.error("", e); }
+                    JSArray jsa = new JSArray();
+                    jsa.put(JSU.N(0), JSU.N(body));
+                    jsa.put(JSU.N(1), JSU.N(fuz1));
+                    jsa.put(JSU.N(2), JSU.N(fuz2));
+                   return jsa;
                }
                 if (name.equals("mail.drop")) {
                     return args.length==0 ? new Drop() : new Drop(JSU.toString(args[0]));
@@ -251,9 +313,7 @@ public class Script extends JS.Obj implements Target {
                 }
                 if (name.equals("mail.forward2") || name.equals("forward2")) {
                     try {
-                        Message m2 = Message.newMessage(m,
-                                                        m.envelopeFrom,
-                                                        new Address(JSU.toString(a)));
+                        Message m2 = m.withEnvelope(m.envelopeFrom, new Address(JSU.toString(a)));
                         org.ibex.mail.SMTP.Outgoing.enqueue(m2);
                     } catch (Exception e) {
                         Log.warn(this, e);
@@ -262,7 +322,7 @@ public class Script extends JS.Obj implements Target {
                     return null;
                 }
                 if (name.equals("mail.forward") || name.equals("forward")) {
-                    Message m2 = Message.newMessage(Script.this.m, Script.this.m.envelopeFrom, new Address(JSU.toString(a)));
+                    Message m2 = Script.this.m.withEnvelope(Script.this.m.envelopeFrom, new Address(JSU.toString(a)));
                     org.ibex.mail.SMTP.Outgoing.attempt(m2, false);
                     return Drop.instance;
                 }
@@ -390,5 +450,4 @@ public class Script extends JS.Obj implements Target {
         }
     }
 
-
 }