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