X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fibex%2Fmail%2FMailingList.java;h=7cc661a8adeb52bf2b47dffd5983943989ba3fe0;hb=HEAD;hp=c0c3354b7d018f4da6747fa04f9b756adcab15a9;hpb=02a0f9b2334d98d3d71bca73b8a90f5a36f6a5f3;p=org.ibex.mail.git diff --git a/src/org/ibex/mail/MailingList.java b/src/org/ibex/mail/MailingList.java index c0c3354..7cc661a 100644 --- a/src/org/ibex/mail/MailingList.java +++ b/src/org/ibex/mail/MailingList.java @@ -9,82 +9,208 @@ import org.ibex.mail.target.*; import org.ibex.mail.protocol.*; import java.util.*; import java.io.*; -import org.prevayler.*; -import org.prevayler.Query; - -public class MailingList extends Persistent implements Target { +import java.net.*; +import javax.servlet.*; +import javax.servlet.http.*; + +// TODO: RFC 2919 (List-ID) +// TODO: RFC 2142 (*-Request@) +// TODO: RFC 2369 (URLs as Meta-Syntax) + +// FEATURE: store interesting/important stuff in sqlite +public class MailingList extends Mailbox.MailboxWrapper { + + // FIXME + public MailingList(File path, FileBasedMailbox fbm) throws IOException { + super(fbm); + this.path = path; + this.mailbox = fbm; + properties = new PropertiesFile(new File(path.getCanonicalPath() + File.separatorChar + "properties")); + address = new Address(properties.get("address")); + homepage = properties.get("homepage"); + one_line_description = properties.get("description"); + message_footer = properties.get("footer"); + } - public static enum UserType { Administrator, Moderator, Member } - public static enum SubscriptionType { All, None, Digest, MimeDigest } - public static enum Visibility { Members, Public, Nobody } - public static enum Action { Accept, Hold, Reject } + public void banner(HttpServletRequest request, HttpServletResponse response) throws IOException { + String basename = request.getRequestURL()+""; + PrintWriter pw = new PrintWriter(response.getWriter()); + /* + pw.println(""); + pw.println(" "); + pw.println(" "); + pw.println(" "); + pw.println(" "); + */ + String confirm = request.getParameter("confirm"); + if (confirm != null) { + Subscribe sub = (Subscribe)Confirmation.decode(confirm, secret, new Date()); + String email = sub.email; + synchronized(this) { + String path = this.path.getAbsolutePath() + File.separatorChar + "subscribers" + File.separatorChar+sub.email; + if (sub.un) new File(path).delete(); + else { + Log.warn(null, "creating " + path); + new FileOutputStream(path).close(); + } + } + pw.println(" successfully "+sub.adj+"d " + email + " to " + properties.get("address")); + } else { + String action = request.getParameter("action"); + String email = request.getParameter("email"); + if (action != null) { + Subscribe sub = new Subscribe(email, request.getRequestURL().toString(), action.equals("unsubscribe")); + sub.signAndSend(new Address(properties.get("owner")), + secret, new Date()); + pw.println("a confirmation email has been sent to " + email + + "; click the enclosed link to confirm your request to " + action); + } else { + pw.println("
"); + pw.println(" "+properties.get("address")+"
"); + pw.println(" "+properties.get("description")+" "); + pw.println("
"); + pw.println("access via: "); + if (path.getAbsolutePath().startsWith("/afs/")) + pw.println("[AFS] "); + pw.println("[NNTP]"); + pw.println("[SMTP]"); + pw.println("[HTTP]"); + pw.println("
"); + pw.println("
"); + pw.println(" "); + pw.println(" "); + pw.println(" "); + pw.println("
"); + pw.println("
"); + } + } + //pw.println(" "); + //pw.println(""); + pw.flush(); + } - public Address address; - private final long secret = new Random().nextLong(); + public class Subscribe extends Confirmation { + public String email; + public String basename; + public boolean un; + public String adj; + public Subscribe(String email, String basename, boolean un) { + super(new Address(email), new Date().getTime() + (1000 * 60 * 60 * 24)); + this.email = email; + this.basename = basename; + this.un = un; + this.adj = un ? "unsubscribe" : "subscribe"; + } + public String getDescription() { return adj + " " + email + " to " + properties.get("address"); } + public String getURL(String tail) { return basename + "?frame=banner&confirm="+URLEncoder.encode(tail); } + } - public Hashtable subscribers = new Hashtable(); + private final File path; + private final PropertiesFile properties; + private final FileBasedMailbox mailbox; - public String homepage = ""; - public String one_line_description = ""; - public String long_description = ""; - public String message_footer = ""; + private final long secret = new Random().nextLong(); + public final Address address; + public String homepage; - public Visibility listVisibility = Visibility.Nobody; - public Visibility membershipVisibility = Visibility.Nobody; - public Visibility archiveVisibility = Visibility.Members; - public Action defaultPostingType = Action.Hold; + public String one_line_description; + public String message_footer; - public int bounceThreshhold = 10; + public int bounceThreshhold = 10; public static class Subscriber { public Subscriber(Address a) { this.address = a; } public Address address; - public Action posting = Action.Accept; - public UserType type = UserType.Member; - public SubscriptionType subscription = SubscriptionType.All; - public boolean send_copy_of_own_post = false; - public boolean filter_duplicates_when_ccd = true; } // Pooling ////////////////////////////////////////////////////////////////////////////// - private MailingList(File path) { super(path); } - public static MailingList getMailingList(String path) { return getMailingList(new File(path)); } - public static MailingList getMailingList(File path) { + public Iterable subscribers() { + return new Iterable() { + public java.util.Iterator iterator() { + final File subdir = new File(path.getAbsolutePath() + File.separatorChar + "subscribers"); + if (!subdir.exists()) subdir.mkdirs(); + final String[] subs = !subdir.isDirectory() ? new String[0] : subdir.list(); + return new java.util.Iterator() { + int i=0; + Subscriber prep = null; + public void remove() { + try { + new File(subdir.getAbsolutePath() + File.separatorChar + subs[i++]).delete(); + } catch (Exception e) { + Log.error(MailingList.class, e); + } + } + public boolean hasNext() { if (prep==null) prep = next(); return prep!=null; } + public Subscriber next() { + if (prep!=null) { Subscriber ret = prep; prep = null; return ret; } + while(i cache = new HashMap(); + public static MailingList getMailingList(String path) throws IOException { return getMailingList(new File(path)); } + public static MailingList getMailingList(File path) throws IOException { if (!path.exists()) path.mkdirs(); - path = new File(path.getAbsolutePath() + File.separatorChar + ".mailinglist"); - try { - if (path.exists()) return (MailingList)Persistent.read(path); - MailingList ret = new MailingList(path); - ret.write(); - return ret; - } catch (Exception e) { - Log.error(MailingList.class, e); - return null; - } + MailingList ret = cache.get(path.getCanonicalPath()); + if (ret==null) cache.put(path.getCanonicalPath(), ret = new MailingList(path)); + return ret; } - + */ // Methods ////////////////////////////////////////////////////////////////////////////// - public Mailbox getArchive() { return FileBasedMailbox.getFileBasedMailbox(file.getParent(), true); } - - public void accept(Message m) throws IOException, MailException { - StringBuffer buf = new StringBuffer(); - m.getBody().getStream().transcribe(buf); - Headers head = new Headers(m.headers.getStream()); - head.put("list-id", one_line_description + "<"+address+">"); - - m = Message.newMessage(new Fountain.StringFountain(head.getString()+"\r\n"+buf.toString())); - Log.warn(MailingList.class, "archiving list message " + m.subject); - getArchive().accept(m); - - for(java.util.Enumeration e = subscribers.elements(); e.hasMoreElements();) try { - Subscriber s = (Subscriber)e.nextElement(); - Log.warn(MailingList.class, " trying " + s.address); - SMTP.accept(Message.newMessage(m, m.envelopeFrom, s.address)); - Log.warn("[list]", "successfully sent to " + s); - } catch (Exception e2) { Log.error("[list]", e2); } + public void add(Message message) { + try { + accept(message); + } catch (Exception e) { throw new RuntimeException(e); } + } + public void add(Message message, int flags) { add(message); /* FIXME: flags? */ } + public void accept(Message m) throws MailException { + try { + StringBuffer buf = new StringBuffer(); + m.getBody().getStream().transcribe(buf); + Headers head = new Headers(m.headers, + new String[] { + "List-Id", one_line_description + "<"+address+">", + "Subject", properties.get("prefix") + " " + m.headers.get("Subject") + }); + + m = Message.newMessage(Fountain.Util.concat(new Fountain[] { head, + Fountain.Util.create("\r\n"), + Fountain.Util.create(buf.toString()) })); + Log.warn(MailingList.class, "archiving list message " + m.subject); + mailbox.accept(m); + + for(Subscriber s : subscribers()) try { + Log.warn(MailingList.class, " trying " + s.address); + SMTP.enqueue(m.withEnvelope(m.envelopeFrom, s.address)); + Log.warn("[list]", "successfully sent to " + s); + } catch (Exception e2) { Log.error("[list]", e2); } + } catch (Exception e) { throw new RuntimeException(e); } } //public Filter[] filters = new Filter[0]; @@ -97,3 +223,18 @@ public class MailingList extends Persistent implements Target { // public class AnonymizeSender { public boolean uncorrelated; } //} } + + //public static enum UserType { Administrator, Moderator, Member } + //public static enum SubscriptionType { All, None, Digest, MimeDigest } + //public static enum Visibility { Members, Public, Nobody } + //public static enum Action { Accept, Hold, Reject } + //public Visibility listVisibility = Visibility.Nobody; + //public Visibility membershipVisibility = Visibility.Nobody; + //public Visibility archiveVisibility = Visibility.Members; + //public Action defaultPostingType = Action.Hold; + + //public Action posting = Action.Accept; + //public UserType type = UserType.Member; + //public SubscriptionType subscription = SubscriptionType.All; + //public boolean send_copy_of_own_post = false; + //public boolean filter_duplicates_when_ccd = true;