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