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.commons.logging.Log;
032    import org.apache.commons.logging.LogFactory;
033    
034    /**
035     * Represents a {@link org.apache.camel.Message} for working with Mail
036     *
037     * @version $Revision:520964 $
038     */
039    public class MailMessage extends DefaultMessage {
040        private static final transient Log LOG = LogFactory.getLog(MailMessage.class);
041        private Message mailMessage;
042    
043        public MailMessage() {
044        }
045    
046        public MailMessage(Message message) {
047            this.mailMessage = message;
048        }
049    
050        @Override
051        public String toString() {
052            if (mailMessage != null) {
053                return "MailMessage: " + MailUtils.dumpMessage(mailMessage);
054            } else {
055                return "MailMessage: " + getBody();
056            }
057        }
058    
059        @Override
060        public MailExchange getExchange() {
061            return (MailExchange)super.getExchange();
062        }
063    
064        public MailMessage copy() {
065            MailMessage answer = (MailMessage)super.copy();
066            answer.mailMessage = mailMessage;
067            return answer;
068        }
069    
070        /**
071         * Returns the underlying Mail message
072         */
073        public Message getMessage() {
074            return mailMessage;
075        }
076    
077        public void setMessage(Message mailMessage) {
078            this.mailMessage = mailMessage;
079        }
080    
081        @Override
082        public Object getHeader(String name) {
083            Object answer = super.getHeader(name);
084            
085            // mimic case insensitive search of mail message getHeader
086            if (answer == null) {
087                answer = super.getHeader(name.toLowerCase());
088            }
089            return answer;
090        }
091      
092        @Override
093        public MailMessage newInstance() {
094            return new MailMessage();
095        }
096    
097        @Override
098        protected Object createBody() {
099            if (mailMessage != null) {
100                return getExchange().getBinding().extractBodyFromMail(getExchange(), mailMessage);
101            }
102            return null;
103        }
104    
105        @Override
106        protected void populateInitialHeaders(Map<String, Object> map) {
107            if (mailMessage != null) {
108                try {
109                    map.putAll(getExchange().getBinding().extractHeadersFromMail(mailMessage, getExchange()));
110                } catch (MessagingException e) {
111                    throw new RuntimeCamelException("Error accessing headers due to: " + e.getMessage(), e);
112                }
113            }
114        }
115    
116        @Override
117        protected void populateInitialAttachments(Map<String, DataHandler> map) {
118            if (mailMessage != null) {
119                try {
120                    extractAttachments(mailMessage, map);
121                } catch (Exception e) {
122                    throw new RuntimeCamelException("Error populating the initial mail message attachments", e);
123                }
124            }
125        }
126    
127        public void copyFrom(org.apache.camel.Message that) {
128            super.copyFrom(that);
129            if (that instanceof MailMessage) {
130                MailMessage mailMessage = (MailMessage) that;
131                this.mailMessage = mailMessage.mailMessage;
132            }
133        }
134    
135        /**
136         * Parses the attachments of the given mail message and adds them to the map
137         *
138         * @param  message  the mail message with attachments
139         * @param  map      the map to add found attachments (attachmentFilename is the key)
140         */
141        protected static void extractAttachments(Message message, Map<String, DataHandler> map)
142            throws javax.mail.MessagingException, IOException {
143    
144            LOG.trace("Extracting attachments +++ start +++");
145    
146            Object content = message.getContent();
147            if (content instanceof Multipart) {
148                extractFromMultipart((Multipart)content, map);
149            } else if (content != null) {
150                LOG.trace("No attachments to extract as content is not Multipart: " + content.getClass().getName());
151            }
152    
153            LOG.trace("Extracting attachments +++ done +++");
154        }
155        
156        protected static void extractFromMultipart(Multipart mp, Map<String, DataHandler> map) 
157            throws javax.mail.MessagingException, IOException {
158    
159            for (int i = 0; i < mp.getCount(); i++) {
160                Part part = mp.getBodyPart(i);
161                LOG.trace("Part #" + i + ": " + part);
162    
163                if (part.isMimeType("multipart/*")) {
164                    LOG.trace("Part #" + i + ": is mimetype: multipart/*");
165                    extractFromMultipart((Multipart)part.getContent(), map);
166                } else {
167                    String disposition = part.getDisposition();
168                    if (LOG.isTraceEnabled()) {
169                        LOG.trace("Part #" + i + ": Disposition: " + part.getDisposition());
170                        LOG.trace("Part #" + i + ": Description: " + part.getDescription());
171                        LOG.trace("Part #" + i + ": ContentType: " + part.getContentType());
172                        LOG.trace("Part #" + i + ": FileName: " + part.getFileName());
173                        LOG.trace("Part #" + i + ": Size: " + part.getSize());
174                        LOG.trace("Part #" + i + ": LineCount: " + part.getLineCount());
175                    }
176    
177                    if (disposition != null && (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE))) {
178                        // only add named attachments
179                        String fileName = part.getFileName();
180                        if (fileName != null) {
181                            LOG.debug("Mail contains file attachment: " + fileName);
182                            // Parts marked with a disposition of Part.ATTACHMENT are clearly attachments
183                            CollectionHelper.appendValue(map, fileName, part.getDataHandler());
184                        }
185                    }
186                }
187            }
188        }    
189    
190    }