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