1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.geronimo.javamail.store.imap.connection;
19
20 import java.io.ByteArrayOutputStream;
21 import java.io.UnsupportedEncodingException;
22 import java.util.ArrayList;
23 import java.util.Date;
24 import java.util.List;
25
26 import javax.mail.Flags;
27 import javax.mail.MessagingException;
28 import javax.mail.internet.InternetAddress;
29 import javax.mail.internet.MailDateFormat;
30 import javax.mail.internet.ParameterList;
31
32 import org.apache.geronimo.javamail.util.ResponseFormatException;
33
34
35
36
37 public class IMAPResponseTokenizer {
38
39
40
41 protected static final byte[] decodingTable = new byte[256];
42
43 protected static void initializeDecodingTable()
44 {
45 for (int i = 0; i < IMAPCommand.encodingTable.length; i++)
46 {
47 decodingTable[IMAPCommand.encodingTable[i]] = (byte)i;
48 }
49 }
50
51
52 static {
53 initializeDecodingTable();
54 }
55
56
57 protected static MailDateFormat dateParser = new MailDateFormat();
58
59
60 public static class Token {
61
62 public static final int ATOM = -1;
63 public static final int QUOTEDSTRING = -2;
64 public static final int LITERAL = -3;
65 public static final int NUMERIC = -4;
66 public static final int EOF = -5;
67 public static final int NIL = -6;
68
69 public static final int CONTINUATION = '-';
70 public static final int UNTAGGED = '*';
71
72
73
74
75
76 private int type;
77
78
79
80
81 private String value;
82
83 public Token(int type, String value) {
84 this.type = type;
85 this.value = value;
86 }
87
88 public int getType() {
89 return type;
90 }
91
92 public String getValue() {
93 return value;
94 }
95
96 public boolean isType(int type) {
97 return this.type == type;
98 }
99
100
101
102
103
104
105
106
107 public int getInteger() throws MessagingException {
108 if (value != null) {
109 try {
110 return Integer.parseInt(value);
111 } catch (NumberFormatException e) {
112 }
113 }
114
115 throw new ResponseFormatException("Number value expected in response; fount: " + value);
116 }
117
118
119
120
121
122
123
124
125 public long getLong() throws MessagingException {
126 if (value != null) {
127 try {
128 return Long.parseLong(value);
129 } catch (NumberFormatException e) {
130 }
131 }
132 throw new ResponseFormatException("Number value expected in response; fount: " + value);
133 }
134
135
136
137
138
139
140 public String toString() {
141 if (type == NIL) {
142 return "NIL";
143 }
144 else if (type == EOF) {
145 return "EOF";
146 }
147
148 if (value == null) {
149 return "";
150 }
151 return value;
152 }
153 }
154
155 public static final Token EOF = new Token(Token.EOF, null);
156 public static final Token NIL = new Token(Token.NIL, null);
157
158 private static final String WHITE = " \t\n\r";
159
160
161 private static final String atomDelimiters = "(){}%*\"\\" + WHITE;
162
163
164
165
166
167 private static final String tokenDelimiters = "<>[].(){}%*\"\\" + WHITE;
168
169
170 private byte[] response;
171
172 private int pos;
173
174 public IMAPResponseTokenizer(byte [] response) {
175 this.response = response;
176 }
177
178
179
180
181
182
183 public String getRemainder() {
184
185 if (pos >= response.length) {
186 return "";
187 }
188
189 return new String(response, pos, response.length - pos);
190 }
191
192
193 public Token next() throws MessagingException {
194 return next(false);
195 }
196
197 public Token next(boolean nilAllowed) throws MessagingException {
198 return readToken(nilAllowed, false);
199 }
200
201 public Token next(boolean nilAllowed, boolean expandedDelimiters) throws MessagingException {
202 return readToken(nilAllowed, expandedDelimiters);
203 }
204
205 public Token peek() throws MessagingException {
206 return peek(false, false);
207 }
208
209 public Token peek(boolean nilAllowed) throws MessagingException {
210 return peek(nilAllowed, false);
211 }
212
213 public Token peek(boolean nilAllowed, boolean expandedDelimiters) throws MessagingException {
214 int start = pos;
215 try {
216 return readToken(nilAllowed, expandedDelimiters);
217 } finally {
218 pos = start;
219 }
220 }
221
222
223
224
225
226
227 private Token readAtomicToken(String delimiters) {
228
229 int start = pos;
230 while (++pos < response.length) {
231
232 byte ch = response[pos];
233 if (delimiters.indexOf(response[pos]) != -1 || ch < 32 || ch >= 127) {
234 break;
235 }
236 }
237
238
239 String value = new String(response, start, pos - start);
240 try {
241 int intValue = Integer.parseInt(value);
242 return new Token(Token.NUMERIC, value);
243 } catch (NumberFormatException e) {
244 }
245 return new Token(Token.ATOM, value);
246 }
247
248
249
250
251
252
253
254
255 private Token readToken(boolean nilAllowed, boolean expandedDelimiters) throws MessagingException {
256 String delimiters = expandedDelimiters ? tokenDelimiters : atomDelimiters;
257
258 if (pos >= response.length) {
259 return EOF;
260 } else {
261 byte ch = response[pos];
262 if (ch == '\"') {
263 return readQuotedString();
264
265 } else if (ch == '{') {
266 return readLiteral();
267
268 } else if (WHITE.indexOf(ch) != -1) {
269 eatWhiteSpace();
270 return readToken(nilAllowed, expandedDelimiters);
271
272 } else if (ch < 32 || ch >= 127 || delimiters.indexOf(ch) != -1) {
273 pos++;
274 return new Token((int)ch, String.valueOf((char)ch));
275 } else {
276
277 Token token = readAtomicToken(delimiters);
278
279
280 if (nilAllowed) {
281 if (token.getValue().equalsIgnoreCase("NIL")) {
282 return NIL;
283 }
284 }
285 return token;
286 }
287 }
288 }
289
290
291
292
293
294
295
296
297 private byte[] readData(boolean nilAllowed) throws MessagingException {
298 if (pos >= response.length) {
299 return null;
300 } else {
301 byte ch = response[pos];
302 if (ch == '\"') {
303 return readQuotedStringData();
304
305 } else if (ch == '{') {
306 return readLiteralData();
307
308 } else if (WHITE.indexOf(ch) != -1) {
309 eatWhiteSpace();
310 return readData(nilAllowed);
311
312 } else if (ch < 32 || ch >= 127 || atomDelimiters.indexOf(ch) != -1) {
313 throw new ResponseFormatException("Invalid string value: " + ch);
314 } else {
315
316 if (nilAllowed) {
317
318 Token token = next(true);
319 if (token.isType(Token.NIL)) {
320 return null;
321 }
322
323 throw new ResponseFormatException("Invalid string value: " + token.getValue());
324 }
325
326 throw new ResponseFormatException("Invalid string value: " + ch);
327 }
328 }
329 }
330
331
332
333
334
335
336
337
338
339
340
341 private byte[] getEscapedValue(int start, int end) throws MessagingException {
342 ByteArrayOutputStream value = new ByteArrayOutputStream();
343
344 for (int i = start; i < end; i++) {
345 byte ch = response[i];
346
347 if (ch == '\\') {
348 i++;
349 if (i == end) {
350 throw new ResponseFormatException("Invalid escape character");
351 }
352 value.write(response[i]);
353 }
354
355
356 else if (ch == '\r') {
357
358 if (i < end - 1 && response[i + 1] == '\n') {
359 i++;
360 }
361 }
362 else {
363
364 value.write(ch);
365 }
366 }
367 return value.toByteArray();
368 }
369
370
371
372
373
374
375
376
377 private Token readQuotedString() throws MessagingException {
378
379 String value = new String(readQuotedStringData());
380 return new Token(Token.QUOTEDSTRING, value);
381 }
382
383
384
385
386
387
388
389
390 private byte[] readQuotedStringData() throws MessagingException {
391 int start = pos + 1;
392 boolean requiresEscaping = false;
393
394
395 while (++pos < response.length) {
396 byte ch = response[pos];
397 if (ch == '"') {
398 byte[] value;
399 if (requiresEscaping) {
400 value = getEscapedValue(start, pos);
401 }
402 else {
403 value = subarray(start, pos);
404 }
405
406 pos++;
407 return value;
408 }
409 else if (ch == '\\') {
410 pos++;
411 requiresEscaping = true;
412 }
413
414 else if (ch == '\r') {
415 requiresEscaping = true;
416 }
417 }
418
419 throw new ResponseFormatException("Missing '\"'");
420 }
421
422
423
424
425
426
427
428
429
430 protected Token readLiteral() throws MessagingException {
431 String value = new String(readLiteralData());
432 return new Token(Token.LITERAL, value);
433 }
434
435
436
437
438
439
440
441
442
443 protected byte[] readLiteralData() throws MessagingException {
444 int lengthStart = pos + 1;
445
446
447 int lengthEnd = indexOf("}\r\n", lengthStart);
448 if (lengthEnd == -1) {
449 throw new ResponseFormatException("Missing terminator on literal length");
450 }
451
452 int count = 0;
453 try {
454 count = Integer.parseInt(substring(lengthStart, lengthEnd));
455 } catch (NumberFormatException e) {
456 throw new ResponseFormatException("Invalid literal length " + substring(lengthStart, lengthEnd));
457 }
458
459
460 pos = lengthEnd + 3;
461
462
463 if (pos + count > response.length) {
464 throw new ResponseFormatException("Invalid literal length: " + count);
465 }
466
467 byte[] value = subarray(pos, pos + count);
468 pos += count;
469
470 return value;
471 }
472
473
474
475
476
477
478
479
480
481
482 protected String substring(int start, int end ) {
483 return new String(response, start, end - start);
484 }
485
486
487
488
489
490
491
492
493
494
495 protected byte[] subarray(int start, int end ) {
496 byte[] result = new byte[end - start];
497 System.arraycopy(response, start, result, 0, end - start);
498 return result;
499 }
500
501
502
503
504
505
506
507
508
509
510
511
512 public boolean match(int position, String needle) {
513 int length = needle.length();
514
515 if (response.length - position < length) {
516 return false;
517 }
518
519 for (int i = 0; i < length; i++) {
520 if (response[position + i ] != needle.charAt(i)) {
521 return false;
522 }
523 }
524 return true;
525 }
526
527
528
529
530
531
532
533
534
535
536
537 public int indexOf(String needle) {
538 return indexOf(needle, pos);
539 }
540
541
542
543
544
545
546
547
548
549
550 public int indexOf(String needle, int position) {
551
552 int last = response.length - needle.length();
553
554 if (last < position) {
555 return -1;
556 }
557
558 for (int i = position; i <= last; i++) {
559 if (match(i, needle)) {
560 return i;
561 }
562 }
563 return -1;
564 }
565
566
567
568
569
570
571 private void eatWhiteSpace() {
572
573 while (++pos < response.length
574 && WHITE.indexOf(response[pos]) != -1)
575 ;
576 }
577
578
579
580
581
582
583
584
585 public void checkLeftParen() throws MessagingException {
586 Token token = next();
587 if (token.getType() != '(') {
588 throw new ResponseFormatException("Missing '(' in response");
589 }
590 }
591
592
593
594
595
596
597
598
599 public void checkRightParen() throws MessagingException {
600 Token token = next();
601 if (token.getType() != ')') {
602 throw new ResponseFormatException("Missing ')' in response");
603 }
604 }
605
606
607
608
609
610
611
612
613
614
615 public String readString() throws MessagingException {
616 Token token = next();
617 int type = token.getType();
618
619 if (type != Token.ATOM && type != Token.QUOTEDSTRING && type != Token.LITERAL && type != Token.NUMERIC) {
620 throw new ResponseFormatException("String token expected in response: " + token.getValue());
621 }
622 return token.getValue();
623 }
624
625
626
627
628
629
630
631
632
633
634 public String readEncodedString() throws MessagingException {
635 String value = readString();
636 return decode(value);
637 }
638
639
640
641
642
643
644
645
646
647
648 public String decode(String original) throws MessagingException {
649 StringBuffer result = new StringBuffer();
650
651 for (int i = 0; i < original.length(); i++) {
652 char ch = original.charAt(i);
653
654 if (ch == '&') {
655 i = decode(original, i, result);
656 }
657 else {
658 result.append(ch);
659 }
660 }
661
662 return result.toString();
663 }
664
665
666
667
668
669
670
671
672
673
674
675
676 public static int decode(String original, int index, StringBuffer result) throws MessagingException {
677
678 int terminator = original.indexOf('-', index);
679
680
681 if (terminator == -1) {
682 throw new MessagingException("Invalid UTF-7 encoded string");
683 }
684
685
686 if (terminator == index + 1) {
687
688 result.append('&');
689 return index + 2;
690 }
691
692
693 index++;
694
695 int chars = terminator - index;
696 int quads = chars / 4;
697 int residual = chars % 4;
698
699
700 byte[] buffer = new byte[4];
701 int bufferCount = 0;
702
703
704 for (int i = 0; i < quads; i++) {
705 byte b1 = decodingTable[original.charAt(index++) & 0xff];
706 byte b2 = decodingTable[original.charAt(index++) & 0xff];
707 byte b3 = decodingTable[original.charAt(index++) & 0xff];
708 byte b4 = decodingTable[original.charAt(index++) & 0xff];
709
710 buffer[bufferCount++] = (byte)((b1 << 2) | (b2 >> 4));
711 buffer[bufferCount++] = (byte)((b2 << 4) | (b3 >> 2));
712 buffer[bufferCount++] = (byte)((b3 << 6) | b4);
713
714
715
716 if (bufferCount == 4) {
717
718 b1 = buffer[0];
719 b2 = buffer[1];
720 result.append((char)((b1 << 8) + (b2 & 0xff)));
721 b1 = buffer[2];
722 b2 = buffer[3];
723 result.append((char)((b1 << 8) + (b2 & 0xff)));
724 bufferCount = 0;
725 }
726 else {
727
728 b1 = buffer[0];
729 b2 = buffer[1];
730 result.append((char)((b1 << 8) + (b2 & 0xff)));
731 buffer[0] = buffer[2];
732 bufferCount = 1;
733 }
734 }
735
736
737
738 switch (residual) {
739
740 case 0:
741
742 if (bufferCount == 1) {
743 throw new MessagingException("Invalid UTF-7 encoded string");
744 }
745
746
747 case 1:
748 throw new MessagingException("Invalid UTF-7 encoded string");
749
750
751
752 case 2:
753 {
754 if (bufferCount != 1) {
755 throw new MessagingException("Invalid UTF-7 encoded string");
756 }
757 byte b1 = decodingTable[original.charAt(index++) & 0xff];
758 byte b2 = decodingTable[original.charAt(index++) & 0xff];
759 buffer[bufferCount++] = (byte)((b1 << 2) | (b2 >> 4));
760
761 b1 = buffer[0];
762 b2 = buffer[1];
763 result.append((char)((b1 << 8) + (b2 & 0xff)));
764 break;
765 }
766
767
768 case 3:
769 {
770
771 if (bufferCount == 1) {
772 throw new MessagingException("Invalid UTF-7 encoded string");
773 }
774 byte b1 = decodingTable[original.charAt(index++) & 0xff];
775 byte b2 = decodingTable[original.charAt(index++) & 0xff];
776 byte b3 = decodingTable[original.charAt(index++) & 0xff];
777
778 buffer[bufferCount++] = (byte)((b1 << 2) | (b2 >> 4));
779 buffer[bufferCount++] = (byte)((b2 << 4) | (b3 >> 2));
780
781 b1 = buffer[0];
782 b2 = buffer[1];
783 result.append((char)((b1 << 8) + (b2 & 0xff)));
784 break;
785 }
786 }
787
788
789 return terminator + 1;
790 }
791
792
793
794
795
796
797
798 public String readAtom() throws MessagingException {
799 return readAtom(false);
800 }
801
802
803
804
805
806
807
808
809 public String readAtom(boolean expandedDelimiters) throws MessagingException {
810 Token token = next(false, expandedDelimiters);
811 int type = token.getType();
812
813 if (type != Token.ATOM) {
814 throw new ResponseFormatException("ATOM token expected in response: " + token.getValue());
815 }
816 return token.getValue();
817 }
818
819
820
821
822
823
824
825
826
827 public int readInteger() throws MessagingException {
828 Token token = next();
829 return token.getInteger();
830 }
831
832
833
834
835
836
837
838
839
840 public int readLong() throws MessagingException {
841 Token token = next();
842 return token.getInteger();
843 }
844
845
846
847
848
849
850
851
852
853
854 public String readStringOrNil() throws MessagingException {
855
856 Token token = next(true);
857 int type = token.getType();
858
859 if (type != Token.ATOM && type != Token.QUOTEDSTRING && type != Token.LITERAL && type != Token.NIL) {
860 throw new ResponseFormatException("String token or NIL expected in response: " + token.getValue());
861 }
862
863 return token.getValue();
864 }
865
866
867
868
869
870
871
872
873
874 protected String readQuotedStringOrNil() throws MessagingException {
875
876 Token token = next(true);
877 int type = token.getType();
878
879 if (type != Token.QUOTEDSTRING && type != Token.NIL) {
880 throw new ResponseFormatException("String token or NIL expected in response");
881 }
882
883 return token.getValue();
884 }
885
886
887
888
889
890
891
892
893
894
895 public Date readDate() throws MessagingException {
896 String value = readString();
897
898 try {
899 return dateParser.parse(value);
900 } catch (Exception e) {
901
902 return null;
903 }
904 }
905
906
907
908
909
910
911
912
913
914
915 public Date readDateOrNil() throws MessagingException {
916 String value = readStringOrNil();
917
918 if (value == null) {
919 return null;
920 }
921
922 try {
923 return dateParser.parse(value);
924 } catch (Exception e) {
925
926 return null;
927 }
928 }
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947 public InternetAddress readAddress() throws MessagingException {
948
949 if (peek().getType() != '(') {
950 return null;
951 }
952
953
954 checkLeftParen();
955
956
957 String personal = readStringOrNil();
958
959 String routing = readStringOrNil();
960
961 String mailbox = readStringOrNil();
962
963 String host = readStringOrNil();
964
965 checkRightParen();
966
967
968 if (host != null) {
969 StringBuffer address = new StringBuffer();
970 if (routing != null) {
971 address.append(routing);
972 address.append(':');
973 }
974 address.append(mailbox);
975 address.append('@');
976 address.append(host);
977
978 try {
979 return new InternetAddress(address.toString(), personal);
980 } catch (UnsupportedEncodingException e) {
981 throw new ResponseFormatException("Invalid Internet address format");
982 }
983 }
984 else {
985
986
987 if (mailbox == null) {
988 return null;
989 }
990
991 StringBuffer groupAddress = new StringBuffer();
992
993 groupAddress.append(mailbox);
994 groupAddress.append(':');
995 int count = 0;
996
997 while (true) {
998
999 InternetAddress member = readAddress();
1000 if (member == null) {
1001 groupAddress.append(';');
1002
1003 try {
1004 return new InternetAddress(groupAddress.toString(), personal);
1005 } catch (UnsupportedEncodingException e) {
1006 throw new ResponseFormatException("Invalid Internet address format");
1007 }
1008 }
1009 else {
1010 if (count != 0) {
1011 groupAddress.append(',');
1012 }
1013 groupAddress.append(member.toString());
1014 count++;
1015 }
1016 }
1017 }
1018 }
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029 public InternetAddress[] readAddressList() throws MessagingException {
1030
1031 Token token = next(true);
1032 int type = token.getType();
1033
1034
1035
1036 if (type == Token.NIL) {
1037 return null;
1038 }
1039
1040 else if (type != '(') {
1041 throw new ResponseFormatException("Missing '(' in response");
1042 }
1043
1044 List addresses = new ArrayList();
1045
1046
1047 while (notListEnd()) {
1048
1049
1050 InternetAddress address = readAddress();
1051 addresses.add(address);
1052 }
1053
1054 checkRightParen();
1055 return (InternetAddress[])addresses.toArray(new InternetAddress[addresses.size()]);
1056 }
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067 public boolean checkListEnd() throws MessagingException {
1068 Token token = peek(true);
1069 if (token.getType() == ')') {
1070
1071 next();
1072 return true;
1073 }
1074 return false;
1075 }
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085 public List readStringList() throws MessagingException {
1086 Token token = peek();
1087
1088 List list = new ArrayList();
1089
1090 if (token.getType() == '(') {
1091 next();
1092
1093 while (notListEnd()) {
1094 String value = readString();
1095
1096 if (value != null) {
1097 list.add(value);
1098 }
1099 }
1100
1101 next();
1102 }
1103 else {
1104
1105 String value = readString();
1106
1107 if (value != null) {
1108 list.add(value);
1109 }
1110 }
1111 return list;
1112 }
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 public List readStrings() throws MessagingException {
1123 List list = new ArrayList();
1124
1125 while (hasMore()) {
1126 String value = readString();
1127 list.add(value);
1128 }
1129 return list;
1130 }
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140 public void skipExtensionItem() throws MessagingException {
1141 Token token = next();
1142 int type = token.getType();
1143
1144
1145 if (type == '(') {
1146 skipNestedValue();
1147 }
1148
1149 else if (type == Token.EOF) {
1150 throw new ResponseFormatException("Missing ')'");
1151 }
1152 }
1153
1154
1155
1156
1157
1158
1159 public void skipNestedValue() throws MessagingException {
1160 Token token = next();
1161
1162 while (true) {
1163 int type = token.getType();
1164
1165 if (type == ')') {
1166 return;
1167 }
1168
1169 else if (type == Token.EOF) {
1170 throw new ResponseFormatException("Missing ')'");
1171 }
1172
1173 else if (type == '(') {
1174
1175 skipNestedValue();
1176 }
1177
1178 token = next();
1179 }
1180 }
1181
1182
1183
1184
1185
1186
1187
1188 public void checkToken(int type) throws MessagingException {
1189 Token token = next();
1190 if (token.getType() != type) {
1191 throw new ResponseFormatException("Unexpected token: " + token.getValue());
1192 }
1193 }
1194
1195
1196
1197
1198
1199
1200
1201
1202 public byte[] readByteArray() throws MessagingException {
1203 return readData(true);
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217 static public int getEncoding(byte[] value) {
1218
1219
1220 if (value.length == 0) {
1221 return Token.QUOTEDSTRING;
1222 }
1223
1224 for (int i = 0; i < value.length; i++) {
1225 int ch = value[i];
1226
1227 ch = ch & 0xff;
1228
1229
1230
1231 if (ch == 0x00) {
1232 return Token.LITERAL;
1233 }
1234
1235 if (ch > 0x7F) {
1236 return Token.LITERAL;
1237 }
1238
1239 if (ch == '\r') {
1240 return Token.LITERAL;
1241 }
1242
1243 if (ch == '\n') {
1244 return Token.LITERAL;
1245 }
1246
1247 if (atomDelimiters.indexOf(ch) != -1) {
1248 return Token.QUOTEDSTRING;
1249 }
1250
1251 if (ch < 0x20) {
1252 return Token.QUOTEDSTRING;
1253 }
1254 }
1255
1256 return Token.ATOM;
1257 }
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267 public ParameterList readParameterList() throws MessagingException {
1268 ParameterList params = new ParameterList();
1269
1270
1271 Token token = next(true, false);
1272
1273
1274 if (token.isType(token.NIL)) {
1275 return params;
1276 }
1277
1278
1279 while (notListEnd()) {
1280 String name = readString();
1281 String value = readString();
1282 params.set(name, value);
1283 }
1284
1285 checkRightParen();
1286 return params;
1287 }
1288
1289
1290
1291
1292
1293
1294
1295
1296 public boolean hasMore() throws MessagingException {
1297
1298 eatWhiteSpace();
1299 return pos < response.length;
1300 }
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311 public boolean notListEnd() throws MessagingException {
1312 return peek().getType() != ')';
1313 }
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323 public Flags readFlagList() throws MessagingException {
1324 Flags flags = new Flags();
1325
1326
1327 checkLeftParen();
1328
1329
1330 while (notListEnd()) {
1331
1332
1333
1334 Token token = next();
1335
1336 if (token.isType(token.ATOM)) {
1337
1338 flags.add(token.getValue());
1339 }
1340
1341
1342
1343 else if (token.isType('\\')) {
1344 token = next();
1345
1346 if (token.isType('*')) {
1347
1348 flags.add(Flags.Flag.USER);
1349 }
1350
1351 else if (token.isType(Token.ATOM)) {
1352 String name = token.getValue();
1353 if (name.equalsIgnoreCase("Seen")) {
1354 flags.add(Flags.Flag.SEEN);
1355 }
1356 else if (name.equalsIgnoreCase("RECENT")) {
1357 flags.add(Flags.Flag.RECENT);
1358 }
1359 else if (name.equalsIgnoreCase("DELETED")) {
1360 flags.add(Flags.Flag.DELETED);
1361 }
1362 else if (name.equalsIgnoreCase("ANSWERED")) {
1363 flags.add(Flags.Flag.ANSWERED);
1364 }
1365 else if (name.equalsIgnoreCase("DRAFT")) {
1366 flags.add(Flags.Flag.DRAFT);
1367 }
1368 else if (name.equalsIgnoreCase("FLAGGED")) {
1369 flags.add(Flags.Flag.FLAGGED);
1370 }
1371 else {
1372
1373
1374 flags.add("\\" + name);
1375 }
1376 }
1377 else {
1378 throw new MessagingException("Invalid Flag: " + token.getValue());
1379 }
1380 }
1381 else {
1382 throw new MessagingException("Invalid Flag: " + token.getValue());
1383 }
1384 }
1385
1386
1387 checkRightParen();
1388
1389 return flags;
1390 }
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401 public List readSystemNameList() throws MessagingException {
1402 List flags = new ArrayList();
1403
1404
1405 checkLeftParen();
1406
1407
1408 while (notListEnd()) {
1409
1410
1411
1412 Token token = next();
1413
1414
1415
1416 if (token.isType('\\')) {
1417 token = next();
1418
1419 if (token.isType(Token.ATOM)) {
1420
1421
1422
1423 flags.add("\\" + token.getValue());
1424 }
1425 else {
1426 throw new MessagingException("Invalid Flag: " + token.getValue());
1427 }
1428 }
1429 else {
1430 throw new MessagingException("Invalid Flag: " + token.getValue());
1431 }
1432 }
1433
1434
1435 checkRightParen();
1436
1437 return flags;
1438 }
1439 }
1440