summaryrefslogtreecommitdiffabout
path: root/options.cpp
Unidiff
Diffstat (limited to 'options.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--options.cpp371
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
103BOOL AskWill(BYTE o);
104BOOL AskWont(BYTE o);
105BOOL AskDo(BYTE o);
106BOOL 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
117void 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
160void ProcessDO(BYTE c)
161{
162TOption& 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
193void ProcessWILL(BYTE c)
194{
195TOption& 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
226void ProcessWONT(BYTE c)
227{
228TOption& 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
259void ProcessDONT(BYTE c)
260{
261TOption& 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
290void 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 }
313TOption& to = Options[negOption];
314 to.StoreSByte(c);
315}
316
317BOOL AskWill(BYTE o)
318{
319TOption& 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
331BOOL AskUnwill(BYTE o)
332{
333TOption& 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
345BOOL AskDo(BYTE o)
346{
347TOption& 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
359BOOL AskDont(BYTE o)
360{
361TOption& 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}