*** empty log message ***

This commit is contained in:
Eric J. Bowersox
2002-02-11 03:34:15 +00:00
commit d80b3252a3
16 changed files with 1175 additions and 0 deletions
@@ -0,0 +1,87 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System - Generic Mail Gateway.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.mailgate;
import java.io.*;
public class AttachmentData
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private String type; // data type
private String name; // filename of attachment
private byte[] data; // the actual data
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
AttachmentData(String type, String name, InputStream stm) throws IOException
{
this.type = type;
this.name = name;
ByteArrayOutputStream tmp = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int rd = stm.read(buf);
while (rd>=0)
{ // simple copy loop
if (rd>0)
tmp.write(buf,0,rd);
rd = stm.read(buf);
} // end while
data = tmp.toByteArray();
} // end constructor
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public final String getType()
{
return type;
} // end getType
public final String getFileName()
{
return name;
} // end getFileName
public final int getLength()
{
return data.length;
} // end getLength
public final byte[] getData()
{
return data;
} // end getData
} // end class AttachmentData
@@ -0,0 +1,109 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System - Generic Mail Gateway.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.mailgate;
import java.io.PrintStream;
import java.io.PrintWriter;
public class BaseException extends Exception
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private Throwable inner = null; // internal "root cause" exception
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public BaseException()
{
super();
} // end constructor
public BaseException(String msg)
{
super(msg);
} // end constructor
public BaseException(Throwable inner)
{
super(inner.getMessage());
this.inner = inner;
} // end constructor
public BaseException(String msg, Throwable inner)
{
super(msg);
this.inner = inner;
} // end constructor
/*--------------------------------------------------------------------------------
* Overrides from class Throwable
*--------------------------------------------------------------------------------
*/
public void printStackTrace()
{
this.printStackTrace(System.err);
} // end printStackTrace
public void printStackTrace(PrintStream s)
{
super.printStackTrace(s);
if (inner!=null)
{ // print the inner stack trace
s.print("Root cause: ");
inner.printStackTrace(s);
} // end if
} // end printStackTrace
public void printStackTrace(PrintWriter s)
{
super.printStackTrace(s);
if (inner!=null)
{ // print the inner stack trace
s.print("Root cause: ");
inner.printStackTrace(s);
} // end if
} // end printStackTrace
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public Throwable getException()
{
return inner;
} // end getException
} // end class BaseException
+88
View File
@@ -0,0 +1,88 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System - Generic Mail Gateway.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.mailgate;
import java.util.*;
import org.apache.xmlrpc.*;
public class Library
{
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
public Library()
{ // do nothing
} // end constructor
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public final Integer castInteger(Object obj)
{
if (obj instanceof Integer)
return (Integer)obj;
if (obj instanceof Number)
return new Integer(((Number)obj).intValue());
try
{ // convert to string and parse into an integer
return new Integer(obj.toString());
} // end try
catch (NumberFormatException nfe)
{ // class cast failed
throw new ClassCastException("castInteger: invalid cast");
} // end catch
} // end castInteger
public final String castString(Object obj)
{
return obj.toString();
} // end castString
public final XmlRpcClient connectXMLRPC(String url, boolean lite) throws PermanentExit
{
try
{ // create the client object
if (lite)
return new XmlRpcClientLite(url);
else
return new XmlRpcClient(url);
} // end try
catch (java.net.MalformedURLException e)
{ // translate the exception
throw new PermanentExit("XML-RPC URL malformed: " + url,e);
} // end catch
} // end connectXMLRPC
public final Vector createVector()
{
return new Vector();
} // end createVector
} // end class Library
+312
View File
@@ -0,0 +1,312 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System - Generic Mail Gateway.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.mailgate;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import com.ibm.bsf.*;
public class Main
{
/*--------------------------------------------------------------------------------
* Internal library class
*--------------------------------------------------------------------------------
*/
public class MyLibrary extends Library
{
MyLibrary()
{
super();
} // end constructor
public final String getConfigParam(String name)
{
return props.getProperty("mailgate.script.config." + name);
} // end getConfigParam
} // end class MyLibrary
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
// Exit codes interpreted by qmail-local delivery agent - see qmail-command(8) man page
public static final int EXIT_SUCCESS = 0;
public static final int EXIT_SUCCESS_FINAL = 99;
public static final int EXIT_FAIL_PERMANENT = 100;
public static final int EXIT_FAIL_TEMPORARY = 111;
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private Properties props; // properties loaded from the command line
private File script_file; // script file to be run
private StringBuffer script_code; // script code from above
private Session session; // mail session object
private BSFManager script_mgr; // script manager
private String script_lang; // language the script is written in
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
private Main(String propfile) throws PermanentExit, TemporaryExit
{
File f = new File(propfile);
if (f.canRead())
{ // load up the file
try
{ // load the properties from the file
FileInputStream stm = new FileInputStream(f);
props = new Properties();
props.load(stm);
} // end try
catch (IOException e)
{ // unable to load the system properties!
throw new TemporaryExit("error loading properties from \"" + f.getAbsolutePath() + "\"",e);
} // end catch
} // end if
else // the file name is bogus
throw new PermanentExit("properties file \"" + f.getAbsolutePath() + "\" cannot be read");
// Check the script file name.
String tmp = props.getProperty("mailgate.script");
if (tmp!=null)
{ // see if the script file can be read
script_file = new File(tmp);
if (!(script_file.canRead()))
throw new PermanentExit("script file \"" + script_file.getAbsolutePath() + "\" cannot be read");
} // end if
else // script file not found
throw new PermanentExit("no script file specified in properties");
// Preload the script code.
try
{ // copy the script code to a string buffer
FileReader rdr = new FileReader(script_file);
StringWriter wr = new StringWriter();
char[] buf = new char[4096];
int rd = rdr.read(buf);
while (rd>=0)
{ // simple read-write loop
if (rd>0)
wr.write(buf,0,rd);
rd = rdr.read(buf);
} // end while
script_code = wr.getBuffer(); // load the script code
} // end try
catch (IOException e)
{ // unable to load the buffer
throw new PermanentExit("unable to load script file \"" + script_file.getAbsolutePath() + "\"");
} // end catch
// Load the temporary script directory.
tmp = props.getProperty("mailgate.script.tmpdir");
if (tmp!=null)
{ // Temporary directory specified...
File tmpf = new File(tmp);
if (!(tmpf.isDirectory()))
throw new PermanentExit("temporary dir \"" + tmpf.getAbsolutePath() + "\" does not exist");
tmp = tmpf.getAbsolutePath();
} // end if
else // directory name not found
throw new PermanentExit("no temporary directory specified in properties");
// Create the BSF manager.
script_mgr = new BSFManager();
script_mgr.setTempDir(tmp);
try
{ // declare beans used by the scripting engines
script_mgr.declareBean("lib",new MyLibrary(),MyLibrary.class);
} // end try
catch (BSFException e)
{ // translate the exception
throw new PermanentExit("declaration error in BSF",e);
} // end catch
if (BSFManager.isLanguageRegistered("javascript"))
{ // we need to so some fixing up to make Rhino work
try
{ // ensure the engine is loaded, and do our fixup routine
script_mgr.loadScriptingEngine("javascript");
fixupRhino();
} // end if
catch (BSFException e)
{ // do nothing - we don't have JavaScript loaded
} // end catch
} // end if
try
{ // look up the scripting language for this file
script_lang = script_mgr.getLangFromFilename(script_file.getAbsolutePath());
} // end try
catch (BSFException e)
{ // this may be thrown by getLangFromFilename
throw new PermanentExit("unknown scripting language: file " + script_file.getAbsolutePath());
} // end catch
// Get the E-mail session object.
session = Session.getDefaultInstance(props);
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
private static void fixupRhino()
{
// What fixupRhino does is to turn off the fancy caching in the JavaScript engine. This is because
// caching involves dynamic creation of classes on the fly, and, for some reason (probably because
// of differing ClassLoader implementations), that doesn't work, whether Rhino is loaded in the
// Web application or in the JRE extensions. When caching is turned off, Rhino can be loaded as
// part of the web application, and it can see all the standard classes and all the Web application
// classes. But we have to turn it off by manipulating it via the Reflection API, as, for all we know,
// Rhino isn't even being loaded right now. (Though we have BSF load Rhino right away if it can,
// to try and get this straightened out.)
try
{ // get a pointer to the Context class
Class klass = Class.forName("org.mozilla.javascript.Context");
// get a pointer to its setCachingEnabled method
final Class[] parmtypes = { Boolean.TYPE };
Method m = klass.getMethod("setCachingEnabled",parmtypes);
// invoke it to turn caching off!
final Object[] parms = { Boolean.FALSE };
m.invoke(null,parms);
} // end try
catch (Exception e)
{ // just ignore me
} // end catch
} // end fixupRhino
private void runMe() throws PermanentExit, TemporaryExit
{
MessageData msg;
try
{ // pull the E-mail message from the input and parse it
MimeMessage in_msg = new MimeMessage(session,System.in);
msg = new MessageData(in_msg);
} // end try
catch (MessagingException me)
{ // error loading the E-mail message
throw new PermanentExit("error loading incoming message",me);
} // end catch
catch (IOException ioe)
{ // error reading the message somehow
throw new TemporaryExit("error reading incoming message",ioe);
} // end catch
// Now process the message via the script.
script_mgr.registerBean("message",msg);
try
{ // exec the script!
script_mgr.exec(script_lang,script_file.getAbsolutePath(),1,1,script_code);
} // end try
catch (BSFException e)
{ // handle the exception somehow
Throwable t = e.getTargetException();
if (t instanceof TemporaryExit)
throw (TemporaryExit)t;
if (t instanceof PermanentExit)
throw (PermanentExit)t;
throw new TemporaryExit("script error",e);
} // end catch
} // end runMe
/*--------------------------------------------------------------------------------
* Ye Olde main() Function
*--------------------------------------------------------------------------------
*/
public static void main(String[] args)
{
// Should be invoked from within a .qmail file as:
// |preline -f <this executable>
if (args.length<1)
{ // bad error - bail out
System.err.println("usage: java " + Main.class.getName() + " property-file");
System.exit(EXIT_FAIL_PERMANENT);
} // end if
int rc = EXIT_SUCCESS;
try
{ // create the "self" object
Main self = new Main(args[0]);
self.runMe();
} // end try
catch (TemporaryExit te)
{ // temporary failure
System.err.println("Temporary failure in mail gateway");
te.printStackTrace();
rc = EXIT_FAIL_TEMPORARY;
} // end catch
catch (PermanentExit pe)
{ // permanent failure
System.err.println("Permanent failure in mail gateway");
pe.printStackTrace();
rc = EXIT_FAIL_PERMANENT;
} // end catch
System.exit(rc);
} // end main
} // end class Main
@@ -0,0 +1,215 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System - Generic Mail Gateway.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.mailgate;
import java.io.*;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
public class MessageData
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private Set recipients; // the set of addresses the message was sent to
private String sender; // the sender
private String subject; // the message subject
private String text = null; // the message text
private ArrayList attachments = new ArrayList(); // the attachments
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
public MessageData(MimeMessage msg) throws MessagingException, IOException
{
// Find all recipients of the message and put them in a set, so we can detect if the message
// was sent to a list we "subscribe" to.
Address[] tmp_array = msg.getAllRecipients();
HashSet tmp_set = new HashSet();
int i;
for (i=0; i<tmp_array.length; i++)
if (tmp_array[i].getType().equals("rfc822"))
{ // peel out the actual E-mail address and stick it in the set
InternetAddress addr = (InternetAddress)(tmp_array[i]);
tmp_set.add(addr.getAddress().toLowerCase());
} // end if and for
if (tmp_set.isEmpty())
recipients = Collections.EMPTY_SET;
else
recipients = Collections.unmodifiableSet(tmp_set);
// Get the list of senders and put it together into the "sender" label.
tmp_array = msg.getFrom();
StringBuffer buf = new StringBuffer();
for (i=0; i<tmp_array.length; i++)
{ // append the addresses together
InternetAddress addr = (InternetAddress)(tmp_array[i]);
if (buf.length()>0)
buf.append(", ");
buf.append(addr.toUnicodeString());
} // end for
sender = buf.toString();
// Get the subject line.
subject = msg.getSubject();
if (msg.getContentType().toLowerCase().startsWith("multipart/"))
{ // we need to break up the multipart object
Multipart mp = (Multipart)(msg.getContent());
if (msg.isMimeType("multipart/alternative"))
processAlternative(mp);
else
processMultipart(mp);
} // end if
else // no attachment - we assume it must be text
text = msg.getContent().toString();
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
private void processAlternative(Multipart mp) throws IOException, MessagingException
{
BodyPart html_part = null;
BodyPart plain_part = null;
int count = mp.getCount();
for (int i=0; i<count; i++)
{ // look for HTML and plain text body parts within the alternative
BodyPart bp = mp.getBodyPart(i);
if (bp.isMimeType("text/html") && (html_part==null))
html_part = bp;
else if (bp.isMimeType("text/plain") && (plain_part==null))
plain_part = bp;
if ((html_part!=null) && (plain_part!=null))
break; // all done with scan loop
} // end for
if (html_part!=null)
text = html_part.getContent().toString();
else if (plain_part!=null)
text = plain_part.getContent().toString();
} // end processAlternative
private void processAttachment(BodyPart bp) throws MessagingException, IOException
{
// extract the information
String filename = bp.getFileName();
if ((filename==null) || (filename.length()==0))
return; // discard attachment data if it has no filename
String mime_type = bp.getContentType();
InputStream istm = bp.getInputStream();
// create an attachment and save it
AttachmentData att = new AttachmentData(mime_type,filename,istm);
attachments.add(att);
} // end processAttachment
private void processMultipart(Multipart mp) throws MessagingException, IOException
{
int count = mp.getCount();
for (int i=0; i<count; i++)
{ // analyze each body part
BodyPart bp = mp.getBodyPart(i);
if (bp.isMimeType("multipart/alternative"))
{ // "alternative" multipart may contain the message text
Multipart sub_mp = (Multipart)(bp.getContent());
if (text==null)
processAlternative(sub_mp);
else
{ // we already have the text - take the final alternative and make it an attachment
int desired_index = sub_mp.getCount() - 1;
processAttachment(sub_mp.getBodyPart(desired_index));
} // end else
} // end if
else if (bp.getContentType().toLowerCase().startsWith("multipart/"))
processMultipart((Multipart)(bp.getContent()));
else if ((bp.isMimeType("text/html") || bp.isMimeType("text/plain")) && (text==null))
text = bp.getContent().toString();
else
processAttachment(bp);
} // end for
} // end processMultipart
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public final boolean sentTo(String addr)
{
return recipients.contains(addr.toLowerCase());
} // end sentTo
public final String getSender()
{
return sender;
} // end getSender
public final String getSubject()
{
return subject;
} // end getSubject
public final String getText()
{
return text;
} // end getText
public final int getAttachmentCount()
{
return attachments.size();
} // end getAttachmentCount
public final boolean hasAttachments()
{
return !(attachments.isEmpty());
} // end hasAttachments
public final AttachmentData getAttachment(int ndx)
{
return (AttachmentData)(attachments.get(ndx));
} // end getAttachment
} // end class MessageData
@@ -0,0 +1,51 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System - Generic Mail Gateway.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.mailgate;
public class PermanentExit extends BaseException
{
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public PermanentExit()
{
super();
} // end constructor
public PermanentExit(String msg)
{
super(msg);
} // end constructor
public PermanentExit(Throwable inner)
{
super(inner);
} // end constructor
public PermanentExit(String msg, Throwable inner)
{
super(msg,inner);
} // end constructor
} // end class PermanentExit
@@ -0,0 +1,51 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System - Generic Mail Gateway.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.mailgate;
public class TemporaryExit extends BaseException
{
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public TemporaryExit()
{
super();
} // end constructor
public TemporaryExit(String msg)
{
super(msg);
} // end constructor
public TemporaryExit(Throwable inner)
{
super(inner);
} // end constructor
public TemporaryExit(String msg, Throwable inner)
{
super(msg,inner);
} // end constructor
} // end class TemporaryExit