Skip to content

Package: MimeMessage$RecipientType

MimeMessage$RecipientType

nameinstructionbranchcomplexitylinemethod
MimeMessage.RecipientType(String)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
readResolve()
M: 3 C: 7
70%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
static {...}
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

Coverage

1: /*
2: * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package jakarta.mail.internet;
18:
19: import java.io.BufferedInputStream;
20: import java.io.ByteArrayInputStream;
21: import java.io.ByteArrayOutputStream;
22: import java.io.IOException;
23: import java.io.InputStream;
24: import java.io.ObjectStreamException;
25: import java.io.OutputStream;
26: import java.io.UnsupportedEncodingException;
27: import java.text.ParseException;
28: import java.util.ArrayList;
29: import java.util.Date;
30: import java.util.Enumeration;
31: import java.util.List;
32: import java.util.Properties;
33:
34: import jakarta.activation.DataHandler;
35: import jakarta.mail.Address;
36: import jakarta.mail.Flags;
37: import jakarta.mail.Folder;
38: import jakarta.mail.FolderClosedException;
39: import jakarta.mail.Header;
40: import jakarta.mail.IllegalWriteException;
41: import jakarta.mail.Message;
42: import jakarta.mail.MessageRemovedException;
43: import jakarta.mail.MessagingException;
44: import jakarta.mail.Multipart;
45: import jakarta.mail.Session;
46: import jakarta.mail.util.LineOutputStream;
47:
48:
49:
50: /**
51: * This class represents a MIME style email message. It implements
52: * the <code>Message</code> abstract class and the <code>MimePart</code>
53: * interface. <p>
54: *
55: * Clients wanting to create new MIME style messages will instantiate
56: * an empty MimeMessage object and then fill it with appropriate
57: * attributes and content. <p>
58: *
59: * Service providers that implement MIME compliant backend stores may
60: * want to subclass MimeMessage and override certain methods to provide
61: * specific implementations. The simplest case is probably a provider
62: * that generates a MIME style input stream and leaves the parsing of
63: * the stream to this class. <p>
64: *
65: * MimeMessage uses the <code>InternetHeaders</code> class to parse and
66: * store the top level RFC 822 headers of a message. <p>
67: *
68: * The <code>mail.mime.address.strict</code> session property controls
69: * the parsing of address headers. By default, strict parsing of address
70: * headers is done. If this property is set to <code>"false"</code>,
71: * strict parsing is not done and many illegal addresses that sometimes
72: * occur in real messages are allowed. See the <code>InternetAddress</code>
73: * class for details.
74: *
75: * <hr><strong>A note on RFC 822 and MIME headers</strong><p>
76: *
77: * RFC 822 header fields <strong>must</strong> contain only
78: * US-ASCII characters. MIME allows non ASCII characters to be present
79: * in certain portions of certain headers, by encoding those characters.
80: * RFC 2047 specifies the rules for doing this. The MimeUtility
81: * class provided in this package can be used to to achieve this.
82: * Callers of the <code>setHeader</code>, <code>addHeader</code>, and
83: * <code>addHeaderLine</code> methods are responsible for enforcing
84: * the MIME requirements for the specified headers. In addition, these
85: * header fields must be folded (wrapped) before being sent if they
86: * exceed the line length limitation for the transport (1000 bytes for
87: * SMTP). Received headers may have been folded. The application is
88: * responsible for folding and unfolding headers as appropriate.
89: *
90: * @author John Mani
91: * @author Bill Shannon
92: * @author Max Spivak
93: * @author Kanwar Oberoi
94: * @see        jakarta.mail.internet.MimeUtility
95: * @see        jakarta.mail.Part
96: * @see        jakarta.mail.Message
97: * @see        jakarta.mail.internet.MimePart
98: * @see        jakarta.mail.internet.InternetAddress
99: */
100:
101: public class MimeMessage extends Message implements MimePart {
102:
103: /**
104: * The DataHandler object representing this Message's content.
105: */
106: protected DataHandler dh;
107:
108: /**
109: * Byte array that holds the bytes of this Message's content.
110: */
111: protected byte[] content;
112:
113: /**
114: * If the data for this message was supplied by an
115: * InputStream that implements the SharedInputStream interface,
116: * <code>contentStream</code> is another such stream representing
117: * the content of this message. In this case, <code>content</code>
118: * will be null.
119: *
120: * @since        JavaMail 1.2
121: */
122: protected InputStream contentStream;
123:
124: /**
125: * The InternetHeaders object that stores the header
126: * of this message.
127: */
128: protected InternetHeaders headers;
129:
130: /**
131: * The Flags for this message.
132: */
133: protected Flags flags;
134:
135: /**
136: * A flag indicating whether the message has been modified.
137: * If the message has not been modified, any data in the
138: * <code>content</code> array is assumed to be valid and is used
139: * directly in the <code>writeTo</code> method. This flag is
140: * set to true when an empty message is created or when the
141: * <code>saveChanges</code> method is called.
142: *
143: * @since        JavaMail 1.2
144: */
145: protected boolean modified = false;
146:
147: /**
148: * Does the <code>saveChanges</code> method need to be called on
149: * this message? This flag is set to false by the public constructor
150: * and set to true by the <code>saveChanges</code> method. The
151: * <code>writeTo</code> method checks this flag and calls the
152: * <code>saveChanges</code> method as necessary. This avoids the
153: * common mistake of forgetting to call the <code>saveChanges</code>
154: * method on a newly constructed message.
155: *
156: * @since        JavaMail 1.2
157: */
158: protected boolean saved = false;
159:
160: /**
161: * If our content is a Multipart or Message object, we save it
162: * the first time it's created by parsing a stream so that changes
163: * to the contained objects will not be lost. <p>
164: *
165: * If this field is not null, it's return by the {@link #getContent}
166: * method. The {@link #getContent} method sets this field if it
167: * would return a Multipart or MimeMessage object. This field is
168: * is cleared by the {@link #setDataHandler} method.
169: *
170: * @since        JavaMail 1.5
171: */
172: protected Object cachedContent;
173:
174: // Used to parse dates
175: private static final MailDateFormat mailDateFormat = new MailDateFormat();
176:
177: // Should addresses in headers be parsed in "strict" mode?
178: private boolean strict = true;
179: // Is UTF-8 allowed in headers?
180: private boolean allowutf8 = false;
181:
182: /**
183: * Default constructor. An empty message object is created.
184: * The <code>headers</code> field is set to an empty InternetHeaders
185: * object. The <code>flags</code> field is set to an empty Flags
186: * object. The <code>modified</code> flag is set to true.
187: *
188: * @param        session        the Sesssion
189: */
190: public MimeMessage(Session session) {
191:         super(session);
192:         modified = true;
193:         headers = new InternetHeaders();
194:         flags = new Flags();        // empty flags object
195:         initStrict();
196: }
197:
198: /**
199: * Constructs a MimeMessage by reading and parsing the data from the
200: * specified MIME InputStream. The InputStream will be left positioned
201: * at the end of the data for the message. Note that the input stream
202: * parse is done within this constructor itself. <p>
203: *
204: * The input stream contains an entire MIME formatted message with
205: * headers and data.
206: *
207: * @param session        Session object for this message
208: * @param is        the message input stream
209: * @exception        MessagingException for failures
210: */
211: public MimeMessage(Session session, InputStream is)
212:                         throws MessagingException {
213:         super(session);
214:         flags = new Flags(); // empty Flags object
215:         initStrict();
216:         parse(is);
217:         saved = true;
218: }
219:
220: /**
221: * Constructs a new MimeMessage with content initialized from the
222: * <code>source</code> MimeMessage. The new message is independent
223: * of the original. <p>
224: *
225: * Note: The current implementation is rather inefficient, copying
226: * the data more times than strictly necessary.
227: *
228: * @param        source        the message to copy content from
229: * @exception        MessagingException for failures
230: * @since                JavaMail 1.2
231: */
232: public MimeMessage(MimeMessage source) throws MessagingException {
233:         super(source.session);
234:         flags = source.getFlags();
235:         if (flags == null)        // make sure flags is always set
236:          flags = new Flags();
237:         ByteArrayOutputStream bos;
238:         int size = source.getSize();
239:         if (size > 0)
240:          bos = new ByteArrayOutputStream(size);
241:         else
242:          bos = new ByteArrayOutputStream();
243:         try {
244:          strict = source.strict;
245:          source.writeTo(bos);
246:          bos.close();
247:          InputStream bis = session.getStreamProvider().inputSharedByteArray(bos.toByteArray());
248:          parse(bis);
249:          bis.close();
250:          saved = true;
251:         } catch (IOException ex) {
252:          // should never happen, but just in case...
253:          throw new MessagingException("IOException while copying message",
254:                                          ex);
255:         }
256: }
257:
258: /**
259: * Constructs an empty MimeMessage object with the given Folder
260: * and message number. <p>
261: *
262: * This method is for providers subclassing <code>MimeMessage</code>.
263: *
264: * @param        folder        the Folder this message is from
265: * @param        msgnum        the number of this message
266: */
267: protected MimeMessage(Folder folder, int msgnum) {
268:         super(folder, msgnum);
269:         flags = new Flags(); // empty Flags object
270:         saved = true;
271:         initStrict();
272: }
273:
274: /**
275: * Constructs a MimeMessage by reading and parsing the data from the
276: * specified MIME InputStream. The InputStream will be left positioned
277: * at the end of the data for the message. Note that the input stream
278: * parse is done within this constructor itself. <p>
279: *
280: * This method is for providers subclassing <code>MimeMessage</code>.
281: *
282: * @param folder        The containing folder.
283: * @param is        the message input stream
284: * @param msgnum        Message number of this message within its folder
285: * @exception        MessagingException for failures
286: */
287: protected MimeMessage(Folder folder, InputStream is, int msgnum)
288:                 throws MessagingException {
289:         this(folder, msgnum);
290:         initStrict();
291:         parse(is);
292: }
293:
294: /**
295: * Constructs a MimeMessage from the given InternetHeaders object
296: * and content.
297: *
298: * This method is for providers subclassing <code>MimeMessage</code>.
299: *
300: * @param folder        The containing folder.
301: * @param headers        The headers
302: * @param content        The message content
303: * @param msgnum        Message number of this message within its folder
304: * @exception        MessagingException for failures
305: */
306: protected MimeMessage(Folder folder, InternetHeaders headers,
307:                 byte[] content, int msgnum) throws MessagingException {
308:         this(folder, msgnum);
309:         this.headers = headers;
310:         this.content = content;
311:         initStrict();
312: }
313:
314: /**
315: * Set the strict flag based on property.
316: */
317: private void initStrict() {
318:         if (session != null) {
319:          Properties props = session.getProperties();
320:          strict = MimeUtility.getBooleanProperty(props, "mail.mime.address.strict", true);
321:          allowutf8 = MimeUtility.getBooleanProperty(props, "mail.mime.allowutf8", false);
322:         }
323: }
324:
325: /**
326: * Parse the InputStream setting the <code>headers</code> and
327: * <code>content</code> fields appropriately. Also resets the
328: * <code>modified</code> flag. <p>
329: *
330: * This method is intended for use by subclasses that need to
331: * control when the InputStream is parsed.
332: *
333: * @param is        The message input stream
334: * @exception        MessagingException for failures
335: */
336: protected void parse(InputStream is) throws MessagingException {
337:
338:         if (!(is instanceof ByteArrayInputStream) &&
339:          !(is instanceof BufferedInputStream) &&
340:          !(is instanceof SharedInputStream))
341:          is = new BufferedInputStream(is);
342:         
343:         headers = createInternetHeaders(is);
344:
345:         if (is instanceof SharedInputStream) {
346:          SharedInputStream sis = (SharedInputStream)is;
347:          contentStream = sis.newStream(sis.getPosition(), -1);
348:         } else {
349:          try {
350:                 content = MimeUtility.getBytes(is);
351:          } catch (IOException ioex) {
352:                 throw new MessagingException("IOException", ioex);
353:          }
354:         }
355:
356:         modified = false;
357: }
358:
359: /**
360: * Returns the value of the RFC 822 "From" header fields. If this
361: * header field is absent, the "Sender" header field is used.
362: * If the "Sender" header field is also absent, <code>null</code>
363: * is returned.<p>
364: *
365: * This implementation uses the <code>getHeader</code> method
366: * to obtain the requisite header field.
367: *
368: * @return                Address object
369: * @exception        MessagingException for failures
370: * @see        #headers
371: */
372: @Override
373: public Address[] getFrom() throws MessagingException {
374:         Address[] a = getAddressHeader("From");
375:         if (a == null)
376:          a = getAddressHeader("Sender");
377:         
378:         return a;
379: }
380:
381: /**
382: * Set the RFC 822 "From" header field. Any existing values are
383: * replaced with the given address. If address is <code>null</code>,
384: * this header is removed.
385: *
386: * @param address        the sender of this message
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: * @exception        MessagingException for other failures
393: */
394: @Override
395: public void setFrom(Address address) throws MessagingException {
396: if (address == null)
397: removeHeader("From");
398: else
399: setAddressHeader("From", new Address[] { address });
400: }
401:
402: /**
403: * Set the RFC 822 "From" header field. Any existing values are
404: * replaced with the given addresses. If address is <code>null</code>,
405: * this header is removed.
406: *
407: * @param address        the sender(s) of this message
408: * @exception        IllegalWriteException if the underlying
409: *                        implementation does not support modification
410: *                        of existing values
411: * @exception        IllegalStateException if this message is
412: *                        obtained from a READ_ONLY folder.
413: * @exception        MessagingException for other failures
414: * @since                JvaMail 1.5
415: */
416: public void setFrom(String address) throws MessagingException {
417: if (address == null)
418: removeHeader("From");
419: else
420: setAddressHeader("From", InternetAddress.parse(address));
421: }
422:
423: /**
424: * Set the RFC 822 "From" header field using the value of the
425: * <code>InternetAddress.getLocalAddress</code> method.
426: *
427: * @exception        IllegalWriteException if the underlying
428: *                        implementation does not support modification
429: *                        of existing values
430: * @exception        IllegalStateException if this message is
431: *                        obtained from a READ_ONLY folder.
432: * @exception        MessagingException for other failures
433: */
434: @Override
435: public void setFrom() throws MessagingException {
436:         InternetAddress me = null;
437:         try {
438:          me = InternetAddress._getLocalAddress(session);
439:         } catch (Exception ex) {
440:          // if anything goes wrong (SecurityException, UnknownHostException),
441:          // chain the exception
442:          throw new MessagingException("No From address", ex);
443:         }
444:         if (me != null)
445:          setFrom(me);
446:         else
447:          throw new MessagingException("No From address");
448: }
449:
450: /**
451: * Add the specified addresses to the existing "From" field. If
452: * the "From" field does not already exist, it is created.
453: *
454: * @param addresses        the senders of this message
455: * @exception        IllegalWriteException if the underlying
456: *                        implementation does not support modification
457: *                        of existing values
458: * @exception        IllegalStateException if this message is
459: *                        obtained from a READ_ONLY folder.
460: * @exception        MessagingException for other failures
461: */
462: @Override
463: public void addFrom(Address[] addresses) throws MessagingException {
464:         addAddressHeader("From", addresses);
465: }
466:
467: /**
468: * Returns the value of the RFC 822 "Sender" header field.
469: * If the "Sender" header field is absent, <code>null</code>
470: * is returned.<p>
471: *
472: * This implementation uses the <code>getHeader</code> method
473: * to obtain the requisite header field.
474: *
475: * @return                Address object
476: * @exception        MessagingException for failures
477: * @see                #headers
478: * @since                JavaMail 1.3
479: */
480: public Address getSender() throws MessagingException {
481:         Address[] a = getAddressHeader("Sender");
482:         if (a == null || a.length == 0)
483:          return null;
484:         return a[0];        // there can be only one
485: }
486:
487: /**
488: * Set the RFC 822 "Sender" header field. Any existing values are
489: * replaced with the given address. If address is <code>null</code>,
490: * this header is removed.
491: *
492: * @param address        the sender of this message
493: * @exception        IllegalWriteException if the underlying
494: *                        implementation does not support modification
495: *                        of existing values
496: * @exception        IllegalStateException if this message is
497: *                        obtained from a READ_ONLY folder.
498: * @exception        MessagingException for other failures
499: * @since                JavaMail 1.3
500: */
501: public void setSender(Address address) throws MessagingException {
502: if (address == null)
503: removeHeader("Sender");
504: else
505: setAddressHeader("Sender", new Address[] { address });
506: }
507:
508: /**
509: * This inner class extends the jakarta.mail.Message.RecipientType
510: * class to add additional RecipientTypes. The one additional
511: * RecipientType currently defined here is NEWSGROUPS.
512: *
513: * @see jakarta.mail.Message.RecipientType
514: */
515: public static class RecipientType extends Message.RecipientType {
516:
517:         private static final long serialVersionUID = -5468290701714395543L;
518:
519:         /**
520:          * The "Newsgroup" (Usenet news) recipients.
521:          */
522:         public static final RecipientType NEWSGROUPS =
523:                                         new RecipientType("Newsgroups");
524:         protected RecipientType(String type) {
525:          super(type);
526:         }
527:
528:         @Override
529:         protected Object readResolve() throws ObjectStreamException {
530:•         if (type.equals("Newsgroups"))
531:                 return NEWSGROUPS;
532:          else
533:                 return super.readResolve();
534:         }
535: }
536:
537: /**
538: * Returns the recepients specified by the type. The mapping
539: * between the type and the corresponding RFC 822 header is
540: * as follows:
541: * <pre>
542: *                Message.RecipientType.TO                "To"
543: *                Message.RecipientType.CC                "Cc"
544: *                Message.RecipientType.BCC                "Bcc"
545: *                MimeMessage.RecipientType.NEWSGROUPS        "Newsgroups"
546: * </pre><br>
547: *
548: * Returns null if the header specified by the type is not found
549: * or if its value is empty. <p>
550: *
551: * This implementation uses the <code>getHeader</code> method
552: * to obtain the requisite header field.
553: *
554: * @param type        Type of recepient
555: * @return array of Address objects
556: * @exception MessagingException if header could not
557: * be retrieved
558: * @exception AddressException if the header is misformatted
559: * @see                #headers
560: * @see                jakarta.mail.Message.RecipientType#TO
561: * @see                jakarta.mail.Message.RecipientType#CC
562: * @see                jakarta.mail.Message.RecipientType#BCC
563: * @see                jakarta.mail.internet.MimeMessage.RecipientType#NEWSGROUPS
564: */
565: @Override
566: public Address[] getRecipients(Message.RecipientType type)
567:                                 throws MessagingException {
568:         if (type == RecipientType.NEWSGROUPS) {
569:          String s = getHeader("Newsgroups", ",");
570:          return (s == null) ? null : NewsAddress.parse(s);
571:         } else
572:          return getAddressHeader(getHeaderName(type));
573: }
574:
575: /**
576: * Get all the recipient addresses for the message.
577: * Extracts the TO, CC, BCC, and NEWSGROUPS recipients.
578: *
579: * @return array of Address objects
580: * @exception MessagingException for failures
581: * @see                jakarta.mail.Message.RecipientType#TO
582: * @see                jakarta.mail.Message.RecipientType#CC
583: * @see                jakarta.mail.Message.RecipientType#BCC
584: * @see                jakarta.mail.internet.MimeMessage.RecipientType#NEWSGROUPS
585: */
586: @Override
587: public Address[] getAllRecipients() throws MessagingException {
588:         Address[] all = super.getAllRecipients();
589:         Address[] ng = getRecipients(RecipientType.NEWSGROUPS);
590:
591:         if (ng == null)
592:          return all;                // the common case
593:         if (all == null)
594:          return ng;                // a rare case
595:
596:         Address[] addresses = new Address[all.length + ng.length];
597:         System.arraycopy(all, 0, addresses, 0, all.length);
598:         System.arraycopy(ng, 0, addresses, all.length, ng.length);
599:         return addresses;
600: }
601:         
602: /**
603: * Set the specified recipient type to the given addresses.
604: * If the address parameter is <code>null</code>, the corresponding
605: * recipient field is removed.
606: *
607: * @param type        Recipient type
608: * @param addresses        Addresses
609: * @exception        IllegalWriteException if the underlying
610: *                        implementation does not support modification
611: *                        of existing values
612: * @exception        IllegalStateException if this message is
613: *                        obtained from a READ_ONLY folder.
614: * @exception        MessagingException for other failures
615: * @see                #getRecipients
616: */
617: @Override
618: public void setRecipients(Message.RecipientType type, Address[] addresses)
619: throws MessagingException {
620:         if (type == RecipientType.NEWSGROUPS) {
621:          if (addresses == null || addresses.length == 0)
622:                 removeHeader("Newsgroups");
623:          else
624:                 setHeader("Newsgroups", NewsAddress.toString(addresses));
625:         } else
626:          setAddressHeader(getHeaderName(type), addresses);
627: }
628:
629: /**
630: * Set the specified recipient type to the given addresses.
631: * If the address parameter is <code>null</code>, the corresponding
632: * recipient field is removed.
633: *
634: * @param type Recipient type
635: * @param addresses Addresses
636: * @exception AddressException if the attempt to parse the
637: * addresses String fails
638: * @exception IllegalWriteException if the underlying
639: * implementation does not support modification
640: * of existing values
641: * @exception IllegalStateException if this message is
642: * obtained from a READ_ONLY folder.
643: * @exception MessagingException for other failures
644: * @see #getRecipients
645: * @since JavaMail 1.2
646: */
647: public void setRecipients(Message.RecipientType type, String addresses)
648: throws MessagingException {
649: if (type == RecipientType.NEWSGROUPS) {
650: if (addresses == null || addresses.length() == 0)
651: removeHeader("Newsgroups");
652: else
653: setHeader("Newsgroups", addresses);
654: } else
655: setAddressHeader(getHeaderName(type),
656:                 addresses == null ? null : InternetAddress.parse(addresses));
657: }
658:
659: /**
660: * Add the given addresses to the specified recipient type.
661: *
662: * @param type        Recipient type
663: * @param addresses        Addresses
664: * @exception        IllegalWriteException if the underlying
665: *                        implementation does not support modification
666: *                        of existing values
667: * @exception        IllegalStateException if this message is
668: *                        obtained from a READ_ONLY folder.
669: * @exception        MessagingException for other failures
670: */
671: @Override
672: public void addRecipients(Message.RecipientType type, Address[] addresses)
673: throws MessagingException {
674:         if (type == RecipientType.NEWSGROUPS) {
675:          String s = NewsAddress.toString(addresses);
676:          if (s != null)
677:                 addHeader("Newsgroups", s);
678:         } else
679:          addAddressHeader(getHeaderName(type), addresses);
680: }
681:
682: /**
683: * Add the given addresses to the specified recipient type.
684: *
685: * @param type Recipient type
686: * @param addresses Addresses
687: * @exception AddressException if the attempt to parse the
688: * addresses String fails
689: * @exception IllegalWriteException if the underlying
690: * implementation does not support modification
691: * of existing values
692: * @exception IllegalStateException if this message is
693: * obtained from a READ_ONLY folder.
694: * @exception MessagingException for other failures
695: * @since JavaMail 1.2
696: */
697: public void addRecipients(Message.RecipientType type, String addresses)
698: throws MessagingException {
699: if (type == RecipientType.NEWSGROUPS) {
700: if (addresses != null && addresses.length() != 0)
701: addHeader("Newsgroups", addresses);
702: } else
703: addAddressHeader(getHeaderName(type),
704:                  InternetAddress.parse(addresses));
705: }
706:
707: /**
708: * Return the value of the RFC 822 "Reply-To" header field. If
709: * this header is unavailable or its value is absent, then
710: * the <code>getFrom</code> method is called and its value is returned.
711: *
712: * This implementation uses the <code>getHeader</code> method
713: * to obtain the requisite header field.
714: *
715: * @exception        MessagingException for failures
716: * @see                #headers
717: */
718: @Override
719: public Address[] getReplyTo() throws MessagingException {
720:         Address[] a = getAddressHeader("Reply-To");
721:         if (a == null || a.length == 0)
722:          a = getFrom();
723:         return a;
724: }
725:
726: /**
727: * Set the RFC 822 "Reply-To" header field. If the address
728: * parameter is <code>null</code>, this header is removed.
729: *
730: * @exception        IllegalWriteException if the underlying
731: *                        implementation does not support modification
732: *                        of existing values
733: * @exception        IllegalStateException if this message is
734: *                        obtained from a READ_ONLY folder.
735: * @exception        MessagingException for other failures
736: */
737: @Override
738: public void setReplyTo(Address[] addresses) throws MessagingException {
739:         setAddressHeader("Reply-To", addresses);
740: }
741:
742: // Convenience method to get addresses
743: private Address[] getAddressHeader(String name)
744:                         throws MessagingException {
745:         String s = getHeader(name, ",");
746:         return (s == null) ? null : InternetAddress.parseHeader(s, strict);
747: }
748:
749: // Convenience method to set addresses
750: private void setAddressHeader(String name, Address[] addresses)
751:                         throws MessagingException {
752:         String s;
753:         if (allowutf8)
754:          s = InternetAddress.toUnicodeString(addresses, name.length() + 2);
755:         else
756:          s = InternetAddress.toString(addresses, name.length() + 2);
757:         if (s == null)
758:          removeHeader(name);
759:         else
760:          setHeader(name, s);
761: }
762:
763: private void addAddressHeader(String name, Address[] addresses)
764:                         throws MessagingException {
765:         if (addresses == null || addresses.length == 0)
766:          return;
767:         Address[] a = getAddressHeader(name);
768:         Address[] anew;
769:         if (a == null || a.length == 0)
770:          anew = addresses;
771:         else {
772:          anew = new Address[a.length + addresses.length];
773:          System.arraycopy(a, 0, anew, 0, a.length);
774:          System.arraycopy(addresses, 0, anew, a.length, addresses.length);
775:         }
776:         String s;
777:         if (allowutf8)
778:          s = InternetAddress.toUnicodeString(anew, name.length() + 2);
779:         else
780:          s = InternetAddress.toString(anew, name.length() + 2);
781:         if (s == null)
782:          return;
783:         setHeader(name, s);
784: }
785:
786: /**
787: * Returns the value of the "Subject" header field. Returns null
788: * if the subject field is unavailable or its value is absent. <p>
789: *
790: * If the subject is encoded as per RFC 2047, it is decoded and
791: * converted into Unicode. If the decoding or conversion fails, the
792: * raw data is returned as is. <p>
793: *
794: * This implementation uses the <code>getHeader</code> method
795: * to obtain the requisite header field.
796: *
797: * @return Subject
798: * @exception        MessagingException for failures
799: * @see                #headers
800: */
801: @Override
802: public String getSubject() throws MessagingException {
803:         String rawvalue = getHeader("Subject", null);
804:
805:         if (rawvalue == null)
806:          return null;
807:
808:         try {
809:          return MimeUtility.decodeText(MimeUtility.unfold(rawvalue));
810:         } catch (UnsupportedEncodingException ex) {
811:          return rawvalue;
812:         }
813: }
814:
815: /**
816: * Set the "Subject" header field. If the subject contains
817: * non US-ASCII characters, it will be encoded using the
818: * platform's default charset. If the subject contains only
819: * US-ASCII characters, no encoding is done and it is used
820: * as-is. If the subject is null, the existing "Subject" field
821: * is removed. <p>
822: *
823: * The application must ensure that the subject does not contain
824: * any line breaks. <p>
825: *
826: * Note that if the charset encoding process fails, a
827: * MessagingException is thrown, and an UnsupportedEncodingException
828: * is included in the chain of nested exceptions within the
829: * MessagingException.
830: *
831: * @param         subject                The subject
832: * @exception        IllegalWriteException if the underlying
833: *                        implementation does not support modification
834: *                        of existing values
835: * @exception        IllegalStateException if this message is
836: *                        obtained from a READ_ONLY folder.
837: * @exception        MessagingException for other failures
838: */
839: @Override
840: public void setSubject(String subject) throws MessagingException {
841:         setSubject(subject, null);
842: }
843:
844: /**
845: * Set the "Subject" header field. If the subject contains non
846: * US-ASCII characters, it will be encoded using the specified
847: * charset. If the subject contains only US-ASCII characters, no
848: * encoding is done and it is used as-is. If the subject is null,
849: * the existing "Subject" header field is removed. <p>
850: *
851: * The application must ensure that the subject does not contain
852: * any line breaks. <p>
853: *
854: * Note that if the charset encoding process fails, a
855: * MessagingException is thrown, and an UnsupportedEncodingException
856: * is included in the chain of nested exceptions within the
857: * MessagingException.
858: *
859: * @param        subject                The subject
860: * @param        charset                The charset
861: * @exception                IllegalWriteException if the underlying
862: *                                implementation does not support modification
863: *                                of existing values
864: * @exception                IllegalStateException if this message is
865: *                                obtained from a READ_ONLY folder.
866: * @exception                MessagingException for other failures
867: */
868: public void setSubject(String subject, String charset)
869:                         throws MessagingException {
870:         if (subject == null) {
871:          removeHeader("Subject");
872:         } else {
873:          try {
874:                 setHeader("Subject", MimeUtility.fold(9,
875:                  MimeUtility.encodeText(subject, charset, null)));
876:          } catch (UnsupportedEncodingException uex) {
877:                 throw new MessagingException("Encoding error", uex);
878:          }
879:         }
880: }
881:
882: /**
883: * Returns the value of the RFC 822 "Date" field. This is the date
884: * on which this message was sent. Returns null if this field is
885: * unavailable or its value is absent. <p>
886: *
887: * This implementation uses the <code>getHeader</code> method
888: * to obtain the requisite header field.
889: *
890: * @return The sent Date
891: * @exception        MessagingException for failures
892: */
893: @Override
894: public Date getSentDate() throws MessagingException {
895:         String s = getHeader("Date", null);
896:         if (s != null) {
897:          try {
898:                 synchronized (mailDateFormat) {
899:                  return mailDateFormat.parse(s);
900:                 }
901:          } catch (ParseException pex) {
902:                 return null;
903:          }
904:         }
905:         
906:         return null;
907: }
908:
909: /**
910: * Set the RFC 822 "Date" header field. This is the date on which the
911: * creator of the message indicates that the message is complete
912: * and ready for delivery. If the date parameter is
913: * <code>null</code>, the existing "Date" field is removed.
914: *
915: * @exception        IllegalWriteException if the underlying
916: *                        implementation does not support modification
917: * @exception        IllegalStateException if this message is
918: *                        obtained from a READ_ONLY folder.
919: * @exception        MessagingException for other failures
920: */
921: @Override
922: public void setSentDate(Date d) throws MessagingException {
923:         if (d == null)
924:          removeHeader("Date");
925:         else {
926:          synchronized (mailDateFormat) {
927:                 setHeader("Date", mailDateFormat.format(d));
928:          }
929:         }
930: }
931:
932: /**
933: * Returns the Date on this message was received. Returns
934: * <code>null</code> if this date cannot be obtained. <p>
935: *
936: * Note that RFC 822 does not define a field for the received
937: * date. Hence only implementations that can provide this date
938: * need return a valid value. <p>
939: *
940: * This implementation returns <code>null</code>.
941: *
942: * @return the date this message was received
943: * @exception        MessagingException for failures
944: */
945: @Override
946: public Date getReceivedDate() throws MessagingException {
947:         return null;        
948: }
949:
950: /**
951: * Return the size of the content of this message in bytes.
952: * Return -1 if the size cannot be determined. <p>
953: *
954: * Note that this number may not be an exact measure of the
955: * content size and may or may not account for any transfer
956: * encoding of the content. <p>
957: *
958: * This implementation returns the size of the <code>content</code>
959: * array (if not null), or, if <code>contentStream</code> is not
960: * null, and the <code>available</code> method returns a positive
961: * number, it returns that number as the size. Otherwise, it returns
962: * -1.
963: *
964: * @return size of content in bytes
965: * @exception        MessagingException for failures
966: */
967: @Override
968: public int getSize() throws MessagingException {
969:         if (content != null)
970:          return content.length;
971:         if (contentStream != null) {
972:          try {
973:                 int size = contentStream.available();
974:                 // only believe the size if it's greater than zero, since zero
975:                 // is the default returned by the InputStream class itself
976:                 if (size > 0)
977:                  return size;
978:          } catch (IOException ex) {
979:                 // ignore it
980:          }
981:         }
982:         return -1;
983: }
984:
985: /**
986: * Return the number of lines for the content of this message.
987: * Return -1 if this number cannot be determined. <p>
988: *
989: * Note that this number may not be an exact measure of the
990: * content length and may or may not account for any transfer
991: * encoding of the content. <p>
992: *
993: * This implementation returns -1.
994: *
995: * @return number of lines in the content.
996: * @exception        MessagingException for failures
997: */
998: @Override
999: public int getLineCount() throws MessagingException {
1000:         return -1;
1001: }
1002:
1003: /**
1004: * Returns the value of the RFC 822 "Content-Type" header field.
1005: * This represents the content-type of the content of this
1006: * message. This value must not be null. If this field is
1007: * unavailable, "text/plain" should be returned. <p>
1008: *
1009: * This implementation uses the <code>getHeader</code> method
1010: * to obtain the requisite header field.
1011: *
1012: * @return The ContentType of this part
1013: * @exception        MessagingException for failures
1014: * @see jakarta.activation.DataHandler
1015: */
1016: @Override
1017: public String getContentType() throws MessagingException {
1018:         String s = getHeader("Content-Type", null);
1019:         s = MimeUtil.cleanContentType(this, s);
1020:         if (s == null)
1021:          return "text/plain";
1022:         return s;
1023: }
1024:
1025: /**
1026: * Is this Part of the specified MIME type? This method
1027: * compares <strong>only the <code>primaryType</code> and
1028: * <code>subType</code></strong>.
1029: * The parameters of the content types are ignored. <p>
1030: *
1031: * For example, this method will return <code>true</code> when
1032: * comparing a Part of content type <strong>"text/plain"</strong>
1033: * with <strong>"text/plain; charset=foobar"</strong>. <p>
1034: *
1035: * If the <code>subType</code> of <code>mimeType</code> is the
1036: * special character '*', then the subtype is ignored during the
1037: * comparison.
1038: *
1039: * @param        mimeType        the MIME type to check
1040: * @return                        true if it matches the MIME type
1041: * @exception                MessagingException for failures
1042: */
1043: @Override
1044: public boolean isMimeType(String mimeType) throws MessagingException {
1045:         return MimeBodyPart.isMimeType(this, mimeType);
1046: }
1047:
1048: /**
1049: * Returns the disposition from the "Content-Disposition" header field.
1050: * This represents the disposition of this part. The disposition
1051: * describes how the part should be presented to the user. <p>
1052: *
1053: * If the Content-Disposition field is unavailable,
1054: * <code>null</code> is returned. <p>
1055: *
1056: * This implementation uses the <code>getHeader</code> method
1057: * to obtain the requisite header field.
1058: *
1059: * @return disposition of this part, or null if unknown
1060: * @exception        MessagingException for failures
1061: */
1062: @Override
1063: public String getDisposition() throws MessagingException {
1064:         return MimeBodyPart.getDisposition(this);
1065: }
1066:
1067: /**
1068: * Set the disposition in the "Content-Disposition" header field
1069: * of this body part. If the disposition is null, any existing
1070: * "Content-Disposition" header field is removed.
1071: *
1072: * @exception        IllegalWriteException if the underlying
1073: *                        implementation does not support modification
1074: * @exception        IllegalStateException if this message is
1075: *                        obtained from a READ_ONLY folder.
1076: * @exception        MessagingException for other failures
1077: */
1078: @Override
1079: public void setDisposition(String disposition) throws MessagingException {
1080:         MimeBodyPart.setDisposition(this, disposition);
1081: }
1082:
1083: /**
1084: * Returns the content transfer encoding from the
1085: * "Content-Transfer-Encoding" header
1086: * field. Returns <code>null</code> if the header is unavailable
1087: * or its value is absent. <p>
1088: *
1089: * This implementation uses the <code>getHeader</code> method
1090: * to obtain the requisite header field.
1091: *
1092: * @return content-transfer-encoding
1093: * @exception        MessagingException for failures
1094: */
1095: @Override
1096: public String getEncoding() throws MessagingException {
1097:         return MimeBodyPart.getEncoding(this);
1098: }
1099:
1100: /**
1101: * Returns the value of the "Content-ID" header field. Returns
1102: * <code>null</code> if the field is unavailable or its value is
1103: * absent. <p>
1104: *
1105: * This implementation uses the <code>getHeader</code> method
1106: * to obtain the requisite header field.
1107: *
1108: * @return content-ID
1109: * @exception        MessagingException for failures
1110: */
1111: @Override
1112: public String getContentID() throws MessagingException {
1113:         return getHeader("Content-Id", null);
1114: }
1115:
1116: /**
1117: * Set the "Content-ID" header field of this Message.
1118: * If the <code>cid</code> parameter is null, any existing
1119: * "Content-ID" is removed.
1120: *
1121: * @param        cid        the content ID
1122: * @exception        IllegalWriteException if the underlying
1123: *                        implementation does not support modification
1124: * @exception        IllegalStateException if this message is
1125: *                        obtained from a READ_ONLY folder.
1126: * @exception        MessagingException for other failures
1127: */
1128: public void setContentID(String cid) throws MessagingException {
1129:         if (cid == null)
1130:          removeHeader("Content-ID");
1131:         else
1132:          setHeader("Content-ID", cid);
1133: }
1134:
1135: /**
1136: * Return the value of the "Content-MD5" header field. Returns
1137: * <code>null</code> if this field is unavailable or its value
1138: * is absent. <p>
1139: *
1140: * This implementation uses the <code>getHeader</code> method
1141: * to obtain the requisite header field.
1142: *
1143: * @return content-MD5
1144: * @exception        MessagingException for failures
1145: */
1146: @Override
1147: public String getContentMD5() throws MessagingException {
1148:         return getHeader("Content-MD5", null);
1149: }
1150:
1151: /**
1152: * Set the "Content-MD5" header field of this Message.
1153: *
1154: * @exception        IllegalWriteException if the underlying
1155: *                        implementation does not support modification
1156: * @exception        IllegalStateException if this message is
1157: *                        obtained from a READ_ONLY folder.
1158: * @exception        MessagingException for other failures
1159: */
1160: @Override
1161: public void setContentMD5(String md5) throws MessagingException {
1162:         setHeader("Content-MD5", md5);
1163: }
1164:
1165: /**
1166: * Returns the "Content-Description" header field of this Message.
1167: * This typically associates some descriptive information with
1168: * this part. Returns null if this field is unavailable or its
1169: * value is absent. <p>
1170: *
1171: * If the Content-Description field is encoded as per RFC 2047,
1172: * it is decoded and converted into Unicode. If the decoding or
1173: * conversion fails, the raw data is returned as-is <p>
1174: *
1175: * This implementation uses the <code>getHeader</code> method
1176: * to obtain the requisite header field.
1177: *
1178: * @return        content-description
1179: * @exception        MessagingException for failures
1180: */
1181: @Override
1182: public String getDescription() throws MessagingException {
1183:         return MimeBodyPart.getDescription(this);
1184: }
1185:
1186: /**
1187: * Set the "Content-Description" header field for this Message.
1188: * If the description parameter is <code>null</code>, then any
1189: * existing "Content-Description" fields are removed. <p>
1190: *
1191: * If the description contains non US-ASCII characters, it will
1192: * be encoded using the platform's default charset. If the
1193: * description contains only US-ASCII characters, no encoding
1194: * is done and it is used as-is. <p>
1195: *
1196: * Note that if the charset encoding process fails, a
1197: * MessagingException is thrown, and an UnsupportedEncodingException
1198: * is included in the chain of nested exceptions within the
1199: * MessagingException.
1200: *
1201: * @param description content-description
1202: * @exception        IllegalWriteException if the underlying
1203: *                        implementation does not support modification
1204: * @exception        IllegalStateException if this message is
1205: *                        obtained from a READ_ONLY folder.
1206: * @exception        MessagingException An
1207: *                         UnsupportedEncodingException may be included
1208: *                        in the exception chain if the charset
1209: *                        conversion fails.
1210: */
1211: @Override
1212: public void setDescription(String description) throws MessagingException {
1213:         setDescription(description, null);
1214: }
1215:
1216: /**
1217: * Set the "Content-Description" header field for this Message.
1218: * If the description parameter is <code>null</code>, then any
1219: * existing "Content-Description" fields are removed. <p>
1220: *
1221: * If the description contains non US-ASCII characters, it will
1222: * be encoded using the specified charset. If the description
1223: * contains only US-ASCII characters, no encoding is done and
1224: * it is used as-is. <p>
1225: *
1226: * Note that if the charset encoding process fails, a
1227: * MessagingException is thrown, and an UnsupportedEncodingException
1228: * is included in the chain of nested exceptions within the
1229: * MessagingException.
1230: *
1231: * @param        description        Description
1232: * @param        charset                Charset for encoding
1233: * @exception                IllegalWriteException if the underlying
1234: *                                implementation does not support modification
1235: * @exception                IllegalStateException if this message is
1236: *                                obtained from a READ_ONLY folder.
1237: * @exception                MessagingException An
1238: *                                 UnsupportedEncodingException may be included
1239: *                                in the exception chain if the charset
1240: *                                conversion fails.
1241: */
1242: public void setDescription(String description, String charset)
1243:                 throws MessagingException {
1244:         MimeBodyPart.setDescription(this, description, charset);
1245: }
1246:
1247: /**
1248: * Get the languages specified in the "Content-Language" header
1249: * field of this message. The Content-Language header is defined by
1250: * RFC 1766. Returns <code>null</code> if this field is unavailable
1251: * or its value is absent. <p>
1252: *
1253: * This implementation uses the <code>getHeader</code> method
1254: * to obtain the requisite header field.
1255: *
1256: * @return                        value of content-language header.
1257: * @exception                MessagingException for failures
1258: */
1259: @Override
1260: public String[] getContentLanguage() throws MessagingException {
1261:         return MimeBodyPart.getContentLanguage(this);
1262: }
1263:
1264: /**
1265: * Set the "Content-Language" header of this MimePart. The
1266: * Content-Language header is defined by RFC 1766.
1267: *
1268: * @param languages         array of language tags
1269: * @exception                IllegalWriteException if the underlying
1270: *                                implementation does not support modification
1271: * @exception                IllegalStateException if this message is
1272: *                                obtained from a READ_ONLY folder.
1273: * @exception                MessagingException for other failures
1274: */
1275: @Override
1276: public void setContentLanguage(String[] languages)
1277:                         throws MessagingException {
1278:         MimeBodyPart.setContentLanguage(this, languages);
1279: }
1280:
1281: /**
1282: * Returns the value of the "Message-ID" header field. Returns
1283: * null if this field is unavailable or its value is absent. <p>
1284: *
1285: * The default implementation provided here uses the
1286: * <code>getHeader</code> method to return the value of the
1287: * "Message-ID" field.
1288: *
1289: * @return Message-ID
1290: * @exception MessagingException if the retrieval of this field
1291: *                        causes any exception.
1292: * @see jakarta.mail.search.MessageIDTerm
1293: * @since          JavaMail 1.1
1294: */
1295: public String getMessageID() throws MessagingException {
1296:         return getHeader("Message-ID", null);
1297: }
1298:
1299: /**
1300: * Get the filename associated with this Message. <p>
1301: *
1302: * Returns the value of the "filename" parameter from the
1303: * "Content-Disposition" header field of this message. If it's
1304: * not available, returns the value of the "name" parameter from
1305: * the "Content-Type" header field of this BodyPart.
1306: * Returns <code>null</code> if both are absent. <p>
1307: *
1308: * If the <code>mail.mime.encodefilename</code> System property
1309: * is set to true, the {@link MimeUtility#decodeText
1310: * MimeUtility.decodeText} method will be used to decode the
1311: * filename. While such encoding is not supported by the MIME
1312: * spec, many mailers use this technique to support non-ASCII
1313: * characters in filenames. The default value of this property
1314: * is false.
1315: *
1316: * @return        filename
1317: * @exception                MessagingException for failures
1318: */
1319: @Override
1320: public String getFileName() throws MessagingException {
1321:         return MimeBodyPart.getFileName(this);
1322: }
1323:
1324: /**
1325: * Set the filename associated with this part, if possible. <p>
1326: *
1327: * Sets the "filename" parameter of the "Content-Disposition"
1328: * header field of this message. <p>
1329: *
1330: * If the <code>mail.mime.encodefilename</code> System property
1331: * is set to true, the {@link MimeUtility#encodeText
1332: * MimeUtility.encodeText} method will be used to encode the
1333: * filename. While such encoding is not supported by the MIME
1334: * spec, many mailers use this technique to support non-ASCII
1335: * characters in filenames. The default value of this property
1336: * is false.
1337: *
1338: * @exception                IllegalWriteException if the underlying
1339: *                                implementation does not support modification
1340: * @exception                IllegalStateException if this message is
1341: *                                obtained from a READ_ONLY folder.
1342: * @exception                MessagingException for other failures
1343: */
1344: @Override
1345: public void setFileName(String filename) throws MessagingException {
1346:         MimeBodyPart.setFileName(this, filename);        
1347: }
1348:
1349: private String getHeaderName(Message.RecipientType type)
1350:                                 throws MessagingException {
1351:         String headerName;
1352:
1353:         if (type == Message.RecipientType.TO)
1354:          headerName = "To";
1355:         else if (type == Message.RecipientType.CC)
1356:          headerName = "Cc";
1357:         else if (type == Message.RecipientType.BCC)
1358:          headerName = "Bcc";
1359:         else if (type == MimeMessage.RecipientType.NEWSGROUPS)
1360:          headerName = "Newsgroups";
1361:         else
1362:          throw new MessagingException("Invalid Recipient Type");
1363:         return headerName;
1364: }
1365:
1366:
1367: /**
1368: * Return a decoded input stream for this Message's "content". <p>
1369: *
1370: * This implementation obtains the input stream from the DataHandler,
1371: * that is, it invokes <code>getDataHandler().getInputStream()</code>.
1372: *
1373: * @return                 an InputStream
1374: * @exception IOException this is typically thrown by the
1375: *                        DataHandler. Refer to the documentation for
1376: *                        jakarta.activation.DataHandler for more details.
1377: * @exception        MessagingException for other failures
1378: *
1379: * @see        #getContentStream
1380: * @see         jakarta.activation.DataHandler#getInputStream
1381: */
1382: @Override
1383: public InputStream getInputStream()
1384:                 throws IOException, MessagingException {
1385:         return getDataHandler().getInputStream();
1386: }
1387:
1388: /**
1389: * Produce the raw bytes of the content. This method is used during
1390: * parsing, to create a DataHandler object for the content. Subclasses
1391: * that can provide a separate input stream for just the message
1392: * content might want to override this method. <p>
1393: *
1394: * This implementation returns a SharedInputStream, if
1395: * <code>contentStream</code> is not null. Otherwise, it
1396: * returns a ByteArrayInputStream constructed
1397: * out of the <code>content</code> byte array.
1398: *
1399: * @return        an InputStream containing the raw bytes
1400: * @exception        MessagingException for failures
1401: * @see #content
1402: */
1403: protected InputStream getContentStream() throws MessagingException {
1404:         if (contentStream != null)
1405:          return ((SharedInputStream)contentStream).newStream(0, -1);
1406:         if (content != null) {
1407: return session.getStreamProvider().inputSharedByteArray(content);
1408:         }
1409:         throw new MessagingException("No MimeMessage content");
1410: }
1411:
1412: /**
1413: * Return an InputStream to the raw data with any Content-Transfer-Encoding
1414: * intact. This method is useful if the "Content-Transfer-Encoding"
1415: * header is incorrect or corrupt, which would prevent the
1416: * <code>getInputStream</code> method or <code>getContent</code> method
1417: * from returning the correct data. In such a case the application may
1418: * use this method and attempt to decode the raw data itself. <p>
1419: *
1420: * This implementation simply calls the <code>getContentStream</code>
1421: * method.
1422: *
1423: * @return        an InputStream containing the raw bytes
1424: * @exception        MessagingException for failures
1425: * @see        #getInputStream
1426: * @see        #getContentStream
1427: * @since        JavaMail 1.2
1428: */
1429: public InputStream getRawInputStream() throws MessagingException {
1430:         return getContentStream();
1431: }
1432:
1433: /**
1434: * Return a DataHandler for this Message's content. <p>
1435: *
1436: * The implementation provided here works approximately as follows.
1437: * Note the use of the <code>getContentStream</code> method to
1438: * generate the byte stream for the content. Also note that
1439: * any transfer-decoding is done automatically within this method.
1440: *
1441: * <blockquote><pre>
1442: * getDataHandler() {
1443: * if (dh == null) {
1444: * dh = new DataHandler(new MimePartDataSource(this));
1445: * }
1446: * return dh;
1447: * }
1448: *
1449: * class MimePartDataSource implements DataSource {
1450: * public getInputStream() {
1451: * return MimeUtility.decode(
1452: *                 getContentStream(), getEncoding());
1453: * }
1454: *        
1455: *                .... <other DataSource methods>
1456: * }
1457: * </pre></blockquote>
1458: *
1459: * @exception        MessagingException for failures
1460: */
1461: @Override
1462: public synchronized DataHandler getDataHandler()
1463:                 throws MessagingException {
1464:         if (dh == null)
1465:          dh = new MimeBodyPart.MimePartDataHandler(this);
1466:         return dh;
1467: }
1468:
1469: /**
1470: * Return the content as a Java object. The type of this
1471: * object is dependent on the content itself. For
1472: * example, the native format of a "text/plain" content
1473: * is usually a String object. The native format for a "multipart"
1474: * message is always a Multipart subclass. For content types that are
1475: * unknown to the DataHandler system, an input stream is returned
1476: * as the content. <p>
1477: *
1478: * This implementation obtains the content from the DataHandler,
1479: * that is, it invokes <code>getDataHandler().getContent()</code>.
1480: * If the content is a Multipart or Message object and was created by
1481: * parsing a stream, the object is cached and returned in subsequent
1482: * calls so that modifications to the content will not be lost.
1483: *
1484: * @return Object
1485: * @see                jakarta.mail.Part
1486: * @see                 jakarta.activation.DataHandler#getContent
1487: * @exception IOException this is typically thrown by the
1488: *                        DataHandler. Refer to the documentation for
1489: *                        jakarta.activation.DataHandler for more details.
1490: * @exception MessagingException for other failures
1491: */
1492: @Override
1493: public Object getContent() throws IOException, MessagingException {
1494:         if (cachedContent != null)
1495:          return cachedContent;
1496:         Object c;
1497:         try {
1498:          c = getDataHandler().getContent();
1499:         } catch (IOException e) {
1500:                 if (e.getCause() instanceof FolderClosedException) {
1501:                         FolderClosedException fce = (FolderClosedException) e.getCause();
1502:                         throw new FolderClosedException(fce.getFolder(), e.getMessage(), e);
1503:                 } else if(e.getCause() instanceof MessagingException) {
1504:                         throw new MessageRemovedException(e.getMessage(), e);
1505:                 } else {
1506:                         throw e;
1507:                 }
1508:         }
1509:         if (MimeBodyPart.cacheMultipart &&
1510:                 (c instanceof Multipart || c instanceof Message) &&
1511:                 (content != null || contentStream != null)) {
1512:          cachedContent = c;
1513:          /*
1514:          * We may abandon the input stream so make sure
1515:          * the MimeMultipart has consumed the stream.
1516:          */
1517:          if (c instanceof MimeMultipart)
1518:                 ((MimeMultipart)c).parse();
1519:         }
1520:         return c;
1521: }
1522:
1523: /**
1524: * This method provides the mechanism to set this part's content.
1525: * The given DataHandler object should wrap the actual content.
1526: *
1527: * @param dh The DataHandler for the content.
1528: * @exception        IllegalWriteException if the underlying
1529: *                        implementation does not support modification
1530: * @exception        IllegalStateException if this message is
1531: *                        obtained from a READ_ONLY folder.
1532: * @exception MessagingException for other failures
1533: */
1534: @Override
1535: public synchronized void setDataHandler(DataHandler dh)
1536:                 throws MessagingException {
1537:         this.dh = dh;
1538:         cachedContent = null;
1539:         MimeBodyPart.invalidateContentHeaders(this);
1540: }
1541:
1542: /**
1543: * A convenience method for setting this Message's content. <p>
1544: *
1545: * The content is wrapped in a DataHandler object. Note that a
1546: * DataContentHandler class for the specified type should be
1547: * available to the JavaMail implementation for this to work right.
1548: * i.e., to do <code>setContent(foobar, "application/x-foobar")</code>,
1549: * a DataContentHandler for "application/x-foobar" should be installed.
1550: * Refer to the Java Activation Framework for more information.
1551: *
1552: * @param        o        the content object
1553: * @param        type        Mime type of the object
1554: * @exception IllegalWriteException if the underlying
1555: *                        implementation does not support modification of
1556: *                        existing values
1557: * @exception        IllegalStateException if this message is
1558: *                        obtained from a READ_ONLY folder.
1559: * @exception MessagingException for other failures
1560: */
1561: @Override
1562: public void setContent(Object o, String type)
1563:                         throws MessagingException {
1564:         if (o instanceof Multipart)
1565:          setContent((Multipart)o);
1566:         else
1567:          setDataHandler(new DataHandler(o, type));
1568: }
1569:
1570: /**
1571: * Convenience method that sets the given String as this
1572: * part's content, with a MIME type of "text/plain". If the
1573: * string contains non US-ASCII characters. it will be encoded
1574: * using the platform's default charset. The charset is also
1575: * used to set the "charset" parameter.<p>
1576: *
1577: * Note that there may be a performance penalty if
1578: * <code>text</code> is large, since this method may have
1579: * to scan all the characters to determine what charset to
1580: * use. <p>
1581: *
1582: * If the charset is already known, use the
1583: * <code>setText</code> method that takes the charset parameter.
1584: *
1585: * @param        text        the text content to set
1586: * @exception        MessagingException        if an error occurs
1587: * @see        #setText(String text, String charset)
1588: */
1589: @Override
1590: public void setText(String text) throws MessagingException {
1591:         setText(text, null);
1592: }
1593:
1594: /**
1595: * Convenience method that sets the given String as this part's
1596: * content, with a MIME type of "text/plain" and the specified
1597: * charset. The given Unicode string will be charset-encoded
1598: * using the specified charset. The charset is also used to set
1599: * the "charset" parameter.
1600: *
1601: * @param        text        the text content to set
1602: * @param        charset        the charset to use for the text
1603: * @exception        MessagingException        if an error occurs
1604: */
1605: @Override
1606: public void setText(String text, String charset)
1607:                         throws MessagingException {
1608:         MimeBodyPart.setText(this, text, charset, "plain");
1609: }
1610:
1611: /**
1612: * Convenience method that sets the given String as this part's
1613: * content, with a primary MIME type of "text" and the specified
1614: * MIME subtype. The given Unicode string will be charset-encoded
1615: * using the specified charset. The charset is also used to set
1616: * the "charset" parameter.
1617: *
1618: * @param        text        the text content to set
1619: * @param        charset        the charset to use for the text
1620: * @param        subtype        the MIME subtype to use (e.g., "html")
1621: * @exception        MessagingException        if an error occurs
1622: * @since        JavaMail 1.4
1623: */
1624: @Override
1625: public void setText(String text, String charset, String subtype)
1626: throws MessagingException {
1627:         MimeBodyPart.setText(this, text, charset, subtype);
1628: }
1629:
1630: /**
1631: * This method sets the Message's content to a Multipart object.
1632: *
1633: * @param mp The multipart object that is the Message's content
1634: * @exception IllegalWriteException if the underlying
1635: *                        implementation does not support modification of
1636: *                        existing values
1637: * @exception        IllegalStateException if this message is
1638: *                        obtained from a READ_ONLY folder.
1639: * @exception MessagingException for other failures
1640: */
1641: @Override
1642: public void setContent(Multipart mp) throws MessagingException {
1643:         setDataHandler(new DataHandler(mp, mp.getContentType()));
1644:         mp.setParent(this);
1645: }
1646:
1647: /**
1648: * Get a new Message suitable for a reply to this message.
1649: * The new Message will have its attributes and headers
1650: * set up appropriately. Note that this new message object
1651: * will be empty, i.e., it will <strong>not</strong> have a "content".
1652: * These will have to be suitably filled in by the client. <p>
1653: *
1654: * If <code>replyToAll</code> is set, the new Message will be addressed
1655: * to all recipients of this message. Otherwise, the reply will be
1656: * addressed to only the sender of this message (using the value
1657: * of the <code>getReplyTo</code> method). <p>
1658: *
1659: * The "Subject" field is filled in with the original subject
1660: * prefixed with "Re:" (unless it already starts with "Re:").
1661: * The "In-Reply-To" header is set in the new message if this
1662: * message has a "Message-Id" header. The <code>ANSWERED</code>
1663: * flag is set in this message.
1664: *
1665: * The current implementation also sets the "References" header
1666: * in the new message to include the contents of the "References"
1667: * header (or, if missing, the "In-Reply-To" header) in this message,
1668: * plus the contents of the "Message-Id" header of this message,
1669: * as described in RFC 2822.
1670: *
1671: * @param        replyToAll        reply should be sent to all recipients
1672: *                                of this message
1673: * @return                the reply Message
1674: * @exception        MessagingException for failures
1675: */
1676: @Override
1677: public Message reply(boolean replyToAll) throws MessagingException {
1678:         return reply(replyToAll, true);
1679: }
1680:
1681: /**
1682: * Get a new Message suitable for a reply to this message.
1683: * The new Message will have its attributes and headers
1684: * set up appropriately. Note that this new message object
1685: * will be empty, i.e., it will <strong>not</strong> have a "content".
1686: * These will have to be suitably filled in by the client. <p>
1687: *
1688: * If <code>replyToAll</code> is set, the new Message will be addressed
1689: * to all recipients of this message. Otherwise, the reply will be
1690: * addressed to only the sender of this message (using the value
1691: * of the <code>getReplyTo</code> method). <p>
1692: *
1693: * If <code>setAnswered</code> is set, the
1694: * {@link jakarta.mail.Flags.Flag#ANSWERED ANSWERED} flag is set
1695: * in this message. <p>
1696: *
1697: * The "Subject" field is filled in with the original subject
1698: * prefixed with "Re:" (unless it already starts with "Re:").
1699: * The "In-Reply-To" header is set in the new message if this
1700: * message has a "Message-Id" header.
1701: *
1702: * The current implementation also sets the "References" header
1703: * in the new message to include the contents of the "References"
1704: * header (or, if missing, the "In-Reply-To" header) in this message,
1705: * plus the contents of the "Message-Id" header of this message,
1706: * as described in RFC 2822.
1707: *
1708: * @param        replyToAll        reply should be sent to all recipients
1709: *                                of this message
1710: * @param        setAnswered        set the ANSWERED flag in this message?
1711: * @return                the reply Message
1712: * @exception        MessagingException for failures
1713: * @since                JavaMail 1.5
1714: */
1715: public Message reply(boolean replyToAll, boolean setAnswered)
1716:                                 throws MessagingException {
1717:         MimeMessage reply = createMimeMessage(session);
1718:         /*
1719:          * Have to manipulate the raw Subject header so that we don't lose
1720:          * any encoding information. This is safe because "Re:" isn't
1721:          * internationalized and (generally) isn't encoded. If the entire
1722:          * Subject header is encoded, prefixing it with "Re: " still leaves
1723:          * a valid and correct encoded header.
1724:          */
1725:         String subject = getHeader("Subject", null);
1726:         if (subject != null) {
1727:          if (!subject.regionMatches(true, 0, "Re: ", 0, 4))
1728:                 subject = "Re: " + subject;
1729:          reply.setHeader("Subject", subject);
1730:         }
1731:         Address a[] = getReplyTo();
1732:         reply.setRecipients(Message.RecipientType.TO, a);
1733:         if (replyToAll) {
1734:          List<Address> v = new ArrayList<>();
1735:          // add my own address to list
1736:          InternetAddress me = InternetAddress.getLocalAddress(session);
1737:          if (me != null)
1738:                 v.add(me);
1739:          // add any alternate names I'm known by
1740:          String alternates = null;
1741:          if (session != null)
1742:                 alternates = session.getProperty("mail.alternates");
1743:          if (alternates != null)
1744:                 eliminateDuplicates(v,
1745:                                 InternetAddress.parse(alternates, false));
1746:          // should we Cc all other original recipients?
1747:          boolean replyallcc = false;
1748:          if (session != null)
1749:                 replyallcc = MimeUtility.getBooleanProperty(
1750:                                                 session.getProperties(),
1751:                                                 "mail.replyallcc", false);
1752:          // add the recipients from the To field so far
1753:          eliminateDuplicates(v, a);
1754:          a = getRecipients(Message.RecipientType.TO);
1755:          a = eliminateDuplicates(v, a);
1756:          if (a != null && a.length > 0) {
1757:                 if (replyallcc)
1758:                  reply.addRecipients(Message.RecipientType.CC, a);
1759:                 else
1760:                  reply.addRecipients(Message.RecipientType.TO, a);
1761:          }
1762:          a = getRecipients(Message.RecipientType.CC);
1763:          a = eliminateDuplicates(v, a);
1764:          if (a != null && a.length > 0)
1765:                 reply.addRecipients(Message.RecipientType.CC, a);
1766:          // don't eliminate duplicate newsgroups
1767:          a = getRecipients(RecipientType.NEWSGROUPS);
1768:          if (a != null && a.length > 0)
1769:                 reply.setRecipients(RecipientType.NEWSGROUPS, a);
1770:         }
1771:
1772:         String msgId = getHeader("Message-Id", null);
1773:         if (msgId != null)
1774:          reply.setHeader("In-Reply-To", msgId);
1775:
1776:         /*
1777:          * Set the References header as described in RFC 2822:
1778:          *
1779:          * The "References:" field will contain the contents of the parent's
1780:          * "References:" field (if any) followed by the contents of the parent's
1781:          * "Message-ID:" field (if any). If the parent message does not contain
1782:          * a "References:" field but does have an "In-Reply-To:" field
1783:          * containing a single message identifier, then the "References:" field
1784:          * will contain the contents of the parent's "In-Reply-To:" field
1785:          * followed by the contents of the parent's "Message-ID:" field (if
1786:          * any). If the parent has none of the "References:", "In-Reply-To:",
1787:          * or "Message-ID:" fields, then the new message will have no
1788:          * "References:" field.
1789:          */
1790:         String refs = getHeader("References", " ");
1791:         if (refs == null) {
1792:          // XXX - should only use if it contains a single message identifier
1793:          refs = getHeader("In-Reply-To", " ");
1794:         }
1795:         if (msgId != null) {
1796:          if (refs != null)
1797:                 refs = MimeUtility.unfold(refs) + " " + msgId;
1798:          else
1799:                 refs = msgId;
1800:         }
1801:         if (refs != null)
1802:          reply.setHeader("References", MimeUtility.fold(12, refs));
1803:
1804:         if (setAnswered) {
1805:          try {
1806:                 setFlags(answeredFlag, true);
1807:          } catch (MessagingException mex) {
1808:                 // ignore it
1809:          }
1810:         }
1811:         return reply;
1812: }
1813:
1814: // used above in reply()
1815: private static final Flags answeredFlag = new Flags(Flags.Flag.ANSWERED);
1816:
1817: /**
1818: * Check addrs for any duplicates that may already be in v.
1819: * Return a new array without the duplicates. Add any new
1820: * addresses to v. Note that the input array may be modified.
1821: */
1822: private Address[] eliminateDuplicates(List<Address> v, Address[] addrs) {
1823:         if (addrs == null)
1824:          return null;
1825:         int gone = 0;
1826:         for (int i = 0; i < addrs.length; i++) {
1827:          boolean found = false;
1828:          // search the list for this address
1829:          for (int j = 0; j < v.size(); j++) {
1830:                 if (((InternetAddress)v.get(j)).equals(addrs[i])) {
1831:                  // found it; count it and remove it from the input array
1832:                  found = true;
1833:                  gone++;
1834:                  addrs[i] = null;
1835:                  break;
1836:                 }
1837:          }
1838:          if (!found)
1839:                 v.add(addrs[i]);        // add new address to list
1840:         }
1841:         // if we found any duplicates, squish the array
1842:         if (gone != 0) {
1843:          Address[] a;
1844:          // new array should be same type as original array
1845:          // XXX - there must be a better way, perhaps reflection?
1846:          if (addrs instanceof InternetAddress[])
1847:                 a = new InternetAddress[addrs.length - gone];
1848:          else
1849:                 a = new Address[addrs.length - gone];
1850:          for (int i = 0, j = 0; i < addrs.length; i++)
1851:                 if (addrs[i] != null)
1852:                  a[j++] = addrs[i];
1853:          addrs = a;
1854:         }
1855:         return addrs;
1856: }
1857:
1858: /**
1859: * Output the message as an RFC 822 format stream. <p>
1860: *
1861: * Note that, depending on how the messag was constructed, it may
1862: * use a variety of line termination conventions. Generally the
1863: * output should be sent through an appropriate FilterOutputStream
1864: * that converts the line terminators to the desired form, either
1865: * CRLF for MIME compatibility and for use in Internet protocols,
1866: * or the local platform's line terminator for storage in a local
1867: * text file. <p>
1868: *
1869: * This implementation calls the <code>writeTo(OutputStream,
1870: * String[])</code> method with a null ignore list.
1871: *
1872: * @exception IOException        if an error occurs writing to the stream
1873: *                                or if an error is generated by the
1874: *                                jakarta.activation layer.
1875: * @exception MessagingException for other failures
1876: * @see jakarta.activation.DataHandler#writeTo
1877: */
1878: @Override
1879: public void writeTo(OutputStream os)
1880:                                 throws IOException, MessagingException {
1881:         writeTo(os, null);
1882: }
1883:
1884: /**
1885: * Output the message as an RFC 822 format stream, without
1886: * specified headers. If the <code>saved</code> flag is not set,
1887: * the <code>saveChanges</code> method is called.
1888: * If the <code>modified</code> flag is not
1889: * set and the <code>content</code> array is not null, the
1890: * <code>content</code> array is written directly, after
1891: * writing the appropriate message headers.
1892: *
1893: * @param        os                the stream to write to
1894: * @param        ignoreList        the headers to not include in the output
1895: * @exception IOException        if an error occurs writing to the stream
1896: *                                or if an error is generated by the
1897: *                                jakarta.activation layer.
1898: * @exception jakarta.mail.MessagingException for other failures
1899: * @see jakarta.activation.DataHandler#writeTo
1900: */
1901: public void writeTo(OutputStream os, String[] ignoreList)
1902:                                 throws IOException, MessagingException {
1903:         if (!saved)
1904:          saveChanges();
1905:
1906:         if (modified) {
1907:          MimeBodyPart.writeTo(this, os, ignoreList);
1908:          return;
1909:         }
1910:
1911:         // Else, the content is untouched, so we can just output it
1912:         // First, write out the header
1913:         Enumeration<String> hdrLines = getNonMatchingHeaderLines(ignoreList);
1914: LineOutputStream los = session.getStreamProvider().outputLineStream(os, allowutf8);
1915:         while (hdrLines.hasMoreElements())
1916:          los.writeln(hdrLines.nextElement());
1917:
1918:         // The CRLF separator between header and content
1919:         los.writeln();
1920:
1921:         // Finally, the content.
1922:         if (content == null) {
1923:          // call getContentStream to give subclass a chance to
1924:          // provide the data on demand
1925:          InputStream is = null;
1926:          byte[] buf = new byte[8192];
1927:          try {
1928:                 is = getContentStream();
1929:                 // now copy the data to the output stream
1930:                 int len;
1931:                 while ((len = is.read(buf)) > 0)
1932:                  os.write(buf, 0, len);
1933:          } finally {
1934:                 if (is != null)
1935:                  is.close();
1936:                 buf = null;
1937:          }
1938:         } else {
1939:          os.write(content);
1940:         }
1941:         os.flush();
1942: }
1943:
1944: /**
1945: * Get all the headers for this header_name. Note that certain
1946: * headers may be encoded as per RFC 2047 if they contain
1947: * non US-ASCII characters and these should be decoded. <p>
1948: *
1949: * This implementation obtains the headers from the
1950: * <code>headers</code> InternetHeaders object.
1951: *
1952: * @param        name        name of header
1953: * @return        array of headers
1954: * @exception MessagingException for failures
1955: * @see         jakarta.mail.internet.MimeUtility
1956: */
1957: @Override
1958: public String[] getHeader(String name)
1959:                         throws MessagingException {
1960:         return headers.getHeader(name);
1961: }
1962:
1963: /**
1964: * Get all the headers for this header name, returned as a single
1965: * String, with headers separated by the delimiter. If the
1966: * delimiter is <code>null</code>, only the first header is
1967: * returned.
1968: *
1969: * @param name                the name of this header
1970: * @param delimiter                separator between values
1971: * @return the value fields for all headers with
1972: *                                this name
1973: * @exception         MessagingException for failures
1974: */
1975: @Override
1976: public String getHeader(String name, String delimiter)
1977:                                 throws MessagingException {
1978:         return headers.getHeader(name, delimiter);
1979: }
1980:
1981: /**
1982: * Set the value for this header_name. Replaces all existing
1983: * header values with this new value. Note that RFC 822 headers
1984: * must contain only US-ASCII characters, so a header that
1985: * contains non US-ASCII characters must have been encoded by the
1986: * caller as per the rules of RFC 2047.
1987: *
1988: * @param        name         header name
1989: * @param        value        header value
1990: * @see         jakarta.mail.internet.MimeUtility
1991: * @exception        IllegalWriteException if the underlying
1992: *                        implementation does not support modification
1993: * @exception        IllegalStateException if this message is
1994: *                        obtained from a READ_ONLY folder.
1995: * @exception MessagingException for other failures
1996: */
1997: @Override
1998: public void setHeader(String name, String value)
1999: throws MessagingException {
2000:         headers.setHeader(name, value);        
2001: }
2002:
2003: /**
2004: * Add this value to the existing values for this header_name.
2005: * Note that RFC 822 headers must contain only US-ASCII
2006: * characters, so a header that contains non US-ASCII characters
2007: * must have been encoded as per the rules of RFC 2047.
2008: *
2009: * @param        name         header name
2010: * @param        value        header value
2011: * @see         jakarta.mail.internet.MimeUtility
2012: * @exception        IllegalWriteException if the underlying
2013: *                        implementation does not support modification
2014: * @exception        IllegalStateException if this message is
2015: *                        obtained from a READ_ONLY folder.
2016: * @exception MessagingException for other failures
2017: */
2018: @Override
2019: public void addHeader(String name, String value)
2020: throws MessagingException {
2021:         headers.addHeader(name, value);
2022: }
2023:
2024: /**
2025: * Remove all headers with this name.
2026: * @exception        IllegalWriteException if the underlying
2027: *                        implementation does not support modification
2028: * @exception        IllegalStateException if this message is
2029: *                        obtained from a READ_ONLY folder.
2030: * @exception MessagingException for other failures
2031: */
2032: @Override
2033: public void removeHeader(String name)
2034: throws MessagingException {
2035:         headers.removeHeader(name);
2036: }
2037:
2038: /**
2039: * Return all the headers from this Message as an enumeration
2040: * of Header objects. <p>
2041: *
2042: * Note that certain headers may be encoded as per RFC 2047
2043: * if they contain non US-ASCII characters and these should
2044: * be decoded. <p>
2045: *
2046: * This implementation obtains the headers from the
2047: * <code>headers</code> InternetHeaders object.
2048: *
2049: * @return        array of header objects
2050: * @exception MessagingException for failures
2051: * @see         jakarta.mail.internet.MimeUtility
2052: */
2053: @Override
2054: public Enumeration<Header> getAllHeaders() throws MessagingException {
2055:         return headers.getAllHeaders();        
2056: }
2057:
2058: /**
2059: * Return matching headers from this Message as an Enumeration of
2060: * Header objects. This implementation obtains the headers from
2061: * the <code>headers</code> InternetHeaders object.
2062: *
2063: * @exception MessagingException for failures
2064: */
2065: @Override
2066: public Enumeration<Header> getMatchingHeaders(String[] names)
2067:                         throws MessagingException {
2068:         return headers.getMatchingHeaders(names);
2069: }
2070:
2071: /**
2072: * Return non-matching headers from this Message as an
2073: * Enumeration of Header objects. This implementation
2074: * obtains the header from the <code>headers</code> InternetHeaders object.
2075: *
2076: * @exception MessagingException for failures
2077: */
2078: @Override
2079: public Enumeration<Header> getNonMatchingHeaders(String[] names)
2080:                         throws MessagingException {
2081:         return headers.getNonMatchingHeaders(names);
2082: }
2083:
2084: /**
2085: * Add a raw RFC 822 header-line.
2086: *
2087: * @exception        IllegalWriteException if the underlying
2088: *                        implementation does not support modification
2089: * @exception        IllegalStateException if this message is
2090: *                        obtained from a READ_ONLY folder.
2091: * @exception         MessagingException for other failures
2092: */
2093: @Override
2094: public void addHeaderLine(String line) throws MessagingException {
2095:         headers.addHeaderLine(line);
2096: }
2097:
2098: /**
2099: * Get all header lines as an Enumeration of Strings. A Header
2100: * line is a raw RFC 822 header-line, containing both the "name"
2101: * and "value" field.
2102: *
2103: * @exception         MessagingException for failures
2104: */
2105: @Override
2106: public Enumeration<String> getAllHeaderLines() throws MessagingException {
2107:         return headers.getAllHeaderLines();
2108: }
2109:
2110: /**
2111: * Get matching header lines as an Enumeration of Strings.
2112: * A Header line is a raw RFC 822 header-line, containing both
2113: * the "name" and "value" field.
2114: *
2115: * @exception         MessagingException for failures
2116: */
2117: @Override
2118: public Enumeration<String> getMatchingHeaderLines(String[] names)
2119: throws MessagingException {
2120:         return headers.getMatchingHeaderLines(names);
2121: }
2122:
2123: /**
2124: * Get non-matching header lines as an Enumeration of Strings.
2125: * A Header line is a raw RFC 822 header-line, containing both
2126: * the "name" and "value" field.
2127: *
2128: * @exception         MessagingException for failures
2129: */
2130: @Override
2131: public Enumeration<String> getNonMatchingHeaderLines(String[] names)
2132: throws MessagingException {
2133:         return headers.getNonMatchingHeaderLines(names);
2134: }
2135:
2136: /**
2137: * Return a <code>Flags</code> object containing the flags for
2138: * this message. <p>
2139: *
2140: * Note that a clone of the internal Flags object is returned, so
2141: * modifying the returned Flags object will not affect the flags
2142: * of this message.
2143: *
2144: * @return Flags object containing the flags for this message
2145: * @exception         MessagingException for failures
2146: * @see                 jakarta.mail.Flags
2147: */
2148: @Override
2149: public synchronized Flags getFlags() throws MessagingException {
2150:         return (Flags)flags.clone();
2151: }
2152:
2153: /**
2154: * Check whether the flag specified in the <code>flag</code>
2155: * argument is set in this message. <p>
2156: *
2157: * This implementation checks this message's internal
2158: * <code>flags</code> object.
2159: *
2160: * @param flag        the flag
2161: * @return                value of the specified flag for this message
2162: * @exception MessagingException for failures
2163: * @see                 jakarta.mail.Flags.Flag
2164: * @see                jakarta.mail.Flags.Flag#ANSWERED
2165: * @see                jakarta.mail.Flags.Flag#DELETED
2166: * @see                jakarta.mail.Flags.Flag#DRAFT
2167: * @see                jakarta.mail.Flags.Flag#FLAGGED
2168: * @see                jakarta.mail.Flags.Flag#RECENT
2169: * @see                jakarta.mail.Flags.Flag#SEEN
2170: */
2171: @Override
2172: public synchronized boolean isSet(Flags.Flag flag)
2173:                                 throws MessagingException {
2174:         return (flags.contains(flag));
2175: }
2176:
2177: /**
2178: * Set the flags for this message. <p>
2179: *
2180: * This implementation modifies the <code>flags</code> field.
2181: *
2182: * @exception        IllegalWriteException if the underlying
2183: *                        implementation does not support modification
2184: * @exception        IllegalStateException if this message is
2185: *                        obtained from a READ_ONLY folder.
2186: * @exception         MessagingException for other failures
2187: */
2188: @Override
2189: public synchronized void setFlags(Flags flag, boolean set)
2190:                         throws MessagingException {
2191:         if (set)
2192:          flags.add(flag);
2193:         else
2194:          flags.remove(flag);
2195: }
2196:
2197: /**
2198: * Updates the appropriate header fields of this message to be
2199: * consistent with the message's contents. If this message is
2200: * contained in a Folder, any changes made to this message are
2201: * committed to the containing folder. <p>
2202: *
2203: * If any part of a message's headers or contents are changed,
2204: * <code>saveChanges</code> must be called to ensure that those
2205: * changes are permanent. Otherwise, any such modifications may or
2206: * may not be saved, depending on the folder implementation. <p>
2207: *
2208: * Messages obtained from folders opened READ_ONLY should not be
2209: * modified and saveChanges should not be called on such messages. <p>
2210: *
2211: * This method sets the <code>modified</code> flag to true, the
2212: * <code>save</code> flag to true, and then calls the
2213: * <code>updateHeaders</code> method.
2214: *
2215: * @exception        IllegalWriteException if the underlying
2216: *                        implementation does not support modification
2217: * @exception        IllegalStateException if this message is
2218: *                        obtained from a READ_ONLY folder.
2219: * @exception         MessagingException for other failures
2220: */
2221: @Override
2222: public void saveChanges() throws MessagingException {
2223:         modified = true;
2224:         saved = true;
2225:         updateHeaders();
2226: }
2227:
2228: /**
2229: * Update the Message-ID header. This method is called
2230: * by the <code>updateHeaders</code> and allows a subclass
2231: * to override only the algorithm for choosing a Message-ID.
2232: *
2233: * @exception         MessagingException for failures
2234: * @since                JavaMail 1.4
2235: */
2236: protected void updateMessageID() throws MessagingException {
2237:         setHeader("Message-ID",
2238:                  "<" + UniqueValue.getUniqueMessageIDValue(session) + ">");
2239:
2240: }        
2241:
2242: /**
2243: * Called by the <code>saveChanges</code> method to actually
2244: * update the MIME headers. The implementation here sets the
2245: * <code>Content-Transfer-Encoding</code> header (if needed
2246: * and not already set), the <code>Date</code> header (if
2247: * not already set), the <code>MIME-Version</code> header
2248: * and the <code>Message-ID</code> header. Also, if the content
2249: * of this message is a <code>MimeMultipart</code>, its
2250: * <code>updateHeaders</code> method is called. <p>
2251: *
2252: * If the {@link #cachedContent} field is not null (that is,
2253: * it references a Multipart or Message object), then
2254: * that object is used to set a new DataHandler, any
2255: * stream data used to create this object is discarded,
2256: * and the {@link #cachedContent} field is cleared.
2257: *
2258: * @exception        IllegalWriteException if the underlying
2259: *                        implementation does not support modification
2260: * @exception        IllegalStateException if this message is
2261: *                        obtained from a READ_ONLY folder.
2262: * @exception         MessagingException for other failures
2263: */
2264: protected synchronized void updateHeaders() throws MessagingException {
2265:         MimeBodyPart.updateHeaders(this);        
2266:         setHeader("MIME-Version", "1.0");
2267:         if (getHeader("Date") == null)
2268:          setSentDate(new Date());
2269: updateMessageID();
2270:
2271:         if (cachedContent != null) {
2272:          dh = new DataHandler(cachedContent, getContentType());
2273:          cachedContent = null;
2274:          content = null;
2275:          if (contentStream != null) {
2276:                 try {
2277:                  contentStream.close();
2278:                 } catch (IOException ioex) { }        // nothing to do
2279:          }
2280:          contentStream = null;
2281:         }
2282: }
2283:
2284: /**
2285: * Create and return an InternetHeaders object that loads the
2286: * headers from the given InputStream. Subclasses can override
2287: * this method to return a subclass of InternetHeaders, if
2288: * necessary. This implementation simply constructs and returns
2289: * an InternetHeaders object.
2290: *
2291: * @return        an InternetHeaders object
2292: * @param        is        the InputStream to read the headers from
2293: * @exception         MessagingException for failures
2294: * @since                JavaMail 1.2
2295: */
2296: protected InternetHeaders createInternetHeaders(InputStream is)
2297:                                 throws MessagingException {
2298:         return new InternetHeaders(is, allowutf8);
2299: }
2300:
2301: /**
2302: * Create and return a MimeMessage object. The reply method
2303: * uses this method to create the MimeMessage object that it
2304: * will return. Subclasses can override this method to return
2305: * a subclass of MimeMessage. This implementation simply constructs
2306: * and returns a MimeMessage object using the supplied Session.
2307: *
2308: * @param        session        the Session to use for the new message
2309: * @return                the new MimeMessage object
2310: * @exception         MessagingException for failures
2311: * @since                JavaMail 1.4
2312: */
2313: protected MimeMessage createMimeMessage(Session session)
2314:                                 throws MessagingException {
2315:         return new MimeMessage(session);
2316: }
2317: }