Java tutorial
/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2018 by Hitachi Vantara : http://www.pentaho.com * ******************************************************************************* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.pentaho.di.job.entries.getpop; import com.google.common.annotations.VisibleForTesting; import com.sun.mail.imap.IMAPSSLStore; import com.sun.mail.pop3.POP3SSLStore; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.pentaho.di.core.Const; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.logging.LogChannelInterface; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.vfs.KettleVFS; import org.pentaho.di.i18n.BaseMessages; import javax.mail.Flags; import javax.mail.Flags.Flag; import javax.mail.Folder; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Part; import javax.mail.Session; import javax.mail.Store; import javax.mail.URLName; import javax.mail.internet.MimeUtility; import javax.mail.search.AndTerm; import javax.mail.search.BodyTerm; import javax.mail.search.ComparisonTerm; import javax.mail.search.FlagTerm; import javax.mail.search.FromStringTerm; import javax.mail.search.NotTerm; import javax.mail.search.ReceivedDateTerm; import javax.mail.search.RecipientStringTerm; import javax.mail.search.SearchTerm; import javax.mail.search.SubjectTerm; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import java.util.HashSet; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * MailConnection handles the process of connecting to, reading from POP3/IMAP. * * @author Samatar * @since 01-04-2009 * */ public class MailConnection { private static Class<?> PKG = JobEntryGetPOP.class; // for i18n purposes, needed by Translator2!! /** * Target mail server. */ private String server; private int port; private String username; private String password; private boolean usessl; private boolean write; private boolean useproxy; private String proxyusername; /** * Protocol used. Should be PROTOCOL_POP3 (0) for POP3 and PROTOCOL_IMAP (1) to IMAP */ private int protocol; private Properties prop; private Session session = null; private Store store = null; private Folder folder = null; /** * Contains the list of retrieved messages */ private Message[] messages; /** * Contains the current message */ private Message message; private SearchTerm searchTerm = null; /** * Counts the number of message fetched */ private int messagenr; /** * Counts the number of message saved in a file */ private int nrSavedMessages; /** * Counts the number of message move to a folder */ private int nrMovedMessages; /** * Counts the number of message deleted */ private int nrDeletedMessages; /** * Counts the number of attached files saved in a file */ private int nrSavedAttachedFiles; /** * IMAP folder if user want to move some messages */ private Folder destinationIMAPFolder = null; private LogChannelInterface log; /** * Construct a new Database MailConnection * * @param protocol * the protocol used : MailConnection.PROTOCOL_POP3 or MailConnection.PROTOCOL_IMAP. * @param server * the target server (ip ou name) * @param port * port number on the server * @param password * @param usessl * specify if the connection is established via SSL * @param useproxy * specify if we use proxy authentication * @param proxyusername * proxy authorised user */ public MailConnection(LogChannelInterface log, int protocol, String server, int port, String username, String password, boolean usessl, boolean useproxy, String proxyusername) throws KettleException { this.log = log; // Get system properties try { this.prop = System.getProperties(); } catch (SecurityException s) { this.prop = new Properties(); } this.port = port; this.server = server; this.username = username; this.password = password; this.usessl = usessl; this.protocol = protocol; this.nrSavedMessages = 0; this.nrDeletedMessages = 0; this.nrMovedMessages = 0; this.nrSavedAttachedFiles = 0; this.messagenr = -1; this.useproxy = useproxy; this.proxyusername = proxyusername; try { if (useproxy) { // Need here to pass a proxy // use SASL authentication this.prop.put("mail.imap.sasl.enable", "true"); this.prop.put("mail.imap.sasl.authorizationid", proxyusername); } if (protocol == MailConnectionMeta.PROTOCOL_POP3) { this.prop.setProperty("mail.pop3s.rsetbeforequit", "true"); this.prop.setProperty("mail.pop3.rsetbeforequit", "true"); } else if (protocol == MailConnectionMeta.PROTOCOL_MBOX) { this.prop.setProperty("mstor.mbox.metadataStrategy", "none"); // mstor.mbox.metadataStrategy={none|xml|yaml} this.prop.setProperty("mstor.cache.disabled", "true"); // prevent diskstore fail } String protocolString = (protocol == MailConnectionMeta.PROTOCOL_POP3) ? "pop3" : protocol == MailConnectionMeta.PROTOCOL_MBOX ? "mstor" : "imap"; if (usessl && protocol != MailConnectionMeta.PROTOCOL_MBOX) { // Supports IMAP/POP3 connection with SSL, the connection is established via SSL. this.prop.setProperty("mail." + protocolString + ".socketFactory.class", "javax.net.ssl.SSLSocketFactory"); this.prop.setProperty("mail." + protocolString + ".socketFactory.fallback", "false"); this.prop.setProperty("mail." + protocolString + ".port", "" + port); this.prop.setProperty("mail." + protocolString + ".socketFactory.port", "" + port); // Create session object this.session = Session.getInstance(this.prop, null); this.session.setDebug(log.isDebug()); if (this.port == -1) { this.port = ((protocol == MailConnectionMeta.PROTOCOL_POP3) ? MailConnectionMeta.DEFAULT_SSL_POP3_PORT : MailConnectionMeta.DEFAULT_SSL_IMAP_PORT); } URLName url = new URLName(protocolString, server, port, "", username, password); this.store = (protocol == MailConnectionMeta.PROTOCOL_POP3) ? new POP3SSLStore(this.session, url) : new IMAPSSLStore(this.session, url); url = null; } else { this.session = Session.getInstance(this.prop, null); this.session.setDebug(log.isDebug()); if (protocol == MailConnectionMeta.PROTOCOL_MBOX) { this.store = this.session.getStore(new URLName(protocolString + ":" + server)); } else { this.store = this.session.getStore(protocolString); } } if (log.isDetailed()) { log.logDetailed(BaseMessages.getString(PKG, "JobGetMailsFromPOP.NewConnectionDefined")); } } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "JobGetMailsFromPOP.Error.NewConnection", Const.NVL(this.server, "")), e); } } /** * @return Returns the connection status. true if the connection is still opened */ public boolean isConnected() { return (this.store != null && this.store.isConnected()); } /** * @return Returns the use of SSL. true if the connection use SSL */ public boolean isUseSSL() { return this.usessl; } /** * @return Returns the use of proxy. true if the connection use proxy */ public boolean isUseProxy() { return this.useproxy; } /** * @return Returns the proxy username. */ public String getProxyUsername() { return this.proxyusername; } /** * @return Returns the store * */ public Store getStore() { return this.store; } /** * @return Returns the folder * */ public Folder getFolder() { return this.folder; } /** * Open the connection. * * @throws KettleException * if something went wrong. */ public void connect() throws KettleException { if (log.isDetailed()) { log.logDetailed(BaseMessages.getString(PKG, "JobGetMailsFromPOP.Connecting", this.server, this.username, "" + this.port)); } try { if (this.usessl || this.protocol == MailConnectionMeta.PROTOCOL_MBOX) { // Supports IMAP/POP3 connection with SSL, // the connection is established via SSL. this.store.connect(); } else { if (this.port > -1) { this.store.connect(this.server, this.port, this.username, this.password); } else { this.store.connect(this.server, this.username, this.password); } } if (log.isDetailed()) { log.logDetailed(BaseMessages.getString(PKG, "JobGetMailsFromPOP.Connected", this.server, this.username, "" + this.port)); } } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "JobGetMailsFromPOP.Error.Connecting", this.server, this.username, Const.NVL("" + this.port, "")), e); } } /** * Open the default folder (INBOX) * * @param write * open the folder in write mode * @throws KettleException * if something went wrong. */ public void openFolder(boolean write) throws KettleException { openFolder(null, true, write); } /** * Open the folder. * * @param foldername * the name of the folder to open * @param write * open the folder in write mode * @throws KettleException * if something went wrong. */ public void openFolder(String foldername, boolean write) throws KettleException { openFolder(foldername, false, write); } /** * Open the folder. * * @param foldername * the name of the folder to open * @param defaultFolder * true to open the default folder (INBOX) * @param write * open the folder in write mode * @throws KettleException * if something went wrong. */ public void openFolder(String foldername, boolean defaultFolder, boolean write) throws KettleException { this.write = write; try { if (getFolder() != null) { // A folder is already opened // before make sure to close it closeFolder(true); } if (defaultFolder) { if (protocol == MailConnectionMeta.PROTOCOL_MBOX) { this.folder = this.store.getDefaultFolder(); } else { // get the default folder this.folder = getRecursiveFolder(MailConnectionMeta.INBOX_FOLDER); } if (this.folder == null) { throw new KettleException( BaseMessages.getString(PKG, "JobGetMailsFromPOP.InvalidDefaultFolder.Label")); } if ((folder.getType() & Folder.HOLDS_MESSAGES) == 0) { throw new KettleException( BaseMessages.getString(PKG, "MailConnection.DefaultFolderCanNotHoldMessage")); } } else { // Open specified Folder (for IMAP/MBOX) if (this.protocol == MailConnectionMeta.PROTOCOL_IMAP || this.protocol == MailConnectionMeta.PROTOCOL_MBOX) { this.folder = getRecursiveFolder(foldername); } if (this.folder == null || !this.folder.exists()) { throw new KettleException( BaseMessages.getString(PKG, "JobGetMailsFromPOP.InvalidFolder.Label")); } } if (this.write) { if (log.isDebug()) { log.logDebug(BaseMessages.getString(PKG, "MailConnection.OpeningFolderInWriteMode.Label", getFolderName())); } this.folder.open(Folder.READ_WRITE); } else { if (log.isDebug()) { log.logDebug(BaseMessages.getString(PKG, "MailConnection.OpeningFolderInReadMode.Label", getFolderName())); } this.folder.open(Folder.READ_ONLY); } if (log.isDetailed()) { log.logDetailed( BaseMessages.getString(PKG, "JobGetMailsFromPOP.FolderOpened.Label", getFolderName())); } if (log.isDebug()) { // display some infos on folder //CHECKSTYLE:LineLength:OFF log.logDebug(BaseMessages.getString(PKG, "JobGetMailsFromPOP.FolderOpened.Name", getFolderName())); log.logDebug(BaseMessages.getString(PKG, "JobGetMailsFromPOP.FolderOpened.FullName", this.folder.getFullName())); log.logDebug(BaseMessages.getString(PKG, "JobGetMailsFromPOP.FolderOpened.Url", this.folder.getURLName().toString())); log.logDebug(BaseMessages.getString(PKG, "JobGetMailsFromPOP.FolderOpened.Subscribed", "" + this.folder.isSubscribed())); } } catch (Exception e) { throw new KettleException( defaultFolder ? BaseMessages.getString(PKG, "JobGetMailsFromPOP.Error.OpeningDefaultFolder") : BaseMessages.getString(PKG, "JobGetMailsFromPOP.Error.OpeningFolder", foldername), e); } } private Folder getRecursiveFolder(String foldername) throws MessagingException { Folder dfolder; String[] folderparts = foldername.split("/"); dfolder = this.getStore().getDefaultFolder(); // Open destination folder for (int i = 0; i < folderparts.length; i++) { dfolder = dfolder.getFolder(folderparts[i]); } return dfolder; } /** * Clear search terms. */ public void clearFilters() { this.nrSavedMessages = 0; this.nrDeletedMessages = 0; this.nrMovedMessages = 0; this.nrSavedAttachedFiles = 0; if (this.searchTerm != null) { this.searchTerm = null; } } /** * Disconnect from the server and close folder, connection. * * @throws KettleException */ public void disconnect() throws KettleException { disconnect(true); } /** * Close folder. * * @param expunge * expunge folder * @throws KettleException */ public void closeFolder(boolean expunge) throws KettleException { try { if (this.folder != null && this.folder.isOpen()) { if (log.isDebug()) { log.logDebug(BaseMessages.getString(PKG, "MailConnection.ClosingFolder", getFolderName())); } this.folder.close(expunge); this.folder = null; this.messages = null; this.message = null; this.messagenr = -1; if (log.isDebug()) { log.logDebug(BaseMessages.getString(PKG, "MailConnection.FolderClosed", getFolderName())); } } } catch (Exception e) { throw new KettleException( BaseMessages.getString(PKG, "JobGetMailsFromPOP.Error.ClosingFolder", getFolderName()), e); } } /** * Add search term. * * @param term * search term to add */ private void addSearchTerm(SearchTerm term) { if (this.searchTerm != null) { this.searchTerm = new AndTerm(this.searchTerm, term); } else { this.searchTerm = term; } } public SearchTerm getSearchTerm() { return searchTerm; } /** * Set filter on subject. * * @param subject * messages will be filtered on subject * @param notTerm * negate condition */ public void setSubjectTerm(String subject, boolean notTerm) { if (!Utils.isEmpty(subject)) { if (notTerm) { addSearchTerm(new NotTerm(new SubjectTerm(subject))); } else { addSearchTerm(new SubjectTerm(subject)); } } } /** * Search all messages with body containing the word bodyfilter * * @param bodyfilter * @param notTerm * negate condition */ public void setBodyTerm(String bodyfilter, boolean notTerm) { if (!Utils.isEmpty(bodyfilter)) { if (notTerm) { addSearchTerm(new NotTerm(new BodyTerm(bodyfilter))); } else { addSearchTerm(new BodyTerm(bodyfilter)); } } } /** * Set filter on message sender. * * @param sender * messages will be filtered on sender * @param notTerm * negate condition */ public void setSenderTerm(String sender, boolean notTerm) { if (!Utils.isEmpty(sender)) { if (notTerm) { addSearchTerm(new NotTerm(new FromStringTerm(sender))); } else { addSearchTerm(new FromStringTerm(sender)); } } } /** * Set filter on receipient. * * @param receipient * messages will be filtered on receipient */ public void setReceipientTerm(String receipient) { if (!Utils.isEmpty(receipient)) { addSearchTerm(new RecipientStringTerm(Message.RecipientType.TO, receipient)); } } /** * Set filter on message received date. * * @param receiveddate * messages will be filtered on receiveddate */ public void setReceivedDateTermEQ(Date receiveddate) { if (this.protocol == MailConnectionMeta.PROTOCOL_POP3) { log.logError(BaseMessages.getString(PKG, "MailConnection.Error.ReceivedDatePOP3Unsupported")); } else { addSearchTerm(new ReceivedDateTerm(ComparisonTerm.EQ, receiveddate)); } } /** * Set filter on message received date. * * @param futureDate * messages will be filtered on futureDate */ public void setReceivedDateTermLT(Date futureDate) { if (this.protocol == MailConnectionMeta.PROTOCOL_POP3) { log.logError(BaseMessages.getString(PKG, "MailConnection.Error.ReceivedDatePOP3Unsupported")); } else { addSearchTerm(new ReceivedDateTerm(ComparisonTerm.LT, futureDate)); } } /** * Set filter on message received date. * * @param pastDate * messages will be filtered on pastDate */ public void setReceivedDateTermGT(Date pastDate) { if (this.protocol == MailConnectionMeta.PROTOCOL_POP3) { log.logError(BaseMessages.getString(PKG, "MailConnection.Error.ReceivedDatePOP3Unsupported")); } else { addSearchTerm(new ReceivedDateTerm(ComparisonTerm.GT, pastDate)); } } public void setReceivedDateTermBetween(Date beginDate, Date endDate) { if (this.protocol == MailConnectionMeta.PROTOCOL_POP3) { log.logError(BaseMessages.getString(PKG, "MailConnection.Error.ReceivedDatePOP3Unsupported")); } else { addSearchTerm(new AndTerm(new ReceivedDateTerm(ComparisonTerm.LT, endDate), new ReceivedDateTerm(ComparisonTerm.GT, beginDate))); } } public void setFlagTermNew() { addSearchTerm(new FlagTerm(new Flags(Flags.Flag.RECENT), true)); } public void setFlagTermOld() { addSearchTerm(new FlagTerm(new Flags(Flags.Flag.RECENT), false)); } public void setFlagTermRead() { addSearchTerm(new FlagTerm(new Flags(Flags.Flag.SEEN), true)); } public void setFlagTermUnread() { addSearchTerm(new FlagTerm(new Flags(Flags.Flag.SEEN), false)); } public void setFlagTermFlagged() { addSearchTerm(new FlagTerm(new Flags(Flags.Flag.FLAGGED), true)); } public void setFlagTermNotFlagged() { addSearchTerm(new FlagTerm(new Flags(Flags.Flag.FLAGGED), false)); } public void setFlagTermDraft() { addSearchTerm(new FlagTerm(new Flags(Flags.Flag.DRAFT), true)); } public void setFlagTermNotDraft() { addSearchTerm(new FlagTerm(new Flags(Flags.Flag.DRAFT), false)); } /** * Retrieve all messages from server * * @throws KettleException */ public void retrieveMessages() throws KettleException { try { // search term? if (this.searchTerm != null) { this.messages = this.folder.search(this.searchTerm); } else { this.messages = this.folder.getMessages(); } } catch (Exception e) { this.messages = null; throw new KettleException( BaseMessages.getString(PKG, "MailConnection.Error.RetrieveMessages", getFolderName()), e); } } /* * public void retrieveUnreadMessages() throws Exception { if(this.protocol==PROTOCOL_POP3) throw new * KettleException("Cette fonction est uniquement accessible pour le protocol POP3!"); try { Message msgsAll[]; // * search term? if(this.searchTerm!=null) { msgsAll = this.folder.search(this.searchTerm); }else { msgsAll = * this.folder.getMessages(); } int unreadMsgs = this.folder.getUnreadMessageCount(); int msgCount = msgsAll.length; * * this.messages = this.folder.getMessages(msgCount - unreadMsgs + 1, msgCount); } catch (Exception e) { * this.messages= null; } } */ /** * Disconnect from the server and close folder, connection. * * @param expunge * expunge folder * @throws KettleException */ public void disconnect(boolean expunge) throws KettleException { if (log.isDebug()) { log.logDebug(BaseMessages.getString(PKG, "MailConnection.ClosingConnection")); } try { // close the folder, passing in a true value to expunge the deleted message closeFolder(expunge); clearFilters(); if (this.store != null) { this.store.close(); this.store = null; } if (this.session != null) { this.session = null; } if (this.destinationIMAPFolder != null) { this.destinationIMAPFolder.close(expunge); } if (log.isDebug()) { log.logDebug(BaseMessages.getString(PKG, "MailConnection.ConnectionClosed")); } } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "JobGetMailsFromPOP.Error.ClosingConnection"), e); } } /** * Export message content to a filename. * * @param filename * the target filename * @param foldername * the parent folder of filename * @throws KettleException */ public void saveMessageContentToFile(String filename, String foldername) throws KettleException { OutputStream os = null; try { os = KettleVFS.getOutputStream(foldername + (foldername.endsWith("/") ? "" : "/") + filename, false); getMessage().writeTo(os); updateSavedMessagesCounter(); } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "MailConnection.Error.SavingMessageContent", "" + this.message.getMessageNumber(), filename, foldername), e); } finally { if (os != null) { IOUtils.closeQuietly(os); } } } /** * Save attached files to a folder. * * @param foldername * the target foldername * @throws KettleException */ public void saveAttachedFiles(String foldername) throws KettleException { saveAttachedFiles(foldername, null); } /** * Save attached files to a folder. * * @param foldername * the target foldername * @param pattern * regular expression to filter on files * @throws KettleException */ public void saveAttachedFiles(String foldername, Pattern pattern) throws KettleException { Object content = null; try { content = getMessage().getContent(); if (content instanceof Multipart) { handleMultipart(foldername, (Multipart) content, pattern); } } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "MailConnection.Error.SavingAttachedFiles", "" + this.message.getMessageNumber(), foldername), e); } finally { if (content != null) { content = null; } } } private void handleMultipart(String foldername, Multipart multipart, Pattern pattern) throws KettleException { try { for (int i = 0, n = multipart.getCount(); i < n; i++) { handlePart(foldername, multipart.getBodyPart(i), pattern); } } catch (Exception e) { throw new KettleException(e); } } private void handlePart(String foldername, Part part, Pattern pattern) throws KettleException { try { String disposition = part.getDisposition(); // The RFC2183 doesn't REQUIRE Content-Disposition header field so we'll create one to // fake out the code below. if (disposition == null || disposition.length() < 1) { disposition = Part.ATTACHMENT; } if (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE)) { String MimeText = null; try { MimeText = MimeUtility.decodeText(part.getFileName()); } catch (Exception e) { // Ignore errors } if (MimeText != null) { String filename = MimeUtility.decodeText(part.getFileName()); if (isWildcardMatch(filename, pattern)) { // Save file saveFile(foldername, filename, part.getInputStream()); updateSavedAttachedFilesCounter(); if (log.isDetailed()) { log.logDetailed(BaseMessages.getString(PKG, "JobGetMailsFromPOP.AttachedFileSaved", filename, "" + getMessage().getMessageNumber(), foldername)); } } } } } catch (Exception e) { throw new KettleException(e); } } @VisibleForTesting static String findValidTarget(String folderName, final String fileName) throws KettleException { if (fileName == null || folderName == null) { throw new IllegalArgumentException("Cannot have null arguments to findValidTarget"); } String fileNameRoot = FilenameUtils.getBaseName(fileName), ext = "." + FilenameUtils.getExtension(fileName); if ((ext.length() == 1)) { // only a "." ext = ""; } String rtn = "", base = FilenameUtils.concat(folderName, fileNameRoot); int baseSz = base.length(); StringBuilder build = new StringBuilder(baseSz).append(base); int i = -1; do { i++; build.setLength(baseSz); // bring string back to size build.append(i > 0 ? Integer.toString(i) : "").append(ext); rtn = build.toString(); } while (KettleVFS.fileExists(rtn)); return rtn; } private static void saveFile(String foldername, String filename, InputStream input) throws KettleException { OutputStream fos = null; BufferedOutputStream bos = null; BufferedInputStream bis = null; try { // Do no overwrite existing file String targetFileName; if (filename == null) { File f = File.createTempFile("xx", ".out"); f.deleteOnExit(); // Clean up file filename = f.getName(); targetFileName = foldername + "/" + filename; // Note - createTempFile Used - so will be unique } else { targetFileName = findValidTarget(foldername, filename); } fos = KettleVFS.getOutputStream(targetFileName, false); bos = new BufferedOutputStream(fos); bis = new BufferedInputStream(input); IOUtils.copy(bis, bos); bos.flush(); } catch (Exception e) { throw new KettleException(e); } finally { if (bis != null) { IOUtils.closeQuietly(bis); bis = null; // Help the GC } if (bos != null) { IOUtils.closeQuietly(bos); bos = null; // Help the GC // Note - closing the BufferedOuputStream closes the underlying output stream according to the Javadoc } } } private boolean isWildcardMatch(String filename, Pattern pattern) { boolean retval = true; if (pattern != null) { Matcher matcher = pattern.matcher(filename); retval = (matcher.matches()); } return retval; } /** * Delete current fetched message * * @throws KettleException */ public void deleteMessage() throws KettleException { try { this.message.setFlag(Flags.Flag.DELETED, true); updateDeletedMessagesCounter(); } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "MailConnection.Error.DeletingMessage", "" + getMessage().getMessageNumber()), e); } } /** * Set destination folder * * @param foldername * destination foldername * @param createFolder * flag create folder if needed * @throws KettleException */ public void setDestinationFolder(String foldername, boolean createFolder) throws KettleException { try { String[] folderparts = foldername.split("/"); Folder f = this.getStore().getDefaultFolder(); // Open destination folder for (int i = 0; i < folderparts.length; i++) { f = f.getFolder(folderparts[i]); if (!f.exists()) { if (createFolder) { // Create folder f.create(Folder.HOLDS_MESSAGES); } else { throw new KettleException( BaseMessages.getString(PKG, "MailConnection.Error.FolderNotFound", foldername)); } } } this.destinationIMAPFolder = f; } catch (Exception e) { throw new KettleException(e); } } /** * Move current message to a target folder. (IMAP) You must call setDestinationFolder before calling this method * * @throws KettleException */ public void moveMessage() throws KettleException { try { // move all messages this.folder.copyMessages(new Message[] { this.message }, this.destinationIMAPFolder); updatedMovedMessagesCounter(); // Make sure to delete messages deleteMessage(); } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "MailConnection.Error.MovingMessage", "" + getMessage().getMessageNumber(), this.destinationIMAPFolder.getName()), e); } } /** * Returns the foldername. * * @return foldername */ public String getFolderName() { if (this.folder == null) { return ""; } return this.folder.getName(); } /** * Returns the server name/Ip. * * @return server */ public String getServer() { return server; } /** * Returns the protocol. * * @return protocol */ public int getProtocol() { return protocol; } /** * Returns all messages. * * @return all messages */ public Message[] getMessages() { return messages; } private void updateMessageNr() { this.messagenr++; } private int getMessageNr() { return this.messagenr; } /** * Get next message. * * @throws KettleException */ public void fetchNext() throws KettleException { updateMessageNr(); try { this.message = this.messages[getMessageNr()]; } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "MailConnection.Error.FetchingMessages"), e); } } /** * Returns the current message. * * @return current message */ public Message getMessage() { return this.message; } /** * Returns the number of messages. * * @return messages count */ public int getMessagesCount() { return this.messages.length; } public void updateSavedMessagesCounter() { this.nrSavedMessages++; } public int getSavedMessagesCounter() { return this.nrSavedMessages; } public int getSavedAttachedFilesCounter() { return this.nrSavedAttachedFiles; } public void updateSavedAttachedFilesCounter() { this.nrSavedAttachedFiles++; } public int getDeletedMessagesCounter() { return this.nrDeletedMessages; } private void updateDeletedMessagesCounter() { this.nrDeletedMessages++; } private void setDeletedMessagesCounter() { this.nrDeletedMessages = getMessagesCount(); } /** * Returns count of moved messages. * * @return count of moved messages */ public int getMovedMessagesCounter() { return this.nrMovedMessages; } /** * Update count of moved messages. */ private void updatedMovedMessagesCounter() { this.nrMovedMessages++; } /** * Set count of moved messages. */ private void setMovedMessagesCounter() { this.nrMovedMessages = getMessagesCount(); } /** * Delete messages. * * @throws KettleException */ public void deleteMessages(boolean setCounter) throws KettleException { try { this.folder.setFlags(this.messages, new Flags(Flags.Flag.DELETED), true); if (setCounter) { setDeletedMessagesCounter(); } } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "MailConnection.Error.DeletingMessage"), e); } } /** * Move messages to a folder. You must call setDestinationFolder before calling this method * * @throws KettleException */ public void moveMessages() throws KettleException { try { this.folder.copyMessages(this.messages, this.destinationIMAPFolder); deleteMessages(false); setMovedMessagesCounter(); } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "MailConnection.Error.MovingMessages", this.destinationIMAPFolder.getName()), e); } } /** * Check if a folder exists on server (only IMAP). * * @param foldername * the name of the folder * @return true is folder exists */ public boolean folderExists(String foldername) { boolean retval = false; Folder dfolder = null; try { // Open destination folder dfolder = getRecursiveFolder(foldername); if (dfolder.exists()) { retval = true; } } catch (Exception e) { // Ignore errors } finally { try { if (dfolder != null) { dfolder.close(false); } } catch (Exception e) { /* Ignore */ } } return retval; } private HashSet<String> returnSubfolders(Folder folder) throws KettleException { HashSet<String> list = new HashSet<String>(); try { if ((folder.getType() & Folder.HOLDS_FOLDERS) != 0) { Folder[] f = folder.list(); for (int i = 0; i < f.length; i++) { // Search for sub folders if ((f[i].getType() & Folder.HOLDS_FOLDERS) != 0) { list.add(f[i].getFullName()); list.addAll(returnSubfolders(f[i])); } } } } catch (MessagingException m) { throw new KettleException(m); } return list; } /** * Returns all subfolders of the specified folder * * @param folder * parent folder * @return sub folders */ public String[] returnAllFolders(Folder folder) throws KettleException { HashSet<String> list = new HashSet<String>(); list = returnSubfolders(folder); return list.toArray(new String[list.size()]); } /** * Returns all subfolders of the current folder * * @return sub folders */ public String[] returnAllFolders() throws KettleException { return returnAllFolders(getFolder()); } /** * Returns all subfolders of the folder folder * * @param folder * target folder * @return sub folders */ public String[] returnAllFolders(String folder) throws KettleException { Folder dfolder = null; String[] retval = null; try { if (Utils.isEmpty(folder)) { // Default folder dfolder = getStore().getDefaultFolder(); } else { dfolder = getStore().getFolder(folder); } retval = returnAllFolders(dfolder); } catch (Exception e) { // Ignore errors } finally { try { if (dfolder != null) { dfolder.close(false); } } catch (Exception e) { /* Ignore */ } } return retval; } public String getMessageBody() throws Exception { return getMessageBody(getMessage()); } /** * Return the primary text content of the message. */ public String getMessageBody(Message m) throws MessagingException, IOException { return getMessageBodyOrContentType(m, false); } public String getMessageBodyContentType(Message m) throws MessagingException, IOException { return getMessageBodyOrContentType(m, true); } private String getMessageBodyOrContentType(Part p, final boolean returnContentType) throws MessagingException, IOException { if (p.isMimeType("text/*")) { String s = (String) p.getContent(); return returnContentType ? p.getContentType() : s; } if (p.isMimeType("multipart/alternative")) { // prefer html text over plain text Multipart mp = (Multipart) p.getContent(); String text = null; for (int i = 0; i < mp.getCount(); i++) { Part bp = mp.getBodyPart(i); if (bp.isMimeType("text/plain")) { if (text == null) { text = getMessageBodyOrContentType(bp, returnContentType); } } } return text; } else if (p.isMimeType("multipart/*")) { Multipart mp = (Multipart) p.getContent(); for (int i = 0; i < mp.getCount(); i++) { String s = getMessageBodyOrContentType(mp.getBodyPart(i), returnContentType); if (s != null) { return s; } } } return null; } /** * Returns if message is new * * @return true if new message */ public boolean isMessageNew() { return isMessageNew(getMessage()); } public boolean isMessageNew(Message msg) { try { return msg.isSet(Flag.RECENT); } catch (MessagingException e) { return false; } } /** * Returns if message is read * * @return true if message is read */ public boolean isMessageRead() { return isMessageRead(getMessage()); } public boolean isMessageRead(Message msg) { try { return msg.isSet(Flag.SEEN); } catch (MessagingException e) { return false; } } /** * Returns if message is read * * @return true if message is flagged */ public boolean isMessageFlagged() { return isMessageFlagged(getMessage()); } public boolean isMessageFlagged(Message msg) { try { return msg.isSet(Flag.FLAGGED); } catch (MessagingException e) { return false; } } /** * Returns if message is deleted * * @return true if message is deleted */ public boolean isMessageDeleted() { return isMessageDeleted(getMessage()); } public boolean isMessageDeleted(Message msg) { try { return msg.isSet(Flag.DELETED); } catch (MessagingException e) { return false; } } /** * Returns if message is Draft * * @return true if message is Draft */ public boolean isMessageDraft() { return isMessageDraft(getMessage()); } public boolean isMessageDraft(Message msg) { try { return msg.isSet(Flag.DRAFT); } catch (MessagingException e) { return false; } } public String toString() { if (getServer() != null) { return getServer(); } else { return "-"; } } /** * Returns attached files count for the current message * * @return true if message is Draft * @param pattern * (optional) */ public int getAttachedFilesCount(Pattern pattern) throws KettleException { return getAttachedFilesCount(getMessage(), pattern); } public int getAttachedFilesCount(Message message, Pattern pattern) throws KettleException { Object content = null; int retval = 0; try { content = message.getContent(); if (content instanceof Multipart) { Multipart multipart = (Multipart) content; for (int i = 0, n = multipart.getCount(); i < n; i++) { Part part = multipart.getBodyPart(i); String disposition = part.getDisposition(); if ((disposition != null) && (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE))) { String MimeText = null; try { MimeText = MimeUtility.decodeText(part.getFileName()); } catch (Exception e) { // Ignore errors } if (MimeText != null) { String filename = MimeUtility.decodeText(part.getFileName()); if (isWildcardMatch(filename, pattern)) { retval++; } } } } } } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "MailConnection.Error.CountingAttachedFiles", "" + this.message.getMessageNumber()), e); } finally { if (content != null) { content = null; } } return retval; } }