FileDocCategorySizeDatePackage
IMAPMessage.javaAPI DocJavaMail 1.4.339336Tue Nov 17 10:38:10 GMT 2009com.sun.mail.imap

IMAPMessage

public class IMAPMessage extends MimeMessage
This class implements an IMAPMessage object.

An IMAPMessage object starts out as a light-weight object. It gets filled-in incrementally when a request is made for some item. Or when a prefetch is done using the FetchProfile.

An IMAPMessage has a messageNumber and a sequenceNumber. The messageNumber is its index into its containing folder's messageCache. The sequenceNumber is its IMAP sequence-number.

author
John Mani
author
Bill Shannon

Fields Summary
protected BODYSTRUCTURE
bs
protected ENVELOPE
envelope
private Date
receivedDate
private int
size
private boolean
peek
private long
uid
protected String
sectionId
private String
type
private String
subject
private String
description
private boolean
headersLoaded
private Hashtable
loadedHeaders
private static String
EnvelopeCmd
Constructors Summary
protected IMAPMessage(IMAPFolder folder, int msgnum)
Constructor.


          
         
	super(folder, msgnum);
	flags = null;
    
protected IMAPMessage(Session session)
Constructor, for use by IMAPNestedMessage.

	super(session);
    
Methods Summary
private com.sun.mail.imap.protocol.BODYSTRUCTURE_getBodyStructure()

	return bs;
    
private com.sun.mail.imap.protocol.ENVELOPE_getEnvelope()

	return envelope;
    
private javax.mail.Flags_getFlags()

	return flags;
    
javax.mail.Session_getSession()

	return session;
    
void_setFlags(javax.mail.Flags flags)
accessor routines to make available certain private/protected fields to other classes in this package.

	this.flags = flags;
    
private javax.mail.internet.InternetAddress[]aaclone(javax.mail.internet.InternetAddress[] aa)

	if (aa == null)
	    return null;
	else
	    return (InternetAddress[])aa.clone();
    
public voidaddFrom(javax.mail.Address[] addresses)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidaddHeader(java.lang.String name, java.lang.String value)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidaddHeaderLine(java.lang.String line)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidaddRecipients(javax.mail.Message$RecipientType type, javax.mail.Address[] addresses)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
private synchronized booleanareHeadersLoaded()

	return headersLoaded;
    
protected voidcheckExpunged()

	if (expunged)
	    throw new MessageRemovedException();
    
private static java.lang.StringcraftHeaderCmd(com.sun.mail.imap.protocol.IMAPProtocol p, java.lang.String[] hdrs)

	StringBuffer sb;

	if (p.isREV1())
	    sb = new StringBuffer("BODY.PEEK[HEADER.FIELDS (");
	else
	    sb = new StringBuffer("RFC822.HEADER.LINES (");

	for (int i = 0; i < hdrs.length; i++) {
	    if (i > 0)
		sb.append(" ");
	    sb.append(hdrs[i]);
	}

	if (p.isREV1())
	    sb.append(")]");
	else
	    sb.append(")");
	
	return sb.toString();
    
static voidfetch(com.sun.mail.imap.IMAPFolder folder, Message[] msgs, javax.mail.FetchProfile fp)
The prefetch method. Called from IMAPFolder.fetch()


	/* This class implements the test to be done on each
	 * message in the folder. The test is to check whether the
	 * message has already cached all the items requested in the
	 * FetchProfile. If any item is missing, the test succeeds and
	 * breaks out.
	 */
	class FetchProfileCondition implements Utility.Condition {
	    private boolean needEnvelope = false;
	    private boolean needFlags = false;
	    private boolean needBodyStructure = false;
	    private boolean needUID = false;
	    private boolean needHeaders = false;
	    private boolean needSize = false;
	    private String[] hdrs = null;

	    public FetchProfileCondition(FetchProfile fp) {
		if (fp.contains(FetchProfile.Item.ENVELOPE))
		    needEnvelope = true;
		if (fp.contains(FetchProfile.Item.FLAGS))
		    needFlags = true;
		if (fp.contains(FetchProfile.Item.CONTENT_INFO))
		    needBodyStructure = true;
		if (fp.contains(UIDFolder.FetchProfileItem.UID))
		    needUID = true;
		if (fp.contains(IMAPFolder.FetchProfileItem.HEADERS))
		    needHeaders = true;
		if (fp.contains(IMAPFolder.FetchProfileItem.SIZE))
		    needSize = true;
		hdrs = fp.getHeaderNames();
	    }

	    // The actual test.
	    public boolean test(IMAPMessage m) {
		if (needEnvelope && m._getEnvelope() == null)
		    return true; // no envelope
		if (needFlags && m._getFlags() == null)
		    return true; // no flags
		if (needBodyStructure && m._getBodyStructure() == null)
		    return true; // no BODYSTRUCTURE
		if (needUID && m.getUID() == -1)	// no UID
		    return true;
		if (needHeaders && !m.areHeadersLoaded()) // no headers
		    return true;
		if (needSize && m.size == -1)		// no size
		    return true;

		// Is the desired header present ?
		for (int i = 0; i < hdrs.length; i++) {
		    if (!m.isHeaderLoaded(hdrs[i]))
			return true; // Nope, return
		}

		return false;
	    }
	}

	StringBuffer command = new StringBuffer();
	boolean first = true;
	boolean allHeaders = false;

	if (fp.contains(FetchProfile.Item.ENVELOPE)) {
	    command.append(EnvelopeCmd);
	    first = false;
	}
	if (fp.contains(FetchProfile.Item.FLAGS)) {
	    command.append(first ? "FLAGS" : " FLAGS");
	    first = false;
	}
	if (fp.contains(FetchProfile.Item.CONTENT_INFO)) {
	    command.append(first ? "BODYSTRUCTURE" : " BODYSTRUCTURE");
	    first = false;
	}
	if (fp.contains(UIDFolder.FetchProfileItem.UID)) {
	    command.append(first ? "UID" : " UID");
	    first = false;
	}
	if (fp.contains(IMAPFolder.FetchProfileItem.HEADERS)) {
	    allHeaders = true;
	    if (folder.protocol.isREV1())
		command.append(first ?
			    "BODY.PEEK[HEADER]" : " BODY.PEEK[HEADER]");
	    else
		command.append(first ? "RFC822.HEADER" : " RFC822.HEADER");
	    first = false;
	}
	if (fp.contains(IMAPFolder.FetchProfileItem.SIZE)) {
	    command.append(first ? "RFC822.SIZE" : " RFC822.SIZE");
	    first = false;
	}

	// if we're not fetching all headers, fetch individual headers
	String[] hdrs = null;
	if (!allHeaders) {
	    hdrs = fp.getHeaderNames();
	    if (hdrs.length > 0) {
		if (!first)
		    command.append(" ");
		command.append(craftHeaderCmd(folder.protocol, hdrs));
	    }
	}

	Utility.Condition condition = new FetchProfileCondition(fp);

        // Acquire the Folder's MessageCacheLock.
        synchronized(folder.messageCacheLock) {

	    // Apply the test, and get the sequence-number set for
	    // the messages that need to be prefetched.
	    MessageSet[] msgsets = Utility.toMessageSet(msgs, condition);

	    if (msgsets == null)
		// We already have what we need.
		return;

	    Response[] r = null;
	    Vector v = new Vector(); // to collect non-FETCH responses &
	    			     // unsolicited FETCH FLAG responses 
	    try {
		r = folder.protocol.fetch(msgsets, command.toString());
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (CommandFailedException cfx) {
		// Ignore these, as per RFC 2180
	    } catch (ProtocolException pex) { 
		throw new MessagingException(pex.getMessage(), pex);
	    }

	    if (r == null)
		return;
	   
	    for (int i = 0; i < r.length; i++) {
		if (r[i] == null)
		    continue;
		if (!(r[i] instanceof FetchResponse)) {
		    v.addElement(r[i]); // Unsolicited Non-FETCH response
		    continue;
		}

		// Got a FetchResponse.
		FetchResponse f = (FetchResponse)r[i];
		// Get the corresponding message.
		IMAPMessage msg = folder.getMessageBySeqNumber(f.getNumber());

		int count = f.getItemCount();
		boolean unsolicitedFlags = false;

		for (int j = 0; j < count; j++) {
		    Item item = f.getItem(j);

		    // Check for the FLAGS item
		    if (item instanceof Flags) {
			if (!fp.contains(FetchProfile.Item.FLAGS) ||
			    msg == null)
			    // Ok, Unsolicited FLAGS update.
			    unsolicitedFlags = true;
			else
			    msg.flags = (Flags)item;
		    }

		    // Check for ENVELOPE items
		    else if (item instanceof ENVELOPE)
			msg.envelope = (ENVELOPE)item;
		    else if (item instanceof INTERNALDATE)
			msg.receivedDate = ((INTERNALDATE)item).getDate();
		    else if (item instanceof RFC822SIZE)
			msg.size = ((RFC822SIZE)item).size;

		    // Check for the BODYSTRUCTURE item
		    else if (item instanceof BODYSTRUCTURE)
			msg.bs = (BODYSTRUCTURE)item;
		    // Check for the UID item
		    else if (item instanceof UID) {
			UID u = (UID)item;
			msg.uid = u.uid; // set uid
			// add entry into uid table
			if (folder.uidTable == null)
			    folder.uidTable = new Hashtable();
			folder.uidTable.put(new Long(u.uid), msg);
		    }

		    // Check for header items
		    else if (item instanceof RFC822DATA ||
			     item instanceof BODY) {
			InputStream headerStream;
			if (item instanceof RFC822DATA) // IMAP4
			    headerStream = 
				((RFC822DATA)item).getByteArrayInputStream();
			else	// IMAP4rev1
			    headerStream = 
				((BODY)item).getByteArrayInputStream();
			
			// Load the obtained headers.
			InternetHeaders h = new InternetHeaders();
			h.load(headerStream);
			if (msg.headers == null || allHeaders)
			    msg.headers = h;
			else {
			    /*
			     * This is really painful.  A second fetch
			     * of the same headers (which might occur because
			     * a new header was added to the set requested)
			     * will return headers we already know about.
			     * In this case, only load the headers we haven't
			     * seen before to avoid adding duplicates of
			     * headers we already have.
			     */
			    Enumeration e = h.getAllHeaders();
			    while (e.hasMoreElements()) {
				Header he = (Header)e.nextElement();
				if (!msg.isHeaderLoaded(he.getName()))
				    msg.headers.addHeader(
						he.getName(), he.getValue());
			    }
			}

			// if we asked for all headers, assume we got them
			if (allHeaders)
			    msg.setHeadersLoaded(true);
			else {
			    // Mark all headers we asked for as 'loaded'
			    for (int k = 0; k < hdrs.length; k++)
				msg.setHeaderLoaded(hdrs[k]);
			}
		    }
		}

		// If this response contains any unsolicited FLAGS
		// add it to the unsolicited response vector
		if (unsolicitedFlags)
		    v.addElement(f);
	    }

	    // Dispatch any unsolicited responses
	    int size = v.size();
	    if (size != 0) {
		Response[] responses = new Response[size];
		v.copyInto(responses);
		folder.handleResponses(responses);
	    }

	} // Release messageCacheLock
    
protected voidforceCheckExpunged()
Do a NOOP to force any untagged EXPUNGE responses and then check if this message is expunged.

	synchronized (getMessageCacheLock()) {
	    try {
		getProtocol().noop();
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		// ignore it
	    }
	}
	if (expunged)
	    throw new MessageRemovedException();
    
public java.util.EnumerationgetAllHeaderLines()
Get all header-lines.

	checkExpunged();
	loadHeaders();
	return super.getAllHeaderLines();
    
public java.util.EnumerationgetAllHeaders()
Get all headers.

	checkExpunged();
	loadHeaders();
	return super.getAllHeaders();
    
public java.lang.StringgetContentID()
Get the Content-ID.

	checkExpunged();
	loadBODYSTRUCTURE();
	return bs.id;
    
public java.lang.String[]getContentLanguage()
Get the content language.

    	checkExpunged();
    	loadBODYSTRUCTURE();
    	if (bs.language != null)
	    return (String[])(bs.language).clone();
    	else
	    return null;
    
public java.lang.StringgetContentMD5()
Get the Content-MD5.

	checkExpunged();
	loadBODYSTRUCTURE();
	return bs.md5;
    
protected java.io.InputStreamgetContentStream()
Get all the bytes for this message. Overrides getContentStream() in MimeMessage. This method is ultimately used by the DataHandler to obtain the input stream for this message.

see
javax.mail.internet.MimeMessage#getContentStream

	InputStream is = null;
	boolean pk = getPeek();	// get before acquiring message cache lock

        // Acquire MessageCacheLock, to freeze seqnum.
        synchronized(getMessageCacheLock()) {
	    try {
		IMAPProtocol p = getProtocol();

		// This message could be expunged when we were waiting
		// to acquire the lock ...
		checkExpunged();

		if (p.isREV1() && (getFetchBlockSize() != -1)) // IMAP4rev1
		    return new IMAPInputStream(this, toSection("TEXT"),
					   bs != null ? bs.size : -1, pk);

		if (p.isREV1()) {
		    BODY b;
		    if (pk)
			b = p.peekBody(getSequenceNumber(), toSection("TEXT"));
		    else
			b = p.fetchBody(getSequenceNumber(), toSection("TEXT"));
		    if (b != null)
			is = b.getByteArrayInputStream();
		} else {
		    RFC822DATA rd = p.fetchRFC822(getSequenceNumber(), "TEXT");
		    if (rd != null)
			is = rd.getByteArrayInputStream();
		}
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		forceCheckExpunged();
		throw new MessagingException(pex.getMessage(), pex);
	    }
	}

	if (is == null)
	    throw new MessagingException("No content");
	else
	    return is;
    
public java.lang.StringgetContentType()
Get the Content-Type. Generate this header from the BODYSTRUCTURE. Append parameters as well.

	checkExpunged();

	// If we haven't cached the type yet ..
	if (type == null) {
	    loadBODYSTRUCTURE();
	    // generate content-type from BODYSTRUCTURE
	    ContentType ct = new ContentType(bs.type, bs.subtype, bs.cParams);
	    type = ct.toString();
	}
	return type;
    
public synchronized javax.activation.DataHandlergetDataHandler()
Get the DataHandler object for this message.

	checkExpunged();

	if (dh == null) {
	    loadBODYSTRUCTURE();
	    if (type == null) { // type not yet computed
		// generate content-type from BODYSTRUCTURE
		ContentType ct = new ContentType(bs.type, bs.subtype,
						 bs.cParams);
		type = ct.toString();
	    }

	    /* Special-case Multipart and Nested content. All other
	     * cases are handled by the superclass.
	     */
	    if (bs.isMulti())
		dh = new DataHandler(
			new IMAPMultipartDataSource(this, bs.bodies, 
						    sectionId, this)
		     );
	    else if (bs.isNested() && isREV1())
		/* Nested messages are handled specially only for
		 * IMAP4rev1. IMAP4 doesn't provide enough support to 
		 * FETCH the components of nested messages
		 */
		dh = new DataHandler(
			    new IMAPNestedMessage(this, 
				bs.bodies[0], 
				bs.envelope,
				sectionId == null ? "1" : sectionId + ".1"),
			    type
		     );
	}

	return super.getDataHandler();
    
public java.lang.StringgetDescription()
Get the decoded Content-Description.

	checkExpunged();

	if (description != null) // cached value ?
	    return description;
	
	loadBODYSTRUCTURE();
	if (bs.description == null)
	    return null;
	
	try {
	    description = MimeUtility.decodeText(bs.description);
	} catch (UnsupportedEncodingException ex) {
	    description = bs.description;
	}

	return description;
    
public java.lang.StringgetDisposition()
Get the Content-Disposition.

	checkExpunged();
	loadBODYSTRUCTURE();
	return bs.disposition;
    
public java.lang.StringgetEncoding()
Get the Content-Transfer-Encoding.

	checkExpunged();
	loadBODYSTRUCTURE();
	return bs.encoding;
    
protected intgetFetchBlockSize()

	return ((IMAPStore)folder.getStore()).getFetchBlockSize();
    
public java.lang.StringgetFileName()
Get the "filename" Disposition parameter. (Only available in IMAP4rev1). If thats not available, get the "name" ContentType parameter.

	checkExpunged();

	String filename = null;
	loadBODYSTRUCTURE();

	if (bs.dParams != null)
	    filename = bs.dParams.get("filename");
	if (filename == null && bs.cParams != null)
	    filename = bs.cParams.get("name");
	return filename;
    
public synchronized javax.mail.FlagsgetFlags()
Get the Flags for this message.

	checkExpunged();
	loadFlags();
	return super.getFlags();
    
public javax.mail.Address[]getFrom()
Get the "From" attribute.

	checkExpunged();
	loadEnvelope();
	return aaclone(envelope.from);
    
public java.lang.String[]getHeader(java.lang.String name)
Get the named header.

	checkExpunged();

	if (isHeaderLoaded(name)) // already loaded ?
	    return headers.getHeader(name);

	// Load this particular header
	InputStream is = null;

        // Acquire MessageCacheLock, to freeze seqnum.
        synchronized(getMessageCacheLock()) {
	    try {
		IMAPProtocol p = getProtocol();

		// This message could be expunged when we were waiting
		// to acquire the lock ...
		checkExpunged();

		if (p.isREV1()) {
		    BODY b = p.peekBody(getSequenceNumber(), 
				toSection("HEADER.FIELDS (" + name + ")")
			     );
		    if (b != null)
			is = b.getByteArrayInputStream();
		} else {
		    RFC822DATA rd = p.fetchRFC822(getSequenceNumber(), 
					"HEADER.LINES (" + name + ")");
		    if (rd != null)
			is = rd.getByteArrayInputStream();
		}
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		forceCheckExpunged();
		throw new MessagingException(pex.getMessage(), pex);
	    }
	}

	// if we get this far without "is" being set, something has gone
	// wrong; prevent a later NullPointerException and return null here
	if (is == null)
	    return null;

	if (headers == null)
	    headers = new InternetHeaders();
	headers.load(is); // load this header into the Headers object.
	setHeaderLoaded(name); // Mark this header as loaded

	return headers.getHeader(name);
    
public java.lang.StringgetHeader(java.lang.String name, java.lang.String delimiter)
Get the named header.

	checkExpunged();

	// force the header to be loaded by invoking getHeader(name)
	if (getHeader(name) == null)
	    return null;
	return headers.getHeader(name, delimiter);
    
public java.lang.StringgetInReplyTo()
Get the In-Reply-To header.

since
JavaMail 1.3.3

    	checkExpunged();
    	loadEnvelope();
    	return envelope.inReplyTo;
    
public intgetLineCount()
Get the total number of lines.

Returns the "body_fld_lines" field from the BODYSTRUCTURE. Note that this field is available only for text/plain and message/rfc822 types

	checkExpunged();
	loadBODYSTRUCTURE();
	return bs.lines;
    
public java.util.EnumerationgetMatchingHeaderLines(java.lang.String[] names)
Get all matching header-lines.

	checkExpunged();
	loadHeaders();
	return super.getMatchingHeaderLines(names);
    
public java.util.EnumerationgetMatchingHeaders(java.lang.String[] names)
Get matching headers.

	checkExpunged();
	loadHeaders();
	return super.getMatchingHeaders(names);
    
protected java.lang.ObjectgetMessageCacheLock()
Get the messageCacheLock, associated with this Message's Folder.

	return ((IMAPFolder)folder).messageCacheLock;
    
public java.lang.StringgetMessageID()
Get the Message-ID.

	checkExpunged();
	loadEnvelope();
	return envelope.messageId;
    
public java.util.EnumerationgetNonMatchingHeaderLines(java.lang.String[] names)
Get all non-matching headerlines.

	checkExpunged();
	loadHeaders();
	return super.getNonMatchingHeaderLines(names);
    
public java.util.EnumerationgetNonMatchingHeaders(java.lang.String[] names)
Get non-matching headers.

	checkExpunged();
	loadHeaders();
	return super.getNonMatchingHeaders(names);
    
public synchronized booleangetPeek()
Get whether or not to use the PEEK variant of FETCH when fetching message content.

since
JavaMail 1.3.3

	return peek;
    
protected com.sun.mail.imap.protocol.IMAPProtocolgetProtocol()
Get this message's folder's protocol connection. Throws FolderClosedException, if the protocol connection is not available. ASSERT: Must hold the messageCacheLock.

	((IMAPFolder)folder).waitIfIdle();
	IMAPProtocol p = ((IMAPFolder)folder).protocol;
	if (p == null)
	    throw new FolderClosedException(folder);
	else
	    return p;
    
public java.util.DategetReceivedDate()
Get the recieved date (INTERNALDATE)

	checkExpunged();
	loadEnvelope();
	if (receivedDate == null)
	    return null;
	else
	    return new Date(receivedDate.getTime());
    
public javax.mail.Address[]getRecipients(javax.mail.Message$RecipientType type)
Get the desired Recipient type.

	checkExpunged();
	loadEnvelope();

	if (type == Message.RecipientType.TO)
	    return aaclone(envelope.to);
	else if (type == Message.RecipientType.CC)
	    return aaclone(envelope.cc);
	else if (type == Message.RecipientType.BCC)
	    return aaclone(envelope.bcc);
	else
	    return super.getRecipients(type);
    
public javax.mail.Address[]getReplyTo()
Get the ReplyTo addresses.

	checkExpunged();
	loadEnvelope();
	return aaclone(envelope.replyTo);
    
public javax.mail.AddressgetSender()
Get the "Sender" attribute.

	checkExpunged();
	loadEnvelope();
	if (envelope.sender != null)
		return (envelope.sender)[0];	// there can be only one sender
	else 
		return null;
    
public java.util.DategetSentDate()
Get the SentDate.

	checkExpunged();
	loadEnvelope();
	if (envelope.date == null)
	    return null;
	else
	    return new Date(envelope.date.getTime());
    
protected intgetSequenceNumber()
Get this message's IMAP sequence number. ASSERT: This method must be called only when holding the messageCacheLock.

	return ((IMAPFolder)folder).messageCache.seqnumOf(getMessageNumber());
    
public intgetSize()
Get the message size.

Note that this returns RFC822.SIZE. That is, it's the size of the whole message, header and body included.

	checkExpunged();
	if (size == -1)
	    loadEnvelope();	// XXX - could just fetch the size
	return size;
    
public java.lang.StringgetSubject()
Get the decoded subject.

	checkExpunged();

	if (subject != null) // already cached ?
	    return subject;

	loadEnvelope();
	if (envelope.subject == null) // no subject
	    return null;

	// Cache and return the decoded value.
	try {
	    subject = MimeUtility.decodeText(envelope.subject);
	} catch (UnsupportedEncodingException ex) {
	    subject = envelope.subject;
	}

	return subject;
    
protected longgetUID()

	return uid;
    
public synchronized voidinvalidateHeaders()
Invalidate cached header and envelope information for this message. Subsequent accesses of this information will cause it to be fetched from the server.

since
JavaMail 1.3.3

	headersLoaded = false;
	loadedHeaders = null;
	envelope = null;
	bs = null;
	receivedDate = null;
	size = -1;
	type = null;
	subject = null;
	description = null;
    
private synchronized booleanisHeaderLoaded(java.lang.String name)

	if (headersLoaded) // All headers for this message have been loaded
	    return true;
	
	return (loadedHeaders != null) ? 
		loadedHeaders.containsKey(name.toUpperCase(Locale.ENGLISH)) :
		false;
    
protected booleanisREV1()

	// access the folder's protocol object without waiting
	// for IDLE to complete
	IMAPProtocol p = ((IMAPFolder)folder).protocol;
	if (p == null)
	    throw new FolderClosedException(folder);
	else
	    return p.isREV1();
    
public synchronized booleanisSet(javax.mail.Flags$Flag flag)
Test if the given Flags are set in this message.

	checkExpunged();
	loadFlags();
	return super.isSet(flag);
    
private synchronized voidloadBODYSTRUCTURE()

	if (bs != null) // already loaded
	    return;

	// Acquire MessageCacheLock, to freeze seqnum.
	synchronized(getMessageCacheLock()) {
	    try {
		IMAPProtocol p = getProtocol();

		// This message could be expunged when we were waiting 
		// to acquire the lock ...
		checkExpunged();

		bs = p.fetchBodyStructure(getSequenceNumber());
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		forceCheckExpunged();
		throw new MessagingException(pex.getMessage(), pex);
	    }
	    if (bs == null) {
		// if the FETCH is successful, we should always get a
		// BODYSTRUCTURE, but some servers fail to return it
		// if the message has been expunged
		forceCheckExpunged();
		throw new MessagingException("Unable to load BODYSTRUCTURE");
	    }
	}
    
private synchronized voidloadEnvelope()

	if (envelope != null) // already loaded
	    return;

	Response[] r = null;

	// Acquire MessageCacheLock, to freeze seqnum.
	synchronized(getMessageCacheLock()) {
	    try {
		IMAPProtocol p = getProtocol();

		checkExpunged(); // Insure that this message is not expunged

		int seqnum = getSequenceNumber();
		r = p.fetch(seqnum, EnvelopeCmd);

		for (int i = 0; i < r.length; i++) {
		    // If this response is NOT a FetchResponse or if it does
		    // not match our seqnum, skip.
		    if (r[i] == null ||
			!(r[i] instanceof FetchResponse) ||
			((FetchResponse)r[i]).getNumber() != seqnum)
			continue;

		    FetchResponse f = (FetchResponse)r[i];
		    
		    // Look for the Envelope items.
		    int count = f.getItemCount();
		    for (int j = 0; j < count; j++) {
			Item item = f.getItem(j);
			
			if (item instanceof ENVELOPE)
			    envelope = (ENVELOPE)item;
			else if (item instanceof INTERNALDATE)
			    receivedDate = ((INTERNALDATE)item).getDate();
			else if (item instanceof RFC822SIZE)
			    size = ((RFC822SIZE)item).size;
		    }
		}

		// ((IMAPFolder)folder).handleResponses(r);
		p.notifyResponseHandlers(r);
		p.handleResult(r[r.length - 1]);
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		forceCheckExpunged();
		throw new MessagingException(pex.getMessage(), pex);
	    }

	} // Release MessageCacheLock

	if (envelope == null)
	    throw new MessagingException("Failed to load IMAP envelope");
    
private synchronized voidloadFlags()

	if (flags != null)
	    return;
	
	// Acquire MessageCacheLock, to freeze seqnum.
	synchronized(getMessageCacheLock()) {
	    try {
		IMAPProtocol p = getProtocol();

		// This message could be expunged when we were waiting 
		// to acquire the lock ...
		checkExpunged();

		flags = p.fetchFlags(getSequenceNumber());
		// make sure flags is always set, even if server is broken
		if (flags == null)
		    flags = new Flags();
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		forceCheckExpunged();
		throw new MessagingException(pex.getMessage(), pex);
	    }
	} // Release MessageCacheLock
    
private synchronized voidloadHeaders()

	if (headersLoaded)
	    return;

	InputStream is = null;

	// Acquire MessageCacheLock, to freeze seqnum.
	synchronized (getMessageCacheLock()) {
	    try {
		IMAPProtocol p = getProtocol();

		// This message could be expunged when we were waiting 
		// to acquire the lock ...
		checkExpunged();

		if (p.isREV1()) {
		    BODY b = p.peekBody(getSequenceNumber(), 
					 toSection("HEADER"));
		    if (b != null)
			is = b.getByteArrayInputStream();
		} else {
		    RFC822DATA rd = p.fetchRFC822(getSequenceNumber(), 
						  "HEADER");
		    if (rd != null)
			is = rd.getByteArrayInputStream();
		}
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		forceCheckExpunged();
		throw new MessagingException(pex.getMessage(), pex);
	    }
	} // Release MessageCacheLock

	if (is == null)
	    throw new MessagingException("Cannot load header");
	headers = new InternetHeaders(is);
	headersLoaded = true;
    
public voidremoveHeader(java.lang.String name)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetContentID(java.lang.String cid)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetContentLanguage(java.lang.String[] languages)

    	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetContentMD5(java.lang.String md5)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetDataHandler(javax.activation.DataHandler content)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetDescription(java.lang.String description, java.lang.String charset)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetDisposition(java.lang.String disposition)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
protected voidsetExpunged(boolean set)

	super.setExpunged(set);
    
public voidsetFileName(java.lang.String filename)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public synchronized voidsetFlags(javax.mail.Flags flag, boolean set)
Set/Unset the given flags in this message.

        // Acquire MessageCacheLock, to freeze seqnum.
        synchronized(getMessageCacheLock()) {
	    try {
		IMAPProtocol p = getProtocol();
		checkExpunged(); // Insure that this message is not expunged
		p.storeFlags(getSequenceNumber(), flag, set);
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		throw new MessagingException(pex.getMessage(), pex);
	    }
	}
    
public voidsetFrom(javax.mail.Address address)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetHeader(java.lang.String name, java.lang.String value)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
private synchronized voidsetHeaderLoaded(java.lang.String name)

	if (loadedHeaders == null)
	    loadedHeaders = new Hashtable(1);
	loadedHeaders.put(name.toUpperCase(Locale.ENGLISH), name);
    
private synchronized voidsetHeadersLoaded(boolean loaded)

	headersLoaded = loaded;
    
protected voidsetMessageNumber(int msgnum)
Wrapper around the protected method Message.setMessageNumber() to make that method accessible to IMAPFolder.

	super.setMessageNumber(msgnum);
    
public synchronized voidsetPeek(boolean peek)
Set whether or not to use the PEEK variant of FETCH when fetching message content.

since
JavaMail 1.3.3

	this.peek = peek;
    
public voidsetRecipients(javax.mail.Message$RecipientType type, javax.mail.Address[] addresses)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetReplyTo(javax.mail.Address[] addresses)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetSender(javax.mail.Address address)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetSentDate(java.util.Date d)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
public voidsetSubject(java.lang.String subject, java.lang.String charset)

	throw new IllegalWriteException("IMAPMessage is read-only");
    
protected voidsetUID(long uid)

	this.uid = uid;
    
private java.lang.StringtoSection(java.lang.String what)

	if (sectionId == null)
	    return what;
	else
	    return sectionId + "." + what;
    
public voidwriteTo(java.io.OutputStream os)
Write out the bytes into the given outputstream.

	InputStream is = null;
	boolean pk = getPeek();	// get before acquiring message cache lock

        // Acquire MessageCacheLock, to freeze seqnum.
        synchronized(getMessageCacheLock()) {
	    try {
		IMAPProtocol p = getProtocol();

		checkExpunged(); // insure this message is not expunged

		if (p.isREV1()) {
		    BODY b;
		    if (pk)
			b = p.peekBody(getSequenceNumber(), sectionId);
		    else
			b = p.fetchBody(getSequenceNumber(), sectionId);
		    if (b != null)
			is = b.getByteArrayInputStream();
		} else {
		    RFC822DATA rd = p.fetchRFC822(getSequenceNumber(), null);
		    if (rd != null)
			is = rd.getByteArrayInputStream();
		}
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(folder, cex.getMessage());
	    } catch (ProtocolException pex) {
		forceCheckExpunged();
		throw new MessagingException(pex.getMessage(), pex);
	    }
	}

	if (is == null)
	    throw new MessagingException("No content");
	
	// write out the bytes
	byte[] bytes = new byte[1024];
	int count;
	while ((count = is.read(bytes)) != -1)
	    os.write(bytes, 0, count);