001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.component.mail;
018    
019    import java.io.IOException;
020    import java.util.Map;
021    
022    import javax.activation.DataHandler;
023    import javax.mail.Message;
024    import javax.mail.MessagingException;
025    import javax.mail.Multipart;
026    import javax.mail.Part;
027    
028    import org.apache.camel.RuntimeCamelException;
029    import org.apache.camel.impl.DefaultMessage;
030    import org.apache.camel.util.CollectionHelper;
031    import org.apache.camel.util.ExchangeHelper;
032    import org.apache.commons.logging.Log;
033    import org.apache.commons.logging.LogFactory;
034    
035    /**
036     * Represents a {@link org.apache.camel.Message} for working with Mail
037     *
038     * @version $Revision:520964 $
039     */
040    public class MailMessage extends DefaultMessage {
041        private static final transient Log LOG = LogFactory.getLog(MailMessage.class);
042        private Message mailMessage;
043    
044        public MailMessage() {
045        }
046    
047        public MailMessage(Message message) {
048            this.mailMessage = message;
049        }
050    
051        @Override
052        public String toString() {
053            if (mailMessage != null) {
054                return "MailMessage: " + MailUtils.dumpMessage(mailMessage);
055            } else {
056                return "MailMessage: " + getBody();
057            }
058        }
059    
060        public MailMessage copy() {
061            MailMessage answer = (MailMessage)super.copy();
062            answer.mailMessage = mailMessage;
063            return answer;
064        }
065    
066        /**
067         * Returns the underlying Mail message
068         */
069        public Message getMessage() {
070            return mailMessage;
071        }
072    
073        public void setMessage(Message mailMessage) {
074            this.mailMessage = mailMessage;
075        }
076    
077        @Override
078        public MailMessage newInstance() {
079            return new MailMessage();
080        }
081    
082        @Override
083        protected Object createBody() {
084            if (mailMessage != null) {
085                MailBinding binding = ExchangeHelper.getBinding(getExchange(), MailBinding.class);
086                return binding != null ? binding.extractBodyFromMail(getExchange(), mailMessage) : null;
087            }
088            return null;
089        }
090    
091        @Override
092        protected void populateInitialHeaders(Map<String, Object> map) {
093            if (mailMessage != null) {
094                try {
095                    MailBinding binding = ExchangeHelper.getBinding(getExchange(), MailBinding.class);
096                    if (binding != null) {
097                        map.putAll(binding.extractHeadersFromMail(mailMessage, getExchange()));
098                    }
099                } catch (MessagingException e) {
100                    throw new RuntimeCamelException("Error accessing headers due to: " + e.getMessage(), e);
101                }
102            }
103        }
104    
105        @Override
106        protected void populateInitialAttachments(Map<String, DataHandler> map) {
107            if (mailMessage != null) {
108                try {
109                    extractAttachments(mailMessage, map);
110                } catch (Exception e) {
111                    throw new RuntimeCamelException("Error populating the initial mail message attachments", e);
112                }
113            }
114        }
115    
116        public void copyFrom(org.apache.camel.Message that) {
117            super.copyFrom(that);
118            if (that instanceof MailMessage) {
119                MailMessage mailMessage = (MailMessage) that;
120                this.mailMessage = mailMessage.mailMessage;
121            }
122        }
123    
124        /**
125         * Parses the attachments of the given mail message and adds them to the map
126         *
127         * @param  message  the mail message with attachments
128         * @param  map      the map to add found attachments (attachmentFilename is the key)
129         */
130        protected static void extractAttachments(Message message, Map<String, DataHandler> map)
131            throws javax.mail.MessagingException, IOException {
132    
133            LOG.trace("Extracting attachments +++ start +++");
134    
135            Object content = message.getContent();
136            if (content instanceof Multipart) {
137                extractFromMultipart((Multipart)content, map);
138            } else if (content != null) {
139                LOG.trace("No attachments to extract as content is not Multipart: " + content.getClass().getName());
140            }
141    
142            LOG.trace("Extracting attachments +++ done +++");
143        }
144        
145        protected static void extractFromMultipart(Multipart mp, Map<String, DataHandler> map) 
146            throws javax.mail.MessagingException, IOException {
147    
148            for (int i = 0; i < mp.getCount(); i++) {
149                Part part = mp.getBodyPart(i);
150                LOG.trace("Part #" + i + ": " + part);
151    
152                if (part.isMimeType("multipart/*")) {
153                    LOG.trace("Part #" + i + ": is mimetype: multipart/*");
154                    extractFromMultipart((Multipart)part.getContent(), map);
155                } else {
156                    String disposition = part.getDisposition();
157                    if (LOG.isTraceEnabled()) {
158                        LOG.trace("Part #" + i + ": Disposition: " + part.getDisposition());
159                        LOG.trace("Part #" + i + ": Description: " + part.getDescription());
160                        LOG.trace("Part #" + i + ": ContentType: " + part.getContentType());
161                        LOG.trace("Part #" + i + ": FileName: " + part.getFileName());
162                        LOG.trace("Part #" + i + ": Size: " + part.getSize());
163                        LOG.trace("Part #" + i + ": LineCount: " + part.getLineCount());
164                    }
165    
166                    if (disposition != null && (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE))) {
167                        // only add named attachments
168                        String fileName = part.getFileName();
169                        if (fileName != null) {
170                            LOG.debug("Mail contains file attachment: " + fileName);
171                            // Parts marked with a disposition of Part.ATTACHMENT are clearly attachments
172                            CollectionHelper.appendValue(map, fileName, part.getDataHandler());
173                        }
174                    }
175                }
176            }
177        }    
178    
179    }