author | Michael Krelin <hacker@klever.net> | 2004-07-05 01:53:09 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2004-07-05 01:53:09 (UTC) |
commit | 885f8cc426a8840ae61023b75f3f0e4a1e268082 (patch) (side-by-side diff) | |
tree | 5e942d450c97ca0bf0f9cfb80aa0fefb486535d9 /options.cpp | |
download | kinsole-885f8cc426a8840ae61023b75f3f0e4a1e268082.zip kinsole-885f8cc426a8840ae61023b75f3f0e4a1e268082.tar.gz kinsole-885f8cc426a8840ae61023b75f3f0e4a1e268082.tar.bz2 |
initial commit into svn repository
git-svn-id: http://svn.klever.net/kin/kinsole/trunk@1 fe716a7a-6dde-0310-88d9-d003556173a8
-rw-r--r-- | options.cpp | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/options.cpp b/options.cpp new file mode 100644 index 0000000..171ae4a --- a/dev/null +++ b/options.cpp @@ -0,0 +1,371 @@ +
+enum _TOption {
+ toBinaryTransmission = 0,
+ toEcho = 1, // Done.
+ toReconnection = 2,
+ toSuppressGA = 3, // Eaten
+ toApproxMsgSizeNegotiation = 4,
+ toStatus = 5, // Half-implemented
+ toTimingMark = 6,
+ toRemoteControlledTransAndEcho = 7,
+ toOutputLineWidth = 8,
+ toOutputPageSize = 9,
+ toOutputCRDisposition = 10,
+ toOutputHTabstops = 11,
+ toOutputHTabDisposition = 12,
+ toOutputFFDisposition = 13,
+ toOutputVTabstops = 14,
+ toOutputVTabDisposition = 15,
+ toOutputLFDisposition = 16,
+ toExtendedASCII = 17,
+ toLogout = 18,
+ toByteMacro = 19,
+ toDET = 20,
+ toSUPDUP = 22, // ???
+ toSUPDUPOutput = 22,
+ toSendLocation = 23,
+ toTerminalType =24, // Done.
+ toEndOfRecord = 25,
+ toTACACSUserId = 26,
+ toOutputMarking = 27,
+ toTerminalLocationNumber = 28,
+ toTelnet3270Regime = 29,
+ toX3PAD = 30,
+ toNAWS = 31, // Done.
+ toTerminalSpeed = 32, // No need to implement, really.
+ toRemoteFlowControl = 33, // !!!
+ toLineMode = 34,
+ toXDisplayLocation = 35, // No need to implement until we
+ // do our own X-Server.
+ toEnvironmentOption = 36,
+ toAuthenticationOption = 37,
+ toEncryptionOption = 38,
+ toNewEnviron = 39, // Need to implement
+ toTN3270E = 40,
+ toExtendedOptionsList = 255
+};
+
+struct TOption {
+ enum _state {
+ stateNone=0, stateNo, stateYes, stateWantNo, stateWantYes
+ };
+ UINT m_StateU:3; // State - US
+ UINT m_StateH:3; // State - HIM
+ int m_Q:1;
+ int m_Supported:1;
+ UINT m_SBCluster;
+ UINT m_AllocatedSB;
+ UINT m_StoredSB;
+ LPBYTE m_SB;
+
+ BOOL (*m_OnDo)();
+ BOOL (*m_OnDont)();
+ BOOL (*m_OnWill)();
+ BOOL (*m_OnWont)();
+ BOOL (*m_OnSB)(LPBYTE data,UINT size);
+ BOOL (*m_OnInit)();
+
+ BOOL OnDo() { return m_OnDo?(*m_OnDo)():FALSE; }
+ BOOL OnDont() { return m_OnDont?(*m_OnDont)():FALSE; }
+ BOOL OnWill() { return m_OnWill?(*m_OnWill)():FALSE; }
+ BOOL OnWont() { return m_OnWont?(*m_OnWont)():FALSE; }
+ BOOL OnSB(LPBYTE data,UINT size) { return m_OnSB?(*m_OnSB)(data,size):FALSE; }
+ BOOL OnInit() { return m_OnInit?(*m_OnInit)():FALSE; }
+
+ BOOL StoreSByte(BYTE c) {
+ if(m_AllocatedSB>=m_StoredSB){
+ ASSERT(m_SBCluster);
+ LPBYTE nsb = new BYTE[m_AllocatedSB+m_SBCluster];
+ ASSERT(nsb);
+ if(m_StoredSB){
+ ASSERT(m_SB);
+ memmove(nsb,m_SB,m_StoredSB);
+ }
+ if(m_SB)
+ delete m_SB;
+ m_SB = nsb;
+ }
+ ASSERT(m_SB);
+ m_SB[m_StoredSB++]=c;
+ return TRUE;
+ }
+ BOOL CleanSB() {
+ if(m_SB)
+ delete m_SB;
+ m_SB = NULL;
+ m_AllocatedSB=m_StoredSB=0;
+ return TRUE;
+ }
+
+} Options[256];
+
+
+BOOL AskWill(BYTE o);
+BOOL AskWont(BYTE o);
+BOOL AskDo(BYTE o);
+BOOL AskDont(BYTE o);
+
+#include "NAWS.cpp"
+#include "terminal.cpp"
+#include "status.cpp"
+#include "NEW-ENVIRON.cpp"
+#include "TIMING-MARK.cpp"
+
+BOOL On_ACK() { return TRUE; }
+
+
+void InitOptionsTable()
+{
+ memset(Options,0,sizeof(Options));
+ // Echo
+ Options[toEcho].m_OnDo = On_ACK;
+ Options[toEcho].m_OnDont = On_ACK;
+ Options[toEcho].m_OnWill = On_ACK;
+ Options[toEcho].m_OnWont = On_ACK;
+ // Suppress Go-Ahead
+ Options[toSuppressGA].m_OnWill = On_ACK;
+ Options[toSuppressGA].m_OnDo = On_ACK;
+ // Status
+ Options[toStatus].m_OnWill = statusOnWill;
+ Options[toStatus].m_OnDo = statusOnDo;
+ Options[toStatus].m_OnSB = statusOnSB;
+ // Terminal Type;
+ Options[toTerminalType].m_OnDo = terminaltypeOnDo;
+ Options[toTerminalType].m_OnSB = terminaltypeOnSB;
+ Options[toTerminalType].m_OnInit = terminaltypeOnInit;
+ Options[toTerminalType].m_SBCluster = 32;
+ // NAWS
+ Options[toNAWS].m_OnDo = nawsOnDo;
+ Options[toNAWS].m_SBCluster = 16;
+ // New Environment
+ Options[toNewEnviron].m_OnDo = newenvironOnDo;
+ Options[toNewEnviron].m_OnDont = newenvironOnDont;
+ Options[toNewEnviron].m_OnSB = newenvironOnSB;
+ Options[toNewEnviron].m_SBCluster = 32;
+ // Timing Mark
+ Options[toTimingMark].m_OnDo = tmOnDo;
+ Options[toTimingMark].m_OnWill = tmOnWill;
+
+ for(int tmp=0;tmp<(sizeof(Options)/sizeof(*Options));tmp++){
+ TOption& to = Options[tmp];
+ to.OnInit();
+ if(to.m_OnDo || to.m_OnDont || to.m_OnWill || to.m_OnWont
+ || to.m_OnSB || to.m_OnInit)
+ to.m_Supported=TRUE;
+ if(!to.m_SBCluster)
+ to.m_SBCluster=128;
+ }
+}
+
+void ProcessDO(BYTE c)
+{
+TOption& to = Options[c];
+ // Ignore this junk if we're already in desired mode of operation
+ if(to.m_StateU==TOption::stateYes){
+ connState = cstateNone;
+ return;
+ }
+ TRACE1("He want us to DO %d\n",(WORD)c);
+ if(!to.m_Supported){
+ TRACE1("Unsupported option = %d\n",(WORD)c);
+ // Option is not suported - send WONT and switch to stateNo unless
+ // we've already denied this option.
+ if(to.m_StateU == TOption::stateNone){
+ VERIFY(ShowUnwill(c));
+ to.m_StateU = TOption::stateNo;
+ }
+ }else{
+ // Okay, if we do - we do and tell him so, unless we asked for it.
+ // Otherwise - Tell him we're not about to.
+ if(to.OnDo()){
+ if(to.m_StateU!=TOption::stateWantYes)
+ VERIFY(ShowWill(c));
+ to.m_StateU = TOption::stateYes;
+ }else{
+ if(to.m_StateU!=TOption::stateWantNo)
+ VERIFY(ShowUnwill(c));
+ to.m_StateU = TOption::stateNo;
+ }
+ }
+ connState = cstateNone;
+}
+
+void ProcessWILL(BYTE c)
+{
+TOption& to = Options[c];
+ // Ignore this junk if we consider him already in this mode
+ if(to.m_StateH==TOption::stateYes){
+ connState = cstateNone;
+ return;
+ }
+ TRACE1("He WILL %d\n",(WORD)c);
+ if(!to.m_Supported){
+ TRACE1("Unsupported option = %d\n",(WORD)c);
+ // Since we don't expect remote end to use this option - beg him
+ // not to go for it unless we think we already did.
+ if(to.m_StateH == TOption::stateNone){
+ VERIFY(BegDont(c));
+ to.m_StateH = TOption::stateNo;
+ }
+ }else{
+ if(to.OnWill()){
+ // We've accepted this - tell him to go ahead if we thought he's
+ // in opposite state and adjust our vision/
+ if(to.m_StateH!=TOption::stateWantYes)
+ VERIFY(BegDo(c));
+ to.m_StateH = TOption::stateYes;
+ }else{
+ if(to.m_StateH!=TOption::stateWantNo)
+ VERIFY(BegDont(c));
+ to.m_StateH = TOption::stateNo;
+ }
+ }
+ connState = cstateNone;
+}
+
+void ProcessWONT(BYTE c)
+{
+TOption& to = Options[c];
+ // Ignore this junk if we consider him already in this mode
+ if(to.m_StateH==TOption::stateNo){
+ connState = cstateNone;
+ return;
+ }
+ TRACE1("He WONT %d\n",(WORD)c);
+ if(!to.m_Supported){
+ TRACE1("Unsupported option = %d\n",(WORD)c);
+ // Since we don't expect remote end to use this option - beg him
+ // not to go for it unless we think we already did.
+ if(to.m_StateH == TOption::stateNone){
+ VERIFY(BegDont(c));
+ to.m_StateH = TOption::stateNo;
+ }
+ }else{
+ if(to.OnWont()){
+ // We've accepted this - tell him to go ahead if we thought he's
+ // in opposite state and adjust our vision/
+ if(to.m_StateH!=TOption::stateWantNo)
+ VERIFY(BegDont(c));
+ to.m_StateH = TOption::stateNo;
+ }else{
+ if(to.m_StateH!=TOption::stateWantYes)
+ VERIFY(BegDo(c));
+ to.m_StateH = TOption::stateYes;
+ }
+ }
+ connState = cstateNone;
+}
+
+void ProcessDONT(BYTE c)
+{
+TOption& to = Options[c];
+ // Ignore this junk if we consider him already in this mode
+ if(to.m_StateU==TOption::stateNo){
+ connState = cstateNone;
+ return;
+ }
+ TRACE1("He want us to DONT %d\n",(WORD)c);
+ if(!to.m_Supported){
+ TRACE1("DONT for unsupported option = %d\n",(WORD)c);
+ // Since we don't expect remote end to use this option - beg him
+ // not to go for it unless we think we already did.
+ if(to.m_StateU == TOption::stateNone){
+ VERIFY(ShowUnwill(c));
+ to.m_StateU = TOption::stateNo;
+ }
+ }else{
+ if(to.OnDont()){
+ if(to.m_StateU!=TOption::stateWantNo)
+ VERIFY(ShowUnwill(c));
+ to.m_StateU = TOption::stateNo;
+ }else{
+ if(to.m_StateU!=TOption::stateWantYes)
+ VERIFY(ShowWill(c));
+ to.m_StateU = TOption::stateYes;
+ }
+ }
+ connState = cstateNone;
+}
+
+void ProcessSBData(BYTE c)
+{
+ switch(connState){
+ case cstateSBData:
+ if(c==tnIAC){
+ connState=cstateSBDataIAC;
+ return;
+ }
+ break;
+ case cstateSBDataIAC:
+ if(c==tnSE){
+ // Just let option handler process the data
+ TOption& to = Options[negOption];
+ to.OnSB(to.m_SB,to.m_StoredSB);
+ to.CleanSB();
+ connState = cstateNone;
+ return;
+ }
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+TOption& to = Options[negOption];
+ to.StoreSByte(c);
+}
+
+BOOL AskWill(BYTE o)
+{
+TOption& to = Options[o];
+ if(to.m_StateU==TOption::stateYes || to.m_StateU==TOption::stateWantYes)
+ return TRUE;
+#ifdef _DEBUG
+ if(to.m_StateU==TOption::stateWantNo)
+ TRACE1("NEED TO QUEUE %d\n",(WORD)o);
+#endif
+ VERIFY(ShowWill(o));
+ to.m_StateU=TOption::stateWantYes;
+ return TRUE;
+}
+
+BOOL AskUnwill(BYTE o)
+{
+TOption& to = Options[o];
+ if(to.m_StateU==TOption::stateNo || to.m_StateU==TOption::stateWantNo)
+ return TRUE;
+#ifdef _DEBUG
+ if(to.m_StateU==TOption::stateWantNo)
+ TRACE1("NEED TO QUEUE %d\n",(WORD)o);
+#endif
+ VERIFY(ShowUnwill(o));
+ to.m_StateU=TOption::stateWantNo;
+ return TRUE;
+}
+
+BOOL AskDo(BYTE o)
+{
+TOption& to = Options[o];
+ if(to.m_StateH==TOption::stateYes || to.m_StateH==TOption::stateWantYes)
+ return TRUE;
+#ifdef _DEBUG
+ if(to.m_StateH==TOption::stateWantNo)
+ TRACE1("NEED TO QUEUE %d\n",(WORD)o);
+#endif
+ VERIFY(BegDo(o));
+ to.m_StateH=TOption::stateWantYes;
+ return TRUE;
+}
+
+BOOL AskDont(BYTE o)
+{
+TOption& to = Options[o];
+ if(to.m_StateH==TOption::stateNo || to.m_StateH==TOption::stateWantNo)
+ return TRUE;
+#ifdef _DEBUG
+ if(to.m_StateH==TOption::stateWantYes)
+ TRACE1("NEED TO QUEUE %d\n",(WORD)o);
+#endif
+ VERIFY(BegDont(o));
+ to.m_StateH=TOption::stateWantNo;
+ return TRUE;
+}
|