KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > mail > imap > protocol > BASE64MailboxEncoder


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  * @(#)BASE64MailboxEncoder.java 1.7 05/08/29
24  *
25  * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package com.sun.mail.imap.protocol;
29
30 import java.io.*;
31
32
33 /**
34  *
35  *
36   from RFC2060
37
38 5.1.3. Mailbox International Naming Convention
39
40    By convention, international mailbox names are specified using a
41    modified version of the UTF-7 encoding described in [UTF-7]. The
42    purpose of these modifications is to correct the following problems
43    with UTF-7:
44
45       1) UTF-7 uses the "+" character for shifting; this conflicts with
46          the common use of "+" in mailbox names, in particular USENET
47          newsgroup names.
48
49       2) UTF-7's encoding is BASE64 which uses the "/" character; this
50          conflicts with the use of "/" as a popular hierarchy delimiter.
51
52       3) UTF-7 prohibits the unencoded usage of "\"; this conflicts with
53          the use of "\" as a popular hierarchy delimiter.
54
55       4) UTF-7 prohibits the unencoded usage of "~"; this conflicts with
56          the use of "~" in some servers as a home directory indicator.
57
58       5) UTF-7 permits multiple alternate forms to represent the same
59          string; in particular, printable US-ASCII chararacters can be
60          represented in encoded form.
61
62    In modified UTF-7, printable US-ASCII characters except for "&"
63    represent themselves; that is, characters with octet values 0x20-0x25
64    and 0x27-0x7e. The character "&" (0x26) is represented by the two-
65    octet sequence "&-".
66
67    All other characters (octet values 0x00-0x1f, 0x7f-0xff, and all
68    Unicode 16-bit octets) are represented in modified BASE64, with a
69    further modification from [UTF-7] that "," is used instead of "/".
70    Modified BASE64 MUST NOT be used to represent any printing US-ASCII
71    character which can represent itself.
72
73    "&" is used to shift to modified BASE64 and "-" to shift back to US-
74    ASCII. All names start in US-ASCII, and MUST end in US-ASCII (that
75    is, a name that ends with a Unicode 16-bit octet MUST end with a "-
76    ").
77
78
79
80
81
82 Crispin Standards Track [Page 15]
83
84 RFC 2060 IMAP4rev1 December 1996
85
86
87       For example, here is a mailbox name which mixes English, Japanese,
88       and Chinese text: ~peter/mail/&ZeVnLIqe-/&U,BTFw-
89
90
91  * This class will do the correct Encoding for the IMAP mailboxes
92  *
93  * @version 1.7, 05/08/29
94  * @author Christopher Cotton
95  */

96
97 public class BASE64MailboxEncoder {
98     protected byte[] buffer = new byte[4];
99     protected int bufsize = 0;
100     protected boolean started = false;
101     protected Writer out = null;
102     
103
104     public static String JavaDoc encode(String JavaDoc original) {
105     BASE64MailboxEncoder base64stream = null;
106     char origchars[] = original.toCharArray();
107     int length = origchars.length;
108     boolean changedString = false;
109     CharArrayWriter writer = new CharArrayWriter(length);
110     
111     // loop over all the chars
112
for(int index = 0; index < length; index++) {
113         char current = origchars[index];
114
115         // octets in the range 0x20-0x25,0x27-0x7e are themselves
116
// 0x26 "&" is represented as "&-"
117
if (current >= 0x20 && current <= 0x7e) {
118         if (base64stream != null) {
119             base64stream.flush();
120         }
121         
122         if (current == '&') {
123             changedString = true;
124             writer.write('&');
125             writer.write('-');
126         } else {
127             writer.write(current);
128         }
129         } else {
130
131         // use a B64MailboxEncoder to write out the other bytes
132
// as a modified BASE64. The stream will write out
133
// the beginning '&' and the ending '-' which is part
134
// of every encoding.
135

136         if (base64stream == null) {
137             base64stream = new BASE64MailboxEncoder(writer);
138             changedString = true;
139         }
140         
141         base64stream.write(current);
142         }
143     }
144
145
146     if (base64stream != null) {
147         base64stream.flush();
148     }
149
150     if (changedString) {
151         return writer.toString();
152     } else {
153         return original;
154     }
155     }
156
157
158     /**
159      * Create a BASE64 encoder
160      */

161     public BASE64MailboxEncoder(Writer what) {
162     out = what;
163     }
164
165     public void write(int c) {
166     try {
167         // write out the initial character if this is the first time
168
if (!started) {
169         started = true;
170         out.write('&');
171         }
172     
173         // we write each character as a 2 byte unicode character
174
buffer[bufsize++] = (byte) (c >> 8);
175         buffer[bufsize++] = (byte) (c & 0xff);
176
177         if (bufsize >= 3) {
178         encode();
179         bufsize -= 3;
180         }
181     } catch (IOException e) {
182         //e.printStackTrace();
183
}
184     }
185     
186
187     public void flush() {
188     try {
189         // flush any bytes we have
190
if (bufsize > 0) {
191         encode();
192         bufsize = 0;
193         }
194
195         // write the terminating character of the encoding
196
if (started) {
197         out.write('-');
198         started = false;
199         }
200     } catch (IOException e) {
201         //e.printStackTrace();
202
}
203     }
204
205
206     protected void encode() throws IOException {
207     byte a, b, c;
208     if (bufsize == 1) {
209         a = buffer[0];
210         b = 0;
211         c = 0;
212         out.write(pem_array[(a >>> 2) & 0x3F]);
213         out.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
214         // no padding characters are written
215
} else if (bufsize == 2) {
216         a = buffer[0];
217         b = buffer[1];
218         c = 0;
219         out.write(pem_array[(a >>> 2) & 0x3F]);
220         out.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
221         out.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
222         // no padding characters are written
223
} else {
224         a = buffer[0];
225         b = buffer[1];
226         c = buffer[2];
227         out.write(pem_array[(a >>> 2) & 0x3F]);
228         out.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
229         out.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
230         out.write(pem_array[c & 0x3F]);
231
232         // copy back the extra byte
233
if (bufsize == 4)
234         buffer[0] = buffer[3];
235         }
236     }
237
238     private final static char pem_array[] = {
239     'A','B','C','D','E','F','G','H', // 0
240
'I','J','K','L','M','N','O','P', // 1
241
'Q','R','S','T','U','V','W','X', // 2
242
'Y','Z','a','b','c','d','e','f', // 3
243
'g','h','i','j','k','l','m','n', // 4
244
'o','p','q','r','s','t','u','v', // 5
245
'w','x','y','z','0','1','2','3', // 6
246
'4','5','6','7','8','9','+',',' // 7
247
};
248 }
249
Popular Tags