// Seneschal e-mail list manager // Williams import com.jthomas.pop.*; import com.al_williams.SMTP.*; import java.util.*; import java.io.*; public class Seneschal { String smtpserver; Properties maillist; // list of members static Properties options; // options // helper functions to get addresses public static String getAddress() { return getOpt("address","list@al-williams.com"); } public static String getAdmin() { return getOpt("adminAddress","listadmin@al-williams.com"); } public static void main(String arg[]) { String cfgfile="maillist.cfg"; if (arg.length>1) { System.out.println("Usage: Seneschal [configfile]"); System.exit(1); } if (arg.length==1) cfgfile=arg[0]; options=new Properties(); try { options.load(new FileInputStream(cfgfile)); } catch (IOException ioe) { // can't open setup file? System.out.println("Can't open configuration file "+ioe); System.exit(9); } // Everything is ready to go, so start new Seneschal().go(arg); } // Real main routine public void go(String [] arg) { // set STMP port SMTP.smtpPort=getIntOpt("SMTPPort",25); maillist=new Properties(); // load subscribers list try { maillist.load(new FileInputStream( getOpt("list","maillist"))); } catch (IOException ioe) { System.out.println(ioe); System.exit(2); } // Set up pop server pop3 pop = new pop3(getOpt("popserver"), getOpt("popuser"), getOpt("poppw")); smtpserver=getOpt("smtpserver"); popStatus status=pop.connect(), xstatus; if (status.OK()) status = pop.login(); if (status.OK()) { status = pop.list(); // check mail String[] responses = status.Responses(); String[] xresponses; int n; // for each message.... for(int i=0; i< responses.length; i++) { n=responses[i].indexOf(' '); n=Integer.parseInt(responses[i].substring(0,n)); // read it xstatus=pop.retr(n); if (xstatus.OK()) { xresponses = xstatus.Responses(); // check for recipient for (int n1=0;n<xresponses.length;n1++) { String to; boolean adminflg=false; if (xresponses[n1].length()==0 ) break; if (!xresponses[n1].substring(0,3). equalsIgnoreCase("to:")) continue; if (xresponses[n1].indexOf(getAdmin())!=-1) adminflg=true; if (!adminflg && xresponses[n1].indexOf(getAddress())==-1) continue; // this e-mail message is for me // do something with e-mail message #n // including delete it most likely if (action(pop,n,adminflg)) pop.dele(n); // kill message } } else { System.out.println("RETR ERROR"); } } status = pop.quit(); // must quit to delete properly } } // This is the low-level action that, by default, // builds a hashtable of the headers and a string of the message // only override this if you want greater control public boolean action(pop3 pop, int n,boolean adminflg) { boolean header=true; popStatus status=pop.retr(n); if (!status.OK()) return false; String [] responses = status.Responses(); StringBuffer message = new StringBuffer(); Hashtable headers = new Hashtable(); for (int i=0;i<responses.length;i++) { if (responses[i].length()==0) { header=false; continue; } if (header) { int n1=responses[i].indexOf(':'); if (n1!=-1) headers.put(responses[i].substring(0,n1). trim(),responses[i].substring(n1+1).trim()); } else { message.append(responses[i]); message.append("\n"); } } if (adminflg) return admin(headers,message.toString()); else return action(headers,message.toString()); } // This is the action routine for normal mail public boolean action(Hashtable headers, String message) { SMTP smtp=new SMTP(smtpserver); int rc; MailMessage msg; message+= "\nSent by Seneschal by Al Williams\nTo unsubscribe " + "send unsubscribe to " + getAdmin(); // loop for all members msg=new MailMessage(getAddress(),"", (String)headers.get("Subject"),message); for (Enumeration e=maillist.keys();e.hasMoreElements();) { msg.to=(String)e.nextElement(); rc=smtp.sendMail(msg); if (rc!=0) { System.out.println("Error " + rc); System.out.println(smtp.getLastResponse()); } } return true; } // This is the admin routine that handles messages to the admin public boolean admin(Hashtable headers, String message) { // commands subscribe, unsubscribe boolean rv=true; StringTokenizer strtok = new StringTokenizer(message); while (strtok.hasMoreTokens()) { String tok=strtok.nextToken(); if (tok.equalsIgnoreCase("subscribe")) { rv&=subscribe(baseEmail((String)headers.get("From"))); } if (tok.equalsIgnoreCase("unsubscribe")) { rv&=unsubscribe(baseEmail((String)headers.get("From"))); } } return rv; // all commands must succeed or fail } // subscribe and send confirming e-mail private boolean subscribe(String email) { boolean rv; MailMessage msg=new MailMessage("list",email, "You are subscribed", "This message is to confirm that you have " + "subscribed to the list\nIf you wish to unsubscribe " + "send unsubscribe to " + getAdmin()); SMTP smtp=new SMTP(smtpserver); maillist.put(email,"0"); if (rv=saveList()) rv&=smtp.sendMail(msg)==0; return rv; } // unsubscribe and send confirming e-mail private boolean unsubscribe(String email) { boolean rv; MailMessage msg=new MailMessage("list",email, "You have unsubscribed", "This message is to confirm that you have " + "unsubscribed to the list\nIf you wish to subscribe " + "send subscribe to "+ getAdmin()); SMTP smtp=new SMTP(smtpserver); maillist.remove(email); if (rv=saveList()) rv&=smtp.sendMail(msg)==0; return rv; } // Strip e-mail from within <> private String baseEmail(String email) { int n,n1; n=email.indexOf('<'); if (n==-1) return email; n1=email.indexOf('>'); if (n1==-1) return email; //? return email.substring(n+1,n1); } // Save the list back to property file private boolean saveList() { try { maillist.store(new FileOutputStream( getOpt("list","maillist")),""); return true; } catch (IOException e) { System.out.println("Can't save mail list: " + e); return false; } } // Get an option with a default value (String) private static String getOpt(String key, String def) { String s; s=(String)options.get(key); if (s==null || s.equals("")) s=def; return s; } // Get an option private static String getOpt(String key) { return (String)options.get(key); } // Get an integer option private static int getIntOpt(String key, int def) { String s=getOpt(key,""); if (s.equals("")) return def; return def; } }