1 package com.ozacc.mail.fetch.impl;
2
3 import java.util.Properties;
4
5 import javax.mail.AuthenticationFailedException;
6 import javax.mail.Flags;
7 import javax.mail.Folder;
8 import javax.mail.Message;
9 import javax.mail.MessagingException;
10 import javax.mail.NoSuchProviderException;
11 import javax.mail.Session;
12 import javax.mail.Store;
13 import javax.mail.internet.MimeMessage;
14
15 import org.apache.commons.logging.Log;
16 import org.apache.commons.logging.LogFactory;
17
18 import com.ozacc.mail.MailAuthenticationException;
19 import com.ozacc.mail.MailException;
20 import com.ozacc.mail.NotConnectedException;
21 import com.ozacc.mail.fetch.FetchMailPro;
22 import com.ozacc.mail.fetch.MailConverter;
23 import com.ozacc.mail.fetch.MailFetchException;
24 import com.ozacc.mail.fetch.ReceivedMail;
25
26 /***
27 * <code>FetchMail</code>インターフェースの実装クラス。
28 * <p>
29 * このクラスのインスタンスは、インスタンス変数を用いて状態を保持するため、
30 * ステートレスではありません。ステートフルです。
31 *
32 * @since 1.2
33 * @author Tomohiro Otsuka
34 * @author gaku
35 * @version $Id: FetchMailProImpl.java,v 1.1.2.13 2005/04/10 05:22:24 otsuka Exp $
36 */
37 public class FetchMailProImpl implements FetchMailPro {
38
39 private static Log log = LogFactory.getLog(FetchMailProImpl.class);
40
41 /*** デフォルトのSMTPサーバ。「localhost」 */
42 public static final String DEFAULT_HOST = "localhost";
43
44 /*** デフォルトのプロトコル。「pop3」 */
45 public static final String DEFAULT_PROTOCOL = "pop3";
46
47 /***
48 * デフォルトのポート。「-1」<br>
49 * -1はプロトコルに応じた適切なポートを設定する特別な値。
50 */
51 public static final int DEFAULT_PORT = -1;
52
53 private static final String INBOX_NAME = "INBOX";
54
55 private String host = DEFAULT_HOST;
56
57 private String protocol = DEFAULT_PROTOCOL;
58
59 private int port = DEFAULT_PORT;
60
61 private String username;
62
63 private String password;
64
65 private boolean javaMailLogEnabled;
66
67 private Store store;
68
69 private Folder currentFolder;
70
71 /*** MailConver の実装インスタンス。 */
72 private MailConverter mailConverter = new MailConverterImpl();
73
74 /***
75 * コンストラクタ。
76 */
77 public FetchMailProImpl() {
78 System.setProperty("mail.mime.multipart.ignoremissingendboundary", "true");
79 }
80
81 /***
82 * @see com.ozacc.mail.fetch.FetchMailPro#connect()
83 */
84 public synchronized void connect() throws MailException {
85 if (isConnected()) {
86 log.warn("既にサーバ[" + host + "]に接続されています。再接続するには先に接続を切断する必要があります。");
87 return;
88 }
89
90 log.debug(protocol.toUpperCase() + "サーバ[" + host + "]に接続します。");
91 Session session = Session.getInstance(createProperties(), null);
92 if (javaMailLogEnabled) {
93 session.setDebug(true);
94 }
95 try {
96 store = session.getStore(protocol);
97 store.connect(host, port, username, password);
98 } catch (NoSuchProviderException e) {
99 log.error("指定されたプロトコル[" + protocol + "]はサポートされていません。", e);
100 throw new MailException("指定されたプロトコル[" + protocol + "]はサポートされていません。", e);
101 } catch (AuthenticationFailedException e) {
102 log.error(protocol.toUpperCase() + "サーバ[" + host + "]への接続認証に失敗しました。", e);
103 throw new MailAuthenticationException(protocol.toUpperCase() + "サーバ[" + host
104 + "]への接続認証に失敗しました。", e);
105 } catch (MessagingException e) {
106 log.error(protocol.toUpperCase() + "サーバ[" + host + "]への接続に失敗しました。", e);
107 throw new MailException(protocol.toUpperCase() + "サーバ[" + host + "]への接続に失敗しました。", e);
108 }
109 log.info(protocol.toUpperCase() + "サーバ[" + host + "]に接続しました。");
110
111 changeFolder(INBOX_NAME);
112 }
113
114 /***
115 * Sessionに渡すPropertiesインスタンスを返します。
116 * APOP認証を行う場合に、"mail.pop3.apop.enable"をセットします。
117 *
118 * @return Sessionに渡すPropertiesインスタンス
119 */
120 private Properties createProperties() {
121 Properties prop = new Properties();
122 if ("apop".equalsIgnoreCase(protocol)) {
123 prop.put("mail.pop3.apop.enable", "true");
124 }
125 return prop;
126 }
127
128 /***
129 * @see com.ozacc.mail.fetch.FetchMailPro#disconnect()
130 */
131 public synchronized void disconnect() throws MailException {
132 try {
133 closeCurrentFolderIfOpen();
134 } finally {
135 if (isConnected()) {
136 log.debug(protocol.toUpperCase() + "サーバ[" + host + "]との接続を切断します。");
137 try {
138 store.close();
139 store = null;
140 } catch (MessagingException e) {
141 throw new MailException("サーバ[" + host + "]との接続切断に失敗しました。", e);
142 }
143 }
144 }
145 log.info(protocol.toUpperCase() + "サーバ[" + host + "]との接続を切断しました。");
146 }
147
148 /***
149 * 現在のメッセージフォルダをクローズします。
150 *
151 * @throws MailException メッセージフォルダのクローズに失敗した場合
152 */
153 private void closeCurrentFolderIfOpen() throws MailException {
154 if (currentFolder != null && currentFolder.isOpen()) {
155 log.debug("メッセージフォルダ[" + currentFolder.getName() + "]をクローズします。");
156 try {
157 currentFolder.close(true);
158 } catch (MessagingException e) {
159 log.error("メッセージフォルダ[" + currentFolder.getName() + "]のクローズに失敗しました。", e);
160 throw new MailException("メッセージフォルダ[" + currentFolder.getName() + "]のクローズに失敗しました。",
161 e);
162 }
163 log.debug("メッセージフォルダ[" + currentFolder.getName() + "]をクローズしました。");
164 currentFolder = null;
165 }
166 }
167
168 /***
169 * @see com.ozacc.mail.fetch.FetchMailPro#changeFolder(java.lang.String)
170 */
171 public synchronized void changeFolder(String folderName) throws MailException {
172 if (!isConnected()) {
173 log.warn("メールサーバに接続されていません。");
174 return;
175 }
176
177 closeCurrentFolderIfOpen();
178 log.debug("メッセージフォルダ[" + folderName + "]をオープンします。");
179 try {
180 currentFolder = store.getFolder(folderName);
181 currentFolder.open(Folder.READ_WRITE);
182 } catch (MessagingException e) {
183 log.error("メッセージフォルダ[" + folderName + "]のオープンに失敗しました。", e);
184 throw new MailException("メッセージフォルダ[" + folderName + "]のオープンに失敗しました。", e);
185 }
186 log.debug("メッセージフォルダ[" + folderName + "]をオープンしました。");
187 }
188
189 /***
190 * @see com.ozacc.mail.fetch.FetchMailPro#getMailCount()
191 */
192 public int getMailCount() throws MailException {
193 checkIfCurrentFolderIsOpen();
194 try {
195 return currentFolder.getMessageCount();
196 } catch (MessagingException e) {
197 throw new MailFetchException("メール数の取得に失敗しました。", e);
198 }
199 }
200
201 /***
202 * メールサーバに接続されていて、フォルダが操作できる状態かどうか調べます。
203 * フォルダが操作できる状態にない場合、NotConnectedExceptionをスローします。
204 *
205 * @throws NotConnectedException
206 */
207 private void checkIfCurrentFolderIsOpen() throws NotConnectedException {
208 if (currentFolder == null || !currentFolder.isOpen()) {
209 throw new NotConnectedException(protocol.toUpperCase() + "サーバ[" + host + "]に接続されていません。");
210 }
211 }
212
213 /***
214 * @see com.ozacc.mail.fetch.FetchMailPro#getMail(int)
215 */
216 public ReceivedMail getMail(int num) throws MailException {
217 return getMail(num, false);
218 }
219
220 /***
221 * @see com.ozacc.mail.fetch.FetchMailPro#getMail(int, boolean)
222 */
223 public ReceivedMail getMail(int num, boolean delete) throws MailException {
224 MimeMessage mimeMessage = getMessage(num);
225 try {
226 mimeMessage.setFlag(Flags.Flag.DELETED, delete);
227 log.debug(num + "番目のメッセージにDELETEDフラグをセットしました。");
228 } catch (MessagingException e) {
229 throw new MailException("DELETEDフラグのセットに失敗しました。", e);
230 }
231 return mailConverter.convertIntoMail(mimeMessage);
232 }
233
234 /***
235 * @see com.ozacc.mail.fetch.FetchMailPro#getMails(boolean)
236 */
237 public ReceivedMail[] getMails(boolean delete) throws MailException {
238 MimeMessage[] mimeMessages = getMessages(delete);
239 return mailConverter.convertIntoMails(mimeMessages);
240 }
241
242 /***
243 * @see com.ozacc.mail.fetch.FetchMailPro#getMessage(int)
244 */
245 public synchronized MimeMessage getMessage(int num) throws MailException {
246 checkIfCurrentFolderIsOpen();
247 try {
248 return (MimeMessage)currentFolder.getMessage(num);
249 } catch (MessagingException e) {
250 log.error("メッセージの取得に失敗しました。", e);
251 throw new MailFetchException("メッセージの取得に失敗しました。", e);
252 }
253 }
254
255 public synchronized MimeMessage[] getMessages(boolean delete) throws MailException {
256 checkIfCurrentFolderIsOpen();
257 try {
258 Message[] messages = currentFolder.getMessages();
259 if (log.isInfoEnabled()) {
260 if (messages.length > 0) {
261 log.info(messages.length + "通のメールを受信します。");
262 } else {
263 log.info("受信するメールはありません。");
264 }
265 }
266
267 currentFolder.setFlags(messages, new Flags(Flags.Flag.SEEN), true);
268
269 if (delete) {
270 currentFolder.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
271 }
272 MimeMessage[] mimeMessages = new MimeMessage[messages.length];
273 for (int i = 0; i < messages.length; i++) {
274 mimeMessages[i] = (MimeMessage)messages[i];
275 }
276 return mimeMessages;
277 } catch (MessagingException e) {
278 log.error("メッセージの取得に失敗しました。", e);
279 throw new MailFetchException("メッセージの取得に失敗しました。", e);
280 }
281 }
282
283 /***
284 * @see com.ozacc.mail.fetch.FetchMailPro#isConnected()
285 */
286 public boolean isConnected() {
287 return store != null && store.isConnected();
288 }
289
290 /***
291 * メールサーバのホスト名、またはIPアドレスを返します。
292 *
293 * @return メールサーバのホスト名、またはIPアドレス
294 */
295 public String getHost() {
296 return host;
297 }
298
299 /***
300 * メールサーバのホスト名、またはIPアドレスをセットします。
301 * デフォルトは localhost です。
302 *
303 * @param host メールサーバのホスト名、またはIPアドレス
304 */
305 public void setHost(String host) {
306 this.host = host;
307 }
308
309 /***
310 * メールサーバの認証パスワードを返します。
311 *
312 * @return メールサーバの認証パスワード
313 */
314 public String getPassword() {
315 return password;
316 }
317
318 /***
319 * メールサーバの認証パスワード名をセットします。
320 *
321 * @param password メールサーバの認証パスワード
322 */
323 public void setPassword(String password) {
324 this.password = password;
325 }
326
327 /***
328 * メール受信に使用するプロトコロルをセットします。
329 *
330 * @return プロトコル
331 */
332 public String getProtocol() {
333 return protocol;
334 }
335
336 /***
337 * メール受信に使用するプロトコロルをセットします。
338 * 現在サポートされているプロトコルは、「pop3」と「imap」の二つです。
339 * デフォルトは「pop3」です。
340 * <p>
341 * POP3サーバへの認証をAPOPで行いたい場合は、プロトコル名ではありませんが、
342 * 「apop」を指定してください。APOP認証を使用するには、JavaMail 1.3.2以降が必要です。
343 *
344 * @param protocol プロトコル
345 */
346 public void setProtocol(String protocol) {
347 this.protocol = protocol;
348 }
349
350 /***
351 * @return 認証ユーザ名
352 */
353 public String getUsername() {
354 return username;
355 }
356
357 /***
358 * メールサーバの認証ユーザ名をセットします。
359 *
360 * @param username 認証ユーザ名
361 */
362 public void setUsername(String username) {
363 this.username = username;
364 }
365
366 /***
367 * @return ポート番号
368 */
369 public int getPort() {
370 return port;
371 }
372
373 /***
374 * メール受信に使用するポート番号をセットします。
375 * プロトコルに応じたポート番号が自動的に使用されますので、通常ここでポート番号をセットする必要はありません。
376 *
377 * @param port ポート番号
378 */
379 public void setPort(int port) {
380 this.port = port;
381 }
382
383 /***
384 * JavaMailのデバッグが有効かどうか判定します。
385 *
386 * @return JavaMailのデバッグが有効な場合 ture
387 */
388 public boolean isJavaMailLogEnabled() {
389 return javaMailLogEnabled;
390 }
391
392 /***
393 * JavaMailのデバッグを有効にするかどうか指定します。
394 * 有効にすると、<code>System.out</code>のデバッグメッセージが出力されます。<br>
395 * デフォルトは無効になっています。
396 *
397 * @see javax.mail.session#setDebug(boolean)
398 * @param javaMailLogEnabled The javaMailLogEnabled to set.
399 */
400 public void setJavaMailLogEnabled(boolean javaMailLogEnabled) {
401 this.javaMailLogEnabled = javaMailLogEnabled;
402 }
403
404 /***
405 * MailConveterインターフェースの実装インスタンスをセットします。
406 * デフォルトでは、MailConverterImplが使用されます。
407 *
408 * @see com.ozacc.mail.fetch.MailConveter
409 * @see com.ozacc.mail.fetch.impl.MailConveterImpl
410 * @param mailConverter MailConveterインターフェースの実装インスタンス
411 */
412 public void setMailConverter(MailConverter mailConverter) {
413 this.mailConverter = mailConverter;
414 }
415 }