001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    
020    package org.apache.james.mime4j.message;
021    
022    import java.util.Arrays;
023    import java.util.Collection;
024    import java.util.Collections;
025    import java.util.Date;
026    import java.util.TimeZone;
027    
028    import org.apache.james.mime4j.dom.Header;
029    import org.apache.james.mime4j.dom.Message;
030    import org.apache.james.mime4j.dom.address.Address;
031    import org.apache.james.mime4j.dom.address.AddressList;
032    import org.apache.james.mime4j.dom.address.Mailbox;
033    import org.apache.james.mime4j.dom.address.MailboxList;
034    import org.apache.james.mime4j.dom.field.AddressListField;
035    import org.apache.james.mime4j.dom.field.DateTimeField;
036    import org.apache.james.mime4j.dom.field.FieldName;
037    import org.apache.james.mime4j.dom.field.MailboxField;
038    import org.apache.james.mime4j.dom.field.MailboxListField;
039    import org.apache.james.mime4j.dom.field.ParsedField;
040    import org.apache.james.mime4j.dom.field.UnstructuredField;
041    import org.apache.james.mime4j.stream.Field;
042    
043    /**
044     * Abstract MIME message.
045     */
046    public abstract class AbstractMessage extends AbstractEntity implements Message {
047    
048        /**
049         * Returns the value of the <i>Message-ID</i> header field of this message
050         * or <code>null</code> if it is not present.
051         *
052         * @return the identifier of this message.
053         */
054        public String getMessageId() {
055            Field field = obtainField(FieldName.MESSAGE_ID);
056            if (field == null)
057                return null;
058    
059            return field.getBody();
060        }
061    
062        /**
063         * Creates and sets a new <i>Message-ID</i> header field for this message.
064         * A <code>Header</code> is created if this message does not already have
065         * one.
066         *
067         * @param hostname
068         *            host name to be included in the identifier or
069         *            <code>null</code> if no host name should be included.
070         */
071        public void createMessageId(String hostname) {
072            Header header = obtainHeader();
073    
074            header.setField(newMessageId(hostname));
075        }
076    
077        protected abstract ParsedField newMessageId(String hostname);
078    
079        /**
080         * Returns the (decoded) value of the <i>Subject</i> header field of this
081         * message or <code>null</code> if it is not present.
082         *
083         * @return the subject of this message.
084         */
085        public String getSubject() {
086            UnstructuredField field = obtainField(FieldName.SUBJECT);
087            if (field == null)
088                return null;
089    
090            return field.getValue();
091        }
092    
093        /**
094         * Sets the <i>Subject</i> header field for this message. The specified
095         * string may contain non-ASCII characters, in which case it gets encoded as
096         * an 'encoded-word' automatically. A <code>Header</code> is created if
097         * this message does not already have one.
098         *
099         * @param subject
100         *            subject to set or <code>null</code> to remove the subject
101         *            header field.
102         */
103        public void setSubject(String subject) {
104            Header header = obtainHeader();
105    
106            if (subject == null) {
107                header.removeFields(FieldName.SUBJECT);
108            } else {
109                header.setField(newSubject(subject));
110            }
111        }
112    
113        /**
114         * Returns the value of the <i>Date</i> header field of this message as
115         * <code>Date</code> object or <code>null</code> if it is not present.
116         *
117         * @return the date of this message.
118         */
119        public Date getDate() {
120            DateTimeField dateField = obtainField(FieldName.DATE);
121            if (dateField == null)
122                return null;
123    
124            return dateField.getDate();
125        }
126    
127        /**
128         * Sets the <i>Date</i> header field for this message. This method uses the
129         * default <code>TimeZone</code> of this host to encode the specified
130         * <code>Date</code> object into a string.
131         *
132         * @param date
133         *            date to set or <code>null</code> to remove the date header
134         *            field.
135         */
136        public void setDate(Date date) {
137            setDate(date, null);
138        }
139    
140        /**
141         * Sets the <i>Date</i> header field for this message. The specified
142         * <code>TimeZone</code> is used to encode the specified <code>Date</code>
143         * object into a string.
144         *
145         * @param date
146         *            date to set or <code>null</code> to remove the date header
147         *            field.
148         * @param zone
149         *            a time zone.
150         */
151        public void setDate(Date date, TimeZone zone) {
152            Header header = obtainHeader();
153    
154            if (date == null) {
155                header.removeFields(FieldName.DATE);
156            } else {
157                header.setField(newDate(date, zone));
158            }
159        }
160    
161        /**
162         * Returns the value of the <i>Sender</i> header field of this message as
163         * <code>Mailbox</code> object or <code>null</code> if it is not
164         * present.
165         *
166         * @return the sender of this message.
167         */
168        public Mailbox getSender() {
169            return getMailbox(FieldName.SENDER);
170        }
171    
172        /**
173         * Sets the <i>Sender</i> header field of this message to the specified
174         * mailbox address.
175         *
176         * @param sender
177         *            address to set or <code>null</code> to remove the header
178         *            field.
179         */
180        public void setSender(Mailbox sender) {
181            setMailbox(FieldName.SENDER, sender);
182        }
183    
184        /**
185         * Returns the value of the <i>From</i> header field of this message as
186         * <code>MailboxList</code> object or <code>null</code> if it is not
187         * present.
188         *
189         * @return value of the from field of this message.
190         */
191        public MailboxList getFrom() {
192            return getMailboxList(FieldName.FROM);
193        }
194    
195        /**
196         * Sets the <i>From</i> header field of this message to the specified
197         * mailbox address.
198         *
199         * @param from
200         *            address to set or <code>null</code> to remove the header
201         *            field.
202         */
203        public void setFrom(Mailbox from) {
204            setMailboxList(FieldName.FROM, from);
205        }
206    
207        /**
208         * Sets the <i>From</i> header field of this message to the specified
209         * mailbox addresses.
210         *
211         * @param from
212         *            addresses to set or <code>null</code> or no arguments to
213         *            remove the header field.
214         */
215        public void setFrom(Mailbox... from) {
216            setMailboxList(FieldName.FROM, from);
217        }
218    
219        /**
220         * Sets the <i>From</i> header field of this message to the specified
221         * mailbox addresses.
222         *
223         * @param from
224         *            addresses to set or <code>null</code> or an empty collection
225         *            to remove the header field.
226         */
227        public void setFrom(Collection<Mailbox> from) {
228            setMailboxList(FieldName.FROM, from);
229        }
230    
231        /**
232         * Returns the value of the <i>To</i> header field of this message as
233         * <code>AddressList</code> object or <code>null</code> if it is not
234         * present.
235         *
236         * @return value of the to field of this message.
237         */
238        public AddressList getTo() {
239            return getAddressList(FieldName.TO);
240        }
241    
242        /**
243         * Sets the <i>To</i> header field of this message to the specified
244         * address.
245         *
246         * @param to
247         *            address to set or <code>null</code> to remove the header
248         *            field.
249         */
250        public void setTo(Address to) {
251            setAddressList(FieldName.TO, to);
252        }
253    
254        /**
255         * Sets the <i>To</i> header field of this message to the specified
256         * addresses.
257         *
258         * @param to
259         *            addresses to set or <code>null</code> or no arguments to
260         *            remove the header field.
261         */
262        public void setTo(Address... to) {
263            setAddressList(FieldName.TO, to);
264        }
265    
266        /**
267         * Sets the <i>To</i> header field of this message to the specified
268         * addresses.
269         *
270         * @param to
271         *            addresses to set or <code>null</code> or an empty collection
272         *            to remove the header field.
273         */
274        public void setTo(Collection<? extends Address> to) {
275            setAddressList(FieldName.TO, to);
276        }
277    
278        /**
279         * Returns the value of the <i>Cc</i> header field of this message as
280         * <code>AddressList</code> object or <code>null</code> if it is not
281         * present.
282         *
283         * @return value of the cc field of this message.
284         */
285        public AddressList getCc() {
286            return getAddressList(FieldName.CC);
287        }
288    
289        /**
290         * Sets the <i>Cc</i> header field of this message to the specified
291         * address.
292         *
293         * @param cc
294         *            address to set or <code>null</code> to remove the header
295         *            field.
296         */
297        public void setCc(Address cc) {
298            setAddressList(FieldName.CC, cc);
299        }
300    
301        /**
302         * Sets the <i>Cc</i> header field of this message to the specified
303         * addresses.
304         *
305         * @param cc
306         *            addresses to set or <code>null</code> or no arguments to
307         *            remove the header field.
308         */
309        public void setCc(Address... cc) {
310            setAddressList(FieldName.CC, cc);
311        }
312    
313        /**
314         * Sets the <i>Cc</i> header field of this message to the specified
315         * addresses.
316         *
317         * @param cc
318         *            addresses to set or <code>null</code> or an empty collection
319         *            to remove the header field.
320         */
321        public void setCc(Collection<? extends Address> cc) {
322            setAddressList(FieldName.CC, cc);
323        }
324    
325        /**
326         * Returns the value of the <i>Bcc</i> header field of this message as
327         * <code>AddressList</code> object or <code>null</code> if it is not
328         * present.
329         *
330         * @return value of the bcc field of this message.
331         */
332        public AddressList getBcc() {
333            return getAddressList(FieldName.BCC);
334        }
335    
336        /**
337         * Sets the <i>Bcc</i> header field of this message to the specified
338         * address.
339         *
340         * @param bcc
341         *            address to set or <code>null</code> to remove the header
342         *            field.
343         */
344        public void setBcc(Address bcc) {
345            setAddressList(FieldName.BCC, bcc);
346        }
347    
348        /**
349         * Sets the <i>Bcc</i> header field of this message to the specified
350         * addresses.
351         *
352         * @param bcc
353         *            addresses to set or <code>null</code> or no arguments to
354         *            remove the header field.
355         */
356        public void setBcc(Address... bcc) {
357            setAddressList(FieldName.BCC, bcc);
358        }
359    
360        /**
361         * Sets the <i>Bcc</i> header field of this message to the specified
362         * addresses.
363         *
364         * @param bcc
365         *            addresses to set or <code>null</code> or an empty collection
366         *            to remove the header field.
367         */
368        public void setBcc(Collection<? extends Address> bcc) {
369            setAddressList(FieldName.BCC, bcc);
370        }
371    
372        /**
373         * Returns the value of the <i>Reply-To</i> header field of this message as
374         * <code>AddressList</code> object or <code>null</code> if it is not
375         * present.
376         *
377         * @return value of the reply to field of this message.
378         */
379        public AddressList getReplyTo() {
380            return getAddressList(FieldName.REPLY_TO);
381        }
382    
383        /**
384         * Sets the <i>Reply-To</i> header field of this message to the specified
385         * address.
386         *
387         * @param replyTo
388         *            address to set or <code>null</code> to remove the header
389         *            field.
390         */
391        public void setReplyTo(Address replyTo) {
392            setAddressList(FieldName.REPLY_TO, replyTo);
393        }
394    
395        /**
396         * Sets the <i>Reply-To</i> header field of this message to the specified
397         * addresses.
398         *
399         * @param replyTo
400         *            addresses to set or <code>null</code> or no arguments to
401         *            remove the header field.
402         */
403        public void setReplyTo(Address... replyTo) {
404            setAddressList(FieldName.REPLY_TO, replyTo);
405        }
406    
407        /**
408         * Sets the <i>Reply-To</i> header field of this message to the specified
409         * addresses.
410         *
411         * @param replyTo
412         *            addresses to set or <code>null</code> or an empty collection
413         *            to remove the header field.
414         */
415        public void setReplyTo(Collection<? extends Address> replyTo) {
416            setAddressList(FieldName.REPLY_TO, replyTo);
417        }
418    
419        private Mailbox getMailbox(String fieldName) {
420            MailboxField field = obtainField(fieldName);
421            if (field == null)
422                return null;
423    
424            return field.getMailbox();
425        }
426    
427        private void setMailbox(String fieldName, Mailbox mailbox) {
428            Header header = obtainHeader();
429    
430            if (mailbox == null) {
431                header.removeFields(fieldName);
432            } else {
433                header.setField(newMailbox(fieldName, mailbox));
434            }
435        }
436    
437        private MailboxList getMailboxList(String fieldName) {
438            MailboxListField field = obtainField(fieldName);
439            if (field == null)
440                return null;
441    
442            return field.getMailboxList();
443        }
444    
445        private void setMailboxList(String fieldName, Mailbox mailbox) {
446            setMailboxList(fieldName, mailbox == null ? null : Collections
447                    .singleton(mailbox));
448        }
449    
450        private void setMailboxList(String fieldName, Mailbox... mailboxes) {
451            setMailboxList(fieldName, mailboxes == null ? null : Arrays
452                    .asList(mailboxes));
453        }
454    
455        private void setMailboxList(String fieldName, Collection<Mailbox> mailboxes) {
456            Header header = obtainHeader();
457    
458            if (mailboxes == null || mailboxes.isEmpty()) {
459                header.removeFields(fieldName);
460            } else {
461                header.setField(newMailboxList(fieldName, mailboxes));
462            }
463        }
464    
465        private AddressList getAddressList(String fieldName) {
466            AddressListField field = obtainField(fieldName);
467            if (field == null)
468                return null;
469    
470            return field.getAddressList();
471        }
472    
473        private void setAddressList(String fieldName, Address address) {
474            setAddressList(fieldName, address == null ? null : Collections
475                    .singleton(address));
476        }
477    
478        private void setAddressList(String fieldName, Address... addresses) {
479            setAddressList(fieldName, addresses == null ? null : Arrays
480                    .asList(addresses));
481        }
482    
483        private void setAddressList(String fieldName, Collection<? extends Address> addresses) {
484            Header header = obtainHeader();
485    
486            if (addresses == null || addresses.isEmpty()) {
487                header.removeFields(fieldName);
488            } else {
489                header.setField(newAddressList(fieldName, addresses));
490            }
491        }
492    
493        protected abstract AddressListField newAddressList(String fieldName, Collection<? extends Address> addresses);
494    
495        protected abstract UnstructuredField newSubject(String subject);
496    
497        protected abstract DateTimeField newDate(Date date, TimeZone zone);
498    
499        protected abstract MailboxField newMailbox(String fieldName, Mailbox mailbox);
500    
501        protected abstract MailboxListField newMailboxList(String fieldName, Collection<Mailbox> mailboxes);
502    
503    
504    }