scroll mode for very long start menus
[reactos.git] / reactos / apps / utils / net / telnet / vm.cpp
1 /* $Id: vm.cpp,v 1.1 2001/01/27 22:38:43 ea Exp $
2 *
3 * FILE : vm.cpp
4 * AUTHOR : unknown (sources found on www.telnet.org)
5 * PROJECT : ReactOS Operating System
6 * DESCRIPTION: telnet client for the W32 subsystem
7 * DATE : 2001-01-21
8 * REVISIONS
9 * 2001-02-21 ea Modified to compile under 0.0.16 src tree
10 */
11 #include <winsock.h>
12 #include <windows.h>
13
14 #include "telnet.h"
15
16 // NAME CODE MEANING
17 // NVT codes
18 #define NUL 0 // No Operation
19 #define BEL 7 // BELL
20 #define BS 8 // Back Space
21 #define HT 9 // Horizontal Tab
22 #define LF 10 // Line Feed
23 #define VT 11 // Vertical Tab
24 #define FF 12 // Form Feed
25 #define CR 13 // Carriage Return
26
27 // telnet command codes
28 #define SE 240 // End of subnegotiation parameters.
29 #define NOP 241 // No operation.
30 #define DM 242 // Data Mark
31 #define BRK 243 // Break
32 #define IP 244 // Interrupt Process
33 #define AO 245 // Abort output
34 #define AYT 246 // Are You There
35 #define EC 247 // Erase character
36 #define EL 248 // Erase Line
37 #define GA 249 // Go ahead
38 #define SB 250 // SuBnegotiate
39 #define WILL 251 //
40 #define WONT 252 //
41 #define DO 253 //
42 #define DONT 254 //
43 #define IAC 255 // Interpret As Command
44
45 //Telnet options:
46 // 0x00 - binary mode
47 // 0x01 - Local Echo
48 // 0x03 - Suppress GA (char at a time)
49 // 0x05 - status
50 // 0x06 - Timing Mark
51 //
52 // do 0x25 - zub?
53 //
54 // 0xff - Extended Options List
55
56 enum _option
57 {
58 TOPT_BIN = 0, // Binary Transmission
59 TOPT_ECHO = 1, // Echo
60 TOPT_RECN = 2, // Reconnection
61 TOPT_SUPP = 3, // Suppress Go Ahead
62 TOPT_APRX = 4, // Approx Message Size Negotiation
63 TOPT_STAT = 5, // Status
64 TOPT_TIM = 6, // Timing Mark
65 TOPT_REM = 7, // Remote Controlled Trans and Echo
66 TOPT_OLW = 8, // Output Line Width
67 TOPT_OPS = 9, // Output Page Size
68 TOPT_OCRD = 10, // Output Carriage-Return Disposition
69 TOPT_OHT = 11, // Output Horizontal Tabstops
70 TOPT_OHTD = 12, // Output Horizontal Tab Disposition
71 TOPT_OFD = 13, // Output Formfeed Disposition
72 TOPT_OVT = 14, // Output Vertical Tabstops
73 TOPT_OVTD = 15, // Output Vertical Tab Disposition
74 TOPT_OLD = 16, // Output Linefeed Disposition
75 TOPT_EXT = 17, // Extended ASCII
76 TOPT_LOGO = 18, // Logout
77 TOPT_BYTE = 19, // Byte Macro
78 TOPT_DATA = 20, // Data Entry Terminal
79 TOPT_SUP = 21, // SUPDUP
80 TOPT_SUPO = 22, // SUPDUP Output
81 TOPT_SNDL = 23, // Send Location
82 TOPT_TERM = 24, // Terminal Type
83 TOPT_EOR = 25, // End of Record
84 TOPT_TACACS = 26, // TACACS User Identification
85 TOPT_OM = 27, // Output Marking
86 TOPT_TLN = 28, // Terminal Location Number
87 TOPT_3270 = 29, // Telnet 3270 Regime
88 TOPT_X3 = 30, // X.3 PAD
89 TOPT_NAWS = 31, // Negotiate About Window Size
90 TOPT_TS = 32, // Terminal Speed
91 TOPT_RFC = 33, // Remote Flow Control
92 TOPT_LINE = 34, // Linemode
93 TOPT_XDL = 35, // X Display Location
94 TOPT_ENVIR = 36,// Telnet Environment Option
95 TOPT_AUTH = 37, // Telnet Authentication Option
96 TOPT_NENVIR = 39,// Telnet Environment Option
97 TOPT_EXTOP = 255, // Extended-Options-List
98 TOPT_ERROR = 256 // Magic number
99 };
100
101 // Wanted by linux box:
102 // 37 - TOPT_AUTH
103 // 24 - TOPT_TERM
104
105 enum _verb
106 {
107 verb_sb = 250,
108 verb_will = 251,
109 verb_wont = 252,
110 verb_do = 253,
111 verb_dont = 254
112 };
113
114 enum _state
115 {
116 state_data, //we expect a data byte
117 state_code, //we expect a code
118 state_option //we expect an option
119 };
120
121 int option_error(_verb,_option,int,SOCKET);
122
123 typedef void(*LPOPTIONPROC)(SOCKET,_verb,_option);
124 typedef void(*LPDATAPROC)(SOCKET,unsigned char data);
125
126 ///////////////////////////////////////////////////////////////////////////////
127
128 inline void yesreply(SOCKET server, _verb verb,_option option)
129 {
130 unsigned char buf[3];
131 buf[0] = IAC;
132 buf[1] = (verb==verb_do)?WILL:(verb==verb_dont)?WONT:(verb==verb_will)?DO:DONT;
133 buf[2] = (unsigned char)option;
134 send(server,(char*)buf,3,0);
135 }
136
137 inline void noreply(SOCKET server, _verb verb,_option option)
138 {
139 unsigned char buf[3];
140 buf[0] = IAC;
141 buf[1] = (verb==verb_do)?WONT:(verb==verb_dont)?WILL:(verb==verb_will)?DONT:DO;
142 buf[2] = (unsigned char)option;
143 send(server,(char*)buf,3,0);
144 }
145
146 inline void askfor(SOCKET server, _verb verb,_option option)
147 {
148 unsigned char buf[3];
149 buf[0] = IAC;
150 buf[1] = (unsigned char)verb;
151 buf[2] = (unsigned char)option;
152 send(server,(char*)buf,3,0);
153 }
154
155
156 void ddww_error(SOCKET server,_verb verb,_option option)
157 {
158 #ifdef _DEBUG
159 char tmp[256];
160 wsprintf(tmp,"Unknown Option Code: %s, %i\n",(verb==verb_do)?"DO":(verb==verb_dont)?"DON'T":(verb==verb_will)?"WILL":"WONT",(int)option);
161 OutputDebugString(tmp);
162 #endif
163
164 switch(verb)
165 {
166 case verb_will: // server wants to support something
167 noreply(server,verb,option); // I don't want that.
168 break;
169 case verb_wont: // server waants to disable support
170 return; // don't confirm - already disabled.
171 case verb_do: // server wants me to support something
172 noreply(server,verb,option); //I won't do that
173 break;
174 case verb_dont: // server wants me to disable something
175 return; // don't worry, we don't do that anyway (I hope :)
176 }
177 }
178
179 ///////////////////////////////////////////////////////////////////////////////
180 // Option ECHO & SUPPRESS GA
181 //
182 // These options are curiously intertwined...
183 // The Win32 console doesn't support ECHO_INPUT (echo) if
184 // LINE_INPUT (==GA) isn't set.
185 // I can't see how to code this negotiation without using
186 // some form of Lock-Step algorythm
187 // ie: if("WILL ECHO")
188 // Send "DO SUPP"
189 // if("WILL SUPP")
190 // Send "DO ECHO"
191 // else
192 // Send "DONT ECHO"
193
194
195 void ddww_echo(SOCKET server,_verb verb, _option option)
196 {
197 DWORD mode;
198 GetConsoleMode(StandardInput, & mode); // ENABLE_ECHO_INPUT
199
200 int set = !(mode & ENABLE_ECHO_INPUT);
201
202 switch(verb)
203 {
204 case verb_will: // server wants to echo stuff
205 if(set) return; //don't confirm - already set.
206 SetConsoleMode(StandardInput,mode & (~ENABLE_ECHO_INPUT));
207 break;
208 case verb_wont: // server don't want to echo
209 if(!set) return; //don't confirm - already unset.
210 SetConsoleMode(StandardInput,mode | ENABLE_ECHO_INPUT);
211 break;
212 case verb_do: // server wants me to loopback
213 noreply(server,verb,option);
214 return;
215 case verb_dont: // server doesn't want me to echo
216 break; // don't bother to reply - I don't
217 }
218 yesreply(server,verb,option);
219 }
220
221
222 void ddww_supp(SOCKET server,_verb verb,_option option) //Suppress GA
223 {
224 DWORD mode;
225 GetConsoleMode(StandardInput,&mode); // ENABLE_LINE_INPUT
226
227 int set = !(mode & ENABLE_LINE_INPUT);
228
229 switch(verb)
230 {
231 case verb_will: // server wants to suppress GA's
232 if(set) break; //don't confirm - already set.
233 SetConsoleMode(StandardInput,mode & (~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)));
234 askfor(server,verb_do,TOPT_SUPP);
235 askfor(server,verb_will,TOPT_SUPP);
236 askfor(server,verb_do,TOPT_ECHO);
237 break;
238 case verb_wont: // server wants to send GA's
239 if(!set) break; //don't confirm - already unset.
240 SetConsoleMode(StandardInput,mode | ENABLE_LINE_INPUT);
241 askfor(server,verb_dont,TOPT_SUPP);
242 askfor(server,verb_wont,TOPT_SUPP);
243 break;
244 case verb_do: // server wants me to suppress GA's
245 if(set) break;
246 askfor(server,verb_do,TOPT_SUPP);
247 break;
248 case verb_dont: // server wants me to send GA's
249 if(!set) break;
250 askfor(server,verb_dont,TOPT_SUPP);
251 break;
252 }
253 }
254
255 ///////////////////////////////////////////////////////////////////////////////
256 // Option TERMINAL-TYPE
257
258 void ddww_term(SOCKET server,_verb verb,_option option) //Subnegotiate terminal type
259 {
260 switch(verb)
261 {
262 case verb_will:
263 noreply(server,verb,option); // I don't want terminal info
264 break;
265 case verb_wont:
266 //dat be cool - its not going to send. no need to confirm
267 break;
268 case verb_do:
269 yesreply(server,verb,option); //I'll send it when asked
270 break;
271 case verb_dont://Ok - I won't
272 break;
273 }
274 }
275
276 // TERMINAL TYPE subnegotation
277 enum
278 {
279 SB_TERM_IS = 0,
280 SB_TERM_SEND = 1
281 };
282
283 #define NUM_TERMINALS 2
284
285 struct
286 {
287 char* name;
288 LPDATAPROC termproc;
289 //pre requsites.
290 } terminal[NUM_TERMINALS] = {
291 { "NVT", nvt },
292 { "ANSI", ansi }
293 };
294
295 int term_index = 0;
296
297 void sbproc_term(SOCKET server,unsigned char data)
298 {
299
300 if(data == SB_TERM_SEND)
301 {
302 if(term_index == NUM_TERMINALS)
303 term_index = 0;
304 else
305 term_index++;
306 char buf[16]; //pls limit
307 buf[0] = IAC;
308 buf[1] = SB;
309 buf[2] = TOPT_TERM;
310 buf[3] = SB_TERM_IS;
311 lstrcpy(&buf[4],terminal[(term_index==NUM_TERMINALS)?(NUM_TERMINALS-1):term_index].name);
312 int nlen = lstrlen(&buf[4]);
313 buf[4+nlen] = IAC;
314 buf[5+nlen] = SE;
315 send(server,buf,4+nlen+2,0);
316 }
317 }
318
319 ///////////////////////////////////////////////////////////////////////////////
320
321 struct
322 {
323 _option option;
324 LPOPTIONPROC OptionProc;
325 LPDATAPROC DataProc;
326 } ol[] = {
327 {TOPT_ECHO, ddww_echo, NULL},
328 {TOPT_SUPP, ddww_supp, NULL},
329 {TOPT_TERM, ddww_term, sbproc_term},
330 {TOPT_ERROR, ddww_error, NULL}
331 };
332
333
334 void vm(SOCKET server,unsigned char code)
335 {
336 //These vars are the finite state
337 static int state = state_data;
338 static _verb verb = verb_sb;
339 static LPDATAPROC DataProc = terminal[(term_index==NUM_TERMINALS)?(NUM_TERMINALS-1):term_index].termproc;
340 // for index
341 int i=0;
342
343 //Decide what to do (state based)
344 switch(state)
345 {
346 case state_data:
347 switch(code)
348 {
349 case IAC: state = state_code; break;
350 default: DataProc(server,code);
351 }
352 break;
353 case state_code:
354 state = state_data;
355 switch(code)
356 {
357 // State transition back to data
358 case IAC:
359 DataProc(server,code);
360 break;
361 // Code state transitions back to data
362 case SE:
363 DataProc = terminal[(term_index==NUM_TERMINALS)?(NUM_TERMINALS-1):term_index].termproc;
364 break;
365 case NOP:
366 break;
367 case DM:
368 break;
369 case BRK:
370 break;
371 case IP:
372 break;
373 case AO:
374 break;
375 case AYT:
376 break;
377 case EC:
378 break;
379 case EL:
380 break;
381 case GA:
382 break;
383 // Transitions to option state
384 case SB:
385 verb = verb_sb;
386 state = state_option;
387 break;
388 case WILL:
389 verb = verb_will;
390 state = state_option;
391 break;
392 case WONT:
393 verb = verb_wont;
394 state = state_option;
395 break;
396 case DO:
397 verb = verb_do;
398 state = state_option;
399 break;
400 case DONT:
401 verb = verb_dont;
402 state = state_option;
403 break;
404 }
405 break;
406 case state_option:
407 state = state_data;
408
409 //Find the option entry
410 for(
411 i = 0;
412 ol[i].option != TOPT_ERROR && ol[i].option != code;
413 i++);
414
415 //Do some verb specific stuff
416 if(verb == verb_sb)
417 DataProc = ol[i].DataProc;
418 else
419 ol[i].OptionProc(server,verb,(_option)code);
420 break;
421 }
422 }
423
424 /* EOF */