i4msg.getEnvelope(result, mm);  empty = false;
i4msg.serializeEnvelope(result, mm);  empty = false;
    boolean doFETCH(String tag, String sequenceSet, int attributes, List<ImapPartSpecifier> parts, boolean byUID) throws IOException {        if (!checkState(tag, ImapSession.STATE_SELECTED))            return CONTINUE_PROCESSING;        // 6.4.8: "However, server implementations MUST implicitly include the UID message        //         data item as part of any FETCH response caused by a UID command, regardless        //         of whether a UID was specified as a message data item to the FETCH."        if (byUID)            attributes |= FETCH_UID;        boolean markRead = mSession.getFolder().isWritable() && (attributes & FETCH_MARK_READ) != 0;        List<ImapPartSpecifier> fullMessage = new ArrayList<ImapPartSpecifier>();        if (parts != null && !parts.isEmpty())            for (Iterator it = parts.iterator(); it.hasNext(); ) {                ImapPartSpecifier pspec = (ImapPartSpecifier) it.next();                if (pspec.mPart.equals("") && pspec.mModifier.equals("")) {                    it.remove();  fullMessage.add(pspec);                }            }        String command = (byUID ? "UID FETCH" : "FETCH");        boolean allPresent = true;        synchronized (mMailbox) {            Set<ImapMessage> i4set = mSession.getFolder().getSubsequence(sequenceSet, byUID);            allPresent = byUID || !i4set.contains(null);            for (ImapMessage i4msg : i4set) {                if (i4msg == null)                    continue;                ByteArrayOutputStream baos = new ByteArrayOutputStream();		        PrintStream result = new PrintStream(baos, false, "utf-8");	        	try {                    boolean markMessage = markRead && (i4msg.flags & Flag.FLAG_UNREAD) != 0;                    boolean empty = true;                    byte[] raw = null;                    result.print('*');                    result.print(' ');                    result.print(i4msg.seq);                    result.print(" FETCH (");                    if ((attributes & FETCH_UID) != 0) {                        result.print(empty ? "" : " ");  result.print("UID "); result.print(i4msg.uid);  empty = false;                    }                    if ((attributes & FETCH_INTERNALDATE) != 0) {			        	result.print(empty ? "" : " ");  result.print(i4msg.getDate(mTimeFormat));  empty = false;                    }			        if ((attributes & FETCH_RFC822_SIZE) != 0) {			        	result.print(empty ? "" : " ");  result.print("RFC822.SIZE ");  result.print(i4msg.getSize());  empty = false;                    }                    if (!fullMessage.isEmpty()) {                        raw = mMailbox.getMessageById(getContext(), i4msg.id).getMessageContent();                        for (ImapPartSpecifier pspec : fullMessage) {                            result.print(empty ? "" : " ");  pspec.write(result, raw);  empty = false;                        }                    }			        if (!parts.isEmpty() || (attributes & ~FETCH_FROM_CACHE) != 0) {                        MimeMessage mm;                        try {                            // don't use msg.getMimeMessage() because it implicitly expands TNEF attachments                            InputStream is = raw != null ? new ByteArrayInputStream(raw) : mMailbox.getMessageById(getContext(), i4msg.id).getRawMessage();                            mm = new Mime.FixedMimeMessage(JMSession.getSession(), is);                            if (mSession.isHackEnabled(EnabledHack.WM5))                                if (new ImapMessage.WindowsMobile5Converter().accept(mm)) {                                    // FIXME: terrible hack to work around JavaMail repulsiveness                                    ByteArrayOutputStream baosCopy = new ByteArrayOutputStream();                                    mm.writeTo(baosCopy);                                    mm = new Mime.FixedMimeMessage(JMSession.getSession(), new ByteArrayInputStream(baosCopy.toByteArray()));                                }                            is.close();                        } catch (IOException e) {                            throw ServiceException.FAILURE("error fetching raw content for message " + i4msg.id, e);                        }                        if ((attributes & FETCH_BODY) != 0) {                            result.print(empty ? "" : " ");  result.print("BODY ");                            i4msg.getStructure(result, mm, false);  empty = false;                        }                        if ((attributes & FETCH_BODYSTRUCTURE) != 0) {                            result.print(empty ? "" : " ");  result.print("BODYSTRUCTURE ");                            i4msg.getStructure(result, mm, true);  empty = false;                        }                        if ((attributes & FETCH_ENVELOPE) != 0) {                            result.print(empty ? "" : " ");  result.print("ENVELOPE ");                            i4msg.getEnvelope(result, mm);  empty = false;                        }                        for (ImapPartSpecifier pspec : parts) {                            byte[] content = i4msg.getPart(mm, pspec);                            result.print(empty ? "" : " ");  pspec.write(result, content);  empty = false;                        }			        }                    // FIXME: optimize by doing a single mark-read op on multiple messages                    if (markMessage)                        mMailbox.alterTag(getContext(), i4msg.id, MailItem.TYPE_MESSAGE, Flag.ID_FLAG_UNREAD, false);                    // 6.4.5: "The \Seen flag is implicitly set; if this causes the flags to                    //         change, they SHOULD be included as part of the FETCH responses."                    if ((attributes & FETCH_FLAGS) != 0 || markMessage) {                        mSession.getFolder().undirtyMessage(i4msg);                        result.print(empty ? "" : " ");  result.print(i4msg.getFlags(mSession));  empty = false;                    }                } catch (ServiceException e) {                    ZimbraLog.imap.warn("ignoring error during " + command + ": ", e);                    continue;                } catch (MessagingException e) {                    ZimbraLog.imap.warn("ignoring error during " + command + ": ", e);                    continue;                } finally {                    result.write(')');                    result.write(LINE_SEPARATOR_BYTES, 0, LINE_SEPARATOR_BYTES.length);                    if (baos != null) {                        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());                        mConnection.write(bb);                        ZimbraLog.imap.debug("  S: " + baos);                    }                }            }            sendNotifications(false, false);        }        if (allPresent)        	sendOK(tag, command + " completed");        else {        	// RFC 2180 4.1.2: "The server MAY allow the EXPUNGE of a multi-accessed mailbox,            //                  and on subsequent FETCH commands return FETCH responses only		    //                  for non-expunged messages and a tagged NO."        	sendNO(tag, "some of the requested messages no longer exist");        }        return CONTINUE_PROCESSING;    }