1 /*****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20 package org.apache.james.util;
21
22 import java.io.FilterOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStream;
25
26 /***
27 * Adds extra dot if dot occurs in message body at beginning of line (according to RFC1939)
28 * Compare also org.apache.james.smtpserver.SMTPInputStream
29 */
30 public class ExtraDotOutputStream extends FilterOutputStream {
31
32
33
34
35
36
37
38
39
40
41
42 /***
43 * Counter for number of last (0A or 0D).
44 */
45 protected int countLast0A0D;
46
47 /***
48 * Constructor that wraps an OutputStream.
49 *
50 * @param out the OutputStream to be wrapped
51 */
52 public ExtraDotOutputStream(OutputStream out) {
53 super(out);
54 countLast0A0D = 2;
55 }
56
57 /***
58 * Writes a byte to the stream, adding dots where appropriate.
59 * Also fixes any naked CR or LF to the RFC 2821 mandated CFLF
60 * pairing.
61 *
62 * @param b the byte to write
63 *
64 * @throws IOException if an error occurs writing the byte
65 */
66 public void write(int b) throws IOException {
67 switch (b) {
68 case '.':
69 if (countLast0A0D == 2) {
70
71 out.write('.');
72 }
73 countLast0A0D = 0;
74 break;
75 case '\r':
76 if (countLast0A0D == 1) out.write('\n');
77 countLast0A0D = 1;
78 break;
79 case '\n':
80
81
82
83
84
85 if (countLast0A0D != 1) out.write('\r');
86 countLast0A0D = 2;
87 break;
88 default:
89
90 countLast0A0D = 0;
91 break;
92 }
93 out.write(b);
94 }
95
96 /***
97 * Ensure that the stream is CRLF terminated.
98 *
99 * @throws IOException if an error occurs writing the byte
100 */
101 public void checkCRLFTerminator() throws IOException {
102 if (countLast0A0D != 2) {
103 write('\n');
104 }
105 }
106 }