1 21 22 27 28 package com.sun.mail.imap; 29 30 import java.util.Date ; 31 import java.util.Vector ; 32 import java.util.Hashtable ; 33 import java.util.NoSuchElementException ; 34 import java.io.*; 35 36 import javax.mail.*; 37 import javax.mail.event.*; 38 import javax.mail.internet.*; 39 import javax.mail.search.*; 40 41 import com.sun.mail.util.*; 42 import com.sun.mail.iap.*; 43 import com.sun.mail.imap.protocol.*; 44 45 82 83 144 145 public class IMAPFolder extends Folder implements UIDFolder, ResponseHandler { 146 147 protected String fullName; protected String name; protected int type; protected char separator; protected Flags availableFlags; protected Flags permanentFlags; protected boolean exists = false; protected boolean isNamespace = false; protected String [] attributes; 157 protected IMAPProtocol protocol; protected Vector messageCache; protected Object messageCacheLock; 161 protected Hashtable uidTable; 163 169 static final protected char UNKNOWN_SEPARATOR = '\uffff'; 170 171 private boolean opened = false; 173 183 private boolean reallyClosed = true; 184 185 private int total = -1; private int recent = -1; private int realTotal = -1; private int uidvalidity = -1; private int uidnext = -1; private boolean doExpungeNotification = true; 194 private Status cachedStatus = null; 195 private long cachedStatusTime = 0; 196 197 private boolean debug = false; 198 private PrintStream out; 200 private boolean connectionPoolDebug; 201 202 209 public static class FetchProfileItem extends FetchProfile.Item { 210 protected FetchProfileItem(String name) { 211 super(name); 212 } 213 214 229 public static final FetchProfileItem HEADERS = 230 new FetchProfileItem("HEADERS"); 231 232 240 public static final FetchProfileItem SIZE = 241 new FetchProfileItem("SIZE"); 242 } 243 244 252 protected IMAPFolder(String fullName, char separator, IMAPStore store) { 253 this(fullName, separator, store, false); 254 } 255 256 264 protected IMAPFolder(String fullName, char separator, IMAPStore store, 265 boolean isNamespace) { 266 super(store); 267 if (fullName == null) 268 throw new NullPointerException ("Folder name is null"); 269 this.fullName = fullName; 270 this.separator = separator; 271 this.isNamespace = isNamespace; 272 messageCacheLock = new Object (); 273 debug = store.getSession().getDebug(); 274 connectionPoolDebug = ((IMAPStore)store).getConnectionPoolDebug(); 275 out = store.getSession().getDebugOut(); 276 if (out == null) out = System.out; 278 } 279 280 283 protected IMAPFolder(ListInfo li, IMAPStore store) { 284 this(li.name, li.separator, store); 285 286 if (li.hasInferiors) 287 type |= HOLDS_FOLDERS; 288 if (li.canOpen) 289 type |= HOLDS_MESSAGES; 290 exists = true; 291 attributes = li.attrs; 292 } 293 294 298 private void checkExists() throws MessagingException { 299 if (!exists && !exists()) 302 throw new FolderNotFoundException( 303 this, fullName + " not found"); 304 } 305 306 310 private void checkClosed() { 311 if (opened) 312 throw new IllegalStateException ( 313 "This operation is not allowed on an open folder" 314 ); 315 } 316 317 321 private void checkOpened() throws FolderClosedException { 322 if (!opened) { 323 if (reallyClosed) 324 throw new IllegalStateException ( 325 "This operation is not allowed on a closed folder" 326 ); 327 else throw new FolderClosedException(this, 329 "Lost folder connection to server" 330 ); 331 } 332 } 333 334 339 private void checkRange(int msgno) throws MessagingException { 340 if (msgno < 1) throw new IndexOutOfBoundsException (); 342 343 if (msgno <= total) 344 return; 345 346 349 synchronized(messageCacheLock) { try { 351 keepConnectionAlive(false); 352 } catch (ConnectionException cex) { 353 throw new FolderClosedException(this, cex.getMessage()); 355 } catch (ProtocolException pex) { 356 throw new MessagingException(pex.getMessage(), pex); 357 } 358 } 360 if (msgno > total) throw new IndexOutOfBoundsException (); 362 } 363 364 367 private void checkFlags(Flags flags) throws MessagingException { 368 if (mode != READ_WRITE) 369 throw new IllegalStateException ( 370 "Cannot change flags on READ_ONLY folder: " + fullName 371 ); 372 if (!availableFlags.contains(flags)) 373 throw new MessagingException( 374 "These flags are not supported by this implementation" 375 ); 376 } 377 378 381 public String getName() { 382 385 if (name == null) { 386 try { 387 name = fullName.substring( 388 fullName.lastIndexOf(getSeparator()) + 1 389 ); 390 } catch (MessagingException mex) { } 391 } 392 return name; 393 } 394 395 398 public String getFullName() { 399 return fullName; 400 } 401 402 405 public Folder getParent() throws MessagingException { 406 char c = getSeparator(); 407 int index; 408 if ((index = fullName.lastIndexOf(c)) != -1) 409 return new IMAPFolder(fullName.substring(0, index), 410 c, (IMAPStore)store); 411 else 412 return new DefaultFolder((IMAPStore)store); 413 } 414 415 418 public boolean exists() throws MessagingException { 419 ListInfo[] li = null; 421 final String lname; 422 if (isNamespace && separator != '\0') 423 lname = fullName + separator; 424 else 425 lname = fullName; 426 427 li = (ListInfo[])doCommand(new ProtocolCommand() { 428 public Object doCommand(IMAPProtocol p) throws ProtocolException { 429 return p.list("", lname); 430 } 431 }); 432 433 if (li != null) { 434 int i = findName(li, lname); 435 fullName = li[i].name; 436 separator = li[i].separator; 437 int len = fullName.length(); 438 if (separator != '\0' && len > 0 && 439 fullName.charAt(len - 1) == separator) { 440 fullName = fullName.substring(0, len - 1); 441 } 442 type = 0; 443 if (li[i].hasInferiors) 444 type |= HOLDS_FOLDERS; 445 if (li[i].canOpen) 446 type |= HOLDS_MESSAGES; 447 exists = true; 448 attributes = li[i].attrs; 449 } else 450 exists = false; 451 452 return exists; 453 } 454 455 460 private int findName(ListInfo[] li, String lname) { 461 int i; 462 for (i = 0; i < li.length; i++) { 464 if (li[i].name.equals(lname)) 465 break; 466 } 467 if (i >= li.length) { i = 0; } 473 return i; 474 } 475 476 479 public Folder[] list(String pattern) throws MessagingException { 480 return doList(pattern, false); 481 } 482 483 486 public Folder[] listSubscribed(String pattern) throws MessagingException { 487 return doList(pattern, true); 488 } 489 490 private Folder[] doList(final String pattern, final boolean subscribed) 491 throws MessagingException { 492 checkExists(); 494 if (!isDirectory()) return new Folder[0]; 496 497 final char c = getSeparator(); 498 499 ListInfo[] li = (ListInfo[])doCommandIgnoreFailure( 500 new ProtocolCommand() { 501 public Object doCommand(IMAPProtocol p) 502 throws ProtocolException { 503 if (subscribed) 504 return p.lsub("", fullName + c + pattern); 505 else 506 return p.list("", fullName + c + pattern); 507 } 508 }); 509 510 if (li == null) 511 return new Folder[0]; 512 513 524 int start = 0; 525 if (li.length > 0 && li[0].name.equals(fullName + c)) 527 start = 1; 529 IMAPFolder[] folders = new IMAPFolder[li.length - start]; 530 for (int i = start; i < li.length; i++) 531 folders[i-start] = new IMAPFolder(li[i], (IMAPStore)store); 532 return folders; 533 } 534 535 538 public synchronized char getSeparator() throws MessagingException { 539 if (separator == UNKNOWN_SEPARATOR) { 540 ListInfo[] li = null; 541 542 li = (ListInfo[])doCommand(new ProtocolCommand() { 543 public Object doCommand(IMAPProtocol p) 544 throws ProtocolException { 545 if (p.isREV1()) return p.list(fullName, ""); 549 else return p.list("", fullName); 552 } 553 }); 554 555 if (li != null) 556 separator = li[0].separator; 557 else 558 separator = '/'; } 560 return separator; 561 } 562 563 566 public int getType() throws MessagingException { 567 checkExists(); 568 return type; 569 } 570 571 574 public boolean isSubscribed() { 575 ListInfo[] li = null; 576 final String lname; 577 if (isNamespace && separator != '\0') 578 lname = fullName + separator; 579 else 580 lname = fullName; 581 582 try { 583 li = (ListInfo[])doProtocolCommand(new ProtocolCommand() { 584 public Object doCommand(IMAPProtocol p) 585 throws ProtocolException { 586 return p.lsub("", lname); 587 } 588 }); 589 } catch (ProtocolException pex) { 590 } 591 592 if (li != null) { 593 int i = findName(li, lname); 594 return li[i].canOpen; 595 } else 596 return false; 597 } 598 599 602 public void setSubscribed(final boolean subscribe) 603 throws MessagingException { 604 doCommandIgnoreFailure(new ProtocolCommand() { 605 public Object doCommand(IMAPProtocol p) throws ProtocolException { 606 if (subscribe) 607 p.subscribe(fullName); 608 else 609 p.unsubscribe(fullName); 610 return null; 611 } 612 }); 613 } 614 615 618 public synchronized boolean create(final int type) 619 throws MessagingException { 620 621 char c = 0; 622 if ((type & HOLDS_MESSAGES) == 0) c = getSeparator(); 624 final char sep = c; 625 Object ret = doCommandIgnoreFailure(new ProtocolCommand() { 626 public Object doCommand(IMAPProtocol p) 627 throws ProtocolException { 628 if ((type & HOLDS_MESSAGES) == 0) p.create(fullName + sep); 630 else { 631 p.create(fullName); 632 633 if ((type & HOLDS_FOLDERS) != 0) { 638 ListInfo[] li = p.list("", fullName); 641 if (li != null && !li[0].hasInferiors) { 642 p.delete(fullName); 645 throw new ProtocolException("Unsupported type"); 646 } 647 } 648 } 649 return Boolean.TRUE; 650 } 651 }); 652 653 if (ret == null) 654 return false; 657 boolean retb = exists(); notifyFolderListeners(FolderEvent.CREATED); 662 return retb; 663 } 664 665 668 public synchronized boolean hasNewMessages() throws MessagingException { 669 checkExists(); 670 671 if (opened) { synchronized(messageCacheLock) { 674 try { 676 keepConnectionAlive(true); 677 } catch (ConnectionException cex) { 678 throw new FolderClosedException(this, cex.getMessage()); 679 } catch (ProtocolException pex) { 680 throw new MessagingException(pex.getMessage(), pex); 681 } 682 } 683 return recent > 0 ? true : false; 684 } 685 686 689 Boolean b = (Boolean )doCommandIgnoreFailure(new ProtocolCommand() { 690 public Object doCommand(IMAPProtocol p) throws ProtocolException { 691 ListInfo[] li = p.list("", fullName); 692 if (li != null) { 693 if (li[0].changeState == ListInfo.CHANGED) 694 return Boolean.TRUE; 695 else if (li[0].changeState == ListInfo.UNCHANGED) 696 return Boolean.FALSE; 697 } 698 699 Status status = getStatus(); 701 if (status.recent > 0) 702 return Boolean.TRUE; 703 else 704 return Boolean.FALSE; 705 } 706 }); 707 if (b == null) 708 return false; 710 return b.booleanValue(); 711 } 712 713 716 public Folder getFolder(String name) throws MessagingException { 717 if (exists && !isDirectory()) 720 throw new MessagingException("Cannot contain subfolders"); 721 722 char c = getSeparator(); 723 return new IMAPFolder(fullName + c + name, c, (IMAPStore)store); 724 } 725 726 729 public synchronized boolean delete(boolean recurse) 730 throws MessagingException { 731 checkClosed(); 733 if (recurse) { 734 Folder[] f = list(); 736 for (int i = 0; i < f.length; i++) 737 f[i].delete(recurse); } 739 740 742 Object ret = doCommandIgnoreFailure(new ProtocolCommand() { 743 public Object doCommand(IMAPProtocol p) throws ProtocolException { 744 p.delete(fullName); 745 return Boolean.TRUE; 746 } 747 }); 748 749 if (ret == null) 750 return false; 752 753 exists = false; 755 756 notifyFolderListeners(FolderEvent.DELETED); 758 return true; 759 } 760 761 764 public synchronized boolean renameTo(final Folder f) 765 throws MessagingException { 766 checkClosed(); checkExists(); 768 if (f.getStore() != store) 769 throw new MessagingException("Can't rename across Stores"); 770 771 772 Object ret = doCommandIgnoreFailure(new ProtocolCommand() { 773 public Object doCommand(IMAPProtocol p) throws ProtocolException { 774 p.rename(fullName, f.getFullName()); 775 return Boolean.TRUE; 776 } 777 }); 778 779 if (ret == null) 780 return false; 781 782 exists = false; 783 notifyFolderRenamedListeners(f); 784 return true; 785 } 786 787 790 public synchronized void open(int mode) throws MessagingException { 791 checkClosed(); 793 MailboxInfo mi = null; 794 protocol = ((IMAPStore)store).getProtocol(this); 796 797 CommandFailedException exc = null; 798 lock: 799 synchronized(messageCacheLock) { 801 807 protocol.addResponseHandler(this); 808 809 try { 810 if (mode == READ_ONLY) 811 mi = protocol.examine(fullName); 812 else 813 mi = protocol.select(fullName); 814 } catch (CommandFailedException cex) { 815 releaseProtocol(true); 817 protocol = null; 818 exc = cex; 819 break lock; 820 } catch (ProtocolException pex) { 821 try { 823 protocol.logout(); 824 } catch (ProtocolException pex2) { 825 } finally { 827 releaseProtocol(false); 828 protocol = null; 829 throw new MessagingException(pex.getMessage(), pex); 830 } 831 } 832 833 if (mi.mode != mode) { 834 if (mode == READ_WRITE && mi.mode == READ_ONLY && 835 ((IMAPStore)store).allowReadOnlySelect()) { 836 ; } else { try { 839 protocol.close(); 841 releaseProtocol(true); 842 } catch (ProtocolException pex) { 843 try { 845 protocol.logout(); 846 } catch (ProtocolException pex2) { 847 } finally { 849 releaseProtocol(false); 850 } 851 } finally { 852 protocol = null; 853 throw new ReadOnlyFolderException(this, 854 "Cannot open in desired mode"); 855 } 856 857 } 858 } 859 860 opened = true; 862 reallyClosed = false; 863 this.mode = mi.mode; 864 availableFlags = mi.availableFlags; 865 permanentFlags = mi.permanentFlags; 866 total = realTotal = mi.total; 867 recent = mi.recent; 868 uidvalidity = mi.uidvalidity; 869 uidnext = mi.uidnext; 870 871 messageCache = new Vector (total); 873 for (int i = 0; i < total; i++) 875 messageCache.addElement(new IMAPMessage(this, i+1, i+1)); 876 877 } 879 884 if (exc != null) { 885 checkExists(); 887 if ((type & HOLDS_MESSAGES) == 0) 888 throw new MessagingException("folder cannot contain messages"); 889 throw new MessagingException(exc.getMessage(), exc); 890 } 891 892 notifyConnectionListeners(ConnectionEvent.OPENED); 894 } 895 896 899 public synchronized void fetch(Message[] msgs, FetchProfile fp) 900 throws MessagingException { 901 checkOpened(); 902 IMAPMessage.fetch(this, msgs, fp); 903 } 904 905 908 public synchronized void setFlags(Message[] msgs, Flags flag, boolean value) 909 throws MessagingException { 910 checkOpened(); 911 checkFlags(flag); 913 if (msgs.length == 0) return; 915 916 synchronized(messageCacheLock) { 917 try { 918 MessageSet[] ms = Utility.toMessageSet(msgs, null); 919 if (ms == null) 920 throw new MessageRemovedException( 921 "Messages have been removed"); 922 protocol.storeFlags(ms, flag, value); 923 } catch (ConnectionException cex) { 924 throw new FolderClosedException(this, cex.getMessage()); 925 } catch (ProtocolException pex) { 926 throw new MessagingException(pex.getMessage(), pex); 927 } 928 } 929 } 930 931 934 public synchronized void close(boolean expunge) throws MessagingException { 935 close(expunge, false); 936 } 937 938 941 public synchronized void forceClose() throws MessagingException { 942 close(false, true); 943 } 944 945 private void close(boolean expunge, boolean force) 946 throws MessagingException { 947 synchronized(messageCacheLock) { 948 954 if (!opened && reallyClosed) 955 throw new IllegalStateException ( 956 "This operation is not allowed on a closed folder" 957 ); 958 959 reallyClosed = true; 961 if (!opened) 966 return; 967 968 try { 969 if (force) { 970 if (debug) 971 out.println("DEBUG: forcing folder " + fullName + 972 " to close"); 973 if (protocol != null) 974 protocol.disconnect(); 975 } else if (((IMAPStore)store).isConnectionPoolFull()) { 976 if (debug) 978 out.println("DEBUG: pool is full, not adding " + 979 "an Authenticated connection"); 980 981 if (expunge) 983 protocol.close(); 984 985 if (protocol != null) 986 protocol.logout(); 987 } else { 988 if (!expunge && mode == READ_WRITE) { 992 try { 993 MailboxInfo mi = protocol.examine(fullName); 994 } catch (ProtocolException pex2) { 995 if (protocol != null) 996 protocol.disconnect(); 997 } 998 } 999 if (protocol != null) 1000 protocol.close(); 1001 } 1002 } catch (ProtocolException pex) { 1003 throw new MessagingException(pex.getMessage(), pex); 1004 } finally { 1005 if (opened) 1007 cleanup(true); 1008 } 1009 } 1010 } 1011 1012 private void cleanup(boolean returnToPool) { 1018 releaseProtocol(returnToPool); 1019 protocol = null; 1020 messageCache = null; 1021 uidTable = null; 1022 exists = false; opened = false; 1024 notifyConnectionListeners(ConnectionEvent.CLOSED); 1025 } 1026 1027 1030 public synchronized boolean isOpen() { 1031 synchronized(messageCacheLock) { 1032 if (opened) { 1034 try { 1035 keepConnectionAlive(false); 1036 } catch (ProtocolException pex) { } 1037 } 1038 } 1039 1040 return opened; 1041 } 1042 1043 1046 public Flags getPermanentFlags() { 1047 return permanentFlags; 1048 } 1049 1050 1053 public synchronized int getMessageCount() throws MessagingException { 1054 checkExists(); 1055 if (!opened) { 1056 try { 1059 Status status = getStatus(); 1060 return status.total; 1061 } catch (BadCommandException bex) { 1062 IMAPProtocol p = null; 1065 1066 try { 1067 p = getStoreProtocol(); MailboxInfo minfo = p.examine(fullName); 1069 p.close(); 1070 return minfo.total; 1071 } catch (ProtocolException pex) { 1072 throw new MessagingException(pex.getMessage(), pex); 1074 } finally { 1075 releaseStoreProtocol(p); 1076 } 1077 } catch (ConnectionException cex) { 1078 throw new StoreClosedException(store, cex.getMessage()); 1079 } catch (ProtocolException pex) { 1080 throw new MessagingException(pex.getMessage(), pex); 1081 } 1082 } 1083 1084 synchronized(messageCacheLock) { 1086 try { 1088 keepConnectionAlive(true); 1089 return total; 1090 } catch (ConnectionException cex) { 1091 throw new FolderClosedException(this, cex.getMessage()); 1092 } catch (ProtocolException pex) { 1093 throw new MessagingException(pex.getMessage(), pex); 1094 } 1095 } 1096 } 1097 1098 1101 public synchronized int getNewMessageCount() 1102 throws MessagingException { 1103 checkExists(); 1104 if (!opened) { 1105 try { 1108 Status status = getStatus(); 1109 return status.recent; 1110 } catch (BadCommandException bex) { 1111 IMAPProtocol p = null; 1114 1115 try { 1116 p = getStoreProtocol(); MailboxInfo minfo = p.examine(fullName); 1118 p.close(); 1119 return minfo.recent; 1120 } catch (ProtocolException pex) { 1121 throw new MessagingException(pex.getMessage(), pex); 1123 } finally { 1124 releaseStoreProtocol(p); 1125 } 1126 } catch (ConnectionException cex) { 1127 throw new StoreClosedException(store, cex.getMessage()); 1128 } catch (ProtocolException pex) { 1129 throw new MessagingException(pex.getMessage(), pex); 1130 } 1131 } 1132 1133 synchronized(messageCacheLock) { 1135 try { 1137 keepConnectionAlive(true); 1138 return recent; 1139 } catch (ConnectionException cex) { 1140 throw new FolderClosedException(this, cex.getMessage()); 1141 } catch (ProtocolException pex) { 1142 throw new MessagingException(pex.getMessage(), pex); 1143 } 1144 } 1145 } 1146 1147 1150 public synchronized int getUnreadMessageCount() 1151 throws MessagingException { 1152 checkExists(); 1153 if (!opened) { 1154 try { 1157 Status status = getStatus(); 1158 return status.unseen; 1159 } catch (BadCommandException bex) { 1160 return -1; 1164 } catch (ConnectionException cex) { 1165 throw new StoreClosedException(store, cex.getMessage()); 1166 } catch (ProtocolException pex) { 1167 throw new MessagingException(pex.getMessage(), pex); 1168 } 1169 } 1170 1171 Flags f = new Flags(); 1174 f.add(Flags.Flag.SEEN); 1175 try { 1176 synchronized(messageCacheLock) { 1177 int[] matches = protocol.search(new FlagTerm(f, false)); 1178 return matches.length; } 1180 } catch (ConnectionException cex) { 1181 throw new FolderClosedException(this, cex.getMessage()); 1182 } catch (ProtocolException pex) { 1183 throw new MessagingException(pex.getMessage(), pex); 1185 } 1186 } 1187 1188 1191 public synchronized int getDeletedMessageCount() 1192 throws MessagingException { 1193 checkExists(); 1194 if (!opened) { 1195 return -1; 1197 } 1198 1199 Flags f = new Flags(); 1202 f.add(Flags.Flag.DELETED); 1203 try { 1204 synchronized(messageCacheLock) { 1205 int[] matches = protocol.search(new FlagTerm(f, true)); 1206 return matches.length; } 1208 } catch (ConnectionException cex) { 1209 throw new FolderClosedException(this, cex.getMessage()); 1210 } catch (ProtocolException pex) { 1211 throw new MessagingException(pex.getMessage(), pex); 1213 } 1214 } 1215 1216 1221 private Status getStatus() throws ProtocolException { 1222 int statusCacheTimeout = ((IMAPStore)store).getStatusCacheTimeout(); 1223 1224 if (statusCacheTimeout > 0 && cachedStatus != null && 1226 System.currentTimeMillis() - cachedStatusTime < statusCacheTimeout) 1227 return cachedStatus; 1228 1229 IMAPProtocol p = null; 1230 1231 try { 1232 p = getStoreProtocol(); Status s = p.status(fullName, null); 1234 if (statusCacheTimeout > 0) { 1236 cachedStatus = s; 1237 cachedStatusTime = System.currentTimeMillis(); 1238 } 1239 return s; 1240 } finally { 1241 releaseStoreProtocol(p); 1242 } 1243 } 1244 1245 1248 public synchronized Message getMessage(int msgnum) 1249 throws MessagingException { 1250 checkOpened(); 1251 checkRange(msgnum); 1252 1253 return (Message)messageCache.elementAt(msgnum-1); 1254 } 1255 1256 1259 public void appendMessages(Message[] msgs) throws MessagingException { 1260 checkExists(); 1262 1267 int maxsize = ((IMAPStore)store).getAppendBufferSize(); 1268 1269 for (int i = 0; i < msgs.length; i++) { 1270 final Message m = msgs[i]; 1271 final MessageLiteral mos; 1272 1273 try { 1274 mos = new MessageLiteral(m, 1276 m.getSize() > maxsize ? 0 : maxsize); 1277 } catch (IOException ex) { 1278 throw new MessagingException( 1279 "IOException while appending messages", ex); 1280 } catch (MessageRemovedException mrex) { 1281 continue; } 1283 1284 Date d = m.getReceivedDate(); if (d == null) 1286 d = m.getSentDate(); 1287 final Date dd = d; 1288 final Flags f = m.getFlags(); 1289 doCommand(new ProtocolCommand() { 1290 public Object doCommand(IMAPProtocol p) 1291 throws ProtocolException { 1292 p.append(fullName, f, dd, mos); 1293 return null; 1294 } 1295 }); 1296 } 1297 } 1298 1299 1312 public AppendUID[] appendUIDMessages(Message[] msgs) 1313 throws MessagingException { 1314 checkExists(); 1316 1321 int maxsize = ((IMAPStore)store).getAppendBufferSize(); 1322 1323 AppendUID[] uids = new AppendUID[msgs.length]; 1324 for (int i = 0; i < msgs.length; i++) { 1325 final Message m = msgs[i]; 1326 final MessageLiteral mos; 1327 1328 try { 1329 mos = new MessageLiteral(m, 1331 m.getSize() > maxsize ? 0 : maxsize); 1332 } catch (IOException ex) { 1333 throw new MessagingException( 1334 "IOException while appending messages", ex); 1335 } catch (MessageRemovedException mrex) { 1336 continue; } 1338 1339 Date d = m.getReceivedDate(); if (d == null) 1341 d = m.getSentDate(); 1342 final Date dd = d; 1343 final Flags f = m.getFlags(); 1344 AppendUID auid = (AppendUID)doCommand(new ProtocolCommand() { 1345 public Object doCommand(IMAPProtocol p) 1346 throws ProtocolException { 1347 return p.appenduid(fullName, f, dd, mos); 1348 } 1349 }); 1350 uids[i] = auid; 1351 } 1352 return uids; 1353 } 1354 1355 1369 public Message[] addMessages(Message[] msgs) throws MessagingException { 1370 checkOpened(); 1371 Message[] rmsgs = new MimeMessage[msgs.length]; 1372 AppendUID[] uids = appendUIDMessages(msgs); 1373 for (int i = 0; i < uids.length; i++) { 1374 AppendUID auid = uids[i]; 1375 if (auid != null) { 1376 if (auid.uidvalidity == uidvalidity) { 1377 try { 1378 rmsgs[i] = getMessageByUID(auid.uid); 1379 } catch (MessagingException mex) { 1380 } 1382 } 1383 } 1384 } 1385 return rmsgs; 1386 } 1387 1388 1392 public synchronized void copyMessages(Message[] msgs, Folder folder) 1393 throws MessagingException { 1394 checkOpened(); 1395 1396 if (msgs.length == 0) return; 1398 1399 if (folder.getStore() == store) { 1401 synchronized(messageCacheLock) { 1402 try { 1403 MessageSet[] ms = Utility.toMessageSet(msgs, null); 1404 if (ms == null) 1405 throw new MessageRemovedException( 1406 "Messages have been removed"); 1407 protocol.copy(ms, folder.getFullName()); 1408 } catch (CommandFailedException cfx) { 1409 if (cfx.getMessage().indexOf("TRYCREATE") != -1) 1410 throw new FolderNotFoundException( 1411 folder, 1412 folder.getFullName() + " does not exist" 1413 ); 1414 else 1415 throw new MessagingException(cfx.getMessage(), cfx); 1416 } catch (ConnectionException cex) { 1417 throw new FolderClosedException(this, cex.getMessage()); 1418 } catch (ProtocolException pex) { 1419 throw new MessagingException(pex.getMessage(), pex); 1420 } 1421 } 1422 } else super.copyMessages(msgs, folder); 1424 } 1425 1426 1429 public synchronized Message[] expunge() throws MessagingException { 1430 return expunge(null); 1431 } 1432 1433 1436 public synchronized Message[] expunge(Message[] msgs) 1437 throws MessagingException { 1438 checkOpened(); 1439 1440 Vector v = new Vector (); 1442 if (msgs != null) { 1443 FetchProfile fp = new FetchProfile(); 1445 fp.add(UIDFolder.FetchProfileItem.UID); 1446 fetch(msgs, fp); 1447 } 1448 1449 synchronized(messageCacheLock) { 1450 doExpungeNotification = false; try { 1452 if (msgs != null) 1453 protocol.uidexpunge(Utility.toUIDSet(msgs)); 1454 else 1455 protocol.expunge(); 1456 } catch (CommandFailedException cfx) { 1457 if (mode != READ_WRITE) 1459 throw new IllegalStateException ( 1460 "Cannot expunge READ_ONLY folder: " + fullName); 1461 else 1462 throw new MessagingException(cfx.getMessage(), cfx); 1463 } catch (ConnectionException cex) { 1464 throw new FolderClosedException(this, cex.getMessage()); 1465 } catch (ProtocolException pex) { 1466 throw new MessagingException(pex.getMessage(), pex); 1468 } finally { 1469 doExpungeNotification = true; 1470 } 1471 1472 for (int i = 0; i < messageCache.size(); ) { 1475 IMAPMessage m = (IMAPMessage)messageCache.elementAt(i); 1476 if (m.isExpunged()) { 1477 v.addElement(m); 1479 1487 messageCache.removeElementAt(i); 1488 1489 1490 if (uidTable != null) { 1491 long uid = m.getUID(); 1492 if (uid != -1) 1493 uidTable.remove(new Long (uid)); 1494 } 1495 } else { 1496 1499 m.setMessageNumber(m.getSequenceNumber()); 1500 i++; } 1502 } 1503 } 1504 1505 total = messageCache.size(); 1507 1508 Message[] rmsgs = new Message[v.size()]; 1510 v.copyInto(rmsgs); 1511 if (rmsgs.length > 0) 1512 notifyMessageRemovedListeners(true, rmsgs); 1513 return rmsgs; 1514 } 1515 1516 1519 public synchronized Message[] search(SearchTerm term) 1520 throws MessagingException { 1521 checkOpened(); 1522 1523 try { 1524 Message[] matchMsgs = null; 1525 1526 synchronized(messageCacheLock) { 1527 int[] matches = protocol.search(term); 1528 if (matches != null) { 1529 matchMsgs = new IMAPMessage[matches.length]; 1530 for (int i = 0; i < matches.length; i++) 1532 matchMsgs[i] = getMessageBySeqNumber(matches[i]); 1533 } 1534 } 1535 return matchMsgs; 1536 1537 } catch (CommandFailedException cfx) { 1538 return super.search(term); 1540 } catch (SearchException sex) { 1541 return super.search(term); 1543 } catch (ConnectionException cex) { 1544 throw new FolderClosedException(this, cex.getMessage()); 1545 } catch (ProtocolException pex) { 1546 throw new MessagingException(pex.getMessage(), pex); 1548 } 1549 } 1550 1551 1556 public synchronized Message[] search(SearchTerm term, Message[] msgs) 1557 throws MessagingException { 1558 checkOpened(); 1559 1560 if (msgs.length == 0) 1561 return msgs; 1563 1564 try { 1565 Message[] matchMsgs = null; 1566 1567 synchronized(messageCacheLock) { 1568 MessageSet[] ms = Utility.toMessageSet(msgs, null); 1569 if (ms == null) 1570 throw new MessageRemovedException( 1571 "Messages have been removed"); 1572 int[] matches = protocol.search(ms, term); 1573 if (matches != null) { 1574 matchMsgs = new IMAPMessage[matches.length]; 1575 for (int i = 0; i < matches.length; i++) 1576 matchMsgs[i] = getMessageBySeqNumber(matches[i]); 1577 } 1578 } 1579 return matchMsgs; 1580 1581 } catch (CommandFailedException cfx) { 1582 return super.search(term, msgs); 1584 } catch (SearchException sex) { 1585 return super.search(term, msgs); 1587 } catch (ConnectionException cex) { 1588 throw new FolderClosedException(this, cex.getMessage()); 1589 } catch (ProtocolException pex) { 1590 throw new MessagingException(pex.getMessage(), pex); 1592 } 1593 } 1594 1595 1598 1599 1602 public synchronized long getUIDValidity() throws MessagingException { 1603 if (opened) return uidvalidity; 1605 1606 IMAPProtocol p = null; 1607 Status status = null; 1608 1609 try { 1610 p = getStoreProtocol(); String [] item = { "UIDVALIDITY" }; 1612 status = p.status(fullName, item); 1613 } catch (BadCommandException bex) { 1614 throw new MessagingException("Cannot obtain UIDValidity", bex); 1616 } catch (ConnectionException cex) { 1617 throwClosedException(cex); 1619 } catch (ProtocolException pex) { 1620 throw new MessagingException(pex.getMessage(), pex); 1621 } finally { 1622 releaseStoreProtocol(p); 1623 } 1624 1625 return status.uidvalidity; 1626 } 1627 1628 1645 public synchronized long getUIDNext() throws MessagingException { 1647 if (opened) return uidnext; 1649 1650 IMAPProtocol p = null; 1651 Status status = null; 1652 1653 try { 1654 p = getStoreProtocol(); String [] item = { "UIDNEXT" }; 1656 status = p.status(fullName, item); 1657 } catch (BadCommandException bex) { 1658 throw new MessagingException("Cannot obtain UIDNext", bex); 1660 } catch (ConnectionException cex) { 1661 throwClosedException(cex); 1663 } catch (ProtocolException pex) { 1664 throw new MessagingException(pex.getMessage(), pex); 1665 } finally { 1666 releaseStoreProtocol(p); 1667 } 1668 1669 return status.uidnext; 1670 } 1671 1672 1676 public synchronized Message getMessageByUID(long uid) 1677 throws MessagingException { 1678 checkOpened(); 1680 Long l = new Long (uid); 1681 IMAPMessage m = null; 1682 1683 if (uidTable != null) { 1684 m = (IMAPMessage)uidTable.get(l); 1686 if (m != null) return m; 1688 } else 1689 uidTable = new Hashtable (); 1690 1691 1692 try { 1694 synchronized(messageCacheLock) { 1695 UID u = protocol.fetchSequenceNumber(uid); 1697 1698 if (u != null && u.msgno <= total) { m = (IMAPMessage)messageCache.elementAt(u.msgno-1); 1700 m.setUID(u.uid); uidTable.put(l, m); 1703 } 1704 } 1705 } catch(ConnectionException cex) { 1706 throw new FolderClosedException(this, cex.getMessage()); 1707 } catch (ProtocolException pex) { 1708 throw new MessagingException(pex.getMessage(), pex); 1709 } 1710 1711 return m; 1712 } 1713 1714 1719 public synchronized Message[] getMessagesByUID(long start, long end) 1720 throws MessagingException { 1721 checkOpened(); 1723 if (uidTable == null) 1724 uidTable = new Hashtable (); 1725 1726 Message[] msgs; try { 1728 synchronized(messageCacheLock) { 1729 UID[] ua = protocol.fetchSequenceNumbers(start, end); 1731 1732 msgs = new Message[ua.length]; 1733 IMAPMessage m; 1734 for (int i = 0; i < ua.length; i++) { 1736 m = (IMAPMessage)messageCache.elementAt(ua[i].msgno-1); 1737 m.setUID(ua[i].uid); 1738 msgs[i] = m; 1739 uidTable.put(new Long (ua[i].uid), m); 1740 } 1741 } 1742 } catch(ConnectionException cex) { 1743 throw new FolderClosedException(this, cex.getMessage()); 1744 } catch (ProtocolException pex) { 1745 throw new MessagingException(pex.getMessage(), pex); 1746 } 1747 1748 return msgs; 1749 } 1750 1751 1758 public synchronized Message[] getMessagesByUID(long[] uids) 1759 throws MessagingException { 1760 checkOpened(); long[] unavailUids = uids; 1762 1763 if (uidTable != null) { 1764 Vector v = new Vector (); Long l; 1766 for (int i = 0; i < uids.length; i++) { 1767 if (!uidTable.containsKey(l = new Long (uids[i]))) 1768 v.addElement(l); 1770 } 1771 1772 int vsize = v.size(); 1773 unavailUids = new long[vsize]; 1774 for (int i = 0; i < vsize; i++) 1775 unavailUids[i] = ((Long )v.elementAt(i)).longValue(); 1776 } else 1777 uidTable = new Hashtable (); 1778 1779 if (unavailUids.length > 0) { 1780 try { 1781 synchronized(messageCacheLock) { 1782 UID[] ua = protocol.fetchSequenceNumbers(unavailUids); 1784 IMAPMessage m; 1785 for (int i = 0; i < ua.length; i++) { 1786 m = (IMAPMessage)messageCache.elementAt(ua[i].msgno-1); 1787 m.setUID(ua[i].uid); 1788 uidTable.put(new Long (ua[i].uid), m); 1789 } 1790 } 1791 } catch(ConnectionException cex) { 1792 throw new FolderClosedException(this, cex.getMessage()); 1793 } catch (ProtocolException pex) { 1794 throw new MessagingException(pex.getMessage(), pex); 1795 } 1796 } 1797 1798 Message[] msgs = new Message[uids.length]; 1800 for (int i = 0; i < uids.length; i++) 1801 msgs[i] = (Message)uidTable.get(new Long (uids[i])); 1802 return msgs; 1803 } 1804 1805 1808 public synchronized long getUID(Message message) 1809 throws MessagingException { 1810 if (message.getFolder() != this) 1811 throw new NoSuchElementException ( 1812 "Message does not belong to this folder"); 1813 1814 checkOpened(); 1816 IMAPMessage m = (IMAPMessage)message; 1817 long uid; 1819 if ((uid = m.getUID()) != -1) 1820 return uid; 1821 1822 UID u = null; 1823 synchronized(messageCacheLock) { m.checkExpunged(); try { 1826 u = protocol.fetchUID(m.getSequenceNumber()); 1827 } catch (ConnectionException cex) { 1828 throw new FolderClosedException(this, cex.getMessage()); 1829 } catch (ProtocolException pex) { 1830 throw new MessagingException(pex.getMessage(), pex); 1831 } 1832 } 1833 1834 if (u != null) { 1835 uid = u.uid; 1836 m.setUID(uid); 1838 if (uidTable == null) 1840 uidTable = new Hashtable (); 1841 uidTable.put(new Long (uid), m); 1842 } 1843 1844 return uid; 1845 } 1846 1847 1864 public Quota[] getQuota() throws MessagingException { 1865 return (Quota[])doOptionalCommand("QUOTA not supported", 1866 new ProtocolCommand() { 1867 public Object doCommand(IMAPProtocol p) 1868 throws ProtocolException { 1869 return p.getQuotaRoot(fullName); 1870 } 1871 }); 1872 } 1873 1874 1884 public void setQuota(final Quota quota) throws MessagingException { 1885 doOptionalCommand("QUOTA not supported", 1886 new ProtocolCommand() { 1887 public Object doCommand(IMAPProtocol p) 1888 throws ProtocolException { 1889 p.setQuota(quota); 1890 return null; 1891 } 1892 }); 1893 } 1894 1895 1902 public ACL[] getACL() throws MessagingException { 1903 return (ACL[])doOptionalCommand("ACL not supported", 1904 new ProtocolCommand() { 1905 public Object doCommand(IMAPProtocol p) 1906 throws ProtocolException { 1907 return p.getACL(fullName); 1908 } 1909 }); 1910 } 1911 1912 1920 public void addACL(ACL acl) throws MessagingException { 1921 setACL(acl, '\0'); 1922 } 1923 1924 1932 public void removeACL(final String name) throws MessagingException { 1933 doOptionalCommand("ACL not supported", 1934 new ProtocolCommand() { 1935 public Object doCommand(IMAPProtocol p) 1936 throws ProtocolException { 1937 p.deleteACL(fullName, name); 1938 return null; 1939 } 1940 }); 1941 } 1942 1943 1952 public void addRights(ACL acl) throws MessagingException { 1953 setACL(acl, '+'); 1954 } 1955 1956 1964 public void removeRights(ACL acl) throws MessagingException { 1965 setACL(acl, '-'); 1966 } 1967 1968 1987 public Rights[] listRights(final String name) throws MessagingException { 1988 return (Rights[])doOptionalCommand("ACL not supported", 1989 new ProtocolCommand() { 1990 public Object doCommand(IMAPProtocol p) 1991 throws ProtocolException { 1992 return p.listRights(fullName, name); 1993 } 1994 }); 1995 } 1996 1997 2004 public Rights myRights() throws MessagingException { 2005 return (Rights)doOptionalCommand("ACL not supported", 2006 new ProtocolCommand() { 2007 public Object doCommand(IMAPProtocol p) 2008 throws ProtocolException { 2009 return p.myRights(fullName); 2010 } 2011 }); 2012 } 2013 2014 private void setACL(final ACL acl, final char mod) 2015 throws MessagingException { 2016 doOptionalCommand("ACL not supported", 2017 new ProtocolCommand() { 2018 public Object doCommand(IMAPProtocol p) 2019 throws ProtocolException { 2020 p.setACL(fullName, mod, acl); 2021 return null; 2022 } 2023 }); 2024 } 2025 2026 2032 public String [] getAttributes() throws MessagingException { 2033 if (attributes == null) 2034 exists(); return (String [])(attributes.clone()); 2036 } 2037 2038 2042 2050 public void handleResponse(Response r) { 2051 2052 2055 if (r.isOK() || r.isNO() || r.isBAD() || r.isBYE()) 2056 ((IMAPStore)store).handleResponseCode(r); 2057 2058 2062 if (r.isBYE()) { 2063 if (opened) 2064 cleanup(false); 2065 return; 2066 } else if (r.isOK()) { 2067 return; 2068 } else if (!r.isUnTagged()) { 2069 return; } 2071 2072 2073 if (!(r instanceof IMAPResponse)) { 2074 out.println("UNEXPECTED RESPONSE : " + r.toString()); 2077 out.println("CONTACT javamail@sun.com"); 2078 return; 2079 } 2080 2081 IMAPResponse ir = (IMAPResponse)r; 2082 2083 if (ir.keyEquals("EXISTS")) { int exists = ir.getNumber(); 2085 if (exists <= realTotal) 2086 return; 2088 2089 int count = exists - realTotal; Message[] msgs = new Message[count]; 2091 2092 for (int i = 0; i < count; i++) { 2094 IMAPMessage msg = new IMAPMessage(this, ++total, ++realTotal); 2097 msgs[i] = msg; 2098 messageCache.addElement(msg); 2099 } 2100 2101 notifyMessageAddedListeners(msgs); 2103 2104 } else if (ir.keyEquals("EXPUNGE")) { 2105 2107 IMAPMessage msg = getMessageBySeqNumber(ir.getNumber()); 2108 msg.setExpunged(true); 2110 for (int i = msg.getMessageNumber(); i < total; i++) { 2113 IMAPMessage m = (IMAPMessage)messageCache.elementAt(i); 2116 if (m.isExpunged()) continue; 2118 2119 m.setSequenceNumber(m.getSequenceNumber() - 1); 2121 } 2123 realTotal--; 2125 2126 if (doExpungeNotification) { 2127 Message[] msgs = {msg}; 2129 notifyMessageRemovedListeners(false, msgs); 2130 } 2131 2132 } else if (ir.keyEquals("FETCH")) { 2133 FetchResponse f = (FetchResponse)ir; 2136 Flags flags = (Flags)f.getItem(Flags.class); 2138 2139 if (flags != null) { 2140 IMAPMessage msg = getMessageBySeqNumber(f.getNumber()); 2141 if (msg != null) { msg._setFlags(flags); 2143 notifyMessageChangedListeners( 2144 MessageChangedEvent.FLAGS_CHANGED, msg); 2145 } 2146 } 2147 2148 } else if (ir.keyEquals("RECENT")) { 2149 recent = ir.getNumber(); 2151 } 2152 } 2153 2154 2160 void handleResponses(Response[] r) { 2161 for (int i = 0; i < r.length; i++) { 2162 if (r[i] != null) 2163 handleResponse(r[i]); 2164 } 2165 } 2166 2167 2183 protected synchronized IMAPProtocol getStoreProtocol() 2184 throws ProtocolException { 2185 if (connectionPoolDebug) { 2186 out.println("DEBUG: getStoreProtocol() - " + 2187 "borrowing a connection"); 2188 } 2189 return ((IMAPStore)store).getStoreProtocol(); 2190 } 2191 2192 2195 private synchronized void throwClosedException(ConnectionException cex) 2196 throws FolderClosedException, StoreClosedException { 2197 if ((protocol != null && cex.getProtocol() == protocol) || 2205 (protocol == null && !reallyClosed)) 2206 throw new FolderClosedException(this, cex.getMessage()); 2207 else 2208 throw new StoreClosedException(store, cex.getMessage()); 2209 } 2210 2211 2228 public IMAPProtocol getProtocol() { 2229 return protocol; 2230 } 2231 2232 2235 public static interface ProtocolCommand { 2236 2240 public Object doCommand(IMAPProtocol protocol) throws ProtocolException; 2241 } 2242 2243 2330 public Object doCommand(ProtocolCommand cmd) throws MessagingException { 2331 try { 2332 return doProtocolCommand(cmd); 2333 } catch (ConnectionException cex) { 2334 throwClosedException(cex); 2336 } catch (ProtocolException pex) { 2337 throw new MessagingException(pex.getMessage(), pex); 2338 } 2339 return null; 2340 } 2341 2342 public Object doOptionalCommand(String err, ProtocolCommand cmd) 2343 throws MessagingException { 2344 try { 2345 return doProtocolCommand(cmd); 2346 } catch (BadCommandException bex) { 2347 throw new MessagingException(err, bex); 2348 } catch (ConnectionException cex) { 2349 throwClosedException(cex); 2351 } catch (ProtocolException pex) { 2352 throw new MessagingException(pex.getMessage(), pex); 2353 } 2354 return null; 2355 } 2356 2357 public Object doCommandIgnoreFailure(ProtocolCommand cmd) 2358 throws MessagingException { 2359 try { 2360 return doProtocolCommand(cmd); 2361 } catch (CommandFailedException cfx) { 2362 return null; 2363 } catch (ConnectionException cex) { 2364 throwClosedException(cex); 2366 } catch (ProtocolException pex) { 2367 throw new MessagingException(pex.getMessage(), pex); 2368 } 2369 return null; 2370 } 2371 2372 protected Object doProtocolCommand(ProtocolCommand cmd) 2373 throws ProtocolException { 2374 synchronized (this) { 2375 if (opened && !((IMAPStore)store).hasSeparateStoreConnection()) { 2376 synchronized (messageCacheLock) { 2377 return cmd.doCommand(getProtocol()); 2378 } 2379 } 2380 } 2381 2382 IMAPProtocol p = null; 2384 2385 try { 2386 p = getStoreProtocol(); 2387 return cmd.doCommand(p); 2388 } finally { 2389 releaseStoreProtocol(p); 2390 } 2391 } 2392 2393 2398 protected synchronized void releaseStoreProtocol(IMAPProtocol p) { 2399 if (p != protocol) 2400 ((IMAPStore)store).releaseStoreProtocol(p); 2401 } 2402 2403 2409 private void releaseProtocol(boolean returnToPool) { 2410 if (protocol != null) { 2411 protocol.removeResponseHandler(this); 2412 2413 if (returnToPool) 2414 ((IMAPStore)store).releaseProtocol(this, protocol); 2415 else 2416 ((IMAPStore)store).releaseProtocol(this, null); 2417 } 2418 } 2419 2420 2425 private void keepConnectionAlive(boolean keepStoreAlive) 2426 throws ProtocolException { 2427 2428 if (System.currentTimeMillis() - protocol.getTimestamp() > 1000) 2429 protocol.noop(); 2430 2431 if (keepStoreAlive && ((IMAPStore)store).hasSeparateStoreConnection()) { 2432 IMAPProtocol p = null; 2433 try { 2434 p = ((IMAPStore)store).getStoreProtocol(); 2435 if (System.currentTimeMillis() - p.getTimestamp() > 1000) 2436 p.noop(); 2437 } finally { 2438 ((IMAPStore)store).releaseStoreProtocol(p); 2439 } 2440 } 2441 } 2442 2443 2450 IMAPMessage getMessageBySeqNumber(int seqnum) { 2451 2455 for (int i = seqnum-1; i < total; i++) { 2456 IMAPMessage msg = (IMAPMessage)messageCache.elementAt(i); 2457 if (msg.getSequenceNumber() == seqnum) 2458 return msg; 2459 } 2460 return null; 2461 } 2462 2463 private boolean isDirectory() { 2464 return ((type & HOLDS_FOLDERS) != 0); 2465 } 2466} 2467 2468 2475class MessageLiteral implements Literal { 2476 private Message msg; 2477 private int msgSize = -1; 2478 private byte[] buf; 2480 public MessageLiteral(Message msg, int maxsize) 2481 throws MessagingException, IOException { 2482 this.msg = msg; 2483 LengthCounter lc = new LengthCounter(maxsize); 2485 OutputStream os = new CRLFOutputStream(lc); 2486 msg.writeTo(os); 2487 os.flush(); 2488 msgSize = lc.getSize(); 2489 buf = lc.getBytes(); 2490 } 2491 2492 public int size() { 2493 return msgSize; 2494 } 2495 2496 public void writeTo(OutputStream os) throws IOException { 2497 try { 2499 if (buf != null) 2500 os.write(buf, 0, msgSize); 2501 else { 2502 os = new CRLFOutputStream(os); 2503 msg.writeTo(os); 2504 } 2505 } catch (MessagingException mex) { 2506 throw new IOException("MessagingException while appending message: " 2508 + mex); 2509 } 2510 } 2511} 2512 2513 2518class LengthCounter extends OutputStream { 2519 private int size = 0; 2520 private byte[] buf; 2521 private int maxsize; 2522 2523 public LengthCounter(int maxsize) { 2524 buf = new byte[8192]; 2525 this.maxsize = maxsize; 2526 } 2527 2528 public void write(int b) { 2529 int newsize = size + 1; 2530 if (buf != null) { 2531 if (newsize > maxsize && maxsize >= 0) { 2532 buf = null; 2533 } else if (newsize > buf.length) { 2534 byte newbuf[] = new byte[Math.max(buf.length << 1, newsize)]; 2535 System.arraycopy(buf, 0, newbuf, 0, size); 2536 buf = newbuf; 2537 buf[size] = (byte)b; 2538 } else { 2539 buf[size] = (byte)b; 2540 } 2541 } 2542 size = newsize; 2543 } 2544 2545 public void write(byte b[], int off, int len) { 2546 if ((off < 0) || (off > b.length) || (len < 0) || 2547 ((off + len) > b.length) || ((off + len) < 0)) { 2548 throw new IndexOutOfBoundsException (); 2549 } else if (len == 0) { 2550 return; 2551 } 2552 int newsize = size + len; 2553 if (buf != null) { 2554 if (newsize > maxsize && maxsize >= 0) { 2555 buf = null; 2556 } else if (newsize > buf.length) { 2557 byte newbuf[] = new byte[Math.max(buf.length << 1, newsize)]; 2558 System.arraycopy(buf, 0, newbuf, 0, size); 2559 buf = newbuf; 2560 System.arraycopy(b, off, buf, size, len); 2561 } else { 2562 System.arraycopy(b, off, buf, size, len); 2563 } 2564 } 2565 size = newsize; 2566 } 2567 2568 public void write(byte[] b) throws IOException { 2569 write(b, 0, b.length); 2570 } 2571 2572 public int getSize() { 2573 return size; 2574 } 2575 2576 public byte[] getBytes() { 2577 return buf; 2578 } 2579} 2580 | Popular Tags |