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, any CR is converted to CRLF.
29 * IACs are doubled.
30 * <p>
31 ***/
32
33
34 final class TelnetOutputStream extends OutputStream
35 {
36 private final TelnetClient __client;
37 // TODO there does not appear to be any way to change this value - should it be a ctor parameter?
38 private final boolean __convertCRtoCRLF = true;
39 private boolean __lastWasCR = false;
40
41 TelnetOutputStream(TelnetClient client)
42 {
43 __client = client;
44 }
45
46
47 /***
48 * Writes a byte to the stream.
49 * <p>
50 * @param ch The byte to write.
51 * @exception IOException If an error occurs while writing to the underlying
52 * stream.
53 ***/
54 @Override
55 public void write(int ch) throws IOException
56 {
57
58 synchronized (__client)
59 {
60 ch &= 0xff;
61
62 if (__client._requestedWont(TelnetOption.BINARY)) // i.e. ASCII
63 {
64 if (__lastWasCR)
65 {
66 if (__convertCRtoCRLF)
67 {
68 __client._sendByte('\n');
69 if (ch == '\n') // i.e. was CRLF anyway
70 {
71 __lastWasCR = false;
72 return ;
73 }
74 } // __convertCRtoCRLF
75 else if (ch != '\n')
76 {
77 __client._sendByte('\0'); // RFC854 requires CR NUL for bare CR
78 }
79 }
80
81 __lastWasCR = false;
82
83 switch (ch)
84 {
85 case '\r':
86 __client._sendByte('\r');
87 __lastWasCR = true;
88 break;
89 case TelnetCommand.IAC:
90 __client._sendByte(TelnetCommand.IAC);
91 __client._sendByte(TelnetCommand.IAC);
92 break;
93 default:
94 __client._sendByte(ch);
95 break;
96 }
97 } // end ASCII
98 else if (ch == TelnetCommand.IAC)
99 {
100 __client._sendByte(ch);
101 __client._sendByte(TelnetCommand.IAC);
102 } else {
103 __client._sendByte(ch);
104 }
105 }
106 }
107
108
109 /***
110 * Writes a byte array to the stream.
111 * <p>
112 * @param buffer The byte array to write.
113 * @exception IOException If an error occurs while writing to the underlying
114 * stream.
115 ***/
116 @Override
117 public void write(byte buffer[]) throws IOException
118 {
119 write(buffer, 0, buffer.length);
120 }
121
122
123 /***
124 * Writes a number of bytes from a byte array to the stream starting from
125 * a given offset.
126 * <p>
127 * @param buffer The byte array to write.
128 * @param offset The offset into the array at which to start copying data.
129 * @param length The number of bytes to write.
130 * @exception IOException If an error occurs while writing to the underlying
131 * stream.
132 ***/
133 @Override
134 public void write(byte buffer[], int offset, int length) throws IOException
135 {
136 synchronized (__client)
137 {
138 while (length-- > 0) {
139 write(buffer[offset++]);
140 }
141 }
142 }
143
144 /*** Flushes the stream. ***/
145 @Override
146 public void flush() throws IOException
147 {
148 __client._flushOutputStream();
149 }
150
151 /*** Closes the stream. ***/
152 @Override
153 public void close() throws IOException
154 {
155 __client._closeOutputStream();
156 }
157 }