From c667bcae5613036fc153417748afd0afc99af911 Mon Sep 17 00:00:00 2001 From: adam Date: Thu, 9 Mar 2006 08:24:04 +0000 Subject: [PATCH] updated mailing list format darcs-hash:20060309082404-5007d-6d00cfa346f17ae3feecf98fc061887fbd2ca61d.gz --- src/org/ibex/mail/MailingList.java | 183 ++++++++++++++++++++++++++++-------- 1 file changed, 142 insertions(+), 41 deletions(-) diff --git a/src/org/ibex/mail/MailingList.java b/src/org/ibex/mail/MailingList.java index c0c3354..ea0e248 100644 --- a/src/org/ibex/mail/MailingList.java +++ b/src/org/ibex/mail/MailingList.java @@ -9,78 +9,164 @@ import org.ibex.mail.target.*; import org.ibex.mail.protocol.*; import java.util.*; import java.io.*; +import java.net.*; import org.prevayler.*; import org.prevayler.Query; +import javax.servlet.*; +import javax.servlet.http.*; + +public class MailingList implements Target, Iterable { + + // DO NOT move this below the stuff underneath it + private MailingList(File path) throws IOException { + this.path = path; + archive = FileBasedMailbox.getFileBasedMailbox(path.getCanonicalPath(), true); + 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 class MailingList extends Persistent implements Target { - - 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.getServletPath(); + PrintWriter pw = new PrintWriter(response.getWriter()); + pw.println(""); + pw.println(" "); + String confirm = request.getParameter("confirm"); + if (confirm != null) { + Subscribe sub = (Subscribe)Confirmation.decode(confirm, Long.parseLong(properties.get("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 { + pw.println(" "+properties.get("address")+"
"); + pw.println(" "+properties.get("nntp")+"
"); + 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")), Long.parseLong(properties.get("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(" "); + pw.println(" "); + pw.println(" "); + pw.println("
"); + } + } + pw.println(" "); + pw.println(""); + pw.flush(); + pw.close(); + } - 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 FileBasedMailbox archive; + private final PropertiesFile properties; - 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 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 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 Mailbox getArchive() throws IOException { return archive; } 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+">"); + head.put("List-Id", one_line_description + "<"+address+">"); + head.put("Subject", properties.get("prefix") + " " + head.get("Subject")); 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(); + + for(Subscriber s : this) try { Log.warn(MailingList.class, " trying " + s.address); SMTP.accept(Message.newMessage(m, m.envelopeFrom, s.address)); Log.warn("[list]", "successfully sent to " + s); @@ -97,3 +183,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; -- 1.7.10.4