1 /************************************************************************
2 * Copyright (c) 2003-2006 The Apache Software Foundation. *
3 * All rights reserved. *
4 * ------------------------------------------------------------------- *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you *
6 * may not use this file except in compliance with the License. You *
7 * 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 *
14 * implied. See the License for the specific language governing *
15 * permissions and limitations under the License. *
16 ***********************************************************************/
17
18 package org.apache.james.fetchmail;
19
20 import javax.mail.FetchProfile;
21 import javax.mail.Flags;
22 import javax.mail.Folder;
23 import javax.mail.Message;
24 import javax.mail.MessagingException;
25 import javax.mail.internet.MimeMessage;
26
27 /***
28 * <p>Class <code>FolderProcessor</code> opens a Folder and iterates over all
29 * of the Messages, delegating their processing to
30 * <code>MessageProcessor</code>.</p>
31 *
32 * <p>If isRecurse(), all subfolders are fetched recursively.</p>
33 *
34 * <p>Creation Date: 25-May-03</p>
35 *
36 */
37 public class FolderProcessor extends ProcessorAbstract
38 {
39 /***
40 * The fetched folder
41 */
42 private Folder fieldFolder;
43
44 private Boolean fieldMarkSeenPermanent;
45
46 /***
47 * Constructor for FolderProcessor.
48 * @param folder The folder to be fetched
49 * @param account The account being processed
50 */
51 protected FolderProcessor(Folder folder, Account account)
52 {
53 super(account);
54 setFolder(folder);
55 }
56
57 /***
58 * Method process opens a Folder, fetches the Envelopes for all of its
59 * Messages, creates a <code>MessageProcessor</code> and runs it to process
60 * each message.
61 *
62 * @see org.apache.james.fetchmail.ProcessorAbstract#process()
63 */
64 public void process() throws MessagingException
65 {
66 int messagesProcessed = 0;
67 int messageCount = 0;
68 try
69 {
70
71 try
72 {
73 open();
74 }
75 catch (MessagingException ex)
76 {
77 getLogger().error(
78 getFetchTaskName() + " Failed to open folder!");
79 throw ex;
80 }
81
82
83 synchronized (getFolder())
84 {
85 messageCount = getFolder().getMessageCount();
86 for (int i = 1; i <= messageCount; i++)
87 {
88 MimeMessage message =
89 (MimeMessage) getFolder().getMessage(i);
90 if (isFetchAll() || !isSeen(message))
91 {
92 try
93 {
94 new MessageProcessor(message, getAccount())
95 .process();
96 messagesProcessed++;
97 }
98
99
100 catch (Exception ex)
101 {
102 StringBuffer logMessageBuffer =
103 new StringBuffer("Exception processing message ID: ");
104 logMessageBuffer.append(message.getMessageID());
105 getLogger().error(logMessageBuffer.toString(), ex);
106 }
107 }
108 }
109 }
110 }
111 catch (MessagingException mex)
112 {
113 getLogger().error(
114 "A MessagingException has terminated fetching messages for this folder",
115 mex);
116 }
117 finally
118 {
119
120 try
121 {
122 close();
123 }
124 catch (MessagingException ex)
125 {
126
127 }
128 StringBuffer logMessageBuffer = new StringBuffer("Processed ");
129 logMessageBuffer.append(messagesProcessed);
130 logMessageBuffer.append(" messages of ");
131 logMessageBuffer.append(messageCount);
132 logMessageBuffer.append(" in folder '");
133 logMessageBuffer.append(getFolder().getName());
134 logMessageBuffer.append("'");
135 getLogger().info(logMessageBuffer.toString());
136 }
137
138
139 try
140 {
141 if (isRecurse())
142 recurse();
143 }
144 catch (MessagingException mex)
145 {
146 getLogger().error(
147 "A MessagingException has terminated recursing through sub-folders",
148 mex);
149 }
150
151 return;
152 }
153
154 /***
155 * Method close.
156 * @throws MessagingException
157 */
158 protected void close() throws MessagingException
159 {
160 if (null != getFolder() && getFolder().isOpen())
161 getFolder().close(true);
162 }
163
164 /***
165 * Method recurse.
166 * @throws MessagingException
167 */
168 protected void recurse() throws MessagingException
169 {
170 if ((getFolder().getType() & Folder.HOLDS_FOLDERS)
171 == Folder.HOLDS_FOLDERS)
172 {
173
174 Folder folders[] = getFolder().list();
175
176 for (int i = 0; i < folders.length; i++)
177 {
178 new FolderProcessor(folders[i], getAccount()).process();
179 }
180
181 }
182 }
183
184 /***
185 * Method open.
186 * @throws MessagingException
187 */
188 protected void open() throws MessagingException
189 {
190 int openFlag = Folder.READ_WRITE;
191
192 if (isOpenReadOnly())
193 openFlag = Folder.READ_ONLY;
194
195 getFolder().open(openFlag);
196 }
197
198 /***
199 * Returns the folder.
200 * @return Folder
201 */
202 protected Folder getFolder()
203 {
204 return fieldFolder;
205 }
206
207 /***
208 * Answer if <code>aMessage</code> has been SEEN.
209 * @param aMessage
210 * @return boolean
211 * @throws MessagingException
212 */
213 protected boolean isSeen(MimeMessage aMessage) throws MessagingException
214 {
215 boolean isSeen = false;
216 if (isMarkSeenPermanent().booleanValue())
217 isSeen = aMessage.isSet(Flags.Flag.SEEN);
218 else
219 isSeen = handleMarkSeenNotPermanent(aMessage);
220 return isSeen;
221 }
222
223 /***
224 * Answer the result of computing markSeenPermanent.
225 * @return Boolean
226 */
227 protected Boolean computeMarkSeenPermanent()
228 {
229 return new Boolean(
230 getFolder().getPermanentFlags().contains(Flags.Flag.SEEN));
231 }
232
233 /***
234 * <p>Handler for when the folder does not support the SEEN flag.
235 * The default behaviour implemented here is to answer the value of the
236 * SEEN flag anyway.</p>
237 *
238 * <p>Subclasses may choose to override this method and implement their own
239 * solutions.</p>
240 *
241 * @param aMessage
242 * @return boolean
243 * @throws MessagingException
244 */
245 protected boolean handleMarkSeenNotPermanent(MimeMessage aMessage)
246 throws MessagingException
247 {
248 return aMessage.isSet(Flags.Flag.SEEN);
249 }
250
251 /***
252 * Sets the folder.
253 * @param folder The folder to set
254 */
255 protected void setFolder(Folder folder)
256 {
257 fieldFolder = folder;
258 }
259
260 /***
261 * Returns the isMarkSeenPermanent.
262 * @return Boolean
263 */
264 protected Boolean isMarkSeenPermanent()
265 {
266 Boolean markSeenPermanent = null;
267 if (null == (markSeenPermanent = isMarkSeenPermanentBasic()))
268 {
269 updateMarkSeenPermanent();
270 return isMarkSeenPermanent();
271 }
272 return markSeenPermanent;
273 }
274
275 /***
276 * Returns the markSeenPermanent.
277 * @return Boolean
278 */
279 private Boolean isMarkSeenPermanentBasic()
280 {
281 return fieldMarkSeenPermanent;
282 }
283
284 /***
285 * Sets the markSeenPermanent.
286 * @param markSeenPermanent The isMarkSeenPermanent to set
287 */
288 protected void setMarkSeenPermanent(Boolean markSeenPermanent)
289 {
290 fieldMarkSeenPermanent = markSeenPermanent;
291 }
292
293 /***
294 * Updates the markSeenPermanent.
295 */
296 protected void updateMarkSeenPermanent()
297 {
298 setMarkSeenPermanent(computeMarkSeenPermanent());
299 }
300
301 }