1 /**
2 *
3 * Copyright 2003-2005 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * 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.pop3;
19
20 import java.util.Vector;
21
22 import javax.mail.FetchProfile;
23 import javax.mail.Flags;
24 import javax.mail.Folder;
25 import javax.mail.Message;
26 import javax.mail.MessagingException;
27 import javax.mail.MethodNotSupportedException;
28 import javax.mail.Session;
29 import javax.mail.Store;
30 import javax.mail.URLName;
31 import javax.mail.event.ConnectionEvent;
32
33 import org.apache.geronimo.javamail.store.pop3.message.POP3Message;
34 import org.apache.geronimo.javamail.store.pop3.message.POP3MessageFactory;
35 import org.apache.geronimo.javamail.store.pop3.response.POP3ResponseFactory;
36 import org.apache.geronimo.javamail.store.pop3.response.POP3StatusResponse;
37
38 /**
39 * The POP3 implementation of the javax.mail.Folder Note that only INBOX is
40 * supported in POP3
41 * <p>
42 * <url>http://www.faqs.org/rfcs/rfc1939.html</url>
43 * </p>
44 *
45 * @see javax.mail.Folder
46 *
47 * @version $Rev: 432884 $ $Date: 2006-08-19 14:53:20 -0700 (Sat, 19 Aug 2006) $
48 */
49 public class POP3Folder extends Folder {
50
51 private boolean isFolderOpen = false;
52
53 private int mode;
54
55 private POP3Connection pop3Con;
56
57 private int msgCount;
58
59 private Session session;
60
61 /**
62 * Vector is synchronized so choose over the other Collection impls This is
63 * initialized on open A chache will save the expensive operation of
64 * retrieving the message again from the server.
65 */
66 private Vector msgCache;
67
68 protected POP3Folder(Store store, URLName url) {
69 super(store);
70 }
71
72 protected POP3Folder(Store store, Session session, POP3Connection pop3Con) {
73 super(store);
74 this.pop3Con = pop3Con;
75 this.session = session;
76 }
77
78 public String getName() {
79 return "INBOX";
80 }
81
82 public String getFullName() {
83 return "INBOX";
84 }
85
86 /**
87 * Never return "this" as the parent folder. Somebody not familliar with
88 * POP3 may do something like while(getParent() != null) or something
89 * simmilar which will result in an infinte loop
90 */
91 public Folder getParent() throws MessagingException {
92 throw new MethodNotSupportedException("INBOX is the root folder");
93 }
94
95 public boolean exists() throws MessagingException {
96
97 return true;
98 }
99
100 public Folder[] list(String pattern) throws MessagingException {
101 throw new MethodNotSupportedException("Only INBOX is supported in POP3, no sub folders");
102 }
103
104 /**
105 * No sub folders, hence there is no notion of a seperator
106 */
107 public char getSeparator() throws MessagingException {
108 throw new MethodNotSupportedException("Only INBOX is supported in POP3, no sub folders");
109 }
110
111 public int getType() throws MessagingException {
112 return HOLDS_MESSAGES;
113 }
114
115 public boolean create(int type) throws MessagingException {
116 throw new MethodNotSupportedException("Only INBOX is supported in POP3, no sub folders");
117 }
118
119 public boolean hasNewMessages() throws MessagingException {
120 throw new MethodNotSupportedException("POP3 doesn't support this operation");
121 }
122
123 public Folder getFolder(String name) throws MessagingException {
124 throw new MethodNotSupportedException("Only INBOX is supported in POP3, no sub folders");
125 }
126
127 public boolean delete(boolean recurse) throws MessagingException {
128 throw new MethodNotSupportedException("Only INBOX is supported in POP3 and INBOX cannot be deleted");
129 }
130
131 public boolean renameTo(Folder f) throws MessagingException {
132 throw new MethodNotSupportedException("Only INBOX is supported in POP3 and INBOX cannot be renamed");
133 }
134
135 /**
136 * @see javax.mail.Folder#open(int)
137 */
138 public void open(int mode) throws MessagingException {
139
140 checkClosed();
141
142 try {
143
144 POP3StatusResponse res = (POP3StatusResponse) POP3ResponseFactory.getStatusResponse(pop3Con
145 .sendCommand(POP3CommandFactory.getCOMMAND_STAT()));
146
147
148
149
150 this.mode = mode;
151 this.isFolderOpen = true;
152 this.msgCount = res.getNumMessages();
153
154
155
156 msgCache = new Vector(msgCount);
157 msgCache.setSize(msgCount);
158
159 } catch (Exception e) {
160 throw new MessagingException("Unable to execute STAT command", e);
161 }
162
163 notifyConnectionListeners(ConnectionEvent.OPENED);
164 }
165
166 public void close(boolean expunge) throws MessagingException {
167
168 checkOpen();
169
170 try {
171 if (mode == READ_WRITE) {
172
173 POP3Message m;
174 for (int i = 0; i < msgCache.size(); i++) {
175 if ((m = (POP3Message) msgCache.elementAt(i)) != null) {
176 if (m.isSet(Flags.Flag.DELETED)) {
177 try {
178 pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_DELE(i + 1));
179 } catch (Exception e) {
180 throw new MessagingException("Exception deleting message no [" + (i + 1)
181 + "] during close", e);
182 }
183 }
184 }
185 }
186 }
187
188 try {
189 pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_QUIT());
190 } catch (Exception e) {
191
192 }
193
194
195
196 } finally {
197 try {
198 pop3Con.close();
199 } catch (Exception e) {
200
201
202 pop3Con = null;
203 }
204
205
206
207
208
209 msgCache = null;
210 isFolderOpen = false;
211 notifyConnectionListeners(ConnectionEvent.CLOSED);
212 }
213 }
214
215 public boolean isOpen() {
216 return isFolderOpen;
217 }
218
219 public Flags getPermanentFlags() {
220
221
222
223
224
225
226
227 return new Flags();
228 }
229
230 public int getMessageCount() throws MessagingException {
231 return msgCount;
232 }
233
234 /**
235 * Checks wether the message is in cache, if not will create a new message
236 * object and return it.
237 *
238 * @see javax.mail.Folder#getMessage(int)
239 */
240 public Message getMessage(int msgNum) throws MessagingException {
241
242 checkOpen();
243 if (msgNum < 1 || msgNum > getMessageCount()) {
244 throw new MessagingException("Invalid Message number");
245 }
246
247 Message msg = null;
248 try {
249 msg = (Message) msgCache.elementAt(msgNum);
250 } catch (RuntimeException e) {
251 session.getDebugOut().println("Message not in cache");
252 }
253 if (msg == null) {
254 msg = POP3MessageFactory.createMessage(this, session, pop3Con, msgNum);
255 msgCache.setElementAt(msg, msgNum);
256 }
257
258 return msg;
259 }
260
261 public void appendMessages(Message[] msgs) throws MessagingException {
262 throw new MethodNotSupportedException("Message appending is not supported in POP3");
263
264 }
265
266 public Message[] expunge() throws MessagingException {
267 throw new MethodNotSupportedException("Expunge is not supported in POP3");
268 }
269
270 public int getMode() throws IllegalStateException {
271
272 checkOpen();
273 return mode;
274 }
275
276 /**
277 * @see javax.mail.Folder#fetch(javax.mail.Message[],
278 * javax.mail.FetchProfile)
279 *
280 * The JavaMail API recommends that this method be overrident to provide a
281 * meaningfull implementation.
282 */
283 public void fetch(Message[] msgs, FetchProfile fp) throws MessagingException {
284
285 checkOpen();
286 for (int i = 0; i < msgs.length; i++) {
287 Message msg = msgs[i];
288 if (msg == null) {
289 msg = POP3MessageFactory.createMessage(this, session, pop3Con, i);
290 }
291 if (fp.contains(FetchProfile.Item.ENVELOPE)) {
292 msg = POP3MessageFactory.createMessageWithEvelope((POP3Message) msg);
293 }
294
295 if (fp.contains(FetchProfile.Item.CONTENT_INFO)) {
296 msg = POP3MessageFactory.createMessageWithContentInfo((POP3Message) msg);
297 }
298
299 if (fp.contains(FetchProfile.Item.FLAGS)) {
300 msg = POP3MessageFactory.createMessageWithFlags((POP3Message) msg);
301 }
302
303 msgs[i] = msg;
304 }
305 }
306
307 /**
308 * Below is a list of covinience methods that avoid repeated checking for a
309 * value and throwing an exception
310 */
311
312 /** Ensure the folder is open */
313 private void checkOpen() throws IllegalStateException {
314 if (!isFolderOpen) {
315 throw new IllegalStateException("Folder is not Open");
316 }
317 }
318
319 /** Ensure the folder is not open */
320 private void checkClosed() throws IllegalStateException {
321 if (isFolderOpen) {
322 throw new IllegalStateException("Folder is Open");
323 }
324 }
325
326 /**
327 * @see javax.mail.Folder#notifyMessageChangedListeners(int,
328 * javax.mail.Message)
329 *
330 * this method is protected and cannot be used outside of Folder, therefore
331 * had to explicitly expose it via a method in POP3Folder, so that
332 * POP3Message has access to it
333 *
334 * Bad design on the part of the Java Mail API.
335 */
336 public void notifyMessageChangedListeners(int type, Message m) {
337 super.notifyMessageChangedListeners(type, m);
338 }
339
340 }