/[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.1 by dog, Sun Oct 19 08:51:37 2003 UTC revision 1.2 by dog, Sun Oct 19 16:16:50 2003 UTC
# Line 77  public class POP3Connection Line 77  public class POP3Connection
77     */     */
78    public static final int DEFAULT_PORT = 110;    public static final int DEFAULT_PORT = 110;
79    
80          // -- POP3 vocabulary --    // -- POP3 vocabulary --
81          private static final String _OK = "+OK";    private static final String _OK = "+OK";
82          private static final String _ERR = "-ERR";    private static final String _ERR = "-ERR";
83          private static final String _READY = "+ ";    private static final String _READY = "+ ";
84            
85          protected static final String STAT = "STAT";    protected static final String STAT = "STAT";
86          protected static final String LIST = "LIST";    protected static final String LIST = "LIST";
87          protected static final String RETR = "RETR";    protected static final String RETR = "RETR";
88          protected static final String DELE = "DELE";    protected static final String DELE = "DELE";
89          protected static final String NOOP = "NOOP";    protected static final String NOOP = "NOOP";
90          protected static final String RSET = "RSET";    protected static final String RSET = "RSET";
91          protected static final String QUIT = "QUIT";    protected static final String QUIT = "QUIT";
92          protected static final String TOP = "TOP";    protected static final String TOP = "TOP";
93          protected static final String UIDL = "UIDL";    protected static final String UIDL = "UIDL";
94          protected static final String USER = "USER";    protected static final String USER = "USER";
95          protected static final String PASS = "PASS";    protected static final String PASS = "PASS";
96          protected static final String APOP = "APOP";    protected static final String APOP = "APOP";
97          protected static final String CAPA = "CAPA";    protected static final String CAPA = "CAPA";
98          protected static final String STLS = "STLS";    protected static final String STLS = "STLS";
99          protected static final String AUTH = "AUTH";    protected static final String AUTH = "AUTH";
100    
101          protected static final int OK = 0;    protected static final int OK = 0;
102          protected static final int ERR = 1;    protected static final int ERR = 1;
103          protected static final int READY = 2;    protected static final int READY = 2;
104    
105          /**          /**
106           * The socket used to communicate with the server.           * The socket used to communicate with the server.
107           */           */
108    protected Socket socket;    protected Socket socket;
109    
110          /**          /**
111           * The socket input stream.           * The socket input stream.
112           */           */
113    protected LineInputStream in;    protected LineInputStream in;
114    
115          /**          /**
116           * The socket output stream.           * The socket output stream.
117           */           */
118    protected CRLFOutputStream out;    protected CRLFOutputStream out;
119      
120          /**          /**
121           * The last response received from the server.           * The last response received from the server.
122           * The status code (+OK or -ERR) is stripped from the line.           * The status code (+OK or -ERR) is stripped from the line.
123           */           */
124    protected String response;    protected String response;
125    
126          /**          /**
127           * If true, print debugging information.           * If true, print debugging information.
128           */           */
129          protected boolean debug;    protected boolean debug;
130    
131          /**          /**
132           * The APOP timestamp, if sent by the server on connection.           * The APOP timestamp, if sent by the server on connection.
133           * Otherwise null.           * Otherwise null.
134           */           */
135          protected byte[] timestamp;    protected byte[] timestamp;
136    
137    /**    /**
138     * Creates a new connection to the server.     * Creates a new connection to the server.
# Line 140  public class POP3Connection Line 140  public class POP3Connection
140           * @param port the port to connect to (if <=0, use default POP3 port)           * @param port the port to connect to (if <=0, use default POP3 port)
141     */     */
142    public POP3Connection(String hostname, int port)    public POP3Connection(String hostname, int port)
143                  throws UnknownHostException, IOException      throws UnknownHostException, IOException
144          {    {
145                  this(hostname, port, -1, -1, false);      this(hostname, port, -1, -1, false);
146          }    }
147            
148    /**    /**
149     * Creates a new connection to the server.     * Creates a new connection to the server.
150           * @param hostname the hostname of the server to connect to           * @param hostname the hostname of the server to connect to
# Line 154  public class POP3Connection Line 154  public class POP3Connection
154           * @param debug print debugging information           * @param debug print debugging information
155     */     */
156    public POP3Connection(String hostname, int port,    public POP3Connection(String hostname, int port,
157                          int connectionTimeout, int timeout, boolean debug)                          int connectionTimeout, int timeout, boolean debug)
158                  throws UnknownHostException, IOException      throws UnknownHostException, IOException
159    {    {
160                  this.debug = debug;      this.debug = debug;
161      if (port<=0)      if (port <= 0)
162        port = DEFAULT_PORT;        port = DEFAULT_PORT;
163    
164                  // Set up socket      // Set up socket
165                  // TODO connection timeout      // TODO connection timeout
166                  socket = new Socket(hostname, port);      socket = new Socket(hostname, port);
167                  if (timeout>0)      if (timeout > 0)
168                          socket.setSoTimeout(timeout);        socket.setSoTimeout(timeout);
169                    
170                  InputStream in = socket.getInputStream();      InputStream in = socket.getInputStream();
171                  in = new BufferedInputStream(in);        in = new BufferedInputStream(in);
172                  in = new CRLFInputStream(in);        in = new CRLFInputStream(in);
173                  this.in = new LineInputStream(in);        this.in = new LineInputStream(in);
174                  OutputStream out = socket.getOutputStream();      OutputStream out = socket.getOutputStream();
175                  out = new BufferedOutputStream(out);        out = new BufferedOutputStream(out);
176                  this.out = new CRLFOutputStream(out);        this.out = new CRLFOutputStream(out);
177                    
178                  if (getResponse()!=OK)      if (getResponse() != OK)
179                          throw new ProtocolException("Connect failed: "+response);        throw new ProtocolException("Connect failed: " + response);
180                  // APOP timestamp      // APOP timestamp
181                  timestamp = parseTimestamp(response);        timestamp = parseTimestamp(response);
182          }    }
183    
184          /**          /**
185           * Authenticates the connection using the specified SASL mechanism,           * Authenticates the connection using the specified SASL mechanism,
186           * username, and password.           * username, and password.
187           * @param mechanism a SASL authentication mechanism, e.g. LOGIN, PLAIN,           * @param mechanism a SASL authentication mechanism, e.g. LOGIN, PLAIN,
# Line 190  public class POP3Connection Line 190  public class POP3Connection
190           * @param password the authentication credentials           * @param password the authentication credentials
191           * @return true if authentication was successful, false otherwise           * @return true if authentication was successful, false otherwise
192           */           */
193          public boolean auth(String mechanism, String username, String password)    public boolean auth(String mechanism, String username, String password)
194                  throws IOException      throws IOException
195          {    {
196                  try      try
197                  {      {
198                          String[] m = new String[] { mechanism };        String[]m = new String[]
199                          CallbackHandler ch = new SaslCallbackHandler(username, password);        {
200                          // Avoid lengthy callback procedure for GNU Crypto        mechanism};
201                          Properties p = new Properties();        CallbackHandler ch = new SaslCallbackHandler(username, password);
202                          p.put("gnu.crypto.sasl.username", username);        // Avoid lengthy callback procedure for GNU Crypto
203                          p.put("gnu.crypto.sasl.password", password);        Properties p = new Properties();
204                          SaslClient sasl = Sasl.createSaslClient(m, null, "smtp",          p.put("gnu.crypto.sasl.username", username);
205                                          socket.getInetAddress().getHostName(), p, ch);          p.put("gnu.crypto.sasl.password", password);
206                                  SaslClient sasl = Sasl.createSaslClient(m, null, "smtp",
207                          StringBuffer cmd = new StringBuffer(AUTH);                                                socket.getInetAddress().
208                          cmd.append(' ');                                                getHostName(), p, ch);
209                          cmd.append(mechanism);  
210                          if (sasl.hasInitialResponse())        StringBuffer cmd = new StringBuffer(AUTH);
211                          {          cmd.append(' ');
212                                  cmd.append(' ');          cmd.append(mechanism);
213                                  byte[] init = sasl.evaluateChallenge(new byte[0]);        if (sasl.hasInitialResponse())
214                                  cmd.append(new String(init, "US-ASCII"));        {
215                          }          cmd.append(' ');
216                          send(cmd.toString());          byte[] init = sasl.evaluateChallenge(new byte[0]);
217                          while (true)          cmd.append(new String(init, "US-ASCII"));
218                          {        }
219                                  switch (getResponse())        send(cmd.toString());
220                                  {        while (true)
221                                          case ERR:        {
222                                                  return false;          switch (getResponse())
223                                          case OK:          {
224                                                  String qop = (String)sasl.getNegotiatedProperty(Sasl.QOP);          case ERR:
225                                                  if ("auth-int".equalsIgnoreCase(qop)            return false;
226                                                                  || "auth-conf".equalsIgnoreCase(qop))          case OK:
227                                                  {            String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
228                                                          InputStream in = socket.getInputStream();            if ("auth-int".equalsIgnoreCase(qop)
229                                                          in = new BufferedInputStream(in);                || "auth-conf".equalsIgnoreCase(qop))
230                                                          in = new SaslInputStream(sasl, in);            {
231                                                          in = new CRLFInputStream(in);              InputStream in = socket.getInputStream();
232                                                          this.in = new LineInputStream(in);              in = new BufferedInputStream(in);
233                                                          OutputStream out = socket.getOutputStream();              in = new SaslInputStream(sasl, in);
234                                                          out = new BufferedOutputStream(out);              in = new CRLFInputStream(in);
235                                                          out = new SaslOutputStream(sasl, out);              this.in = new LineInputStream(in);
236                                                          this.out = new CRLFOutputStream(out);              OutputStream out = socket.getOutputStream();
237                                                  }              out = new BufferedOutputStream(out);
238                                                  return true;              out = new SaslOutputStream(sasl, out);
239                                          case READY:              this.out = new CRLFOutputStream(out);
240                                                  try            }
241                                                  {            return true;
242                                                          byte[] c0 = response.getBytes("US-ASCII");          case READY:
243                                                          byte[] c1 = BASE64.decode(c0); // challenge            try
244                                                          byte[] r0 = sasl.evaluateChallenge(c1);            {
245                                                          byte[] r1 = BASE64.encode(r0); // response              byte[]c0 = response.getBytes("US-ASCII");
246                                                          out.write(r1);              byte[]c1 = BASE64.decode(c0);       // challenge
247                                                          out.write(0x0d);              byte[]r0 = sasl.evaluateChallenge(c1);
248                                                          out.flush();              byte[]r1 = BASE64.encode(r0);       // response
249                                                  }              out.write(r1);
250                                                  catch (SaslException e)              out.write(0x0d);
251                                                  {              out.flush();
252                                                          // Error in SASL challenge evaluation - cancel exchange            }
253                                                          out.write(0x2a);            catch(SaslException e)
254                                                          out.write(0x0d);            {
255                                                          out.flush();              // Error in SASL challenge evaluation - cancel exchange
256                                                  }              out.write(0x2a);
257                                  }              out.write(0x0d);
258                          }              out.flush();
259                  }            }
260                  catch (SaslException e)          }
261                  {        }
262                          return false; // No provider for mechanism      }
263                  }      catch(SaslException e)
264                  catch (ClassNotFoundException e)      {
265                  {        return false;             // No provider for mechanism
266                          return false; // No javax.security.sasl classes      }
267                  }      catch(ClassNotFoundException e)
268          }      {
269          return false;             // No javax.security.sasl classes
270        }
271      }
272    
273          /**          /**
274           * Authenticate the specified user using the APOP MD5-based method.           * Authenticate the specified user using the APOP MD5-based method.
275           * This does not transmit the password in the clear, but doesn't provide           * This does not transmit the password in the clear, but doesn't provide
276           * any transport-level privacy features either.           * any transport-level privacy features either.
277           * @param username the user to authenticate           * @param username the user to authenticate
278           * @param password the user's password           * @param password the user's password
279           */           */
280          public boolean apop(String username, String password)    public boolean apop(String username, String password) throws IOException
281                  throws IOException    {
282          {      if (username == null || password == null || timestamp != null)
283                  if (username==null || password==null || timestamp!=null)        return false;
284                          return false;      // APOP <username> <digest>
285                  // APOP <username> <digest>      try
286                  try      {
287                  {        byte[]secret = password.getBytes("US-ASCII");
288                          byte[] secret = password.getBytes("US-ASCII");        // compute digest
289                          // compute digest        byte[] target = new byte[timestamp.length + secret.length];
290                          byte[] target = new byte[timestamp.length + secret.length];        System.arraycopy(timestamp, 0, target, 0, timestamp.length);
291                          System.arraycopy(timestamp, 0, target, 0, timestamp.length);        System.arraycopy(secret, 0, target, timestamp.length, secret.length);
292                          System.arraycopy(secret, 0, target, timestamp.length, secret.length);        MessageDigest md5 = MessageDigest.getInstance("MD5");
293                          MessageDigest md5 = MessageDigest.getInstance("MD5");          byte[] db = md5.digest(target);
294                          byte[] db = md5.digest(target);        // create hexadecimal representation
295                          // create hexadecimal representation        StringBuffer digest = new StringBuffer();
296                          StringBuffer digest = new StringBuffer();        for (int i = 0; i < db.length; i++)
297                          for (int i=0; i<db.length; i++)        {
298                          {          int c = (int) db[i];
299                                  int c = (int)db[i];          if (c < 0)
300                                  if (c<0)              c += 256;
301                                          c += 256;            digest.append(Integer.toHexString(c));
302                                  digest.append(Integer.toHexString(c));        }
303                          }        // send command
304                          // send command        String cmd =
305                          String cmd = new StringBuffer(APOP)          new StringBuffer(APOP).append(' ').append(username).append(' ').
306                                  .append(' ')          append(digest.toString()).toString();
307                                  .append(username)        send(cmd);
308                                  .append(' ')        return getResponse() == OK;
309                                  .append(digest.toString())      }
310                                  .toString();      catch(NoSuchAlgorithmException e)
311                          send(cmd);      {
312                          return getResponse()==OK;        Logger logger = Logger.getInstance();
313                  }        logger.log("pop3", "MD5 algorithm not found");
314                  catch (NoSuchAlgorithmException e)        return false;
315                  {      }
316                          Logger logger = Logger.getInstance();    }
                         logger.log("pop3", "MD5 algorithm not found");  
                         return false;  
                 }  
         }  
317    
318          /**          /**
319           * Authenticate the user using the basic USER and PASS handshake.           * Authenticate the user using the basic USER and PASS handshake.
320           * It is recommended to use a more secure authentication method such as           * It is recommended to use a more secure authentication method such as
321           * the <code>auth</code> or <code>apop</code> method if the server           * the <code>auth</code> or <code>apop</code> method if the server
# Line 324  public class POP3Connection Line 323  public class POP3Connection
323           * @param username the user to authenticate           * @param username the user to authenticate
324           * @param password the user's password           * @param password the user's password
325           */           */
326          public boolean login(String username, String password)    public boolean login(String username, String password) throws IOException
327                  throws IOException    {
328          {      if (username == null || password == null)
329                  if (username==null || password==null)        return false;
330                          return false;      // USER <username>
331                  // USER <username>      String cmd =
332                  String cmd = new StringBuffer(USER)        new StringBuffer(USER).append(' ').append(username).toString();
333                          .append(' ')        send(cmd);
334                          .append(username)      if (getResponse() != OK)
335                          .toString();          return false;
336                  send(cmd);      // PASS <password>
337                  if (getResponse()!=OK)        cmd = new StringBuffer(PASS).append(' ').append(password).toString();
338                          return false;        send(cmd);
339                  // PASS <password>        return getResponse() == OK;
340                  cmd = new StringBuffer(PASS)    }
                         .append(' ')  
                         .append(password)  
                         .toString();  
                 send(cmd);  
                 return getResponse()==OK;  
         }  
341    
342    /**    /**
343     * Attempts to start TLS on the specified connection.     * Attempts to start TLS on the specified connection.
344     * See RFC 2595 for details     * See RFC 2595 for details
345     * @return true if successful, false otherwise     * @return true if successful, false otherwise
346     */     */
347    public boolean stls()    public boolean stls() throws IOException
     throws IOException  
348    {    {
349      try      try
350      {      {
351        // Use SSLSocketFactory to negotiate a TLS session and wrap the        // Use SSLSocketFactory to negotiate a TLS session and wrap the
352                          // current socket.        // current socket.
353                          SSLSocketFactory factory =        SSLSocketFactory factory =
354                                  (SSLSocketFactory)SSLSocketFactory.getDefault();          (SSLSocketFactory) SSLSocketFactory.getDefault();
355        
356                          send(STLS);          send(STLS);
357                          if (getResponse()!=OK)        if (getResponse() != OK)
358                                  return false;            return false;
359                            
360                          socket = factory.createSocket(socket,          socket = factory.createSocket(socket,
361                                          socket.getInetAddress().getHostName(),                                        socket.getInetAddress().getHostName(),
362                                          socket.getPort(),                                        socket.getPort(), true);
363                                          true);  
364                                  // set up streams
365                          // set up streams        InputStream in = socket.getInputStream();
366                          InputStream in = socket.getInputStream();          in = new BufferedInputStream(in);
367                          in = new BufferedInputStream(in);          in = new CRLFInputStream(in);
368                          in = new CRLFInputStream(in);          this.in = new LineInputStream(in);
369                          this.in = new LineInputStream(in);        OutputStream out = socket.getOutputStream();
370                          OutputStream out = socket.getOutputStream();          out = new BufferedOutputStream(out);
371                          out = new BufferedOutputStream(out);          this.out = new CRLFOutputStream(out);
372                          this.out = new CRLFOutputStream(out);  
373                                    return true;
       return true;  
374      }      }
375      catch (ClassNotFoundException e)      catch(ClassNotFoundException e)
376      {      {
377        return false; // No javax.net classes in runtime        return false;             // No javax.net classes in runtime
378      }      }
379    }    }
380      
381          /**          /**
382           * Returns the number of messages in the maildrop.           * Returns the number of messages in the maildrop.
383           */           */
384          public int stat()    public int stat() throws IOException
385                  throws IOException    {
386          {      send(STAT);
387                  send(STAT);      if (getResponse() != OK)
388                  if (getResponse()!=OK)        throw new ProtocolException("STAT failed: " + response);
389                          throw new ProtocolException("STAT failed: "+response);        try
390                  try      {
391                  {        return Integer.parseInt(response.substring(0, response.indexOf(' ')));
392                          return Integer.parseInt(response.substring(0, response.indexOf(' ')));      }
393                  }      catch(NumberFormatException e)
394                  catch (NumberFormatException e)      {
395                  {        throw new ProtocolException("Not a number: " + response);
396                          throw new ProtocolException("Not a number: "+response);      }
397                  }      catch(ArrayIndexOutOfBoundsException e)
398                  catch (ArrayIndexOutOfBoundsException e)      {
399                  {        throw new ProtocolException("Not a STAT response: " + response);
400                          throw new ProtocolException("Not a STAT response: "+response);      }
401                  }    }
         }  
402    
403          /**          /**
404           * Returns the size of the specified message.           * Returns the size of the specified message.
405           * @param msgnum the message number           * @param msgnum the message number
406           */           */
407          public int list(int msgnum)    public int list(int msgnum) throws IOException
408                  throws IOException    {
409          {      String cmd = new StringBuffer(LIST).append(' ').append(msgnum).toString();
410                  String cmd = new StringBuffer(LIST)        send(cmd);
411                          .append(' ')      if (getResponse() != OK)
412                          .append(msgnum)        throw new ProtocolException("LIST failed: " + response);
413                          .toString();        try
414                  send(cmd);      {
415                  if (getResponse()!=OK)        return Integer.parseInt(response.substring(response.indexOf(' ') + 1));
416                          throw new ProtocolException("LIST failed: "+response);      }
417                  try      catch(NumberFormatException e)
418                  {      {
419                          return Integer.parseInt(response.substring(response.indexOf(' ')+1));        throw new ProtocolException("Not a number: " + response);
420                  }      }
421                  catch (NumberFormatException e)    }
                 {  
                         throw new ProtocolException("Not a number: "+response);  
                 }  
         }  
422    
423          /**          /**
424           * Returns an input stream containing the entire message.           * Returns an input stream containing the entire message.
425           * This input stream must be read in its entirety before further commands           * This input stream must be read in its entirety before further commands
426           * can be issued on this connection.           * can be issued on this connection.
427           * @param msgnum the message number           * @param msgnum the message number
428           */           */
429          public InputStream retr(int msgnum)    public InputStream retr(int msgnum) throws IOException
430                  throws IOException    {
431          {      String cmd = new StringBuffer(RETR).append(' ').append(msgnum).toString();
432                  String cmd = new StringBuffer(RETR)        send(cmd);
433                          .append(' ')      if (getResponse() != OK)
434                          .append(msgnum)        throw new ProtocolException("RETR failed: " + response);
435                          .toString();        return new MessageInputStream(in);
436                  send(cmd);    }
                 if (getResponse()!=OK)  
                         throw new ProtocolException("RETR failed: "+response);  
                 return new MessageInputStream(in);  
         }  
437    
438          /**          /**
439           * Marks the specified message as deleted.           * Marks the specified message as deleted.
440           * @param msgnum the message number           * @param msgnum the message number
441           */           */
442          public void dele(int msgnum)    public void dele(int msgnum) throws IOException
443                  throws IOException    {
444          {      String cmd = new StringBuffer(DELE).append(' ').append(msgnum).toString();
445                  String cmd = new StringBuffer(DELE)        send(cmd);
446                          .append(' ')      if (getResponse() != OK)
447                          .append(msgnum)        throw new ProtocolException("DELE failed: " + response);
448                          .toString();    }
                 send(cmd);  
                 if (getResponse()!=OK)  
                         throw new ProtocolException("DELE failed: "+response);  
         }  
449    
450          /**          /**
451           * Does nothing.           * Does nothing.
452           * This can be used to keep the connection alive.           * This can be used to keep the connection alive.
453           */           */
454          public void noop()    public void noop() throws IOException
455                  throws IOException    {
456          {      send(NOOP);
457                  send(NOOP);      if (getResponse() != OK)
458                  if (getResponse()!=OK)        throw new ProtocolException("NOOP failed: " + response);
459                          throw new ProtocolException("NOOP failed: "+response);    }
         }  
460    
461          /**          /**
462           * If any messages have been marked as deleted, they are unmarked.           * If any messages have been marked as deleted, they are unmarked.
463           */           */
464          public void rset()    public void rset() throws IOException
465                  throws IOException    {
466          {      send(RSET);
467                  send(RSET);      if (getResponse() != OK)
468                  if (getResponse()!=OK)        throw new ProtocolException("RSET failed: " + response);
469                          throw new ProtocolException("RSET failed: "+response);    }
         }  
470    
471    /**    /**
472     * Closes the connection.     * Closes the connection.
# Line 499  public class POP3Connection Line 475  public class POP3Connection
475           * @return true if all deleted messages were successfully removed, false           * @return true if all deleted messages were successfully removed, false
476           * otherwise           * otherwise
477     */     */
478    public boolean quit()    public boolean quit() throws IOException
     throws IOException  
479    {    {
480                  send(QUIT);      send(QUIT);
481                  int ret = getResponse();      int ret = getResponse();
482                  socket.close();        socket.close();
483                  return ret==OK;        return ret == OK;
484    }    }
485    
486          /**          /**
487           * Returns just the headers of the specified message as an input stream.           * Returns just the headers of the specified message as an input stream.
488           * The stream must be read in its entirety before further commands can be           * The stream must be read in its entirety before further commands can be
489           * issued.           * issued.
490           * @param msgnum the message number           * @param msgnum the message number
491           */           */
492          public InputStream top(int msgnum)    public InputStream top(int msgnum) throws IOException
493                  throws IOException    {
494          {      String cmd =
495                  String cmd = new StringBuffer(TOP)        new StringBuffer(TOP).append(' ').append(msgnum).append(' ').append(0).
496                          .append(' ')        toString();
497                          .append(msgnum)        send(cmd);
498                          .append(' ')      if (getResponse() != OK)
499                          .append(0)        throw new ProtocolException("TOP failed: " + response);
500                          .toString();        return new MessageInputStream(in);
501                  send(cmd);    }
                 if (getResponse()!=OK)  
                         throw new ProtocolException("TOP failed: "+response);  
                 return new MessageInputStream(in);  
         }  
502    
503          /**          /**
504           * Returns a unique identifier for the specified message.           * Returns a unique identifier for the specified message.
505           * @param msgnum the message number           * @param msgnum the message number
506           */           */
507          public String uidl(int msgnum)    public String uidl(int msgnum) throws IOException
508                  throws IOException    {
509          {      String cmd = new StringBuffer(UIDL).append(' ').append(msgnum).toString();
510                  String cmd = new StringBuffer(UIDL)        send(cmd);
511                          .append(' ')      if (getResponse() != OK)
512                          .append(msgnum)        throw new ProtocolException("UIDL failed: " + response);
513                          .toString();        return response.substring(response.indexOf(' ') + 1);
514                  send(cmd);    }
                 if (getResponse()!=OK)  
                         throw new ProtocolException("UIDL failed: "+response);  
                 return response.substring(response.indexOf(' ')+1);  
         }  
515    
516    /**    /**
517     * Returns a list of capabilities supported by the POP3 server.     * Returns a list of capabilities supported by the POP3 server.
518     * If the server does not support POP3 extensions, returns     * If the server does not support POP3 extensions, returns
519     * <code>null</code>.     * <code>null</code>.
520     */     */
521    public List capa()    public List capa() throws IOException
     throws IOException  
522    {    {
523      send(CAPA);      send(CAPA);
524      if (getResponse()==OK)      if (getResponse() == OK)
525      {      {
526        final String DOT = ".";        final String DOT = ".";
527        List list = new ArrayList();        List list = new ArrayList();
528        for (String line = in.readLine();        for (String line = in.readLine();
529            !DOT.equals(line);             !DOT.equals(line); line = in.readLine())
           line = in.readLine())  
530          list.add(line);          list.add(line);
531        return list;          return list;
532      }      }
533      return null;      return null;
534    }    }
# Line 573  public class POP3Connection Line 538  public class POP3Connection
538     * If <code>debug</code> is <code>true</code>,     * If <code>debug</code> is <code>true</code>,
539           * the command is logged.           * the command is logged.
540     */     */
541    protected void send(String command)    protected void send(String command) throws IOException
     throws IOException  
542    {    {
543      if (debug)      if (debug)
544                  {      {
545                          Logger logger = Logger.getInstance();        Logger logger = Logger.getInstance();
546        logger.log("pop3", "> "+command);          logger.log("pop3", "> " + command);
547                  }      }
548      out.write(command);      out.write(command);
549      out.writeln();      out.writeln();
550      out.flush();      out.flush();
# Line 591  public class POP3Connection Line 555  public class POP3Connection
555     * If <code>debug</code> is <code>true</code>,     * If <code>debug</code> is <code>true</code>,
556           * the response is logged.           * the response is logged.
557     */     */
558    protected int getResponse()    protected int getResponse() throws IOException
     throws IOException  
559    {    {
560      response = in.readLine();      response = in.readLine();
561      if (debug)      if (debug)
562                  {      {
563                          Logger logger = Logger.getInstance();        Logger logger = Logger.getInstance();
564        logger.log("pop3", "< "+response);          logger.log("pop3", "< " + response);
565                  }      }
566      if (response.indexOf(_OK)==0)      if (response.indexOf(_OK) == 0)
567      {      {
568        response = response.substring(3).trim();        response = response.substring(3).trim();
569        return OK;        return OK;
570      }      }
571      else if (response.indexOf(_ERR)==0)      else if (response.indexOf(_ERR) == 0)
572                  {      {
573        response = response.substring(4).trim();        response = response.substring(4).trim();
574                          return ERR;        return ERR;
575                  }      }
576      else if (response.indexOf(_READY)==0)      else if (response.indexOf(_READY) == 0)
577                  {      {
578        response = response.substring(2).trim();        response = response.substring(2).trim();
579                          return READY;        return READY;
580                  }      }
581                  else      else
582                  {      {
583                          throw new ProtocolException("Unexpected response: "+response);        throw new ProtocolException("Unexpected response: " + response);
584                  }      }
585    }    }
586    
587          /*    /*
588           * Parse the APOP timestamp from the server's banner greeting.     * Parse the APOP timestamp from the server's banner greeting.
589           */     */
590          byte[] parseTimestamp(String greeting)    byte[]parseTimestamp(String greeting) throws IOException
591      throws IOException    {
592          {      int bra = greeting.indexOf('<');
593                  int bra = greeting.indexOf('<');      if (bra != -1)
594                  if (bra!=-1)      {
595                  {        int ket = greeting.indexOf('>', bra);
596                          int ket = greeting.indexOf('>', bra);        if (ket != -1)
597                          if (ket!=-1)        {
598                          {          String mid = greeting.substring(bra, ket + 1);
599                                  String mid = greeting.substring(bra, ket+1);          int at = mid.indexOf('@');
600                                  int at = mid.indexOf('@');          if (at != -1)           // This is a valid RFC822 msg-id
601                                  if (at!=-1) // This is a valid RFC822 msg-id              return mid.getBytes("US-ASCII");
602                                          return mid.getBytes("US-ASCII");        }
603                          }      }
604                  }      return null;
605                  return null;    }
         }  
606    
607  }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

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