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 }