1 21 22 27 28 package com.sun.mail.imap.protocol; 29 30 import java.io.*; 31 import java.util.*; 32 import java.text.*; 33 import java.lang.reflect.*; 34 35 import javax.mail.*; 36 import javax.mail.internet.*; 37 import javax.mail.search.*; 38 39 import com.sun.mail.util.*; 40 import com.sun.mail.iap.*; 41 42 import com.sun.mail.imap.ACL; 43 import com.sun.mail.imap.Rights; 44 import com.sun.mail.imap.AppendUID; 45 46 59 60 public class IMAPProtocol extends Protocol { 61 62 private boolean rev1 = false; private boolean authenticated; 67 private Hashtable capabilities = null; 68 private Vector authmechs = null; 69 private String [] searchCharsets; 71 private String name; 72 private Properties props; 73 private SaslAuthenticator saslAuthenticator; 75 84 public IMAPProtocol(String name, String host, int port, 85 boolean debug, PrintStream out, Properties props, 86 boolean isSSL) throws IOException, ProtocolException { 87 super(host, port, debug, out, props, "mail." + name, isSSL); 88 89 this.name = name; 90 this.props = props; 91 92 if (capabilities == null) 93 capability(); 94 95 if (hasCapability("IMAP4rev1")) 96 rev1 = true; 97 98 searchCharsets = new String [2]; searchCharsets[0] = "UTF-8"; 100 searchCharsets[1] = MimeUtility.mimeCharset( 101 MimeUtility.getDefaultJavaCharset() 102 ); 103 } 104 105 110 public void capability() throws ProtocolException { 111 Response[] r = command("CAPABILITY", null); 113 114 if (!r[r.length-1].isOK()) 115 throw new ProtocolException(r[r.length-1].toString()); 116 117 capabilities = new Hashtable(10); 118 authmechs = new Vector(5); 119 for (int i = 0, len = r.length; i < len; i++) { 120 if (!(r[i] instanceof IMAPResponse)) 121 continue; 122 123 IMAPResponse ir = (IMAPResponse)r[i]; 124 125 if (ir.keyEquals("CAPABILITY")) 130 parseCapabilities(ir); 131 } 132 } 133 134 138 protected void setCapabilities(Response r) { 139 byte b; 140 while ((b = r.readByte()) > 0 && b != (byte)'[') 141 ; 142 if (b == 0) 143 return; 144 String s; 145 s = r.readAtom(); 146 if (!s.equalsIgnoreCase("CAPABILITY")) 147 return; 148 capabilities = new Hashtable(10); 149 authmechs = new Vector(5); 150 parseCapabilities(r); 151 } 152 153 157 protected void parseCapabilities(Response r) { 158 String s; 159 while ((s = r.readAtom(']')) != null) { 160 if (s.length() == 0) { 161 if (r.peekByte() == (byte)']') 162 break; 163 174 r.skipToken(); 175 } else { 176 capabilities.put(s.toUpperCase(), s); 177 if (s.regionMatches(true, 0, "AUTH=", 0, 5)) { 178 authmechs.addElement(s.substring(5)); 179 if (debug) 180 out.println("IMAP DEBUG: AUTH: " + s.substring(5)); 181 } 182 } 183 } 184 } 185 186 189 protected void processGreeting(Response r) throws ProtocolException { 190 super.processGreeting(r); if (r.isOK()) { setCapabilities(r); 193 return; 194 } 195 IMAPResponse ir = (IMAPResponse)r; 197 if (ir.keyEquals("PREAUTH")) { 198 authenticated = true; 199 setCapabilities(r); 200 } else 201 throw new ConnectionException(this, r); 202 } 203 204 208 public boolean isAuthenticated() { 209 return authenticated; 210 } 211 212 215 public boolean isREV1() { 216 return rev1; 217 } 218 219 222 protected boolean supportsNonSyncLiterals() { 223 return hasCapability("LITERAL+"); 224 } 225 226 229 public Response readResponse() throws IOException, ProtocolException { 230 return IMAPResponse.readResponse(this); 231 } 232 233 238 public boolean hasCapability(String c) { 239 return capabilities.containsKey(c.toUpperCase()); 240 } 241 242 248 public void disconnect() { 249 super.disconnect(); 250 authenticated = false; } 252 253 258 public void noop() throws ProtocolException { 259 if (debug) 260 out.println("IMAP DEBUG: IMAPProtocol noop"); 261 simpleCommand("NOOP", null); 262 } 263 264 269 public void logout() throws ProtocolException { 270 Response[] r = command("LOGOUT", null); 272 273 authenticated = false; 274 notifyResponseHandlers(r); 277 disconnect(); 278 } 279 280 285 public void login(String u, String p) throws ProtocolException { 286 Argument args = new Argument(); 287 args.writeString(u); 288 args.writeString(p); 289 290 simpleCommand("LOGIN", args); 291 authenticated = true; 293 } 294 295 300 public void authlogin(String u, String p) throws ProtocolException { 301 Vector v = new Vector(); 302 String tag = null; 303 Response r = null; 304 boolean done = false; 305 306 try { 307 tag = writeCommand("AUTHENTICATE LOGIN", null); 308 } catch (Exception ex) { 309 r = Response.byeResponse(ex); 311 done = true; 312 } 313 314 OutputStream os = getOutputStream(); 316 331 332 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 333 OutputStream b64os = new BASE64EncoderStream(bos, Integer.MAX_VALUE); 334 byte[] CRLF = { (byte)'\r', (byte)'\n'}; 335 boolean first = true; 336 337 while (!done) { try { 339 r = readResponse(); 340 if (r.isContinuation()) { 341 String s; 343 if (first) { s = u; 345 first = false; 346 } else s = p; 348 349 b64os.write(ASCIIUtility.getBytes(s)); 351 b64os.flush(); 353 bos.write(CRLF); os.write(bos.toByteArray()); os.flush(); bos.reset(); } else if (r.isTagged() && r.getTag().equals(tag)) 358 done = true; 360 else if (r.isBYE()) done = true; 362 else v.addElement(r); 364 } catch (Exception ioex) { 365 r = Response.byeResponse(ioex); 367 done = true; 368 } 369 } 370 371 377 Response[] responses = new Response[v.size()]; 378 v.copyInto(responses); 379 notifyResponseHandlers(responses); 380 381 handleResult(r); 383 if (r.isOK()) 385 setCapabilities(r); 386 authenticated = true; 388 } 389 390 391 403 public void authplain(String authzid, String u, String p) 404 throws ProtocolException { 405 Vector v = new Vector(); 406 String tag = null; 407 Response r = null; 408 boolean done = false; 409 410 try { 411 tag = writeCommand("AUTHENTICATE PLAIN", null); 412 } catch (Exception ex) { 413 r = Response.byeResponse(ex); 415 done = true; 416 } 417 418 OutputStream os = getOutputStream(); 420 435 436 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 437 OutputStream b64os = new BASE64EncoderStream(bos, Integer.MAX_VALUE); 438 439 while (!done) { try { 441 r = readResponse(); 442 if (r.isContinuation()) { 443 final String nullByte = "\0"; 445 String s = authzid + nullByte + u + nullByte + p; 446 447 b64os.write(ASCIIUtility.getBytes(s)); 449 b64os.flush(); 451 bos.write(CRLF); os.write(bos.toByteArray()); os.flush(); bos.reset(); } else if (r.isTagged() && r.getTag().equals(tag)) 456 done = true; 458 else if (r.isBYE()) done = true; 460 else v.addElement(r); 462 } catch (Exception ioex) { 463 r = Response.byeResponse(ioex); 465 done = true; 466 } 467 } 468 469 475 Response[] responses = new Response[v.size()]; 476 v.copyInto(responses); 477 notifyResponseHandlers(responses); 478 479 handleResult(r); 481 if (r.isOK()) 483 setCapabilities(r); 484 authenticated = true; 486 } 487 488 491 public void sasllogin(String [] allowed, String realm, String authzid, 492 String u, String p) throws ProtocolException { 493 if (saslAuthenticator == null) { 494 try { 495 Class sac = Class.forName( 496 "com.sun.mail.imap.protocol.IMAPSaslAuthenticator"); 497 Constructor c = sac.getConstructor(new Class [] { 498 IMAPProtocol.class, 499 String .class, 500 Properties.class, 501 Boolean.TYPE, 502 PrintStream.class, 503 String .class 504 }); 505 saslAuthenticator = (SaslAuthenticator)c.newInstance( 506 new Object [] { 507 this, 508 name, 509 props, 510 debug ? Boolean.TRUE : Boolean.FALSE, 511 out, 512 host 513 }); 514 } catch (Exception ex) { 515 if (debug) 516 out.println("IMAP DEBUG: Can't load SASL authenticator: " + 517 ex); 518 return; } 521 } 522 523 Vector v; 525 if (allowed != null && allowed.length > 0) { 526 v = new Vector(allowed.length); 528 for (int i = 0; i < allowed.length; i++) 529 if (authmechs.contains(allowed[i])) v.addElement(allowed[i]); 531 } else { 532 v = authmechs; 534 } 535 String [] mechs = new String [v.size()]; 536 v.copyInto(mechs); 537 if (saslAuthenticator.authenticate(mechs, realm, authzid, u, p)) 538 authenticated = true; 539 } 540 541 OutputStream getIMAPOutputStream() { 543 return getOutputStream(); 544 } 545 546 551 public void proxyauth(String u) throws ProtocolException { 552 Argument args = new Argument(); 553 args.writeString(u); 554 555 simpleCommand("PROXYAUTH", args); 556 } 557 558 563 public void startTLS() throws ProtocolException { 564 try { 565 super.startTLS("STARTTLS"); 566 } catch (ProtocolException pex) { 567 throw pex; 571 } catch (Exception ex) { 572 Response[] r = { Response.byeResponse(ex) }; 575 notifyResponseHandlers(r); 576 disconnect(); 577 } 578 } 579 580 585 public MailboxInfo select(String mbox) throws ProtocolException { 586 mbox = BASE64MailboxEncoder.encode(mbox); 588 589 Argument args = new Argument(); 590 args.writeString(mbox); 591 592 Response[] r = command("SELECT", args); 593 594 MailboxInfo minfo = new MailboxInfo(r); 597 598 notifyResponseHandlers(r); 600 601 Response response = r[r.length-1]; 602 603 if (response.isOK()) { if (response.toString().indexOf("READ-ONLY") != -1) 605 minfo.mode = Folder.READ_ONLY; 606 else 607 minfo.mode = Folder.READ_WRITE; 608 } 609 610 handleResult(response); 611 return minfo; 612 } 613 614 619 public MailboxInfo examine(String mbox) throws ProtocolException { 620 mbox = BASE64MailboxEncoder.encode(mbox); 622 623 Argument args = new Argument(); 624 args.writeString(mbox); 625 626 Response[] r = command("EXAMINE", args); 627 628 MailboxInfo minfo = new MailboxInfo(r); 631 minfo.mode = Folder.READ_ONLY; 633 notifyResponseHandlers(r); 635 636 handleResult(r[r.length-1]); 637 return minfo; 638 } 639 640 645 public Status status(String mbox, String [] items) 646 throws ProtocolException { 647 if (!isREV1() && !hasCapability("IMAP4SUNVERSION")) 648 throw new BadCommandException("STATUS not supported"); 651 652 mbox = BASE64MailboxEncoder.encode(mbox); 654 655 Argument args = new Argument(); 656 args.writeString(mbox); 657 658 Argument itemArgs = new Argument(); 659 if (items == null) 660 items = Status.standardItems; 661 662 for (int i = 0, len = items.length; i < len; i++) 663 itemArgs.writeAtom(items[i]); 664 args.writeArgument(itemArgs); 665 666 Response[] r = command("STATUS", args); 667 668 Status status = null; 669 Response response = r[r.length-1]; 670 671 if (response.isOK()) { for (int i = 0, len = r.length; i < len; i++) { 674 if (!(r[i] instanceof IMAPResponse)) 675 continue; 676 677 IMAPResponse ir = (IMAPResponse)r[i]; 678 if (ir.keyEquals("STATUS")) { 679 if (status == null) 680 status = new Status(ir); 681 else Status.add(status, new Status(ir)); 683 r[i] = null; 684 } 685 } 686 } 687 688 notifyResponseHandlers(r); 690 handleResult(response); 691 return status; 692 } 693 694 699 public void create(String mbox) throws ProtocolException { 700 mbox = BASE64MailboxEncoder.encode(mbox); 702 703 Argument args = new Argument(); 704 args.writeString(mbox); 705 706 simpleCommand("CREATE", args); 707 } 708 709 714 public void delete(String mbox) throws ProtocolException { 715 mbox = BASE64MailboxEncoder.encode(mbox); 717 718 Argument args = new Argument(); 719 args.writeString(mbox); 720 721 simpleCommand("DELETE", args); 722 } 723 724 729 public void rename(String o, String n) throws ProtocolException { 730 o = BASE64MailboxEncoder.encode(o); 732 n = BASE64MailboxEncoder.encode(n); 733 734 Argument args = new Argument(); 735 args.writeString(o); 736 args.writeString(n); 737 738 simpleCommand("RENAME", args); 739 } 740 741 746 public void subscribe(String mbox) throws ProtocolException { 747 Argument args = new Argument(); 748 mbox = BASE64MailboxEncoder.encode(mbox); 750 args.writeString(mbox); 751 752 simpleCommand("SUBSCRIBE", args); 753 } 754 755 760 public void unsubscribe(String mbox) throws ProtocolException { 761 Argument args = new Argument(); 762 mbox = BASE64MailboxEncoder.encode(mbox); 764 args.writeString(mbox); 765 766 simpleCommand("UNSUBSCRIBE", args); 767 } 768 769 774 public ListInfo[] list(String ref, String pattern) 775 throws ProtocolException { 776 return doList("LIST", ref, pattern); 777 } 778 779 784 public ListInfo[] lsub(String ref, String pattern) 785 throws ProtocolException { 786 return doList("LSUB", ref, pattern); 787 } 788 789 private ListInfo[] doList(String cmd, String ref, String pat) 790 throws ProtocolException { 791 ref = BASE64MailboxEncoder.encode(ref); 793 pat = BASE64MailboxEncoder.encode(pat); 794 795 Argument args = new Argument(); 796 args.writeString(ref); 797 args.writeString(pat); 798 799 Response[] r = command(cmd, args); 800 801 ListInfo[] linfo = null; 802 Response response = r[r.length-1]; 803 804 if (response.isOK()) { Vector v = new Vector(1); 806 for (int i = 0, len = r.length; i < len; i++) { 807 if (!(r[i] instanceof IMAPResponse)) 808 continue; 809 810 IMAPResponse ir = (IMAPResponse)r[i]; 811 if (ir.keyEquals(cmd)) { 812 v.addElement(new ListInfo(ir)); 813 r[i] = null; 814 } 815 } 816 if (v.size() > 0) { 817 linfo = new ListInfo[v.size()]; 818 v.copyInto(linfo); 819 } 820 } 821 822 notifyResponseHandlers(r); 824 handleResult(response); 825 return linfo; 826 } 827 828 833 public void append(String mbox, Flags f, Date d, 834 Literal data) throws ProtocolException { 835 appenduid(mbox, f, d, data, false); } 837 838 843 public AppendUID appenduid(String mbox, Flags f, Date d, 844 Literal data) throws ProtocolException { 845 return appenduid(mbox, f, d, data, true); 846 } 847 848 public AppendUID appenduid(String mbox, Flags f, Date d, 849 Literal data, boolean uid) throws ProtocolException { 850 mbox = BASE64MailboxEncoder.encode(mbox); 852 853 Argument args = new Argument(); 854 args.writeString(mbox); 855 856 if (f != null) f.remove(Flags.Flag.RECENT); 859 869 args.writeAtom(createFlagList(f)); 870 if (d != null) args.writeString(INTERNALDATE.format(d)); 872 873 args.writeBytes(data); 874 875 Response[] r = command("APPEND", args); 876 877 notifyResponseHandlers(r); 879 880 handleResult(r[r.length-1]); 882 883 if (uid) 884 return getAppendUID(r[r.length-1]); 885 else 886 return null; 887 } 888 889 893 private AppendUID getAppendUID(Response r) { 894 if (!r.isOK()) 895 return null; 896 byte b; 897 while ((b = r.readByte()) > 0 && b != (byte)'[') 898 ; 899 if (b == 0) 900 return null; 901 String s; 902 s = r.readAtom(); 903 if (!s.equalsIgnoreCase("APPENDUID")) 904 return null; 905 906 long uidvalidity = r.readLong(); 907 long uid = r.readLong(); 908 return new AppendUID(uidvalidity, uid); 909 } 910 911 916 public void check() throws ProtocolException { 917 simpleCommand("CHECK", null); 918 } 919 920 925 public void close() throws ProtocolException { 926 simpleCommand("CLOSE", null); 927 } 928 929 934 public void expunge() throws ProtocolException { 935 simpleCommand("EXPUNGE", null); 936 } 937 938 943 public void uidexpunge(UIDSet[] set) throws ProtocolException { 944 if (!hasCapability("UIDPLUS")) 945 throw new BadCommandException("UID EXPUNGE not supported"); 946 simpleCommand("UID EXPUNGE " + UIDSet.toString(set), null); 947 } 948 949 952 public BODYSTRUCTURE fetchBodyStructure(int msgno) 953 throws ProtocolException { 954 Response[] r = fetch(msgno, "BODYSTRUCTURE"); 955 notifyResponseHandlers(r); 956 957 Response response = r[r.length-1]; 958 if (response.isOK()) 959 return (BODYSTRUCTURE)FetchResponse.getItem(r, msgno, 960 BODYSTRUCTURE.class); 961 else if (response.isNO()) 962 return null; 963 else { 964 handleResult(response); 965 return null; 966 } 967 } 968 969 973 public BODY peekBody(int msgno, String section) 974 throws ProtocolException { 975 return fetchBody(msgno, section, true); 976 } 977 978 981 public BODY fetchBody(int msgno, String section) 982 throws ProtocolException { 983 return fetchBody(msgno, section, false); 984 } 985 986 private BODY fetchBody(int msgno, String section, boolean peek) 987 throws ProtocolException { 988 Response[] r; 989 990 if (peek) 991 r = fetch(msgno, 992 "BODY.PEEK[" + (section == null ? "]" : section + "]")); 993 else 994 r = fetch(msgno, 995 "BODY[" + (section == null ? "]" : section + "]")); 996 997 notifyResponseHandlers(r); 998 999 Response response = r[r.length-1]; 1000 if (response.isOK()) 1001 return (BODY)FetchResponse.getItem(r, msgno, BODY.class); 1002 else if (response.isNO()) 1003 return null; 1004 else { 1005 handleResult(response); 1006 return null; 1007 } 1008 } 1009 1010 1013 public BODY peekBody(int msgno, String section, int start, int size) 1014 throws ProtocolException { 1015 return fetchBody(msgno, section, start, size, true); 1016 } 1017 1018 1021 public BODY fetchBody(int msgno, String section, int start, int size) 1022 throws ProtocolException { 1023 return fetchBody(msgno, section, start, size, false); 1024 } 1025 1026 private BODY fetchBody(int msgno, String section, int start, int size, 1027 boolean peek) throws ProtocolException { 1028 Response[] r = fetch( 1029 msgno, (peek ? "BODY.PEEK[" : "BODY[" ) + 1030 (section == null ? "]<" : (section +"]<")) + 1031 String.valueOf(start) + "." + 1032 String.valueOf(size) + ">" 1033 ); 1034 1035 notifyResponseHandlers(r); 1036 1037 Response response = r[r.length-1]; 1038 if (response.isOK()) 1039 return (BODY)FetchResponse.getItem(r, msgno, BODY.class); 1040 else if (response.isNO()) 1041 return null; 1042 else { 1043 handleResult(response); 1044 return null; 1045 } 1046 } 1047 1048 1053 public RFC822DATA fetchRFC822(int msgno, String what) 1054 throws ProtocolException { 1055 Response[] r = fetch(msgno, 1056 what == null ? "RFC822" : "RFC822." + what 1057 ); 1058 1059 notifyResponseHandlers(r); 1061 1062 Response response = r[r.length-1]; 1063 if (response.isOK()) 1064 return (RFC822DATA)FetchResponse.getItem(r, msgno, 1065 RFC822DATA.class); 1066 else if (response.isNO()) 1067 return null; 1068 else { 1069 handleResult(response); 1070 return null; 1071 } 1072 } 1073 1074 1077 public Flags fetchFlags(int msgno) throws ProtocolException { 1078 Flags flags = null; 1079 Response[] r = fetch(msgno, "FLAGS"); 1080 1081 for (int i = 0, len = r.length; i < len; i++) { 1083 if (r[i] == null || 1084 !(r[i] instanceof FetchResponse) || 1085 ((FetchResponse)r[i]).getNumber() != msgno) 1086 continue; 1087 1088 FetchResponse fr = (FetchResponse)r[i]; 1089 if ((flags = (Flags)fr.getItem(Flags.class)) != null) { 1090 r[i] = null; break; 1092 } 1093 } 1094 1095 notifyResponseHandlers(r); 1097 handleResult(r[r.length-1]); 1098 return flags; 1099 } 1100 1101 1104 public UID fetchUID(int msgno) throws ProtocolException { 1105 Response[] r = fetch(msgno, "UID"); 1106 1107 notifyResponseHandlers(r); 1109 1110 Response response = r[r.length-1]; 1111 if (response.isOK()) 1112 return (UID)FetchResponse.getItem(r, msgno, UID.class); 1113 else if (response.isNO()) return null; 1115 else { 1116 handleResult(response); 1117 return null; } 1119 } 1120 1121 1126 public UID fetchSequenceNumber(long uid) throws ProtocolException { 1127 UID u = null; 1128 Response[] r = fetch(String.valueOf(uid), "UID", true); 1129 1130 for (int i = 0, len = r.length; i < len; i++) { 1131 if (r[i] == null || !(r[i] instanceof FetchResponse)) 1132 continue; 1133 1134 FetchResponse fr = (FetchResponse)r[i]; 1135 if ((u = (UID)fr.getItem(UID.class)) != null) { 1136 if (u.uid == uid) break; 1138 else 1139 u = null; 1140 } 1141 } 1142 1143 notifyResponseHandlers(r); 1144 handleResult(r[r.length-1]); 1145 return u; 1146 } 1147 1148 1153 public UID[] fetchSequenceNumbers(long start, long end) 1154 throws ProtocolException { 1155 Response[] r = fetch(String.valueOf(start) + ":" + 1156 (end == UIDFolder.LASTUID ? "*" : 1157 String.valueOf(end)), 1158 "UID", true); 1159 1160 UID u; 1161 Vector v = new Vector(); 1162 for (int i = 0, len = r.length; i < len; i++) { 1163 if (r[i] == null || !(r[i] instanceof FetchResponse)) 1164 continue; 1165 1166 FetchResponse fr = (FetchResponse)r[i]; 1167 if ((u = (UID)fr.getItem(UID.class)) != null) 1168 v.addElement(u); 1169 } 1170 1171 notifyResponseHandlers(r); 1172 handleResult(r[r.length-1]); 1173 1174 UID[] ua = new UID[v.size()]; 1175 v.copyInto(ua); 1176 return ua; 1177 } 1178 1179 1184 public UID[] fetchSequenceNumbers(long[] uids) throws ProtocolException { 1185 StringBuffer sb = new StringBuffer (); 1186 for (int i = 0; i < uids.length; i++) { 1187 if (i > 0) 1188 sb.append(","); 1189 sb.append(String.valueOf(uids[i])); 1190 } 1191 1192 Response[] r = fetch(sb.toString(), "UID", true); 1193 1194 UID u; 1195 Vector v = new Vector(); 1196 for (int i = 0, len = r.length; i < len; i++) { 1197 if (r[i] == null || !(r[i] instanceof FetchResponse)) 1198 continue; 1199 1200 FetchResponse fr = (FetchResponse)r[i]; 1201 if ((u = (UID)fr.getItem(UID.class)) != null) 1202 v.addElement(u); 1203 } 1204 1205 notifyResponseHandlers(r); 1206 handleResult(r[r.length-1]); 1207 1208 UID[] ua = new UID[v.size()]; 1209 v.copyInto(ua); 1210 return ua; 1211 } 1212 1213 public Response[] fetch(MessageSet[] msgsets, String what) 1214 throws ProtocolException { 1215 return fetch(MessageSet.toString(msgsets), what, false); 1216 } 1217 1218 public Response[] fetch(int start, int end, String what) 1219 throws ProtocolException { 1220 return fetch(String.valueOf(start) + ":" + String.valueOf(end), 1221 what, false); 1222 } 1223 1224 public Response[] fetch(int msg, String what) 1225 throws ProtocolException { 1226 return fetch(String.valueOf(msg), what, false); 1227 } 1228 1229 private Response[] fetch(String msgSequence, String what, boolean uid) 1230 throws ProtocolException { 1231 if (uid) 1232 return command("UID FETCH " + msgSequence +" (" + what + ")",null); 1233 else 1234 return command("FETCH " + msgSequence + " (" + what + ")", null); 1235 } 1236 1237 1240 public void copy(MessageSet[] msgsets, String mbox) 1241 throws ProtocolException { 1242 copy(MessageSet.toString(msgsets), mbox); 1243 } 1244 1245 public void copy(int start, int end, String mbox) 1246 throws ProtocolException { 1247 copy(String.valueOf(start) + ":" + String.valueOf(end), 1248 mbox); 1249 } 1250 1251 private void copy(String msgSequence, String mbox) 1252 throws ProtocolException { 1253 mbox = BASE64MailboxEncoder.encode(mbox); 1255 1256 Argument args = new Argument(); 1257 args.writeAtom(msgSequence); 1258 args.writeString(mbox); 1259 1260 simpleCommand("COPY", args); 1261 } 1262 1263 public void storeFlags(MessageSet[] msgsets, Flags flags, boolean set) 1264 throws ProtocolException { 1265 storeFlags(MessageSet.toString(msgsets), flags, set); 1266 } 1267 1268 public void storeFlags(int start, int end, Flags flags, boolean set) 1269 throws ProtocolException { 1270 storeFlags(String.valueOf(start) + ":" + String.valueOf(end), 1271 flags, set); 1272 } 1273 1274 1277 public void storeFlags(int msg, Flags flags, boolean set) 1278 throws ProtocolException { 1279 storeFlags(String.valueOf(msg), flags, set); 1280 } 1281 1282 private void storeFlags(String msgset, Flags flags, boolean set) 1283 throws ProtocolException { 1284 Response[] r; 1285 if (set) 1286 r = command("STORE " + msgset + " +FLAGS " + 1287 createFlagList(flags), null); 1288 else 1289 r = command("STORE " + msgset + " -FLAGS " + 1290 createFlagList(flags), null); 1291 1292 notifyResponseHandlers(r); 1294 handleResult(r[r.length-1]); 1295 } 1296 1297 1300 private String createFlagList(Flags flags) { 1301 StringBuffer sb = new StringBuffer (); 1302 sb.append("("); 1304 Flags.Flag[] sf = flags.getSystemFlags(); boolean first = true; 1306 for (int i = 0; i < sf.length; i++) { 1307 String s; 1308 Flags.Flag f = sf[i]; 1309 if (f == Flags.Flag.ANSWERED) 1310 s = "\\Answered"; 1311 else if (f == Flags.Flag.DELETED) 1312 s = "\\Deleted"; 1313 else if (f == Flags.Flag.DRAFT) 1314 s = "\\Draft"; 1315 else if (f == Flags.Flag.FLAGGED) 1316 s = "\\Flagged"; 1317 else if (f == Flags.Flag.RECENT) 1318 s = "\\Recent"; 1319 else if (f == Flags.Flag.SEEN) 1320 s = "\\Seen"; 1321 else 1322 continue; if (first) 1324 first = false; 1325 else 1326 sb.append(' '); 1327 sb.append(s); 1328 } 1329 1330 String [] uf = flags.getUserFlags(); for (int i = 0; i < uf.length; i++) { 1332 if (first) 1333 first = false; 1334 else 1335 sb.append(' '); 1336 sb.append(uf[i]); 1337 } 1338 1339 sb.append(")"); return sb.toString(); 1341 } 1342 1343 1352 public int[] search(MessageSet[] msgsets, SearchTerm term) 1353 throws ProtocolException, SearchException { 1354 return search(MessageSet.toString(msgsets), term); 1355 } 1356 1357 1365 public int[] search(SearchTerm term) 1366 throws ProtocolException, SearchException { 1367 return search("ALL", term); 1368 } 1369 1370 1374 private int[] search(String msgSequence, SearchTerm term) 1375 throws ProtocolException, SearchException { 1376 if (SearchSequence.isAscii(term)) { 1378 try { 1379 return issueSearch(msgSequence, term, null); 1380 } catch (IOException ioex) { } 1381 } 1382 1383 1389 1390 for (int i = 0; i < searchCharsets.length; i++) { 1392 if (searchCharsets[i] == null) 1393 continue; 1394 1395 try { 1396 return issueSearch(msgSequence, term, searchCharsets[i]); 1397 } catch (CommandFailedException cfx) { 1398 1403 searchCharsets[i] = null; 1404 continue; 1405 } catch (IOException ioex) { 1406 1407 continue; 1408 } catch (ProtocolException pex) { 1409 throw pex; 1410 } catch (SearchException sex) { 1411 throw sex; 1412 } 1413 } 1414 1415 throw new SearchException("Search failed"); 1417 } 1418 1419 1424 private int[] issueSearch(String msgSequence, SearchTerm term, 1425 String charset) 1426 throws ProtocolException, SearchException, IOException { 1427 1428 Argument args = SearchSequence.generateSequence(term, 1430 charset == null ? null : 1431 MimeUtility.javaCharset(charset) 1432 ); 1433 args.writeAtom(msgSequence); 1434 1435 Response[] r; 1436 1437 if (charset == null) r = command("SEARCH", args); 1439 else 1440 r = command("SEARCH CHARSET " + charset, args); 1441 1442 Response response = r[r.length-1]; 1443 int[] matches = null; 1444 1445 if (response.isOK()) { Vector v = new Vector(); 1448 int num; 1449 for (int i = 0, len = r.length; i < len; i++) { 1450 if (!(r[i] instanceof IMAPResponse)) 1451 continue; 1452 1453 IMAPResponse ir = (IMAPResponse)r[i]; 1454 if (ir.keyEquals("SEARCH")) { 1456 while ((num = ir.readNumber()) != -1) 1457 v.addElement(new Integer (num)); 1458 r[i] = null; 1459 } 1460 } 1461 1462 int vsize = v.size(); 1464 matches = new int[vsize]; 1465 for (int i = 0; i < vsize; i++) 1466 matches[i] = ((Integer )v.elementAt(i)).intValue(); 1467 } 1468 1469 notifyResponseHandlers(r); 1471 handleResult(response); 1472 return matches; 1473 } 1474 1475 1480 public Namespaces namespace() throws ProtocolException { 1481 if (!hasCapability("NAMESPACE")) 1482 throw new BadCommandException("NAMESPACE not supported"); 1483 1484 Response[] r = command("NAMESPACE", null); 1485 1486 Namespaces namespace = null; 1487 Response response = r[r.length-1]; 1488 1489 if (response.isOK()) { for (int i = 0, len = r.length; i < len; i++) { 1492 if (!(r[i] instanceof IMAPResponse)) 1493 continue; 1494 1495 IMAPResponse ir = (IMAPResponse)r[i]; 1496 if (ir.keyEquals("NAMESPACE")) { 1497 if (namespace == null) 1498 namespace = new Namespaces(ir); 1499 r[i] = null; 1500 } 1501 } 1502 } 1503 1504 notifyResponseHandlers(r); 1506 handleResult(response); 1507 return namespace; 1508 } 1509 1510 1519 public Quota[] getQuotaRoot(String mbox) throws ProtocolException { 1520 if (!hasCapability("QUOTA")) 1521 throw new BadCommandException("GETQUOTAROOT not supported"); 1522 1523 mbox = BASE64MailboxEncoder.encode(mbox); 1525 1526 Argument args = new Argument(); 1527 args.writeString(mbox); 1528 1529 Response[] r = command("GETQUOTAROOT", args); 1530 1531 Response response = r[r.length-1]; 1532 1533 Hashtable tab = new Hashtable(); 1534 1535 if (response.isOK()) { for (int i = 0, len = r.length; i < len; i++) { 1538 if (!(r[i] instanceof IMAPResponse)) 1539 continue; 1540 1541 IMAPResponse ir = (IMAPResponse)r[i]; 1542 if (ir.keyEquals("QUOTAROOT")) { 1543 1546 ir.readAtomString(); 1548 String root = null; 1550 while ((root = ir.readAtomString()) != null) 1551 tab.put(root, new Quota(root)); 1552 r[i] = null; 1553 } else if (ir.keyEquals("QUOTA")) { 1554 Quota quota = parseQuota(ir); 1555 Quota q = (Quota)tab.get(quota.quotaRoot); 1556 if (q != null && q.resources != null) { 1557 } 1559 tab.put(quota.quotaRoot, quota); 1560 r[i] = null; 1561 } 1562 } 1563 } 1564 1565 notifyResponseHandlers(r); 1567 handleResult(response); 1568 1569 Quota[] qa = new Quota[tab.size()]; 1570 Enumeration e = tab.elements(); 1571 for (int i = 0; e.hasMoreElements(); i++) 1572 qa[i] = (Quota)e.nextElement(); 1573 return qa; 1574 } 1575 1576 1584 public Quota[] getQuota(String root) throws ProtocolException { 1585 if (!hasCapability("QUOTA")) 1586 throw new BadCommandException("QUOTA not supported"); 1587 1588 Argument args = new Argument(); 1589 args.writeString(root); 1590 1591 Response[] r = command("GETQUOTA", args); 1592 1593 Quota quota = null; 1594 Vector v = new Vector(); 1595 Response response = r[r.length-1]; 1596 1597 if (response.isOK()) { for (int i = 0, len = r.length; i < len; i++) { 1600 if (!(r[i] instanceof IMAPResponse)) 1601 continue; 1602 1603 IMAPResponse ir = (IMAPResponse)r[i]; 1604 if (ir.keyEquals("QUOTA")) { 1605 quota = parseQuota(ir); 1606 v.addElement(quota); 1607 r[i] = null; 1608 } 1609 } 1610 } 1611 1612 notifyResponseHandlers(r); 1614 handleResult(response); 1615 Quota[] qa = new Quota[v.size()]; 1616 v.copyInto(qa); 1617 return qa; 1618 } 1619 1620 1627 public void setQuota(Quota quota) throws ProtocolException { 1628 if (!hasCapability("QUOTA")) 1629 throw new BadCommandException("QUOTA not supported"); 1630 1631 Argument args = new Argument(); 1632 args.writeString(quota.quotaRoot); 1633 Argument qargs = new Argument(); 1634 if (quota.resources != null) { 1635 for (int i = 0; i < quota.resources.length; i++) { 1636 qargs.writeAtom(quota.resources[i].name); 1637 qargs.writeNumber(quota.resources[i].limit); 1638 } 1639 } 1640 args.writeArgument(qargs); 1641 1642 Response[] r = command("SETQUOTA", args); 1643 Response response = r[r.length-1]; 1644 1645 1649 1668 1669 notifyResponseHandlers(r); 1671 handleResult(response); 1672 1677 } 1678 1679 1682 private Quota parseQuota(Response r) throws ParsingException { 1683 String quotaRoot = r.readAtomString(); Quota q = new Quota(quotaRoot); 1686 r.skipSpaces(); 1687 if (r.readByte() != '(') 1689 throw new ParsingException("parse error in QUOTA"); 1690 1691 Vector v = new Vector(); 1692 while (r.peekByte() != ')') { 1693 String name = r.readAtom(); 1695 if (name != null) { 1696 long usage = r.readLong(); 1697 long limit = r.readLong(); 1698 Quota.Resource res = new Quota.Resource(name, usage, limit); 1699 v.addElement(res); 1700 } 1701 } 1702 r.readByte(); 1703 q.resources = new Quota.Resource[v.size()]; 1704 v.copyInto(q.resources); 1705 return q; 1706 } 1707 1708 1709 1714 public void setACL(String mbox, char modifier, ACL acl) 1715 throws ProtocolException { 1716 if (!hasCapability("ACL")) 1717 throw new BadCommandException("ACL not supported"); 1718 1719 mbox = BASE64MailboxEncoder.encode(mbox); 1721 1722 Argument args = new Argument(); 1723 args.writeString(mbox); 1724 args.writeString(acl.getName()); 1725 String rights = acl.getRights().toString(); 1726 if (modifier == '+' || modifier == '-') 1727 rights = modifier + rights; 1728 args.writeString(rights); 1729 1730 Response[] r = command("SETACL", args); 1731 Response response = r[r.length-1]; 1732 1733 notifyResponseHandlers(r); 1735 handleResult(response); 1736 } 1737 1738 1743 public void deleteACL(String mbox, String user) throws ProtocolException { 1744 if (!hasCapability("ACL")) 1745 throw new BadCommandException("ACL not supported"); 1746 1747 mbox = BASE64MailboxEncoder.encode(mbox); 1749 1750 Argument args = new Argument(); 1751 args.writeString(mbox); 1752 args.writeString(user); 1753 1754 Response[] r = command("DELETEACL", args); 1755 Response response = r[r.length-1]; 1756 1757 notifyResponseHandlers(r); 1759 handleResult(response); 1760 } 1761 1762 1767 public ACL[] getACL(String mbox) throws ProtocolException { 1768 if (!hasCapability("ACL")) 1769 throw new BadCommandException("ACL not supported"); 1770 1771 mbox = BASE64MailboxEncoder.encode(mbox); 1773 1774 Argument args = new Argument(); 1775 args.writeString(mbox); 1776 1777 Response[] r = command("GETACL", args); 1778 Response response = r[r.length-1]; 1779 1780 Vector v = new Vector(); 1782 if (response.isOK()) { for (int i = 0, len = r.length; i < len; i++) { 1784 if (!(r[i] instanceof IMAPResponse)) 1785 continue; 1786 1787 IMAPResponse ir = (IMAPResponse)r[i]; 1788 if (ir.keyEquals("ACL")) { 1789 ir.readAtomString(); 1793 String name = null; 1794 while ((name = ir.readAtomString()) != null) { 1795 String rights = ir.readAtomString(); 1796 if (rights == null) 1797 break; 1798 ACL acl = new ACL(name, new Rights(rights)); 1799 v.addElement(acl); 1800 } 1801 r[i] = null; 1802 } 1803 } 1804 } 1805 1806 notifyResponseHandlers(r); 1808 handleResult(response); 1809 ACL[] aa = new ACL[v.size()]; 1810 v.copyInto(aa); 1811 return aa; 1812 } 1813 1814 1819 public Rights[] listRights(String mbox, String user) 1820 throws ProtocolException { 1821 if (!hasCapability("ACL")) 1822 throw new BadCommandException("ACL not supported"); 1823 1824 mbox = BASE64MailboxEncoder.encode(mbox); 1826 1827 Argument args = new Argument(); 1828 args.writeString(mbox); 1829 args.writeString(user); 1830 1831 Response[] r = command("LISTRIGHTS", args); 1832 Response response = r[r.length-1]; 1833 1834 Vector v = new Vector(); 1836 if (response.isOK()) { for (int i = 0, len = r.length; i < len; i++) { 1838 if (!(r[i] instanceof IMAPResponse)) 1839 continue; 1840 1841 IMAPResponse ir = (IMAPResponse)r[i]; 1842 if (ir.keyEquals("LISTRIGHTS")) { 1843 ir.readAtomString(); 1847 ir.readAtomString(); 1849 String rights; 1850 while ((rights = ir.readAtomString()) != null) 1851 v.addElement(new Rights(rights)); 1852 r[i] = null; 1853 } 1854 } 1855 } 1856 1857 notifyResponseHandlers(r); 1859 handleResult(response); 1860 Rights[] ra = new Rights[v.size()]; 1861 v.copyInto(ra); 1862 return ra; 1863 } 1864 1865 1870 public Rights myRights(String mbox) throws ProtocolException { 1871 if (!hasCapability("ACL")) 1872 throw new BadCommandException("ACL not supported"); 1873 1874 mbox = BASE64MailboxEncoder.encode(mbox); 1876 1877 Argument args = new Argument(); 1878 args.writeString(mbox); 1879 1880 Response[] r = command("MYRIGHTS", args); 1881 Response response = r[r.length-1]; 1882 1883 Rights rights = null; 1885 if (response.isOK()) { for (int i = 0, len = r.length; i < len; i++) { 1887 if (!(r[i] instanceof IMAPResponse)) 1888 continue; 1889 1890 IMAPResponse ir = (IMAPResponse)r[i]; 1891 if (ir.keyEquals("MYRIGHTS")) { 1892 ir.readAtomString(); 1895 String rs = ir.readAtomString(); 1896 if (rights == null) 1897 rights = new Rights(rs); 1898 r[i] = null; 1899 } 1900 } 1901 } 1902 1903 notifyResponseHandlers(r); 1905 handleResult(response); 1906 return rights; 1907 } 1908} 1909 | Popular Tags |