@@ -22,6 +22,13 @@ namespace TelnetNegotiationCore.Protocols;
2222/// </remarks>
2323public class CharsetProtocol : TelnetProtocolPluginBase
2424{
25+ private static readonly byte [ ] s_charsetRejected = new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ;
26+ private static readonly byte [ ] s_doCharset = new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . DO , ( byte ) Trigger . CHARSET } ;
27+ private static readonly byte [ ] s_willCharset = new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . WILL , ( byte ) Trigger . CHARSET } ;
28+ private static readonly byte [ ] s_ttableRejected = new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ;
29+ private static readonly byte [ ] s_ttableAck = new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_ACK , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ;
30+ private static readonly byte [ ] s_ttableNak = new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_NAK , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ;
31+
2532 private byte [ ] _charsetByteState = [ ] ;
2633 private int _charsetByteIndex = 0 ;
2734 private byte [ ] _acceptedCharsetByteState = [ ] ;
@@ -327,7 +334,7 @@ private async ValueTask CompleteCharsetAsync(StateMachine<State, Trigger>.Transi
327334
328335 if ( _charsetOffered && context . Mode == Interpreters . TelnetInterpreter . TelnetMode . Server )
329336 {
330- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
337+ await context . SendNegotiationAsync ( s_charsetRejected ) ;
331338 return ;
332339 }
333340
@@ -346,7 +353,7 @@ private async ValueTask CompleteCharsetAsync(StateMachine<State, Trigger>.Transi
346353
347354 if ( chosenEncoding == null )
348355 {
349- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
356+ await context . SendNegotiationAsync ( s_charsetRejected ) ;
350357 return ;
351358 }
352359
@@ -380,7 +387,7 @@ private async ValueTask CompleteAcceptedCharsetAsync(StateMachine<State, Trigger
380387 catch ( Exception ex )
381388 {
382389 context . Logger . LogError ( ex , "Unexpected error during Accepting Charset Negotiation. Could not find charset: {charset}" , ascii . GetString ( _acceptedCharsetByteState ! , 0 , _acceptedCharsetByteIndex ) ) ;
383- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
390+ await context . SendNegotiationAsync ( s_charsetRejected ) ;
384391 }
385392 context . Logger . LogInformation ( "Connection: Accepted Charset Negotiation for: {charset}" , CurrentEncoding . WebName ) ;
386393 _charsetOffered = false ;
@@ -389,14 +396,14 @@ private async ValueTask CompleteAcceptedCharsetAsync(StateMachine<State, Trigger
389396 private async ValueTask OnWillingCharsetAsync ( StateMachine < State , Trigger > . Transition _ , IProtocolContext context )
390397 {
391398 context . Logger . LogDebug ( "Connection: {ConnectionState}" , "Request charset negotiation from Client" ) ;
392- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . DO , ( byte ) Trigger . CHARSET } ) ;
399+ await context . SendNegotiationAsync ( s_doCharset ) ;
393400 _charsetOffered = false ;
394401 }
395402
396403 private async ValueTask WillingCharsetAsync ( IProtocolContext context )
397404 {
398405 context . Logger . LogDebug ( "Connection: {ConnectionState}" , "Announcing willingness to Charset!" ) ;
399- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . WILL , ( byte ) Trigger . CHARSET } ) ;
406+ await context . SendNegotiationAsync ( s_willCharset ) ;
400407 }
401408
402409 private async ValueTask OnDoCharsetAsync ( StateMachine < State , Trigger > . Transition _ , IProtocolContext context )
@@ -455,15 +462,15 @@ private async ValueTask CompleteTTableAsync(StateMachine<State, Trigger>.Transit
455462 if ( _ttableByteIndex < TTABLE_MIN_LENGTH )
456463 {
457464 context . Logger . LogWarning ( "TTABLE-IS message too short" ) ;
458- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
465+ await context . SendNegotiationAsync ( s_ttableRejected ) ;
459466 return ;
460467 }
461468
462469 var version = _ttableByteState [ 0 ] ;
463470 if ( version != TTABLE_VERSION_1 )
464471 {
465472 context . Logger . LogWarning ( "Unsupported TTABLE version: {Version}" , version ) ;
466- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
473+ await context . SendNegotiationAsync ( s_ttableRejected ) ;
467474 return ;
468475 }
469476
@@ -482,26 +489,26 @@ private async ValueTask CompleteTTableAsync(StateMachine<State, Trigger>.Transit
482489
483490 // Send TTABLE-ACK
484491 context . Logger . LogInformation ( "TTABLE accepted and acknowledged" ) ;
485- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_ACK , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
492+ await context . SendNegotiationAsync ( s_ttableAck ) ;
486493 }
487494 else
488495 {
489496 // Send TTABLE-NAK to request retransmission
490497 context . Logger . LogInformation ( "TTABLE rejected by callback, sending NAK" ) ;
491- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_NAK , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
498+ await context . SendNegotiationAsync ( s_ttableNak ) ;
492499 }
493500 }
494501 else
495502 {
496503 // No callback registered, reject TTABLE
497504 context . Logger . LogDebug ( "No TTABLE callback registered, rejecting" ) ;
498- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
505+ await context . SendNegotiationAsync ( s_ttableRejected ) ;
499506 }
500507 }
501508 catch ( Exception ex )
502509 {
503510 context . Logger . LogError ( ex , "Error processing TTABLE-IS message" ) ;
504- await context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
511+ await context . SendNegotiationAsync ( s_ttableRejected ) ;
505512 }
506513 }
507514
@@ -614,7 +621,7 @@ public async ValueTask SendTTableRejectedAsync()
614621 throw new InvalidOperationException ( "Protocol not initialized" ) ;
615622 }
616623
617- await Context . SendNegotiationAsync ( new byte [ ] { ( byte ) Trigger . IAC , ( byte ) Trigger . SB , ( byte ) Trigger . CHARSET , ( byte ) Trigger . TTABLE_REJECTED , ( byte ) Trigger . IAC , ( byte ) Trigger . SE } ) ;
624+ await Context . SendNegotiationAsync ( s_ttableRejected ) ;
618625 Context . Logger . LogInformation ( "Sent TTABLE-REJECTED message" ) ;
619626 }
620627
0 commit comments