KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > mail > pop3 > POP3Folder


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  * @(#)POP3Folder.java 1.31 05/08/29
24  *
25  * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package com.sun.mail.pop3;
29
30 import javax.mail.*;
31 import javax.mail.internet.*;
32 import javax.mail.event.*;
33 import java.io.InputStream JavaDoc;
34 import java.io.BufferedInputStream JavaDoc;
35 import java.io.ByteArrayInputStream JavaDoc;
36 import java.io.IOException JavaDoc;
37 import java.io.EOFException JavaDoc;
38 import java.util.Vector JavaDoc;
39 import java.util.StringTokenizer JavaDoc;
40 import java.lang.reflect.Constructor JavaDoc;
41
42 import com.sun.mail.util.LineInputStream;
43
44 /**
45  * A POP3 Folder (can only be "INBOX").
46  *
47  * See the <a HREF="package-summary.html">com.sun.mail.pop3</a> package
48  * documentation for further information on the POP3 protocol provider. <p>
49  *
50  * @author Bill Shannon
51  * @author John Mani (ported to the javax.mail APIs)
52  */

53 public class POP3Folder extends Folder {
54
55     private String JavaDoc name;
56     private Protocol port;
57     private int total;
58     private int size;
59     private boolean exists = false;
60     private boolean opened = false;
61     private Vector JavaDoc message_cache;
62     private boolean doneUidl = false;
63
64     POP3Folder(POP3Store store, String JavaDoc name) {
65     super(store);
66     this.name = name;
67     if (name.equalsIgnoreCase("INBOX"))
68         exists = true;
69     }
70
71     public String JavaDoc getName() {
72     return name;
73     }
74
75     public String JavaDoc getFullName() {
76     return name;
77     }
78
79     public Folder getParent() {
80     return new DefaultFolder((POP3Store)store);
81     }
82
83     /**
84      * Always true for the folder "INBOX", always false for
85      * any other name.
86      *
87      * @return true for INBOX, false otherwise
88      */

89     public boolean exists() {
90     return exists;
91     }
92
93     /**
94      * Always throws <code>MessagingException</code> because no POP3 folders
95      * can contain subfolders.
96      *
97      * @exception MessagingException always
98      */

99     public Folder[] list(String JavaDoc pattern) throws MessagingException {
100     throw new MessagingException("not a directory");
101     }
102
103     /**
104      * Always returns a NUL character because POP3 doesn't support a hierarchy.
105      *
106      * @return NUL
107      */

108     public char getSeparator() {
109     return '\0';
110     }
111
112     /**
113      * Always returns Folder.HOLDS_MESSAGES.
114      *
115      * @return Folder.HOLDS_MESSAGES
116      */

117     public int getType() {
118     return HOLDS_MESSAGES;
119     }
120
121     /**
122      * Always returns <code>false</code>; the POP3 protocol doesn't
123      * support creating folders.
124      *
125      * @return false
126      */

127     public boolean create(int type) throws MessagingException {
128     return false;
129     }
130
131     /**
132      * Always returns <code>false</code>; the POP3 protocol provides
133      * no way to determine when a new message arrives.
134      *
135      * @return false
136      */

137     public boolean hasNewMessages() throws MessagingException {
138     return false; // no way to know
139
}
140
141     /**
142      * Always throws <code>MessagingException</code> because no POP3 folders
143      * can contain subfolders.
144      *
145      * @exception MessagingException always
146      */

147     public Folder getFolder(String JavaDoc name) throws MessagingException {
148     throw new MessagingException("not a directory");
149     }
150
151     /**
152      * Always throws <code>MethodNotSupportedException</code>
153      * because the POP3 protocol doesn't allow the INBOX to
154      * be deleted.
155      *
156      * @exception MethodNotSupportedException always
157      */

158     public boolean delete(boolean recurse) throws MessagingException {
159     throw new MethodNotSupportedException("delete");
160     }
161
162     /**
163      * Always throws <code>MethodNotSupportedException</code>
164      * because the POP3 protocol doesn't support multiple folders.
165      *
166      * @exception MethodNotSupportedException always
167      */

168     public boolean renameTo(Folder f) throws MessagingException {
169     throw new MethodNotSupportedException("renameTo");
170     }
171
172     /**
173      * Throws <code>FolderNotFoundException</code> unless this
174      * folder is named "INBOX".
175      *
176      * @exception FolderNotFoundException if not INBOX
177      * @exception AuthenticationException authentication failures
178      * @exception MessagingException other open failures
179      */

180     public synchronized void open(int mode) throws MessagingException {
181     checkClosed();
182     if (!exists)
183         throw new FolderNotFoundException(this, "folder is not INBOX");
184
185     try {
186         port = ((POP3Store)store).getPort(this);
187         Status s = port.stat();
188         total = s.total;
189         size = s.size;
190         this.mode = mode;
191         opened = true;
192     } catch (IOException JavaDoc ioex) {
193         try {
194         if (port != null)
195             port.quit();
196         } catch (IOException JavaDoc ioex2) {
197         // ignore
198
} finally {
199         port = null;
200         ((POP3Store)store).closePort(this);
201         }
202         throw new MessagingException("Open failed", ioex);
203     }
204
205     // Create the message cache vector of appropriate size
206
message_cache = new Vector JavaDoc(total);
207     message_cache.setSize(total);
208     doneUidl = false;
209
210     notifyConnectionListeners(ConnectionEvent.OPENED);
211     }
212
213     public synchronized void close(boolean expunge) throws MessagingException {
214     checkOpen();
215
216     try {
217         /*
218          * Some POP3 servers will mark messages for deletion when
219          * they're read. To prevent such messages from being
220          * deleted before the client deletes them, you can set
221          * the mail.pop3.rsetbeforequit property to true. This
222          * causes us to issue a POP3 RSET command to clear all
223          * the "marked for deletion" flags. We can then explicitly
224          * delete messages as desired.
225          */

226         if (((POP3Store)store).rsetBeforeQuit)
227         port.rset();
228         if (expunge && mode == READ_WRITE) {
229         // find all messages marked deleted and issue DELE commands
230
POP3Message m;
231         for (int i = 0; i < message_cache.size(); i++) {
232             if ((m = (POP3Message)message_cache.elementAt(i)) != null) {
233             if (m.isSet(Flags.Flag.DELETED))
234                 try {
235                 port.dele(i + 1);
236                 } catch (IOException JavaDoc ioex) {
237                 throw new MessagingException(
238                     "Exception deleting messages during close",
239                     ioex);
240                 }
241             }
242         }
243         }
244
245         port.quit();
246     } catch (IOException JavaDoc ex) {
247         // do nothing
248
} finally {
249         port = null;
250         ((POP3Store)store).closePort(this);
251         message_cache = null;
252         opened = false;
253         notifyConnectionListeners(ConnectionEvent.CLOSED);
254     }
255     }
256
257     public boolean isOpen() {
258     if (!opened)
259         return false;
260     if (store.isConnected())
261         return true;
262     try {
263         close(false);
264     } catch (MessagingException ex) { }
265     return false;
266     }
267
268     /**
269      * Always returns an empty <code>Flags</code> object because
270      * the POP3 protocol doesn't support any permanent flags.
271      *
272      * @return empty Flags object
273      */

274     public Flags getPermanentFlags() {
275     return new Flags(); // empty flags object
276
}
277
278     /**
279      * Will not change while the folder is open because the POP3
280      * protocol doesn't support notification of new messages
281      * arriving in open folders.
282      */

283     public int getMessageCount() throws MessagingException {
284     if (!opened)
285         return -1;
286     checkReadable();
287     return total;
288     }
289
290     public synchronized Message getMessage(int msgno)
291                     throws MessagingException {
292     checkOpen();
293
294     POP3Message m;
295
296     // Assuming that msgno is <= total
297
if ((m = (POP3Message)message_cache.elementAt(msgno-1)) == null) {
298         m = createMessage(this, msgno);
299         message_cache.setElementAt(m, msgno-1);
300     }
301     return m;
302     }
303
304     protected POP3Message createMessage(Folder f, int msgno)
305                 throws MessagingException {
306     POP3Message m = null;
307     Constructor JavaDoc cons = ((POP3Store)store).messageConstructor;
308     if (cons != null) {
309         try {
310         Object JavaDoc[] o = { this, new Integer JavaDoc(msgno) };
311         m = (POP3Message)cons.newInstance(o);
312         } catch (Exception JavaDoc ex) {
313         // ignore
314
}
315     }
316     if (m == null)
317         m = new POP3Message(this, msgno);
318     return m;
319     }
320
321     /**
322      * Always throws <code>MethodNotSupportedException</code>
323      * because the POP3 protocol doesn't support appending messages.
324      *
325      * @exception MethodNotSupportedException always
326      */

327     public void appendMessages(Message[] msgs) throws MessagingException {
328     throw new MethodNotSupportedException("Append not supported");
329     }
330
331     /**
332      * Always throws <code>MethodNotSupportedException</code>
333      * because the POP3 protocol doesn't support expunging messages
334      * without closing the folder; call the {@link #close close} method
335      * with the <code>expunge</code> argument set to <code>true</code>
336      * instead.
337      *
338      * @exception MethodNotSupportedException always
339      */

340     public Message[] expunge() throws MessagingException {
341     throw new MethodNotSupportedException("Expunge not supported");
342     }
343
344     /**
345      * Prefetch information about POP3 messages.
346      * If the FetchProfile contains <code>UIDFolder.FetchProfileItem.UID</code>,
347      * POP3 UIDs for all messages in the folder are fetched using the POP3
348      * UIDL command.
349      * If the FetchProfile contains <code>FetchProfile.Item.ENVELOPE</code>,
350      * the headers and size of all messages are fetched using the POP3 TOP
351      * and LIST commands.
352      */

353     public synchronized void fetch(Message[] msgs, FetchProfile fp)
354                 throws MessagingException {
355     checkReadable();
356     if (!doneUidl && fp.contains(UIDFolder.FetchProfileItem.UID)) {
357         /*
358          * Since the POP3 protocol only lets us fetch the UID
359          * for a single message or for all messages, we go ahead
360          * and fetch UIDs for all messages here, ignoring the msgs
361          * parameter. We could be more intelligent and base this
362          * decision on the number of messages fetched, or the
363          * percentage of the total number of messages fetched.
364          */

365         String JavaDoc[] uids = new String JavaDoc[message_cache.size()];
366         try {
367         if (!port.uidl(uids))
368             return;
369         } catch (EOFException JavaDoc eex) {
370         close(false);
371         throw new FolderClosedException(this, eex.toString());
372         } catch (IOException JavaDoc ex) {
373         throw new MessagingException("error getting UIDL", ex);
374         }
375         for (int i = 0; i < uids.length; i++) {
376         if (uids[i] == null)
377             continue;
378         POP3Message m = (POP3Message)getMessage(i + 1);
379         m.uid = uids[i];
380         }
381         doneUidl = true; // only do this once
382
}
383     if (fp.contains(FetchProfile.Item.ENVELOPE)) {
384         for (int i = 0; i < msgs.length; i++) {
385         try {
386             POP3Message msg = (POP3Message)msgs[i];
387             // fetch headers
388
msg.getHeader("");
389             // fetch message size
390
msg.getSize();
391         } catch (MessageRemovedException mex) {
392             // should never happen, but ignore it if it does
393
}
394         }
395     }
396     }
397
398     /**
399      * Return the unique ID string for this message, or null if
400      * not available. Uses the POP3 UIDL command.
401      *
402      * @return unique ID string
403      * @exception MessagingException
404      */

405     public synchronized String JavaDoc getUID(Message msg) throws MessagingException {
406     checkOpen();
407     POP3Message m = (POP3Message)msg;
408     try {
409         if (m.uid == POP3Message.UNKNOWN)
410         m.uid = port.uidl(m.getMessageNumber());
411         return m.uid;
412     } catch (EOFException JavaDoc eex) {
413         close(false);
414         throw new FolderClosedException(this, eex.toString());
415     } catch (IOException JavaDoc ex) {
416         throw new MessagingException("error getting UIDL", ex);
417     }
418     }
419
420     /**
421      * Return the size of this folder, as was returned by the POP3 STAT
422      * command when this folder was opened.
423      *
424      * @return folder size
425      * @exception IllegalStateException if the folder isn't open
426      */

427     public int getSize() throws MessagingException {
428     checkOpen();
429     return size;
430     }
431
432     /**
433      * Return the sizes of all messages in this folder, as returned
434      * by the POP3 LIST command. Each entry in the array corresponds
435      * to a message; entry <i>i</i> corresponds to message number <i>i+1</i>.
436      *
437      * @return array of message sizes
438      * @exception IllegalStateException if the folder isn't open
439      * @since JavaMail 1.3.3
440      */

441     public synchronized int[] getSizes() throws MessagingException {
442     checkOpen();
443     int sizes[] = new int[total];
444     InputStream JavaDoc is = null;
445     LineInputStream lis = null;
446     try {
447         is = port.list();
448         lis = new LineInputStream(is);
449         String JavaDoc line;
450         while ((line = lis.readLine()) != null) {
451         try {
452             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(line);
453             int msgnum = Integer.parseInt(st.nextToken());
454             int size = Integer.parseInt(st.nextToken());
455             if (msgnum > 0 && msgnum <= total)
456             sizes[msgnum - 1] = size;
457         } catch (Exception JavaDoc e) {
458         }
459         }
460     } catch (IOException JavaDoc ex) {
461         // ignore it?
462
} finally {
463         try {
464         if (lis != null)
465             lis.close();
466         } catch (IOException JavaDoc cex) { }
467         try {
468         if (is != null)
469             is.close();
470         } catch (IOException JavaDoc cex) { }
471     }
472     return sizes;
473     }
474
475     /**
476      * Return the raw results of the POP3 LIST command with no arguments.
477      *
478      * @return InputStream containing results
479      * @exception IllegalStateException if the folder isn't open
480      * @since JavaMail 1.3.3
481      */

482     public synchronized InputStream JavaDoc listCommand()
483                 throws MessagingException, IOException JavaDoc {
484     checkOpen();
485     return port.list();
486     }
487
488     /**
489      * Close the folder when we're finalized.
490      */

491     protected void finalize() throws Throwable JavaDoc {
492     super.finalize();
493     close(false);
494     }
495
496     /* Ensure the folder is open */
497     void checkOpen() throws IllegalStateException JavaDoc {
498     if (!opened)
499         throw new IllegalStateException JavaDoc("Folder is not Open");
500     }
501
502     /* Ensure the folder is not open */
503     void checkClosed() throws IllegalStateException JavaDoc {
504     if (opened)
505         throw new IllegalStateException JavaDoc("Folder is Open");
506     }
507
508     /* Ensure the folder is open & readable */
509     void checkReadable() throws IllegalStateException JavaDoc {
510     if (!opened || (mode != READ_ONLY && mode != READ_WRITE))
511         throw new IllegalStateException JavaDoc("Folder is not Readable");
512     }
513
514     /* Ensure the folder is open & writable */
515     void checkWritable() throws IllegalStateException JavaDoc {
516     if (!opened || mode != READ_WRITE)
517         throw new IllegalStateException JavaDoc("Folder is not Writable");
518     }
519
520     /**
521      * Centralize access to the Protocol object by POP3Message
522      * objects so that they will fail appropriately when the folder
523      * is closed.
524      */

525     Protocol getProtocol() throws MessagingException {
526     checkOpen();
527     return port;
528     }
529
530     /*
531      * Only here to make accessible to POP3Message.
532      */

533     protected void notifyMessageChangedListeners(int type, Message m) {
534     super.notifyMessageChangedListeners(type, m);
535     }
536 }
537
Popular Tags