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