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
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>org.example</groupId>
|
<groupId>org.example</groupId>
|
||||||
<artifactId>Widerhall</artifactId>
|
<artifactId>Widerhall</artifactId>
|
||||||
<version>0.2.33</version>
|
<version>0.2.34</version>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|||||||
@@ -163,24 +163,22 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void forward(Message message) throws MessagingException {
|
private void forward(Message message, Stream<ListMember> members) throws MessagingException {
|
||||||
try {
|
if (hasState(STATE_PUBLIC_ARCHIVE)) storeMessage(message);
|
||||||
String newSender = !hasState(STATE_FORWARD_FROM) ? email() : null;
|
String newSender = !hasState(STATE_FORWARD_FROM) ? email() : null;
|
||||||
var receivers = members()
|
var receivers = members
|
||||||
.stream()
|
.map(ListMember::user)
|
||||||
.map(ListMember::user)
|
.map(User::email)
|
||||||
.map(User::email)
|
.toList();
|
||||||
.toList();
|
var subject = message.getSubject();
|
||||||
var subject = message.getSubject();
|
|
||||||
|
|
||||||
if (!subject.contains(stamp())) subject = stamp()+" "+subject;
|
if (!subject.contains(stamp())) subject = stamp()+" "+subject;
|
||||||
var replyTo = (newSender == null && hasState(STATE_REPLY_TO_LIST)) ? email() : null;
|
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);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public MailingList forwardAttached(boolean forward) throws SQLException {
|
public MailingList forwardAttached(boolean forward) throws SQLException {
|
||||||
return setFlag(STATE_FORWARD_ATTACHED,forward);
|
return setFlag(STATE_FORWARD_ATTACHED,forward);
|
||||||
}
|
}
|
||||||
@@ -216,16 +214,6 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
return ml;
|
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){
|
public boolean hasState(int test){
|
||||||
return (state & test) > 0;
|
return (state & test) > 0;
|
||||||
}
|
}
|
||||||
@@ -238,20 +226,6 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
return setFlag(STATE_HIDE_RECEIVERS,hide);
|
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
|
* test, whether the current ML is subscribable by a given user
|
||||||
* @param user
|
* @param user
|
||||||
@@ -343,8 +317,8 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<ListMember> members() throws SQLException {
|
public Stream<ListMember> members() throws SQLException {
|
||||||
return ListMember.of(this);
|
return ListMember.of(this).stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean membersMayBeListedBy(User user) {
|
public boolean membersMayBeListedBy(User user) {
|
||||||
@@ -386,6 +360,10 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stream<ListMember> moderators() throws SQLException {
|
||||||
|
return members().filter(ListMember::isModerator);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean modsMayEditMods(){
|
public boolean modsMayEditMods(){
|
||||||
return hasState(STATE_MODS_CAN_EDIT_MODS);
|
return hasState(STATE_MODS_CAN_EDIT_MODS);
|
||||||
}
|
}
|
||||||
@@ -412,27 +390,52 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
public void onMessageReceived(Message message) throws MessagingException {
|
public void onMessageReceived(Message message) throws MessagingException {
|
||||||
LOG.info("Message received: {}",message.getFrom());
|
LOG.info("Message received: {}",message.getFrom());
|
||||||
String subject = message.getSubject();
|
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];
|
try {
|
||||||
if (from instanceof InternetAddress internetAddress){
|
if (subject.toLowerCase().contains("undelivered")){
|
||||||
var senderEmail = ((InternetAddress) from).getAddress();
|
forward(message,moderators());
|
||||||
if (!isAllowedSender(senderEmail)) {
|
|
||||||
retainMessage(message);
|
|
||||||
sentRetentionNotification(senderEmail);
|
|
||||||
return;
|
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 {
|
public MailingList openForGuests(boolean open) throws SQLException {
|
||||||
@@ -463,6 +466,10 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stream<ListMember> owners() throws SQLException {
|
||||||
|
return members().filter(ListMember::isOwner);
|
||||||
|
}
|
||||||
|
|
||||||
public MailingList replyToList(boolean on) throws SQLException {
|
public MailingList replyToList(boolean on) throws SQLException {
|
||||||
return setFlag(STATE_REPLY_TO_LIST,on);
|
return setFlag(STATE_REPLY_TO_LIST,on);
|
||||||
}
|
}
|
||||||
@@ -536,9 +543,7 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
|
|
||||||
private void sentRetentionNotification(String senderEmail) {
|
private void sentRetentionNotification(String senderEmail) {
|
||||||
try {
|
try {
|
||||||
var receivers = members()
|
var receivers = moderators()
|
||||||
.stream()
|
|
||||||
.filter(ListMember::isOwner)
|
|
||||||
.map(ListMember::user)
|
.map(ListMember::user)
|
||||||
.map(User::email)
|
.map(User::email)
|
||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
@@ -619,6 +624,10 @@ public class MailingList implements MessageHandler, ProblemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Stream<ListMember> subscribers() throws SQLException {
|
||||||
|
return members().filter(ListMember::isSubscriber);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request list subscription for the given user.
|
* 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.
|
* Usually creates a ListMember entry with AWAITING_CONFIRMATION state is created and a confirmation request email is sent.
|
||||||
|
|||||||
@@ -94,10 +94,15 @@ public class Rest extends HttpServlet {
|
|||||||
if (!allowed) return Map.of(ERROR,"You are not allowed to remove this list!");
|
if (!allowed) return Map.of(ERROR,"You are not allowed to remove this list!");
|
||||||
try {
|
try {
|
||||||
list.hide(true).enable(false).openForGuests(false).openForSubscribers(false);
|
list.hide(true).enable(false).openForGuests(false).openForSubscribers(false);
|
||||||
for (ListMember member : list.members()) { // drop all list members except for owner
|
list.members().forEach(listMember -> {
|
||||||
if (!member.isOwner()) member.unsubscribe();
|
try {
|
||||||
}
|
listMember.unsubscribe();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
LOG.debug("Disabling and hiding of {} failed",list.email(),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()));
|
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()));
|
if (!list.membersMayBeListedBy(user)) Map.of(ERROR,t("You are not allowed to list members of '{}'",list.email()));
|
||||||
try {
|
try {
|
||||||
var members = list.members()
|
var members = list.members()
|
||||||
.stream()
|
|
||||||
.map(ListMember::safeMap)
|
.map(ListMember::safeMap)
|
||||||
.toList();
|
.toList();
|
||||||
return Map.of(MEMBERS,members,LIST,list.minimalMap());
|
return Map.of(MEMBERS,members,LIST,list.minimalMap());
|
||||||
|
|||||||
Reference in New Issue
Block a user