View Javadoc
1   /*
2    * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
3    * Copyright (C) 2010  Mickael Guessant
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18   */
19  package davmail.exchange;
20  
21  import java.io.FilterOutputStream;
22  import java.io.IOException;
23  import java.io.OutputStream;
24  
25  /**
26   * RFC 1939: 3 Basic Operations
27   * [...]
28   * If any line begins with the termination octet, the line is "byte-stuffed" by
29   * pre-pending the termination octet to that line of the response.
30   */
31  public class DoubleDotOutputStream extends FilterOutputStream {
32  
33      // remember last 2 bytes written
34      final int[] buf = {0, 0};
35  
36      public DoubleDotOutputStream(OutputStream out) {
37          super(out);
38      }
39  
40      @Override
41      public void write(int b) throws IOException {
42          if (b == '.' && (buf[0] == '\r' || buf[0] == '\n' || buf[0] == 0)) {
43              // line starts with '.', prepend it with an additional '.'
44              out.write('.');
45          }
46          out.write(b);
47  
48          buf[1] = buf[0];
49          buf[0] = b;
50      }
51  
52      /**
53       * RFC 1939: 3 Basic Operations
54       * [...]
55       * Hence a multi-line response is terminated with the five octets
56       * "CRLF.CRLF"
57       * <p/>
58       * Do not close actual outputstream
59       *
60       * @throws IOException on error
61       */
62      @Override
63      public void close() throws IOException {
64          if (buf[1] != '\r' || buf[0] != '\n') {
65              out.write('\r');
66              out.write('\n');
67          }
68          out.write('.');
69          out.write('\r');
70          out.write('\n');
71      }
72  
73  }