KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > mail > iap > Response


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)Response.java 1.18 05/08/29
24  *
25  * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package com.sun.mail.iap;
29
30 import java.io.*;
31 import java.util.*;
32 import com.sun.mail.util.*;
33
34 /**
35  * This class represents a response obtained from the input stream
36  * of an IMAP server.
37  *
38  * @version 1.1, 97/11/10
39  * @author John Mani
40  */

41
42 public class Response {
43     protected int index; // internal index (updated during the parse)
44
protected int pindex; // index after parse, for reset
45
protected int size; // number of valid bytes in our buffer
46
protected byte[] buffer = null;
47     protected int type = 0;
48     protected String JavaDoc tag = null;
49
50     private static final int increment = 100;
51
52     // The first and second bits indicate whether this response
53
// is a Continuation, Tagged or Untagged
54
public final static int TAG_MASK = 0x03;
55     public final static int CONTINUATION = 0x01;
56     public final static int TAGGED = 0x02;
57     public final static int UNTAGGED = 0x03;
58
59     // The third, fourth and fifth bits indicate whether this response
60
// is an OK, NO, BAD or BYE response
61
public final static int TYPE_MASK = 0x1C;
62     public final static int OK = 0x04;
63     public final static int NO = 0x08;
64     public final static int BAD = 0x0C;
65     public final static int BYE = 0x10;
66
67     // The sixth bit indicates whether a BYE response is synthetic or real
68
public final static int SYNTHETIC = 0x20;
69
70     public Response(String JavaDoc s) {
71     buffer = ASCIIUtility.getBytes(s);
72     size = buffer.length;
73     parse();
74     }
75
76    /**
77     * Read a new Response from the given Protocol
78     * @param p the Protocol object
79     */

80     public Response(Protocol p) throws IOException, ProtocolException {
81
82     // read one response into 'buffer'
83
ByteArray response = p.getInputStream().readResponse();
84     buffer = response.getBytes();
85     size = response.getCount() - 2; // Skip the terminating CRLF
86

87     parse();
88     }
89
90     /**
91      * Copy constructor.
92      */

93     public Response(Response r) {
94     index = r.index;
95     size = r.size;
96     buffer = r.buffer;
97     type = r.type;
98     tag = r.tag;
99     }
100
101     /**
102      * Return a Response object that looks like a BYE protocol response.
103      * Include the details of the exception in the response string.
104      */

105     public static Response byeResponse(Exception JavaDoc ex) {
106     String JavaDoc err = "* BYE JavaMail Exception: " + ex.toString();
107     err = err.replace('\r', ' ').replace('\n', ' ');
108     Response r = new Response(err);
109     r.type |= SYNTHETIC;
110     return r;
111     }
112
113     private void parse() {
114     index = 0; // position internal index at start
115

116     if (buffer[index] == '+') { // Continuation statement
117
type |= CONTINUATION;
118         index += 1; // Position beyond the '+'
119
return; // return
120
} else if (buffer[index] == '*') { // Untagged statement
121
type |= UNTAGGED;
122         index += 1; // Position beyond the '*'
123
} else { // Tagged statement
124
type |= TAGGED;
125         tag = readAtom(); // read the TAG, index positioned beyond tag
126
}
127
128     int mark = index; // mark
129
String JavaDoc s = readAtom(); // updates index
130
if (s.equalsIgnoreCase("OK"))
131         type |= OK;
132     else if (s.equalsIgnoreCase("NO"))
133         type |= NO;
134     else if (s.equalsIgnoreCase("BAD"))
135         type |= BAD;
136     else if (s.equalsIgnoreCase("BYE"))
137         type |= BYE;
138     else
139         index = mark; // reset
140

141     pindex = index;
142     return;
143     }
144
145     public void skipSpaces() {
146     while (index < size && buffer[index] == ' ')
147         index++;
148     }
149
150     /**
151      * Skip to the next space, for use in error recovery while parsing.
152      */

153     public void skipToken() {
154     while (index < size && buffer[index] != ' ')
155         index++;
156     }
157
158     public void skip(int count) {
159     index += count;
160     }
161
162     public byte peekByte() {
163     if (index < size)
164         return buffer[index];
165     else
166         return 0; // XXX - how else to signal error?
167
}
168
169     /**
170      * Return the next byte from this Statement.
171      * @return the next byte.
172      */

173     public byte readByte() {
174     if (index < size)
175         return buffer[index++];
176     else
177         return 0; // XXX - how else to signal error?
178
}
179
180     /**
181      * Extract an ATOM, starting at the current position. Updates
182      * the internal index to beyond the Atom.
183      * @return an Atom
184      */

185     public String JavaDoc readAtom() {
186     return readAtom('\0');
187     }
188
189     /**
190      * Extract an ATOM, but stop at the additional delimiter
191      * (if not NUL). Used to parse a response code inside [].
192      */

193     public String JavaDoc readAtom(char delim) {
194     skipSpaces();
195
196     if (index >= size) // already at end of response
197
return null;
198
199     /*
200      * An ATOM is any CHAR delimited by :
201      * SPACE | CTL | '(' | ')' | '{' | '%' | '*' | '"' | '\'
202      */

203     byte b;
204     int start = index;
205     while (index < size && ((b = buffer[index]) > ' ') &&
206            b != '(' && b != ')' && b != '%' && b != '*' &&
207            b != '"' && b != '\\' && b != 0x7f &&
208            (delim == '\0' || b != delim))
209         index++;
210
211     return ASCIIUtility.toString(buffer, start, index);
212     }
213
214     /**
215      * Read a string as an arbitrary sequence of characters,
216      * stopping at the delimiter Used to read part of a
217      * response code inside [].
218      */

219     public String JavaDoc readString(char delim) {
220     skipSpaces();
221
222     if (index >= size) // already at end of response
223
return null;
224
225     int start = index;
226     while (index < size && buffer[index] != delim)
227         index++;
228
229     return ASCIIUtility.toString(buffer, start, index);
230     }
231
232     public String JavaDoc[] readStringList() {
233     skipSpaces();
234
235     if (buffer[index] != '(') // not what we expected
236
return null;
237     index++; // skip '('
238

239     Vector v = new Vector();
240     do {
241         v.addElement(readString());
242     } while (buffer[index++] != ')');
243
244     int size = v.size();
245     if (size > 0) {
246         String JavaDoc[] s = new String JavaDoc[size];
247         v.copyInto(s);
248         return s;
249     } else // empty list
250
return null;
251     }
252
253     /**
254      * Extract an integer, starting at the current position. Updates the
255      * internal index to beyond the number. Returns -1 if a number was
256      * not found.
257      *
258      * @return a number
259      */

260     public int readNumber() {
261     // Skip leading spaces
262
skipSpaces();
263
264         int start = index;
265         while (index < size && Character.isDigit((char)buffer[index]))
266             index++;
267
268         if (index > start) {
269         try {
270         return ASCIIUtility.parseInt(buffer, start, index);
271         } catch (NumberFormatException JavaDoc nex) { }
272     }
273
274     return -1;
275     }
276
277     /**
278      * Extract a long number, starting at the current position. Updates the
279      * internal index to beyond the number. Returns -1 if a long number
280      * was not found.
281      *
282      * @return a long
283      */

284     public long readLong() {
285     // Skip leading spaces
286
skipSpaces();
287
288         int start = index;
289         while (index < size && Character.isDigit((char)buffer[index]))
290             index++;
291
292         if (index > start) {
293         try {
294         return ASCIIUtility.parseLong(buffer, start, index);
295         } catch (NumberFormatException JavaDoc nex) { }
296     }
297
298     return -1;
299     }
300
301     /**
302      * Extract a NSTRING, starting at the current position. Return it as
303      * a String. The sequence 'NIL' is returned as null
304      *
305      * NSTRING := QuotedString | Literal | "NIL"
306      *
307      * @return a String
308      */

309     public String JavaDoc readString() {
310     return (String JavaDoc)parseString(false, true);
311     }
312
313     /**
314      * Extract a NSTRING, starting at the current position. Return it as
315      * a ByteArrayInputStream. The sequence 'NIL' is returned as null
316      *
317      * NSTRING := QuotedString | Literal | "NIL"
318      *
319      * @return a ByteArrayInputStream
320      */

321     public ByteArrayInputStream readBytes() {
322     ByteArray ba = readByteArray();
323     if (ba != null)
324         return ba.toByteArrayInputStream();
325     else
326         return null;
327     }
328
329     /**
330      * Extract a NSTRING, starting at the current position. Return it as
331      * a ByteArray. The sequence 'NIL' is returned as null
332      *
333      * NSTRING := QuotedString | Literal | "NIL"
334      *
335      * @return a ByteArray
336      */

337     public ByteArray readByteArray() {
338     /*
339      * Special case, return the data after the continuation uninterpreted.
340      * It's usually a challenge for an AUTHENTICATE command.
341      */

342     if (isContinuation()) {
343         skipSpaces();
344         return new ByteArray(buffer, index, size - index);
345     }
346     return (ByteArray)parseString(false, false);
347     }
348
349     /**
350      * Extract an ASTRING, starting at the current position
351      * and return as a String. An ASTRING can be a QuotedString, a
352      * Literal or an Atom
353      *
354      * Any errors in parsing returns null
355      *
356      * ASTRING := QuotedString | Literal | Atom
357      *
358      * @return a String
359      */

360     public String JavaDoc readAtomString() {
361     return (String JavaDoc)parseString(true, true);
362     }
363
364     /**
365      * Generic parsing routine that can parse out a Quoted-String,
366      * Literal or Atom and return the parsed token as a String
367      * or a ByteArray. Errors or NIL data will return null.
368      */

369     private Object JavaDoc parseString(boolean parseAtoms, boolean returnString) {
370     byte b;
371
372     // Skip leading spaces
373
skipSpaces();
374     
375     b = buffer[index];
376     if (b == '"') { // QuotedString
377
index++; // skip the quote
378
int start = index;
379         int copyto = index;
380
381         while ((b = buffer[index]) != '"') {
382         if (b == '\\') // skip escaped byte
383
index++;
384         if (index != copyto) { // only copy if we need to
385
// Beware: this is a destructive copy. I'm
386
// pretty sure this is OK, but ... ;>
387
buffer[copyto] = buffer[index];
388         }
389         copyto++;
390         index++;
391         }
392         index++; // skip past the terminating quote
393

394         if (returnString)
395         return ASCIIUtility.toString(buffer, start, copyto);
396         else
397         return new ByteArray(buffer, start, copyto-start);
398     } else if (b == '{') { // Literal
399
int start = ++index; // note the start position
400

401         while (buffer[index] != '}')
402         index++;
403
404         int count = 0;
405         try {
406         count = ASCIIUtility.parseInt(buffer, start, index);
407         } catch (NumberFormatException JavaDoc nex) {
408         // throw new ParsingException();
409
return null;
410         }
411
412         start = index + 3; // skip "}\r\n"
413
index = start + count; // position index to beyond the literal
414

415         if (returnString) // return as String
416
return ASCIIUtility.toString(buffer, start, start + count);
417         else
418             return new ByteArray(buffer, start, count);
419     } else if (parseAtoms) { // parse as an ATOM
420
int start = index; // track this, so that we can use to
421
// creating ByteArrayInputStream below.
422
String JavaDoc s = readAtom();
423         if (returnString)
424         return s;
425         else // *very* unlikely
426
return new ByteArray(buffer, start, index);
427     } else if (b == 'N' || b == 'n') { // the only valid value is 'NIL'
428
index += 3; // skip past NIL
429
return null;
430     }
431     return null; // Error
432
}
433
434     public int getType() {
435     return type;
436     }
437
438     public boolean isContinuation() {
439     return ((type & TAG_MASK) == CONTINUATION);
440     }
441
442     public boolean isTagged() {
443     return ((type & TAG_MASK) == TAGGED);
444     }
445
446     public boolean isUnTagged() {
447     return ((type & TAG_MASK) == UNTAGGED);
448     }
449
450     public boolean isOK() {
451     return ((type & TYPE_MASK) == OK);
452     }
453
454     public boolean isNO() {
455     return ((type & TYPE_MASK) == NO);
456     }
457
458     public boolean isBAD() {
459     return ((type & TYPE_MASK) == BAD);
460     }
461
462     public boolean isBYE() {
463     return ((type & TYPE_MASK) == BYE);
464     }
465
466     public boolean isSynthetic() {
467     return ((type & SYNTHETIC) == SYNTHETIC);
468     }
469
470     /**
471      * Return the tag, if this is a tagged statement.
472      * @return tag of this tagged statement
473      */

474     public String JavaDoc getTag() {
475     return tag;
476     }
477
478     /**
479      * Return the rest of the response as a string, usually used to
480      * return the arbitrary message text after a NO response.
481      */

482     public String JavaDoc getRest() {
483     skipSpaces();
484     return ASCIIUtility.toString(buffer, index, size);
485     }
486
487     /**
488      * Reset pointer to beginning of response.
489      */

490     public void reset() {
491     index = pindex;
492     }
493
494     public String JavaDoc toString() {
495     return ASCIIUtility.toString(buffer, 0, size);
496     }
497
498 }
499
Popular Tags