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 routeMessage(message);
160 }
161 }
162 catch (MuleException e)
163 {
164 getConnector().getMuleContext().getExceptionListener().handleException(e);
165 }
166 catch (Exception e)
167 {
168 Exception forwarded;
169
170 if (message != null)
171 {
172 forwarded = new org.mule.api.MessagingException(EmailMessages.routingError(), message, e);
173 }
174 else
175 {
176 forwarded = new ReceiveException(endpoint, -1, e);
177 }
178
179 getConnector().getMuleContext().getExceptionListener().handleException(forwarded);
180 }
181 }
182
183 if (moveToFolder != null)
184 {
185 try
186 {
187 folder.copyMessages(messages, moveToFolder);
188 }
189 catch (MessagingException e)
190 {
191 getConnector().getMuleContext().getExceptionListener().handleException(e);
192 }
193 }
194 }
195 }
196
197 public void messagesRemoved(MessageCountEvent event)
198 {
199 if (logger.isDebugEnabled())
200 {
201 Message messages[] = event.getMessages();
202 for (int i = 0; i < messages.length; i++)
203 {
204 try
205 {
206 logger.debug("Message removed: " + messages[i].getSubject());
207 }
208 catch (MessagingException ignore)
209 {
210 logger.debug("ignoring exception: " + ignore.getMessage());
211 }
212 }
213 }
214 }
215
216
217 public Folder getFolder()
218 {
219 return folder;
220 }
221
222
223 public synchronized void setFolder(Folder folder)
224 {
225 if (folder == null)
226 {
227 throw new IllegalArgumentException("Mail folder cannot be null");
228 }
229 this.folder = folder;
230 synchronized (this.folder)
231 {
232 if (!this.folder.isOpen())
233 {
234 try
235 {
236 this.folder.open(Folder.READ_WRITE);
237 }
238 catch (MessagingException e)
239 {
240 logger.warn("Failed to open folder: " + folder.getFullName(), e);
241 }
242 }
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255
256 protected void storeMessage(Message msg) throws IOException, MessagingException
257 {
258 if (backupEnabled)
259 {
260 String filename = msg.getFileName();
261 if (filename == null)
262 {
263 Address[] from = msg.getFrom();
264 if (from != null && from.length > 0)
265 {
266 filename = from[0] instanceof InternetAddress
267 ? ((InternetAddress) from[0]).getAddress()
268 : from[0].toString();
269 }
270 else
271 {
272 filename = "(no from address)";
273 }
274 filename += "[" + UUID.getUUID() + "]";
275 }
276 filename = FileUtils.prepareWinFilename(filename);
277 filename = backupFolder + filename + ".msg";
278 if (logger.isDebugEnabled())
279 {
280 logger.debug("Writing message to: " + filename);
281 }
282 File f = FileUtils.createFile(filename);
283 FileOutputStream fos = new FileOutputStream(f);
284 msg.writeTo(fos);
285 }
286 }
287
288 @Override
289 public synchronized void poll()
290 {
291 try
292 {
293 try
294 {
295 if (!folder.isOpen())
296 {
297 folder.open(Folder.READ_WRITE);
298 }
299 }
300 catch (Exception e)
301 {
302 if (logger.isDebugEnabled())
303 {
304 logger.debug("ignoring exception: " + e.getMessage());
305 }
306 }
307
308 int count = folder.getMessageCount();
309 if (count > 0)
310 {
311 Message[] messages = folder.getMessages();
312 MessageCountEvent event = new MessageCountEvent(folder, MessageCountEvent.ADDED, true,
313 messages);
314 messagesAdded(event);
315 }
316 else if (count == -1)
317 {
318 throw new MessagingException("Cannot monitor folder: " + folder.getFullName()
319 + " as folder is closed");
320 }
321 }
322 catch (MessagingException e)
323 {
324 getConnector().getMuleContext().getExceptionListener().handleException(e);
325 }
326 finally
327 {
328 try
329 {
330 folder.close(true);
331 }
332 catch (Exception e)
333 {
334 logger.error("Failed to close pop3 inbox: " + e.getMessage());
335 }
336 }
337 }
338
339 @Override
340 protected void doDispose()
341 {
342 if (null != folder)
343 {
344 folder.removeMessageCountListener(this);
345 if (folder.isOpen())
346 {
347 try
348 {
349
350 folder.close(true);
351 }
352 catch (Exception e)
353 {
354 logger.debug("ignoring exception: " + e.getMessage(), e);
355 }
356 }
357 }
358 }
359
360 @Override
361 protected MuleMessage handleUnacceptedFilter(MuleMessage message)
362 {
363 super.handleUnacceptedFilter(message);
364 if (message.getPayload() instanceof Message)
365 {
366 Message msg = (Message) message.getPayload();
367 try
368 {
369 msg.setFlag(Flags.Flag.DELETED, endpoint.isDeleteUnacceptedMessages());
370 }
371 catch (MessagingException e)
372 {
373 logger.error("failed to set message deleted: " + e.getMessage(), e);
374 }
375 }
376 return message;
377 }
378 }