1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.email;
12
13 import org.mule.api.MuleException;
14 import org.mule.api.MuleMessage;
15 import org.mule.api.MuleRuntimeException;
16 import org.mule.api.construct.FlowConstruct;
17 import org.mule.api.endpoint.InboundEndpoint;
18 import org.mule.api.lifecycle.CreateException;
19 import org.mule.api.transport.Connector;
20 import org.mule.api.transport.ReceiveException;
21 import org.mule.transport.AbstractPollingMessageReceiver;
22 import org.mule.transport.email.i18n.EmailMessages;
23 import org.mule.util.FileUtils;
24 import org.mule.util.StringUtils;
25 import org.mule.util.UUID;
26
27 import java.io.File;
28 import java.io.FileOutputStream;
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.List;
32
33 import javax.mail.Address;
34 import javax.mail.Flags;
35 import javax.mail.Folder;
36 import javax.mail.Message;
37 import javax.mail.MessagingException;
38 import javax.mail.Store;
39 import javax.mail.event.MessageCountEvent;
40 import javax.mail.event.MessageCountListener;
41 import javax.mail.internet.InternetAddress;
42 import javax.mail.internet.MimeMessage;
43
44
45
46
47
48
49
50
51 public class RetrieveMessageReceiver extends AbstractPollingMessageReceiver implements MessageCountListener
52 {
53 private Folder folder = null;
54 private Folder moveToFolder = null;
55 private boolean backupEnabled;
56 private String backupFolder = null;
57
58 public RetrieveMessageReceiver(Connector connector,
59 FlowConstruct flowConstruct,
60 InboundEndpoint endpoint,
61 long checkFrequency,
62 boolean backupEnabled,
63 String backupFolder) throws CreateException
64 {
65 super(connector, flowConstruct, endpoint);
66 this.backupFolder = backupFolder;
67 this.backupEnabled = backupEnabled;
68 this.setFrequency(checkFrequency);
69 }
70
71 private AbstractRetrieveMailConnector castConnector()
72 {
73 return (AbstractRetrieveMailConnector) getConnector();
74 }
75
76 @Override
77 protected void doConnect() throws Exception
78 {
79 SessionDetails session = castConnector().getSessionDetails(endpoint);
80
81 Store store = session.newStore();
82 store.connect();
83 folder = store.getFolder(castConnector().getMailboxFolder());
84 if (castConnector().getMoveToFolder() != null)
85 {
86 moveToFolder = store.getFolder(castConnector().getMoveToFolder());
87 moveToFolder.open(Folder.READ_WRITE);
88 }
89
90
91 if (StringUtils.isEmpty(backupFolder))
92 {
93 this.backupFolder = connector.getMuleContext().getConfiguration().getWorkingDirectory()
94 + "/mail/" + folder.getName();
95 }
96
97 if (backupFolder != null && !this.backupFolder.endsWith(File.separator))
98 {
99 this.backupFolder += File.separator;
100 }
101 }
102
103 @Override
104 protected void doDisconnect() throws Exception
105 {
106
107 }
108
109 @Override
110 protected void doStop()
111 {
112 if (folder != null)
113 {
114 folder.removeMessageCountListener(this);
115 }
116 }
117
118 @Override
119 protected void doStart() throws MuleException
120 {
121 super.doStart();
122 folder.addMessageCountListener(this);
123 }
124
125 public void messagesAdded(MessageCountEvent event)
126 {
127 try
128 {
129 Message messages[] = event.getMessages();
130 List<Message> processedMessages = new ArrayList<Message>();
131 if (messages != null)
132 {
133 MuleMessage message = null;
134 for (int i = 0; i < messages.length; i++)
135 {
136 if (getLifecycleState().isStopping())
137 {
138 break;
139 }
140 processedMessages.add(messages[i]);
141 try
142 {
143 if (!messages[i].getFlags().contains(Flags.Flag.DELETED)
144 && !messages[i].getFlags().contains(Flags.Flag.SEEN))
145 {
146 MimeMessage mimeMessage = new MimeMessage((MimeMessage) messages[i]);
147 storeMessage(mimeMessage);
148 message = createMuleMessage(mimeMessage, endpoint.getEncoding());
149
150 if (castConnector().isDeleteReadMessages())
151 {
152
153 messages[i].setFlag(Flags.Flag.DELETED, true);
154 }
155 else
156 {
157 if (this.getEndpoint().getFilter() != null && this.getEndpoint().getFilter().accept(message))
158 {
159 Flags.Flag flag = castConnector().getDefaultProcessMessageAction();
160 if (flag != null)
161 {
162 messages[i].setFlag(flag, true);
163 }
164 }
165 else
166 {
167 messages[i].setFlag(Flags.Flag.SEEN, false);
168 }
169 }
170
171 routeMessage(message);
172 }
173 }
174 catch (MuleException e)
175 {
176 throw e;
177 }
178 catch (Exception e)
179 {
180 Exception forwarded;
181
182 if (message != null)
183 {
184 forwarded = new org.mule.api.MessagingException(EmailMessages.routingError(), message, e);
185 }
186 else
187 {
188 forwarded = new ReceiveException(endpoint, -1, e);
189 }
190 throw forwarded;
191 }
192 }
193
194 if (moveToFolder != null)
195 {
196 folder.copyMessages(processedMessages.toArray(new Message[processedMessages.size()]), moveToFolder);
197 }
198 }
199 }
200 catch (Exception e)
201 {
202
203 throw new MuleRuntimeException(e);
204 }
205 }
206
207 public void messagesRemoved(MessageCountEvent event)
208 {
209 if (logger.isDebugEnabled())
210 {
211 Message messages[] = event.getMessages();
212 for (int i = 0; i < messages.length; i++)
213 {
214 try
215 {
216 logger.debug("Message removed: " + messages[i].getSubject());
217 }
218 catch (MessagingException ignore)
219 {
220 logger.debug("ignoring exception: " + ignore.getMessage());
221 }
222 }
223 }
224 }
225
226
227 public Folder getFolder()
228 {
229 return folder;
230 }
231
232
233 public synchronized void setFolder(Folder folder)
234 {
235 if (folder == null)
236 {
237 throw new IllegalArgumentException("Mail folder cannot be null");
238 }
239 this.folder = folder;
240 synchronized (this.folder)
241 {
242 if (!this.folder.isOpen())
243 {
244 try
245 {
246 this.folder.open(Folder.READ_WRITE);
247 }
248 catch (MessagingException e)
249 {
250 logger.warn("Failed to open folder: " + folder.getFullName(), e);
251 }
252 }
253 }
254 }
255
256
257
258
259
260
261
262
263
264
265
266 protected void storeMessage(Message msg) throws IOException, MessagingException
267 {
268 if (backupEnabled)
269 {
270 String filename = msg.getFileName();
271 if (filename == null)
272 {
273 Address[] from = msg.getFrom();
274 if (from != null && from.length > 0)
275 {
276 filename = from[0] instanceof InternetAddress
277 ? ((InternetAddress) from[0]).getAddress()
278 : from[0].toString();
279 }
280 else
281 {
282 filename = "(no from address)";
283 }
284 filename += "[" + UUID.getUUID() + "]";
285 }
286 filename = FileUtils.prepareWinFilename(filename);
287 filename = backupFolder + filename + ".msg";
288 if (logger.isDebugEnabled())
289 {
290 logger.debug("Writing message to: " + filename);
291 }
292 File f = FileUtils.createFile(filename);
293 FileOutputStream fos = new FileOutputStream(f);
294 msg.writeTo(fos);
295 }
296 }
297
298 @Override
299 public synchronized void poll()
300 {
301 boolean done = false;
302 while (!done)
303 {
304 if (getLifecycleState().isStopping())
305 {
306 break;
307 }
308 try
309 {
310 try
311 {
312 if (!folder.isOpen())
313 {
314 folder.open(Folder.READ_WRITE);
315 }
316 }
317 catch (Exception e)
318 {
319 if (logger.isDebugEnabled())
320 {
321 logger.debug("ignoring exception: " + e.getMessage());
322 }
323 }
324
325 int count = folder.getMessageCount();
326 int batchSize = getBatchSize(count);
327 if (count > 0)
328 {
329 Message[] messages = folder.getMessages(1, batchSize);
330 MessageCountEvent event = new MessageCountEvent(folder, MessageCountEvent.ADDED, true,
331 messages);
332 messagesAdded(event);
333 }
334 else if (count == -1)
335 {
336 throw new MessagingException("Cannot monitor folder: " + folder.getFullName()
337 + " as folder is closed");
338 }
339 done = batchSize >= count;
340 }
341 catch (MessagingException e)
342 {
343 done = true;
344 getConnector().getMuleContext().getExceptionListener().handleException(e);
345 }
346 finally
347 {
348 try
349 {
350 folder.close(true);
351 }
352 catch (Exception e)
353 {
354 logger.error("Failed to close pop3 inbox: " + e.getMessage());
355 }
356 }
357 }
358 }
359
360
361 @Override
362 protected boolean pollOnPrimaryInstanceOnly()
363 {
364 return true;
365 }
366
367 @Override
368 protected void doDispose()
369 {
370 if (null != folder)
371 {
372 folder.removeMessageCountListener(this);
373 if (folder.isOpen())
374 {
375 try
376 {
377
378 folder.close(true);
379 }
380 catch (Exception e)
381 {
382 logger.debug("ignoring exception: " + e.getMessage(), e);
383 }
384 }
385 }
386 }
387
388 @Override
389 protected MuleMessage handleUnacceptedFilter(MuleMessage message)
390 {
391 super.handleUnacceptedFilter(message);
392 if (message.getPayload() instanceof Message)
393 {
394 Message msg = (Message) message.getPayload();
395 try
396 {
397 msg.setFlag(Flags.Flag.DELETED, endpoint.isDeleteUnacceptedMessages());
398 }
399 catch (MessagingException e)
400 {
401 logger.error("failed to set message deleted: " + e.getMessage(), e);
402 }
403 }
404 return message;
405 }
406 }