From 1ad9c7278ef3e3e592e9838275913cec8c9423b3 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sat, 23 Apr 2022 18:03:03 +0200 Subject: [PATCH] fixed message forwarding: - messages to open lists are always accepted and sent to all subscribers - messages to normal lists are accepted from subscribers and sent to all subscribers - messages to moderated lists are accepted only from mods and sent to all subscribers - messages to moderated lists are from non-mod subscribers are forwarded to the mods - all other messages are retained --- pom.xml | 2 +- .../widerhall/data/MailingList.java | 131 ++++++++++-------- .../de/srsoftware/widerhall/web/Rest.java | 14 +- 3 files changed, 80 insertions(+), 67 deletions(-) diff --git a/pom.xml b/pom.xml index ec48e0b..d727bce 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.example Widerhall - 0.2.33 + 0.2.34 diff --git a/src/main/java/de/srsoftware/widerhall/data/MailingList.java b/src/main/java/de/srsoftware/widerhall/data/MailingList.java index 33ad39c..b6e6a85 100644 --- a/src/main/java/de/srsoftware/widerhall/data/MailingList.java +++ b/src/main/java/de/srsoftware/widerhall/data/MailingList.java @@ -163,24 +163,22 @@ public class MailingList implements MessageHandler, ProblemListener { return this; } - private void forward(Message message) throws MessagingException { - try { - String newSender = !hasState(STATE_FORWARD_FROM) ? email() : null; - var receivers = members() - .stream() - .map(ListMember::user) - .map(User::email) - .toList(); - var subject = message.getSubject(); + private void forward(Message message, Stream members) throws MessagingException { + if (hasState(STATE_PUBLIC_ARCHIVE)) storeMessage(message); + String newSender = !hasState(STATE_FORWARD_FROM) ? email() : null; + var receivers = members + .map(ListMember::user) + .map(User::email) + .toList(); + var subject = message.getSubject(); - 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); - } + 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); } + + public MailingList forwardAttached(boolean forward) throws SQLException { return setFlag(STATE_FORWARD_ATTACHED,forward); } @@ -216,16 +214,6 @@ public class MailingList implements MessageHandler, ProblemListener { return ml; } - private boolean hashMember(String senderEmail) { - if (senderEmail == null) return false; - try { - return members().stream().map(ListMember::user).map(User::email).anyMatch(senderEmail::equals); - } catch (SQLException e) { - LOG.warn("hasMember() failded for {}",email(),e); - } - return false; - } - public boolean hasState(int test){ return (state & test) > 0; } @@ -238,20 +226,6 @@ public class MailingList implements MessageHandler, ProblemListener { return setFlag(STATE_HIDE_RECEIVERS,hide); } - public boolean isAllowedSender(String senderEmail){ - if (senderEmail == null || senderEmail.isBlank()) return false; - try { - var user = User.load(senderEmail); - if (user == null) return this.isOpenForGuests(); - var member = ListMember.load(this,user); - if (member == null) return this.isOpenForGuests(); - if (member.isModerator()) return true; - if (member.isSubscriber()) return this.isOpenForSubscribers(); - } catch (SQLException e) { - LOG.warn("Failed to load User for {}",senderEmail,e); - } - return this.isOpenForGuests(); - } /** * test, whether the current ML is subscribable by a given user * @param user @@ -343,8 +317,8 @@ public class MailingList implements MessageHandler, ProblemListener { return false; } - public Set members() throws SQLException { - return ListMember.of(this); + public Stream members() throws SQLException { + return ListMember.of(this).stream(); } public boolean membersMayBeListedBy(User user) { @@ -386,6 +360,10 @@ public class MailingList implements MessageHandler, ProblemListener { } + public Stream moderators() throws SQLException { + return members().filter(ListMember::isModerator); + } + public boolean modsMayEditMods(){ return hasState(STATE_MODS_CAN_EDIT_MODS); } @@ -412,27 +390,52 @@ public class MailingList implements MessageHandler, ProblemListener { public void onMessageReceived(Message message) throws MessagingException { LOG.info("Message received: {}",message.getFrom()); 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); - } - return; - } - Address from = message.getFrom()[0]; - if (from instanceof InternetAddress internetAddress){ - var senderEmail = ((InternetAddress) from).getAddress(); - if (!isAllowedSender(senderEmail)) { - retainMessage(message); - sentRetentionNotification(senderEmail); + try { + if (subject.toLowerCase().contains("undelivered")){ + forward(message,moderators()); return; } + + Address from = message.getFrom()[0]; + if (from instanceof InternetAddress internetAddress) { + var senderEmail = internetAddress.getAddress(); + + var user = User.load(senderEmail); + if (user == null) { // no subscription + if (this.isOpenForGuests()) { + forward(message,subscribers()); + } else { + retainMessage(message); + sentRetentionNotification(senderEmail); + + } + return; + } + + var member = ListMember.load(this, user); + if (member == null || member.isAwaiting()) { // no subscription + if (this.isOpenForGuests()) { + forward(message,subscribers()); + } else { + retainMessage(message); + sentRetentionNotification(senderEmail); + } + return; + } + + // at this point the member is at least a subscriber! + + if (member.isModerator() || this.isOpenForSubscribers()) { + forward(message,subscribers()); + } else { + forward(message,moderators()); + } + } + } catch (SQLException e){ + LOG.warn("Failed to process message '{}'",subject,e); } - if (hasState(STATE_PUBLIC_ARCHIVE)) storeMessage(message); - forward(message); + } public MailingList openForGuests(boolean open) throws SQLException { @@ -463,6 +466,10 @@ public class MailingList implements MessageHandler, ProblemListener { return list; } + public Stream owners() throws SQLException { + return members().filter(ListMember::isOwner); + } + public MailingList replyToList(boolean on) throws SQLException { return setFlag(STATE_REPLY_TO_LIST,on); } @@ -536,9 +543,7 @@ public class MailingList implements MessageHandler, ProblemListener { private void sentRetentionNotification(String senderEmail) { try { - var receivers = members() - .stream() - .filter(ListMember::isOwner) + var receivers = moderators() .map(ListMember::user) .map(User::email) .collect(Collectors.joining(", ")); @@ -619,6 +624,10 @@ public class MailingList implements MessageHandler, ProblemListener { } } + private Stream subscribers() throws SQLException { + return members().filter(ListMember::isSubscriber); + } + /** * Request list subscription for the given user. * Usually creates a ListMember entry with AWAITING_CONFIRMATION state is created and a confirmation request email is sent. diff --git a/src/main/java/de/srsoftware/widerhall/web/Rest.java b/src/main/java/de/srsoftware/widerhall/web/Rest.java index b8df3f6..4c7313e 100644 --- a/src/main/java/de/srsoftware/widerhall/web/Rest.java +++ b/src/main/java/de/srsoftware/widerhall/web/Rest.java @@ -94,10 +94,15 @@ public class Rest extends HttpServlet { if (!allowed) return Map.of(ERROR,"You are not allowed to remove this list!"); try { list.hide(true).enable(false).openForGuests(false).openForSubscribers(false); - for (ListMember member : list.members()) { // drop all list members except for owner - if (!member.isOwner()) member.unsubscribe(); - } - } catch (SQLException e) { + list.members().forEach(listMember -> { + try { + listMember.unsubscribe(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + }); + + } catch (Exception e) { LOG.debug("Disabling and hiding of {} failed",list.email(),e); } return Map.of(SUCCESS,t("List {} disabled, closed for subscribers and hidden. Members have been removed.",list.email())); @@ -338,7 +343,6 @@ public class Rest extends HttpServlet { if (!list.membersMayBeListedBy(user)) Map.of(ERROR,t("You are not allowed to list members of '{}'",list.email())); try { var members = list.members() - .stream() .map(ListMember::safeMap) .toList(); return Map.of(MEMBERS,members,LIST,list.minimalMap());