/[classpath]/inetlib/source/gnu/inet/pop3/POP3Connection.java
ViewVC logotype

Diff of /inetlib/source/gnu/inet/pop3/POP3Connection.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.16 by dog, Thu Oct 21 15:21:55 2004 UTC revision 1.17 by dog, Thu Nov 25 22:15:05 2004 UTC
# Line 1  Line 1 
1  /*  /*
2   * $Id$   * POP3Connection.java
3   * Copyright (C) 2003 The Free Software Foundation   * Copyright (C) 2003 The Free Software Foundation
4   *   *
5   * This file is part of GNU inetlib, a library.   * This file is part of GNU inetlib, a library.
# Line 91  import gnu.inet.util.SaslPlain; Line 91  import gnu.inet.util.SaslPlain;
91   * over POP3 documented in RFC 2595 and the AUTH command in RFC 1734.   * over POP3 documented in RFC 2595 and the AUTH command in RFC 1734.
92   *   *
93   * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>   * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  * @version $Revision$ $Date$  
94   */   */
95  public class POP3Connection  public class POP3Connection
96  {  {
# Line 162  public class POP3Connection Line 161  public class POP3Connection
161     * Creates a new connection to the server.     * Creates a new connection to the server.
162     * @param hostname the hostname of the server to connect to     * @param hostname the hostname of the server to connect to
163     */     */
164    public POP3Connection (String hostname)    public POP3Connection(String hostname)
165      throws UnknownHostException, IOException      throws UnknownHostException, IOException
166    {    {
167      this (hostname, -1, 0, 0, false);      this(hostname, -1, 0, 0, false);
168    }    }
169    
170    /**    /**
171     * Creates a new connection to the server.     * Creates a new connection to the server.
172     * @param hostname the hostname of the server to connect to     * @param hostname the hostname of the server to connect to
173     * @param port the port to connect to (if &lt;=0, use default POP3 port)     * @param port the port to connect to(if &lt;=0, use default POP3 port)
174     */     */
175    public POP3Connection (String hostname, int port)    public POP3Connection(String hostname, int port)
176      throws UnknownHostException, IOException      throws UnknownHostException, IOException
177    {    {
178      this (hostname, port, 0, 0, false);      this(hostname, port, 0, 0, false);
179    }    }
180    
181    /**    /**
182     * Creates a new connection to the server.     * Creates a new connection to the server.
183     * @param hostname the hostname of the server to connect to     * @param hostname the hostname of the server to connect to
184     * @param port the port to connect to (if &lt;=0, use default POP3 port)     * @param port the port to connect to(if &lt;=0, use default POP3 port)
185     * @param connectionTimeout the connection timeout, in milliseconds     * @param connectionTimeout the connection timeout, in milliseconds
186     * @param timeout the I/O timeout, in milliseconds     * @param timeout the I/O timeout, in milliseconds
187     * @param debug print debugging information     * @param debug print debugging information
188     */     */
189    public POP3Connection (String hostname, int port,    public POP3Connection(String hostname, int port,
190                           int connectionTimeout, int timeout, boolean debug)                          int connectionTimeout, int timeout, boolean debug)
191      throws UnknownHostException, IOException      throws UnknownHostException, IOException
192    {    {
193      this.debug = debug;      this.debug = debug;
# Line 198  public class POP3Connection Line 197  public class POP3Connection
197        }        }
198            
199      // Set up socket      // Set up socket
200      socket = new Socket ();      socket = new Socket();
201      InetSocketAddress address = new InetSocketAddress (hostname, port);      InetSocketAddress address = new InetSocketAddress(hostname, port);
202      if (connectionTimeout > 0)      if (connectionTimeout > 0)
203        {        {
204          socket.connect (address, connectionTimeout);          socket.connect(address, connectionTimeout);
205        }        }
206      else      else
207        {        {
208          socket.connect (address);          socket.connect(address);
209        }        }
210      if (timeout > 0)      if (timeout > 0)
211        {        {
212          socket.setSoTimeout (timeout);          socket.setSoTimeout(timeout);
213        }        }
214            
215      InputStream in = socket.getInputStream ();      InputStream in = socket.getInputStream();
216      in = new BufferedInputStream (in);      in = new BufferedInputStream(in);
217      in = new CRLFInputStream (in);      in = new CRLFInputStream(in);
218      this.in = new LineInputStream (in);      this.in = new LineInputStream(in);
219      OutputStream out = socket.getOutputStream ();      OutputStream out = socket.getOutputStream();
220      out = new BufferedOutputStream (out);      out = new BufferedOutputStream(out);
221      this.out = new CRLFOutputStream (out);      this.out = new CRLFOutputStream(out);
222            
223      if (getResponse() != OK)      if (getResponse() != OK)
224        {        {
225          throw new ProtocolException ("Connect failed: " + response);          throw new ProtocolException("Connect failed: " + response);
226        }        }
227      // APOP timestamp      // APOP timestamp
228      timestamp = parseTimestamp (response);      timestamp = parseTimestamp(response);
229    }    }
230    
231    /**    /**
# Line 238  public class POP3Connection Line 237  public class POP3Connection
237     * @param password the authentication credentials     * @param password the authentication credentials
238     * @return true if authentication was successful, false otherwise     * @return true if authentication was successful, false otherwise
239     */     */
240    public boolean auth (String mechanism, String username, String password)    public boolean auth(String mechanism, String username, String password)
241      throws IOException      throws IOException
242    {    {
243      try      try
244        {        {
245          String[] m = new String[] { mechanism };          String[] m = new String[] { mechanism };
246          CallbackHandler ch = new SaslCallbackHandler (username, password);          CallbackHandler ch = new SaslCallbackHandler(username, password);
247          // Avoid lengthy callback procedure for GNU Crypto          // Avoid lengthy callback procedure for GNU Crypto
248          Properties p = new Properties ();          Properties p = new Properties();
249          p.put ("gnu.crypto.sasl.username", username);          p.put("gnu.crypto.sasl.username", username);
250          p.put ("gnu.crypto.sasl.password", password);          p.put("gnu.crypto.sasl.password", password);
251          SaslClient sasl =          SaslClient sasl =
252            Sasl.createSaslClient (m, null, "pop3",            Sasl.createSaslClient(m, null, "pop3",
253                                   socket.getInetAddress ().getHostName (),                                  socket.getInetAddress().getHostName(),
254                                   p, ch);                                  p, ch);
255          if (sasl == null)          if (sasl == null)
256            {            {
257              // Fall back to home-grown SASL clients              // Fall back to home-grown SASL clients
258              if ("LOGIN".equalsIgnoreCase (mechanism))              if ("LOGIN".equalsIgnoreCase(mechanism))
259                {                {
260                  sasl = new SaslLogin (username, password);                  sasl = new SaslLogin(username, password);
261                }                }
262              else if ("PLAIN".equalsIgnoreCase (mechanism))              else if ("PLAIN".equalsIgnoreCase(mechanism))
263                {                {
264                  sasl = new SaslPlain (username, password);                  sasl = new SaslPlain(username, password);
265                }                }
266              else if ("CRAM-MD5".equalsIgnoreCase (mechanism))              else if ("CRAM-MD5".equalsIgnoreCase(mechanism))
267                {                {
268                  sasl = new SaslCramMD5 (username, password);                  sasl = new SaslCramMD5(username, password);
269                }                }
270              else              else
271                {                {
# Line 274  public class POP3Connection Line 273  public class POP3Connection
273                }                }
274            }            }
275                    
276          StringBuffer cmd = new StringBuffer (AUTH);          StringBuffer cmd = new StringBuffer(AUTH);
277          cmd.append (' ');          cmd.append(' ');
278          cmd.append (mechanism);          cmd.append(mechanism);
279          send (cmd.toString ());          send(cmd.toString());
280          while (true)          while (true)
281            {            {
282              switch (getResponse ())              switch (getResponse())
283                {                {
284                case OK:                case OK:
285                  String qop = (String) sasl.getNegotiatedProperty (Sasl.QOP);                  String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
286                  if ("auth-int".equalsIgnoreCase (qop)                  if ("auth-int".equalsIgnoreCase(qop)
287                      || "auth-conf".equalsIgnoreCase (qop))                      || "auth-conf".equalsIgnoreCase(qop))
288                    {                    {
289                      InputStream in = socket.getInputStream ();                      InputStream in = socket.getInputStream();
290                      in = new BufferedInputStream (in);                      in = new BufferedInputStream(in);
291                      in = new SaslInputStream (sasl, in);                      in = new SaslInputStream(sasl, in);
292                      in = new CRLFInputStream (in);                      in = new CRLFInputStream(in);
293                      this.in = new LineInputStream (in);                      this.in = new LineInputStream(in);
294                      OutputStream out = socket.getOutputStream ();                      OutputStream out = socket.getOutputStream();
295                      out = new BufferedOutputStream (out);                      out = new BufferedOutputStream(out);
296                      out = new SaslOutputStream (sasl, out);                      out = new SaslOutputStream(sasl, out);
297                      this.out = new CRLFOutputStream (out);                      this.out = new CRLFOutputStream(out);
298                    }                    }
299                  return true;                  return true;
300                case READY:                case READY:
301                  try                  try
302                    {                    {
303                      byte[] c0 = response.getBytes ("US-ASCII");                      byte[] c0 = response.getBytes("US-ASCII");
304                      byte[] c1 = BASE64.decode (c0);       // challenge                      byte[] c1 = BASE64.decode(c0);       // challenge
305                      byte[] r0 = sasl.evaluateChallenge (c1);                      byte[] r0 = sasl.evaluateChallenge(c1);
306                      byte[] r1 = BASE64.encode (r0);       // response                      byte[] r1 = BASE64.encode(r0);       // response
307                      out.write (r1);                      out.write(r1);
308                      out.write (0x0d);                      out.write(0x0d);
309                      out.flush ();                      out.flush();
310                      if (debug)                      if (debug)
311                        {                        {
312                          Logger logger = Logger.getInstance ();                          Logger logger = Logger.getInstance();
313                          logger.log ("pop3", "> " +                          logger.log("pop3", "> " +
314                                      new String (r1, "US-ASCII"));                                      new String(r1, "US-ASCII"));
315                        }                        }
316                    }                    }
317                  catch (SaslException e)                  catch (SaslException e)
318                    {                    {
319                      // Error in SASL challenge evaluation - cancel exchange                      // Error in SASL challenge evaluation - cancel exchange
320                      out.write (0x2a);                      out.write(0x2a);
321                      out.write (0x0d);                      out.write(0x0d);
322                      out.flush ();                      out.flush();
323                      if (debug)                      if (debug)
324                        {                        {
325                          Logger logger = Logger.getInstance ();                          Logger logger = Logger.getInstance();
326                          logger.log ("pop3", "> *");                          logger.log("pop3", "> *");
327                        }                        }
328                    }                    }
329                default:                default:
# Line 349  public class POP3Connection Line 348  public class POP3Connection
348     * @param username the user to authenticate     * @param username the user to authenticate
349     * @param password the user's password     * @param password the user's password
350     */     */
351    public boolean apop (String username, String password)    public boolean apop(String username, String password)
352      throws IOException      throws IOException
353    {    {
354      if (username == null || password == null || timestamp == null)      if (username == null || password == null || timestamp == null)
# Line 359  public class POP3Connection Line 358  public class POP3Connection
358      // APOP <username> <digest>      // APOP <username> <digest>
359      try      try
360        {        {
361          byte[] secret = password.getBytes ("US-ASCII");          byte[] secret = password.getBytes("US-ASCII");
362          // compute digest          // compute digest
363          byte[] target = new byte[timestamp.length + secret.length];          byte[] target = new byte[timestamp.length + secret.length];
364          System.arraycopy (timestamp, 0, target, 0, timestamp.length);          System.arraycopy(timestamp, 0, target, 0, timestamp.length);
365          System.arraycopy (secret, 0, target, timestamp.length, secret.length);          System.arraycopy(secret, 0, target, timestamp.length, secret.length);
366          MessageDigest md5 = MessageDigest.getInstance ("MD5");          MessageDigest md5 = MessageDigest.getInstance("MD5");
367          byte[] db = md5.digest (target);          byte[] db = md5.digest(target);
368          // create hexadecimal representation          // create hexadecimal representation
369          StringBuffer digest = new StringBuffer ();          StringBuffer digest = new StringBuffer();
370          for (int i = 0; i < db.length; i++)          for (int i = 0; i < db.length; i++)
371            {            {
372              int c = (int) db[i];              int c = (int) db[i];
# Line 375  public class POP3Connection Line 374  public class POP3Connection
374                {                {
375                  c += 256;                  c += 256;
376                }                }
377              digest.append (Integer.toHexString ((c & 0xf0) >> 4));              digest.append(Integer.toHexString((c & 0xf0) >> 4));
378              digest.append (Integer.toHexString (c & 0x0f));              digest.append(Integer.toHexString(c & 0x0f));
379            }            }
380          // send command          // send command
381          String cmd = new StringBuffer (APOP)          String cmd = new StringBuffer(APOP)
382            .append (' ')            .append(' ')
383            .append (username)            .append(username)
384            .append (' ')            .append(' ')
385            .append (digest.toString ())            .append(digest.toString())
386            .toString ();            .toString();
387          send (cmd);          send(cmd);
388          return getResponse () == OK;          return getResponse() == OK;
389        }        }
390      catch (NoSuchAlgorithmException e)      catch (NoSuchAlgorithmException e)
391        {        {
392          Logger logger = Logger.getInstance ();          Logger logger = Logger.getInstance();
393          logger.log ("pop3", "MD5 algorithm not found");          logger.log("pop3", "MD5 algorithm not found");
394          return false;          return false;
395        }        }
396    }    }
# Line 404  public class POP3Connection Line 403  public class POP3Connection
403     * @param username the user to authenticate     * @param username the user to authenticate
404     * @param password the user's password     * @param password the user's password
405     */     */
406    public boolean login (String username, String password)    public boolean login(String username, String password)
407      throws IOException      throws IOException
408    {    {
409      if (username == null || password == null)      if (username == null || password == null)
# Line 413  public class POP3Connection Line 412  public class POP3Connection
412        }        }
413      // USER <username>      // USER <username>
414      String cmd = USER + ' ' + username;      String cmd = USER + ' ' + username;
415      send (cmd);      send(cmd);
416      if (getResponse () != OK)      if (getResponse() != OK)
417        {        {
418          return false;          return false;
419        }        }
420      // PASS <password>      // PASS <password>
421      cmd = PASS + ' ' + password;      cmd = PASS + ' ' + password;
422      send (cmd);      send(cmd);
423      return getResponse () == OK;      return getResponse() == OK;
424    }    }
425        
426    /**    /**
# Line 429  public class POP3Connection Line 428  public class POP3Connection
428     * See RFC 2595 for details     * See RFC 2595 for details
429     * @return true if successful, false otherwise     * @return true if successful, false otherwise
430     */     */
431    public boolean stls ()    public boolean stls()
432      throws IOException      throws IOException
433    {    {
434      return stls (new EmptyX509TrustManager ());      return stls(new EmptyX509TrustManager());
435    }    }
436        
437    /**    /**
# Line 441  public class POP3Connection Line 440  public class POP3Connection
440     * @param tm the custom trust manager to use     * @param tm the custom trust manager to use
441     * @return true if successful, false otherwise     * @return true if successful, false otherwise
442     */     */
443    public boolean stls (TrustManager tm)    public boolean stls(TrustManager tm)
444      throws IOException      throws IOException
445    {    {
446      try      try
447        {        {
448          // Use SSLSocketFactory to negotiate a TLS session and wrap the          // Use SSLSocketFactory to negotiate a TLS session and wrap the
449          // current socket.          // current socket.
450          SSLContext context = SSLContext.getInstance ("TLS");          SSLContext context = SSLContext.getInstance("TLS");
451          // We don't require strong validation of the server certificate          // We don't require strong validation of the server certificate
452          TrustManager[] trust = new TrustManager[] { tm };          TrustManager[] trust = new TrustManager[] { tm };
453          context.init (null, trust, null);          context.init(null, trust, null);
454          SSLSocketFactory factory = context.getSocketFactory ();          SSLSocketFactory factory = context.getSocketFactory();
455                    
456          send (STLS);          send(STLS);
457          if (getResponse () != OK)          if (getResponse() != OK)
458            {            {
459              return false;              return false;
460            }            }
461                    
462          String hostname = socket.getInetAddress ().getHostName ();          String hostname = socket.getInetAddress().getHostName();
463          int port = socket.getPort ();          int port = socket.getPort();
464          SSLSocket ss =          SSLSocket ss =
465            (SSLSocket) factory.createSocket (socket, hostname, port, true);            (SSLSocket) factory.createSocket(socket, hostname, port, true);
466          String[] protocols = { "TLSv1", "SSLv3" };          String[] protocols = { "TLSv1", "SSLv3" };
467          ss.setEnabledProtocols (protocols);          ss.setEnabledProtocols(protocols);
468          ss.setUseClientMode (true);          ss.setUseClientMode(true);
469          ss.startHandshake ();          ss.startHandshake();
470                    
471          // set up streams          // set up streams
472          InputStream in = ss.getInputStream ();          InputStream in = ss.getInputStream();
473          in = new BufferedInputStream (in);          in = new BufferedInputStream(in);
474          in = new CRLFInputStream (in);          in = new CRLFInputStream(in);
475          this.in = new LineInputStream (in);          this.in = new LineInputStream(in);
476          OutputStream out = ss.getOutputStream ();          OutputStream out = ss.getOutputStream();
477          out = new BufferedOutputStream (out);          out = new BufferedOutputStream(out);
478          this.out = new CRLFOutputStream (out);          this.out = new CRLFOutputStream(out);
479                    
480          return true;          return true;
481        }        }
# Line 489  public class POP3Connection Line 488  public class POP3Connection
488    /**    /**
489     * Returns the number of messages in the maildrop.     * Returns the number of messages in the maildrop.
490     */     */
491    public int stat ()    public int stat()
492      throws IOException      throws IOException
493    {    {
494      send (STAT);      send(STAT);
495      if (getResponse () != OK)      if (getResponse() != OK)
496        {        {
497          throw new ProtocolException ("STAT failed: " + response);          throw new ProtocolException("STAT failed: " + response);
498        }        }
499      try      try
500        {        {
501          return          return
502            Integer.parseInt (response.substring (0, response.indexOf (' ')));            Integer.parseInt(response.substring(0, response.indexOf(' ')));
503        }        }
504      catch (NumberFormatException e)      catch (NumberFormatException e)
505        {        {
506          throw new ProtocolException ("Not a number: " + response);          throw new ProtocolException("Not a number: " + response);
507        }        }
508      catch (ArrayIndexOutOfBoundsException e)      catch (ArrayIndexOutOfBoundsException e)
509        {        {
510          throw new ProtocolException ("Not a STAT response: " + response);          throw new ProtocolException("Not a STAT response: " + response);
511        }        }
512    }    }
513        
# Line 516  public class POP3Connection Line 515  public class POP3Connection
515     * Returns the size of the specified message.     * Returns the size of the specified message.
516     * @param msgnum the message number     * @param msgnum the message number
517     */     */
518    public int list (int msgnum)    public int list(int msgnum)
519      throws IOException      throws IOException
520    {    {
521      String cmd = LIST + ' ' + msgnum;      String cmd = LIST + ' ' + msgnum;
522      send (cmd);      send(cmd);
523      if (getResponse () != OK)      if (getResponse() != OK)
524        {        {
525          throw new ProtocolException ("LIST failed: " + response);          throw new ProtocolException("LIST failed: " + response);
526        }        }
527      try      try
528        {        {
529          return          return
530            Integer.parseInt (response.substring (response.indexOf (' ') + 1));            Integer.parseInt(response.substring(response.indexOf(' ') + 1));
531        }        }
532      catch (NumberFormatException e)      catch (NumberFormatException e)
533        {        {
534          throw new ProtocolException ("Not a number: " + response);          throw new ProtocolException("Not a number: " + response);
535        }        }
536    }    }
537        
# Line 542  public class POP3Connection Line 541  public class POP3Connection
541     * can be issued on this connection.     * can be issued on this connection.
542     * @param msgnum the message number     * @param msgnum the message number
543     */     */
544    public InputStream retr (int msgnum)    public InputStream retr(int msgnum)
545      throws IOException      throws IOException
546    {    {
547      String cmd = RETR + ' ' + msgnum;      String cmd = RETR + ' ' + msgnum;
548      send (cmd);      send(cmd);
549      if (getResponse () != OK)      if (getResponse() != OK)
550        {        {
551          throw new ProtocolException ("RETR failed: " + response);          throw new ProtocolException("RETR failed: " + response);
552        }        }
553      return new MessageInputStream (in);      return new MessageInputStream(in);
554    }    }
555        
556    /**    /**
557     * Marks the specified message as deleted.     * Marks the specified message as deleted.
558     * @param msgnum the message number     * @param msgnum the message number
559     */     */
560    public void dele (int msgnum)    public void dele(int msgnum)
561      throws IOException      throws IOException
562    {    {
563      String cmd = DELE + ' ' + msgnum;      String cmd = DELE + ' ' + msgnum;
564      send (cmd);      send(cmd);
565      if (getResponse () != OK)      if (getResponse() != OK)
566        {        {
567          throw new ProtocolException ("DELE failed: " + response);          throw new ProtocolException("DELE failed: " + response);
568        }        }
569    }    }
570        
# Line 573  public class POP3Connection Line 572  public class POP3Connection
572     * Does nothing.     * Does nothing.
573     * This can be used to keep the connection alive.     * This can be used to keep the connection alive.
574     */     */
575    public void noop ()    public void noop()
576      throws IOException      throws IOException
577    {    {
578      send (NOOP);      send(NOOP);
579      if (getResponse () != OK)      if (getResponse() != OK)
580        {        {
581          throw new ProtocolException ("NOOP failed: " + response);          throw new ProtocolException("NOOP failed: " + response);
582        }        }
583    }    }
584    
585    /**    /**
586     * If any messages have been marked as deleted, they are unmarked.     * If any messages have been marked as deleted, they are unmarked.
587     */     */
588    public void rset ()    public void rset()
589      throws IOException      throws IOException
590    {    {
591      send (RSET);      send(RSET);
592      if (getResponse () != OK)      if (getResponse() != OK)
593        {        {
594          throw new ProtocolException ("RSET failed: " + response);          throw new ProtocolException("RSET failed: " + response);
595        }        }
596    }    }
597        
# Line 603  public class POP3Connection Line 602  public class POP3Connection
602     * @return true if all deleted messages were successfully removed, false     * @return true if all deleted messages were successfully removed, false
603     * otherwise     * otherwise
604     */     */
605    public boolean quit ()    public boolean quit()
606      throws IOException      throws IOException
607    {    {
608      send (QUIT);      send(QUIT);
609      int ret = getResponse ();      int ret = getResponse();
610      socket.close ();      socket.close();
611      return ret == OK;      return ret == OK;
612    }    }
613    
# Line 618  public class POP3Connection Line 617  public class POP3Connection
617     * issued.     * issued.
618     * @param msgnum the message number     * @param msgnum the message number
619     */     */
620    public InputStream top (int msgnum)    public InputStream top(int msgnum)
621      throws IOException      throws IOException
622    {    {
623      String cmd = TOP + ' ' + msgnum + ' ' + '0';      String cmd = TOP + ' ' + msgnum + ' ' + '0';
624      send (cmd);      send(cmd);
625      if (getResponse () != OK)      if (getResponse() != OK)
626        {        {
627          throw new ProtocolException ("TOP failed: " + response);          throw new ProtocolException("TOP failed: " + response);
628        }        }
629      return new MessageInputStream (in);      return new MessageInputStream(in);
630    }    }
631        
632    /**    /**
633     * Returns a unique identifier for the specified message.     * Returns a unique identifier for the specified message.
634     * @param msgnum the message number     * @param msgnum the message number
635     */     */
636    public String uidl (int msgnum)    public String uidl(int msgnum)
637      throws IOException      throws IOException
638    {    {
639      String cmd = UIDL + ' ' + msgnum;      String cmd = UIDL + ' ' + msgnum;
640      send (cmd);      send(cmd);
641      if (getResponse () != OK)      if (getResponse() != OK)
642        {        {
643          throw new ProtocolException ("UIDL failed: " + response);          throw new ProtocolException("UIDL failed: " + response);
644        }        }
645      return response.substring (response.indexOf (' ') + 1);      return response.substring(response.indexOf(' ') + 1);
646    }    }
647    
648    /**    /**
649     * Returns a map of message number to UID pairs.     * Returns a map of message number to UID pairs.
650     * Message numbers are Integers, UIDs are Strings.     * Message numbers are Integers, UIDs are Strings.
651     */     */
652    public Map uidl ()    public Map uidl()
653      throws IOException      throws IOException
654    {    {
655      send (UIDL);      send(UIDL);
656      if (getResponse () != OK)      if (getResponse() != OK)
657        {        {
658          throw new ProtocolException ("UIDL failed: " + response);          throw new ProtocolException("UIDL failed: " + response);
659        }        }
660      Map uids = new LinkedHashMap ();      Map uids = new LinkedHashMap();
661      String line = in.readLine ();      String line = in.readLine();
662      while (line != null && !(".".equals (line)))      while (line != null && !(".".equals(line)))
663        {        {
664          int si = line.indexOf (' ');          int si = line.indexOf(' ');
665          if (si < 1)          if (si < 1)
666            {            {
667              throw new ProtocolException ("Invalid UIDL response: " + line);              throw new ProtocolException("Invalid UIDL response: " + line);
668            }            }
669          try          try
670            {            {
671              uids.put (new Integer (line.substring (0, si)),              uids.put(new Integer(line.substring(0, si)),
672                        line.substring (si + 1));                        line.substring(si + 1));
673            }            }
674          catch (NumberFormatException e)          catch (NumberFormatException e)
675            {            {
676              throw new ProtocolException ("Invalid message number: " + line);              throw new ProtocolException("Invalid message number: " + line);
677            }            }
678        }        }
679      return Collections.unmodifiableMap (uids);      return Collections.unmodifiableMap(uids);
680    }    }
681    
682    /**    /**
# Line 685  public class POP3Connection Line 684  public class POP3Connection
684     * If the server does not support POP3 extensions, returns     * If the server does not support POP3 extensions, returns
685     * <code>null</code>.     * <code>null</code>.
686     */     */
687    public List capa ()    public List capa()
688      throws IOException      throws IOException
689    {    {
690      send (CAPA);      send(CAPA);
691      if (getResponse () == OK)      if (getResponse() == OK)
692        {        {
693          final String DOT = ".";          final String DOT = ".";
694          List list = new ArrayList ();          List list = new ArrayList();
695          for (String line = in.readLine ();          for (String line = in.readLine();
696               !DOT.equals (line);               !DOT.equals(line);
697               line = in.readLine ())               line = in.readLine())
698            {            {
699              list.add (line);              list.add(line);
700            }            }
701          return Collections.unmodifiableList (list);          return Collections.unmodifiableList(list);
702        }        }
703      return null;      return null;
704    }    }
# Line 709  public class POP3Connection Line 708  public class POP3Connection
708     * If <code>debug</code> is <code>true</code>,     * If <code>debug</code> is <code>true</code>,
709     * the command is logged.     * the command is logged.
710     */     */
711    protected void send (String command)    protected void send(String command)
712      throws IOException      throws IOException
713    {    {
714      if (debug)      if (debug)
715        {        {
716          Logger logger = Logger.getInstance ();          Logger logger = Logger.getInstance();
717          logger.log ("pop3", "> " + command);          logger.log("pop3", "> " + command);
718        }        }
719      out.write (command);      out.write(command);
720      out.writeln ();      out.writeln();
721      out.flush ();      out.flush();
722    }    }
723        
724    /**    /**
# Line 727  public class POP3Connection Line 726  public class POP3Connection
726     * If <code>debug</code> is <code>true</code>,     * If <code>debug</code> is <code>true</code>,
727     * the response is logged.     * the response is logged.
728     */     */
729    protected int getResponse ()    protected int getResponse()
730      throws IOException      throws IOException
731    {    {
732      response = in.readLine ();      response = in.readLine();
733      if (debug)      if (debug)
734        {        {
735          Logger logger = Logger.getInstance ();          Logger logger = Logger.getInstance();
736          logger.log ("pop3", "< " + response);          logger.log("pop3", "< " + response);
737        }        }
738      if (response.indexOf (_OK) == 0)      if (response.indexOf(_OK) == 0)
739        {        {
740          response = response.substring (3).trim ();          response = response.substring(3).trim();
741          return OK;          return OK;
742        }        }
743      else if (response.indexOf (_ERR) == 0)      else if (response.indexOf(_ERR) == 0)
744        {        {
745          response = response.substring (4).trim ();          response = response.substring(4).trim();
746          return ERR;          return ERR;
747        }        }
748      else if (response.indexOf (_READY) == 0)      else if (response.indexOf(_READY) == 0)
749        {        {
750          response = response.substring (2).trim ();          response = response.substring(2).trim();
751          return READY;          return READY;
752        }        }
753      else      else
754        {        {
755          throw new ProtocolException ("Unexpected response: " + response);          throw new ProtocolException("Unexpected response: " + response);
756        }        }
757    }    }
758        
759    /*    /*
760     * Parse the APOP timestamp from the server's banner greeting.     * Parse the APOP timestamp from the server's banner greeting.
761     */     */
762    byte[] parseTimestamp (String greeting)    byte[] parseTimestamp(String greeting)
763      throws IOException      throws IOException
764    {    {
765      int bra = greeting.indexOf ('<');      int bra = greeting.indexOf('<');
766      if (bra != -1)      if (bra != -1)
767        {        {
768          int ket = greeting.indexOf ('>', bra);          int ket = greeting.indexOf('>', bra);
769          if (ket != -1)          if (ket != -1)
770            {            {
771              String mid = greeting.substring (bra, ket + 1);              String mid = greeting.substring(bra, ket + 1);
772              int at = mid.indexOf ('@');              int at = mid.indexOf('@');
773              if (at != -1)           // This is a valid RFC822 msg-id              if (at != -1)           // This is a valid RFC822 msg-id
774                {                {
775                  return mid.getBytes ("US-ASCII");                  return mid.getBytes("US-ASCII");
776                }                }
777            }            }
778        }        }
# Line 781  public class POP3Connection Line 780  public class POP3Connection
780    }    }
781        
782  }  }
783    

Legend:
Removed from v.1.16  
changed lines
  Added in v.1.17

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26