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