001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.geronimo.javamail.store.imap.connection;
019    import java.util.ArrayList;
020    import java.util.List;
021    
022    import javax.mail.MessagingException;
023    
024    /**
025     * Util class to represent a composite FETCH response from an IMAP server.  The
026     * response may have information about multiple message dataItems.
027     *
028     * @version $Rev: 594520 $ $Date: 2007-11-13 07:57:39 -0500 (Tue, 13 Nov 2007) $
029     */
030    public class IMAPFetchResponse extends IMAPUntaggedResponse {
031        // parsed sections within the FETCH response structure 
032        protected List dataItems = new ArrayList();
033        // the message number to which this applies 
034        public int sequenceNumber; 
035    
036        public IMAPFetchResponse(int sequenceNumber, byte[] data, IMAPResponseTokenizer source) throws MessagingException {
037            super("FETCH", data);
038            
039            this.sequenceNumber = sequenceNumber; 
040    
041            // fetch responses are a list, even if there is just a single member.
042            source.checkLeftParen();
043    
044            // loop until we find the list end.
045            while (source.notListEnd()) {
046                // the response names are coded as ATOMS.  The BODY one's use a special 
047                // syntax, so we need to use the expanded delimiter set to pull this out. 
048                String itemName = source.readAtom(true).toUpperCase();
049    
050                if (itemName.equals("ENVELOPE")) {
051                    dataItems.add(new IMAPEnvelope(source));
052                }
053                else if (itemName.equals("BODYSTRUCTURE")) {
054                    dataItems.add(new IMAPBodyStructure(source));
055                }
056                else if (itemName.equals("FLAGS")) {
057                    dataItems.add(new IMAPFlags(source));
058                }
059                else if (itemName.equals("INTERNALDATE")) {
060                    dataItems.add(new IMAPInternalDate(source));
061                }
062                else if (itemName.equals("UID")) {
063                    dataItems.add(new IMAPUid(sequenceNumber, source));
064                }
065                else if (itemName.equals("RFC822")) {
066                    // all of the RFC822 items are of form 
067                    // "RFC822.name".  We used the expanded parse above because 
068                    // the BODY names include some complicated bits.  If we got one 
069                    // of the RFC822 sections, then parse the rest of the name using 
070                    // the old rules, which will pull in the rest of the name from the period. 
071                    itemName = source.readAtom(false).toUpperCase();
072                    if (itemName.equals(".SIZE")) {
073                        dataItems.add(new IMAPMessageSize(source));
074                    }
075                    else if (itemName.equals(".HEADER")) {
076                        dataItems.add(new IMAPInternetHeader(source.readByteArray()));
077                    }
078                    else if (itemName.equals(".TEXT")) {
079                        dataItems.add(new IMAPMessageText(source.readByteArray()));
080                    }
081                }
082                // this is just the body alone. Specific body segments 
083                // have a more complex naming structure.  Believe it or  
084                // not, 
085                else if (itemName.equals("BODY")) {
086                    // time to go parse out the section information from the 
087                    // name.  
088                    IMAPBodySection section = new IMAPBodySection(source); 
089                    
090                    switch (section.section) {
091                        case IMAPBodySection.BODY:
092                            // a "full body cast".  Just grab the binary data 
093                            dataItems.add(new IMAPBody(section, source.readByteArray())); 
094                            break; 
095                            
096                        case IMAPBodySection.HEADERS:
097                        case IMAPBodySection.HEADERSUBSET:
098                        case IMAPBodySection.MIME:
099                            // these 3 are all variations of a header request
100                            dataItems.add(new IMAPInternetHeader(section, source.readByteArray())); 
101                            break; 
102                            
103                        case IMAPBodySection.TEXT:
104                            // just the text portion of the body 
105                            // a "full body cast".  Just grab the binary data 
106                            dataItems.add(new IMAPMessageText(section, source.readByteArray())); 
107                            break; 
108                    }
109                }
110            }
111            // swallow the terminating right paren
112            source.checkRightParen(); 
113        }
114        
115        /**
116         * Retrieve the sequence number for the FETCH item. 
117         * 
118         * @return The message sequence number this FETCH applies to. 
119         */
120        public int getSequenceNumber() {
121            return sequenceNumber; 
122        }
123    
124        /**
125         * Get the section count.
126         *
127         * @return The number of sections in the response.
128         */
129        public int getCount() {
130            return dataItems.size();
131        }
132    
133        /**
134         * Get the complete set of response dataItems.
135         *
136         * @return The List of IMAPFetchResponse values.
137         */
138        public List getDataItems() {
139            return dataItems;
140        }
141    
142    
143        /**
144         * Fetch a particular response type from the response dataItems.
145         *
146         * @param type   The target FETCH type.
147         *
148         * @return The first IMAPFetchDataItem item that matches the response type.
149         */
150        public IMAPFetchDataItem getDataItem(int type) {
151            for (int i = 0; i < dataItems.size(); i ++) {
152                IMAPFetchDataItem item = (IMAPFetchDataItem)dataItems.get(i);
153                if (item.isType(type)) {
154                    return item;
155                }
156            }
157            return null;
158        }
159        
160    }
161