KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > mail > providers > pop3 > POP3Store


1 /*
2  * POP3Store.java
3  * Copyright (C) 1999, 2003 Chris Burdess <dog@gnu.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * You also have permission to link it with the Sun Microsystems, Inc.
11  * JavaMail(tm) extension and run that combination.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */

22 package gnu.mail.providers.pop3;
23 import java.io.IOException JavaDoc;
24
25 import java.io.InputStream JavaDoc;
26 import java.net.Socket JavaDoc;
27 import java.net.UnknownHostException JavaDoc;
28 import javax.mail.Folder JavaDoc;
29 import javax.mail.Message JavaDoc;
30 import javax.mail.MessagingException JavaDoc;
31 import javax.mail.Session JavaDoc;
32 import javax.mail.Store JavaDoc;
33 import javax.mail.URLName JavaDoc;
34
35 import gnu.mail.util.CRLFInputStream;
36 import gnu.mail.util.CRLFOutputStream;
37 import gnu.mail.util.LineInputStream;
38 import gnu.mail.util.MessageInputStream;
39
40 /**
41  * The storage class implementing the POP3 mail protocol.
42  *
43  * @author <a HREF='mailto:dog@gnu.org'>Chris Burdess</a>
44  * @author <a HREF='mailto:nferrier@tapsellferrier.co.uk'>Nic Ferrier</a>
45  * @version 1.2
46  */

47 public final class POP3Store
48      extends Store JavaDoc
49 {
50
51     /** The default POP3 port. */
52     public final static int DEFAULT_PORT = 110;
53
54     static int fetchsize = 1024;
55
56     static final int OK = 0, ERR = -1;
57     
58     static final String JavaDoc CRLF = "\r\n";
59
60     Socket JavaDoc socket;
61     LineInputStream in;
62     CRLFOutputStream out;
63     String JavaDoc hostname; // response codes
64
String JavaDoc response; // last response
65

66     POP3Folder root; // the root folder
67

68
69     /**
70      * Constructor.
71      *
72      * @param session Description of Parameter
73      * @param urlname Description of Parameter
74      */

75     public POP3Store(Session JavaDoc session, URLName JavaDoc urlname)
76     {
77         super(session, urlname);
78         debug = session.getDebug();
79         String JavaDoc ccs = session.getProperty("mail.pop3.fetchsize");
80         if (ccs != null) {
81             try {
82                 fetchsize = Math.max(Integer.parseInt(ccs), 1024);
83             }
84             catch (NumberFormatException JavaDoc e) {
85             }
86         }
87     }
88
89
90     //protocol and socket methods
91

92     /**
93      * Connects to the POP3 server and authenticates with the specified
94      * parameters.
95      *
96      * @param host Description of Parameter
97      * @param port Description of Parameter
98      * @param username Description of Parameter
99      * @param password Description of Parameter
100      * @return Description of the Returned Value
101      * @exception MessagingException Description of Exception
102      */

103     protected boolean protocolConnect(String JavaDoc host, int port, String JavaDoc username, String JavaDoc password)
104         throws MessagingException JavaDoc
105     {
106         if (port < 0) {
107             port = DEFAULT_PORT;
108         }
109         if (host == null || username == null || password == null) {
110             return false;
111         }
112         if (socket != null) {
113             return true;
114         }
115         synchronized (this) {
116             try {
117                 hostname = host;
118                 socket = new Socket JavaDoc(host, port);
119                 in = new LineInputStream(new CRLFInputStream(socket.getInputStream()));
120                 out = new CRLFOutputStream(socket.getOutputStream());
121                 if (getResponse() != OK) {
122                     throw new MessagingException JavaDoc("Connect failed: " + response);
123                 }
124                 int index = response.indexOf(' ');
125                 if (index > -1) {
126                     hostname = response.substring(0, index);
127                 }
128                 send("USER " + username);
129                 if (getResponse() != OK) {
130                     return false;
131                 }
132                 send("PASS " + password);
133                 if (getResponse() != OK) {
134                     return false;
135                 }
136                 return true;
137             }
138             catch (UnknownHostException JavaDoc e) {
139                 throw new MessagingException JavaDoc("Connect failed", e);
140             }
141             catch (IOException JavaDoc e) {
142                 throw new MessagingException JavaDoc("Connect failed", e);
143             }
144             catch (NullPointerException JavaDoc e) {
145                 throw new MessagingException JavaDoc("Connect failed", e);
146             }
147         }
148     }
149
150
151     /**
152      * Closes the connection.
153      *
154      * @exception MessagingException Description of Exception
155      */

156     public synchronized void close()
157         throws MessagingException JavaDoc
158     {
159         if (socket != null) {
160             synchronized (this) {
161                 try {
162                     send("QUIT");
163                     if (getResponse() != OK) {
164                         throw new MessagingException JavaDoc("Close failed: " + response);
165                     }
166                     socket.close();
167                     socket = null;
168                 }
169                 catch (IOException JavaDoc e) {
170                     // socket.close() always seems to throw an exception!
171
//throw new MessagingException("Close failed", e);
172
}
173             }
174         }
175         super.close();
176
177     }
178
179
180     /**
181      * Parse the response from the server.
182      * If the <code>Store</code> switch <code>debug</code> is
183      * <code>true</code> then the response is echoed to
184      * <code>System.err</code>.
185      *
186      * @return The Response value
187      * @exception IOException Description of Exception
188      */

189     private int getResponse()
190         throws IOException JavaDoc
191     {
192         String JavaDoc okstr = "+OK";
193         String JavaDoc errstr = "-ERR";
194         response = in.readLine();
195         Session.log("POP< " + response);
196         if (response != null) {
197             if (response.indexOf(okstr) == 0) {
198                 response = response.substring(okstr.length()).trim();
199                 return OK;
200             }
201             else if (response.indexOf(errstr) == 0) {
202                 response = response.substring(errstr.length()).trim();
203             }
204         }
205         return ERR;
206     }
207
208
209     /**
210      * Send the command to the server.
211      * If the <code>Session</code> switch <code>debug</code> is
212      * <code>true</code> then the command is echoed to
213      * <code>System.err</code>.
214      *
215      * @param command Description of Parameter
216      * @exception IOException Description of Exception
217      */

218     private void send(String JavaDoc command)
219         throws IOException JavaDoc
220     {
221         final String JavaDoc PasswordCommandPrefix = "PASS ";
222         
223         if (command.toUpperCase().startsWith(PasswordCommandPrefix)) {
224             Session.log("POP> " + PasswordCommandPrefix + "***");
225         }
226         else
227         {
228             Session.log("POP> " + command);
229         }
230         
231         out.write((command + CRLF).getBytes());
232         out.flush();
233     }
234
235
236     /**
237      * Get a stream of content related to a particular message.
238      *
239      * @param msgnum Description of Parameter
240      * @return Description of the Returned Value
241      * @exception MessagingException Description of Exception
242      */

243     synchronized InputStream JavaDoc popRETR(int msgnum)
244         throws MessagingException JavaDoc
245     {
246         try {
247             send("RETR " + msgnum);
248             if (getResponse() != OK) {
249                 throw new MessagingException JavaDoc("Retrieve failed: " + response);
250             }
251             return new MessageInputStream(in);
252         }
253         catch (IOException JavaDoc e) {
254             throw new MessagingException JavaDoc("Retrieve failed.", e);
255         }
256         catch (NumberFormatException JavaDoc e) {
257             throw new MessagingException JavaDoc("Retrieve failed.", e);
258         }
259     }
260
261
262     /**
263      * Get just the headers of a particular message.
264      * This method issues the command
265      * <blockquote>
266      * TOP msg 0
267      * </blockquote>
268      * Which servers should understand to be:
269      * <blockquote>
270      * send 0 lines of the content, ie: the just the header
271      * </blockquote>
272      * But I'm not sure of the extent of support in POP servers for
273      * this particular trick. If it goes wrong this code will die
274      * because we expect to see something.
275      *
276      * @param msgnum Description of Parameter
277      * @return Description of the Returned Value
278      * @exception MessagingException Description of Exception
279      */

280     synchronized InputStream JavaDoc popTOP(int msgnum)
281         throws MessagingException JavaDoc
282     {
283         try {
284             send("TOP " + msgnum + " 0");
285             if (getResponse() != OK) {
286                 throw new MessagingException JavaDoc("Retrieve failed: " + response);
287             }
288             return new MessageInputStream(in);
289         }
290         catch (IOException JavaDoc e) {
291             throw new MessagingException JavaDoc("Retrieve failed.", e);
292         }
293         catch (NumberFormatException JavaDoc e) {
294             throw new MessagingException JavaDoc("Retrieve failed.", e);
295         }
296     }
297
298
299     /**
300      * @return the hostname of the POP server.
301      */

302     String JavaDoc getHostName()
303     {
304         return hostname;
305     }
306
307     //javamail provider methods
308

309     /**
310      * Used by the Folder to assess how many messages there are.
311      *
312      * @return The MessageCount value
313      * @exception MessagingException Description of Exception
314      */

315     synchronized int getMessageCount()
316         throws MessagingException JavaDoc
317     {
318         try {
319             send("STAT");
320             if (getResponse() != OK) {
321                 throw new MessagingException JavaDoc("Status failed: " + response);
322             }
323             try {
324                 return Integer.parseInt(response.substring(0, response.indexOf(' ')));
325             }
326             catch (NumberFormatException JavaDoc e) {
327                 throw new MessagingException JavaDoc("Status failed: " + response);
328             }
329         }
330         catch (IOException JavaDoc e) {
331             throw new MessagingException JavaDoc("Status failed.", e);
332         }
333     }
334
335
336     /**
337      * Retrieve the message.
338      * This method tries to build a nearly empty message object (with
339      * just the size). If it can't do that it pulls back the whole thing.
340      *
341      * @param folder Description of Parameter
342      * @param msgnum Description of Parameter
343      * @return The Message value
344      * @exception MessagingException Description of Exception
345      */

346     synchronized Message JavaDoc getMessage(POP3Folder folder, int msgnum)
347         throws MessagingException JavaDoc
348     {
349         Message JavaDoc message = null;
350         int size = -1;
351         try {
352             send("LIST " + msgnum);
353             if (getResponse() != OK) {
354                 throw new MessagingException JavaDoc("List failed: " + response);
355             }
356             //try and get the message size
357
String JavaDoc sizePart = response.substring(response.indexOf(' ') + 1);
358             size = Integer.parseInt(sizePart);
359         }
360         catch (Throwable JavaDoc t) {
361             //failed to work out the size
362
//- just try to retrieve the whole message
363
try {
364                 send("RETR " + msgnum);
365                 if (getResponse() != OK) {
366                     throw new MessagingException JavaDoc("Retrieve failed: " + response);
367                 }
368             }
369             catch (IOException JavaDoc e) {
370                 throw new MessagingException JavaDoc("Retrieve failed.", e);
371             }
372         }
373
374         // create an object for the message
375
if (size > -1) {
376             message = new POP3Message(folder, msgnum, size);
377         }
378         else {
379             message = new POP3Message(folder, new MessageInputStream(in), msgnum);
380         }
381
382         return message;
383     }
384
385
386     synchronized void delete(int msgnum)
387         throws MessagingException JavaDoc
388     {
389         try {
390             send("DELE " + msgnum);
391             if (getResponse() != OK) {
392                 throw new MessagingException JavaDoc("Delete failed: " + response);
393             }
394         }
395         catch (IOException JavaDoc e) {
396             throw new MessagingException JavaDoc("Delete failed.", e);
397         }
398     }
399
400
401     /**
402      * Returns the root folder.
403      *
404      * @return The DefaultFolder value
405      * @exception MessagingException Description of Exception
406      */

407     public Folder JavaDoc getDefaultFolder()
408         throws MessagingException JavaDoc
409     {
410         synchronized (this) {
411             if (root == null) {
412                 root = new POP3Folder(this, Folder.HOLDS_FOLDERS);
413             }
414         }
415         return root;
416     }
417
418
419     /**
420      * Returns the folder with the specified name.
421      *
422      * @param s Description of Parameter
423      * @return The Folder value
424      * @exception MessagingException Description of Exception
425      */

426     public Folder JavaDoc getFolder(String JavaDoc s)
427         throws MessagingException JavaDoc
428     {
429         return getDefaultFolder().getFolder(s);
430     }
431
432
433     /**
434      * Returns the folder whose name is the file part of the specified URLName.
435      *
436      * @param urlname Description of Parameter
437      * @return The Folder value
438      * @exception MessagingException Description of Exception
439      */

440     public Folder JavaDoc getFolder(URLName JavaDoc urlname)
441         throws MessagingException JavaDoc
442     {
443         return getDefaultFolder().getFolder(urlname.getFile());
444     }
445
446 }
447
448
Popular Tags