diff options
author | Mike Buland <eichlan@xagasoft.com> | 2007-10-14 22:27:51 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2007-10-14 22:27:51 +0000 |
commit | e72d6077b475bc6142afc3b5967db113922c76f5 (patch) | |
tree | 45bdb7b69ec4c1dbcfadc1fa568b1d6b341a6f0f /src/protocoltelnet.cpp | |
parent | 44eac9521632f8da42f73085db945bdba45f8311 (diff) | |
download | libbu++-e72d6077b475bc6142afc3b5967db113922c76f5.tar.gz libbu++-e72d6077b475bc6142afc3b5967db113922c76f5.tar.bz2 libbu++-e72d6077b475bc6142afc3b5967db113922c76f5.tar.xz libbu++-e72d6077b475bc6142afc3b5967db113922c76f5.zip |
Fixed an interesting ideosyncacy in Bu::Hash in a safe way, I should try to do
this with the Bu::Archive next. Basically, there's one generic template
function that will convert anything that can safely cast to a uint32_t and that
supports direct comparisson, and doesn't have it's own override already to be
a Hash key, such as char, uint8_t, uint64_t, etc.
The Telnet protocol handler does everything I need it too for now, next up for
it is escape sequence handling, it would be nice to make this general too, by
using the termcap database or something, but there is an ANSI/ISO standard now,
I may just go ahead and use that. Also, it looks like it'd be pretty easy to
make the canonical mode editing functions be pluggable to facilitate different
types of editing, but that can be done down the road as well.
Diffstat (limited to 'src/protocoltelnet.cpp')
-rw-r--r-- | src/protocoltelnet.cpp | 532 |
1 files changed, 496 insertions, 36 deletions
diff --git a/src/protocoltelnet.cpp b/src/protocoltelnet.cpp index b0209db..e4fc926 100644 --- a/src/protocoltelnet.cpp +++ b/src/protocoltelnet.cpp | |||
@@ -1,30 +1,69 @@ | |||
1 | #include "bu/protocoltelnet.h" | 1 | #include "bu/protocoltelnet.h" |
2 | #include "bu/client.h" | 2 | #include "bu/client.h" |
3 | 3 | ||
4 | #define CODE_SE '\xf0' /**< End of subnegotiation params. */ | 4 | /* We apparently at least want defs for the lower 13, not sure we care about |
5 | #define CODE_NOP '\xf1' /**< No operation (keep-alive). */ | 5 | * the rest of the chars, maybe escape. |
6 | #define CODE_DM '\xf2' /**< Datastream side of a Synch. */ | 6 | */ |
7 | #define CODE_BRK '\xf3' /**< Break character. */ | 7 | #define CH_NUL '\x00' /* NUL */ |
8 | #define CODE_IP '\xf4' /**< Interrupt Process character. */ | 8 | #define CH_SOH '\x01' /* Start Of Heading */ |
9 | #define CODE_AO '\xf5' /**< Abort Output character. */ | 9 | #define CH_STX '\x02' /* Start of Text */ |
10 | #define CODE_AYT '\xf6' /**< Are You There? character. */ | 10 | #define CH_ETX '\x03' /* End of Text */ |
11 | #define CODE_EC '\xf7' /**< Erase Character character. */ | 11 | #define CH_EOT '\x04' /* End of transmission */ |
12 | #define CODE_EL '\xf8' /**< Erase Line character. */ | 12 | #define CH_ENQ '\x05' /* Enquiery */ |
13 | #define CODE_GA '\xf9' /**< Go Ahead signal. */ | 13 | #define CH_ACK '\x06' /* Acknowledge */ |
14 | #define CODE_SB '\xfa' /**< Begin subnegotiation options. */ | 14 | #define CH_BEL '\x07' /* Bell */ |
15 | #define CODE_WILL '\xfb' /**< Desire to do something. */ | 15 | #define CH_BS '\x08' /* Backspace */ |
16 | #define CODE_WONT '\xfc' /**< Refuse to perform. */ | 16 | #define CH_TAB '\x09' /* Horizontal Tab */ |
17 | #define CODE_DO '\xfd' /**< Request option. */ | 17 | #define CH_LF '\x0A' /* NL Line feed, new line */ |
18 | #define CODE_DONT '\xfe' /**< Demand a stop. */ | 18 | #define CH_VT '\x0B' /* Vertical Tab */ |
19 | 19 | #define CH_FF '\x0C' /* Form feed, new page */ | |
20 | #define CODE_IAC '\xff' /**< Interpret-As-Command. */ | 20 | #define CH_CR '\x0D' /* Carriage return */ |
21 | 21 | #define CH_ESC '\x1B' /* Escape */ | |
22 | #define OPT_BINARY '\x00' /**< Binary mode (file transfers?). */ | 22 | #define CH_DEL '\x7F' /* Delete */ |
23 | #define OPT_ECHO '\x01' /**< (local) Echo mode. */ | 23 | |
24 | #define CODE_SE '\xf0' /* End of subnegotiation params. */ | ||
25 | #define CODE_NOP '\xf1' /* No operation (keep-alive). */ | ||
26 | #define CODE_DM '\xf2' /* Datastream side of a Synch. */ | ||
27 | #define CODE_BRK '\xf3' /* Break character. */ | ||
28 | #define CODE_IP '\xf4' /* Interrupt Process character. */ | ||
29 | #define CODE_AO '\xf5' /* Abort Output character. */ | ||
30 | #define CODE_AYT '\xf6' /* Are You There? character. */ | ||
31 | #define CODE_EC '\xf7' /* Erase Character character. */ | ||
32 | #define CODE_EL '\xf8' /* Erase Line character. */ | ||
33 | #define CODE_GA '\xf9' /* Go Ahead signal. */ | ||
34 | #define CODE_SB '\xfa' /* Begin subnegotiation options. */ | ||
35 | #define CODE_WILL '\xfb' /* Desire to do something. */ | ||
36 | #define CODE_WONT '\xfc' /* Refuse to perform. */ | ||
37 | #define CODE_DO '\xfd' /* Request option. */ | ||
38 | #define CODE_DONT '\xfe' /* Demand a stop. */ | ||
39 | |||
40 | #define CODE_IAC '\xff' /* Interpret-As-Command. */ | ||
41 | |||
42 | #define OPT_BINARY '\x00' /* Binary mode (file transfers?). */ | ||
43 | #define OPT_ECHO '\x01' /* (local) Echo mode. */ | ||
44 | #define OPT_SUPGA '\x03' /* Suppress Go Ahead signals. */ | ||
45 | #define OPT_STATUS '\x05' /* Allow status messages. */ | ||
46 | #define OPT_TIMING '\x06' /* Place a timing mark in the code. */ | ||
47 | #define OPT_EXASCII '\x11' /* Extended ASCII. */ | ||
48 | #define OPT_LOGOUT '\x12' /* Logout. */ | ||
49 | #define OPT_TTYPE '\x18' /* Terminal Type. */ | ||
50 | #define OPT_NAWS '\x1f' /* Negotiate about window size. */ | ||
51 | #define OPT_TSPEED '\x20' /* Terminal Speed. */ | ||
52 | #define OPT_NEWENV '\x27' /* New Environment Option. */ | ||
53 | #define OPT_EXOPL '\xff' /* Can we, will we, handle extended options. */ | ||
54 | |||
55 | #ifndef __TELNET_DEBUG | ||
56 | # define printCode( a ) (void)0 | ||
57 | # define printOpt( a ) (void)0 | ||
58 | #endif | ||
24 | 59 | ||
25 | Bu::ProtocolTelnet::ProtocolTelnet() : | 60 | Bu::ProtocolTelnet::ProtocolTelnet() : |
26 | oBinary( *this, OPT_BINARY ), | 61 | oBinary( *this, OPT_BINARY ), |
27 | oEcho( *this, OPT_ECHO ) | 62 | oEcho( *this, OPT_ECHO ), |
63 | oNAWS( *this, OPT_NAWS ), | ||
64 | oSuppressGA(*this, OPT_SUPGA ), | ||
65 | bCanonical( true ), | ||
66 | bSubOpt( false ) | ||
28 | { | 67 | { |
29 | } | 68 | } |
30 | 69 | ||
@@ -34,13 +73,410 @@ Bu::ProtocolTelnet::~ProtocolTelnet() | |||
34 | 73 | ||
35 | void Bu::ProtocolTelnet::onNewConnection( Bu::Client *pClient ) | 74 | void Bu::ProtocolTelnet::onNewConnection( Bu::Client *pClient ) |
36 | { | 75 | { |
76 | this->pClient = pClient; | ||
37 | } | 77 | } |
38 | 78 | ||
39 | void Bu::ProtocolTelnet::onNewData( Bu::Client *pClient ) | 79 | void Bu::ProtocolTelnet::onNewData( Bu::Client *pClient ) |
40 | { | 80 | { |
81 | char bc; | ||
82 | int iLeft; | ||
83 | while( (iLeft = pClient->getInputSize()) ) | ||
84 | { | ||
85 | if( bSubOpt ) | ||
86 | { | ||
87 | pClient->peek( &bc, 1 ); | ||
88 | if( bc == CODE_IAC ) | ||
89 | { | ||
90 | if( iLeft <= 1 ) return; | ||
91 | char bc2; | ||
92 | printCode( CODE_IAC ); | ||
93 | pClient->peek( &bc2, 1, 1 ); | ||
94 | printCode( bc2 ); | ||
95 | if( bc2 == CODE_SE ) | ||
96 | { | ||
97 | bSubOpt = false; | ||
98 | onSubOpt(); | ||
99 | } | ||
100 | else if( bc2 == CODE_IAC ) | ||
101 | { | ||
102 | sSubBuf += CODE_IAC; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | // Error of some sort. | ||
107 | } | ||
108 | pClient->seek( 1 ); | ||
109 | } | ||
110 | else | ||
111 | { | ||
112 | sSubBuf += bc; | ||
113 | } | ||
114 | pClient->seek( 1 ); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | pClient->peek( &bc, 1 ); | ||
119 | if( bc == CODE_IAC ) | ||
120 | { | ||
121 | if( iLeft <= 1 ) return; | ||
122 | char bc2; | ||
123 | pClient->peek( &bc2, 1, 1 ); | ||
124 | printCode( bc ); | ||
125 | printCode( bc2 ); | ||
126 | |||
127 | switch( bc2 ) | ||
128 | { | ||
129 | case CODE_WILL: | ||
130 | if( iLeft <= 2 ) return; | ||
131 | { | ||
132 | char bc3; | ||
133 | pClient->peek( &bc3, 1, 2 ); | ||
134 | pClient->seek( 1 ); | ||
135 | printOpt( bc3 ); | ||
136 | onWill( bc3 ); | ||
137 | } | ||
138 | break; | ||
139 | |||
140 | case CODE_WONT: | ||
141 | if( iLeft <= 2 ) return; | ||
142 | { | ||
143 | char bc3; | ||
144 | pClient->peek( &bc3, 1, 2 ); | ||
145 | pClient->seek( 1 ); | ||
146 | printOpt( bc3 ); | ||
147 | onWont( bc3 ); | ||
148 | } | ||
149 | break; | ||
150 | |||
151 | case CODE_DO: | ||
152 | if( iLeft <= 2 ) return; | ||
153 | { | ||
154 | char bc3; | ||
155 | pClient->peek( &bc3, 1, 2 ); | ||
156 | pClient->seek( 1 ); | ||
157 | printOpt( bc3 ); | ||
158 | onDo( bc3 ); | ||
159 | } | ||
160 | break; | ||
161 | |||
162 | case CODE_DONT: | ||
163 | if( iLeft <= 2 ) return; | ||
164 | { | ||
165 | char bc3; | ||
166 | pClient->peek( &bc3, 1, 2 ); | ||
167 | pClient->seek( 1 ); | ||
168 | printOpt( bc3 ); | ||
169 | onDont( bc3 ); | ||
170 | } | ||
171 | break; | ||
172 | |||
173 | case CODE_SB: | ||
174 | if( iLeft <= 2 ) return; | ||
175 | { | ||
176 | pClient->peek( &cSubOpt, 1, 2 ); | ||
177 | pClient->seek( 1 ); | ||
178 | printOpt( cSubOpt ); | ||
179 | bSubOpt = true; | ||
180 | } | ||
181 | break; | ||
182 | |||
183 | case CODE_IAC: | ||
184 | sDataBuf += CODE_IAC; | ||
185 | printCode( CODE_IAC ); | ||
186 | break; | ||
187 | } | ||
188 | pClient->seek( 1 ); | ||
189 | #ifdef __TELNET_DEBUG | ||
190 | printf("\n"); | ||
191 | #endif | ||
192 | } | ||
193 | else if( bc == CODE_SB ) | ||
194 | { | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | // This is where control code handling goes | ||
199 | // Also, possibly, character code conversion, although I'm not | ||
200 | // sure that really matters anymore, go ASCII/UTF-8 | ||
201 | if( bCanonical ) | ||
202 | { | ||
203 | if( bc < 0x20 || bc >= CH_DEL ) | ||
204 | { | ||
205 | if( bc == CH_CR ) | ||
206 | { | ||
207 | if( iLeft <= 1 ) return; | ||
208 | char bc2; | ||
209 | pClient->peek( &bc2, 1, 1 ); | ||
210 | if( bc2 == CH_NUL || bc2 == CH_LF ) | ||
211 | { | ||
212 | onCtlChar( bc ); | ||
213 | gotLine( sDataBuf ); | ||
214 | sDataBuf.clear(); | ||
215 | } | ||
216 | pClient->seek( 1 ); | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | onCtlChar( bc ); | ||
221 | } | ||
222 | } | ||
223 | else | ||
224 | { | ||
225 | sDataBuf += bc; | ||
226 | if( oEcho.isLocalSet() ) | ||
227 | { | ||
228 | pClient->write( &bc, 1 ); | ||
229 | #ifdef __TELNET_DEBUG | ||
230 | printf("%c", bc ); | ||
231 | fflush( stdout ); | ||
232 | #endif | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | sDataBuf += bc; | ||
239 | if( oEcho.isLocalSet() ) | ||
240 | { | ||
241 | pClient->write( &bc, 1 ); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | pClient->seek( 1 ); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | // It's true, this code will not be executed if we only have half of an | ||
250 | // IAC code or multibyte escape sequence or something, but then again, it | ||
251 | // shouldn't be called then, and really, shouldn't be, it'll be called soon | ||
252 | // enough, when we get the rest of that code. | ||
253 | if( !bCanonical ) | ||
254 | { | ||
255 | gotData( sDataBuf ); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | void Bu::ProtocolTelnet::setCanonical( bool bCon ) | ||
260 | { | ||
261 | bCanonical = bCon; | ||
262 | } | ||
263 | |||
264 | bool Bu::ProtocolTelnet::isCanonical() | ||
265 | { | ||
266 | return bCanonical; | ||
267 | } | ||
268 | |||
269 | void Bu::ProtocolTelnet::write( const Bu::FString &sData ) | ||
270 | { | ||
271 | pClient->write( sData ); | ||
272 | } | ||
273 | |||
274 | void Bu::ProtocolTelnet::write( char *pData, int iSize ) | ||
275 | { | ||
276 | pClient->write( pData, iSize ); | ||
277 | } | ||
278 | |||
279 | void Bu::ProtocolTelnet::write( char cData ) | ||
280 | { | ||
281 | pClient->write( &cData, 1 ); | ||
282 | } | ||
283 | |||
284 | void Bu::ProtocolTelnet::onWill( char cCode ) | ||
285 | { | ||
286 | try | ||
287 | { | ||
288 | Option *pOpt = hOpts[cCode]; | ||
289 | if( pOpt->isRemoteEnabled() ) | ||
290 | { | ||
291 | pOpt->fOpts |= Option::fRemoteIs; | ||
292 | char buf[3] = { CODE_IAC, CODE_DO, cCode }; | ||
293 | pClient->write( buf, 3 ); | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | char buf[3] = { CODE_IAC, CODE_DONT, cCode }; | ||
298 | pClient->write( buf, 3 ); | ||
299 | } | ||
300 | |||
301 | } | ||
302 | catch( Bu::HashException &e ) | ||
303 | { | ||
304 | char buf[3] = { CODE_IAC, CODE_DONT, cCode }; | ||
305 | pClient->write( buf, 3 ); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | void Bu::ProtocolTelnet::onWont( char cCode ) | ||
310 | { | ||
311 | try | ||
312 | { | ||
313 | Option *pOpt = hOpts[cCode]; | ||
314 | |||
315 | pOpt->fOpts &= ~Option::fRemoteIs; | ||
316 | char buf[3] = { CODE_IAC, CODE_DONT, cCode }; | ||
317 | pClient->write( buf, 3 ); | ||
318 | } | ||
319 | catch( Bu::HashException &e ) | ||
320 | { | ||
321 | char buf[3] = { CODE_IAC, CODE_DONT, cCode }; | ||
322 | pClient->write( buf, 3 ); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | void Bu::ProtocolTelnet::onDo( char cCode ) | ||
327 | { | ||
328 | try | ||
329 | { | ||
330 | Option *pOpt = hOpts[cCode]; | ||
331 | if( pOpt->isLocalEnabled() ) | ||
332 | { | ||
333 | pOpt->fOpts |= Option::fLocalIs; | ||
334 | char buf[3] = { CODE_IAC, CODE_WILL, cCode }; | ||
335 | pClient->write( buf, 3 ); | ||
336 | } | ||
337 | else | ||
338 | { | ||
339 | char buf[3] = { CODE_IAC, CODE_WONT, cCode }; | ||
340 | pClient->write( buf, 3 ); | ||
341 | } | ||
342 | |||
343 | } | ||
344 | catch( Bu::HashException &e ) | ||
345 | { | ||
346 | char buf[3] = { CODE_IAC, CODE_WONT, cCode }; | ||
347 | pClient->write( buf, 3 ); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | void Bu::ProtocolTelnet::onDont( char cCode ) | ||
352 | { | ||
353 | try | ||
354 | { | ||
355 | Option *pOpt = hOpts[cCode]; | ||
356 | |||
357 | pOpt->fOpts &= ~Option::fLocalIs; | ||
358 | char buf[3] = { CODE_IAC, CODE_DONT, cCode }; | ||
359 | pClient->write( buf, 3 ); | ||
360 | } | ||
361 | catch( Bu::HashException &e ) | ||
362 | { | ||
363 | char buf[3] = { CODE_IAC, CODE_DONT, cCode }; | ||
364 | pClient->write( buf, 3 ); | ||
365 | } | ||
41 | } | 366 | } |
42 | 367 | ||
368 | void Bu::ProtocolTelnet::onSubOpt() | ||
369 | { | ||
370 | switch( cSubOpt ) | ||
371 | { | ||
372 | case OPT_NAWS: | ||
373 | { | ||
374 | uint16_t iWidth, iHeight; | ||
375 | ((char *)&iWidth)[1] = sSubBuf[0]; | ||
376 | ((char *)&iWidth)[0] = sSubBuf[1]; | ||
377 | ((char *)&iHeight)[1] = sSubBuf[2]; | ||
378 | ((char *)&iHeight)[0] = sSubBuf[3]; | ||
379 | onSubNAWS( iWidth, iHeight ); | ||
380 | } | ||
381 | break; | ||
43 | 382 | ||
383 | default: | ||
384 | onSubUnknown( cSubOpt, sSubBuf ); | ||
385 | break; | ||
386 | } | ||
387 | |||
388 | sSubBuf.clear(); | ||
389 | } | ||
390 | |||
391 | void Bu::ProtocolTelnet::onCtlChar( char cChr ) | ||
392 | { | ||
393 | #ifdef __TELNET_DEBUG | ||
394 | switch( cChr ) | ||
395 | { | ||
396 | case CH_NUL: printf("NUL "); break; | ||
397 | case CH_SOH: printf("SOH "); break; | ||
398 | case CH_STX: printf("STX "); break; | ||
399 | case CH_ETX: printf("ETX "); break; | ||
400 | case CH_EOT: printf("EOT "); break; | ||
401 | case CH_ENQ: printf("ENQ "); break; | ||
402 | case CH_ACK: printf("ACK "); break; | ||
403 | case CH_BEL: printf("BEL "); break; | ||
404 | case CH_BS: printf("BS "); break; | ||
405 | case CH_TAB: printf("TAB "); break; | ||
406 | case CH_LF: printf("LF "); break; | ||
407 | case CH_VT: printf("VT "); break; | ||
408 | case CH_FF: printf("FF "); break; | ||
409 | case CH_CR: printf("CR "); break; | ||
410 | case CH_ESC: printf("ESC "); break; | ||
411 | case CH_DEL: printf("DEL "); break; | ||
412 | default: printf("!![%02x] ", cChr ); break; | ||
413 | } | ||
414 | fflush( stdout ); | ||
415 | #endif | ||
416 | |||
417 | switch( cChr ) | ||
418 | { | ||
419 | case CH_DEL: | ||
420 | { | ||
421 | if( sDataBuf.getSize() > 0 ) | ||
422 | { | ||
423 | sDataBuf.resize( sDataBuf.getSize()-1 ); | ||
424 | char buf[3] = { CH_BS, ' ', CH_BS }; | ||
425 | pClient->write( buf, 3 ); | ||
426 | } | ||
427 | } | ||
428 | break; | ||
429 | |||
430 | } | ||
431 | } | ||
432 | |||
433 | #ifdef __TELNET_DEBUG | ||
434 | void Bu::ProtocolTelnet::printCode( char cCode ) | ||
435 | { | ||
436 | switch( cCode ) | ||
437 | { | ||
438 | case CODE_SE: printf("SE "); break; | ||
439 | case CODE_NOP: printf("NOP "); break; | ||
440 | case CODE_DM: printf("DM "); break; | ||
441 | case CODE_BRK: printf("BRK "); break; | ||
442 | case CODE_IP: printf("IP "); break; | ||
443 | case CODE_AO: printf("AO "); break; | ||
444 | case CODE_AYT: printf("AYT "); break; | ||
445 | case CODE_EC: printf("EC "); break; | ||
446 | case CODE_EL: printf("EL "); break; | ||
447 | case CODE_GA: printf("GA "); break; | ||
448 | case CODE_SB: printf("SB "); break; | ||
449 | case CODE_WILL: printf("WILL "); break; | ||
450 | case CODE_WONT: printf("WONT "); break; | ||
451 | case CODE_DO: printf("DO "); break; | ||
452 | case CODE_DONT: printf("DONT "); break; | ||
453 | case CODE_IAC: printf("IAC "); break; | ||
454 | default: printf("??%02x ", cCode ); break; | ||
455 | } | ||
456 | fflush( stdout ); | ||
457 | } | ||
458 | |||
459 | void Bu::ProtocolTelnet::printOpt( char cOpt ) | ||
460 | { | ||
461 | switch( cOpt ) | ||
462 | { | ||
463 | case OPT_BINARY: printf("BINARY "); break; | ||
464 | case OPT_ECHO: printf("ECHO "); break; | ||
465 | case OPT_SUPGA: printf("SUPGA "); break; | ||
466 | case OPT_STATUS: printf("STATUS "); break; | ||
467 | case OPT_TIMING: printf("TIMING "); break; | ||
468 | case OPT_EXASCII: printf("EXASCII "); break; | ||
469 | case OPT_LOGOUT: printf("LOGOUT "); break; | ||
470 | case OPT_TTYPE: printf("TTYPE "); break; | ||
471 | case OPT_NAWS: printf("NAWS "); break; | ||
472 | case OPT_TSPEED: printf("TSPEED "); break; | ||
473 | case OPT_NEWENV: printf("NEWENV "); break; | ||
474 | case OPT_EXOPL: printf("EXOPL "); break; | ||
475 | default: printf("??%02x ", cOpt); break; | ||
476 | } | ||
477 | fflush( stdout ); | ||
478 | } | ||
479 | #endif | ||
44 | 480 | ||
45 | Bu::ProtocolTelnet::Option::Option( Bu::ProtocolTelnet &rPT, char cCode ) : | 481 | Bu::ProtocolTelnet::Option::Option( Bu::ProtocolTelnet &rPT, char cCode ) : |
46 | rPT( rPT ), | 482 | rPT( rPT ), |
@@ -68,19 +504,31 @@ void Bu::ProtocolTelnet::Option::localSet( bool bSet ) | |||
68 | { | 504 | { |
69 | if( bSet == (bool)(fOpts&fLocalIs) ) return; | 505 | if( bSet == (bool)(fOpts&fLocalIs) ) return; |
70 | 506 | ||
71 | char buf[2]; | 507 | char buf[3] = { CODE_IAC, 0, cCode }; |
72 | 508 | ||
73 | if( bSet ) | 509 | if( bSet ) |
74 | { | 510 | { |
75 | buf[0] = CODE_WILL; | 511 | buf[1] = CODE_WILL; |
76 | buf[1] = cCode; | 512 | rPT.pClient->write( buf, 3 ); |
77 | rPT.pClient->write( buf, 2 ); | 513 | #ifdef __TELNET_DEBUG |
514 | printf("<= "); | ||
515 | rPT.printCode( buf[0] ); | ||
516 | rPT.printCode( buf[1] ); | ||
517 | rPT.printOpt( buf[2] ); | ||
518 | printf("\n"); | ||
519 | #endif | ||
78 | } | 520 | } |
79 | else | 521 | else |
80 | { | 522 | { |
81 | buf[0] = CODE_WONT; | 523 | buf[1] = CODE_WONT; |
82 | buf[1] = cCode; | 524 | rPT.pClient->write( buf, 3 ); |
83 | rPT.pClient->write( buf, 2 ); | 525 | #ifdef __TELNET_DEBUG |
526 | printf("<= "); | ||
527 | rPT.printCode( buf[0] ); | ||
528 | rPT.printCode( buf[1] ); | ||
529 | rPT.printOpt( buf[2] ); | ||
530 | printf("\n"); | ||
531 | #endif | ||
84 | } | 532 | } |
85 | } | 533 | } |
86 | 534 | ||
@@ -101,21 +549,33 @@ void Bu::ProtocolTelnet::Option::remoteEnable( bool bSet ) | |||
101 | 549 | ||
102 | void Bu::ProtocolTelnet::Option::remoteSet( bool bSet ) | 550 | void Bu::ProtocolTelnet::Option::remoteSet( bool bSet ) |
103 | { | 551 | { |
104 | if( bSet == (bool)(fOpts&fRemoteIs) ) return; | 552 | //if( bSet == (bool)(fOpts&fRemoteIs) ) return; |
105 | 553 | ||
106 | char buf[2]; | 554 | char buf[3] = { CODE_IAC, 0, cCode }; |
107 | 555 | ||
108 | if( bSet ) | 556 | if( bSet ) |
109 | { | 557 | { |
110 | buf[0] = CODE_DO; | 558 | buf[1] = CODE_DO; |
111 | buf[1] = cCode; | 559 | rPT.pClient->write( buf, 3 ); |
112 | rPT.pClient->write( buf, 2 ); | 560 | #ifdef __TELNET_DEBUG |
561 | printf("<= "); | ||
562 | rPT.printCode( buf[0] ); | ||
563 | rPT.printCode( buf[1] ); | ||
564 | rPT.printOpt( buf[2] ); | ||
565 | printf("\n"); | ||
566 | #endif | ||
113 | } | 567 | } |
114 | else | 568 | else |
115 | { | 569 | { |
116 | buf[0] = CODE_DONT; | 570 | buf[1] = CODE_DONT; |
117 | buf[1] = cCode; | 571 | rPT.pClient->write( buf, 3 ); |
118 | rPT.pClient->write( buf, 2 ); | 572 | #ifdef __TELNET_DEBUG |
573 | printf("<= "); | ||
574 | rPT.printCode( buf[0] ); | ||
575 | rPT.printCode( buf[1] ); | ||
576 | rPT.printOpt( buf[2] ); | ||
577 | printf("\n"); | ||
578 | #endif | ||
119 | } | 579 | } |
120 | } | 580 | } |
121 | 581 | ||