View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.geronimo.javamail.store.imap;
19  
20  import java.io.InputStream;
21  import java.io.UnsupportedEncodingException;
22  import java.util.Enumeration; 
23  
24  import javax.activation.DataHandler;   
25  
26  import javax.mail.IllegalWriteException; 
27  import javax.mail.MessagingException;
28  import javax.mail.Multipart;
29  
30  import javax.mail.internet.MimeBodyPart;
31  import javax.mail.internet.MimeUtility;
32  
33  import org.apache.geronimo.javamail.store.imap.connection.IMAPBodyStructure;
34  import org.apache.geronimo.javamail.store.imap.connection.IMAPConnection;
35  
36  
37  public class IMAPMimeBodyPart extends MimeBodyPart {
38      // the message we're part of
39      protected IMAPMessage message;
40      // the retrieved BODYSTRUCTURE information for this part.
41      protected IMAPBodyStructure bodyStructure;
42      // the section identifier.  This will be in a format such as 1.2.3, which 
43      // would refer to the "third part contained in the second part of the first part"...
44      // got all that?  There will be a quiz at the end of class :-)
45      protected String section;
46      // flag to indicate whether the body part headers have been loaded.
47      boolean headersLoaded = false;
48  
49      /**
50       * Create an instance of a MimeBodyPart within an 
51       * IMAP message.
52       * 
53       * @param message The parent Message instance containing this part.
54       * @param bodyStructure
55       *                The IMAPBodyStructure information describing the part.
56       * @param section The numeric section identifier string for this part.
57       *                This is a hierarchical set of numbers describing
58       *                how to navigate to the message part on the IMAP
59       *                server.  For example, "2.1.3" would be the third
60       *                subpart of the first subpart of the second main
61       *                message part.
62       */
63      public IMAPMimeBodyPart(IMAPMessage message, IMAPBodyStructure bodyStructure, String section) {
64          super();
65          this.message = message;
66          this.bodyStructure = bodyStructure;
67          this.section = section;
68      }
69  
70  
71      /**
72       * Get the size of the message part.
73       * 
74       * @return The size information returned in the IMAP body structure.
75       * @exception MessagingException
76       */
77      public int getSize() throws MessagingException {
78          return bodyStructure.bodySize;
79      }
80  
81      /**
82       * Get the estimated line count for the body part.
83       * 
84       * @return The line count information returned by the IMAP 
85       *         server.
86       * @exception MessagingException
87       */
88      public int getLineCount() throws MessagingException {
89          return bodyStructure.lines;
90      }
91  
92      /**
93       * Get the content type for the body part.
94       * 
95       * @return The mimetype for the body part, in string format.
96       * @exception MessagingException
97       */
98      public String getContentType() throws MessagingException {
99          return bodyStructure.mimeType.toString();
100     }
101 
102     /**
103      * Test if the body part is of a particular MIME type.
104      * 
105      * @param type   The string MIME-type name.  A wild card * can be
106      *               specified for the subpart type.
107      * 
108      * @return true if the body part matches the give MIME-type.
109      * @exception MessagingException
110      */
111     public boolean isMimeType(String type) throws MessagingException {
112         return bodyStructure.mimeType.match(type);
113     }
114 
115     /**
116      * Retrieve the disposition information about this 
117      * body part.
118      * 
119      * @return The disposition information, as a string value.
120      * @exception MessagingException
121      */
122     public String getDisposition() throws MessagingException {
123         return bodyStructure.disposition.getDisposition();
124     }
125 
126     /**
127      * Set the disposition information.  The IMAP message 
128      * is read-only, so this is an error.
129      * 
130      * @param disposition
131      *               The disposition string.
132      * 
133      * @exception MessagingException
134      */
135     public void setDisposition(String disposition) throws MessagingException {
136         throw new IllegalWriteException("IMAP message parts are read-only");
137     }
138 
139     public String getEncoding() throws MessagingException {
140         return bodyStructure.transferEncoding;
141     }
142 
143     public String getContentID() throws MessagingException {
144         return bodyStructure.contentID;
145     }
146 
147     public void setContentID(String id) throws MessagingException {
148         throw new IllegalWriteException("IMAP message parts are read-only");
149     }
150 
151     public String getContentMD5() throws MessagingException {
152         return bodyStructure.md5Hash;
153     }
154 
155     public void setContentMD5(String id) throws MessagingException {
156         throw new IllegalWriteException("IMAP message parts are read-only");
157     }
158 
159     public String getDescription() throws MessagingException {
160         String description = bodyStructure.contentDescription;
161         if (description != null) {
162             try {
163                 // this could be both folded and encoded.  Return this to usable form.
164                 return MimeUtility.decodeText(MimeUtility.unfold(description));
165             } catch (UnsupportedEncodingException e) {
166                 // ignore
167             }
168         }
169         // return the raw version for any errors (this might be null also)
170         return description;
171     }
172 
173     public void setDescription(String d, String charset) throws MessagingException {
174         throw new IllegalWriteException("IMAP message parts are read-only");
175     }
176 
177     public String getFileName() throws MessagingException {
178         String filename = bodyStructure.disposition.getParameter("filename");
179         if (filename == null) {
180             filename = bodyStructure.mimeType.getParameter("name");
181         }
182         return filename;
183     }
184 
185     public void setFileName(String name) throws MessagingException {
186         throw new IllegalWriteException("IMAP message parts are read-only");
187     }
188 
189     protected InputStream getContentStream() throws MessagingException {
190 
191         // no content loaded yet?
192         if (content == null) {
193             // make sure we're still valid
194             message.checkValidity();
195             // make sure the content is fully loaded
196             loadContent();
197         }
198 
199         // allow the super class to handle creating it from the loaded content.
200         return super.getContentStream();
201     }
202 
203 
204     /**
205      * Create the DataHandler object for this message.
206      *
207      * @return The DataHandler object that processes the content set for this
208      *         message.
209      * @exception MessagingException
210      */
211     public synchronized DataHandler getDataHandler() throws MessagingException {
212         if (dh == null) {                                                
213             // are we working with a multipart message here?
214             if (bodyStructure.isMultipart()) {
215                 dh = new DataHandler(new IMAPMultipartDataSource(message, this, section, bodyStructure));
216                 return dh;
217             }
218             else if (bodyStructure.isAttachedMessage()) {
219                 dh = new DataHandler(new IMAPAttachedMessage(message, section, bodyStructure.nestedEnvelope, 
220                     bodyStructure.nestedBody), bodyStructure.mimeType.toString());
221                 return dh;
222             }
223         }
224 
225         // single part messages get handled the normal way.
226         return super.getDataHandler();
227     }
228 
229     public void setDataHandler(DataHandler content) throws MessagingException {
230         throw new IllegalWriteException("IMAP body parts are read-only");
231     }
232 
233     public void setContent(Object o, String type) throws MessagingException {
234         throw new IllegalWriteException("IMAP body parts are read-only");
235     }
236 
237     public void setContent(Multipart mp) throws MessagingException {
238         throw new IllegalWriteException("IMAP body parts are read-only");
239     }
240 
241 
242 	/******************************************************************
243 	 * Following is a set of methods that deal with headers
244 	 * These methods are just overrides on the superclass methods to
245      * allow lazy loading of the header information.
246 	 ********************************************************************/
247 
248 	public String[] getHeader(String name) throws MessagingException {
249         loadHeaders();
250 		return headers.getHeader(name);
251 	}
252 
253 	public String getHeader(String name, String delimiter) throws MessagingException {
254         loadHeaders();
255 		return headers.getHeader(name, delimiter);
256 	}
257 
258 	public Enumeration getAllHeaders() throws MessagingException {
259         loadHeaders();
260 		return headers.getAllHeaders();
261 	}
262 
263 	public Enumeration getMatchingHeaders(String[] names)  throws MessagingException {
264         loadHeaders();
265 		return headers.getMatchingHeaders(names);
266 	}
267 
268 	public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
269         loadHeaders();
270 		return headers.getNonMatchingHeaders(names);
271 	}
272 
273 	public Enumeration getAllHeaderLines() throws MessagingException {
274         loadHeaders();
275 		return headers.getAllHeaderLines();
276 	}
277 
278 	public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
279         loadHeaders();
280 		return headers.getMatchingHeaderLines(names);
281 	}
282 
283 	public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
284         loadHeaders();
285 		return headers.getNonMatchingHeaderLines(names);
286 	}
287 
288     // the following are overrides for header modification methods.  These messages are read only,
289     // so the headers cannot be modified.
290     public void addHeader(String name, String value) throws MessagingException {
291         throw new IllegalWriteException("IMAP messages are read-only");
292     }
293 
294     public void setHeader(String name, String value) throws MessagingException {
295         throw new IllegalWriteException("IMAP messages are read-only");
296     }
297 
298 
299     public void removeHeader(String name) throws MessagingException {
300         throw new IllegalWriteException("IMAP messages are read-only");
301     }
302 
303     public void addHeaderLine(String line) throws MessagingException {
304         throw new IllegalWriteException("IMAP messages are read-only");
305     }
306 
307 
308     /**
309      * Load the mime part headers into this body part.
310      *
311      * @exception MessagingException
312      */
313     protected synchronized void loadHeaders() throws MessagingException {
314         // have them already?  Super..
315         if (headers != null) {
316             return;
317         }
318                            
319         IMAPConnection connection = message.getConnection();
320         try {
321             // this asks for the MIME subsection of the given section piece.
322             headers = connection.fetchHeaders(message.getSequenceNumber(), section);
323         } finally {    
324             message.releaseConnection(connection);
325         }
326 
327     }
328 
329 
330     /**
331      * Load the message content into the BodyPart object.
332      *
333      * @exception MessagingException
334      */
335     protected void loadContent() throws MessagingException {
336         // if we've loaded this already, just return
337         if (content != null) {
338             return;
339         }
340         
341         IMAPConnection connection = message.getConnection();
342         try {
343             // load the content from the server. 
344             content = connection.fetchContent(message.getSequenceNumber(), section); 
345         } finally {
346             message.releaseConnection(connection); 
347         }
348     }
349 }
350