diff --git a/pom.xml b/pom.xml index 131af62..180b480 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.example Widerhall - 0.0.21 + 0.1.1 diff --git a/src/main/java/de/srsoftware/widerhall/data/ListMember.java b/src/main/java/de/srsoftware/widerhall/data/ListMember.java index 1aa4897..61807ea 100644 --- a/src/main/java/de/srsoftware/widerhall/data/ListMember.java +++ b/src/main/java/de/srsoftware/widerhall/data/ListMember.java @@ -136,6 +136,10 @@ public class ListMember { } + public boolean isOwner(){ + return hasState(STATE_OWNER); + } + /** * return a set of list emails of MailingLists owned by the given user * @param user diff --git a/src/main/java/de/srsoftware/widerhall/data/MailingList.java b/src/main/java/de/srsoftware/widerhall/data/MailingList.java index 708d855..ed71b03 100644 --- a/src/main/java/de/srsoftware/widerhall/data/MailingList.java +++ b/src/main/java/de/srsoftware/widerhall/data/MailingList.java @@ -40,8 +40,11 @@ public class MailingList implements MessageHandler { private static final int STATE_PUBLIC = 2; public static final int STATE_FORWARD_FROM = 4; public static final int STATE_FORWARD_ATTACHED = 8; + public static final int STATE_HIDE_RECEIVERS = 16; + public static final int STATE_REPLY_TO_LIST = 32; private static final int VISIBLE = 1; private static final int HIDDEN = 0; + private static final int DEFAULT_STATE = STATE_PENDING|STATE_HIDE_RECEIVERS; private final String name; private final String email; private int state; @@ -88,7 +91,7 @@ public class MailingList implements MessageHandler { * @throws SQLException */ public static MailingList create(String email, String name, String imapHost, int imapPort, String imapUser, String imapPass, String inbox, String smtpHost, int smtpPort, String smtpUser, String smtpPass) throws SQLException { - return new MailingList(email, name, imapHost, imapPort, imapUser, imapPass, inbox, smtpHost, smtpPort, smtpUser, smtpPass, STATE_PENDING).save(); + return new MailingList(email, name, imapHost, imapPort, imapUser, imapPass, inbox, smtpHost, smtpPort, smtpUser, smtpPass, DEFAULT_STATE).save(); } /** @@ -143,9 +146,17 @@ public class MailingList implements MessageHandler { private void forward(Message message) throws MessagingException { try { - var emails = members().stream().map(ListMember::user).map(User::email).toList(); - String sender = (state & STATE_FORWARD_FROM) > 0 ? message.getFrom()[0].toString() : email(); - smtp.bccForward(sender,message,emails); + String newSender = !hasState(STATE_FORWARD_FROM) ? email() : null; + var receivers = members() + .stream() + .map(ListMember::user) + .map(User::email) + .toList(); + var subject = message.getSubject(); + // TODO: remove '(from …)' from subject + if (!subject.contains(stamp())) subject = stamp()+" "+subject; + var replyTo = (newSender == null && hasState(STATE_REPLY_TO_LIST)) ? email() : null; + smtp.forward(newSender,receivers,message,subject,hasState(STATE_FORWARD_ATTACHED),hasState(STATE_HIDE_RECEIVERS),replyTo); } catch (SQLException e) { LOG.error("Failed to read list members of {} from database. Cannot forward message!",email(),e); } @@ -194,6 +205,10 @@ public class MailingList implements MessageHandler { setFlag(STATE_PUBLIC,!hide); } + public void hideReceivers(boolean hide) throws SQLException { + setFlag(STATE_HIDE_RECEIVERS,hide); + } + /** * test, whether the current ML is subscribable by a given user * @param user @@ -235,7 +250,7 @@ public class MailingList implements MessageHandler { public boolean mayBeAlteredBy(User user) { if (user.hashPermission(PERMISSION_ADMIN)) return true; try { - if (ListMember.load(this,user).hasState(ListMember.STATE_OWNER)) return true; + if (ListMember.load(this,user).isOwner()) return true; } catch (SQLException e) { LOG.debug("Error loading list member for ({}, {})",user.email(),email()); } @@ -245,7 +260,7 @@ public class MailingList implements MessageHandler { public boolean mayBeTestedBy(User user) { if (user.hashPermission(PERMISSION_ADMIN)) return true; try { - if (ListMember.load(this,user).hasState(ListMember.STATE_OWNER)) return true; + if (ListMember.load(this,user).isOwner()) return true; } catch (SQLException e) { LOG.debug("Error loading list member for ({}, {})",user.email(),email()); } @@ -259,7 +274,7 @@ public class MailingList implements MessageHandler { public boolean membersMayBeListedBy(User user) { if (user.hashPermission(PERMISSION_ADMIN)) return true; try { - if (ListMember.load(this,user).hasState(ListMember.STATE_OWNER)) return true; + if (ListMember.load(this,user).isOwner()) return true; } catch (SQLException e) { LOG.debug("Error loading list member for ({}, {})",user.email(),email()); } @@ -287,8 +302,18 @@ public class MailingList implements MessageHandler { @Override public void onMessageReceived(Message message) throws MessagingException { LOG.debug("Message received: {}",message.getFrom()); - storeMessage(message); - forward(message); + String subject = message.getSubject(); + if (subject.toLowerCase().contains("undelivered")){ + try { + var receivers = members().stream().filter(ListMember::isOwner).map(ListMember::user).map(User::email).toList(); + smtp.forward(email(), receivers, message, message.getSubject(), false,false,null); + } catch (SQLException e){ + LOG.error("Was not able to load members of {}; Non-Delivery notification dropped!",this.email(),e); + } + } else { + storeMessage(message); + forward(message); + } } /** @@ -311,6 +336,10 @@ public class MailingList implements MessageHandler { return list; } + public void replyToList(boolean on) throws SQLException { + setFlag(STATE_REPLY_TO_LIST,on); + } + /** * creates a map of the current ML containing all fields but passwords. @@ -441,6 +470,11 @@ public class MailingList implements MessageHandler { } } + + private String stamp() { + return "["+name+"]"; + } + private void storeMessage(Message message){ // TODO: implement } diff --git a/src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java b/src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java index 3531054..ebc5cdc 100644 --- a/src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java +++ b/src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java @@ -30,21 +30,42 @@ public class SmtpClient { this.port = port; } - public void bccForward(String from, Message message, List emails) throws MessagingException { + + + public void forward(String newSender, List receivers, Message message, String subject, boolean forwardAsAttachment, boolean bcc, String replyTo) throws MessagingException { if (session == null) login(); MimeMessage forward = new MimeMessage(session); - forward.setFrom(from); - forward.setRecipients(Message.RecipientType.BCC,InternetAddress.parse(String.join(", ",emails))); - forward.setSubject(message.getSubject()); + var oldSender = message.getFrom()[0].toString(); + if (newSender != null){ + forward.setFrom(newSender); + forward.setSubject(subject+" (from "+oldSender+")"); + } else { + forward.setFrom(oldSender); + forward.setSubject(subject); + } + if (replyTo != null) forward.setReplyTo(InternetAddress.parse(replyTo)); + var recipientType = bcc ? Message.RecipientType.BCC : Message.RecipientType.TO; + forward.setRecipients(recipientType,InternetAddress.parse(String.join(", ",receivers))); MimeMultipart multipart = new MimeMultipart(); - MimeBodyPart messageBodyPart = new MimeBodyPart(); - - messageBodyPart.setDataHandler(message.getDataHandler()); - multipart.addBodyPart(messageBodyPart); - + if (forwardAsAttachment){ + MimeBodyPart bodyPart = new MimeBodyPart(); + bodyPart.setText("Find the forwarded message in the attachment(s)!\n"); + multipart.addBodyPart(bodyPart); + + // create another body part to contain the message to be forwarded + bodyPart = new MimeBodyPart(); + // forwardedMsg is the MimeMessage object you want to forward as an attachment + bodyPart.setContent(message, "message/rfc822"); + bodyPart.setDisposition(Part.ATTACHMENT); + multipart.addBodyPart(bodyPart); + } else { + MimeBodyPart bodyPart = new MimeBodyPart(); + + bodyPart.setDataHandler(message.getDataHandler()); + multipart.addBodyPart(bodyPart); + } forward.setContent(multipart); - send(forward); } diff --git a/src/main/java/de/srsoftware/widerhall/web/Rest.java b/src/main/java/de/srsoftware/widerhall/web/Rest.java index 1785ef2..c85cda0 100644 --- a/src/main/java/de/srsoftware/widerhall/web/Rest.java +++ b/src/main/java/de/srsoftware/widerhall/web/Rest.java @@ -220,6 +220,8 @@ public class Rest extends HttpServlet { var map = new HashMap<>(); if (list.hasState(MailingList.STATE_FORWARD_FROM)) map.put("forward_from",true); if (list.hasState(MailingList.STATE_FORWARD_ATTACHED)) map.put("forward_attached",true); + if (list.hasState(MailingList.STATE_HIDE_RECEIVERS)) map.put("hide_receivers",true); + if (list.hasState(MailingList.STATE_REPLY_TO_LIST)) map.put("reply_to_list",true); return map; } diff --git a/src/main/java/de/srsoftware/widerhall/web/Web.java b/src/main/java/de/srsoftware/widerhall/web/Web.java index 67dbf76..fe8d5d6 100644 --- a/src/main/java/de/srsoftware/widerhall/web/Web.java +++ b/src/main/java/de/srsoftware/widerhall/web/Web.java @@ -291,6 +291,8 @@ public class Web extends TemplateServlet { try { list.forwardFrom(Util.getCheckbox(req, "forward_from")); list.forwardAttached(Util.getCheckbox(req, "forward_attached")); + list.hideReceivers(Util.getCheckbox(req, "hide_receivers")); + list.replyToList(Util.getCheckbox(req, "reply_to_list")); data.put(NOTES,t("Sucessfully updated MailingList!")); } catch (SQLException e){ LOG.warn("Failed to update MailingList:",e); diff --git a/static/templates/inspect.st b/static/templates/inspect.st index 8089e37..a286c05 100644 --- a/static/templates/inspect.st +++ b/static/templates/inspect.st @@ -19,10 +19,18 @@ Forward using original sender + + diff --git a/static/templates/js.st b/static/templates/js.st index 5300ef8..2cb8226 100644 --- a/static/templates/js.st +++ b/static/templates/js.st @@ -59,6 +59,8 @@ function showListDetail(data){ console.log(data); if (data.forward_from) $('input[name="forward_from"]').prop('checked',true); if (data.forward_attached) $('input[name="forward_attached"]').prop('checked',true); + if (data.hide_receivers) $('input[name="hide_receivers"]').prop('checked',true); + if (data.reply_to_list) $('input[name="reply_to_list"]').prop('checked',true); } function showListOfEditableLists(data){