/[classpath]/inetlib/source/gnu/inet/imap/IMAPConnection.java
ViewVC logotype

Diff of /inetlib/source/gnu/inet/imap/IMAPConnection.java

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

revision 1.24 by dog, Thu Oct 21 15:21:55 2004 UTC revision 1.25 by dog, Thu Nov 25 22:15:05 2004 UTC
# Line 1  Line 1 
1  /*  /*
2   * $Id$   * IMAPConnection.java
3   * Copyright (C) 2003,2004 The Free Software Foundation   * Copyright (C) 2003,2004 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 85  import gnu.inet.util.SaslPlain; Line 85  import gnu.inet.util.SaslPlain;
85   * The protocol class implementing IMAP4rev1.   * The protocol class implementing IMAP4rev1.
86   *   *
87   * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>   * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  * @version $Revision$ $Date$  
88   */   */
89  public class IMAPConnection  public class IMAPConnection
90  implements IMAPConstants    implements IMAPConstants
91  {  {
92    
93    /**    /**
# Line 155  implements IMAPConstants Line 154  implements IMAPConstants
154     * Creates a new connection to the default IMAP port.     * Creates a new connection to the default IMAP port.
155     * @param host the name of the host to connect to     * @param host the name of the host to connect to
156     */     */
157    public IMAPConnection (String host)    public IMAPConnection(String host)
158      throws UnknownHostException, IOException      throws UnknownHostException, IOException
159    {    {
160      this (host, -1, 0, 0, false, null, false);      this(host, -1, 0, 0, false, null, false);
161    }    }
162        
163    /**    /**
# Line 166  implements IMAPConstants Line 165  implements IMAPConstants
165     * @param host the name of the host to connect to     * @param host the name of the host to connect to
166     * @param port the port to connect to, or -1 for the default     * @param port the port to connect to, or -1 for the default
167     */     */
168    public IMAPConnection (String host, int port)    public IMAPConnection(String host, int port)
169      throws UnknownHostException, IOException      throws UnknownHostException, IOException
170    {    {
171      this (host, port, 0, 0, false, null, false);      this(host, port, 0, 0, false, null, false);
172    }    }
173        
174    /**    /**
# Line 180  implements IMAPConstants Line 179  implements IMAPConstants
179     * @param timeout the socket timeout     * @param timeout the socket timeout
180     * @param debug log debugging information     * @param debug log debugging information
181     */     */
182    public IMAPConnection (String host, int port,    public IMAPConnection(String host, int port,
183                           int connectionTimeout, int timeout,                          int connectionTimeout, int timeout,
184                           boolean debug)                          boolean debug)
185      throws UnknownHostException, IOException      throws UnknownHostException, IOException
186    {    {
187      this (host, port, connectionTimeout, timeout, false, null, debug);      this(host, port, connectionTimeout, timeout, false, null, debug);
188    }    }
189        
190    /**    /**
# Line 195  implements IMAPConstants Line 194  implements IMAPConstants
194     * @param tm a trust manager used to check SSL certificates, or null to     * @param tm a trust manager used to check SSL certificates, or null to
195     * use the default     * use the default
196     */     */
197    public IMAPConnection (String host, int port, TrustManager tm)    public IMAPConnection(String host, int port, TrustManager tm)
198      throws UnknownHostException, IOException      throws UnknownHostException, IOException
199    {    {
200      this (host, port, 0, 0, true, tm, false);      this(host, port, 0, 0, true, tm, false);
201    }    }
202        
203    /**    /**
# Line 212  implements IMAPConstants Line 211  implements IMAPConstants
211     * use the default     * use the default
212     * @param debug log debugging information     * @param debug log debugging information
213     */     */
214    public IMAPConnection (String host, int port,    public IMAPConnection(String host, int port,
215                           int connectionTimeout, int timeout,                          int connectionTimeout, int timeout,
216                           boolean secure, TrustManager tm,                          boolean secure, TrustManager tm,
217                           boolean debug)                          boolean debug)
218      throws UnknownHostException, IOException      throws UnknownHostException, IOException
219    {    {
220      this.debug = debug;      this.debug = debug;
# Line 227  implements IMAPConstants Line 226  implements IMAPConstants
226      // Set up socket      // Set up socket
227      try      try
228        {        {
229          socket = new Socket ();          socket = new Socket();
230          InetSocketAddress address = new InetSocketAddress (host, port);          InetSocketAddress address = new InetSocketAddress(host, port);
231          if (connectionTimeout > 0)          if (connectionTimeout > 0)
232            {            {
233              socket.connect (address, connectionTimeout);              socket.connect(address, connectionTimeout);
234            }            }
235          else          else
236            {            {
237              socket.connect (address);              socket.connect(address);
238            }            }
239          if (timeout > 0)          if (timeout > 0)
240            {            {
241              socket.setSoTimeout (timeout);              socket.setSoTimeout(timeout);
242            }            }
243          if (secure)          if (secure)
244            {            {
245              SSLSocketFactory factory = getSSLSocketFactory (tm);              SSLSocketFactory factory = getSSLSocketFactory(tm);
246              SSLSocket ss =              SSLSocket ss =
247                (SSLSocket) factory.createSocket (socket, host, port, true);                (SSLSocket) factory.createSocket(socket, host, port, true);
248              String[] protocols = { "TLSv1", "SSLv3" };              String[] protocols = { "TLSv1", "SSLv3" };
249              ss.setEnabledProtocols (protocols);              ss.setEnabledProtocols(protocols);
250              ss.setUseClientMode (true);              ss.setUseClientMode(true);
251              ss.startHandshake ();              ss.startHandshake();
252              socket = ss;              socket = ss;
253            }            }
254        }        }
255      catch (GeneralSecurityException e)      catch (GeneralSecurityException e)
256        {        {
257          e.printStackTrace ();          e.printStackTrace();
258          throw new IOException (e.getMessage ());          throw new IOException(e.getMessage());
259        }        }
260            
261      InputStream in = socket.getInputStream ();      InputStream in = socket.getInputStream();
262      in = new BufferedInputStream (in);      in = new BufferedInputStream(in);
263      this.in = new IMAPResponseTokenizer (in);      this.in = new IMAPResponseTokenizer(in);
264      OutputStream out = socket.getOutputStream ();      OutputStream out = socket.getOutputStream();
265      out = new BufferedOutputStream (out);      out = new BufferedOutputStream(out);
266      this.out = new CRLFOutputStream (out);      this.out = new CRLFOutputStream(out);
267            
268      asyncResponses = new ArrayList ();      asyncResponses = new ArrayList();
269      alerts = new ArrayList ();      alerts = new ArrayList();
270    }    }
271        
272    /**    /**
273     * Sets whether debugging output should use ANSI colour escape sequences.     * Sets whether debugging output should use ANSI colour escape sequences.
274     */     */
275    public void setAnsiDebug (boolean flag)    public void setAnsiDebug(boolean flag)
276    {    {
277      ansiDebug = flag;      ansiDebug = flag;
278    }    }
# Line 281  implements IMAPConstants Line 280  implements IMAPConstants
280    /**    /**
281     * Returns a new tag for a command.     * Returns a new tag for a command.
282     */     */
283    protected String newTag ()    protected String newTag()
284    {    {
285      return TAG_PREFIX + (++tagIndex);      return TAG_PREFIX + (++tagIndex);
286    }    }
# Line 289  implements IMAPConstants Line 288  implements IMAPConstants
288    /**    /**
289     * Sends the specified IMAP tagged command to the server.     * Sends the specified IMAP tagged command to the server.
290     */     */
291    protected void sendCommand (String tag, String command)    protected void sendCommand(String tag, String command)
292      throws IOException      throws IOException
293    {    {
294      if (debug)      if (debug)
295        {        {
296          Logger logger = Logger.getInstance ();          Logger logger = Logger.getInstance();
297          logger.log("imap", "> " + tag + " " + command);          logger.log("imap", "> " + tag + " " + command);
298        }        }
299      out.write (tag + ' ' + command);      out.write(tag + ' ' + command);
300      out.writeln ();      out.writeln();
301      out.flush ();      out.flush();
302    }    }
303        
304    /**    /**
# Line 308  implements IMAPConstants Line 307  implements IMAPConstants
307     * @return true if OK was received, or false if NO was received     * @return true if OK was received, or false if NO was received
308     * @exception IOException if BAD was received or an I/O error occurred     * @exception IOException if BAD was received or an I/O error occurred
309     */     */
310    protected boolean invokeSimpleCommand (String command)    protected boolean invokeSimpleCommand(String command)
311      throws IOException      throws IOException
312    {    {
313      String tag = newTag ();      String tag = newTag();
314      sendCommand (tag, command);      sendCommand(tag, command);
315      while (true)      while (true)
316        {        {
317          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
318          String id = response.getID ();          String id = response.getID();
319          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
320            {            {
321              processAlerts (response);              processAlerts(response);
322              if (id == OK)              if (id == OK)
323                {                {
324                  return true;                  return true;
# Line 330  implements IMAPConstants Line 329  implements IMAPConstants
329                }                }
330              else              else
331                {                {
332                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
333                }                }
334            }            }
335          else if (response.isUntagged ())          else if (response.isUntagged())
336            {            {
337              asyncResponses.add (response);              asyncResponses.add(response);
338            }            }
339          else          else
340            {            {
341              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
342            }            }
343        }        }
344    }    }
# Line 353  implements IMAPConstants Line 352  implements IMAPConstants
352     * <li>An untagged error response</li>     * <li>An untagged error response</li>
353     * <li>A continuation response</li>     * <li>A continuation response</li>
354     */     */
355    protected IMAPResponse readResponse ()    protected IMAPResponse readResponse()
356      throws IOException      throws IOException
357    {    {
358      IMAPResponse response = in.next ();      IMAPResponse response = in.next();
359      if (debug)      if (debug)
360        {        {
361          Logger logger = Logger.getInstance ();          Logger logger = Logger.getInstance();
362          if (response == null)          if (response == null)
363            {            {
364              logger.log("imap", "<EOF");              logger.log("imap", "<EOF");
365            }            }
366          else if (ansiDebug)          else if (ansiDebug)
367            {            {
368              logger.log("imap", "< " + response.toANSIString ());              logger.log("imap", "< " + response.toANSIString());
369            }            }
370          else          else
371            {            {
372              logger.log("imap", "< " + response.toString ());              logger.log("imap", "< " + response.toString());
373            }            }
374        }        }
375      if (response == null)      if (response == null)
376        {        {
377          throw new IOException ("EOF");          throw new IOException("EOF");
378        }        }
379      return response;      return response;
380    }    }
381        
382    // -- Alert notifications --    // -- Alert notifications --
383        
384    private void processAlerts (IMAPResponse response)    private void processAlerts(IMAPResponse response)
385    {    {
386      List code = response.getResponseCode ();      List code = response.getResponseCode();
387      if (code != null && code.contains (ALERT))      if (code != null && code.contains(ALERT))
388        {        {
389          alerts.add (response.getText ());          alerts.add(response.getText());
390        }        }
391    }    }
392        
393    /**    /**
394     * Indicates if there are alerts pending for the user-agent.     * Indicates if there are alerts pending for the user-agent.
395     */     */
396    public boolean alertsPending ()    public boolean alertsPending()
397    {    {
398      return (alerts.size () > 0);      return (alerts.size() > 0);
399    }    }
400        
401    /**    /**
402     * Returns the pending alerts for the user-agent as an array.     * Returns the pending alerts for the user-agent as an array.
403     */     */
404    public String[] getAlerts ()    public String[] getAlerts()
405    {    {
406      String[] a = new String[alerts.size ()];      String[] a = new String[alerts.size()];
407      alerts.toArray (a);      alerts.toArray(a);
408      alerts.clear ();             // flush      alerts.clear();             // flush
409      return a;      return a;
410    }    }
411        
# Line 415  implements IMAPConstants Line 414  implements IMAPConstants
414    /**    /**
415     * Returns a list of the capabilities of the IMAP server.     * Returns a list of the capabilities of the IMAP server.
416     */     */
417    public List capability ()    public List capability()
418      throws IOException      throws IOException
419    {    {
420      String tag = newTag ();      String tag = newTag();
421      sendCommand (tag, CAPABILITY);      sendCommand(tag, CAPABILITY);
422      List capabilities = new ArrayList ();      List capabilities = new ArrayList();
423      while (true)      while (true)
424        {        {
425          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
426          String id = response.getID ();          String id = response.getID();
427          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
428            {            {
429              processAlerts (response);              processAlerts(response);
430              if (id == OK)              if (id == OK)
431                {                {
432                  if (capabilities.size () == 0)                  if (capabilities.size() == 0)
433                    {                    {
434                      // The capability list may be contained in the                      // The capability list may be contained in the
435                      // response text.                      // response text.
436                      addTokens (capabilities, response.getText ());                      addTokens(capabilities, response.getText());
437                    }                    }
438                  return capabilities;                  return capabilities;
439                }                }
440              else              else
441                {                {
442                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
443                }                }
444            }            }
445          else if (response.isUntagged ())          else if (response.isUntagged())
446            {            {
447              if (id == CAPABILITY)              if (id == CAPABILITY)
448                {                {
449                  // The capability list may be contained in the                  // The capability list may be contained in the
450                  // response text.                  // response text.
451                  addTokens (capabilities, response.getText ());                  addTokens(capabilities, response.getText());
452                }                }
453              else if (id == OK)              else if (id == OK)
454                {                {
455                  // The capability list may be contained in the                  // The capability list may be contained in the
456                  // response code.                  // response code.
457                  List code = response.getResponseCode ();                  List code = response.getResponseCode();
458                  int len = (code == null) ? 0 : code.size ();                  int len = (code == null) ? 0 : code.size();
459                  if (len > 0 && CAPABILITY.equals (code.get (0)))                  if (len > 0 && CAPABILITY.equals(code.get(0)))
460                    {                    {
461                      for (int i = 1; i < len; i++)                      for (int i = 1; i < len; i++)
462                        {                        {
463                          String token = (String) code.get (i);                          String token = (String) code.get(i);
464                          if (!capabilities.contains (token))                          if (!capabilities.contains(token))
465                            {                            {
466                              capabilities.add (token);                              capabilities.add(token);
467                            }                            }
468                        }                        }
469                    }                    }
470                  else                  else
471                    {                    {
472                      asyncResponses.add (response);                      asyncResponses.add(response);
473                    }                    }
474                }                }
475              else              else
476                {                {
477                  asyncResponses.add (response);                  asyncResponses.add(response);
478                }                }
479            }            }
480          else          else
481            {            {
482              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
483            }            }
484        }        }
485    }    }
486        
487    private void addTokens (List list, String text)    private void addTokens(List list, String text)
488    {    {
489      int start = 0;      int start = 0;
490      int end = text.indexOf (' ');      int end = text.indexOf(' ');
491      String token;      String token;
492      while (end != -1)      while (end != -1)
493        {        {
494          token = text.substring (start, end);          token = text.substring(start, end);
495          if (!list.contains (token))          if (!list.contains(token))
496            {            {
497              list.add (token);              list.add(token);
498            }            }
499          start = end + 1;          start = end + 1;
500          end = text.indexOf (' ', start);          end = text.indexOf(' ', start);
501        }        }
502      token = text.substring (start);      token = text.substring(start);
503      if (token.length () > 0 && !list.contains (token))      if (token.length() > 0 && !list.contains(token))
504        {        {
505          list.add (token);          list.add(token);
506        }        }
507    }    }
508        
# Line 512  implements IMAPConstants Line 511  implements IMAPConstants
511     * If a change in mailbox state is detected, a new mailbox status is     * If a change in mailbox state is detected, a new mailbox status is
512     * returned, otherwise this method returns null.     * returned, otherwise this method returns null.
513     */     */
514    public MailboxStatus noop ()    public MailboxStatus noop()
515      throws IOException      throws IOException
516    {    {
517      String tag = newTag ();      String tag = newTag();
518      sendCommand (tag, NOOP);      sendCommand(tag, NOOP);
519      boolean changed = false;      boolean changed = false;
520      MailboxStatus ms = new MailboxStatus ();      MailboxStatus ms = new MailboxStatus();
521      Iterator asyncIterator = asyncResponses.iterator ();      Iterator asyncIterator = asyncResponses.iterator();
522      while (true)      while (true)
523        {        {
524          IMAPResponse response;          IMAPResponse response;
525          // Process any asynchronous responses first          // Process any asynchronous responses first
526          if (asyncIterator.hasNext ())          if (asyncIterator.hasNext())
527            {            {
528              response = (IMAPResponse) asyncIterator.next ();              response = (IMAPResponse) asyncIterator.next();
529              asyncIterator.remove ();              asyncIterator.remove();
530            }            }
531          else          else
532            {            {
533              response = readResponse ();              response = readResponse();
534            }            }
535          String id = response.getID ();          String id = response.getID();
536          if (response.isUntagged ())          if (response.isUntagged())
537            {            {
538              changed = changed || updateMailboxStatus (ms, id, response);              changed = changed || updateMailboxStatus(ms, id, response);
539            }            }
540          else if (tag.equals (response.getTag ()))          else if (tag.equals(response.getTag()))
541            {            {
542              processAlerts (response);              processAlerts(response);
543              if (id == OK)              if (id == OK)
544                {                {
545                  return changed ? ms : null;                  return changed ? ms : null;
546                }                }
547              else              else
548                {                {
549                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
550                }                }
551            }            }
552          else          else
553            {            {
554              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
555            }            }
556        }        }
557    }    }
# Line 562  implements IMAPConstants Line 561  implements IMAPConstants
561     * sockets.     * sockets.
562     * @param tm an optional trust manager to use     * @param tm an optional trust manager to use
563     */     */
564    protected SSLSocketFactory getSSLSocketFactory (TrustManager tm)    protected SSLSocketFactory getSSLSocketFactory(TrustManager tm)
565      throws GeneralSecurityException      throws GeneralSecurityException
566    {    {
567      if (tm == null)      if (tm == null)
568        {        {
569          tm = new EmptyX509TrustManager ();          tm = new EmptyX509TrustManager();
570        }        }
571      SSLContext context = SSLContext.getInstance ("TLS");      SSLContext context = SSLContext.getInstance("TLS");
572      TrustManager[] trust = new TrustManager[] { tm };      TrustManager[] trust = new TrustManager[] { tm };
573      context.init (null, trust, null);      context.init(null, trust, null);
574      return context.getSocketFactory ();      return context.getSocketFactory();
575    }    }
576        
577    /**    /**
# Line 580  implements IMAPConstants Line 579  implements IMAPConstants
579     * See RFC 2595 for details.     * See RFC 2595 for details.
580     * @return true if successful, false otherwise     * @return true if successful, false otherwise
581     */     */
582    public boolean starttls ()    public boolean starttls()
583      throws IOException      throws IOException
584    {    {
585      return starttls (new EmptyX509TrustManager ());      return starttls(new EmptyX509TrustManager());
586    }    }
587        
588    /**    /**
# Line 592  implements IMAPConstants Line 591  implements IMAPConstants
591     * @param tm the custom trust manager to use     * @param tm the custom trust manager to use
592     * @return true if successful, false otherwise     * @return true if successful, false otherwise
593     */     */
594    public boolean starttls (TrustManager tm)    public boolean starttls(TrustManager tm)
595      throws IOException      throws IOException
596    {    {
597      try      try
598        {        {
599          SSLSocketFactory factory = getSSLSocketFactory (tm);          SSLSocketFactory factory = getSSLSocketFactory(tm);
600          String hostname = socket.getInetAddress ().getHostName ();          String hostname = socket.getInetAddress().getHostName();
601          int port = socket.getPort ();          int port = socket.getPort();
602                    
603          String tag = newTag ();          String tag = newTag();
604          sendCommand (tag, STARTTLS);          sendCommand(tag, STARTTLS);
605          while (true)          while (true)
606            {            {
607              IMAPResponse response = readResponse ();              IMAPResponse response = readResponse();
608              if (response.isTagged () && tag.equals (response.getTag ()))              if (response.isTagged() && tag.equals(response.getTag()))
609                {                {
610                  processAlerts (response);                  processAlerts(response);
611                  String id = response.getID ();                  String id = response.getID();
612                  if (id == OK)                  if (id == OK)
613                    {                    {
614                      break;              // negotiate TLS                      break;              // negotiate TLS
# Line 621  implements IMAPConstants Line 620  implements IMAPConstants
620                }                }
621              else              else
622                {                {
623                  asyncResponses.add (response);                  asyncResponses.add(response);
624                }                }
625            }            }
626                    
627          SSLSocket ss =          SSLSocket ss =
628            (SSLSocket) factory.createSocket (socket, hostname, port, true);            (SSLSocket) factory.createSocket(socket, hostname, port, true);
629          String[] protocols = { "TLSv1", "SSLv3" };          String[] protocols = { "TLSv1", "SSLv3" };
630          ss.setEnabledProtocols (protocols);          ss.setEnabledProtocols(protocols);
631          ss.setUseClientMode (true);          ss.setUseClientMode(true);
632          ss.startHandshake ();          ss.startHandshake();
633                    
634          InputStream in = ss.getInputStream ();          InputStream in = ss.getInputStream();
635          in = new BufferedInputStream (in);          in = new BufferedInputStream(in);
636          this.in = new IMAPResponseTokenizer (in);          this.in = new IMAPResponseTokenizer(in);
637          OutputStream out = ss.getOutputStream ();          OutputStream out = ss.getOutputStream();
638          out = new BufferedOutputStream (out);          out = new BufferedOutputStream(out);
639          this.out = new CRLFOutputStream (out);          this.out = new CRLFOutputStream(out);
640          return true;          return true;
641        }        }
642      catch (GeneralSecurityException e)      catch (GeneralSecurityException e)
# Line 656  implements IMAPConstants Line 655  implements IMAPConstants
655    public boolean login(String username, String password)    public boolean login(String username, String password)
656      throws IOException      throws IOException
657    {    {
658      return invokeSimpleCommand (LOGIN + ' ' + quote (username) +      return invokeSimpleCommand(LOGIN + ' ' + quote(username) +
659                                  ' ' + quote (password));                                 ' ' + quote(password));
660    }    }
661        
662    /**    /**
# Line 669  implements IMAPConstants Line 668  implements IMAPConstants
668     * @param password the authentication credentials     * @param password the authentication credentials
669     * @return true if authentication was successful, false otherwise     * @return true if authentication was successful, false otherwise
670     */     */
671    public boolean authenticate (String mechanism, String username,    public boolean authenticate(String mechanism, String username,
672                                 String password)                                String password)
673      throws IOException      throws IOException
674    {    {
675      try      try
676        {        {
677          String[] m = new String[] { mechanism };          String[] m = new String[] { mechanism };
678          CallbackHandler ch = new SaslCallbackHandler (username, password);          CallbackHandler ch = new SaslCallbackHandler(username, password);
679          // Avoid lengthy callback procedure for GNU Crypto          // Avoid lengthy callback procedure for GNU Crypto
680          Properties p = new Properties ();          Properties p = new Properties();
681          p.put ("gnu.crypto.sasl.username", username);          p.put("gnu.crypto.sasl.username", username);
682          p.put ("gnu.crypto.sasl.password", password);          p.put("gnu.crypto.sasl.password", password);
683          SaslClient sasl = Sasl.createSaslClient (m, null, "imap",          SaslClient sasl = Sasl.createSaslClient(m, null, "imap",
684                                                   socket.getInetAddress ().                                                  socket.getInetAddress().
685                                                   getHostName (), p, ch);                                                  getHostName(), p, ch);
686          if (sasl == null)          if (sasl == null)
687            {            {
688              // Fall back to home-grown SASL clients              // Fall back to home-grown SASL clients
689              if ("LOGIN".equalsIgnoreCase (mechanism))              if ("LOGIN".equalsIgnoreCase(mechanism))
690                {                {
691                  sasl = new SaslLogin (username, password);                  sasl = new SaslLogin(username, password);
692                }                }
693              else if ("PLAIN".equalsIgnoreCase (mechanism))              else if ("PLAIN".equalsIgnoreCase(mechanism))
694                {                {
695                  sasl = new SaslPlain (username, password);                  sasl = new SaslPlain(username, password);
696                }                }
697              else if ("CRAM-MD5".equalsIgnoreCase (mechanism))              else if ("CRAM-MD5".equalsIgnoreCase(mechanism))
698                {                {
699                  sasl = new SaslCramMD5 (username, password);                  sasl = new SaslCramMD5(username, password);
700                }                }
701              else              else
702                {                {
703                  if (debug)                  if (debug)
704                    {                    {
705                      Logger logger = Logger.getInstance ();                      Logger logger = Logger.getInstance();
706                      logger.log("imap", mechanism + " not available");                      logger.log("imap", mechanism + " not available");
707                    }                    }
708                  return false;                  return false;
709                }                }
710            }            }
711                    
712          StringBuffer cmd = new StringBuffer (AUTHENTICATE);          StringBuffer cmd = new StringBuffer(AUTHENTICATE);
713          cmd.append (' ');          cmd.append(' ');
714          cmd.append (mechanism);          cmd.append(mechanism);
715          String tag = newTag ();          String tag = newTag();
716          sendCommand (tag, cmd.toString ());          sendCommand(tag, cmd.toString());
717          while (true)          while (true)
718            {            {
719              IMAPResponse response = readResponse ();              IMAPResponse response = readResponse();
720              if (tag.equals (response.getTag ()))              if (tag.equals(response.getTag()))
721                {                {
722                  processAlerts (response);                  processAlerts(response);
723                  String id = response.getID ();                  String id = response.getID();
724                  if (id == OK)                  if (id == OK)
725                    {                    {
726                      String qop =                      String qop =
727                        (String) sasl.getNegotiatedProperty (Sasl.QOP);                       (String) sasl.getNegotiatedProperty(Sasl.QOP);
728                      if ("auth-int".equalsIgnoreCase (qop)                      if ("auth-int".equalsIgnoreCase(qop)
729                          || "auth-conf".equalsIgnoreCase (qop))                          || "auth-conf".equalsIgnoreCase(qop))
730                        {                        {
731                          InputStream in = socket.getInputStream ();                          InputStream in = socket.getInputStream();
732                          in = new BufferedInputStream (in);                          in = new BufferedInputStream(in);
733                          in = new SaslInputStream (sasl, in);                          in = new SaslInputStream(sasl, in);
734                          this.in = new IMAPResponseTokenizer (in);                          this.in = new IMAPResponseTokenizer(in);
735                          OutputStream out = socket.getOutputStream ();                          OutputStream out = socket.getOutputStream();
736                          out = new BufferedOutputStream (out);                          out = new BufferedOutputStream(out);
737                          out = new SaslOutputStream (sasl, out);                          out = new SaslOutputStream(sasl, out);
738                          this.out = new CRLFOutputStream (out);                          this.out = new CRLFOutputStream(out);
739                        }                        }
740                      return true;                      return true;
741                    }                    }
# Line 746  implements IMAPConstants Line 745  implements IMAPConstants
745                    }                    }
746                  else if (id == BAD)                  else if (id == BAD)
747                    {                    {
748                      throw new IMAPException (id, response.getText ());                      throw new IMAPException(id, response.getText());
749                    }                    }
750                }                }
751              else if (response.isContinuation ())              else if (response.isContinuation())
752                {                {
753                  try                  try
754                    {                    {
755                      byte[] c0 = response.getText ().getBytes (US_ASCII);                      byte[] c0 = response.getText().getBytes(US_ASCII);
756                      byte[] c1 = BASE64.decode (c0);       // challenge                      byte[] c1 = BASE64.decode(c0);       // challenge
757                      byte[] r0 = sasl.evaluateChallenge (c1);                      byte[] r0 = sasl.evaluateChallenge(c1);
758                      byte[] r1 = BASE64.encode (r0);       // response                      byte[] r1 = BASE64.encode(r0);       // response
759                      out.write (r1);                      out.write(r1);
760                      out.writeln ();                      out.writeln();
761                      out.flush ();                      out.flush();
762                      if (debug)                      if (debug)
763                        {                        {
764                          Logger logger = Logger.getInstance ();                          Logger logger = Logger.getInstance();
765                          logger.log ("imap", "> " + new String (r1, US_ASCII));                          logger.log("imap", "> " + new String(r1, US_ASCII));
766                        }                        }
767                    }                    }
768                  catch (SaslException e)                  catch (SaslException e)
769                    {                    {
770                      // Error in SASL challenge evaluation - cancel exchange                      // Error in SASL challenge evaluation - cancel exchange
771                      out.write (0x2a);                      out.write(0x2a);
772                      out.writeln ();                      out.writeln();
773                      out.flush ();                      out.flush();
774                      if (debug)                      if (debug)
775                        {                        {
776                          Logger logger = Logger.getInstance ();                          Logger logger = Logger.getInstance();
777                          logger.log ("imap", "> *");                          logger.log("imap", "> *");
778                        }                        }
779                    }                    }
780                }                }
781              else              else
782                {                {
783                  asyncResponses.add (response);                  asyncResponses.add(response);
784                }                }
785            }            }
786        }        }
# Line 789  implements IMAPConstants Line 788  implements IMAPConstants
788        {        {
789          if (debug)          if (debug)
790            {            {
791              Logger logger = Logger.getInstance ();              Logger logger = Logger.getInstance();
792              logger.error ("imap", e);              logger.error("imap", e);
793            }            }
794          return false;             // No provider for mechanism          return false;             // No provider for mechanism
795        }        }
# Line 798  implements IMAPConstants Line 797  implements IMAPConstants
797        {        {
798          if (debug)          if (debug)
799            {            {
800              Logger logger = Logger.getInstance ();              Logger logger = Logger.getInstance();
801              logger.error ("imap", e);              logger.error("imap", e);
802            }            }
803          return false;             // No javax.security.sasl classes          return false;             // No javax.security.sasl classes
804        }        }
# Line 809  implements IMAPConstants Line 808  implements IMAPConstants
808     * Logout this connection.     * Logout this connection.
809     * Underlying network resources will be freed.     * Underlying network resources will be freed.
810     */     */
811    public void logout ()    public void logout()
812      throws IOException      throws IOException
813    {    {
814      String tag = newTag ();      String tag = newTag();
815      sendCommand (tag, LOGOUT);      sendCommand(tag, LOGOUT);
816      while (true)      while (true)
817        {        {
818          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
819          if (response.isTagged () && tag.equals (response.getTag ()))          if (response.isTagged() && tag.equals(response.getTag()))
820            {            {
821              processAlerts (response);              processAlerts(response);
822              String id = response.getID ();              String id = response.getID();
823              if (id == OK)              if (id == OK)
824                {                {
825                  socket.close ();                  socket.close();
826                  return;                  return;
827                }                }
828              else              else
829                {                {
830                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
831                }                }
832            }            }
833          else          else
834            {            {
835              asyncResponses.add (response);              asyncResponses.add(response);
836            }            }
837        }        }
838    }    }
# Line 844  implements IMAPConstants Line 843  implements IMAPConstants
843     * @param mailbox the mailbox name     * @param mailbox the mailbox name
844     * @return a MailboxStatus containing the state of the selected mailbox     * @return a MailboxStatus containing the state of the selected mailbox
845     */     */
846    public MailboxStatus select (String mailbox)    public MailboxStatus select(String mailbox)
847      throws IOException      throws IOException
848    {    {
849      return selectImpl (mailbox, SELECT);      return selectImpl(mailbox, SELECT);
850    }    }
851        
852    /**    /**
# Line 856  implements IMAPConstants Line 855  implements IMAPConstants
855     * @param mailbox the mailbox name     * @param mailbox the mailbox name
856     * @return a MailboxStatus containing the state of the selected mailbox     * @return a MailboxStatus containing the state of the selected mailbox
857     */     */
858    public MailboxStatus examine (String mailbox)    public MailboxStatus examine(String mailbox)
859      throws IOException      throws IOException
860    {    {
861      return selectImpl (mailbox, EXAMINE);      return selectImpl(mailbox, EXAMINE);
862    }    }
863    
864    protected MailboxStatus selectImpl (String mailbox, String command)    protected MailboxStatus selectImpl(String mailbox, String command)
865      throws IOException      throws IOException
866    {    {
867      String tag = newTag ();      String tag = newTag();
868      sendCommand(tag, command + ' ' + quote (UTF7imap.encode (mailbox)));      sendCommand(tag, command + ' ' + quote(UTF7imap.encode(mailbox)));
869      MailboxStatus ms = new MailboxStatus ();      MailboxStatus ms = new MailboxStatus();
870      while (true)      while (true)
871        {        {
872          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
873          String id = response.getID ();          String id = response.getID();
874          if (response.isUntagged ())          if (response.isUntagged())
875            {            {
876              if (!updateMailboxStatus (ms, id, response))              if (!updateMailboxStatus(ms, id, response))
877                {                {
878                  asyncResponses.add (response);                  asyncResponses.add(response);
879                }                }
880            }            }
881          else if (tag.equals (response.getTag ()))          else if (tag.equals(response.getTag()))
882            {            {
883              processAlerts (response);              processAlerts(response);
884              if (id == OK)              if (id == OK)
885                {                {
886                  List rc = response.getResponseCode ();                  List rc = response.getResponseCode();
887                  if (rc != null && rc.size() > 0 && rc.get(0) == READ_WRITE)                  if (rc != null && rc.size() > 0 && rc.get(0) == READ_WRITE)
888                    {                    {
889                      ms.readWrite = true;                      ms.readWrite = true;
# Line 893  implements IMAPConstants Line 892  implements IMAPConstants
892                }                }
893              else              else
894                {                {
895                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
896                }                }
897            }            }
898          else          else
899            {            {
900              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
901            }            }
902        }        }
903    }    }
904        
905    protected boolean updateMailboxStatus (MailboxStatus ms, String id,    protected boolean updateMailboxStatus(MailboxStatus ms, String id,
906                                           IMAPResponse response)                                          IMAPResponse response)
907      throws IOException      throws IOException
908    {    {
909      if (id == OK)      if (id == OK)
910        {        {
911          boolean changed = false;          boolean changed = false;
912          List rc = response.getResponseCode ();          List rc = response.getResponseCode();
913          int len = (rc == null) ? 0 : rc.size ();          int len = (rc == null) ? 0 : rc.size();
914          for (int i = 0; i < len; i++)          for (int i = 0; i < len; i++)
915            {            {
916              Object ocmd = rc.get (i);              Object ocmd = rc.get(i);
917              if (ocmd instanceof String)              if (ocmd instanceof String)
918                {                {
919                  String cmd = (String) ocmd;                  String cmd = (String) ocmd;
920                  if (i + 1 < len)                  if (i + 1 < len)
921                    {                    {
922                      Object oparam = rc.get (i + 1);                      Object oparam = rc.get(i + 1);
923                      if (oparam instanceof String)                      if (oparam instanceof String)
924                        {                        {
925                          String param = (String) oparam;                          String param = (String) oparam;
# Line 929  implements IMAPConstants Line 928  implements IMAPConstants
928                              if (cmd == UNSEEN)                              if (cmd == UNSEEN)
929                                {                                {
930                                  ms.firstUnreadMessage =                                  ms.firstUnreadMessage =
931                                    Integer.parseInt (param);                                    Integer.parseInt(param);
932                                  i++;                                  i++;
933                                  changed = true;                                  changed = true;
934                                }                                }
935                              else if (cmd == UIDVALIDITY)                              else if (cmd == UIDVALIDITY)
936                                {                                {
937                                  ms.uidValidity = Integer.parseInt (param);                                  ms.uidValidity = Integer.parseInt(param);
938                                  i++;                                  i++;
939                                  changed = true;                                  changed = true;
940                                }                                }
941                            }                            }
942                          catch(NumberFormatException e)                          catch (NumberFormatException e)
943                            {                            {
944                                throw new ProtocolException("Illegal " + cmd +                              throw new ProtocolException("Illegal " + cmd +
945                                                            " value: " + param);                                                          " value: " + param);
946                            }                            }
947                        }                        }
948                      else if (oparam instanceof List)                      else if (oparam instanceof List)
# Line 962  implements IMAPConstants Line 961  implements IMAPConstants
961        }        }
962      else if (id == EXISTS)      else if (id == EXISTS)
963        {        {
964          ms.messageCount = response.getCount ();          ms.messageCount = response.getCount();
965          return true;          return true;
966        }        }
967      else if (id == RECENT)      else if (id == RECENT)
968        {        {
969          ms.newMessageCount = response.getCount ();          ms.newMessageCount = response.getCount();
970          return true;          return true;
971        }        }
972      else if (id == FLAGS)      else if (id == FLAGS)
973        {        {
974          ms.flags = response.getResponseCode ();          ms.flags = response.getResponseCode();
975          return true;          return true;
976        }        }
977      else      else
# Line 986  implements IMAPConstants Line 985  implements IMAPConstants
985     * @param mailbox the mailbox name     * @param mailbox the mailbox name
986     * @return true if the mailbox was successfully created, false otherwise     * @return true if the mailbox was successfully created, false otherwise
987     */     */
988    public boolean create (String mailbox)    public boolean create(String mailbox)
989      throws IOException      throws IOException
990    {    {
991      return invokeSimpleCommand (CREATE + ' ' + quote (UTF7imap.encode (mailbox)));      return invokeSimpleCommand(CREATE + ' ' + quote(UTF7imap.encode(mailbox)));
992    }    }
993        
994    /**    /**
# Line 997  implements IMAPConstants Line 996  implements IMAPConstants
996     * @param mailbox the mailbox name     * @param mailbox the mailbox name
997     * @return true if the mailbox was successfully deleted, false otherwise     * @return true if the mailbox was successfully deleted, false otherwise
998     */     */
999    public boolean delete (String mailbox)    public boolean delete(String mailbox)
1000      throws IOException      throws IOException
1001    {    {
1002      return invokeSimpleCommand (DELETE + ' ' + quote (UTF7imap.encode (mailbox)));      return invokeSimpleCommand(DELETE + ' ' + quote(UTF7imap.encode(mailbox)));
1003    }    }
1004        
1005    /**    /**
# Line 1009  implements IMAPConstants Line 1008  implements IMAPConstants
1008     * @param target the target mailbox name     * @param target the target mailbox name
1009     * @return true if the mailbox was successfully renamed, false otherwise     * @return true if the mailbox was successfully renamed, false otherwise
1010     */     */
1011    public boolean rename (String source, String target)    public boolean rename(String source, String target)
1012      throws IOException      throws IOException
1013    {    {
1014      return invokeSimpleCommand (RENAME + ' ' + quote (UTF7imap.encode (source)) +      return invokeSimpleCommand(RENAME + ' ' + quote(UTF7imap.encode(source)) +
1015                                  ' ' + quote (UTF7imap.encode (target)));                                 ' ' + quote(UTF7imap.encode(target)));
1016    }    }
1017        
1018    /**    /**
# Line 1022  implements IMAPConstants Line 1021  implements IMAPConstants
1021     * @param mailbox the mailbox name     * @param mailbox the mailbox name
1022     * @return true if the mailbox was successfully subscribed, false otherwise     * @return true if the mailbox was successfully subscribed, false otherwise
1023     */     */
1024    public boolean subscribe (String mailbox)    public boolean subscribe(String mailbox)
1025      throws IOException      throws IOException
1026    {    {
1027      return invokeSimpleCommand (SUBSCRIBE + ' ' + quote (UTF7imap.encode (mailbox)));      return invokeSimpleCommand(SUBSCRIBE + ' ' +
1028                                   quote(UTF7imap.encode(mailbox)));
1029    }    }
1030        
1031    /**    /**
# Line 1034  implements IMAPConstants Line 1034  implements IMAPConstants
1034     * @param mailbox the mailbox name     * @param mailbox the mailbox name
1035     * @return true if the mailbox was successfully unsubscribed, false otherwise     * @return true if the mailbox was successfully unsubscribed, false otherwise
1036     */     */
1037    public boolean unsubscribe (String mailbox)    public boolean unsubscribe(String mailbox)
1038      throws IOException      throws IOException
1039    {    {
1040      return invokeSimpleCommand (UNSUBSCRIBE + ' ' + quote (UTF7imap.encode (mailbox)));      return invokeSimpleCommand(UNSUBSCRIBE + ' ' +
1041                                   quote(UTF7imap.encode(mailbox)));
1042    }    }
1043        
1044    /**    /**
# Line 1047  implements IMAPConstants Line 1048  implements IMAPConstants
1048     * defined     * defined
1049     * @param mailbox a mailbox name, possibly including IMAP wildcards     * @param mailbox a mailbox name, possibly including IMAP wildcards
1050     */     */
1051    public ListEntry[] list (String reference, String mailbox)    public ListEntry[] list(String reference, String mailbox)
1052      throws IOException      throws IOException
1053    {    {
1054      return listImpl (LIST, reference, mailbox);      return listImpl(LIST, reference, mailbox);
1055    }    }
1056        
1057    /**    /**
1058     * Returns a subset of subscribed names.     * Returns a subset of subscribed names.
1059     * @see #list     * @see #list
1060     */     */
1061    public ListEntry[] lsub (String reference, String mailbox)    public ListEntry[] lsub(String reference, String mailbox)
1062      throws IOException      throws IOException
1063    {    {
1064      return listImpl (LSUB, reference, mailbox);      return listImpl(LSUB, reference, mailbox);
1065    }    }
1066        
1067    protected ListEntry[] listImpl (String command, String reference,    protected ListEntry[] listImpl(String command, String reference,
1068                                    String mailbox)                                   String mailbox)
1069      throws IOException      throws IOException
1070    {    {
1071      if (reference == null)      if (reference == null)
# Line 1075  implements IMAPConstants Line 1076  implements IMAPConstants
1076        {        {
1077          mailbox = "";          mailbox = "";
1078        }        }
1079      String tag = newTag ();      String tag = newTag();
1080      sendCommand (tag, command + ' ' +      sendCommand(tag, command + ' ' +
1081                   quote (UTF7imap.encode (reference)) + ' ' +                  quote(UTF7imap.encode(reference)) + ' ' +
1082                   quote (UTF7imap.encode (mailbox)));                  quote(UTF7imap.encode(mailbox)));
1083      List acc = new ArrayList ();      List acc = new ArrayList();
1084      while (true)      while (true)
1085        {        {
1086          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1087          String id = response.getID ();          String id = response.getID();
1088          if (response.isUntagged ())          if (response.isUntagged())
1089            {            {
1090              if (id.equals (command))              if (id.equals(command))
1091                {                {
1092                  List code = response.getResponseCode ();                  List code = response.getResponseCode();
1093                  String text = response.getText ();                  String text = response.getText();
1094                                    
1095                  // Populate entry attributes with the interned versions                  // Populate entry attributes with the interned versions
1096                  // of the response code.                  // of the response code.
1097                  // NB IMAP servers do not necessarily pay attention to case.                  // NB IMAP servers do not necessarily pay attention to case.
1098                  int alen = (code == null) ? 0 : code.size ();                  int alen = (code == null) ? 0 : code.size();
1099                  boolean noinferiors = false;                  boolean noinferiors = false;
1100                  boolean noselect = false;                  boolean noselect = false;
1101                  boolean marked = false;                  boolean marked = false;
1102                  boolean unmarked = false;                  boolean unmarked = false;
1103                  for (int i = 0; i < alen; i++)                  for (int i = 0; i < alen; i++)
1104                    {                    {
1105                      String attribute = (String) code.get (i);                      String attribute = (String) code.get(i);
1106                      if (attribute.equalsIgnoreCase (LIST_NOINFERIORS))                      if (attribute.equalsIgnoreCase(LIST_NOINFERIORS))
1107                        {                        {
1108                          noinferiors = true;                          noinferiors = true;
1109                        }                        }
1110                      else if (attribute.equalsIgnoreCase (LIST_NOSELECT))                      else if (attribute.equalsIgnoreCase(LIST_NOSELECT))
1111                        {                        {
1112                          noselect = true;                          noselect = true;
1113                        }                        }
1114                      else if (attribute.equalsIgnoreCase (LIST_MARKED))                      else if (attribute.equalsIgnoreCase(LIST_MARKED))
1115                        {                        {
1116                          marked = true;                          marked = true;
1117                        }                        }
1118                      else if (attribute.equalsIgnoreCase (LIST_UNMARKED))                      else if (attribute.equalsIgnoreCase(LIST_UNMARKED))
1119                        {                        {
1120                          unmarked = true;                          unmarked = true;
1121                        }                        }
1122                    }                    }
1123                  int si = text.indexOf (' ');                  int si = text.indexOf(' ');
1124                  char delimiter = '\u0000';                  char delimiter = '\u0000';
1125                  String d = text.substring (0, si);                  String d = text.substring(0, si);
1126                  if (!d.equalsIgnoreCase (NIL))                  if (!d.equalsIgnoreCase(NIL))
1127                    {                    {
1128                      delimiter = stripQuotes (d).charAt (0);                      delimiter = stripQuotes(d).charAt(0);
1129                    }                    }
1130                  String mbox = stripQuotes (text.substring (si + 1));                  String mbox = stripQuotes(text.substring(si + 1));
1131                  mbox = UTF7imap.decode (mbox);                  mbox = UTF7imap.decode(mbox);
1132                  ListEntry entry = new ListEntry (mbox, delimiter, noinferiors,                  ListEntry entry = new ListEntry(mbox, delimiter, noinferiors,
1133                                                   noselect, marked, unmarked);                                                  noselect, marked, unmarked);
1134                  acc.add (entry);                  acc.add(entry);
1135                }                }
1136              else              else
1137                {                {
1138                  asyncResponses.add (response);                  asyncResponses.add(response);
1139                }                }
1140            }            }
1141          else if (tag.equals (response.getTag ()))          else if (tag.equals(response.getTag()))
1142            {            {
1143              processAlerts (response);              processAlerts(response);
1144              if (id == OK)              if (id == OK)
1145                {                {
1146                  ListEntry[] entries = new ListEntry[acc.size ()];                  ListEntry[] entries = new ListEntry[acc.size()];
1147                  acc.toArray (entries);                  acc.toArray(entries);
1148                  return entries;                  return entries;
1149                }                }
1150              else              else
1151                {                {
1152                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1153                }                }
1154            }            }
1155          else          else
1156            {            {
1157              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1158            }            }
1159        }        }
1160    }    }
# Line 1161  implements IMAPConstants Line 1162  implements IMAPConstants
1162    /**    /**
1163     * Requests the status of the specified mailbox.     * Requests the status of the specified mailbox.
1164     */     */
1165    public MailboxStatus status (String mailbox, String[] statusNames)    public MailboxStatus status(String mailbox, String[] statusNames)
1166      throws IOException      throws IOException
1167    {    {
1168      String tag = newTag ();      String tag = newTag();
1169      StringBuffer buffer = new StringBuffer (STATUS)      StringBuffer buffer = new StringBuffer(STATUS)
1170        .append (' ')        .append(' ')
1171        .append (quote (UTF7imap.encode (mailbox)))        .append(quote(UTF7imap.encode(mailbox)))
1172        .append (' ')        .append(' ')
1173        .append ('(');        .append('(');
1174      for (int i = 0; i < statusNames.length; i++)      for (int i = 0; i < statusNames.length; i++)
1175        {        {
1176          if (i > 0)          if (i > 0)
1177            {            {
1178              buffer.append (' ');              buffer.append(' ');
1179            }            }
1180          buffer.append (statusNames[i]);          buffer.append(statusNames[i]);
1181        }        }
1182      buffer.append (')');      buffer.append(')');
1183      sendCommand (tag, buffer.toString ());      sendCommand(tag, buffer.toString());
1184      MailboxStatus ms = new MailboxStatus ();      MailboxStatus ms = new MailboxStatus();
1185      while (true)      while (true)
1186        {        {
1187          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1188          String id = response.getID ();          String id = response.getID();
1189          if (response.isUntagged ())          if (response.isUntagged())
1190            {            {
1191              if (id == STATUS)              if (id == STATUS)
1192                {                {
1193                  List code = response.getResponseCode ();                  List code = response.getResponseCode();
1194                  int last = (code == null) ? 0 : code.size () - 1;                  int last = (code == null) ? 0 : code.size() - 1;
1195                  for (int i = 0; i < last; i += 2)                  for (int i = 0; i < last; i += 2)
1196                    {                    {
1197                      try                      try
1198                        {                        {
1199                          String statusName = ((String) code.get (i)).intern ();                          String statusName = ((String) code.get(i)).intern();
1200                          int value = Integer.parseInt ((String) code.get (i + 1));                          int value = Integer.parseInt((String) code.get(i + 1));
1201                          if (statusName == MESSAGES)                          if (statusName == MESSAGES)
1202                            {                            {
1203                              ms.messageCount = value;                              ms.messageCount = value;
# Line 1220  implements IMAPConstants Line 1221  implements IMAPConstants
1221                        }                        }
1222                      catch (NumberFormatException e)                      catch (NumberFormatException e)
1223                        {                        {
1224                          throw new IMAPException (id, "Invalid code: " + code);                          throw new IMAPException(id, "Invalid code: " + code);
1225                        }                        }
1226                    }                    }
1227                }                }
1228              else              else
1229                {                {
1230                  asyncResponses.add (response);                  asyncResponses.add(response);
1231                }                }
1232            }            }
1233          else if (tag.equals (response.getTag ()))          else if (tag.equals(response.getTag()))
1234            {            {
1235              processAlerts (response);              processAlerts(response);
1236              if (id == OK)              if (id == OK)
1237                {                {
1238                  return ms;                  return ms;
1239                }                }
1240              else              else
1241                {                {
1242                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1243                }                }
1244            }            }
1245          else          else
1246            {            {
1247              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1248            }            }
1249        }        }
1250    }    }
# Line 1254  implements IMAPConstants Line 1255  implements IMAPConstants
1255     * written and then closed.     * written and then closed.
1256     * @param mailbox the mailbox name     * @param mailbox the mailbox name
1257     * @param flags optional list of flags to specify for the message     * @param flags optional list of flags to specify for the message
1258     * @param content the message body (including headers)     * @param content the message body(including headers)
1259     * @return true if successful, false if error in flags/text     * @return true if successful, false if error in flags/text
1260     */     */
1261    public boolean append (String mailbox, String[] flags, byte[] content)    public boolean append(String mailbox, String[] flags, byte[] content)
1262      throws IOException      throws IOException
1263    {    {
1264      String tag = newTag ();      String tag = newTag();
1265      StringBuffer buffer = new StringBuffer (APPEND)      StringBuffer buffer = new StringBuffer(APPEND)
1266        .append (' ')        .append(' ')
1267        .append (quote (UTF7imap.encode (mailbox)))        .append(quote(UTF7imap.encode(mailbox)))
1268        .append (' ');        .append(' ');
1269      if (flags != null)      if (flags != null)
1270        {        {
1271          buffer.append ('(');          buffer.append('(');
1272          for (int i = 0; i < flags.length; i++)          for (int i = 0; i < flags.length; i++)
1273            {            {
1274              if (i > 0)              if (i > 0)
1275                {                {
1276                  buffer.append (' ');                  buffer.append(' ');
1277                }                }
1278              buffer.append (flags[i]);              buffer.append(flags[i]);
1279            }            }
1280          buffer.append (')');          buffer.append(')');
1281          buffer.append (' ');          buffer.append(' ');
1282        }        }
1283      buffer.append ('{');      buffer.append('{');
1284      buffer.append (content.length);      buffer.append(content.length);
1285      buffer.append ('}');      buffer.append('}');
1286      sendCommand (tag, buffer.toString ());      sendCommand(tag, buffer.toString());
1287      IMAPResponse response = readResponse ();      IMAPResponse response = readResponse();
1288      if (!response.isContinuation ())      if (!response.isContinuation())
1289        {        {
1290          throw new IMAPException (response.getID (), response.getText ());          throw new IMAPException(response.getID(), response.getText());
1291        }        }
1292      out.write (content);         // write the message body      out.write(content);         // write the message body
1293      out.writeln ();      out.writeln();
1294      out.flush ();      out.flush();
1295      while (true)      while (true)
1296        {        {
1297          response = readResponse ();          response = readResponse();
1298          String id = response.getID ();          String id = response.getID();
1299          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
1300            {            {
1301              processAlerts (response);              processAlerts(response);
1302              if (id == OK)              if (id == OK)
1303                {                {
1304                  return true;                  return true;
# Line 1308  implements IMAPConstants Line 1309  implements IMAPConstants
1309                }                }
1310              else              else
1311                {                {
1312                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1313                }                }
1314            }            }
1315          else if (response.isUntagged ())          else if (response.isUntagged())
1316            {            {
1317              asyncResponses.add (response);              asyncResponses.add(response);
1318            }            }
1319          else          else
1320            {            {
1321              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1322            }            }
1323        }        }
1324    }    }
# Line 1325  implements IMAPConstants Line 1326  implements IMAPConstants
1326    /**    /**
1327     * Request a checkpoint of the currently selected mailbox.     * Request a checkpoint of the currently selected mailbox.
1328     */     */
1329    public void check ()    public void check()
1330      throws IOException      throws IOException
1331    {    {
1332      invokeSimpleCommand (CHECK);      invokeSimpleCommand(CHECK);
1333    }    }
1334        
1335    /**    /**
# Line 1336  implements IMAPConstants Line 1337  implements IMAPConstants
1337     * and close the mailbox.     * and close the mailbox.
1338     * @return true if successful, false if no mailbox was selected     * @return true if successful, false if no mailbox was selected
1339     */     */
1340    public boolean close ()    public boolean close()
1341      throws IOException      throws IOException
1342    {    {
1343      return invokeSimpleCommand (CLOSE);      return invokeSimpleCommand(CLOSE);
1344    }    }
1345        
1346    /**    /**
1347     * Permanently removes all messages that have the \Delete flag set.     * Permanently removes all messages that have the \Delete flag set.
1348     * @return the numbers of the messages expunged     * @return the numbers of the messages expunged
1349     */     */
1350    public int[] expunge ()    public int[] expunge()
1351      throws IOException      throws IOException
1352    {    {
1353      String tag = newTag ();      String tag = newTag();
1354      sendCommand (tag, EXPUNGE);      sendCommand(tag, EXPUNGE);
1355      List numbers = new ArrayList ();      List numbers = new ArrayList();
1356      while (true)      while (true)
1357        {        {
1358          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1359          String id = response.getID ();          String id = response.getID();
1360          if (response.isUntagged ())          if (response.isUntagged())
1361            {            {
1362              if (id == EXPUNGE)              if (id == EXPUNGE)
1363                {                {
1364                  numbers.add (new Integer (response.getCount ()));                  numbers.add(new Integer(response.getCount()));
1365                }                }
1366              else              else
1367                {                {
1368                  asyncResponses.add (response);                  asyncResponses.add(response);
1369                }                }
1370            }            }
1371          else if (tag.equals (response.getTag ()))          else if (tag.equals(response.getTag()))
1372            {            {
1373              processAlerts (response);              processAlerts(response);
1374              if (id == OK)              if (id == OK)
1375                {                {
1376                  int len = numbers.size ();                  int len = numbers.size();
1377                  int[] mn = new int[len];                  int[] mn = new int[len];
1378                  for (int i = 0; i < len; i++)                  for (int i = 0; i < len; i++)
1379                    {                    {
1380                      mn[i] = ((Integer) numbers.get (i)).intValue ();                      mn[i] = ((Integer) numbers.get(i)).intValue();
1381                    }                    }
1382                  return mn;                  return mn;
1383                }                }
1384              else              else
1385                {                {
1386                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1387                }                }
1388            }            }
1389          else          else
1390            {            {
1391              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1392            }            }
1393        }        }
1394    }    }
# Line 1396  implements IMAPConstants Line 1397  implements IMAPConstants
1397     * Searches the currently selected mailbox for messages matching the     * Searches the currently selected mailbox for messages matching the
1398     * specified criteria.     * specified criteria.
1399     */     */
1400    public int[] search (String charset, String[] criteria)    public int[] search(String charset, String[] criteria)
1401      throws IOException      throws IOException
1402    {    {
1403      String tag = newTag ();      String tag = newTag();
1404      StringBuffer buffer = new StringBuffer (SEARCH);      StringBuffer buffer = new StringBuffer(SEARCH);
1405      buffer.append (' ');      buffer.append(' ');
1406      if (charset != null)      if (charset != null)
1407        {        {
1408          buffer.append (charset);          buffer.append(charset);
1409          buffer.append (' ');          buffer.append(' ');
1410        }        }
1411      for (int i = 0; i < criteria.length; i++)      for (int i = 0; i < criteria.length; i++)
1412        {        {
1413          if (i > 0)          if (i > 0)
1414            {            {
1415              buffer.append (' ');              buffer.append(' ');
1416            }            }
1417          buffer.append (criteria[i]);          buffer.append(criteria[i]);
1418        }        }
1419      sendCommand (tag, buffer.toString ());      sendCommand(tag, buffer.toString());
1420      List list = new ArrayList ();      List list = new ArrayList();
1421      while (true)      while (true)
1422        {        {
1423          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1424          String id = response.getID ();          String id = response.getID();
1425          if (response.isUntagged ())          if (response.isUntagged())
1426            {            {
1427              if (id == SEARCH)              if (id == SEARCH)
1428                {                {
1429                  String text = response.getText ();                  String text = response.getText();
1430                  try                  try
1431                    {                    {
1432                      int si = text.indexOf (' ');                      int si = text.indexOf(' ');
1433                      while (si != -1)                      while (si != -1)
1434                        {                        {
1435                          list.add (new Integer (text.substring (0, si)));                          list.add(new Integer(text.substring(0, si)));
1436                          text = text.substring (si + 1);                          text = text.substring(si + 1);
1437                          si = text.indexOf (' ');                          si = text.indexOf(' ');
1438                        }                        }
1439                      list.add (new Integer (text));                      list.add(new Integer(text));
1440                    }                    }
1441                  catch (NumberFormatException e)                  catch (NumberFormatException e)
1442                    {                    {
1443                      throw new IMAPException (id, "Expecting number: " + text);                      throw new IMAPException(id, "Expecting number: " + text);
1444                    }                    }
1445                }                }
1446              else              else
1447                {                {
1448                  asyncResponses.add (response);                  asyncResponses.add(response);
1449                }                }
1450            }            }
1451          else if (tag.equals (response.getTag ()))          else if (tag.equals(response.getTag()))
1452            {            {
1453              processAlerts (response);              processAlerts(response);
1454              if (id == OK)              if (id == OK)
1455                {                {
1456                  int len = list.size ();                  int len = list.size();
1457                  int[] mn = new int[len];                  int[] mn = new int[len];
1458                  for (int i = 0; i < len; i++)                  for (int i = 0; i < len; i++)
1459                    {                    {
1460                      mn[i] = ((Integer) list.get (i)).intValue ();                      mn[i] = ((Integer) list.get(i)).intValue();
1461                    }                    }
1462                  return mn;                  return mn;
1463                }                }
1464              else              else
1465                {                {
1466                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1467                }                }
1468            }            }
1469          else          else
1470            {            {
1471              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1472            }            }
1473        }        }
1474    }    }
# Line 1477  implements IMAPConstants Line 1478  implements IMAPConstants
1478     * @param message the message number     * @param message the message number
1479     * @param fetchCommands the fetch commands, e.g. FLAGS     * @param fetchCommands the fetch commands, e.g. FLAGS
1480     */     */
1481    public MessageStatus fetch (int message, String[] fetchCommands)    public MessageStatus fetch(int message, String[] fetchCommands)
1482      throws IOException      throws IOException
1483    {    {
1484      String ids = (message == -1) ? "*" : Integer.toString (message);      String ids = (message == -1) ? "*" : Integer.toString(message);
1485      return fetchImpl (FETCH, ids, fetchCommands)[0];      return fetchImpl(FETCH, ids, fetchCommands)[0];
1486    }    }
1487    
1488    /**    /**
# Line 1491  implements IMAPConstants Line 1492  implements IMAPConstants
1492     * @param end the message number of the last message     * @param end the message number of the last message
1493     * @param fetchCommands the fetch commands, e.g. FLAGS     * @param fetchCommands the fetch commands, e.g. FLAGS
1494     */     */
1495    public MessageStatus[] fetch (int start, int end, String[] fetchCommands)    public MessageStatus[] fetch(int start, int end, String[] fetchCommands)
1496      throws IOException      throws IOException
1497    {    {
1498      StringBuffer ids = new StringBuffer ();      StringBuffer ids = new StringBuffer();
1499      ids.append ((start == -1) ? '*' : start);      ids.append((start == -1) ? '*' : start);
1500      ids.append (':');      ids.append(':');
1501      ids.append ((end == -1) ? '*' : end);      ids.append((end == -1) ? '*' : end);
1502      return fetchImpl (FETCH, ids.toString (), fetchCommands);      return fetchImpl(FETCH, ids.toString(), fetchCommands);
1503    }    }
1504    
1505    /**    /**
# Line 1506  implements IMAPConstants Line 1507  implements IMAPConstants
1507     * @param messages the message numbers     * @param messages the message numbers
1508     * @param fetchCommands the fetch commands, e.g. FLAGS     * @param fetchCommands the fetch commands, e.g. FLAGS
1509     */     */
1510    public MessageStatus[] fetch (int[] messages, String[] fetchCommands)    public MessageStatus[] fetch(int[] messages, String[] fetchCommands)
1511      throws IOException      throws IOException
1512    {    {
1513      StringBuffer ids = new StringBuffer ();      StringBuffer ids = new StringBuffer();
1514      for (int i = 0; i < messages.length; i++)      for (int i = 0; i < messages.length; i++)
1515        {        {
1516          if (i > 0)          if (i > 0)
1517            {            {
1518              ids.append (',');              ids.append(',');
1519            }            }
1520          ids.append (messages[i]);          ids.append(messages[i]);
1521        }        }
1522      return fetchImpl (FETCH, ids.toString (), fetchCommands);      return fetchImpl(FETCH, ids.toString(), fetchCommands);
1523    }    }
1524    
1525    /**    /**
# Line 1526  implements IMAPConstants Line 1527  implements IMAPConstants
1527     * @param uid the message UID     * @param uid the message UID
1528     * @param fetchCommands the fetch commands, e.g. FLAGS     * @param fetchCommands the fetch commands, e.g. FLAGS
1529     */     */
1530    public MessageStatus uidFetch (long uid, String[] fetchCommands)    public MessageStatus uidFetch(long uid, String[] fetchCommands)
1531      throws IOException      throws IOException
1532    {    {
1533      String ids = (uid == -1L) ? "*" : Long.toString (uid);      String ids = (uid == -1L) ? "*" : Long.toString(uid);
1534      return fetchImpl (UID + ' ' + FETCH, ids, fetchCommands)[0];      return fetchImpl(UID + ' ' + FETCH, ids, fetchCommands)[0];
1535    }    }
1536        
1537    /**    /**
# Line 1540  implements IMAPConstants Line 1541  implements IMAPConstants
1541     * @param end the message number of the last message     * @param end the message number of the last message
1542     * @param fetchCommands the fetch commands, e.g. FLAGS     * @param fetchCommands the fetch commands, e.g. FLAGS
1543     */     */
1544    public MessageStatus[] uidFetch (long start, long end,    public MessageStatus[] uidFetch(long start, long end,
1545                                     String[] fetchCommands)                                     String[] fetchCommands)
1546      throws IOException      throws IOException
1547    {    {
1548      StringBuffer ids = new StringBuffer ();      StringBuffer ids = new StringBuffer();
1549      ids.append ((start == -1L) ? '*' : start);      ids.append((start == -1L) ? '*' : start);
1550      ids.append (':');      ids.append(':');
1551      ids.append ((end == -1L) ? '*' : end);      ids.append((end == -1L) ? '*' : end);
1552      return fetchImpl (UID + ' ' + FETCH, ids.toString (), fetchCommands);      return fetchImpl(UID + ' ' + FETCH, ids.toString(), fetchCommands);
1553    }    }
1554        
1555    /**    /**
# Line 1556  implements IMAPConstants Line 1557  implements IMAPConstants
1557     * @param uids the message UIDs     * @param uids the message UIDs
1558     * @param fetchCommands the fetch commands, e.g. FLAGS     * @param fetchCommands the fetch commands, e.g. FLAGS
1559     */     */
1560    public MessageStatus[] uidFetch (long[] uids, String[] fetchCommands)    public MessageStatus[] uidFetch(long[] uids, String[] fetchCommands)
1561      throws IOException      throws IOException
1562    {    {
1563      StringBuffer ids = new StringBuffer ();      StringBuffer ids = new StringBuffer();
1564      for (int i = 0; i < uids.length; i++)      for (int i = 0; i < uids.length; i++)
1565        {        {
1566          if (i > 0)          if (i > 0)
1567            {            {
1568              ids.append (',');              ids.append(',');
1569            }            }
1570          ids.append (uids[i]);          ids.append(uids[i]);
1571        }        }
1572      return fetchImpl (UID + ' ' + FETCH, ids.toString (), fetchCommands);      return fetchImpl(UID + ' ' + FETCH, ids.toString(), fetchCommands);
1573    }    }
1574        
1575    private MessageStatus[] fetchImpl (String cmd, String ids,    private MessageStatus[] fetchImpl(String cmd, String ids,
1576                                       String[] fetchCommands)                                      String[] fetchCommands)
1577      throws IOException      throws IOException
1578    {    {
1579      String tag = newTag ();      String tag = newTag();
1580      StringBuffer buffer = new StringBuffer (cmd);      StringBuffer buffer = new StringBuffer(cmd);
1581      buffer.append (' ');      buffer.append(' ');
1582      buffer.append (ids);      buffer.append(ids);
1583      buffer.append (' ');      buffer.append(' ');
1584      buffer.append ('(');      buffer.append('(');
1585      for (int i = 0; i < fetchCommands.length; i++)      for (int i = 0; i < fetchCommands.length; i++)
1586        {        {
1587          if (i > 0)          if (i > 0)
1588            {            {
1589              buffer.append (' ');              buffer.append(' ');
1590            }            }
1591          buffer.append (fetchCommands[i]);          buffer.append(fetchCommands[i]);
1592        }        }
1593      buffer.append (')');      buffer.append(')');
1594      sendCommand (tag, buffer.toString ());      sendCommand(tag, buffer.toString());
1595      List list = new ArrayList ();      List list = new ArrayList();
1596      while (true)      while (true)
1597        {        {
1598          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1599          String id = response.getID ();          String id = response.getID();
1600          if (response.isUntagged ())          if (response.isUntagged())
1601            {            {
1602              if (id == FETCH)              if (id == FETCH)
1603                {                {
1604                  int msgnum = response.getCount ();                  int msgnum = response.getCount();
1605                  List code = response.getResponseCode ();                  List code = response.getResponseCode();
1606                  MessageStatus status = new MessageStatus (msgnum, code);                  MessageStatus status = new MessageStatus(msgnum, code);
1607                  list.add (status);                  list.add(status);
1608                }                }
1609              else              else
1610                {                {
1611                  asyncResponses.add (response);                  asyncResponses.add(response);
1612                }                }
1613            }            }
1614          else if (tag.equals (response.getTag ()))          else if (tag.equals(response.getTag()))
1615            {            {
1616              processAlerts (response);              processAlerts(response);
1617              if (id == OK)              if (id == OK)
1618                {                {
1619                  MessageStatus[] statuses = new MessageStatus[list.size ()];                  MessageStatus[] statuses = new MessageStatus[list.size()];
1620                  list.toArray (statuses);                  list.toArray(statuses);
1621                  return statuses;                  return statuses;
1622                }                }
1623              else              else
1624                {                {
1625                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1626                }                }
1627            }            }
1628          else          else
1629            {            {
1630              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1631            }            }
1632        }        }
1633    }    }
# Line 1634  implements IMAPConstants Line 1635  implements IMAPConstants
1635    /**    /**
1636     * Alters data associated with the specified message in the mailbox.     * Alters data associated with the specified message in the mailbox.
1637     * @param message the message number     * @param message the message number
1638     * @param flagCommand FLAGS, +FLAGS, -FLAGS (or .SILENT versions)     * @param flagCommand FLAGS, +FLAGS, -FLAGS(or .SILENT versions)
1639     * @param flags message flags to set     * @param flags message flags to set
1640     * @return the message status     * @return the message status
1641     */     */
1642    public MessageStatus store (int message, String flagCommand,    public MessageStatus store(int message, String flagCommand,
1643                                String[] flags)                               String[] flags)
1644      throws IOException      throws IOException
1645    {    {
1646      String ids = (message == -1) ? "*" : Integer.toString (message);      String ids = (message == -1) ? "*" : Integer.toString(message);
1647      return storeImpl (STORE, ids, flagCommand, flags)[0];      return storeImpl(STORE, ids, flagCommand, flags)[0];
1648    }    }
1649    
1650    /**    /**
# Line 1651  implements IMAPConstants Line 1652  implements IMAPConstants
1652     * mailbox.     * mailbox.
1653     * @param start the message number of the first message     * @param start the message number of the first message
1654     * @param end the message number of the last message     * @param end the message number of the last message
1655     * @param flagCommand FLAGS, +FLAGS, -FLAGS (or .SILENT versions)     * @param flagCommand FLAGS, +FLAGS, -FLAGS(or .SILENT versions)
1656     * @param flags message flags to set     * @param flags message flags to set
1657     * @return a list of message-number to current flags     * @return a list of message-number to current flags
1658     */     */
1659    public MessageStatus[] store (int start, int end, String flagCommand,    public MessageStatus[] store(int start, int end, String flagCommand,
1660                                  String[] flags)                                 String[] flags)
1661      throws IOException      throws IOException
1662    {    {
1663      StringBuffer ids = new StringBuffer ();      StringBuffer ids = new StringBuffer();
1664      ids.append ((start == -1) ? '*' : start);      ids.append((start == -1) ? '*' : start);
1665      ids.append (':');      ids.append(':');
1666      ids.append ((end == -1) ? '*' : end);      ids.append((end == -1) ? '*' : end);
1667      return storeImpl (STORE, ids.toString (), flagCommand, flags);      return storeImpl(STORE, ids.toString(), flagCommand, flags);
1668    }    }
1669    
1670    /**    /**
1671     * Alters data associated with messages in the mailbox.     * Alters data associated with messages in the mailbox.
1672     * @param messages the message numbers     * @param messages the message numbers
1673     * @param flagCommand FLAGS, +FLAGS, -FLAGS (or .SILENT versions)     * @param flagCommand FLAGS, +FLAGS, -FLAGS(or .SILENT versions)
1674     * @param flags message flags to set     * @param flags message flags to set
1675     * @return a list of message-number to current flags     * @return a list of message-number to current flags
1676     */     */
1677    public MessageStatus[] store (int[] messages, String flagCommand,    public MessageStatus[] store(int[] messages, String flagCommand,
1678                                  String[] flags)                                 String[] flags)
1679      throws IOException      throws IOException
1680    {    {
1681      StringBuffer ids = new StringBuffer ();      StringBuffer ids = new StringBuffer();
1682      for (int i = 0; i < messages.length; i++)      for (int i = 0; i < messages.length; i++)
1683        {        {
1684          if (i > 0)          if (i > 0)
1685            {            {
1686              ids.append (',');              ids.append(',');
1687            }            }
1688          ids.append (messages[i]);          ids.append(messages[i]);
1689        }        }
1690      return storeImpl (STORE, ids.toString (), flagCommand, flags);      return storeImpl(STORE, ids.toString(), flagCommand, flags);
1691    }    }
1692        
1693    /**    /**
1694     * Alters data associated with the specified message in the mailbox.     * Alters data associated with the specified message in the mailbox.
1695     * @param uid the message UID     * @param uid the message UID
1696     * @param flagCommand FLAGS, +FLAGS, -FLAGS (or .SILENT versions)     * @param flagCommand FLAGS, +FLAGS, -FLAGS(or .SILENT versions)
1697     * @param flags message flags to set     * @param flags message flags to set
1698     * @return the message status     * @return the message status
1699     */     */
1700    public MessageStatus uidStore (long uid, String flagCommand,    public MessageStatus uidStore(long uid, String flagCommand,
1701                                   String[] flags)                                  String[] flags)
1702      throws IOException      throws IOException
1703    {    {
1704      String ids = (uid == -1L) ? "*" : Long.toString (uid);      String ids = (uid == -1L) ? "*" : Long.toString(uid);
1705      return storeImpl (UID + ' ' + STORE, ids, flagCommand, flags)[0];      return storeImpl(UID + ' ' + STORE, ids, flagCommand, flags)[0];
1706    }    }
1707    
1708    /**    /**
# Line 1709  implements IMAPConstants Line 1710  implements IMAPConstants
1710     * mailbox.     * mailbox.
1711     * @param start the UID of the first message     * @param start the UID of the first message
1712     * @param end the UID of the last message     * @param end the UID of the last message
1713     * @param flagCommand FLAGS, +FLAGS, -FLAGS (or .SILENT versions)     * @param flagCommand FLAGS, +FLAGS, -FLAGS(or .SILENT versions)
1714     * @param flags message flags to set     * @param flags message flags to set
1715     * @return a list of message-number to current flags     * @return a list of message-number to current flags
1716     */     */
1717    public MessageStatus[] uidStore (long start, long end, String flagCommand,    public MessageStatus[] uidStore(long start, long end, String flagCommand,
1718                                     String[] flags)                                    String[] flags)
1719      throws IOException      throws IOException
1720    {    {
1721      StringBuffer ids = new StringBuffer ();      StringBuffer ids = new StringBuffer();
1722      ids.append ((start == -1L) ? '*' : start);      ids.append((start == -1L) ? '*' : start);
1723      ids.append (':');      ids.append(':');
1724      ids.append ((end == -1L) ? '*' : end);      ids.append((end == -1L) ? '*' : end);
1725      return storeImpl (UID + ' ' + STORE, ids.toString (), flagCommand, flags);      return storeImpl(UID + ' ' + STORE, ids.toString(), flagCommand, flags);
1726    }    }
1727    
1728    /**    /**
1729     * Alters data associated with messages in the mailbox.     * Alters data associated with messages in the mailbox.
1730     * @param uids the message UIDs     * @param uids the message UIDs
1731     * @param flagCommand FLAGS, +FLAGS, -FLAGS (or .SILENT versions)     * @param flagCommand FLAGS, +FLAGS, -FLAGS(or .SILENT versions)
1732     * @param flags message flags to set     * @param flags message flags to set
1733     * @return a list of message-number to current flags     * @return a list of message-number to current flags
1734     */     */
1735    public MessageStatus[] uidStore (long[] uids, String flagCommand,    public MessageStatus[] uidStore(long[] uids, String flagCommand,
1736                                     String[] flags)                                    String[] flags)
1737      throws IOException      throws IOException
1738    {    {
1739      StringBuffer ids = new StringBuffer ();      StringBuffer ids = new StringBuffer();
1740      for (int i = 0; i < uids.length; i++)      for (int i = 0; i < uids.length; i++)
1741        {        {
1742          if (i > 0)          if (i > 0)
1743            {            {
1744              ids.append (',');              ids.append(',');
1745            }            }
1746          ids.append (uids[i]);          ids.append(uids[i]);
1747        }        }
1748      return storeImpl (UID + ' ' + STORE, ids.toString (), flagCommand, flags);      return storeImpl(UID + ' ' + STORE, ids.toString(), flagCommand, flags);
1749    }    }
1750        
1751    private MessageStatus[] storeImpl (String cmd, String ids,    private MessageStatus[] storeImpl(String cmd, String ids,
1752                                       String flagCommand, String[] flags)                                      String flagCommand, String[] flags)
1753      throws IOException      throws IOException
1754    {    {
1755      String tag = newTag ();      String tag = newTag();
1756      StringBuffer buffer = new StringBuffer (cmd);      StringBuffer buffer = new StringBuffer(cmd);
1757      buffer.append (' ');      buffer.append(' ');
1758      buffer.append (ids);      buffer.append(ids);
1759      buffer.append (' ');      buffer.append(' ');
1760      buffer.append (flagCommand);      buffer.append(flagCommand);
1761      buffer.append (' ');      buffer.append(' ');
1762      buffer.append ('(');      buffer.append('(');
1763      for (int i = 0; i < flags.length; i++)      for (int i = 0; i < flags.length; i++)
1764        {        {
1765          if (i > 0)          if (i > 0)
1766            {            {
1767              buffer.append (' ');              buffer.append(' ');
1768            }            }
1769          buffer.append (flags[i]);          buffer.append(flags[i]);
1770        }        }
1771      buffer.append (')');      buffer.append(')');
1772      sendCommand (tag, buffer.toString ());      sendCommand(tag, buffer.toString());
1773      List list = new ArrayList ();      List list = new ArrayList();
1774      while (true)      while (true)
1775        {        {
1776          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1777          String id = response.getID ();          String id = response.getID();
1778          if (response.isUntagged ())          if (response.isUntagged())
1779            {            {
1780              int msgnum = response.getCount ();              int msgnum = response.getCount();
1781              List code = response.getResponseCode ();              List code = response.getResponseCode();
1782              // 2 different styles returned by server: FETCH or FETCH FLAGS              // 2 different styles returned by server: FETCH or FETCH FLAGS
1783              if (id == FETCH)              if (id == FETCH)
1784                {                {
1785                  MessageStatus mf = new MessageStatus (msgnum, code);                  MessageStatus mf = new MessageStatus(msgnum, code);
1786                  list.add (mf);                  list.add(mf);
1787                }                }
1788              else if (id == FETCH_FLAGS)              else if (id == FETCH_FLAGS)
1789                {                {
1790                  List base = new ArrayList ();                  List base = new ArrayList();
1791                  base.add (FLAGS);                  base.add(FLAGS);
1792                  base.add (code);                  base.add(code);
1793                  MessageStatus mf = new MessageStatus (msgnum, base);                  MessageStatus mf = new MessageStatus(msgnum, base);
1794                  list.add (mf);                  list.add(mf);
1795                }                }
1796              else              else
1797                {                {
1798                  asyncResponses.add (response);                  asyncResponses.add(response);
1799                }                }
1800            }            }
1801          else if (tag.equals (response.getTag ()))          else if (tag.equals(response.getTag()))
1802            {            {
1803              processAlerts (response);              processAlerts(response);
1804              if (id == OK)              if (id == OK)
1805                {                {
1806                  MessageStatus[] mf = new MessageStatus[list.size ()];                  MessageStatus[] mf = new MessageStatus[list.size()];
1807                  list.toArray (mf);                  list.toArray(mf);
1808                  return mf;                  return mf;
1809                }                }
1810              else              else
1811                {                {
1812                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1813                }                }
1814            }            }
1815          else          else
1816            {            {
1817              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1818            }            }
1819        }        }
1820    }    }
# Line 1823  implements IMAPConstants Line 1824  implements IMAPConstants
1824     * @param messages the message numbers     * @param messages the message numbers
1825     * @param mailbox the destination mailbox     * @param mailbox the destination mailbox
1826     */     */
1827    public boolean copy (int[] messages, String mailbox)    public boolean copy(int[] messages, String mailbox)
1828      throws IOException      throws IOException
1829    {    {
1830      if (messages == null || messages.length < 1)      if (messages == null || messages.length < 1)
1831        {        {
1832          return true;          return true;
1833        }        }
1834      StringBuffer buffer = new StringBuffer (COPY)      StringBuffer buffer = new StringBuffer(COPY)
1835        .append (' ');        .append(' ');
1836      for (int i = 0; i < messages.length; i++)      for (int i = 0; i < messages.length; i++)
1837        {        {
1838          if (i > 0)          if (i > 0)
1839            {            {
1840              buffer.append (',');              buffer.append(',');
1841            }            }
1842          buffer.append (messages[i]);          buffer.append(messages[i]);
1843        }        }
1844      buffer.append (' ').append (quote (UTF7imap.encode (mailbox)));      buffer.append(' ').append(quote(UTF7imap.encode(mailbox)));
1845      return invokeSimpleCommand (buffer.toString ());      return invokeSimpleCommand(buffer.toString());
1846    }    }
1847    
1848    /**    /**
1849     * Returns the namespaces available on the server.     * Returns the namespaces available on the server.
1850     * See RFC 2342 for details.     * See RFC 2342 for details.
1851     */     */
1852    public Namespaces namespace ()    public Namespaces namespace()
1853      throws IOException      throws IOException
1854    {    {
1855      String tag = newTag ();      String tag = newTag();
1856      sendCommand (tag, NAMESPACE);      sendCommand(tag, NAMESPACE);
1857      Namespaces namespaces = null;      Namespaces namespaces = null;
1858      while (true)      while (true)
1859        {        {
1860          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1861          String id = response.getID ();          String id = response.getID();
1862          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
1863            {            {
1864              processAlerts (response);              processAlerts(response);
1865              if (id == OK)              if (id == OK)
1866                {                {
1867                  return namespaces;                  return namespaces;
1868                }                }
1869              else              else
1870                {                {
1871                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1872                }                }
1873            }            }
1874          else if (response.isUntagged ())          else if (response.isUntagged())
1875            {            {
1876              if (NAMESPACE.equals (response.getID ()))              if (NAMESPACE.equals(response.getID()))
1877                {                {
1878                  namespaces = new Namespaces (response.getText ());                  namespaces = new Namespaces(response.getText());
1879                }                }
1880              else              else
1881                {                {
1882                  asyncResponses.add (response);                  asyncResponses.add(response);
1883                }                }
1884            }            }
1885          else          else
1886            {            {
1887              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1888            }            }
1889        }        }
1890    }    }
# Line 1895  implements IMAPConstants Line 1896  implements IMAPConstants
1896     * @param principal the authentication identifier     * @param principal the authentication identifier
1897     * @param rights the rights to assign     * @param rights the rights to assign
1898     */     */
1899    public boolean setacl (String mailbox, String principal, int rights)    public boolean setacl(String mailbox, String principal, int rights)
1900      throws IOException      throws IOException
1901    {    {
1902      String command = SETACL + ' ' + quote (UTF7imap.encode (mailbox)) +      String command = SETACL + ' ' + quote(UTF7imap.encode(mailbox)) +
1903        ' ' + UTF7imap.encode (principal) + ' ' + rightsToString (rights);        ' ' + UTF7imap.encode(principal) + ' ' + rightsToString(rights);
1904      return invokeSimpleCommand (command);      return invokeSimpleCommand(command);
1905    }    }
1906    
1907    /**    /**
# Line 1909  implements IMAPConstants Line 1910  implements IMAPConstants
1910     * @param mailbox the mailbox name     * @param mailbox the mailbox name
1911     * @param principal the authentication identifier     * @param principal the authentication identifier
1912     */     */
1913    public boolean deleteacl (String mailbox, String principal)    public boolean deleteacl(String mailbox, String principal)
1914      throws IOException      throws IOException
1915    {    {
1916      String command = DELETEACL + ' ' + quote (UTF7imap.encode (mailbox)) +      String command = DELETEACL + ' ' + quote(UTF7imap.encode(mailbox)) +
1917        ' ' + UTF7imap.encode (principal);        ' ' + UTF7imap.encode(principal);
1918      return invokeSimpleCommand (command);      return invokeSimpleCommand(command);
1919    }    }
1920    
1921    /**    /**
# Line 1923  implements IMAPConstants Line 1924  implements IMAPConstants
1924     * @param mailbox the mailbox name     * @param mailbox the mailbox name
1925     * @return a map of principal names to Integer rights     * @return a map of principal names to Integer rights
1926     */     */
1927    public Map getacl (String mailbox)    public Map getacl(String mailbox)
1928      throws IOException      throws IOException
1929    {    {
1930      String tag = newTag ();      String tag = newTag();
1931      sendCommand (tag, GETACL + ' ' + quote (UTF7imap.encode (mailbox)));      sendCommand(tag, GETACL + ' ' + quote(UTF7imap.encode(mailbox)));
1932      Map ret = new TreeMap ();      Map ret = new TreeMap();
1933      while (true)      while (true)
1934        {        {
1935          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1936          String id = response.getID ();          String id = response.getID();
1937          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
1938            {            {
1939              processAlerts (response);              processAlerts(response);
1940              if (id == OK)              if (id == OK)
1941                {                {
1942                  return ret;                  return ret;
# Line 1946  implements IMAPConstants Line 1947  implements IMAPConstants
1947                }                }
1948              else              else
1949                {                {
1950                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
1951                }                }
1952            }            }
1953          else if (response.isUntagged ())          else if (response.isUntagged())
1954            {            {
1955              if (ACL.equals (response.getID ()))              if (ACL.equals(response.getID()))
1956                {                {
1957                  String text = response.getText ();                  String text = response.getText();
1958                  List args = parseACL (text, 1);                  List args = parseACL(text, 1);
1959                  String rights = (String) args.get (2);                  String rights = (String) args.get(2);
1960                  ret.put (args.get (1), new Integer (stringToRights (rights)));                  ret.put(args.get(1), new Integer(stringToRights(rights)));
1961                }                }
1962              else              else
1963                {                {
1964                  asyncResponses.add (response);                  asyncResponses.add(response);
1965                }                }
1966            }            }
1967          else          else
1968            {            {
1969              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
1970            }            }
1971        }        }
1972    }    }
# Line 1976  implements IMAPConstants Line 1977  implements IMAPConstants
1977     * @param mailbox the mailbox name     * @param mailbox the mailbox name
1978     * @param principal the authentication identity     * @param principal the authentication identity
1979     */     */
1980    public int listrights (String mailbox, String principal)    public int listrights(String mailbox, String principal)
1981      throws IOException      throws IOException
1982    {    {
1983      String tag = newTag ();      String tag = newTag();
1984      String command = LISTRIGHTS + ' ' + quote (UTF7imap.encode (mailbox)) +      String command = LISTRIGHTS + ' ' + quote(UTF7imap.encode(mailbox)) +
1985        ' ' + UTF7imap.encode (principal);        ' ' + UTF7imap.encode(principal);
1986      sendCommand (tag, command);      sendCommand(tag, command);
1987      int ret = -1;      int ret = -1;
1988      while (true)      while (true)
1989        {        {
1990          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
1991          String id = response.getID ();          String id = response.getID();
1992          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
1993            {            {
1994              processAlerts (response);              processAlerts(response);
1995              if (id == OK)              if (id == OK)
1996                {                {
1997                  return ret;                  return ret;
# Line 2001  implements IMAPConstants Line 2002  implements IMAPConstants
2002                }                }
2003              else              else
2004                {                {
2005                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
2006                }                }
2007            }            }
2008          else if (response.isUntagged ())          else if (response.isUntagged())
2009            {            {
2010              if (LISTRIGHTS.equals (response.getID ()))              if (LISTRIGHTS.equals(response.getID()))
2011                {                {
2012                  String text = response.getText ();                  String text = response.getText();
2013                  List args = parseACL (text, 1);                  List args = parseACL(text, 1);
2014                  ret = stringToRights ((String) args.get (2));                  ret = stringToRights((String) args.get(2));
2015                }                }
2016              else              else
2017                {                {
2018                  asyncResponses.add (response);                  asyncResponses.add(response);
2019                }                }
2020            }            }
2021          else          else
2022            {            {
2023              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
2024            }            }
2025        }        }
2026    }    }
# Line 2029  implements IMAPConstants Line 2030  implements IMAPConstants
2030     * The returned rights are a logical OR of RIGHTS_* bits.     * The returned rights are a logical OR of RIGHTS_* bits.
2031     * @param mailbox the mailbox name     * @param mailbox the mailbox name
2032     */     */
2033    public int myrights (String mailbox)    public int myrights(String mailbox)
2034      throws IOException      throws IOException
2035    {    {
2036      String tag = newTag ();      String tag = newTag();
2037      String command = MYRIGHTS + ' ' + quote (UTF7imap.encode (mailbox));      String command = MYRIGHTS + ' ' + quote(UTF7imap.encode(mailbox));
2038      sendCommand (tag, command);      sendCommand(tag, command);
2039      int ret = -1;      int ret = -1;
2040      while (true)      while (true)
2041        {        {
2042          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
2043          String id = response.getID ();          String id = response.getID();
2044          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
2045            {            {
2046              processAlerts (response);              processAlerts(response);
2047              if (id == OK)              if (id == OK)
2048                {                {
2049                  return ret;                  return ret;
# Line 2053  implements IMAPConstants Line 2054  implements IMAPConstants
2054                }                }
2055              else              else
2056                {                {
2057                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
2058                }                }
2059            }            }
2060          else if (response.isUntagged ())          else if (response.isUntagged())
2061            {            {
2062              if (MYRIGHTS.equals (response.getID ()))              if (MYRIGHTS.equals(response.getID()))
2063                {                {
2064                  String text = response.getText ();                  String text = response.getText();
2065                  List args = parseACL (text, 0);                  List args = parseACL(text, 0);
2066                  ret = stringToRights ((String) args.get (2));                  ret = stringToRights((String) args.get(2));
2067                }                }
2068              else              else
2069                {                {
2070                  asyncResponses.add (response);                  asyncResponses.add(response);
2071                }                }
2072            }            }
2073          else          else
2074            {            {
2075              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
2076            }            }
2077        }        }
2078    }    }
2079    
2080    private String rightsToString (int rights)    private String rightsToString(int rights)
2081    {    {
2082      StringBuffer buf = new StringBuffer ();      StringBuffer buf = new StringBuffer();
2083      if ((rights & RIGHTS_LOOKUP) != 0)      if ((rights & RIGHTS_LOOKUP) != 0)
2084        {        {
2085          buf.append ('l');          buf.append('l');
2086        }        }
2087      if ((rights & RIGHTS_READ) != 0)      if ((rights & RIGHTS_READ) != 0)
2088        {        {
2089          buf.append ('r');          buf.append('r');
2090        }        }
2091      if ((rights & RIGHTS_SEEN) != 0)      if ((rights & RIGHTS_SEEN) != 0)
2092        {        {
2093          buf.append ('s');          buf.append('s');
2094        }        }
2095      if ((rights & RIGHTS_WRITE) != 0)      if ((rights & RIGHTS_WRITE) != 0)
2096        {        {
2097          buf.append ('w');          buf.append('w');
2098        }        }
2099      if ((rights & RIGHTS_INSERT) != 0)      if ((rights & RIGHTS_INSERT) != 0)
2100        {        {
2101          buf.append ('i');          buf.append('i');
2102        }        }
2103      if ((rights & RIGHTS_POST) != 0)      if ((rights & RIGHTS_POST) != 0)
2104        {        {
2105          buf.append ('p');          buf.append('p');
2106        }        }
2107      if ((rights & RIGHTS_CREATE) != 0)      if ((rights & RIGHTS_CREATE) != 0)
2108        {        {
2109          buf.append ('c');          buf.append('c');
2110        }        }
2111      if ((rights & RIGHTS_DELETE) != 0)      if ((rights & RIGHTS_DELETE) != 0)
2112        {        {
2113          buf.append ('d');          buf.append('d');
2114        }        }
2115      if ((rights & RIGHTS_ADMIN) != 0)      if ((rights & RIGHTS_ADMIN) != 0)
2116        {        {
2117          buf.append ('a');          buf.append('a');
2118        }        }
2119      return buf.toString ();      return buf.toString();
2120    }    }
2121    
2122    private int stringToRights (String text)    private int stringToRights(String text)
2123    {    {
2124      int ret = 0;      int ret = 0;
2125      int len = text.length ();      int len = text.length();
2126      for (int i = 0; i < len; i++)      for (int i = 0; i < len; i++)
2127        {        {
2128          switch (text.charAt (i))          switch (text.charAt(i))
2129            {            {
2130            case 'l':            case 'l':
2131              ret |= RIGHTS_LOOKUP;              ret |= RIGHTS_LOOKUP;
# Line 2162  implements IMAPConstants Line 2163  implements IMAPConstants
2163     * Parse an ACL entry into a list of 2 or 3 components: mailbox name,     * Parse an ACL entry into a list of 2 or 3 components: mailbox name,
2164     * optional principal, and rights.     * optional principal, and rights.
2165     */     */
2166    private List parseACL (String text, int prolog)    private List parseACL(String text, int prolog)
2167    {    {
2168      int len = text.length ();      int len = text.length();
2169      boolean inQuotes = false;      boolean inQuotes = false;
2170      List ret = new ArrayList ();      List ret = new ArrayList();
2171      StringBuffer buf = new StringBuffer ();      StringBuffer buf = new StringBuffer();
2172      for (int i = 0; i < len; i++)      for (int i = 0; i < len; i++)
2173        {        {
2174          char c = text.charAt (i);          char c = text.charAt(i);
2175          switch (c)          switch (c)
2176            {            {
2177            case '"':            case '"':
2178              inQuotes = !inQuotes;              inQuotes = !inQuotes;
2179              break;              break;
2180            case ' ':            case ' ':
2181              if (inQuotes || ret.size () > prolog)              if (inQuotes || ret.size() > prolog)
2182                {                {
2183                  buf.append (c);                  buf.append(c);
2184                }                }
2185              else              else
2186                {                {
2187                  ret.add (UTF7imap.decode (buf.toString ()));                  ret.add(UTF7imap.decode(buf.toString()));
2188                  buf.setLength (0);                  buf.setLength(0);
2189                }                }
2190              break;              break;
2191            default:            default:
2192              buf.append (c);              buf.append(c);
2193            }            }
2194        }        }
2195      ret.add (buf.toString ());      ret.add(buf.toString());
2196      return ret;      return ret;
2197    }    }
2198    
# Line 2201  implements IMAPConstants Line 2202  implements IMAPConstants
2202     * @param resources the list of resources and associated limits to set     * @param resources the list of resources and associated limits to set
2203     * @return the new quota, or <code>null</code> if the operation failed     * @return the new quota, or <code>null</code> if the operation failed
2204     */     */
2205    public Quota setquota (String quotaRoot, Quota.Resource[] resources)    public Quota setquota(String quotaRoot, Quota.Resource[] resources)
2206      throws IOException      throws IOException
2207    {    {
2208      // Create resource limits list      // Create resource limits list
2209      StringBuffer resourceLimits = new StringBuffer ();      StringBuffer resourceLimits = new StringBuffer();
2210      if (resources != null)      if (resources != null)
2211        {        {
2212          for (int i = 0; i < resources.length; i++)          for (int i = 0; i < resources.length; i++)
2213            {            {
2214              if (i > 0)              if (i > 0)
2215                {                {
2216                  resourceLimits.append (' ');                  resourceLimits.append(' ');
2217                }                }
2218              resourceLimits.append (resources[i].toString ());              resourceLimits.append(resources[i].toString());
2219            }            }
2220        }        }
2221      String tag = newTag ();      String tag = newTag();
2222      String command = SETQUOTA + ' ' + quote (UTF7imap.encode (quotaRoot)) +      String command = SETQUOTA + ' ' + quote(UTF7imap.encode(quotaRoot)) +
2223        ' ' + resourceLimits.toString ();        ' ' + resourceLimits.toString();
2224      sendCommand (tag, command);      sendCommand(tag, command);
2225      Quota ret = null;      Quota ret = null;
2226      while (true)      while (true)
2227        {        {
2228          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
2229          String id = response.getID ();          String id = response.getID();
2230          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
2231            {            {
2232              processAlerts (response);              processAlerts(response);
2233              if (id == OK)              if (id == OK)
2234                {                {
2235                  return ret;                  return ret;
# Line 2239  implements IMAPConstants Line 2240  implements IMAPConstants
2240                }                }
2241              else              else
2242                {                {
2243                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
2244                }                }
2245            }            }
2246          else if (response.isUntagged ())          else if (response.isUntagged())
2247            {            {
2248              if (QUOTA.equals (response.getID ()))              if (QUOTA.equals(response.getID()))
2249                {                {
2250                  ret = new Quota (response.getText ());                  ret = new Quota(response.getText());
2251                }                }
2252              else              else
2253                {                {
2254                  asyncResponses.add (response);                  asyncResponses.add(response);
2255                }                }
2256            }            }
2257          else          else
2258            {            {
2259              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
2260            }            }
2261        }        }
2262    }    }
# Line 2264  implements IMAPConstants Line 2265  implements IMAPConstants
2265     * Returns the specified quota root's resource usage and limits.     * Returns the specified quota root's resource usage and limits.
2266     * @param quotaRoot the quota root     * @param quotaRoot the quota root
2267     */     */
2268    public Quota getquota (String quotaRoot)    public Quota getquota(String quotaRoot)
2269      throws IOException      throws IOException
2270    {    {
2271      String tag = newTag ();      String tag = newTag();
2272      String command = GETQUOTA + ' ' + quote (UTF7imap.encode (quotaRoot));      String command = GETQUOTA + ' ' + quote(UTF7imap.encode(quotaRoot));
2273      sendCommand (tag, command);      sendCommand(tag, command);
2274      Quota ret = null;      Quota ret = null;
2275      while (true)      while (true)
2276        {        {
2277          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
2278          String id = response.getID ();          String id = response.getID();
2279          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
2280            {            {
2281              processAlerts (response);              processAlerts(response);
2282              if (id == OK)              if (id == OK)
2283                {                {
2284                  return ret;                  return ret;
# Line 2288  implements IMAPConstants Line 2289  implements IMAPConstants
2289                }                }
2290              else              else
2291                {                {
2292                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
2293                }                }
2294            }            }
2295          else if (response.isUntagged ())          else if (response.isUntagged())
2296            {            {
2297              if (QUOTA.equals (response.getID ()))              if (QUOTA.equals(response.getID()))
2298                {                {
2299                  ret = new Quota (response.getText ());                  ret = new Quota(response.getText());
2300                }                }
2301              else              else
2302                {                {
2303                  asyncResponses.add (response);                  asyncResponses.add(response);
2304                }                }
2305            }            }
2306          else          else
2307            {            {
2308              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
2309            }            }
2310        }        }
2311    }    }
# Line 2313  implements IMAPConstants Line 2314  implements IMAPConstants
2314     * Returns the quotas for the given mailbox.     * Returns the quotas for the given mailbox.
2315     * @param mailbox the mailbox name     * @param mailbox the mailbox name
2316     */     */
2317    public Quota[] getquotaroot (String mailbox)    public Quota[] getquotaroot(String mailbox)
2318      throws IOException      throws IOException
2319    {    {
2320      String tag = newTag ();      String tag = newTag();
2321      String command = GETQUOTAROOT + ' ' + quote (UTF7imap.encode (mailbox));      String command = GETQUOTAROOT + ' ' + quote(UTF7imap.encode(mailbox));
2322      sendCommand (tag, command);      sendCommand(tag, command);
2323      List acc = new ArrayList ();      List acc = new ArrayList();
2324      while (true)      while (true)
2325        {        {
2326          IMAPResponse response = readResponse ();          IMAPResponse response = readResponse();
2327          String id = response.getID ();          String id = response.getID();
2328          if (tag.equals (response.getTag ()))          if (tag.equals(response.getTag()))
2329            {            {
2330              processAlerts (response);              processAlerts(response);
2331              if (id == OK)              if (id == OK)
2332                {                {
2333                  Quota[] ret = new Quota[acc.size ()];                  Quota[] ret = new Quota[acc.size()];
2334                  acc.toArray (ret);                  acc.toArray(ret);
2335                  return ret;                  return ret;
2336                }                }
2337              else if (id == NO)              else if (id == NO)
# Line 2339  implements IMAPConstants Line 2340  implements IMAPConstants
2340                }                }
2341              else              else
2342                {                {
2343                  throw new IMAPException (id, response.getText ());                  throw new IMAPException(id, response.getText());
2344                }                }
2345            }            }
2346          else if (response.isUntagged ())          else if (response.isUntagged())
2347            {            {
2348              if (QUOTA.equals (response.getID ()))              if (QUOTA.equals(response.getID()))
2349                {                {
2350                  acc.add (new Quota (response.getText ()));                  acc.add(new Quota(response.getText()));
2351                }                }
2352              else              else
2353                {                {
2354                  asyncResponses.add (response);                  asyncResponses.add(response);
2355                }                }
2356            }            }
2357          else          else
2358            {            {
2359              throw new IMAPException (id, response.getText ());              throw new IMAPException(id, response.getText());
2360            }            }
2361        }        }
2362    }    }
# Line 2365  implements IMAPConstants Line 2366  implements IMAPConstants
2366    /**    /**
2367     * Remove the quotes from each end of a string literal.     * Remove the quotes from each end of a string literal.
2368     */     */
2369    static String stripQuotes (String text)    static String stripQuotes(String text)
2370    {    {
2371      if (text.charAt (0) == '"')      if (text.charAt(0) == '"')
2372        {        {
2373          int len = text.length ();          int len = text.length();
2374          if (text.charAt (len - 1) == '"')          if (text.charAt(len - 1) == '"')
2375            {            {
2376              return text.substring (1, len - 1);              return text.substring(1, len - 1);
2377            }            }
2378        }        }
2379      return text;      return text;
# Line 2381  implements IMAPConstants Line 2382  implements IMAPConstants
2382    /**    /**
2383     * Quote the specified text if necessary.     * Quote the specified text if necessary.
2384     */     */
2385    static String quote (String text)    static String quote(String text)
2386    {    {
2387      if (text.length () == 0 || text.indexOf (' ') != -1)      if (text.length() == 0 || text.indexOf(' ') != -1)
2388        {        {
2389          StringBuffer buffer = new StringBuffer ();          StringBuffer buffer = new StringBuffer();
2390          buffer.append ('"');          buffer.append('"');
2391          buffer.append (text);          buffer.append(text);
2392          buffer.append ('"');          buffer.append('"');
2393          return buffer.toString ();          return buffer.toString();
2394        }        }
2395      return text;      return text;
2396    }    }
2397        
2398  }  }
2399    

Legend:
Removed from v.1.24  
changed lines
  Added in v.1.25

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