|  |  | @ -2,15 +2,22 @@ package de.srsoftware.widerhall.data; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | import de.srsoftware.widerhall.Configuration; |  |  |  | import de.srsoftware.widerhall.Configuration; | 
			
		
	
		
		
			
				
					
					|  |  |  | import de.srsoftware.widerhall.mail.ImapClient; |  |  |  | import de.srsoftware.widerhall.mail.ImapClient; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import de.srsoftware.widerhall.mail.MessageHandler; | 
			
		
	
		
		
			
				
					
					|  |  |  | import de.srsoftware.widerhall.mail.SmtpClient; |  |  |  | import de.srsoftware.widerhall.mail.SmtpClient; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.slf4j.Logger; |  |  |  | import org.slf4j.Logger; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.slf4j.LoggerFactory; |  |  |  | import org.slf4j.LoggerFactory; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import javax.mail.Address; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import javax.mail.Message; | 
			
		
	
		
		
			
				
					
					|  |  |  | import javax.mail.MessagingException; |  |  |  | import javax.mail.MessagingException; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import javax.mail.internet.AddressException; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import javax.mail.internet.InternetAddress; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import javax.mail.internet.MimeMessage; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.io.UnsupportedEncodingException; |  |  |  | import java.io.UnsupportedEncodingException; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.sql.ResultSet; |  |  |  | import java.sql.ResultSet; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.sql.SQLException; |  |  |  | import java.sql.SQLException; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.util.*; |  |  |  | import java.util.*; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import java.util.stream.Stream; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | import static de.srsoftware.widerhall.Constants.*; |  |  |  | import static de.srsoftware.widerhall.Constants.*; | 
			
		
	
		
		
			
				
					
					|  |  |  | import static de.srsoftware.widerhall.Util.t; |  |  |  | import static de.srsoftware.widerhall.Util.t; | 
			
		
	
	
		
		
			
				
					|  |  | @ -19,7 +26,7 @@ import static de.srsoftware.widerhall.data.User.PERMISSION_ADMIN; | 
			
		
	
		
		
			
				
					
					|  |  |  | /** |  |  |  | /** | 
			
		
	
		
		
			
				
					
					|  |  |  |  * this class encapsulates a MailingList db object |  |  |  |  * this class encapsulates a MailingList db object | 
			
		
	
		
		
			
				
					
					|  |  |  |  */ |  |  |  |  */ | 
			
		
	
		
		
			
				
					
					|  |  |  | public class MailingList { |  |  |  | public class MailingList implements MessageHandler { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     private static final Logger LOG = LoggerFactory.getLogger(MailingList.class); |  |  |  |     private static final Logger LOG = LoggerFactory.getLogger(MailingList.class); | 
			
		
	
		
		
			
				
					
					|  |  |  |     private static final String IMAP_HOST = "imap_host"; |  |  |  |     private static final String IMAP_HOST = "imap_host"; | 
			
		
	
		
		
			
				
					
					|  |  |  |     private static final String IMAP_PORT = "imap_port"; |  |  |  |     private static final String IMAP_PORT = "imap_port"; | 
			
		
	
	
		
		
			
				
					|  |  | @ -106,6 +113,17 @@ public class MailingList { | 
			
		
	
		
		
			
				
					
					|  |  |  |         Database.open().query(sql).compile().run(); |  |  |  |         Database.open().query(sql).compile().run(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     /** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      * load the set of mailing lists a given user is allowed to edit | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      * @param user | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      * @return | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     public static Set<MailingList> editableBy(User user) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         var list = new HashSet<MailingList>(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         for (String key : ListMember.listsOwnedBy(user)) list.add(load(key)); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return list; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     public String email() { |  |  |  |     public String email() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         return email; |  |  |  |         return email; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | @ -114,39 +132,21 @@ public class MailingList { | 
			
		
	
		
		
			
				
					
					|  |  |  |     public void enable(boolean enable) throws SQLException { |  |  |  |     public void enable(boolean enable) throws SQLException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         state = enable ? state | STATE_ENABLED : state ^ (state & STATE_ENABLED); |  |  |  |         state = enable ? state | STATE_ENABLED : state ^ (state & STATE_ENABLED); | 
			
		
	
		
		
			
				
					
					|  |  |  |         Database.open().update(TABLE_NAME).set(STATE,state).where(EMAIL, email()).compile().run(); |  |  |  |         Database.open().update(TABLE_NAME).set(STATE,state).where(EMAIL, email()).compile().run(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     public void hide(boolean hide) throws SQLException { |  |  |  |         if (enable) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         state = hide ? state ^ (state & STATE_PUBLIC) : state | STATE_PUBLIC; |  |  |  |             imap.start().addListener(this); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         Database.open().update(TABLE_NAME).set(STATE,state).where(EMAIL, email()).compile().run(); |  |  |  |         } else { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             imap.stop(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /** |  |  |  |     private void forward(Message message) throws MessagingException { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |      * test, whether the current ML is subscribable by a given user |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |      * @param user |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |      * @return |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |      */ |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     public boolean isOpenFor(User user) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         if ((state & STATE_PUBLIC) > 0) return true; // all users may subscribe public mailing lists
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (user == null) return false; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             var member = ListMember.load(this,user); |  |  |  |             var emails = members().stream().map(User::email).toList(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             return member.hasState(ListMember.STATE_OWNER|ListMember.STATE_SUBSCRIBER); // owners may subscribe their own mailing lists
 |  |  |  |             smtp.bccForward(email(),message,emails); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         } catch (SQLException e) { |  |  |  |         } catch (SQLException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             LOG.warn("Was not able to load ListMember: ",e); |  |  |  |             LOG.error("Failed to read list members of {} from database. Cannot forward message!",email(),e); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             return false; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     /** |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |      * load the set of mailing lists a given user is allowed to edit |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |      * @param user |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |      * @return |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |      */ |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     public static Set<MailingList> editableBy(User user) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         var list = new HashSet<MailingList>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         for (String key : ListMember.listsOwnedBy(user)) list.add(load(key)); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         return list; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /** |  |  |  |     /** | 
			
		
	
	
		
		
			
				
					|  |  | @ -175,6 +175,28 @@ public class MailingList { | 
			
		
	
		
		
			
				
					
					|  |  |  |         return ml; |  |  |  |         return ml; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     public void hide(boolean hide) throws SQLException { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         state = hide ? state ^ (state & STATE_PUBLIC) : state | STATE_PUBLIC; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         Database.open().update(TABLE_NAME).set(STATE,state).where(EMAIL, email()).compile().run(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     /** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      * test, whether the current ML is subscribable by a given user | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      * @param user | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      * @return | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     public boolean isOpenFor(User user) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if ((state & STATE_PUBLIC) > 0) return true; // all users may subscribe public mailing lists
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if (user == null) return false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             var member = ListMember.load(this,user); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return member.hasState(ListMember.STATE_OWNER|ListMember.STATE_SUBSCRIBER); // owners may subscribe their own mailing lists
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } catch (SQLException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             LOG.warn("Was not able to load ListMember: ",e); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /** |  |  |  |     /** | 
			
		
	
		
		
			
				
					
					|  |  |  |      * Load a ML object by it's identifying email address. |  |  |  |      * Load a ML object by it's identifying email address. | 
			
		
	
		
		
			
				
					
					|  |  |  |      * This is a cached method: if the ML has been loaded before, the already-loaded object will be returned. |  |  |  |      * This is a cached method: if the ML has been loaded before, the already-loaded object will be returned. | 
			
		
	
	
		
		
			
				
					|  |  | @ -196,6 +218,10 @@ public class MailingList { | 
			
		
	
		
		
			
				
					
					|  |  |  |         return ml; |  |  |  |         return ml; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     private Set<User> members() throws SQLException { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return ListMember.of(email()).keySet(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /** |  |  |  |     /** | 
			
		
	
		
		
			
				
					
					|  |  |  |      * creates a map from the current ML object containing only email and name of the ML |  |  |  |      * creates a map from the current ML object containing only email and name of the ML | 
			
		
	
		
		
			
				
					
					|  |  |  |      * @return |  |  |  |      * @return | 
			
		
	
	
		
		
			
				
					|  |  | @ -213,6 +239,13 @@ public class MailingList { | 
			
		
	
		
		
			
				
					
					|  |  |  |         return name; |  |  |  |         return name; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     @Override | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     public void onMessageReceived(Message message) throws MessagingException { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         LOG.debug("Message received: {}",message.getFrom()); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         storeMessage(message); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         forward(message); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /** |  |  |  |     /** | 
			
		
	
		
		
			
				
					
					|  |  |  |      * provide the set of mailing lists that are publicy open to subscriptions |  |  |  |      * provide the set of mailing lists that are publicy open to subscriptions | 
			
		
	
		
		
			
				
					
					|  |  |  |      * @return |  |  |  |      * @return | 
			
		
	
	
		
		
			
				
					|  |  | @ -362,6 +395,10 @@ public class MailingList { | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     private void storeMessage(Message message){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // TODO: implement
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /** |  |  |  |     /** | 
			
		
	
		
		
			
				
					
					|  |  |  |      * send a test email to the provided user |  |  |  |      * send a test email to the provided user | 
			
		
	
	
		
		
			
				
					|  |  | @ -374,4 +411,14 @@ public class MailingList { | 
			
		
	
		
		
			
				
					
					|  |  |  |         var text = "If you received this mail, the SMTP settings of your mailing list are correct."; |  |  |  |         var text = "If you received this mail, the SMTP settings of your mailing list are correct."; | 
			
		
	
		
		
			
				
					
					|  |  |  |         smtp.login().send(email(),name(),user.email(),subject,text); |  |  |  |         smtp.login().send(email(),name(),user.email(),subject,text); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     public static Stream<InternetAddress> toAddress(String email) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return Arrays.asList(InternetAddress.parse(email)).stream(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } catch (AddressException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             LOG.debug("Was not able to parse {}",email,e); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return new ArrayList<InternetAddress>().stream(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |