Skip to content

Package: BASE64MailboxEncoder

BASE64MailboxEncoder

nameinstructionbranchcomplexitylinemethod
BASE64MailboxEncoder(Writer)
M: 19 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
encode()
M: 177 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 23 C: 0
0%
M: 1 C: 0
0%
encode(String)
M: 75 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 24 C: 0
0%
M: 1 C: 0
0%
flush()
M: 21 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 260 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
write(int)
M: 53 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package org.eclipse.angus.mail.imap.protocol;
18:
19: import java.io.*;
20:
21:
22: /**
23: * From RFC2060:
24: *
25: * <blockquote><pre>
26: *
27: * 5.1.3. Mailbox International Naming Convention
28: *
29: * By convention, international mailbox names are specified using a
30: * modified version of the UTF-7 encoding described in [UTF-7]. The
31: * purpose of these modifications is to correct the following problems
32: * with UTF-7:
33: *
34: * 1) UTF-7 uses the "+" character for shifting; this conflicts with
35: * the common use of "+" in mailbox names, in particular USENET
36: * newsgroup names.
37: *
38: * 2) UTF-7's encoding is BASE64 which uses the "/" character; this
39: * conflicts with the use of "/" as a popular hierarchy delimiter.
40: *
41: * 3) UTF-7 prohibits the unencoded usage of "\"; this conflicts with
42: * the use of "\" as a popular hierarchy delimiter.
43: *
44: * 4) UTF-7 prohibits the unencoded usage of "~"; this conflicts with
45: * the use of "~" in some servers as a home directory indicator.
46: *
47: * 5) UTF-7 permits multiple alternate forms to represent the same
48: * string; in particular, printable US-ASCII chararacters can be
49: * represented in encoded form.
50: *
51: * In modified UTF-7, printable US-ASCII characters except for "&"
52: * represent themselves; that is, characters with octet values 0x20-0x25
53: * and 0x27-0x7e. The character "&" (0x26) is represented by the two-
54: * octet sequence "&-".
55: *
56: * All other characters (octet values 0x00-0x1f, 0x7f-0xff, and all
57: * Unicode 16-bit octets) are represented in modified BASE64, with a
58: * further modification from [UTF-7] that "," is used instead of "/".
59: * Modified BASE64 MUST NOT be used to represent any printing US-ASCII
60: * character which can represent itself.
61: *
62: * "&" is used to shift to modified BASE64 and "-" to shift back to US-
63: * ASCII. All names start in US-ASCII, and MUST end in US-ASCII (that
64: * is, a name that ends with a Unicode 16-bit octet MUST end with a "-
65: * ").
66: *
67: * For example, here is a mailbox name which mixes English, Japanese,
68: * and Chinese text: ~peter/mail/&ZeVnLIqe-/&U,BTFw-
69: *
70: * </pre></blockquote>
71: *
72: * This class will do the correct Encoding for the IMAP mailboxes.
73: *
74: * @author        Christopher Cotton
75: */
76:
77: public class BASE64MailboxEncoder {
78: protected byte[] buffer = new byte[4];
79: protected int bufsize = 0;
80: protected boolean started = false;
81: protected Writer out = null;
82:
83:
84: public static String encode(String original) {
85:         BASE64MailboxEncoder base64stream = null;
86:         char origchars[] = original.toCharArray();
87:         int length = origchars.length;
88:         boolean changedString = false;
89:         CharArrayWriter writer = new CharArrayWriter(length);
90:         
91:         // loop over all the chars
92:•        for(int index = 0; index < length; index++) {
93:          char current = origchars[index];
94:
95:          // octets in the range 0x20-0x25,0x27-0x7e are themselves
96:          // 0x26 "&" is represented as "&-"
97:•         if (current >= 0x20 && current <= 0x7e) {
98:•                if (base64stream != null) {
99:                  base64stream.flush();
100:                 }
101:                 
102:•                if (current == '&') {
103:                  changedString = true;
104:                  writer.write('&');
105:                  writer.write('-');
106:                 } else {
107:                  writer.write(current);
108:                 }
109:          } else {
110:
111:                 // use a B64MailboxEncoder to write out the other bytes
112:                 // as a modified BASE64. The stream will write out
113:                 // the beginning '&' and the ending '-' which is part
114:                 // of every encoding.
115:
116:•                if (base64stream == null) {
117:                  base64stream = new BASE64MailboxEncoder(writer);
118:                  changedString = true;
119:                 }
120:                 
121:                 base64stream.write(current);
122:          }
123:         }
124:
125:
126:•        if (base64stream != null) {
127:          base64stream.flush();
128:         }
129:
130:•        if (changedString) {
131:          return writer.toString();
132:         } else {
133:          return original;
134:         }
135: }
136:
137:
138: /**
139: * Create a BASE64 encoder
140: *
141: * @param        what        where to write the encoded name
142: */
143: public BASE64MailboxEncoder(Writer what) {
144:         out = what;
145: }
146:
147: public void write(int c) {
148:         try {
149:          // write out the initial character if this is the first time
150:•         if (!started) {
151:                 started = true;
152:                 out.write('&');
153:          }
154:         
155:          // we write each character as a 2 byte unicode character
156:          buffer[bufsize++] = (byte) (c >> 8);
157:          buffer[bufsize++] = (byte) (c & 0xff);
158:
159:•         if (bufsize >= 3) {
160:                 encode();
161:                 bufsize -= 3;
162:          }
163:         } catch (IOException e) {
164:          //e.printStackTrace();
165:         }
166: }
167:
168:
169: public void flush() {
170:         try {
171:          // flush any bytes we have
172:•         if (bufsize > 0) {
173:                 encode();
174:                 bufsize = 0;
175:          }
176:
177:          // write the terminating character of the encoding
178:•         if (started) {
179:                 out.write('-');
180:                 started = false;
181:          }
182:         } catch (IOException e) {
183:          //e.printStackTrace();
184:         }
185: }
186:
187:
188: protected void encode() throws IOException {
189:         byte a, b, c;
190:•        if (bufsize == 1) {
191:          a = buffer[0];
192:          b = 0;
193:          c = 0;
194:          out.write(pem_array[(a >>> 2) & 0x3F]);
195:          out.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
196:                 // no padding characters are written
197:•        } else if (bufsize == 2) {
198:          a = buffer[0];
199:          b = buffer[1];
200:          c = 0;
201:          out.write(pem_array[(a >>> 2) & 0x3F]);
202:          out.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
203:          out.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
204:                 // no padding characters are written
205:         } else {
206:          a = buffer[0];
207:          b = buffer[1];
208:          c = buffer[2];
209:          out.write(pem_array[(a >>> 2) & 0x3F]);
210:          out.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
211:          out.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
212:          out.write(pem_array[c & 0x3F]);
213:
214:          // copy back the extra byte
215:•         if (bufsize == 4)
216:                 buffer[0] = buffer[3];
217: }
218: }
219:
220: private final static char pem_array[] = {
221:         'A','B','C','D','E','F','G','H', // 0
222:         'I','J','K','L','M','N','O','P', // 1
223:         'Q','R','S','T','U','V','W','X', // 2
224:         'Y','Z','a','b','c','d','e','f', // 3
225:         'g','h','i','j','k','l','m','n', // 4
226:         'o','p','q','r','s','t','u','v', // 5
227:         'w','x','y','z','0','1','2','3', // 6
228:         '4','5','6','7','8','9','+',',' // 7
229: };
230: }