for (Iterator it = parts.iterator(); it.hasNext(); ) { ImapPartSpecifier pspec = (ImapPartSpecifier) it.next();
for (Iterator<ImapPartSpecifier> it = parts.iterator(); it.hasNext(); ) { ImapPartSpecifier pspec = it.next();
    boolean doFETCH(String tag, String sequenceSet, int attributes, List<ImapPartSpecifier> parts, boolean byUID) throws IOException, ImapParseException {        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;        String command = (byUID ? "UID FETCH" : "FETCH");        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.isEntireMessage()) {                    it.remove();  fullMessage.add(pspec);                }            }        Set<ImapMessage> i4set;        synchronized (mMailbox) {            i4set = mSession.getFolder().getSubsequence(sequenceSet, byUID);        }        boolean allPresent = byUID || !i4set.contains(null);        i4set.remove(null);        for (ImapMessage i4msg : i4set) {            OutputStream baos = new BufferedOutputStream(new ConnectionOutputStream(), 4000);             ByteArrayOutputStream baosDebug = ZimbraLog.imap.isDebugEnabled() ? new ByteArrayOutputStream() : null;            PrintStream result = new PrintStream(new ByteUtil.TeeOutputStream(baos, baosDebug), false, "utf-8");        	try {                boolean markMessage = markRead && (i4msg.flags & Flag.BITMASK_UNREAD) != 0;                boolean empty = true;                byte[] raw = null;                MailItem item = null;                MimeMessage mm = null;                if (!fullMessage.isEmpty() || !parts.isEmpty() || (attributes & ~FETCH_FROM_CACHE) != 0) {                    GetItemOperation op = new GetItemOperation(mSession, getContext(), mMailbox, Requester.IMAP, i4msg.msgId, i4msg.getType());                    op.schedule();                    item = op.getItem();                }                result.print("* " + i4msg.sequence + " FETCH (");                if ((attributes & FETCH_UID) != 0) {                    result.print((empty ? "" : " ") + "UID " + i4msg.imapUid);  empty = false;                }                if ((attributes & FETCH_INTERNALDATE) != 0) {                    result.print((empty ? "" : " ") + "INTERNALDATE \"" + mTimeFormat.format(new Date(item.getDate())) + '"');  empty = false;                }                if ((attributes & FETCH_RFC822_SIZE) != 0) {                    result.print((empty ? "" : " ") + "RFC822.SIZE " + i4msg.getSize(item));  empty = false;                }                if ((attributes & FETCH_BINARY_SIZE) != 0) {                    result.print((empty ? "" : " ") + "BINARY.SIZE[] " + i4msg.getSize(item));  empty = false;                }                if (!fullMessage.isEmpty()) {                    raw = ImapMessage.getContent(item);                    for (ImapPartSpecifier pspec : fullMessage) {                        ZimbraLog.imap.info("before pspec.write");                        result.print(empty ? "" : " ");  pspec.write(result, baos, raw);  empty = false;                        ZimbraLog.imap.info("after pspec.write");                    }                }                if (!parts.isEmpty() || (attributes & ~FETCH_FROM_MIME) != 0) {                    try {                        // don't use msg.getMimeMessage() because it implicitly expands TNEF attachments                        InputStream is = raw != null ? new ByteArrayInputStream(raw) : ImapMessage.getContentStream(item);                        mm = new Mime.FixedMimeMessage(JMSession.getSession(), is);                        is.close();                    } catch (IOException e) {                        throw ServiceException.FAILURE("error closing stream for message " + i4msg.msgId, e);                    }                }                if ((attributes & FETCH_BODY) != 0) {                    result.print((empty ? "" : " ") + "BODY ");                    i4msg.serializeStructure(result, mm, false);  empty = false;                }                if ((attributes & FETCH_BODYSTRUCTURE) != 0) {                    result.print((empty ? "" : " ") + "BODYSTRUCTURE ");                    i4msg.serializeStructure(result, mm, true);  empty = false;                }                if ((attributes & FETCH_ENVELOPE) != 0) {                    result.print((empty ? "" : " ") + "ENVELOPE ");                    i4msg.serializeEnvelope(result, mm);  empty = false;                }                for (ImapPartSpecifier pspec: parts) {                    result.print(empty ? "" : " ");  pspec.write(result, mm);  empty = false;                }                // FIXME: optimize by doing a single mark-read op on multiple messages                if (markMessage) {                    AlterTagOperation op = new AlterTagOperation(mSession, getContext(), mMailbox, Requester.IMAP, i4msg.msgId, i4msg.getType(), Flag.ID_FLAG_UNREAD, false);                    op.schedule();                }                                // 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 ? "" : " ") + i4msg.getFlags(mSession));  empty = false;                }            } catch (ImapPartSpecifier.BinaryDecodingException e) {                // don't write this response line if we're returning NO                baos = null;                throw new ImapParseException(tag, "UNKNOWN-CTE", command + "failed: unknown content-type-encoding", 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);                baos.close();                if (baosDebug != null) {                    ZimbraLog.imap.debug("  S: " + baosDebug);                }            }        }        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;    }