KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > mail > imap > IMAPInputStream


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)IMAPInputStream.java 1.10 06/03/24
24  *
25  * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package com.sun.mail.imap;
29
30 import java.io.*;
31 import javax.mail.*;
32 import com.sun.mail.imap.protocol.*;
33 import com.sun.mail.iap.*;
34
35 /**
36  * This class implements an IMAP data stream.
37  *
38  * @author John Mani
39  */

40
41 public class IMAPInputStream extends InputStream {
42     private IMAPMessage msg; // this message
43
private String JavaDoc section; // section-id
44
private int pos; // track the position within the IMAP datastream
45
private int blksize; // number of bytes to read in each FETCH request
46
private int max; // the total number of bytes in this section.
47
// -1 indicates unknown
48
private byte[] buf; // the buffer obtained from fetchBODY()
49
private int bufcount; // The index one greater than the index of the
50
// last valid byte in 'buf'
51
private int bufpos; // The current position within 'buf'
52
private boolean peek; // peek instead of fetch?
53

54
55     /**
56      * Create an IMAPInputStream.
57      */

58     public IMAPInputStream(IMAPMessage msg, String JavaDoc section, int max,
59                 boolean peek) {
60     this.msg = msg;
61     this.section = section;
62     this.max = max;
63     this.peek = peek;
64     pos = 0;
65     blksize = msg.getFetchBlockSize();
66     }
67
68     /**
69      * Fetch more data from the server. This method assumes that all
70      * data has already been read in, hence bufpos > bufcount.
71      */

72     private void fill() throws IOException {
73     /*
74      * If we know the total number of bytes available from this
75      * section, let's check if we have consumed that many bytes.
76      */

77     if (max != -1 && pos >= max) {
78         if (pos == 0)
79         checkSeen();
80         return; // the caller of fill() will return -1.
81
}
82
83     BODY b = null;
84
85     // Acquire MessageCacheLock, to freeze seqnum.
86
synchronized (msg.getMessageCacheLock()) {
87
88         // Check whether this message is expunged
89
if (msg.isExpunged())
90         throw new IOException("No content for expunged message");
91
92         int seqnum = msg.getSequenceNumber();
93         int cnt = blksize;
94         if (max != -1 && pos + blksize > max)
95         cnt = max - pos;
96         try {
97         IMAPProtocol p = msg.getProtocol();
98         if (peek)
99             b = p.peekBody(seqnum, section, pos, cnt);
100         else
101             b = p.fetchBody(seqnum, section, pos, cnt);
102         } catch (ProtocolException pex) {
103         throw new IOException(pex.getMessage());
104         } catch (FolderClosedException fex) {
105         throw new IOException(fex.getMessage());
106         }
107     }
108
109     ByteArray ba;
110     if (b == null || ((ba = b.getByteArray()) == null))
111         throw new IOException("No content");
112
113     // make sure the SEEN flag is set after reading the first chunk
114
if (pos == 0)
115         checkSeen();
116
117     // setup new values ..
118
buf = ba.getBytes();
119     bufpos = ba.getStart();
120     int n = ba.getCount(); // will be zero, if all data has been
121
// consumed from the server.
122
bufcount = bufpos + n;
123     pos += n;
124     }
125
126     /**
127      * Reads the next byte of data from this buffered input stream.
128      * If no byte is available, the value <code>-1</code> is returned.
129      */

130     public synchronized int read() throws IOException {
131     if (bufpos >= bufcount) {
132         fill();
133         if (bufpos >= bufcount)
134         return -1; // EOF
135
}
136     return buf[bufpos++] & 0xff;
137     }
138
139     /**
140      * Reads up to <code>len</code> bytes of data from this
141      * input stream into the given buffer. <p>
142      *
143      * Returns the total number of bytes read into the buffer,
144      * or <code>-1</code> if there is no more data. <p>
145      *
146      * Note that this method mimics the "weird !" semantics of
147      * BufferedInputStream in that the number of bytes actually
148      * returned may be less that the requested value. So callers
149      * of this routine should be aware of this and must check
150      * the return value to insure that they have obtained the
151      * requisite number of bytes.
152      */

153     public synchronized int read(byte b[], int off, int len)
154         throws IOException {
155
156     int avail = bufcount - bufpos;
157     if (avail <= 0) {
158         fill();
159         avail = bufcount - bufpos;
160         if (avail <= 0)
161         return -1; // EOF
162
}
163     int cnt = (avail < len) ? avail : len;
164     System.arraycopy(buf, bufpos, b, off, cnt);
165     bufpos += cnt;
166     return cnt;
167     }
168
169     /**
170      * Reads up to <code>b.length</code> bytes of data from this input
171      * stream into an array of bytes. <p>
172      *
173      * Returns the total number of bytes read into the buffer, or
174      * <code>-1</code> is there is no more data. <p>
175      *
176      * Note that this method mimics the "weird !" semantics of
177      * BufferedInputStream in that the number of bytes actually
178      * returned may be less that the requested value. So callers
179      * of this routine should be aware of this and must check
180      * the return value to insure that they have obtained the
181      * requisite number of bytes.
182      */

183     public int read(byte b[]) throws IOException {
184     return read(b, 0, b.length);
185     }
186
187     /**
188      * Returns the number of bytes that can be read from this input
189      * stream without blocking.
190      */

191     public synchronized int available() throws IOException {
192     return (bufcount - bufpos);
193     }
194
195     /**
196      * Normally the SEEN flag will have been set by now, but if not,
197      * force it to be set (as long as the folder isn't open read-only
198      * and we're not peeking).
199      * And of course, if there's no folder (e.g., a nested message)
200      * don't do anything.
201      */

202     private void checkSeen() {
203     if (peek) // if we're peeking, don't set the SEEN flag
204
return;
205     try {
206         Folder f = msg.getFolder();
207         if (f != null && f.getMode() != Folder.READ_ONLY &&
208             !msg.isSet(Flags.Flag.SEEN))
209         msg.setFlag(Flags.Flag.SEEN, true);
210     } catch (MessagingException ex) {
211         // ignore it
212
}
213     }
214 }
215
Popular Tags