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.construct.FlowConstruct;
16 import org.mule.api.endpoint.InboundEndpoint;
17 import org.mule.api.lifecycle.CreateException;
18 import org.mule.api.transport.Connector;
19 import org.mule.api.transport.ReceiveException;
20 import org.mule.transport.AbstractPollingMessageReceiver;
21 import org.mule.transport.email.i18n.EmailMessages;
22 import org.mule.util.FileUtils;
23 import org.mule.util.StringUtils;
24 import org.mule.util.UUID;
25
26 import java.io.File;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29
30 import javax.mail.Address;
31 import javax.mail.Flags;
32 import javax.mail.Folder;
33 import javax.mail.Message;
34 import javax.mail.MessagingException;
35 import javax.mail.Store;
36 import javax.mail.event.MessageCountEvent;
37 import javax.mail.event.MessageCountListener;
38 import javax.mail.internet.InternetAddress;
39 import javax.mail.internet.MimeMessage;
40
41
42
43
44
45
46
47
48 public class RetrieveMessageReceiver extends AbstractPollingMessageReceiver implements MessageCountListener
49 {
50 private Folder folder = null;
51 private Folder moveToFolder = null;
52 private boolean backupEnabled;
53 private String backupFolder = null;
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 if (folder != null)
110 {
111 folder.removeMessageCountListener(this);
112 }
113 }
114
115 @Override
116 protected void doStart() throws MuleException
117 {
118 super.doStart();
119 folder.addMessageCountListener(this);
120 }
121
122 public void messagesAdded(MessageCountEvent event)
123 {
124 Message messages[] = event.getMessages();
125 if (messages != null)
126 {
127 MuleMessage message = null;
128 for (int i = 0; i < messages.length; i++)
129 {
130 try
131 {
132 if (!messages[i].getFlags().contains(Flags.Flag.DELETED)
133 && !messages[i].getFlags().contains(Flags.Flag.SEEN))
134 {
135 MimeMessage mimeMessage = new MimeMessage((MimeMessage) messages[i]);
136 storeMessage(mimeMessage);
137 message = createMuleMessage(mimeMessage, endpoint.getEncoding());
138
139 if (castConnector().isDeleteReadMessages())
140 {
141
142 messages[i].setFlag(Flags.Flag.DELETED, true);
143 }
144 else
145 {
146 if (this.getEndpoint().getFilter().accept(message))
147 {
148 Flags.Flag flag = castConnector().getDefaultProcessMessageAction();
149 if (flag != null)
150 {
151 messages[i].setFlag(flag, true);
152 }
153 }
154 else
155 {
156 messages[i].setFlag(Flags.Flag.SEEN, false);
157 }
158 }
159
160 routeMessage(message);
161 }
162 }
163 catch (MuleException e)
164 {
165 getConnector().getMuleContext().getExceptionListener().handleException(e);
166 }
167 catch (Exception e)
168 {
169 Exception forwarded;
170
171 if (message != null)
172 {
173 forwarded = new org.mule.api.MessagingException(EmailMessages.routingError(), message, e);
174 }
175 else
176 {
177 forwarded = new ReceiveException(endpoint, -1, e);
178 }
179
180 getConnector().getMuleContext().getExceptionListener().handleException(forwarded);
181 }
182 }
183
184 if (moveToFolder != null)
185 {
186 try
187 {
188 folder.copyMessages(messages, moveToFolder);
189 }
190 catch (MessagingException e)
191 {
192 getConnector().getMuleContext().getExceptionListener().handleException(e);
193 }
194 }
195 }
196 }
197
198 public void messagesRemoved(MessageCountEvent event)
199 {
200 if (logger.isDebugEnabled())
201 {
202 Message messages[] = event.getMessages();
203 for (int i = 0; i < messages.length; i++)
204 {
205 try
206 {
207 logger.debug("Message removed: " + messages[i].getSubject());
208 }
209 catch (MessagingException ignore)
210 {
211 logger.debug("ignoring exception: " + ignore.getMessage());
212 }
213 }
214 }
215 }
216
217
218 public Folder getFolder()
219 {
220 return folder;
221 }
222
223
224 public synchronized void setFolder(Folder folder)
225 {
226 if (folder == null)
227 {
228 throw new IllegalArgumentException("Mail folder cannot be null");
229 }
230 this.folder = folder;
231 synchronized (this.folder)
232 {
233 if (!this.folder.isOpen())
234 {
235 try
236 {
237 this.folder.open(Folder.READ_WRITE);
238 }
239 catch (MessagingException e)
240 {
241 logger.warn("Failed to open folder: " + folder.getFullName(), e);
242 }
243 }
244 }
245 }
246
247
248
249
250
251
252
253
254
255
256
257 protected void storeMessage(Message msg) throws IOException, MessagingException
258 {
259 if (backupEnabled)
260 {
261 String filename = msg.getFileName();
262 if (filename == null)
263 {
264 Address[] from = msg.getFrom();
265 if (from != null && from.length > 0)
266 {
267 filename = from[0] instanceof InternetAddress
268 ? ((InternetAddress) from[0]).getAddress()
269 : from[0].toString();
270 }
271 else
272 {
273 filename = "(no from address)";
274 }
275 filename += "[" + UUID.getUUID() + "]";
276 }
277 filename = FileUtils.prepareWinFilename(filename);
278 filename = backupFolder + filename + ".msg";
279 if (logger.isDebugEnabled())
280 {
281 logger.debug("Writing message to: " + filename);
282 }
283 File f = FileUtils.createFile(filename);
284 FileOutputStream fos = new FileOutputStream(f);
285 msg.writeTo(fos);
286 }
287 }
288
289 @Override
290 public synchronized void poll()
291 {
292 try
293 {
294 try
295 {
296 if (!folder.isOpen())
297 {
298 folder.open(Folder.READ_WRITE);
299 }
300 }
301 catch (Exception e)
302 {
303 if (logger.isDebugEnabled())
304 {
305 logger.debug("ignoring exception: " + e.getMessage());
306 }
307 }
308
309 int count = folder.getMessageCount();
310 if (count > 0)
311 {
312 Message[] messages = folder.getMessages();
313 MessageCountEvent event = new MessageCountEvent(folder, MessageCountEvent.ADDED, true,
314 messages);
315 messagesAdded(event);
316 }
317 else if (count == -1)
318 {
319 throw new MessagingException("Cannot monitor folder: " + folder.getFullName()
320 + " as folder is closed");
321 }
322 }
323 catch (MessagingException e)
324 {
325 getConnector().getMuleContext().getExceptionListener().handleException(e);
326 }
327 finally
328 {
329 try
330 {
331 folder.close(true);
332 }
333 catch (Exception e)
334 {
335 logger.error("Failed to close pop3 inbox: " + e.getMessage());
336 }
337 }
338 }
339
340 @Override
341 protected void doDispose()
342 {
343 if (null != folder)
344 {
345 folder.removeMessageCountListener(this);
346 if (folder.isOpen())
347 {
348 try
349 {
350
351 folder.close(true);
352 }
353 catch (Exception e)
354 {
355 logger.debug("ignoring exception: " + e.getMessage(), e);
356 }
357 }
358 }
359 }
360
361 @Override
362 protected MuleMessage handleUnacceptedFilter(MuleMessage message)
363 {
364 super.handleUnacceptedFilter(message);
365 if (message.getPayload() instanceof Message)
366 {
367 Message msg = (Message) message.getPayload();
368 try
369 {
370 msg.setFlag(Flags.Flag.DELETED, endpoint.isDeleteUnacceptedMessages());
371 }
372 catch (MessagingException e)
373 {
374 logger.error("failed to set message deleted: " + e.getMessage(), e);
375 }
376 }
377 return message;
378 }
379 }