001 /** 002 * 003 * Copyright 2003-2006 The Apache Software Foundation 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package javax.mail; 019 020 import java.io.InvalidObjectException; 021 import java.io.ObjectStreamException; 022 import java.io.Serializable; 023 import java.util.Date; 024 import javax.mail.search.SearchTerm; 025 026 /** 027 * @version $Rev: 421852 $ $Date: 2006-07-14 03:02:19 -0700 (Fri, 14 Jul 2006) $ 028 */ 029 public abstract class Message implements Part { 030 /** 031 * Enumeration of types of recipients allowed by the Message class. 032 */ 033 public static class RecipientType implements Serializable { 034 /** 035 * A "To" or primary recipient. 036 */ 037 public static final RecipientType TO = new RecipientType("To"); 038 /** 039 * A "Cc" or carbon-copy recipient. 040 */ 041 public static final RecipientType CC = new RecipientType("Cc"); 042 /** 043 * A "Bcc" or blind carbon-copy recipient. 044 */ 045 public static final RecipientType BCC = new RecipientType("Bcc"); 046 protected String type; 047 048 protected RecipientType(String type) { 049 this.type = type; 050 } 051 052 protected Object readResolve() throws ObjectStreamException { 053 if (type.equals("To")) { 054 return TO; 055 } else if (type.equals("Cc")) { 056 return CC; 057 } else if (type.equals("Bcc")) { 058 return BCC; 059 } else { 060 throw new InvalidObjectException("Invalid RecipientType: " + type); 061 } 062 } 063 064 public String toString() { 065 return type; 066 } 067 } 068 069 /** 070 * The index of a message withing its folder, or zero if the message was not retrieved from a folder. 071 */ 072 protected int msgnum; 073 /** 074 * True if this message has been expunged from the Store. 075 */ 076 protected boolean expunged; 077 /** 078 * The {@link Folder} that contains this message, or null if it was not obtained from a folder. 079 */ 080 protected Folder folder; 081 /** 082 * The {@link Session} associated with this message. 083 */ 084 protected Session session; 085 086 /** 087 * Default constructor. 088 */ 089 protected Message() { 090 } 091 092 /** 093 * Constructor initializing folder and message msgnum; intended to be used by implementations of Folder. 094 * 095 * @param folder the folder that contains the message 096 * @param msgnum the message index within the folder 097 */ 098 protected Message(Folder folder, int msgnum) { 099 this.folder = folder; 100 this.msgnum = msgnum; 101 // make sure we copy the session information from the folder. 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 }