KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > ristretto > imap > IMAPCommand


1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is Ristretto Mail API.
15  *
16  * The Initial Developers of the Original Code are
17  * Timo Stich and Frederik Dietz.
18  * Portions created by the Initial Developers are Copyright (C) 2004
19  * All Rights Reserved.
20  *
21  * Contributor(s):
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either the GNU General Public License Version 2 or later (the "GPL"), or
25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the MPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the MPL, the GPL or the LGPL.
34  *
35  * ***** END LICENSE BLOCK ***** */

36 package org.columba.ristretto.imap;
37
38 import java.io.IOException JavaDoc;
39 import java.io.InputStream JavaDoc;
40 import java.io.OutputStream JavaDoc;
41 import java.nio.charset.Charset JavaDoc;
42 import java.util.Arrays JavaDoc;
43 import java.util.Iterator JavaDoc;
44
45 import org.columba.ristretto.io.StreamUtils;
46
47 /**
48  * Command which is send to the IMAP Server. IMAPCommand is used by the
49  * IMAPProtocol to send commands. Every command has a unique tag that identifies
50  * it and the answer from the server.
51  *
52  * <br>
53  * <b>RFC(s): </b> 3105
54  *
55  * @author Timo Stich <tstich@users.sourceforge.net>
56  */

57 public class IMAPCommand {
58     private String JavaDoc tag;
59
60     private String JavaDoc command;
61
62     private Object JavaDoc[] parameters;
63
64     private boolean lastWasLiteral;
65
66     private Charset JavaDoc charset;
67
68     /**
69      * Constructs the IMAPCommand.
70      * @param tag
71      * @param command
72      * @param parameters
73      */

74     public IMAPCommand(String JavaDoc tag, String JavaDoc command, Object JavaDoc[] parameters) {
75         this(tag, command, parameters, Charset.forName("ISO-8859-1"));
76     }
77
78     /**
79      * Constructs the IMAPCommand.
80      * @param tag
81      *
82      * @param command
83      */

84     public IMAPCommand(String JavaDoc tag, String JavaDoc command) {
85         this(tag, command, null);
86     }
87
88     /**
89      * Writes the IMAPCommand to an OutputStream. The given InputStream is also
90      * needed since the response of the IMAP server is needed to continue the
91      * command in case of a literal send.
92      *
93      * @param in
94      * @param out
95      * @throws IMAPException
96      * @throws IOException
97      */

98     public void writeToStream(IMAPInputStream in, OutputStream JavaDoc out)
99             throws IMAPException, IOException JavaDoc {
100         Object JavaDoc arg;
101         out.write(tag.getBytes("US-ASCII"));
102         out.write(' ');
103         out.write(command.getBytes("US-ASCII"));
104         // write arguments
105
if (parameters != null) {
106             Iterator JavaDoc it = Arrays.asList(parameters).iterator();
107             while (it.hasNext()) {
108                 out.write(' ');
109                 arg = it.next();
110                 if (arg instanceof String JavaDoc) {
111                     writeString((String JavaDoc) arg, in, out);
112                 } else if (arg instanceof String JavaDoc[]) {
113                     writeStringArray((String JavaDoc[]) arg, in, out);
114                 } else if (arg instanceof InputStream JavaDoc) {
115                     writeInputStream((InputStream JavaDoc) arg, in, out);
116                 } else if (arg instanceof SearchKey) {
117                     writeSearchKey((SearchKey) arg, in, out);
118                 } else if (arg instanceof byte[]) {
119                     writeByteArray(((byte[]) arg), in, out);
120                 } else if (arg instanceof Integer JavaDoc[]) {
121                     writeAddress(((Integer JavaDoc[]) arg), in, out);
122                 } else if (arg instanceof char[]) {
123                     writeCharArray(((char[]) arg), in, out);
124                 } else if (arg instanceof Section) {
125                     writeSection((Section) arg, in, out);
126                 } else {
127                     writeCharArray(arg.toString().toCharArray(), in, out);
128                 }
129             }
130         }
131
132         out.write('\r');
133         out.write('\n');
134         out.flush();
135     }
136
137     private void writeSearchKey(SearchKey key, IMAPInputStream in,
138             OutputStream JavaDoc out) throws IOException JavaDoc, IMAPException {
139         String JavaDoc[] strings = key.toStringArray();
140
141         if (strings.length > 1) {
142             out.write('(');
143             out.write(strings[0].getBytes(charset.name()));
144             for (int i = 1; i < strings.length; i++) {
145                 out.write(' ');
146                 writeString(strings[i], in, out);
147             }
148             out.write(')');
149         } else if (strings.length == 1) {
150             writeString(strings[0], in, out);
151         }
152
153     }
154
155     private void writeSection(Section section, IMAPInputStream in,
156             OutputStream JavaDoc out) throws IMAPException, IOException JavaDoc {
157         Object JavaDoc arg;
158         out.write('(');
159         out.write(section.getType().getBytes("US-ASCII"));
160         out.write('[');
161
162         Iterator JavaDoc it = Arrays.asList(section.getParams()).iterator();
163         while (it.hasNext()) {
164             arg = it.next();
165             if (arg instanceof String JavaDoc) {
166                 writeString((String JavaDoc) arg, in, out);
167                 if (it.hasNext())
168                     out.write(' ');
169             } else if (arg instanceof String JavaDoc[]) {
170                 writeStringArray((String JavaDoc[]) arg, in, out);
171             } else if (arg instanceof Integer JavaDoc[]) {
172                 writeAddress((Integer JavaDoc[]) arg, in, out);
173             } else {
174                 writeCharArray(arg.toString().toCharArray(), in, out);
175             }
176         }
177
178         out.write(']');
179         out.write(')');
180         lastWasLiteral = false;
181     }
182
183     /**
184      * @param cs
185      * @param in
186      * @param out
187      */

188     private void writeCharArray(char[] cs, IMAPInputStream in, OutputStream JavaDoc out)
189             throws IMAPException, IOException JavaDoc {
190         for (int i = 0; i < cs.length; i++) {
191             out.write(cs[i]);
192         }
193     }
194
195     /**
196      * @param integers
197      * @param in
198      * @param out
199      */

200     private void writeAddress(Integer JavaDoc[] integers, IMAPInputStream in,
201             OutputStream JavaDoc out) throws IMAPException, IOException JavaDoc {
202
203         out.write(new Integer JavaDoc(integers[0].intValue() + 1).toString().getBytes(
204                 charset.name()));
205         for (int i = 1; i < integers.length; i++) {
206             out.write('.');
207             out.write(new Integer JavaDoc(integers[i].intValue() + 1).toString()
208                     .getBytes(charset.name()));
209         }
210
211         lastWasLiteral = false;
212     }
213
214     /**
215      * @param bs
216      * @param in
217      * @param out
218      */

219     private void writeByteArray(byte[] bs, IMAPInputStream in, OutputStream JavaDoc out)
220             throws IMAPException, IOException JavaDoc {
221         out.write('{');
222         out.write(Integer.toString(bs.length).getBytes(charset.name()));
223         out.write('}');
224         out.write('\r');
225         out.write('\n');
226         out.flush();
227         IMAPResponse response = in.readResponse();
228         if (response.getResponseType() != IMAPResponse.RESPONSE_CONTINUATION)
229             throw new IMAPException(response);
230
231         out.write(bs);
232         out.flush();
233         lastWasLiteral = true;
234     }
235
236     /**
237      * @param stream
238      * @param out
239      */

240     private void writeInputStream(InputStream JavaDoc stream, IMAPInputStream in,
241             OutputStream JavaDoc out) throws IMAPException, IOException JavaDoc {
242         int size = 1000;
243
244         out.write('{');
245         out
246                 .write(Integer.toString(stream.available()).getBytes(
247                         charset.name()));
248         //out.write(Integer.toString(size).getBytes("US-ASCII"));
249
out.write('}');
250         out.write('\r');
251         out.write('\n');
252         out.flush();
253
254         IMAPResponse response = in.readResponse();
255         if (response.getResponseType() != IMAPResponse.RESPONSE_CONTINUATION)
256             throw new IMAPException(response);
257
258         // Copy the stream to the outputstream
259
StreamUtils.streamCopy(stream, out, 1400);
260
261         //debug
262
/*
263          * for(int i=0;i <size; i++) { out.write(Integer.toString(i %
264          * 10).getBytes()); } out.flush();
265          */

266         lastWasLiteral = true;
267     }
268
269     /**
270      * @param strings
271      * @param out
272      */

273     private void writeStringArray(String JavaDoc[] strings, IMAPInputStream in,
274             OutputStream JavaDoc out) throws IMAPException, IOException JavaDoc {
275         out.write('(');
276         if (strings.length > 0) {
277             out.write(strings[0].getBytes(charset.name()));
278             for (int i = 1; i < strings.length; i++) {
279                 out.write(' ');
280                 writeString(strings[i], in, out);
281             }
282         }
283         out.write(')');
284         lastWasLiteral = false;
285     }
286
287     /**
288      * @param sequence
289      */

290     private void writeString(String JavaDoc sequence, IMAPInputStream in,
291             OutputStream JavaDoc out) throws IMAPException, IOException JavaDoc {
292         // check if the argument is 7-bit, " and \ safe
293
boolean plainSafe = true;
294         boolean quote = sequence.length() == 0;
295
296         int i = 0;
297         while (i < sequence.length() && plainSafe) {
298             plainSafe &= sequence.charAt(i) < 128;
299             plainSafe &= sequence.charAt(i) != '\"';
300             plainSafe &= sequence.charAt(i) != '\\';
301             plainSafe &= sequence.charAt(i) != '\0';
302             plainSafe &= sequence.charAt(i) != '\r';
303             plainSafe &= sequence.charAt(i) != '\n';
304
305             quote |= sequence.charAt(i) == ' ';
306             quote |= sequence.charAt(i) == '(';
307             quote |= sequence.charAt(i) == ')';
308             quote |= sequence.charAt(i) == '{';
309             quote |= sequence.charAt(i) == '%';
310             quote |= sequence.charAt(i) == '*';
311             quote |= sequence.charAt(i) == ']';
312             //quote |= sequence.charAt(i) == '/';
313

314             i++;
315         }
316         // write as literal if not plain safe else just write the bytes
317
if (plainSafe) {
318             if (quote) {
319                 out.write('\"');
320             }
321             out.write(sequence.getBytes(charset.name()));
322             if (quote) {
323                 out.write('\"');
324             }
325             lastWasLiteral = false;
326         } else {
327             writeByteArray(sequence.getBytes(charset.name()), in, out);
328         }
329     }
330
331     /**
332      * Gets the tag that identifies the command.
333      *
334      * @return Returns the tag.
335      */

336     public String JavaDoc getTag() {
337         return tag;
338     }
339
340     /**
341      * Constructs the IMAPCommand.java.
342      *
343      * @param tag
344      * @param command
345      * @param parameters
346      * @param charset
347      */

348     public IMAPCommand(String JavaDoc tag, String JavaDoc command, Object JavaDoc[] parameters,
349             Charset JavaDoc charset) {
350         this.tag = tag;
351         this.command = command;
352         this.parameters = parameters;
353         this.charset = charset;
354     }
355
356     /**
357      * Estimates the length of the Command without literal sizes. This is used
358      * to ensure that the total length is less than 1000 octets as proposed in
359      * RFC 2683.
360      *
361      * @return the estimated total length of the command.
362      */

363     public int estimateLength() {
364         // Tag + WS + command
365
int estimatedLength = command.length() + tag.length() + 1;
366
367         // Sum the estimated length for each parameter
368
if (parameters != null) {
369             for (int i = 0; i < parameters.length; i++) {
370                 // estimated the length of the parameter
371
if (parameters[i] instanceof char[]) {
372                     estimatedLength += ((char[]) parameters[i]).length;
373                 }
374
375                 else if (parameters[i] instanceof String JavaDoc) {
376                     estimatedLength += ((String JavaDoc) parameters[i]).length();
377                 }
378
379                 else if (parameters[i] instanceof String JavaDoc[]) {
380                     String JavaDoc[] strings = (String JavaDoc[]) parameters[i];
381                     for (int j = 0; j < strings.length; j++) {
382                         estimatedLength += strings[j].length();
383                     }
384                 }
385
386                 else if (parameters[i] instanceof SearchKey) {
387                     String JavaDoc[] strings = ((SearchKey) parameters[i])
388                             .toStringArray();
389                     for (int j = 0; j < strings.length; j++) {
390                         estimatedLength += strings[j].length();
391                     }
392                 }
393
394                 else {
395                     // default length
396
estimatedLength += 3;
397                 }
398
399                 // this is for space, parenthesis, etc.
400
estimatedLength++;
401             }
402         }
403
404         return estimatedLength;
405     }
406 }
Popular Tags