1 /**
2 *
3 * Copyright 2003-2004 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: 384283 $ $Date: 2006-03-08 09:51:44 -0800 (Wed, 08 Mar 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
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 }