View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.telnet;
19  
20  import java.io.IOException;
21  import java.io.OutputStream;
22  
23  /**
24   * Wraps an output stream.
25   * <p>
26   * In binary mode, the only conversion is to double IAC.
27   * <p>
28   * In ASCII mode, if convertCRtoCRLF is true (currently always true), any CR is converted to CRLF.
29   * IACs are doubled.
30   * Also a bare LF is converted to CRLF and a bare CR is converted to CR\0
31   * <p>
32   ***/
33  
34  
35  final class TelnetOutputStream extends OutputStream
36  {
37      private final TelnetClient __client;
38      // TODO there does not appear to be any way to change this value - should it be a ctor parameter?
39      private final boolean __convertCRtoCRLF = true;
40      private boolean __lastWasCR = false;
41  
42      TelnetOutputStream(TelnetClient client)
43      {
44          __client = client;
45      }
46  
47  
48      /***
49       * Writes a byte to the stream.
50       * <p>
51       * @param ch The byte to write.
52       * @exception IOException If an error occurs while writing to the underlying
53       *            stream.
54       ***/
55      @Override
56      public void write(int ch) throws IOException
57      {
58  
59          synchronized (__client)
60          {
61              ch &= 0xff;
62  
63              if (__client._requestedWont(TelnetOption.BINARY)) // i.e. ASCII
64              {
65                  if (__lastWasCR)
66                  {
67                      if (__convertCRtoCRLF)
68                      {
69                          __client._sendByte('\n');
70                          if (ch == '\n') // i.e. was CRLF anyway
71                          {
72                              __lastWasCR = false;
73                              return ;
74                          }
75                      } // __convertCRtoCRLF
76                      else if (ch != '\n')
77                       {
78                          __client._sendByte('\0'); // RFC854 requires CR NUL for bare CR
79                      }
80                  }
81  
82                  switch (ch)
83                  {
84                  case '\r':
85                      __client._sendByte('\r');
86                      __lastWasCR = true;
87                      break;
88                  case '\n':
89                      if (!__lastWasCR) { // convert LF to CRLF
90                          __client._sendByte('\r');
91                      }
92                      __client._sendByte(ch);
93                      __lastWasCR = false;
94                      break;
95                  case TelnetCommand.IAC:
96                      __client._sendByte(TelnetCommand.IAC);
97                      __client._sendByte(TelnetCommand.IAC);
98                      __lastWasCR = false;
99                      break;
100                 default:
101                     __client._sendByte(ch);
102                     __lastWasCR = false;
103                     break;
104                 }
105             } // end ASCII
106             else if (ch == TelnetCommand.IAC)
107             {
108                 __client._sendByte(ch);
109                 __client._sendByte(TelnetCommand.IAC);
110             } else {
111                 __client._sendByte(ch);
112             }
113         }
114     }
115 
116 
117     /***
118      * Writes a byte array to the stream.
119      * <p>
120      * @param buffer  The byte array to write.
121      * @exception IOException If an error occurs while writing to the underlying
122      *            stream.
123      ***/
124     @Override
125     public void write(byte buffer[]) throws IOException
126     {
127         write(buffer, 0, buffer.length);
128     }
129 
130 
131     /***
132      * Writes a number of bytes from a byte array to the stream starting from
133      * a given offset.
134      * <p>
135      * @param buffer  The byte array to write.
136      * @param offset  The offset into the array at which to start copying data.
137      * @param length  The number of bytes to write.
138      * @exception IOException If an error occurs while writing to the underlying
139      *            stream.
140      ***/
141     @Override
142     public void write(byte buffer[], int offset, int length) throws IOException
143     {
144         synchronized (__client)
145         {
146             while (length-- > 0) {
147                 write(buffer[offset++]);
148             }
149         }
150     }
151 
152     /*** Flushes the stream. ***/
153     @Override
154     public void flush() throws IOException
155     {
156         __client._flushOutputStream();
157     }
158 
159     /*** Closes the stream. ***/
160     @Override
161     public void close() throws IOException
162     {
163         __client._closeOutputStream();
164     }
165 }