From 1ff4432aa75107ff628147c7808d97697d0c1b64 Mon Sep 17 00:00:00 2001 From: jomu Date: Tue, 10 Oct 2017 15:49:57 +0000 Subject: [PATCH] added ExchangeMailReader via ews-java-lib --- network/pom.xml | 10 +- .../network/mail/MailReaderConfiguration.java | 24 ++ .../mail/exchange/ExchangeMailReader.java | 249 ++++++++++++++++++ .../network/mail/imap/ImapMailReader.java | 2 +- .../mail/exchange/ExchangeMailReaderTest.java | 66 +++++ 5 files changed, 346 insertions(+), 5 deletions(-) create mode 100644 network/src/main/java/de/muehlencord/shared/network/mail/exchange/ExchangeMailReader.java create mode 100644 network/src/test/java/de/muehlencord/shared/network/mail/exchange/ExchangeMailReaderTest.java diff --git a/network/pom.xml b/network/pom.xml index 92d538b..84a7759 100644 --- a/network/pom.xml +++ b/network/pom.xml @@ -52,11 +52,13 @@ - javax.mail - mail - jar - compile + com.sun.mail + javax.mail + + com.microsoft.ews-java-api + ews-java-api + commons-net diff --git a/network/src/main/java/de/muehlencord/shared/network/mail/MailReaderConfiguration.java b/network/src/main/java/de/muehlencord/shared/network/mail/MailReaderConfiguration.java index 6c01d64..628d79a 100644 --- a/network/src/main/java/de/muehlencord/shared/network/mail/MailReaderConfiguration.java +++ b/network/src/main/java/de/muehlencord/shared/network/mail/MailReaderConfiguration.java @@ -22,6 +22,10 @@ public class MailReaderConfiguration { * the password to connect with */ private String password = null; + /** + * the email of the user + */ + private String emailAddress = null; /** * the protocol to use, currently supported imap and imaps */ @@ -43,6 +47,22 @@ public class MailReaderConfiguration { this.password = pw; } + /** + * creates a new config + * + * @param mailHost the smtp host to connect to + * @param host the mailreader host (imap, exchange, pop, ...) to connect to + * @param user the username to connect with + * @param pw the password to connect with + */ + public MailReaderConfiguration(String mailHost, String host, String user, String pw, String email) { + this.smtpHost = mailHost; + this.readerHost = host; + this.userName = user; + this.password = pw; + this.emailAddress = email; + } + /** * @return the smtpHost */ @@ -71,6 +91,10 @@ public class MailReaderConfiguration { return password; } + public String getEmailAddress() { + return emailAddress; + } + public MailProtocol getProtocol() { return protocol; } diff --git a/network/src/main/java/de/muehlencord/shared/network/mail/exchange/ExchangeMailReader.java b/network/src/main/java/de/muehlencord/shared/network/mail/exchange/ExchangeMailReader.java new file mode 100644 index 0000000..6681bcb --- /dev/null +++ b/network/src/main/java/de/muehlencord/shared/network/mail/exchange/ExchangeMailReader.java @@ -0,0 +1,249 @@ +package de.muehlencord.shared.network.mail.exchange; + +import de.muehlencord.shared.network.mail.MailMessage; +import de.muehlencord.shared.network.mail.MailReader; +import de.muehlencord.shared.network.mail.MailReaderConfiguration; +import de.muehlencord.shared.network.mail.MailReaderConnectionException; +import de.muehlencord.shared.network.mail.MailReaderException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import microsoft.exchange.webservices.data.autodiscover.IAutodiscoverRedirectionUrl; +import microsoft.exchange.webservices.data.core.ExchangeService; +import microsoft.exchange.webservices.data.core.PropertySet; +import microsoft.exchange.webservices.data.core.service.item.Item; +import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion; +import microsoft.exchange.webservices.data.core.enumeration.property.BasePropertySet; +import microsoft.exchange.webservices.data.core.enumeration.property.WellKnownFolderName; +import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException; +import microsoft.exchange.webservices.data.core.service.folder.Folder; +import microsoft.exchange.webservices.data.core.service.schema.EmailMessageSchema; +import microsoft.exchange.webservices.data.credential.ExchangeCredentials; +import microsoft.exchange.webservices.data.credential.WebCredentials; +import microsoft.exchange.webservices.data.property.complex.InternetMessageHeaderCollection; +import microsoft.exchange.webservices.data.search.FindFoldersResults; +import microsoft.exchange.webservices.data.search.FindItemsResults; +import microsoft.exchange.webservices.data.search.FolderView; +import microsoft.exchange.webservices.data.search.ItemView; +import microsoft.exchange.webservices.data.search.filter.SearchFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Joern Muehlencord + */ +public class ExchangeMailReader implements MailReader { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExchangeMailReader.class); + private final MailReaderConfiguration configuration; + private ExchangeService service = null; + + public ExchangeMailReader(MailReaderConfiguration config) { + this.configuration = config; + } + + @Override + public void connect() throws MailReaderConnectionException { + try { + String hostName = getConfiguration().getReaderHost(); + String userName = getConfiguration().getUserName(); + String password = getConfiguration().getPassword(); + String emailAddress = getConfiguration().getEmailAddress(); + + service = new ExchangeService(ExchangeVersion.Exchange2010_SP2); + + ExchangeCredentials credentials = new WebCredentials(userName, password); + service.setCredentials(credentials); + service.autodiscoverUrl(emailAddress, new RedirectionUrlCallback()); + + LOGGER.info("Connected to " + getConnectionShortCut()); + } catch (Exception ex) { + throw new MailReaderConnectionException(ex.getMessage(), ex); + } + } + + @Override + public void disconnect() { + if (service != null) { + service.close(); + } + } + + private Folder findFolderByName(String folderName) throws MailReaderException { + String[] folderNameParts = folderName.split("/"); + try { + Folder inbox = Folder.bind(service, WellKnownFolderName.Inbox); + int currentFolderPart = 0; + Folder currentFolder = inbox; + while ((currentFolderPart < folderNameParts.length)) { + FindFoldersResults findResults = service.findFolders(currentFolder.getId(), new FolderView(Integer.MAX_VALUE)); + Iterator it = findResults.getFolders().iterator(); + boolean nextFolderFound = false; + while (it.hasNext() && !nextFolderFound) { + Folder nextFolder = it.next(); + if (nextFolder.getDisplayName().equalsIgnoreCase(folderNameParts[currentFolderPart])) { + // found next folder + currentFolder = nextFolder; + currentFolderPart++; + nextFolderFound = true; + } + } + // checked all sub folders + if (!nextFolderFound) { + throw new MailReaderException("Cannot find subfolder named " + folderNameParts[currentFolderPart] + " in folder " + currentFolder.getDisplayName()); + } + } + + return currentFolder; + } catch (Exception ex) { + throw new MailReaderException("Error while finding folder " + folderName + ". Reason: " + ex.getMessage(), ex); + + } + + } + + @Override + public String getDefaultFolder() throws MailReaderException { + try { + Folder inbox = Folder.bind(service, WellKnownFolderName.Inbox); + return inbox.getDisplayName(); + } catch (Exception ex) { + throw new MailReaderException("Cannot bind inbox folder", ex); + } + } + + @Override + public List getSubFolder(String sourceFolder) throws MailReaderException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getFolder(String folderPath) throws MailReaderException { + Folder folder = findFolderByName(folderPath); + try { + return folder.getDisplayName(); + } catch (ServiceLocalException ex) { + throw new MailReaderException(ex.getMessage(), ex); + } + } + + @Override + public int getMessageCount(String holdFolder) throws MailReaderException { + Folder folder = findFolderByName(holdFolder); + try { + return folder.getTotalCount(); + } catch (ServiceLocalException ex) { + throw new MailReaderException(ex.getMessage(), ex); + } + } + + private List getMessages(String folderName, ItemView view) throws MailReaderException { + List returnValue = new ArrayList<>(); + try { + Folder folder = findFolderByName(folderName); + FindItemsResults findResults = service.findItems(folder.getId(), view); + PropertySet propertySet = new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.InternetMessageId); + service.loadPropertiesForItems(findResults, propertySet); + for (Item item : findResults.getItems()) { + String subject = item.getSubject(); + String content = item.getBody().toString(); + InternetMessageHeaderCollection headers = item.getInternetMessageHeaders(); + String messageId = headers.find("Message-ID").getValue(); + MailMessage mailMessage = new MailMessage(subject, content, messageId); + returnValue.add(mailMessage); + } + + return returnValue; + } catch (Exception ex) { + throw new MailReaderException(ex.getMessage(), ex); + } + + } + + @Override + public List getMessages(String folderName) throws MailReaderException { + ItemView view = new ItemView(Integer.MAX_VALUE); + return getMessages(folderName, view); + } + + @Override + public List getMessages(String folderName, int start, int end) throws MailReaderException { + ItemView view = new ItemView(end - start); + view.setOffset(start); + return getMessages(folderName, view); + } + + private Item findMessageByMessageId(String folderName, String messageId) throws MailReaderException { + try { + PropertySet propertySet = new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.InternetMessageId); + Folder folder = findFolderByName(folderName); + ItemView view = new ItemView(1); + view.setPropertySet(propertySet); + + SearchFilter searchFilter = new SearchFilter.IsEqualTo(EmailMessageSchema.InternetMessageId, messageId); + FindItemsResults findResults = service.findItems(folder.getId(), searchFilter, view); + service.loadPropertiesForItems(findResults, propertySet); + + if (findResults.getItems().isEmpty()) { + return null; + } else { + return findResults.getItems().get(0); + } + } catch (Exception ex) { + throw new MailReaderException(ex.getMessage(), ex); + } + + } + + @Override + public void copyMessage(MailMessage mm, String sourceFolder, String destFolder) throws MailReaderException { + try { + Item message = findMessageByMessageId(sourceFolder, mm.getMessageId()); + + Folder destination = findFolderByName(destFolder); + service.copyItem(message.getId(), destination.getId()); + } catch (Exception ex) { + throw new MailReaderException(ex.getMessage(), ex); + } + } + + @Override + public void moveMessage(MailMessage mm, String sourceFolder, String destFolder) throws MailReaderException { + try { + Item message = findMessageByMessageId(sourceFolder, mm.getMessageId()); + Folder destination = findFolderByName(destFolder); + service.moveItem(message.getId(), destination.getId()); + } catch (Exception ex) { + throw new MailReaderException(ex.getMessage(), ex); + } + } + + @Override + public void setSeenFlag(String folder, MailMessage mm, boolean flagValue) throws MailReaderException { + // FIXME - add implementation + } + + /** + * returns userName@hostname + * + * @return userName@hostname + */ + private String getConnectionShortCut() { + return getConfiguration().getUserName() + "@" + getConfiguration().getReaderHost(); + } + + /* *** getter / setter *** */ + public MailReaderConfiguration getConfiguration() { + return configuration; + } + +} + +class RedirectionUrlCallback implements IAutodiscoverRedirectionUrl { + + @Override + public boolean autodiscoverRedirectionUrlValidationCallback(String redirectionUrl) { + return redirectionUrl.toLowerCase().startsWith("https://"); + } +} diff --git a/network/src/main/java/de/muehlencord/shared/network/mail/imap/ImapMailReader.java b/network/src/main/java/de/muehlencord/shared/network/mail/imap/ImapMailReader.java index 6bda2da..2b10242 100644 --- a/network/src/main/java/de/muehlencord/shared/network/mail/imap/ImapMailReader.java +++ b/network/src/main/java/de/muehlencord/shared/network/mail/imap/ImapMailReader.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Implementation of MaiLReader to connect to an IMAP server + * Implementation of MailReader to connect to an IMAP server * * @author joern@muehlencord.de */ diff --git a/network/src/test/java/de/muehlencord/shared/network/mail/exchange/ExchangeMailReaderTest.java b/network/src/test/java/de/muehlencord/shared/network/mail/exchange/ExchangeMailReaderTest.java new file mode 100644 index 0000000..0066953 --- /dev/null +++ b/network/src/test/java/de/muehlencord/shared/network/mail/exchange/ExchangeMailReaderTest.java @@ -0,0 +1,66 @@ +package de.muehlencord.shared.network.mail.exchange; + +import de.muehlencord.shared.network.mail.MailMessage; +import de.muehlencord.shared.network.mail.MailReader; +import de.muehlencord.shared.network.mail.MailReaderConfiguration; +import de.muehlencord.shared.network.mail.MailReaderConnectionException; +import de.muehlencord.shared.network.mail.MailReaderException; +import java.util.List; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeNotNull; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Joern Muehlencord + */ +public class ExchangeMailReaderTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExchangeMailReaderTest.class); + + @Test + public void testConnect() { + try { + LOGGER.info("testConnect"); + String imapHost = null; + String smtpHost = null; + String folder = null; + String testFolder = null; + String userName = null; + String password = null; + String emailaddress = null; + + assumeNotNull(imapHost); + assumeNotNull(smtpHost); + assumeNotNull(folder); + assumeNotNull(testFolder); + assumeNotNull(userName); + assumeNotNull(emailaddress); + assumeNotNull(password); + + + MailReaderConfiguration config = new MailReaderConfiguration(smtpHost, imapHost, userName, password, emailaddress); + MailReader instance = new ExchangeMailReader(config); + + instance.connect(); + int messageCount = instance.getMessageCount(folder); + LOGGER.info("Found {} messages in folder {}", messageCount, folder); + List messages = instance.getMessages(folder, 0, 50); + LOGGER.info("Retrieved {} messages from folder", messages.size()); + + // instance.copyMessage(messages.get(0), folder, testFolder); + instance.disconnect(); + + } catch (MailReaderConnectionException | MailReaderException ex) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(ex.toString(), ex); + } else { + LOGGER.error(ex.toString()); + } + fail("An error occured"); + } + } + +}