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.text.DateFormat;
020    import java.util.Date;
021    import javax.mail.Address;
022    import javax.mail.Message;
023    import javax.mail.MessagingException;
024    
025    import org.apache.camel.util.ObjectHelper;
026    
027    /**
028     * Mail utility class.
029     * <p>
030     * Parts of the code copied from Apache ServiceMix.
031     *
032     * @version 
033     */
034    public final class MailUtils {
035    
036        public static final int DEFAULT_PORT_SMTP = 25;
037        public static final int DEFAULT_PORT_SMTPS = 465;
038        public static final int DEFAULT_PORT_POP3 = 110;
039        public static final int DEFAULT_PORT_POP3S = 995;
040        public static final int DEFAULT_PORT_NNTP = 119;
041        public static final int DEFAULT_PORT_IMAP = 143;
042        public static final int DEFAULT_PORT_IMAPS = 993;
043    
044        public static final String PROTOCOL_SMTP = "smtp";
045        public static final String PROTOCOL_SMTPS = "smtps";
046        public static final String PROTOCOL_POP3 = "pop3";
047        public static final String PROTOCOL_POP3S = "pop3s";
048        public static final String PROTOCOL_NNTP = "nntp";
049        public static final String PROTOCOL_IMAP = "imap";
050        public static final String PROTOCOL_IMAPS = "imaps";
051    
052        private MailUtils() {
053        }
054    
055        /**
056         * Returns the default port for a given protocol.
057         * <p>
058         * If a protocol could not successfully be determined the default port number for SMTP protocol is returned.
059         *
060         * @param protocol the protocol
061         * @return the default port
062         */
063        public static int getDefaultPortForProtocol(final String protocol) {
064            int port = DEFAULT_PORT_SMTP;
065    
066            if (protocol != null) {
067                if (protocol.equalsIgnoreCase(PROTOCOL_IMAP)) {
068                    port = DEFAULT_PORT_IMAP;
069                } else if (protocol.equalsIgnoreCase(PROTOCOL_IMAPS)) {
070                    port = DEFAULT_PORT_IMAPS;
071                } else if (protocol.equalsIgnoreCase(PROTOCOL_NNTP)) {
072                    port = DEFAULT_PORT_NNTP;
073                } else if (protocol.equalsIgnoreCase(PROTOCOL_POP3)) {
074                    port = DEFAULT_PORT_POP3;
075                } else if (protocol.equalsIgnoreCase(PROTOCOL_POP3S)) {
076                    port = DEFAULT_PORT_POP3S;
077                } else if (protocol.equalsIgnoreCase(PROTOCOL_SMTP)) {
078                    port = DEFAULT_PORT_SMTP;
079                } else if (protocol.equalsIgnoreCase(PROTOCOL_SMTPS)) {
080                    port = DEFAULT_PORT_SMTPS;
081                } else {
082                    port = DEFAULT_PORT_SMTP;
083                }
084            }
085    
086            return port;
087        }
088    
089        /**
090         * Gets a log dump of the given message that can be used for tracing etc.
091         *
092         * @param message the Mail message
093         * @return a log string with important fields dumped
094         */
095        public static String dumpMessage(Message message) {
096            if (message == null) {
097                return "null";
098            }
099            
100            try {
101                StringBuilder sb = new StringBuilder();
102    
103                int number = message.getMessageNumber();
104                sb.append("messageNumber=[").append(number).append("]");
105    
106                Address[] from = message.getFrom();
107                if (from != null) {
108                    for (Address adr : from) {
109                        sb.append(", from=[").append(adr).append("]");
110                    }
111                }
112    
113                Address[] to = message.getRecipients(Message.RecipientType.TO);
114                if (to != null) {
115                    for (Address adr : to) {
116                        sb.append(", to=[").append(adr).append("]");
117                    }
118                }
119    
120                String subject = message.getSubject();
121                if (subject != null) {
122                    sb.append(", subject=[").append(subject).append("]");
123                }
124    
125                Date sentDate = message.getSentDate();
126                if (sentDate != null) {
127                    sb.append(", sentDate=[").append(DateFormat.getDateTimeInstance().format(sentDate)).append("]");
128                }
129    
130                Date receivedDate = message.getReceivedDate();
131                if (receivedDate != null) {
132                    sb.append(", receivedDate=[").append(DateFormat.getDateTimeInstance().format(receivedDate)).append("]");
133                }
134    
135                return sb.toString();
136            } catch (MessagingException e) {
137                // ignore the error and just return tostring 
138                return message.toString();
139            }
140        }
141    
142        /**
143         * Pads the content-type so it has a space after semi colon that separate pairs.
144         * <p/>
145         * This is needed as some mail servers will choke otherwise
146         *
147         * @param contentType the content type
148         * @return the padded content type
149         */
150        public static String padContentType(String contentType) {
151            StringBuilder sb = new StringBuilder();
152            String[] parts = contentType.split(";");
153            for (int i = 0; i < parts.length; i++) {
154                String part = parts[i];
155                if (ObjectHelper.isNotEmpty(part)) {
156                    part = part.trim();
157                    sb.append(part);
158                    if (i < parts.length - 1) {
159                        sb.append("; ");
160                    }
161                }
162            }
163            return sb.toString();
164        }
165    
166        /**
167         * Replaces the charset in the content-type
168         *
169         * @param contentType the content-type
170         * @param charset  the charset to replace, can be <tt>null</tt> to remove charset
171         * @return the content-type with replaced charset
172         */
173        public static String replaceCharSet(String contentType, String charset) {
174            boolean replaced = false;
175            StringBuilder sb = new StringBuilder();
176            String[] parts = contentType.split(";");
177            for (int i = 0; i < parts.length; i++) {
178                String part = parts[i];
179                part = part.trim();
180                if (!part.startsWith("charset")) {
181                    part = part.trim();
182                    if (sb.length() > 0) {
183                        sb.append("; ");
184                    }
185                    sb.append(part);
186                } else if (charset != null) {
187                    // replace with new charset
188                    if (sb.length() > 0) {
189                        sb.append("; ");
190                    }
191                    sb.append("charset=");
192                    sb.append(charset);
193                    replaced = true;
194                }
195            }
196    
197            // if we did not replace any existing charset, then append new charset at the end
198            if (!replaced && charset != null) {
199                if (sb.length() > 0) {
200                    sb.append("; ");
201                }
202                sb.append("charset=");
203                sb.append(charset);
204            }
205    
206            return sb.toString();
207        }
208    
209        /**
210         * Gets the charset from the content-type
211         *
212         * @param contentType the content-type
213         * @return the charset, or <tt>null</tt> if no charset existed
214         */
215        public static String getCharSetFromContentType(String contentType) {
216            if (contentType == null) {
217                return null;
218            }
219    
220            String[] parts = contentType.split(";");
221            for (int i = 0; i < parts.length; i++) {
222                String part = parts[i];
223                part = part.trim();
224                if (part.startsWith("charset")) {
225                    return ObjectHelper.after(part, "charset=");
226                }
227            }
228            return null;
229        }
230    
231    }