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. |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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; |
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 |
} |
} |
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 |
} |
} |
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 |
/** |
/** |
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; |
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 |
} |
} |
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 |
|
|
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 |
|
|
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 |
} |
} |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
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) |
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 |
/** |
/** |
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 |
} |
} |
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 |
} |
} |
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 |
} |
} |
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 |
} |
} |
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 |
} |
} |
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 |
/** |
/** |
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; |
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; |
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) |
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 |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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) |
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 |
} |
} |
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; |
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 |
} |
} |
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; |
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 |
} |
} |
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 |
/** |
/** |
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 |
} |
} |
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 |
} |
} |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
} |
} |
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 |
/** |
/** |
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 |
/** |
/** |
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 |
} |
} |
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 |
} |
} |
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 |
/** |
/** |
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 |
/** |
/** |
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; |
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 |
} |
} |
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; |
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 |
} |
} |
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; |
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; |
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 |
|
|
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; |
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 |
} |
} |
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; |
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 |
} |
} |
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) |
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 |
} |
} |
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; |
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 |
|
|