|
|
@ -164,24 +164,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("Laden der Listen-Mitglieder von {} fehlgeschlagen. Nachricht kann nicht weitergeleitet werden!",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); |
|
|
|
} |
|
|
|
} |
|
|
@ -217,16 +215,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() fehlgeschlagen für {}",email(),e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public boolean hasState(int test){ |
|
|
|
public boolean hasState(int test){ |
|
|
|
return (state & test) > 0; |
|
|
|
return (state & test) > 0; |
|
|
|
} |
|
|
|
} |
|
|
@ -239,20 +227,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("Laden des Nutzers zu {} fehlgeschlagen",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 |
|
|
@ -344,8 +318,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) { |
|
|
@ -387,6 +361,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); |
|
|
|
} |
|
|
|
} |
|
|
@ -413,27 +391,52 @@ public class MailingList implements MessageHandler, ProblemListener { |
|
|
|
public void onMessageReceived(Message message) throws MessagingException { |
|
|
|
public void onMessageReceived(Message message) throws MessagingException { |
|
|
|
LOG.info("Nachricht empfangen: {}",message.getFrom()); |
|
|
|
LOG.info("Nachricht empfangen: {}",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 { |
|
|
@ -464,6 +467,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); |
|
|
|
} |
|
|
|
} |
|
|
@ -537,9 +544,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(", ")); |
|
|
@ -620,6 +625,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. |
|
|
|