-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 @@ | |||
1 | |||
2 | enum_TOption { | ||
3 | toBinaryTransmission = 0, | ||
4 | toEcho = 1, // Done. | ||
5 | toReconnection = 2, | ||
6 | toSuppressGA = 3, // Eaten | ||
7 | toApproxMsgSizeNegotiation = 4, | ||
8 | toStatus = 5, // Half-implemented | ||
9 | toTimingMark = 6, | ||
10 | toRemoteControlledTransAndEcho = 7, | ||
11 | toOutputLineWidth = 8, | ||
12 | toOutputPageSize = 9, | ||
13 | toOutputCRDisposition = 10, | ||
14 | toOutputHTabstops = 11, | ||
15 | toOutputHTabDisposition = 12, | ||
16 | toOutputFFDisposition = 13, | ||
17 | toOutputVTabstops = 14, | ||
18 | toOutputVTabDisposition = 15, | ||
19 | toOutputLFDisposition = 16, | ||
20 | toExtendedASCII = 17, | ||
21 | toLogout = 18, | ||
22 | toByteMacro = 19, | ||
23 | toDET = 20, | ||
24 | toSUPDUP = 22,// ??? | ||
25 | toSUPDUPOutput = 22, | ||
26 | toSendLocation = 23, | ||
27 | toTerminalType =24, // Done. | ||
28 | toEndOfRecord = 25, | ||
29 | toTACACSUserId = 26, | ||
30 | toOutputMarking = 27, | ||
31 | toTerminalLocationNumber = 28, | ||
32 | toTelnet3270Regime = 29, | ||
33 | toX3PAD = 30, | ||
34 | toNAWS = 31, // Done. | ||
35 | toTerminalSpeed = 32, // No need to implement, really. | ||
36 | toRemoteFlowControl = 33, // !!! | ||
37 | toLineMode = 34, | ||
38 | toXDisplayLocation = 35, // No need to implement until we | ||
39 | // do our own X-Server. | ||
40 | toEnvironmentOption = 36, | ||
41 | toAuthenticationOption = 37, | ||
42 | toEncryptionOption = 38, | ||
43 | toNewEnviron = 39, // Need to implement | ||
44 | toTN3270E = 40, | ||
45 | toExtendedOptionsList = 255 | ||
46 | }; | ||
47 | |||
48 | struct TOption{ | ||
49 | enum _state { | ||
50 | stateNone=0, stateNo, stateYes, stateWantNo, stateWantYes | ||
51 | }; | ||
52 | UINT m_StateU:3;// State - US | ||
53 | UINT m_StateH:3;// State - HIM | ||
54 | int m_Q:1; | ||
55 | int m_Supported:1; | ||
56 | UINT m_SBCluster; | ||
57 | UINT m_AllocatedSB; | ||
58 | UINT m_StoredSB; | ||
59 | LPBYTE m_SB; | ||
60 | |||
61 | BOOL (*m_OnDo)(); | ||
62 | BOOL (*m_OnDont)(); | ||
63 | BOOL (*m_OnWill)(); | ||
64 | BOOL (*m_OnWont)(); | ||
65 | BOOL (*m_OnSB)(LPBYTE data,UINT size); | ||
66 | BOOL (*m_OnInit)(); | ||
67 | |||
68 | BOOL OnDo() { return m_OnDo?(*m_OnDo)():FALSE; } | ||
69 | BOOL OnDont() { return m_OnDont?(*m_OnDont)():FALSE; } | ||
70 | BOOL OnWill() { return m_OnWill?(*m_OnWill)():FALSE; } | ||
71 | BOOL OnWont() { return m_OnWont?(*m_OnWont)():FALSE; } | ||
72 | BOOL OnSB(LPBYTE data,UINT size) { return m_OnSB?(*m_OnSB)(data,size):FALSE; } | ||
73 | BOOL OnInit() { return m_OnInit?(*m_OnInit)():FALSE; } | ||
74 | |||
75 | BOOL StoreSByte(BYTE c) { | ||
76 | if(m_AllocatedSB>=m_StoredSB){ | ||
77 | ASSERT(m_SBCluster); | ||
78 | LPBYTE nsb = new BYTE[m_AllocatedSB+m_SBCluster]; | ||
79 | ASSERT(nsb); | ||
80 | if(m_StoredSB){ | ||
81 | ASSERT(m_SB); | ||
82 | memmove(nsb,m_SB,m_StoredSB); | ||
83 | } | ||
84 | if(m_SB) | ||
85 | delete m_SB; | ||
86 | m_SB = nsb; | ||
87 | } | ||
88 | ASSERT(m_SB); | ||
89 | m_SB[m_StoredSB++]=c; | ||
90 | return TRUE; | ||
91 | } | ||
92 | BOOL CleanSB() { | ||
93 | if(m_SB) | ||
94 | delete m_SB; | ||
95 | m_SB = NULL; | ||
96 | m_AllocatedSB=m_StoredSB=0; | ||
97 | return TRUE; | ||
98 | } | ||
99 | |||
100 | }Options[256]; | ||
101 | |||
102 | |||
103 | BOOL AskWill(BYTE o); | ||
104 | BOOL AskWont(BYTE o); | ||
105 | BOOL AskDo(BYTE o); | ||
106 | BOOL AskDont(BYTE o); | ||
107 | |||
108 | #include "NAWS.cpp" | ||
109 | #include "terminal.cpp" | ||
110 | #include "status.cpp" | ||
111 | #include "NEW-ENVIRON.cpp" | ||
112 | #include "TIMING-MARK.cpp" | ||
113 | |||
114 | BOOL On_ACK(){ return TRUE; } | ||
115 | |||
116 | |||
117 | void InitOptionsTable() | ||
118 | { | ||
119 | memset(Options,0,sizeof(Options)); | ||
120 | // Echo | ||
121 | Options[toEcho].m_OnDo = On_ACK; | ||
122 | Options[toEcho].m_OnDont = On_ACK; | ||
123 | Options[toEcho].m_OnWill = On_ACK; | ||
124 | Options[toEcho].m_OnWont = On_ACK; | ||
125 | // Suppress Go-Ahead | ||
126 | Options[toSuppressGA].m_OnWill = On_ACK; | ||
127 | Options[toSuppressGA].m_OnDo = On_ACK; | ||
128 | // Status | ||
129 | Options[toStatus].m_OnWill = statusOnWill; | ||
130 | Options[toStatus].m_OnDo = statusOnDo; | ||
131 | Options[toStatus].m_OnSB = statusOnSB; | ||
132 | // Terminal Type; | ||
133 | Options[toTerminalType].m_OnDo = terminaltypeOnDo; | ||
134 | Options[toTerminalType].m_OnSB = terminaltypeOnSB; | ||
135 | Options[toTerminalType].m_OnInit = terminaltypeOnInit; | ||
136 | Options[toTerminalType].m_SBCluster = 32; | ||
137 | // NAWS | ||
138 | Options[toNAWS].m_OnDo = nawsOnDo; | ||
139 | Options[toNAWS].m_SBCluster = 16; | ||
140 | // New Environment | ||
141 | Options[toNewEnviron].m_OnDo = newenvironOnDo; | ||
142 | Options[toNewEnviron].m_OnDont = newenvironOnDont; | ||
143 | Options[toNewEnviron].m_OnSB = newenvironOnSB; | ||
144 | Options[toNewEnviron].m_SBCluster = 32; | ||
145 | // Timing Mark | ||
146 | Options[toTimingMark].m_OnDo = tmOnDo; | ||
147 | Options[toTimingMark].m_OnWill = tmOnWill; | ||
148 | |||
149 | for(int tmp=0;tmp<(sizeof(Options)/sizeof(*Options));tmp++){ | ||
150 | TOption& to = Options[tmp]; | ||
151 | to.OnInit(); | ||
152 | if(to.m_OnDo || to.m_OnDont || to.m_OnWill || to.m_OnWont | ||
153 | || to.m_OnSB || to.m_OnInit) | ||
154 | to.m_Supported=TRUE; | ||
155 | if(!to.m_SBCluster) | ||
156 | to.m_SBCluster=128; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | void ProcessDO(BYTE c) | ||
161 | { | ||
162 | TOption& to = Options[c]; | ||
163 | // Ignore this junk if we're already in desired mode of operation | ||
164 | if(to.m_StateU==TOption::stateYes){ | ||
165 | connState = cstateNone; | ||
166 | return; | ||
167 | } | ||
168 | TRACE1("He want us to DO %d\n",(WORD)c); | ||
169 | if(!to.m_Supported){ | ||
170 | TRACE1("Unsupported option = %d\n",(WORD)c); | ||
171 | // Option is not suported - send WONT and switch to stateNo unless | ||
172 | // we've already denied this option. | ||
173 | if(to.m_StateU == TOption::stateNone){ | ||
174 | VERIFY(ShowUnwill(c)); | ||
175 | to.m_StateU = TOption::stateNo; | ||
176 | } | ||
177 | }else{ | ||
178 | // Okay, if we do - we do and tell him so, unless we asked for it. | ||
179 | // Otherwise - Tell him we're not about to. | ||
180 | if(to.OnDo()){ | ||
181 | if(to.m_StateU!=TOption::stateWantYes) | ||
182 | VERIFY(ShowWill(c)); | ||
183 | to.m_StateU = TOption::stateYes; | ||
184 | }else{ | ||
185 | if(to.m_StateU!=TOption::stateWantNo) | ||
186 | VERIFY(ShowUnwill(c)); | ||
187 | to.m_StateU = TOption::stateNo; | ||
188 | } | ||
189 | } | ||
190 | connState = cstateNone; | ||
191 | } | ||
192 | |||
193 | void ProcessWILL(BYTE c) | ||
194 | { | ||
195 | TOption& to = Options[c]; | ||
196 | // Ignore this junk if we consider him already in this mode | ||
197 | if(to.m_StateH==TOption::stateYes){ | ||
198 | connState = cstateNone; | ||
199 | return; | ||
200 | } | ||
201 | TRACE1("He WILL %d\n",(WORD)c); | ||
202 | if(!to.m_Supported){ | ||
203 | TRACE1("Unsupported option = %d\n",(WORD)c); | ||
204 | // Since we don't expect remote end to use this option - beg him | ||
205 | // not to go for it unless we think we already did. | ||
206 | if(to.m_StateH == TOption::stateNone){ | ||
207 | VERIFY(BegDont(c)); | ||
208 | to.m_StateH = TOption::stateNo; | ||
209 | } | ||
210 | }else{ | ||
211 | if(to.OnWill()){ | ||
212 | // We've accepted this - tell him to go ahead if we thought he's | ||
213 | // in opposite state and adjust our vision/ | ||
214 | if(to.m_StateH!=TOption::stateWantYes) | ||
215 | VERIFY(BegDo(c)); | ||
216 | to.m_StateH = TOption::stateYes; | ||
217 | }else{ | ||
218 | if(to.m_StateH!=TOption::stateWantNo) | ||
219 | VERIFY(BegDont(c)); | ||
220 | to.m_StateH = TOption::stateNo; | ||
221 | } | ||
222 | } | ||
223 | connState = cstateNone; | ||
224 | } | ||
225 | |||
226 | void ProcessWONT(BYTE c) | ||
227 | { | ||
228 | TOption& to = Options[c]; | ||
229 | // Ignore this junk if we consider him already in this mode | ||
230 | if(to.m_StateH==TOption::stateNo){ | ||
231 | connState = cstateNone; | ||
232 | return; | ||
233 | } | ||
234 | TRACE1("He WONT %d\n",(WORD)c); | ||
235 | if(!to.m_Supported){ | ||
236 | TRACE1("Unsupported option = %d\n",(WORD)c); | ||
237 | // Since we don't expect remote end to use this option - beg him | ||
238 | // not to go for it unless we think we already did. | ||
239 | if(to.m_StateH == TOption::stateNone){ | ||
240 | VERIFY(BegDont(c)); | ||
241 | to.m_StateH = TOption::stateNo; | ||
242 | } | ||
243 | }else{ | ||
244 | if(to.OnWont()){ | ||
245 | // We've accepted this - tell him to go ahead if we thought he's | ||
246 | // in opposite state and adjust our vision/ | ||
247 | if(to.m_StateH!=TOption::stateWantNo) | ||
248 | VERIFY(BegDont(c)); | ||
249 | to.m_StateH = TOption::stateNo; | ||
250 | }else{ | ||
251 | if(to.m_StateH!=TOption::stateWantYes) | ||
252 | VERIFY(BegDo(c)); | ||
253 | to.m_StateH = TOption::stateYes; | ||
254 | } | ||
255 | } | ||
256 | connState = cstateNone; | ||
257 | } | ||
258 | |||
259 | void ProcessDONT(BYTE c) | ||
260 | { | ||
261 | TOption& to = Options[c]; | ||
262 | // Ignore this junk if we consider him already in this mode | ||
263 | if(to.m_StateU==TOption::stateNo){ | ||
264 | connState = cstateNone; | ||
265 | return; | ||
266 | } | ||
267 | TRACE1("He want us to DONT %d\n",(WORD)c); | ||
268 | if(!to.m_Supported){ | ||
269 | TRACE1("DONT for unsupported option = %d\n",(WORD)c); | ||
270 | // Since we don't expect remote end to use this option - beg him | ||
271 | // not to go for it unless we think we already did. | ||
272 | if(to.m_StateU == TOption::stateNone){ | ||
273 | VERIFY(ShowUnwill(c)); | ||
274 | to.m_StateU = TOption::stateNo; | ||
275 | } | ||
276 | }else{ | ||
277 | if(to.OnDont()){ | ||
278 | if(to.m_StateU!=TOption::stateWantNo) | ||
279 | VERIFY(ShowUnwill(c)); | ||
280 | to.m_StateU = TOption::stateNo; | ||
281 | }else{ | ||
282 | if(to.m_StateU!=TOption::stateWantYes) | ||
283 | VERIFY(ShowWill(c)); | ||
284 | to.m_StateU = TOption::stateYes; | ||
285 | } | ||
286 | } | ||
287 | connState = cstateNone; | ||
288 | } | ||
289 | |||
290 | void ProcessSBData(BYTE c) | ||
291 | { | ||
292 | switch(connState){ | ||
293 | case cstateSBData: | ||
294 | if(c==tnIAC){ | ||
295 | connState=cstateSBDataIAC; | ||
296 | return; | ||
297 | } | ||
298 | break; | ||
299 | case cstateSBDataIAC: | ||
300 | if(c==tnSE){ | ||
301 | // Just let option handler process the data | ||
302 | TOption& to = Options[negOption]; | ||
303 | to.OnSB(to.m_SB,to.m_StoredSB); | ||
304 | to.CleanSB(); | ||
305 | connState = cstateNone; | ||
306 | return; | ||
307 | } | ||
308 | break; | ||
309 | default: | ||
310 | ASSERT(FALSE); | ||
311 | break; | ||
312 | } | ||
313 | TOption& to = Options[negOption]; | ||
314 | to.StoreSByte(c); | ||
315 | } | ||
316 | |||
317 | BOOL AskWill(BYTE o) | ||
318 | { | ||
319 | TOption& to = Options[o]; | ||
320 | if(to.m_StateU==TOption::stateYes || to.m_StateU==TOption::stateWantYes) | ||
321 | return TRUE; | ||
322 | #ifdef _DEBUG | ||
323 | if(to.m_StateU==TOption::stateWantNo) | ||
324 | TRACE1("NEED TO QUEUE %d\n",(WORD)o); | ||
325 | #endif | ||
326 | VERIFY(ShowWill(o)); | ||
327 | to.m_StateU=TOption::stateWantYes; | ||
328 | return TRUE; | ||
329 | } | ||
330 | |||
331 | BOOL AskUnwill(BYTE o) | ||
332 | { | ||
333 | TOption& to = Options[o]; | ||
334 | if(to.m_StateU==TOption::stateNo || to.m_StateU==TOption::stateWantNo) | ||
335 | return TRUE; | ||
336 | #ifdef _DEBUG | ||
337 | if(to.m_StateU==TOption::stateWantNo) | ||
338 | TRACE1("NEED TO QUEUE %d\n",(WORD)o); | ||
339 | #endif | ||
340 | VERIFY(ShowUnwill(o)); | ||
341 | to.m_StateU=TOption::stateWantNo; | ||
342 | return TRUE; | ||
343 | } | ||
344 | |||
345 | BOOL AskDo(BYTE o) | ||
346 | { | ||
347 | TOption& to = Options[o]; | ||
348 | if(to.m_StateH==TOption::stateYes || to.m_StateH==TOption::stateWantYes) | ||
349 | return TRUE; | ||
350 | #ifdef _DEBUG | ||
351 | if(to.m_StateH==TOption::stateWantNo) | ||
352 | TRACE1("NEED TO QUEUE %d\n",(WORD)o); | ||
353 | #endif | ||
354 | VERIFY(BegDo(o)); | ||
355 | to.m_StateH=TOption::stateWantYes; | ||
356 | return TRUE; | ||
357 | } | ||
358 | |||
359 | BOOL AskDont(BYTE o) | ||
360 | { | ||
361 | TOption& to = Options[o]; | ||
362 | if(to.m_StateH==TOption::stateNo || to.m_StateH==TOption::stateWantNo) | ||
363 | return TRUE; | ||
364 | #ifdef _DEBUG | ||
365 | if(to.m_StateH==TOption::stateWantYes) | ||
366 | TRACE1("NEED TO QUEUE %d\n",(WORD)o); | ||
367 | #endif | ||
368 | VERIFY(BegDont(o)); | ||
369 | to.m_StateH=TOption::stateWantNo; | ||
370 | return TRUE; | ||
371 | } | ||