View Javadoc

1   /**
2    *
3    * Copyright 2003-2006 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package javax.mail;
19  
20  import java.io.InvalidObjectException;
21  import java.io.ObjectStreamException;
22  import java.io.Serializable;
23  import java.util.Date;
24  import javax.mail.search.SearchTerm;
25  
26  /**
27   * @version $Rev: 421852 $ $Date: 2006-07-14 03:02:19 -0700 (Fri, 14 Jul 2006) $
28   */
29  public abstract class Message implements Part {
30      /**
31       * Enumeration of types of recipients allowed by the Message class.
32       */
33      public static class RecipientType implements Serializable {
34          /**
35           * A "To" or primary recipient.
36           */
37          public static final RecipientType TO = new RecipientType("To");
38          /**
39           * A "Cc" or carbon-copy recipient.
40           */
41          public static final RecipientType CC = new RecipientType("Cc");
42          /**
43           * A "Bcc" or blind carbon-copy recipient.
44           */
45          public static final RecipientType BCC = new RecipientType("Bcc");
46          protected String type;
47  
48          protected RecipientType(String type) {
49              this.type = type;
50          }
51  
52          protected Object readResolve() throws ObjectStreamException {
53              if (type.equals("To")) {
54                  return TO;
55              } else if (type.equals("Cc")) {
56                  return CC;
57              } else if (type.equals("Bcc")) {
58                  return BCC;
59              } else {
60                  throw new InvalidObjectException("Invalid RecipientType: " + type);
61              }
62          }
63  
64          public String toString() {
65              return type;
66          }
67      }
68  
69      /**
70       * The index of a message withing its folder, or zero if the message was not retrieved from a folder.
71       */
72      protected int msgnum;
73      /**
74       * True if this message has been expunged from the Store.
75       */
76      protected boolean expunged;
77      /**
78       * The {@link Folder} that contains this message, or null if it was not obtained from a folder.
79       */
80      protected Folder folder;
81      /**
82       * The {@link Session} associated with this message.
83       */
84      protected Session session;
85  
86      /**
87       * Default constructor.
88       */
89      protected Message() {
90      }
91  
92      /**
93       * Constructor initializing folder and message msgnum; intended to be used by implementations of Folder.
94       *
95       * @param folder the folder that contains the message
96       * @param msgnum the message index within the folder
97       */
98      protected Message(Folder folder, int msgnum) {
99          this.folder = folder;
100         this.msgnum = msgnum;
101         // make sure we copy the session information from the folder.
102         this.session = folder.getStore().getSession();
103     }
104 
105     /**
106      * Constructor initializing the session; intended to by used by client created instances.
107      *
108      * @param session the session associated with this message
109      */
110     protected Message(Session session) {
111         this.session = session;
112     }
113 
114     /**
115      * Return the "From" header indicating the identity of the person who the message is from;
116      * in some circumstances this may be different to the actual sender.
117      *
118      * @return a list of addresses this message is from; may be empty if the header is present but empty, or null
119      *         if the header is not present
120      * @throws MessagingException if there was a problem accessing the store
121      */
122     public abstract Address[] getFrom() throws MessagingException;
123 
124     /**
125      * Set the "From" header for this message to the value of the "mail.user" property,
126      * of if that property is not set, to the value of the system property "user.name"
127      *
128      * @throws MessagingException if there was a problem accessing the store
129      */
130     public abstract void setFrom() throws MessagingException;
131 
132     /**
133      * Set the "From" header to the supplied address.
134      *
135      * @param address the address of the person who the message is from
136      * @throws MessagingException if there was a problem accessing the store
137      */
138     public abstract void setFrom(Address address) throws MessagingException;
139 
140     /**
141      * Add multiple addresses to the "From" header.
142      *
143      * @param addresses the addresses to add
144      * @throws MessagingException if there was a problem accessing the store
145      */
146     public abstract void addFrom(Address[] addresses) throws MessagingException;
147 
148     /**
149      * Get all recipients of the given type.
150      *
151      * @param type the type of recipient to get
152      * @return a list of addresses; may be empty if the header is present but empty,
153      *         or null if the header is not present
154      * @throws MessagingException if there was a problem accessing the store
155      * @see RecipientType
156      */
157     public abstract Address[] getRecipients(RecipientType type) throws MessagingException;
158 
159     /**
160      * Get all recipients of this message.
161      * The default implementation extracts the To, Cc, and Bcc recipients using {@link #getRecipients(javax.mail.Message.RecipientType)}
162      * and then concatentates the results into a single array; it returns null if no headers are defined.
163      *
164      * @return an array containing all recipients
165      * @throws MessagingException if there was a problem accessing the store
166      */
167     public Address[] getAllRecipients() throws MessagingException {
168         Address[] to = getRecipients(RecipientType.TO);
169         Address[] cc = getRecipients(RecipientType.CC);
170         Address[] bcc = getRecipients(RecipientType.BCC);
171         if (to == null && cc == null && bcc == null) {
172             return null;
173         }
174         int length = (to != null ? to.length : 0) + (cc != null ? cc.length : 0) + (bcc != null ? bcc.length : 0);
175         Address[] result = new Address[length];
176         int j = 0;
177         if (to != null) {
178             for (int i = 0; i < to.length; i++) {
179                 result[j++] = to[i];
180             }
181         }
182         if (cc != null) {
183             for (int i = 0; i < cc.length; i++) {
184                 result[j++] = cc[i];
185             }
186         }
187         if (bcc != null) {
188             for (int i = 0; i < bcc.length; i++) {
189                 result[j++] = bcc[i];
190             }
191         }
192         return result;
193     }
194 
195     /**
196      * Set the list of recipients for the specified type.
197      *
198      * @param type      the type of recipient
199      * @param addresses the new addresses
200      * @throws MessagingException if there was a problem accessing the store
201      */
202     public abstract void setRecipients(RecipientType type, Address[] addresses) throws MessagingException;
203 
204     /**
205      * Set the list of recipients for the specified type to a single address.
206      *
207      * @param type    the type of recipient
208      * @param address the new address
209      * @throws MessagingException if there was a problem accessing the store
210      */
211     public void setRecipient(RecipientType type, Address address) throws MessagingException {
212         setRecipients(type, new Address[]{address});
213     }
214 
215     /**
216      * Add recipents of a specified type.
217      *
218      * @param type      the type of recipient
219      * @param addresses the addresses to add
220      * @throws MessagingException if there was a problem accessing the store
221      */
222     public abstract void addRecipients(RecipientType type, Address[] addresses) throws MessagingException;
223 
224     /**
225      * Add a recipent of a specified type.
226      *
227      * @param type    the type of recipient
228      * @param address the address to add
229      * @throws MessagingException if there was a problem accessing the store
230      */
231     public void addRecipient(RecipientType type, Address address) throws MessagingException {
232         addRecipients(type, new Address[]{address});
233     }
234 
235     /**
236      * Get the addresses to which replies should be directed.
237      * <p/>
238      * As the most common behavior is to return to sender, the default implementation
239      * simply calls {@link #getFrom()}.
240      *
241      * @return a list of addresses to which replies should be directed
242      * @throws MessagingException if there was a problem accessing the store
243      */
244     public Address[] getReplyTo() throws MessagingException {
245         return getFrom();
246     }
247 
248     /**
249      * Set the addresses to which replies should be directed.
250      * <p/>
251      * The default implementation throws a MethodNotSupportedException.
252      *
253      * @param addresses to which replies should be directed
254      * @throws MessagingException if there was a problem accessing the store
255      */
256     public void setReplyTo(Address[] addresses) throws MessagingException {
257         throw new MethodNotSupportedException("setReplyTo not supported");
258     }
259 
260     /**
261      * Get the subject for this message.
262      *
263      * @return the subject
264      * @throws MessagingException if there was a problem accessing the store
265      */
266     public abstract String getSubject() throws MessagingException;
267 
268     /**
269      * Set the subject of this message
270      *
271      * @param subject the subject
272      * @throws MessagingException if there was a problem accessing the store
273      */
274     public abstract void setSubject(String subject) throws MessagingException;
275 
276     /**
277      * Return the date that this message was sent.
278      *
279      * @return the date this message was sent
280      * @throws MessagingException if there was a problem accessing the store
281      */
282     public abstract Date getSentDate() throws MessagingException;
283 
284     /**
285      * Set the date this message was sent.
286      *
287      * @param sent the date when this message was sent
288      * @throws MessagingException if there was a problem accessing the store
289      */
290     public abstract void setSentDate(Date sent) throws MessagingException;
291 
292     /**
293      * Return the date this message was received.
294      *
295      * @return the date this message was received
296      * @throws MessagingException if there was a problem accessing the store
297      */
298     public abstract Date getReceivedDate() throws MessagingException;
299 
300     /**
301      * Return a copy the flags associated with this message.
302      *
303      * @return a copy of the flags for this message
304      * @throws MessagingException if there was a problem accessing the store
305      */
306     public abstract Flags getFlags() throws MessagingException;
307 
308     /**
309      * Check whether the supplied flag is set.
310      * The default implementation checks the flags returned by {@link #getFlags()}.
311      *
312      * @param flag the flags to check for
313      * @return true if the flags is set
314      * @throws MessagingException if there was a problem accessing the store
315      */
316     public boolean isSet(Flags.Flag flag) throws MessagingException {
317         return getFlags().contains(flag);
318     }
319 
320     /**
321      * Set the flags specified to the supplied value; flags not included in the
322      * supplied {@link Flags} parameter are not affected.
323      *
324      * @param flags the flags to modify
325      * @param set   the new value of those flags
326      * @throws MessagingException if there was a problem accessing the store
327      */
328     public abstract void setFlags(Flags flags, boolean set) throws MessagingException;
329 
330     /**
331      * Set a flag to the supplied value.
332      * The default implmentation uses {@link #setFlags(Flags, boolean)}.
333      *
334      * @param flag the flag to set
335      * @param set  the value for that flag
336      * @throws MessagingException if there was a problem accessing the store
337      */
338     public void setFlag(Flags.Flag flag, boolean set) throws MessagingException {
339         setFlags(new Flags(flag), set);
340     }
341 
342     /**
343      * Return the message number for this Message.
344      * This number refers to the relative position of this message in a Folder; the message
345      * number for any given message can change during a seesion if the Folder is expunged.
346      * Message numbers for messages in a folder start at one; the value zero indicates that
347      * this message does not belong to a folder.
348      *
349      * @return the message number
350      */
351     public int getMessageNumber() {
352         return msgnum;
353     }
354 
355     /**
356      * Set the message number for this Message.
357      * This must be invoked by implementation classes when the message number changes.
358      *
359      * @param number the new message number
360      */
361     protected void setMessageNumber(int number) {
362         msgnum = number;
363     }
364 
365     /**
366      * Return the folder containing this message. If this is a new or nested message
367      * then this method returns null.
368      *
369      * @return the folder containing this message
370      */
371     public Folder getFolder() {
372         return folder;
373     }
374 
375     /**
376      * Checks to see if this message has been expunged. If true, all methods other than
377      * {@link #getMessageNumber()} are invalid.
378      *
379      * @return true if this method has been expunged
380      */
381     public boolean isExpunged() {
382         return expunged;
383     }
384 
385     /**
386      * Set the expunged flag for this message.
387      *
388      * @param expunged true if this message has been expunged
389      */
390     protected void setExpunged(boolean expunged) {
391         this.expunged = expunged;
392     }
393 
394     /**
395      * Create a new message suitable as a reply to this message with all headers set
396      * up appropriately. The message body will be empty.
397      * <p/>
398      * if replyToAll is set then the new message will be addressed to all recipients
399      * of this message; otherwise the reply will be addressed only to the sender as
400      * returned by {@link #getReplyTo()}.
401      * <p/>
402      * The subject field will be initialized with the subject field from the orginal
403      * message; the text "Re:" will be prepended unless it is already present.
404      *
405      * @param replyToAll if true, indciates the message should be addressed to all recipients not just the sender
406      * @return a new message suitable as a reply to this message
407      * @throws MessagingException if there was a problem accessing the store
408      */
409     public abstract Message reply(boolean replyToAll) throws MessagingException;
410 
411     /**
412      * To ensure changes are saved to the store, this message should be invoked
413      * before its containing folder is closed. Implementations may save modifications
414      * immediately but are free to defer such updates to they may be sent to the server
415      * in one batch; if saveChanges is not called then such changes may not be made
416      * permanent.
417      *
418      * @throws MessagingException if there was a problem accessing the store
419      */
420     public abstract void saveChanges() throws MessagingException;
421 
422     /**
423      * Apply the specified search criteria to this message
424      *
425      * @param term the search criteria
426      * @return true if this message matches the search criteria.
427      * @throws MessagingException if there was a problem accessing the store
428      */
429     public boolean match(SearchTerm term) throws MessagingException {
430         return term.match(this);
431     }
432 }