1 |
/* |
2 |
* Message.java |
3 |
* Copyright(C) 2002 The Free Software Foundation |
4 |
* |
5 |
* This file is part of GNU JavaMail, a library. |
6 |
* |
7 |
* GNU JavaMail is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License as published by |
9 |
* the Free Software Foundation; either version 2 of the License, or |
10 |
*(at your option) any later version. |
11 |
* |
12 |
* GNU JavaMail is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this library; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 |
* |
21 |
* As a special exception, if you link this library with other files to |
22 |
* produce an executable, this library does not by itself cause the |
23 |
* resulting executable to be covered by the GNU General Public License. |
24 |
* This exception does not however invalidate any other reasons why the |
25 |
* executable file might be covered by the GNU General Public License. |
26 |
*/ |
27 |
|
28 |
package javax.mail; |
29 |
|
30 |
import java.io.InvalidObjectException; |
31 |
import java.io.ObjectStreamException; |
32 |
import java.io.Serializable; |
33 |
import java.util.Date; |
34 |
import java.util.Enumeration; |
35 |
import javax.mail.search.SearchTerm; |
36 |
|
37 |
/** |
38 |
* This class models an email message. This is an abstract class. Subclasses |
39 |
* provide actual implementations. |
40 |
* <p> |
41 |
* Message implements the Part interface. Message contains a set of attributes |
42 |
* and a "content". Messages within a folder also have a set of flags that |
43 |
* describe its state within the folder. |
44 |
* <p> |
45 |
* Message defines some new attributes in addition to those defined in the |
46 |
* Part interface. These attributes specify meta-data for the message - i.e., |
47 |
* addressing and descriptive information about the message. |
48 |
* <p> |
49 |
* Message objects are obtained either from a Folder or by constructing a new |
50 |
* Message object of the appropriate subclass. Messages that have been received |
51 |
* are normally retrieved from a folder named "INBOX". |
52 |
* <p> |
53 |
* A Message object obtained from a folder is just a lightweight reference to |
54 |
* the actual message. The Message is 'lazily' filled up(on demand) when |
55 |
* each item is requested from the message. Note that certain folder |
56 |
* implementations may return Message objects that are pre-filled with certain |
57 |
* user-specified items. To send a message, an appropriate subclass of |
58 |
* Message(e.g., MimeMessage) is instantiated, the attributes and content |
59 |
* are filled in, and the message is sent using the <code>Transport.send</code> |
60 |
* method. |
61 |
* |
62 |
* @see Part |
63 |
* @author <a href="mailto:dog@gnu.org">Chris Burdess</a> |
64 |
* @version 1.3 |
65 |
*/ |
66 |
public abstract class Message |
67 |
implements Part |
68 |
{ |
69 |
|
70 |
/** |
71 |
* This inner class defines the types of recipients allowed by the |
72 |
* Message class. |
73 |
* The currently defined types are TO, CC and BCC. |
74 |
* Note that this class only has a protected constructor, |
75 |
* thereby restricting new Recipient types to either this class or |
76 |
* subclasses. This effectively implements an enumeration of the allowed |
77 |
* Recipient types. The following code sample shows how to use this class |
78 |
* to obtain the "TO" recipients from a message. |
79 |
*/ |
80 |
public static class RecipientType |
81 |
implements Serializable |
82 |
{ |
83 |
|
84 |
/** |
85 |
* The "To"(primary) recipients. |
86 |
*/ |
87 |
public static final RecipientType TO = new RecipientType("To"); |
88 |
|
89 |
/** |
90 |
* The "Cc"(carbon copy) recipients. |
91 |
*/ |
92 |
public static final RecipientType CC = new RecipientType("Cc"); |
93 |
|
94 |
/** |
95 |
* The "Bcc"(blind carbon copy) recipients. |
96 |
*/ |
97 |
public static final RecipientType BCC = new RecipientType("Bcc"); |
98 |
|
99 |
/** |
100 |
* The type of recipient, usually the name of a corresponding Internet |
101 |
* standard header. |
102 |
*/ |
103 |
protected String type; |
104 |
|
105 |
/** |
106 |
* Constructor for use by subclasses. |
107 |
*/ |
108 |
protected RecipientType(String type) |
109 |
{ |
110 |
this.type = type; |
111 |
} |
112 |
|
113 |
/** |
114 |
* When deserializing a RecipientType, we need to make sure to return |
115 |
* only one of the known static final instances defined in this class. |
116 |
* Subclasses must implement their own readResolve method that checks |
117 |
* for their known instances before calling this super method. |
118 |
*/ |
119 |
protected Object readResolve() |
120 |
throws ObjectStreamException |
121 |
{ |
122 |
if (type.equals("To")) |
123 |
{ |
124 |
return TO; |
125 |
} |
126 |
if (type.equals("Cc")) |
127 |
{ |
128 |
return CC; |
129 |
} |
130 |
if (type.equals("Bcc")) |
131 |
{ |
132 |
return BCC; |
133 |
} |
134 |
throw new InvalidObjectException("Unknown RecipientType: " + type); |
135 |
} |
136 |
|
137 |
} |
138 |
|
139 |
/** |
140 |
* The number of this message within its folder, |
141 |
* or zero if the message was not retrieved from a folder. |
142 |
*/ |
143 |
protected int msgnum = 0; |
144 |
|
145 |
/** |
146 |
* True if this message has been expunged. |
147 |
*/ |
148 |
protected boolean expunged = false; |
149 |
|
150 |
/** |
151 |
* The containing folder, if this message is obtained from a folder |
152 |
*/ |
153 |
protected Folder folder; |
154 |
|
155 |
/** |
156 |
* The Session object for this Message |
157 |
*/ |
158 |
protected Session session; |
159 |
|
160 |
/** |
161 |
* No-arg version of the constructor. |
162 |
*/ |
163 |
protected Message() |
164 |
{ |
165 |
folder = null; |
166 |
session = null; |
167 |
} |
168 |
|
169 |
/** |
170 |
* Constructor that takes a Folder and a message number. |
171 |
* Used by Folder implementations. |
172 |
* @param folder containing folder |
173 |
* @param msgnum this message's sequence number within this folder |
174 |
*/ |
175 |
protected Message(Folder folder, int msgnum) |
176 |
{ |
177 |
this.folder = folder; |
178 |
this.msgnum = msgnum; |
179 |
session = folder.store.session; |
180 |
} |
181 |
|
182 |
/** |
183 |
* Constructor that takes a Session. |
184 |
* Used for client created Message objects. |
185 |
* @param session A Session object |
186 |
*/ |
187 |
protected Message(Session session) |
188 |
{ |
189 |
folder = null; |
190 |
this.session = session; |
191 |
} |
192 |
|
193 |
/** |
194 |
* Returns the "From" attribute. |
195 |
* The "From" attribute contains the identity of the person(s) who |
196 |
* wished this message to be sent. |
197 |
* <p> |
198 |
* In certain implementations, this may be different from the entity that |
199 |
* actually sent the message. |
200 |
* <p> |
201 |
* This method returns null if this attribute is not present in this message. |
202 |
* Returns an empty array if this attribute is present, but contains no |
203 |
* addresses. |
204 |
*/ |
205 |
public abstract Address[] getFrom() |
206 |
throws MessagingException; |
207 |
|
208 |
/** |
209 |
* Set the "From" attribute in this Message. |
210 |
* The value of this attribute is obtained from the property "mail.user". |
211 |
* If this property is absent, the system property "user.name" is used. |
212 |
* @exception IllegalWriteException if the underlying implementation does |
213 |
* not support modification of existing values |
214 |
* @exception IllegalStateException if this message is obtained from a |
215 |
* READ_ONLY folder. |
216 |
*/ |
217 |
public abstract void setFrom() |
218 |
throws MessagingException; |
219 |
|
220 |
/** |
221 |
* Set the "From" attribute in this Message. |
222 |
* @param address the sender |
223 |
* @exception IllegalWriteException if the underlying implementation does |
224 |
* not support modification of existing values |
225 |
* @exception IllegalStateException if this message is obtained from a |
226 |
* READ_ONLY folder. |
227 |
*/ |
228 |
public abstract void setFrom(Address address) |
229 |
throws MessagingException; |
230 |
|
231 |
/** |
232 |
* Add these addresses to the existing "From" attribute |
233 |
* @param addresses - the senders |
234 |
* @exception IllegalWriteException if the underlying implementation does |
235 |
* not support modification of existing values |
236 |
* @exception IllegalStateException if this message is obtained from a |
237 |
* READ_ONLY folder. |
238 |
*/ |
239 |
public abstract void addFrom(Address[] addresses) |
240 |
throws MessagingException; |
241 |
|
242 |
/** |
243 |
* Get all the recipient addresses of the given type. |
244 |
* <p> |
245 |
* This method returns null if the header for the given type is not present |
246 |
* in this message. Returns an empty array if the header is present, but |
247 |
* contains no addresses. |
248 |
* @param type the recipient type |
249 |
*/ |
250 |
public abstract Address[] getRecipients(RecipientType type) |
251 |
throws MessagingException; |
252 |
|
253 |
/** |
254 |
* Get all the recipient addresses for the message. |
255 |
* The default implementation extracts the TO, CC, and BCC recipients |
256 |
* using the getRecipients method. |
257 |
* <p> |
258 |
* This method returns null if none of the recipient headers are present in |
259 |
* this message. Returns an empty array if any recipient header is present, |
260 |
* but contains no addresses. |
261 |
*/ |
262 |
public Address[] getAllRecipients() |
263 |
throws MessagingException |
264 |
{ |
265 |
Address[] to = getRecipients(RecipientType.TO); |
266 |
Address[] cc = getRecipients(RecipientType.CC); |
267 |
Address[] bcc = getRecipients(RecipientType.BCC); |
268 |
|
269 |
if (cc == null && bcc == null) |
270 |
return to; |
271 |
|
272 |
int count = (to == null ? 0 : to.length) + |
273 |
(cc == null ? 0 : cc.length) + |
274 |
(bcc == null ? 0 : bcc.length); |
275 |
Address[] all = new Address[count]; |
276 |
int offset = 0; |
277 |
if (to != null) |
278 |
{ |
279 |
System.arraycopy(to, 0, all, offset, to.length); |
280 |
offset += to.length; |
281 |
} |
282 |
if (cc != null) |
283 |
{ |
284 |
System.arraycopy(cc, 0, all, offset, cc.length); |
285 |
offset += cc.length; |
286 |
} |
287 |
if (bcc != null) |
288 |
{ |
289 |
System.arraycopy(bcc, 0, all, offset, bcc.length); |
290 |
offset += bcc.length; |
291 |
} |
292 |
return all; |
293 |
} |
294 |
|
295 |
/** |
296 |
* Set the recipient addresses. |
297 |
* All addresses of the specified type are replaced by the addresses |
298 |
* parameter. |
299 |
* @param type the recipient type |
300 |
* @param addresses the addresses |
301 |
* @exception IllegalWriteException if the underlying implementation |
302 |
* does not support modification of existing values |
303 |
* @exception IllegalStateException if this message is obtained from |
304 |
* a READ_ONLY folder. |
305 |
*/ |
306 |
public abstract void setRecipients(RecipientType type, Address[] addresses) |
307 |
throws MessagingException; |
308 |
|
309 |
/** |
310 |
* Set the recipient address. |
311 |
* All addresses of the specified type are replaced by the address parameter. |
312 |
* <p> |
313 |
* The default implementation uses the setRecipients method. |
314 |
* @exception IllegalWriteException if the underlying implementation |
315 |
* does not support modification of existing values |
316 |
*/ |
317 |
public void setRecipient(RecipientType type, Address address) |
318 |
throws MessagingException |
319 |
{ |
320 |
setRecipients(type, new Address[] { address }); |
321 |
} |
322 |
|
323 |
/** |
324 |
* Add these recipient addresses to the existing ones of the given type. |
325 |
* @param type the recipient type |
326 |
* @param addresses the addresses |
327 |
* @exception IllegalWriteException if the underlying implementation |
328 |
* does not support modification of existing values |
329 |
* @exception IllegalStateException if this message is obtained from |
330 |
* a READ_ONLY folder. |
331 |
*/ |
332 |
public abstract void addRecipients(RecipientType type, Address[] addresses) |
333 |
throws MessagingException; |
334 |
|
335 |
/** |
336 |
* Add this recipient address to the existing ones of the given type. |
337 |
* <p> |
338 |
* The default implementation uses the addRecipients method. |
339 |
* @exception IllegalWriteException if the underlying implementation |
340 |
* does not support modification of existing values |
341 |
*/ |
342 |
public void addRecipient(RecipientType type, Address address) |
343 |
throws MessagingException |
344 |
{ |
345 |
addRecipients(type, new Address[] { address }); |
346 |
} |
347 |
|
348 |
/** |
349 |
* Get the addresses to which replies should be directed. |
350 |
* This will usually be the sender of the message, but some messages |
351 |
* may direct replies to a different address. |
352 |
* <p> |
353 |
* The default implementation simply calls the getFrom method. |
354 |
* <p> |
355 |
* This method returns null if the corresponding header is not present. |
356 |
* Returns an empty array if the header is present, but contains no |
357 |
* addresses. |
358 |
*/ |
359 |
public Address[] getReplyTo() |
360 |
throws MessagingException |
361 |
{ |
362 |
return getFrom(); |
363 |
} |
364 |
|
365 |
/** |
366 |
* Set the addresses to which replies should be directed. |
367 |
*(Normally only a single address will be specified.) |
368 |
* Not all message types allow this to be specified separately from |
369 |
* the sender of the message. |
370 |
* <p> |
371 |
* The default implementation provided here just throws the |
372 |
* MethodNotSupportedException. |
373 |
*/ |
374 |
public void setReplyTo(Address[] addresses) |
375 |
throws MessagingException |
376 |
{ |
377 |
throw new MethodNotSupportedException(); |
378 |
} |
379 |
|
380 |
/** |
381 |
* Get the subject of this message. |
382 |
*/ |
383 |
public abstract String getSubject() |
384 |
throws MessagingException; |
385 |
|
386 |
/** |
387 |
* Set the subject of this message. |
388 |
* @param subject the subject |
389 |
* @exception IllegalWriteException if the underlying implementation |
390 |
* does not support modification of existing values |
391 |
* @exception IllegalStateException if this message is obtained from |
392 |
* a READ_ONLY folder. |
393 |
*/ |
394 |
public abstract void setSubject(String subject) |
395 |
throws MessagingException; |
396 |
|
397 |
/** |
398 |
* Get the date this message was sent. |
399 |
*/ |
400 |
public abstract Date getSentDate() |
401 |
throws MessagingException; |
402 |
|
403 |
/** |
404 |
* Set the sent date of this message. |
405 |
* @param date the sent date of this message |
406 |
* @exception IllegalWriteException if the underlying implementation |
407 |
* does not support modification of existing values |
408 |
* @exception IllegalStateException if this message is obtained from |
409 |
* a READ_ONLY folder. |
410 |
*/ |
411 |
public abstract void setSentDate(Date date) |
412 |
throws MessagingException; |
413 |
|
414 |
/** |
415 |
* Get the date this message was received. |
416 |
*/ |
417 |
public abstract Date getReceivedDate() |
418 |
throws MessagingException; |
419 |
|
420 |
/** |
421 |
* Returns a Flags object containing the flags for this message. |
422 |
* <p> |
423 |
* Modifying any of the flags in this returned Flags object will not affect |
424 |
* the flags of this message. Use <code>setFlags()</code> to do that. |
425 |
*/ |
426 |
public abstract Flags getFlags() |
427 |
throws MessagingException; |
428 |
|
429 |
/** |
430 |
* Check whether the flag specified in the flag argument is set in this |
431 |
* message. |
432 |
* <p> |
433 |
* The default implementation uses getFlags. |
434 |
* @param flag the flag |
435 |
* @return value of the specified flag for this message |
436 |
*/ |
437 |
public boolean isSet(Flags.Flag flag) |
438 |
throws MessagingException |
439 |
{ |
440 |
return getFlags().contains(flag); |
441 |
} |
442 |
|
443 |
/** |
444 |
* Set the specified flags on this message to the specified value. |
445 |
* Note that any flags in this message that are not specified in the |
446 |
* given Flags object are unaffected. |
447 |
* <p> |
448 |
* This will result in a MessageChangedEvent being delivered to any |
449 |
* MessageChangedListener registered on this Message's containing folder. |
450 |
* @param flag Flags object containing the flags to be set |
451 |
* @param set the value to be set |
452 |
* @exception IllegalWriteException if the underlying implementation |
453 |
* does not support modification of existing values |
454 |
* @exception IllegalStateException if this message is obtained from |
455 |
* a READ_ONLY folder. |
456 |
*/ |
457 |
public abstract void setFlags(Flags flag, boolean set) |
458 |
throws MessagingException; |
459 |
|
460 |
/** |
461 |
* Set the specified flag on this message to the specified value. |
462 |
* This will result in a MessageChangedEvent being delivered to any |
463 |
* MessageChangedListener registered on this Message's containing folder. |
464 |
* <p> |
465 |
* The default implementation uses the <code>setFlags</code> method. |
466 |
* @exception IllegalWriteException if the underlying implementation |
467 |
* does not support modification of existing values |
468 |
* @exception IllegalStateException if this message is obtained from |
469 |
* a READ_ONLY folder. |
470 |
*/ |
471 |
public void setFlag(Flags.Flag flag, boolean set) |
472 |
throws MessagingException |
473 |
{ |
474 |
setFlags(new Flags(flag), set); |
475 |
} |
476 |
|
477 |
/** |
478 |
* Get the Message number for this Message. |
479 |
* A Message object's message number is the relative position of this |
480 |
* Message in its Folder. Note that the message number for a particular |
481 |
* Message can change during a session if other messages in the Folder |
482 |
* are deleted and expunged. |
483 |
* <p> |
484 |
* Valid message numbers start at 1. Messages that do not belong to any |
485 |
* folder(like newly composed or derived messages) have 0 as their |
486 |
* message number. |
487 |
*/ |
488 |
public int getMessageNumber() |
489 |
{ |
490 |
return msgnum; |
491 |
} |
492 |
|
493 |
/** |
494 |
* Set the Message number for this Message. |
495 |
* This method is invoked only by the implementation classes. |
496 |
*/ |
497 |
protected void setMessageNumber(int msgnum) |
498 |
{ |
499 |
this.msgnum = msgnum; |
500 |
} |
501 |
|
502 |
/** |
503 |
* Get the folder from which this message was obtained. |
504 |
* If this is a new message or nested message, this method returns null. |
505 |
*/ |
506 |
public Folder getFolder() |
507 |
{ |
508 |
return folder; |
509 |
} |
510 |
|
511 |
/** |
512 |
* Checks whether this message is expunged. |
513 |
* All other methods except <code>getMessageNumber()</code> are invalid |
514 |
* on an expunged Message object. |
515 |
* <p> |
516 |
* Messages that are expunged due to an explict expunge() request on the |
517 |
* containing Folder are removed from the Folder immediately. Messages that |
518 |
* are externally expunged by another source are marked "expunged" and return |
519 |
* true for the <code>isExpunged()</code> method, but they are not removed |
520 |
* from the Folder until an explicit <code>expunge()</code> is done on the |
521 |
* Folder. |
522 |
* <p> |
523 |
* See the description of <code>expunge()</code> for more details on |
524 |
* expunge handling. |
525 |
* @see Folder#expunge |
526 |
*/ |
527 |
public boolean isExpunged() |
528 |
{ |
529 |
return expunged; |
530 |
} |
531 |
|
532 |
/** |
533 |
* Sets the expunged flag for this Message. |
534 |
* This method is to be used only by the implementation classes. |
535 |
*/ |
536 |
protected void setExpunged(boolean expunged) |
537 |
{ |
538 |
this.expunged = expunged; |
539 |
} |
540 |
|
541 |
/** |
542 |
* Get a new Message suitable for a reply to this message. |
543 |
* The new Message will have its attributes and headers set up |
544 |
* appropriately. Note that this new message object will be empty, |
545 |
* that is, it will not have a "content". |
546 |
* These will have to be suitably filled in by the client. |
547 |
* <p> |
548 |
* If <code>replyToAll</code> is set, the new Message will be addressed |
549 |
* to all recipients of this message. Otherwise, the reply will be |
550 |
* addressed to only the sender of this message(using the value of the |
551 |
* <code>getReplyTo</code> method). |
552 |
* <p> |
553 |
* The "Subject" field is filled in with the original subject prefixed with |
554 |
* "Re:"(unless it already starts with "Re:"). |
555 |
* <p> |
556 |
* The reply message will use the same session as this message. |
557 |
* @param replyToAll reply should be sent to all recipients of this message |
558 |
*/ |
559 |
public abstract Message reply(boolean replyToAll) |
560 |
throws MessagingException; |
561 |
|
562 |
/** |
563 |
* Save any changes made to this message into the message-store when the |
564 |
* containing folder is closed, if the message is contained in a folder. |
565 |
*(Some implementations may save the changes immediately.) |
566 |
* Update any header fields to be consistent with the changed message |
567 |
* contents. If any part of a message's headers or contents are changed, |
568 |
* <code>saveChanges</code> must be called to ensure that those changes |
569 |
* are permanent. If <code>saveChanges</code> is not called, any such |
570 |
* modifications may or may not be saved, depending on the message store |
571 |
* and folder implementation. |
572 |
* <p> |
573 |
* Messages obtained from folders opened READ_ONLY should not be modified |
574 |
* and <code>saveChanges</code> should not be called on such messages. |
575 |
* @exception IllegalWriteException if the underlying implementation |
576 |
* does not support modification of existing values |
577 |
* @exception IllegalStateException if this message is obtained from |
578 |
* a READ_ONLY folder. |
579 |
*/ |
580 |
public abstract void saveChanges() |
581 |
throws MessagingException; |
582 |
|
583 |
/** |
584 |
* Apply the specified Search criterion to this message. |
585 |
* @param term the Search criterion |
586 |
*/ |
587 |
public boolean match(SearchTerm term) |
588 |
throws MessagingException |
589 |
{ |
590 |
return term.match(this); |
591 |
} |
592 |
|
593 |
} |