View Javadoc

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