001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: /*
038: * @(#)IMAPBodyPart.java 1.20 07/06/13
039: */
040:
041: package com.sun.mail.imap;
042:
043: import java.io.*;
044:
045: import java.util.Enumeration;
046: import javax.mail.*;
047: import javax.mail.internet.*;
048: import javax.activation.*;
049:
050: import com.sun.mail.util.*;
051: import com.sun.mail.iap.*;
052: import com.sun.mail.imap.protocol.*;
053:
054: /**
055: * This class
056: *
057: * @version 1.4, 97/12/09
058: * @author John Mani
059: */
060:
061: public class IMAPBodyPart extends MimeBodyPart {
062: private IMAPMessage message;
063: private BODYSTRUCTURE bs;
064: private String sectionId;
065:
066: // processed values ..
067: private String type;
068: private String description;
069:
070: private boolean headersLoaded = false;
071:
072: protected IMAPBodyPart(BODYSTRUCTURE bs, String sid,
073: IMAPMessage message) {
074: super ();
075: this .bs = bs;
076: this .sectionId = sid;
077: this .message = message;
078: // generate content-type
079: ContentType ct = new ContentType(bs.type, bs.subtype,
080: bs.cParams);
081: type = ct.toString();
082: }
083:
084: /* Override this method to make it a no-op, rather than throw
085: * an IllegalWriteException. This will permit IMAPBodyParts to
086: * be inserted in newly crafted MimeMessages, especially when
087: * forwarding or replying to messages.
088: */
089: protected void updateHeaders() {
090: return;
091: }
092:
093: public int getSize() throws MessagingException {
094: return bs.size;
095: }
096:
097: public int getLineCount() throws MessagingException {
098: return bs.lines;
099: }
100:
101: public String getContentType() throws MessagingException {
102: return type;
103: }
104:
105: public String getDisposition() throws MessagingException {
106: return bs.disposition;
107: }
108:
109: public void setDisposition(String disposition)
110: throws MessagingException {
111: throw new IllegalWriteException("IMAPBodyPart is read-only");
112: }
113:
114: public String getEncoding() throws MessagingException {
115: return bs.encoding;
116: }
117:
118: public String getContentID() throws MessagingException {
119: return bs.id;
120: }
121:
122: public String getContentMD5() throws MessagingException {
123: return bs.md5;
124: }
125:
126: public void setContentMD5(String md5) throws MessagingException {
127: throw new IllegalWriteException("IMAPBodyPart is read-only");
128: }
129:
130: public String getDescription() throws MessagingException {
131: if (description != null) // cached value ?
132: return description;
133:
134: if (bs.description == null)
135: return null;
136:
137: try {
138: description = MimeUtility.decodeText(bs.description);
139: } catch (UnsupportedEncodingException ex) {
140: description = bs.description;
141: }
142:
143: return description;
144: }
145:
146: public void setDescription(String description, String charset)
147: throws MessagingException {
148: throw new IllegalWriteException("IMAPBodyPart is read-only");
149: }
150:
151: public String getFileName() throws MessagingException {
152: String filename = null;
153: if (bs.dParams != null)
154: filename = bs.dParams.get("filename");
155: if (filename == null && bs.cParams != null)
156: filename = bs.cParams.get("name");
157: return filename;
158: }
159:
160: public void setFileName(String filename) throws MessagingException {
161: throw new IllegalWriteException("IMAPBodyPart is read-only");
162: }
163:
164: protected InputStream getContentStream() throws MessagingException {
165: InputStream is = null;
166: boolean pk = message.getPeek(); // acquire outisde of message cache lock
167:
168: // Acquire MessageCacheLock, to freeze seqnum.
169: synchronized (message.getMessageCacheLock()) {
170: try {
171: IMAPProtocol p = message.getProtocol();
172:
173: // Check whether this message is expunged
174: message.checkExpunged();
175:
176: if (p.isREV1() && (message.getFetchBlockSize() != -1))
177: return new IMAPInputStream(message, sectionId,
178: bs.size, pk);
179:
180: // Else, vanila IMAP4, no partial fetch
181:
182: int seqnum = message.getSequenceNumber();
183: BODY b;
184: if (pk)
185: b = p.peekBody(seqnum, sectionId);
186: else
187: b = p.fetchBody(seqnum, sectionId);
188: if (b != null)
189: is = b.getByteArrayInputStream();
190: } catch (ConnectionException cex) {
191: throw new FolderClosedException(message.getFolder(),
192: cex.getMessage());
193: } catch (ProtocolException pex) {
194: throw new MessagingException(pex.getMessage(), pex);
195: }
196: }
197:
198: if (is == null)
199: throw new MessagingException("No content");
200: else
201: return is;
202: }
203:
204: public synchronized DataHandler getDataHandler()
205: throws MessagingException {
206: if (dh == null) {
207: if (bs.isMulti())
208: dh = new DataHandler(new IMAPMultipartDataSource(this ,
209: bs.bodies, sectionId, message));
210: else if (bs.isNested() && message.isREV1())
211: dh = new DataHandler(new IMAPNestedMessage(message,
212: bs.bodies[0], bs.envelope, sectionId), type);
213: }
214:
215: return super .getDataHandler();
216: }
217:
218: public void setDataHandler(DataHandler content)
219: throws MessagingException {
220: throw new IllegalWriteException("IMAPBodyPart is read-only");
221: }
222:
223: public void setContent(Object o, String type)
224: throws MessagingException {
225: throw new IllegalWriteException("IMAPBodyPart is read-only");
226: }
227:
228: public void setContent(Multipart mp) throws MessagingException {
229: throw new IllegalWriteException("IMAPBodyPart is read-only");
230: }
231:
232: public String[] getHeader(String name) throws MessagingException {
233: loadHeaders();
234: return super .getHeader(name);
235: }
236:
237: public void setHeader(String name, String value)
238: throws MessagingException {
239: throw new IllegalWriteException("IMAPBodyPart is read-only");
240: }
241:
242: public void addHeader(String name, String value)
243: throws MessagingException {
244: throw new IllegalWriteException("IMAPBodyPart is read-only");
245: }
246:
247: public void removeHeader(String name) throws MessagingException {
248: throw new IllegalWriteException("IMAPBodyPart is read-only");
249: }
250:
251: public Enumeration getAllHeaders() throws MessagingException {
252: loadHeaders();
253: return super .getAllHeaders();
254: }
255:
256: public Enumeration getMatchingHeaders(String[] names)
257: throws MessagingException {
258: loadHeaders();
259: return super .getMatchingHeaders(names);
260: }
261:
262: public Enumeration getNonMatchingHeaders(String[] names)
263: throws MessagingException {
264: loadHeaders();
265: return super .getNonMatchingHeaders(names);
266: }
267:
268: public void addHeaderLine(String line) throws MessagingException {
269: throw new IllegalWriteException("IMAPBodyPart is read-only");
270: }
271:
272: public Enumeration getAllHeaderLines() throws MessagingException {
273: loadHeaders();
274: return super .getAllHeaderLines();
275: }
276:
277: public Enumeration getMatchingHeaderLines(String[] names)
278: throws MessagingException {
279: loadHeaders();
280: return super .getMatchingHeaderLines(names);
281: }
282:
283: public Enumeration getNonMatchingHeaderLines(String[] names)
284: throws MessagingException {
285: loadHeaders();
286: return super .getNonMatchingHeaderLines(names);
287: }
288:
289: private synchronized void loadHeaders() throws MessagingException {
290: if (headersLoaded)
291: return;
292:
293: if (headers == null)
294: headers = new InternetHeaders();
295:
296: // load headers
297:
298: // Acquire MessageCacheLock, to freeze seqnum.
299: synchronized (message.getMessageCacheLock()) {
300: try {
301: IMAPProtocol p = message.getProtocol();
302:
303: // Check whether this message got expunged
304: message.checkExpunged();
305:
306: if (p.isREV1()) {
307: int seqnum = message.getSequenceNumber();
308: BODY b = p.peekBody(seqnum, sectionId + ".MIME");
309:
310: if (b == null)
311: throw new MessagingException(
312: "Failed to fetch headers");
313:
314: ByteArrayInputStream bis = b
315: .getByteArrayInputStream();
316: if (bis == null)
317: throw new MessagingException(
318: "Failed to fetch headers");
319:
320: headers.load(bis);
321:
322: } else {
323:
324: // RFC 1730 does not provide for fetching BodyPart headers
325: // So, just dump the RFC1730 BODYSTRUCTURE into the
326: // headerStore
327:
328: // Content-Type
329: headers.addHeader("Content-Type", type);
330: // Content-Transfer-Encoding
331: headers.addHeader("Content-Transfer-Encoding",
332: bs.encoding);
333: // Content-Description
334: if (bs.description != null)
335: headers.addHeader("Content-Description",
336: bs.description);
337: // Content-ID
338: if (bs.id != null)
339: headers.addHeader("Content-ID", bs.id);
340: // Content-MD5
341: if (bs.md5 != null)
342: headers.addHeader("Content-MD5", bs.md5);
343: }
344: } catch (ConnectionException cex) {
345: throw new FolderClosedException(message.getFolder(),
346: cex.getMessage());
347: } catch (ProtocolException pex) {
348: throw new MessagingException(pex.getMessage(), pex);
349: }
350: }
351: headersLoaded = true;
352: }
353: }
|