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