|
1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Telnet Protocol API |
|
15 // Supported RFC class implementations |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 */ |
|
22 |
|
23 #include "TELFSM.H" |
|
24 #include "TELDEBUG.H" |
|
25 |
|
26 // The option negotiation class |
|
27 // Independent of the option |
|
28 // All option classes contain one of these state machine classes |
|
29 |
|
30 TOptionFSM::TOptionFSM() |
|
31 /** |
|
32 Constructor |
|
33 Set up the defaults |
|
34 */ |
|
35 { |
|
36 Allowed = ENoOption; |
|
37 Us = ENo; |
|
38 UsQ = EEmpty; |
|
39 Him = ENo; |
|
40 HimQ = EEmpty; |
|
41 } |
|
42 |
|
43 void TOptionFSM::Reset() |
|
44 /** |
|
45 Reset restores the state machine to default but leaves the permissions |
|
46 */ |
|
47 { |
|
48 Us = ENo; |
|
49 UsQ = EEmpty; |
|
50 Him = ENo; |
|
51 HimQ = EEmpty; |
|
52 } |
|
53 |
|
54 TInt32 TOptionFSM::Request(const TInt32 aRequest,TInt32& aAction,TInt32& aEvent) |
|
55 /** |
|
56 Implementation of RFC 1143 Q Method bidirectional Telnet option state machine |
|
57 Can be called from the client side (aRequest = EClientXX) or the line side (aRequest = EServerXX). |
|
58 |
|
59 errors are returned for illegal requests |
|
60 aEvent is set when an option transits to enabled or disabled |
|
61 aAction's are the Telnet defined DO, WILL, WONT, DONT |
|
62 */ |
|
63 { |
|
64 TInt32 Ret = EErrNone; |
|
65 aAction = ENoAction; |
|
66 aEvent = ENoEvent; |
|
67 |
|
68 switch(aRequest) |
|
69 { |
|
70 // |
|
71 case EServerWill : |
|
72 if(Him == ENo) |
|
73 { |
|
74 if(Allowed & EServerWill) |
|
75 { |
|
76 Him = EYes; |
|
77 Ret = EErrNone; |
|
78 aEvent = EServerEnabled; |
|
79 aAction = ESendDo; |
|
80 } |
|
81 else |
|
82 { |
|
83 Ret = EErrNone; |
|
84 aEvent = ENoEvent; |
|
85 aAction = ESendDont; |
|
86 } |
|
87 } |
|
88 else if(Him == EYes) |
|
89 { |
|
90 Ret = EErrNone; |
|
91 aEvent = ENoEvent; |
|
92 aAction = ENoAction; |
|
93 } |
|
94 else if(Him == EWantNo && HimQ == EEmpty) |
|
95 { |
|
96 Him = ENo; |
|
97 Ret = EProtocolError; |
|
98 aEvent = EServerDisabled; |
|
99 aAction = ENoAction; |
|
100 } |
|
101 else if(Him == EWantNo && HimQ == EOpposite) |
|
102 { |
|
103 Him = EYes; |
|
104 HimQ = EEmpty; |
|
105 Ret = EProtocolError; |
|
106 aEvent = EServerEnabled; |
|
107 aAction = ENoAction; |
|
108 } |
|
109 else if(Him == EWantYes && HimQ == EEmpty) |
|
110 { |
|
111 Him = EYes; |
|
112 Ret = EErrNone; |
|
113 aEvent = EServerEnabled; |
|
114 aAction = ENoAction; |
|
115 } |
|
116 else if(Him == EWantYes && HimQ == EOpposite) |
|
117 { |
|
118 Him = EWantNo; |
|
119 HimQ = EEmpty; |
|
120 Ret = EErrNone; |
|
121 aEvent = ENoEvent; |
|
122 aAction = ESendDont; |
|
123 } |
|
124 break; |
|
125 // |
|
126 case EServerDo : |
|
127 if(Us == ENo) |
|
128 { |
|
129 if(Allowed & EServerDo) |
|
130 { |
|
131 Us = EYes; |
|
132 Ret = EErrNone; |
|
133 aEvent = EClientEnabled; |
|
134 aAction = ESendWill; |
|
135 } |
|
136 else |
|
137 { |
|
138 Ret = EErrNone; |
|
139 aEvent = ENoEvent; |
|
140 aAction = ESendWont; |
|
141 } |
|
142 } |
|
143 else if(Us == EYes) |
|
144 { |
|
145 Ret = EErrNone; |
|
146 aEvent = ENoEvent; |
|
147 aAction = ENoAction; |
|
148 } |
|
149 else if(Us == EWantNo && UsQ == EEmpty) |
|
150 { |
|
151 Us = ENo; |
|
152 Ret = EProtocolError; |
|
153 aEvent = EClientDisabled; |
|
154 aAction = ENoAction; |
|
155 } |
|
156 else if(Us == EWantNo && UsQ == EOpposite) |
|
157 { |
|
158 Us = EYes; |
|
159 UsQ = EEmpty; |
|
160 Ret = EProtocolError; |
|
161 aEvent = EClientEnabled; |
|
162 aAction = ENoAction; |
|
163 } |
|
164 else if(Us == EWantYes && UsQ == EEmpty) |
|
165 { |
|
166 Us = EYes; |
|
167 Ret = EErrNone; |
|
168 aEvent = EClientEnabled; |
|
169 aAction = ENoAction; |
|
170 } |
|
171 else if(Us == EWantYes && UsQ == EOpposite) |
|
172 { |
|
173 Us = EWantNo; |
|
174 UsQ = EEmpty; |
|
175 Ret = EErrNone; |
|
176 aEvent = ENoEvent; |
|
177 aAction = ESendWont; |
|
178 } |
|
179 break; |
|
180 // |
|
181 |
|
182 case EServerWont : |
|
183 if(Him == ENo) |
|
184 { |
|
185 Ret = EErrNone; |
|
186 aEvent = ENoEvent; |
|
187 aAction = ENoAction; |
|
188 } |
|
189 else if(Him == EYes) |
|
190 { |
|
191 Him = ENo; |
|
192 Ret = EErrNone; |
|
193 aEvent = EServerDisabled; |
|
194 aAction = ESendDont; |
|
195 } |
|
196 else if(Him == EWantNo && HimQ == EEmpty) |
|
197 { |
|
198 Him = ENo; |
|
199 Ret = EErrNone; |
|
200 aEvent = EServerDisabled; |
|
201 aAction = ENoAction; |
|
202 } |
|
203 else if(Him == EWantNo && HimQ == EOpposite) |
|
204 { |
|
205 Him = EWantYes; |
|
206 HimQ = ENone; |
|
207 Ret = EErrNone; |
|
208 aEvent = ENoEvent; |
|
209 aAction = ESendDo; |
|
210 } |
|
211 else if(Him == EWantYes && HimQ == EEmpty) |
|
212 { |
|
213 Him = ENo; |
|
214 Ret = EErrNone; |
|
215 aEvent = EServerDisabled; |
|
216 aAction = ENoAction; |
|
217 } |
|
218 else if(Him == EWantYes && HimQ == EOpposite) |
|
219 { |
|
220 Him = ENo; |
|
221 HimQ = ENone; |
|
222 Ret = EErrNone; |
|
223 aEvent = EServerDisabled; |
|
224 aAction = ENoAction; |
|
225 } |
|
226 break; |
|
227 // |
|
228 case EServerDont : |
|
229 if(Us == ENo) |
|
230 { |
|
231 Ret = EErrNone; |
|
232 aEvent = ENoEvent; |
|
233 aAction = ENoAction; |
|
234 } |
|
235 else if(Us == EYes) |
|
236 { |
|
237 Us = ENo; |
|
238 Ret = EErrNone; |
|
239 aEvent = EClientDisabled; |
|
240 aAction = ESendWont; |
|
241 } |
|
242 else if(Us == EWantNo && UsQ == EEmpty) |
|
243 { |
|
244 Us = ENo; |
|
245 Ret = EErrNone; |
|
246 aEvent = EClientDisabled; |
|
247 aAction = ENoAction; |
|
248 } |
|
249 else if(Us == EWantNo && UsQ == EOpposite) |
|
250 { |
|
251 Us = EWantYes; |
|
252 UsQ = ENone; |
|
253 Ret = EErrNone; |
|
254 aEvent = ENoEvent; |
|
255 aAction = ESendWill; |
|
256 } |
|
257 else if(Us == EWantYes && UsQ == EEmpty) |
|
258 { |
|
259 Us = ENo; |
|
260 Ret = EErrNone; |
|
261 aEvent = EClientDisabled; |
|
262 aAction = ENoAction; |
|
263 } |
|
264 else if(Us == EWantYes && UsQ == EOpposite) |
|
265 { |
|
266 Us = ENo; |
|
267 UsQ = ENone; |
|
268 Ret = EErrNone; |
|
269 aEvent = EClientDisabled; |
|
270 aAction = ENoAction; |
|
271 } |
|
272 break; |
|
273 // |
|
274 case EClientDo : |
|
275 if(!(Allowed & EClientDo)) |
|
276 { |
|
277 Ret = EPermissionsError; |
|
278 aEvent = ENoEvent; |
|
279 aAction = ENoAction; |
|
280 } |
|
281 else if(Him == ENo) |
|
282 { |
|
283 Him = EWantYes; |
|
284 Ret = EErrNone; |
|
285 aEvent = ENoEvent; |
|
286 aAction = ESendDo; |
|
287 } |
|
288 else if(Him == EYes) |
|
289 { |
|
290 Ret = EProtocolError; |
|
291 aEvent = ENoEvent; |
|
292 aAction = ENoAction; |
|
293 } |
|
294 else if(Him == EWantNo && HimQ == EEmpty) |
|
295 { |
|
296 if(UsQ == EOpposite) |
|
297 { |
|
298 Ret = EErrNone; |
|
299 HimQ = EOpposite; |
|
300 } |
|
301 else |
|
302 Ret = EProtocolError; |
|
303 aEvent = ENoEvent; |
|
304 aAction = ENoAction; |
|
305 } |
|
306 else if(Him == EWantNo && HimQ == EOpposite) |
|
307 { |
|
308 Ret = EProtocolError; |
|
309 aEvent = ENoEvent; |
|
310 aAction = ENoAction; |
|
311 } |
|
312 else if(Him == EWantYes && HimQ == EEmpty) |
|
313 { |
|
314 Ret = EProtocolError; |
|
315 aEvent = ENoEvent; |
|
316 aAction = ENoAction; |
|
317 } |
|
318 else if(Him == EWantYes && HimQ == EOpposite) |
|
319 { |
|
320 HimQ = EEmpty; |
|
321 Ret = EErrNone; |
|
322 aEvent = ENoEvent; |
|
323 aAction = ENoAction; |
|
324 } |
|
325 break; |
|
326 // |
|
327 case EClientWill : |
|
328 if(!(Allowed & EClientWill)) |
|
329 { |
|
330 Ret = EPermissionsError; |
|
331 aEvent = ENoEvent; |
|
332 aAction = ENoAction; |
|
333 } |
|
334 else if(Us == ENo) |
|
335 { |
|
336 Us = EWantYes; |
|
337 Ret = EErrNone; |
|
338 aEvent = ENoEvent; |
|
339 aAction = ESendWill; |
|
340 } |
|
341 else if(Us == EYes) |
|
342 { |
|
343 Ret = EProtocolError; |
|
344 aEvent = ENoEvent; |
|
345 aAction = ENoAction; |
|
346 } |
|
347 else if(Us == EWantNo && UsQ == EEmpty) |
|
348 { |
|
349 if(HimQ == EOpposite) |
|
350 { |
|
351 Ret = EErrNone; |
|
352 UsQ = EOpposite; |
|
353 } |
|
354 else |
|
355 Ret = EProtocolError; |
|
356 aEvent = ENoEvent; |
|
357 aAction = ENoAction; |
|
358 } |
|
359 else if(Us == EWantNo && UsQ == EOpposite) |
|
360 { |
|
361 Ret = EProtocolError; |
|
362 aEvent = ENoEvent; |
|
363 aAction = ENoAction; |
|
364 } |
|
365 else if(Us == EWantYes && UsQ == EEmpty) |
|
366 { |
|
367 Ret = EProtocolError; |
|
368 aEvent = ENoEvent; |
|
369 aAction = ENoAction; |
|
370 } |
|
371 else if(Us == EWantYes && UsQ == EOpposite) |
|
372 { |
|
373 UsQ = EEmpty; |
|
374 Ret = EErrNone; |
|
375 aEvent = ENoEvent; |
|
376 aAction = ENoAction; |
|
377 } |
|
378 break; |
|
379 // |
|
380 case EClientDont : |
|
381 if(Him == ENo) |
|
382 { |
|
383 Ret = EProtocolError; |
|
384 aEvent = ENoEvent; |
|
385 aAction = ENoAction; |
|
386 } |
|
387 else if(Him == EYes) |
|
388 { |
|
389 Him = EWantNo; |
|
390 Ret = EErrNone; |
|
391 aEvent = ENoEvent; |
|
392 aAction = ESendDont; |
|
393 } |
|
394 else if(Him == EWantNo && HimQ == EEmpty) |
|
395 { |
|
396 Ret = EProtocolError; |
|
397 aEvent = ENoEvent; |
|
398 aAction = ENoAction; |
|
399 } |
|
400 else if(Him == EWantNo && HimQ == EOpposite) |
|
401 { |
|
402 HimQ = EEmpty; |
|
403 Ret = EErrNone; |
|
404 aEvent = ENoEvent; |
|
405 aAction = ENoAction; |
|
406 } |
|
407 else if(Him == EWantYes && HimQ == EEmpty) |
|
408 { |
|
409 if(UsQ == EOpposite) |
|
410 { |
|
411 HimQ = EOpposite; |
|
412 Ret = EErrNone; |
|
413 } |
|
414 else |
|
415 Ret = EProtocolError; |
|
416 aEvent = ENoEvent; |
|
417 aAction = ENoAction; |
|
418 } |
|
419 else if(Him == EWantYes && HimQ == EOpposite) |
|
420 { |
|
421 Ret = EProtocolError; |
|
422 aEvent = ENoEvent; |
|
423 aAction = ENoAction; |
|
424 } |
|
425 break; |
|
426 // |
|
427 case EClientWont : |
|
428 if(Us == ENo) |
|
429 { |
|
430 Ret = EProtocolError; |
|
431 aEvent = ENoEvent; |
|
432 aAction = ENoAction; |
|
433 } |
|
434 else if(Us == EYes) |
|
435 { |
|
436 Us = EWantNo; |
|
437 Ret = EErrNone; |
|
438 aEvent = ENoEvent; |
|
439 aAction = ESendWont; |
|
440 } |
|
441 else if(Us == EWantNo && UsQ == EEmpty) |
|
442 { |
|
443 Ret = EProtocolError; |
|
444 aEvent = ENoEvent; |
|
445 aAction = ENoAction; |
|
446 } |
|
447 else if(Us == EWantNo && UsQ == EOpposite) |
|
448 { |
|
449 UsQ = EEmpty; |
|
450 Ret = EErrNone; |
|
451 aEvent = ENoEvent; |
|
452 aAction = ENoAction; |
|
453 } |
|
454 else if(Us == EWantYes && UsQ == EEmpty) |
|
455 { |
|
456 if(HimQ == EOpposite) |
|
457 { |
|
458 UsQ = EOpposite; |
|
459 Ret = EErrNone; |
|
460 } |
|
461 else |
|
462 Ret = EProtocolError; |
|
463 |
|
464 aEvent = ENoEvent; |
|
465 aAction = ENoAction; |
|
466 } |
|
467 else if(Us == EWantYes && UsQ == EOpposite) |
|
468 { |
|
469 Ret = EProtocolError; |
|
470 aEvent = ENoEvent; |
|
471 aAction = ENoAction; |
|
472 } |
|
473 break; |
|
474 |
|
475 default : |
|
476 break; |
|
477 |
|
478 |
|
479 } |
|
480 return(Ret); |
|
481 } |
|
482 |
|
483 // The base class for all RFC option classes |
|
484 |
|
485 CRFCOptionBase::~CRFCOptionBase() |
|
486 /** |
|
487 Destructor |
|
488 */ |
|
489 { |
|
490 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CRFCOptionBase::D'Tor")); |
|
491 } |
|
492 |
|
493 void CRFCOptionBase::CreateOptionResponse(TInt8 aOption,TInt32 aAction,TDes8& aBuffer) |
|
494 /** |
|
495 Create a Telnet protocol request or response |
|
496 */ |
|
497 { |
|
498 aBuffer.Append(KTelnetIAC); |
|
499 |
|
500 // MAP our local codes to the genuine telnet ones |
|
501 if(aAction == TOptionFSM::ESendWill) |
|
502 aBuffer.Append(KTelnetWILL); |
|
503 else if(aAction == TOptionFSM::ESendDo) |
|
504 aBuffer.Append(KTelnetDO); |
|
505 else if(aAction == TOptionFSM::ESendDont) |
|
506 aBuffer.Append(KTelnetDONT); |
|
507 else if(aAction == TOptionFSM::ESendWont) |
|
508 aBuffer.Append(KTelnetWONT); |
|
509 |
|
510 aBuffer.Append(aOption); |
|
511 }; |
|
512 |
|
513 |
|
514 void CUnknownOption::RequestUnknown(TInt8 aOption,const TInt32 aRequest, TDes8& aAction,TInt32& aEvent) |
|
515 /** |
|
516 For tidy code we keep a class that handles unknown option requests from the server. |
|
517 The result of a call into this object will always be WONT or DONT |
|
518 */ |
|
519 { |
|
520 TInt32 action; |
|
521 iFSM.Request(aRequest,action,aEvent); |
|
522 if(action != TOptionFSM::ENoAction) |
|
523 CRFCOptionBase::CreateOptionResponse(aOption,action,aAction); |
|
524 } |
|
525 |
|
526 CUnknownOption* CUnknownOption::NewL() |
|
527 { |
|
528 CUnknownOption* self = new(ELeave) CUnknownOption; |
|
529 CleanupStack::PushL(self); |
|
530 self->ConstructL(); |
|
531 CleanupStack::Pop(); |
|
532 return self; |
|
533 } |
|
534 |
|
535 void CUnknownOption::ConstructL() |
|
536 { |
|
537 } |
|
538 |
|
539 CUnknownOption::~CUnknownOption() |
|
540 /** |
|
541 Destructor |
|
542 */ |
|
543 { |
|
544 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CUnknownOption::D'Tor")); |
|
545 } |
|
546 |
|
547 CSuppressGAOption* CSuppressGAOption::NewL() |
|
548 { |
|
549 CSuppressGAOption* self = new(ELeave) CSuppressGAOption; |
|
550 CleanupStack::PushL(self); |
|
551 self->ConstructL(); |
|
552 CleanupStack::Pop(); |
|
553 return self; |
|
554 } |
|
555 |
|
556 TInt32 CSuppressGAOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent) |
|
557 /** |
|
558 Virtual overide |
|
559 Should always be a request for DO or WILL as we always suppress the Go Ahead signal |
|
560 */ |
|
561 { |
|
562 TInt32 action; |
|
563 |
|
564 iFSM.Request(aRequest,action,aEvent); |
|
565 if(action != TOptionFSM::ENoAction) |
|
566 CreateOptionResponse(KTelnetProtOptionSuppressGA,action,aAction); |
|
567 return(KErrNone); |
|
568 } |
|
569 |
|
570 void CSuppressGAOption::ConstructL() |
|
571 { |
|
572 } |
|
573 |
|
574 void CSuppressGAOption::GetTelnetOptionStatus(TDes8& aCurrentStatus) |
|
575 /** |
|
576 Virtual overide |
|
577 Returns a Telnet Protocol option status , see RFC 859 |
|
578 */ |
|
579 { |
|
580 if(iFSM.ClientEnabled()) |
|
581 { |
|
582 aCurrentStatus.Append(KTelnetDO); |
|
583 aCurrentStatus.Append(KTelnetProtOptionSuppressGA); |
|
584 } |
|
585 } |
|
586 |
|
587 |
|
588 CStatusOption* CStatusOption::NewL() |
|
589 { |
|
590 CStatusOption* self = new(ELeave) CStatusOption; |
|
591 CleanupStack::PushL(self); |
|
592 self->ConstructL(); |
|
593 CleanupStack::Pop(); |
|
594 return self; |
|
595 } |
|
596 |
|
597 TInt32 CStatusOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent) |
|
598 /** |
|
599 Virtual overide |
|
600 */ |
|
601 { |
|
602 TInt32 action; |
|
603 |
|
604 iFSM.Request(aRequest,action,aEvent); |
|
605 if(action != TOptionFSM::ENoAction) |
|
606 CreateOptionResponse(KTelnetProtOptionStatus,action,aAction); |
|
607 |
|
608 return(KErrNone); |
|
609 } |
|
610 |
|
611 void CStatusOption::ConstructL() |
|
612 { |
|
613 } |
|
614 |
|
615 void CStatusOption::GetTelnetOptionStatus(TDes8& aCurrentStatus) |
|
616 /** |
|
617 Virtual overide |
|
618 Returns a Telnet Protocol option status , see RFC 859 |
|
619 */ |
|
620 { |
|
621 if(iFSM.ClientEnabled()) |
|
622 { |
|
623 aCurrentStatus.Append(KTelnetWILL); |
|
624 aCurrentStatus.Append(KTelnetProtOptionStatus); |
|
625 } |
|
626 if(iFSM.ServerEnabled()) |
|
627 { |
|
628 aCurrentStatus.Append(KTelnetDO); |
|
629 aCurrentStatus.Append(KTelnetProtOptionStatus); |
|
630 } |
|
631 } |
|
632 |
|
633 CSpeedOption* CSpeedOption::NewL() |
|
634 { |
|
635 CSpeedOption* self = new(ELeave) CSpeedOption; |
|
636 CleanupStack::PushL(self); |
|
637 self->ConstructL(); |
|
638 CleanupStack::Pop(); |
|
639 return self; |
|
640 } |
|
641 |
|
642 TInt32 CSpeedOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent) |
|
643 /** |
|
644 Virtual overide |
|
645 */ |
|
646 { |
|
647 TInt32 action; |
|
648 TInt32 err; |
|
649 err = iFSM.Request(aRequest,action,aEvent); |
|
650 if(action != TOptionFSM::ENoAction) |
|
651 CreateOptionResponse(KTelnetProtOptionTerminalSpeed,action,aAction); |
|
652 return(err); |
|
653 } |
|
654 |
|
655 void CSpeedOption::GetTelnetSubOption(TDes8& aOutBuffer) |
|
656 /** |
|
657 Creates the sub option for telling the server our speed |
|
658 */ |
|
659 { |
|
660 aOutBuffer.Append(KTelnetIAC); // Interpret As Command |
|
661 aOutBuffer.Append(KTelnetSB); // Suboption start |
|
662 aOutBuffer.Append(KTelnetProtOptionTerminalSpeed); //Terminal Speed |
|
663 aOutBuffer.Append(KTelnetCommandIS); // IS |
|
664 |
|
665 aOutBuffer.Append(iTermSpeed); // Receive Speed |
|
666 aOutBuffer.Append(','); |
|
667 aOutBuffer.Append(iTermSpeed); // Send Speed |
|
668 |
|
669 aOutBuffer.Append(KTelnetIAC); // Interpret As Command |
|
670 aOutBuffer.Append(KTelnetSE); // Suboption End |
|
671 } |
|
672 |
|
673 void CSpeedOption::ConstructL() |
|
674 { |
|
675 iTermSpeed = _L8("38400"); |
|
676 } |
|
677 |
|
678 void CSpeedOption::GetTelnetOptionStatus(TDes8& aCurrentStatus) |
|
679 /** |
|
680 Virtual overide |
|
681 Returns a Telnet Protocol option status , see RFC 859 |
|
682 */ |
|
683 { |
|
684 if(iFSM.ClientEnabled()) |
|
685 { |
|
686 aCurrentStatus.Append(KTelnetWILL); |
|
687 aCurrentStatus.Append(KTelnetProtOptionTerminalSpeed); |
|
688 } |
|
689 } |
|
690 |
|
691 TBool CSpeedOption::Set(const TDesC8& aSpeed) |
|
692 /** |
|
693 Sets the speed option, return TRUE if it's altered |
|
694 */ |
|
695 { |
|
696 TBool ret; |
|
697 (iTermSpeed == aSpeed) ? (ret = FALSE) : (ret = TRUE); |
|
698 iTermSpeed = aSpeed; |
|
699 return ret; |
|
700 } |
|
701 |
|
702 CLogoutOption* CLogoutOption::NewL() |
|
703 { |
|
704 CLogoutOption* self = new(ELeave) CLogoutOption; |
|
705 CleanupStack::PushL(self); |
|
706 self->ConstructL(); |
|
707 CleanupStack::Pop(); |
|
708 return self; |
|
709 } |
|
710 |
|
711 TInt32 CLogoutOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent) |
|
712 /** |
|
713 Virtual overide |
|
714 */ |
|
715 { |
|
716 TInt32 action; |
|
717 TInt32 err; |
|
718 err = iFSM.Request(aRequest,action,aEvent); |
|
719 if(action != TOptionFSM::ENoAction) |
|
720 CreateOptionResponse(KTelnetProtOptionLogoff,action,aAction); |
|
721 return(err); |
|
722 } |
|
723 |
|
724 void CLogoutOption::ConstructL() |
|
725 { |
|
726 } |
|
727 |
|
728 void CLogoutOption::GetTelnetOptionStatus(TDes8& aCurrentStatus) |
|
729 /** |
|
730 I don't think this method is relevant for status reporting but for consistency and is |
|
731 never called to report it's status. |
|
732 */ |
|
733 { |
|
734 if(iFSM.ServerEnabled()) |
|
735 { |
|
736 aCurrentStatus.Append(KTelnetDO); |
|
737 aCurrentStatus.Append(KTelnetProtOptionLogoff); |
|
738 } |
|
739 } |
|
740 |
|
741 CTerminalTypeOption* CTerminalTypeOption::NewL() |
|
742 { |
|
743 CTerminalTypeOption* self = new(ELeave) CTerminalTypeOption; |
|
744 CleanupStack::PushL(self); |
|
745 self->ConstructL(); |
|
746 CleanupStack::Pop(); |
|
747 return self; |
|
748 } |
|
749 |
|
750 TInt32 CTerminalTypeOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent) |
|
751 /** |
|
752 Virtual overide |
|
753 */ |
|
754 { |
|
755 TInt32 action; |
|
756 TInt32 err; |
|
757 err = iFSM.Request(aRequest,action,aEvent); |
|
758 if(action != TOptionFSM::ENoAction) |
|
759 CreateOptionResponse(KTelnetProtOptionTerminalType,action,aAction); |
|
760 return(err); |
|
761 } |
|
762 |
|
763 void CTerminalTypeOption::ConstructL() |
|
764 { |
|
765 iTermType = _L8("dumb"); |
|
766 } |
|
767 |
|
768 void CTerminalTypeOption::GetTelnetSubOption(TDes8& aOutBuffer) |
|
769 { |
|
770 aOutBuffer.Append(KTelnetIAC); // Interpret As Command |
|
771 aOutBuffer.Append(KTelnetSB); // Suboption Start |
|
772 aOutBuffer.Append(KTelnetProtOptionTerminalType); // Terminal Type |
|
773 aOutBuffer.Append(KTelnetCommandIS); // IS |
|
774 aOutBuffer.Append(iTermType); // Terminal Type eg "dumb" |
|
775 aOutBuffer.Append(KTelnetIAC);// Interpret As Command |
|
776 aOutBuffer.Append(KTelnetSE); // Suboption End |
|
777 } |
|
778 |
|
779 void CTerminalTypeOption::GetTelnetOptionStatus(TDes8& aCurrentStatus) |
|
780 /** |
|
781 Virtual overide |
|
782 Returns a Telnet Protocol option status , see RFC 859 |
|
783 */ |
|
784 { |
|
785 if(iFSM.ClientEnabled()) |
|
786 { |
|
787 aCurrentStatus.Append(KTelnetWILL); |
|
788 aCurrentStatus.Append(KTelnetProtOptionTerminalType); |
|
789 } |
|
790 } |
|
791 |
|
792 TBool CTerminalTypeOption::Set(const TDesC8& aType) |
|
793 /** |
|
794 Sets the terminal type, returns TRUE if the type has altered |
|
795 */ |
|
796 { |
|
797 TBool ret; |
|
798 (aType == iTermType) ? (ret = FALSE) : (ret = TRUE); |
|
799 iTermType = aType; |
|
800 return ret; |
|
801 } |
|
802 |
|
803 CWindowSizeOption* CWindowSizeOption::NewL() |
|
804 { |
|
805 CWindowSizeOption* self = new(ELeave) CWindowSizeOption; |
|
806 CleanupStack::PushL(self); |
|
807 self->ConstructL(); |
|
808 CleanupStack::Pop(); |
|
809 return self; |
|
810 } |
|
811 |
|
812 TInt32 CWindowSizeOption::RequestOption(const TInt32 aRequest, TDes8& aAction,TInt32& aEvent) |
|
813 { |
|
814 TInt32 action; |
|
815 TInt32 err; |
|
816 err = iFSM.Request(aRequest,action,aEvent); |
|
817 if(action != TOptionFSM::ENoAction) |
|
818 CreateOptionResponse(KTelnetProtOptionWindowSize,action,aAction); |
|
819 return(err); |
|
820 } |
|
821 |
|
822 void CWindowSizeOption::ConstructL() |
|
823 { |
|
824 iWindowSize.x = 80; |
|
825 iWindowSize.y = 24; |
|
826 } |
|
827 |
|
828 TBool CWindowSizeOption::Set(const TTelnetConfig::TWindowSize& aSize) |
|
829 /** |
|
830 Sets the window size, returns TRUE if it's altered |
|
831 */ |
|
832 { |
|
833 TBool ret; |
|
834 (iWindowSize.x == aSize.x && iWindowSize.y == aSize.y) ? (ret = FALSE) : (ret = TRUE); |
|
835 iWindowSize.x = aSize.x; |
|
836 iWindowSize.y = aSize.y; |
|
837 return ret; |
|
838 } |
|
839 |
|
840 void CWindowSizeOption::GetTelnetSubOption(TDes8& aOutBuffer) |
|
841 /** |
|
842 Creates the window size suboption in short's |
|
843 Make sure we escape any Interpret As Command 255's (unlikely to occur) |
|
844 */ |
|
845 { |
|
846 aOutBuffer.Append(KTelnetIAC); // Interpret As Command |
|
847 aOutBuffer.Append(KTelnetSB); // Suboption Start |
|
848 aOutBuffer.Append(KTelnetProtOptionWindowSize); // Window Size (NAWS) |
|
849 |
|
850 TUint8 nibble; |
|
851 |
|
852 nibble = (TUint8)(iWindowSize.x >> 8); // High Byte of x |
|
853 aOutBuffer.Append(nibble); |
|
854 if(nibble == KTelnetIAC) // Escape check |
|
855 aOutBuffer.Append(KTelnetIAC); |
|
856 nibble = (TUint8)iWindowSize.x; // Low byte of x |
|
857 aOutBuffer.Append(nibble); |
|
858 if(nibble == KTelnetIAC) // Escape check |
|
859 aOutBuffer.Append(KTelnetIAC); |
|
860 |
|
861 nibble = (TUint8)(iWindowSize.y >> 8); // High byte of y |
|
862 aOutBuffer.Append(nibble); |
|
863 if(nibble == KTelnetIAC) // Escape check |
|
864 aOutBuffer.Append(KTelnetIAC); |
|
865 nibble = (TUint8)iWindowSize.y; // Low byte of y |
|
866 aOutBuffer.Append(nibble); |
|
867 if(nibble == KTelnetIAC) // Escape check |
|
868 aOutBuffer.Append(KTelnetIAC); |
|
869 |
|
870 aOutBuffer.Append(KTelnetIAC); // Interpret As Command |
|
871 aOutBuffer.Append(KTelnetSE); // Suboption End |
|
872 } |
|
873 |
|
874 void CWindowSizeOption::GetTelnetOptionStatus(TDes8& aCurrentStatus) |
|
875 /** |
|
876 Virtual overide |
|
877 Returns a Telnet Protocol option status , see RFC 859 |
|
878 */ |
|
879 { |
|
880 if(iFSM.ClientEnabled()) |
|
881 { |
|
882 aCurrentStatus.Append(KTelnetWILL); |
|
883 aCurrentStatus.Append(KTelnetProtOptionWindowSize); |
|
884 } |
|
885 } |
|
886 |
|
887 |
|
888 CEchoOption* CEchoOption::NewL() |
|
889 { |
|
890 CEchoOption* self = new(ELeave) CEchoOption; |
|
891 CleanupStack::PushL(self); |
|
892 self->ConstructL(); |
|
893 CleanupStack::Pop(); |
|
894 return self; |
|
895 } |
|
896 |
|
897 TInt32 CEchoOption::RequestOption(const TInt32 aRequest,TDes8& aAction,TInt32& aEvent) |
|
898 { |
|
899 TInt32 action; |
|
900 TInt32 err; |
|
901 err = iFSM.Request(aRequest,action,aEvent); |
|
902 if(action != TOptionFSM::ENoAction) |
|
903 CreateOptionResponse(KTelnetProtOptionEcho,action,aAction); |
|
904 return(err); |
|
905 } |
|
906 |
|
907 void CEchoOption::ConstructL() |
|
908 { |
|
909 } |
|
910 |
|
911 void CEchoOption::GetTelnetOptionStatus(TDes8& aCurrentStatus) |
|
912 /** |
|
913 Virtual overide |
|
914 Returns a Telnet Protocol option status , see RFC 859 |
|
915 */ |
|
916 { |
|
917 if(iFSM.ClientEnabled()) |
|
918 { |
|
919 aCurrentStatus.Append(KTelnetWILL); |
|
920 aCurrentStatus.Append(KTelnetProtOptionEcho); |
|
921 } |
|
922 } |
|
923 |
|
924 |
|
925 CBinaryOption* CBinaryOption::NewL() |
|
926 { |
|
927 CBinaryOption* self = new(ELeave) CBinaryOption; |
|
928 CleanupStack::PushL(self); |
|
929 self->ConstructL(); |
|
930 CleanupStack::Pop(); |
|
931 return self; |
|
932 } |
|
933 |
|
934 TInt32 CBinaryOption::RequestOption(const TInt32 aRequest,TDes8& aAction,TInt32& aEvent) |
|
935 { |
|
936 TInt32 action; |
|
937 TInt32 err; |
|
938 |
|
939 err = iFSM.Request(aRequest,action,aEvent); |
|
940 if(action != TOptionFSM::ENoAction) |
|
941 CreateOptionResponse(KTelnetProtOptionBinary,action,aAction); |
|
942 return(err); |
|
943 } |
|
944 |
|
945 void CBinaryOption::ConstructL() |
|
946 { |
|
947 } |
|
948 |
|
949 void CBinaryOption::GetTelnetOptionStatus(TDes8& aCurrentStatus) |
|
950 /** |
|
951 Virtual overide |
|
952 Returns a Telnet Protocol option status , see RFC 859 |
|
953 */ |
|
954 { |
|
955 if(iFSM.ClientEnabled()) |
|
956 { |
|
957 aCurrentStatus.Append(KTelnetWILL); |
|
958 aCurrentStatus.Append(KTelnetProtOptionBinary); |
|
959 } |
|
960 } |
|
961 |
|
962 CProto* CProto::NewL(const TTelnetConfig& aConfig,MProtoEvent* aNotifier) |
|
963 { |
|
964 CProto* self = new(ELeave) CProto; |
|
965 CleanupStack::PushL(self); |
|
966 self->ConstructL(aConfig,aNotifier); |
|
967 CleanupStack::Pop(); |
|
968 return self; |
|
969 } |
|
970 |
|
971 void CProto::ConstructL(const TTelnetConfig& aConfig,MProtoEvent* aNotifier) |
|
972 /** |
|
973 Initialises the protocol object and creates the RFC objects |
|
974 */ |
|
975 { |
|
976 iNotifier = aNotifier; |
|
977 |
|
978 iReceiveState = ENormal; |
|
979 iUrgentFlag = FALSE; |
|
980 |
|
981 iBinary = CBinaryOption::NewL(); |
|
982 iEcho = CEchoOption::NewL(); |
|
983 iWindowSize = CWindowSizeOption::NewL(); |
|
984 iTerminalType = CTerminalTypeOption::NewL(); |
|
985 iLogout = CLogoutOption::NewL(); |
|
986 iSpeed = CSpeedOption::NewL(); |
|
987 iGA = CSuppressGAOption::NewL(); |
|
988 iStatus = CStatusOption::NewL(); |
|
989 iUnknown = CUnknownOption::NewL(); |
|
990 |
|
991 // Set the permitted requests for all the RFC objects |
|
992 // Logout permissions are set from the aConfig |
|
993 // Echo permissions are set from aConfig |
|
994 iWindowSize->SetRequestPermission |
|
995 ( |
|
996 TOptionFSM::EServerDo | TOptionFSM::EClientWill |
|
997 ); |
|
998 |
|
999 iStatus->SetRequestPermission |
|
1000 ( |
|
1001 TOptionFSM::EServerWill | TOptionFSM::EClientDo | |
|
1002 TOptionFSM::EClientWill | TOptionFSM::EServerDo |
|
1003 ); |
|
1004 |
|
1005 iSpeed->SetRequestPermission |
|
1006 ( |
|
1007 TOptionFSM::EServerDo | TOptionFSM::EClientWill |
|
1008 ); |
|
1009 |
|
1010 iTerminalType->SetRequestPermission |
|
1011 ( |
|
1012 TOptionFSM::EServerDo | TOptionFSM::EClientWill |
|
1013 ); |
|
1014 |
|
1015 iBinary->SetRequestPermission |
|
1016 ( |
|
1017 TOptionFSM::EClientDo | TOptionFSM::EServerWill | |
|
1018 TOptionFSM::EServerDo | TOptionFSM::EClientWill |
|
1019 ); |
|
1020 |
|
1021 iGA->SetRequestPermission |
|
1022 ( |
|
1023 TOptionFSM::EClientDo | TOptionFSM::EServerWill | |
|
1024 TOptionFSM::EServerDo | TOptionFSM::EClientWill |
|
1025 ); |
|
1026 // NULL means we don't want a protocol string returned to send to the server |
|
1027 ModifyConfig(aConfig,NULL); |
|
1028 } |
|
1029 |
|
1030 void CProto::ReceiveUrgent(TInt aUrgentData) |
|
1031 /** |
|
1032 We've received an urgent notification |
|
1033 aUrgent will be the urgent data byte, currently we're not interested in what it is |
|
1034 */ |
|
1035 { |
|
1036 iUrgentFlag = TRUE; |
|
1037 iUrgentData = aUrgentData; |
|
1038 } |
|
1039 |
|
1040 void CProto::GetOptionStatus(TDes8& aOutBuffer)\ |
|
1041 /** |
|
1042 Called when the server wants to know our perceived state of the Telnet option RFC's |
|
1043 RFC member methods add WILL/DO KTelnetProtOptionXXXX, if its currently enabled for the client |
|
1044 */ |
|
1045 { |
|
1046 aOutBuffer.Append(KTelnetIAC); // Interpret As Command |
|
1047 aOutBuffer.Append(KTelnetSB); // Suboption Start |
|
1048 aOutBuffer.Append(KTelnetProtOptionStatus); // KTelnetProtOptionStatus |
|
1049 aOutBuffer.Append(KTelnetCommandIS); // IS |
|
1050 |
|
1051 iBinary->GetTelnetOptionStatus(aOutBuffer); // ? WILL Binary |
|
1052 iWindowSize->GetTelnetOptionStatus(aOutBuffer); // ? WILL NAWS |
|
1053 iTerminalType->GetTelnetOptionStatus(aOutBuffer); // ? WILL Terminal Type |
|
1054 iSpeed->GetTelnetOptionStatus(aOutBuffer); // ? WILL Terminal Speed |
|
1055 iGA->GetTelnetOptionStatus(aOutBuffer); // ? DO Suppress Go Ahead |
|
1056 iStatus->GetTelnetOptionStatus(aOutBuffer); // ? WILL and/or DO Status |
|
1057 |
|
1058 aOutBuffer.Append(KTelnetIAC); // Interpret As Command |
|
1059 aOutBuffer.Append(KTelnetSE); // Suboption End |
|
1060 } |
|
1061 |
|
1062 void CProto::OptionStatus(TOptionStatus& aStatus) |
|
1063 /** |
|
1064 Client has requested the state of the RFC options |
|
1065 */ |
|
1066 { |
|
1067 (iBinary->ReceiveBinary() == TRUE) ? (aStatus.iServerBinary = TRUE) : (aStatus.iServerBinary = FALSE); |
|
1068 (iBinary->SendBinary() == TRUE) ? (aStatus.iClientBinary = TRUE) : (aStatus.iClientBinary = FALSE); |
|
1069 (iEcho->ReceiveEcho() == TRUE) ? (aStatus.iEcho = TRUE) : (aStatus.iEcho = FALSE); |
|
1070 (iWindowSize->SendWindowSize()) ? (aStatus.iNAWS = TRUE) : (aStatus.iNAWS = FALSE); |
|
1071 (iSpeed->SendSpeed() == TRUE) ? (aStatus.iTerminalSpeed = TRUE) : (aStatus.iTerminalSpeed = FALSE); |
|
1072 (iTerminalType->SendTerminalType() == TRUE) ? (aStatus.iTerminalType = TRUE) : (aStatus.iTerminalType = FALSE); |
|
1073 (iStatus->ReceiveStatus() == TRUE) ? (aStatus.iServerStatus = TRUE) : (aStatus.iServerStatus = FALSE); |
|
1074 (iStatus->SendStatus() == TRUE) ? (aStatus.iClientStatus = TRUE) : (aStatus.iClientStatus = FALSE); |
|
1075 } |
|
1076 |
|
1077 void CProto::ServerOptionStatus(TDes8& aActionBuffer) |
|
1078 { |
|
1079 if(iStatus->ReceiveStatus()) |
|
1080 { |
|
1081 aActionBuffer.Append(KTelnetIAC); // Interpret As Command |
|
1082 aActionBuffer.Append(KTelnetSB); // Suboption Start |
|
1083 aActionBuffer.Append(KTelnetProtOptionStatus);// Status |
|
1084 aActionBuffer.Append(KTelnetCommandSEND); // Send |
|
1085 aActionBuffer.Append(KTelnetIAC); // Interpret As Command |
|
1086 aActionBuffer.Append(KTelnetSE); // Suboption End |
|
1087 } |
|
1088 } |
|
1089 |
|
1090 void CProto::GetInitOptions(TDes8& aActionBuffer) |
|
1091 /** |
|
1092 Should be called following connection |
|
1093 Place here any calls to enable options at connection time |
|
1094 */ |
|
1095 { |
|
1096 TInt32 event; |
|
1097 // Switch on binary if the terminal is not "dumb" |
|
1098 if(iTerminalType->TerminalType() != _L8("dumb")) |
|
1099 ClientRequestOption(KTelnetProtOptionBinary,aActionBuffer,event); |
|
1100 // Always suppress the Go Ahead signal |
|
1101 ClientRequestOption(KTelnetProtOptionSuppressGA,aActionBuffer,event); |
|
1102 } |
|
1103 |
|
1104 |
|
1105 void CProto::ModifyConfig(const TTelnetConfig& aConfig,TDes8 * aActionBuffer) |
|
1106 /** |
|
1107 Modify the configurable options |
|
1108 aActionBuffer is set to NULL if the caller does not want to notify the server of option changes |
|
1109 */ |
|
1110 { |
|
1111 // If the speed has changed |
|
1112 if(iSpeed->Set(aConfig.iTermSpeed)) |
|
1113 { |
|
1114 // If speed option is not enabled and caller wants to notify server |
|
1115 if(!iSpeed->SendSpeed() && aActionBuffer) |
|
1116 { |
|
1117 TInt32 event; |
|
1118 // If caller wants to notify server |
|
1119 // Switch the option on |
|
1120 ClientRequestOption(KTelnetProtOptionTerminalSpeed,*aActionBuffer,event); |
|
1121 } |
|
1122 } |
|
1123 // Terminal Type |
|
1124 // We don't currently support lists of terminal types. |
|
1125 // All telnet servers request the terminal type first thing so, just modify the terminal type |
|
1126 // If the connection is up, then the client will have to close the connection |
|
1127 iTerminalType->Set(aConfig.iTermType); |
|
1128 // NAWS |
|
1129 // If window size has changed |
|
1130 if(iWindowSize->Set(aConfig.iWindowSize)) |
|
1131 { |
|
1132 // If NAWS is not enabled and the user wants to notify the server |
|
1133 if(!iWindowSize->SendWindowSize() && aActionBuffer) |
|
1134 { |
|
1135 TInt32 event; |
|
1136 // Switch on NAWS |
|
1137 ClientRequestOption(KTelnetProtOptionWindowSize,*aActionBuffer,event); |
|
1138 } |
|
1139 else |
|
1140 // Window size is already enabled |
|
1141 // If the caller wants to notify the server |
|
1142 if(aActionBuffer) |
|
1143 // return IAC SB NAWS IS X Y IAC SE |
|
1144 iWindowSize->GetTelnetSubOption(*aActionBuffer); |
|
1145 } |
|
1146 |
|
1147 // Enable/disable server logout is a passive set action |
|
1148 // If the Client wants to force a Telnet defined logout then it should call DoForceLogout() |
|
1149 if(aConfig.iAllowLogout) |
|
1150 iLogout->SetRequestPermission |
|
1151 ( |
|
1152 TOptionFSM::EServerWill | TOptionFSM::EClientDo |
|
1153 ); |
|
1154 else |
|
1155 iLogout->SetRequestPermission |
|
1156 ( |
|
1157 TOptionFSM::ENoOption |
|
1158 ); |
|
1159 // Echo |
|
1160 // First set the permissions for the Server depending on the member boolean |
|
1161 if(aConfig.iServerEcho) |
|
1162 iEcho->SetRequestPermission(TOptionFSM::EServerWill | TOptionFSM::EClientDo); |
|
1163 else |
|
1164 iEcho->SetRequestPermission(TOptionFSM::ENoOption); |
|
1165 |
|
1166 // Echo is a "toggler" |
|
1167 // If we are required to supply an action and the client wants to change the echo state |
|
1168 if(aActionBuffer && iEcho->ReceiveEcho() != aConfig.iServerEcho) |
|
1169 { |
|
1170 TInt32 event; |
|
1171 // Call the routine to create the request as the client is attempting to toggle |
|
1172 // Server echo |
|
1173 ClientRequestOption(KTelnetProtOptionEcho,*aActionBuffer,event); |
|
1174 } |
|
1175 } |
|
1176 |
|
1177 |
|
1178 TInt CProto::ClientRequestOption(TInt32 aOptionRequest,TDes8& aAction,TInt32& aEvent) |
|
1179 /** |
|
1180 Creates client side option requests |
|
1181 Currently we only switch on options |
|
1182 Ignore the errors as we can pre-check the state of the option before we call this. |
|
1183 */ |
|
1184 { |
|
1185 TInt32 err = KErrNone; |
|
1186 TInt32 event; |
|
1187 TBuf8<10> action; |
|
1188 |
|
1189 aEvent = TOptionFSM::ENoEvent; |
|
1190 |
|
1191 // If binary |
|
1192 if(aOptionRequest == KTelnetProtOptionBinary) |
|
1193 { |
|
1194 // Request the server to transmit in Binary |
|
1195 err = iBinary->RequestOption(TOptionFSM::EClientDo,action,event); |
|
1196 aEvent |= event; |
|
1197 aAction.Append(action); |
|
1198 |
|
1199 // Tell the server we are prepared to transmit in binary |
|
1200 action.SetLength(0); |
|
1201 err = iBinary->RequestOption(TOptionFSM::EClientWill,action,event); |
|
1202 aEvent |= event; |
|
1203 aAction.Append(action); |
|
1204 } |
|
1205 else if(aOptionRequest == KTelnetProtOptionSuppressGA) |
|
1206 { |
|
1207 // Request the server to suppress the go ahead signal |
|
1208 err = iGA->RequestOption(TOptionFSM::EClientDo,action,event); |
|
1209 aEvent |= event; |
|
1210 aAction.Append(action); |
|
1211 |
|
1212 // Tell the server we are prepared to suppress the go ahead signal |
|
1213 action.SetLength(0); |
|
1214 err = iGA->RequestOption(TOptionFSM::EClientWill,action,event); |
|
1215 aEvent |= event; |
|
1216 aAction.Append(action); |
|
1217 } |
|
1218 else if(aOptionRequest == KTelnetProtOptionStatus) |
|
1219 { |
|
1220 // Tell the server we are prepared to send status information |
|
1221 err = iStatus->RequestOption(TOptionFSM::EClientWill,action,event); |
|
1222 aEvent = event; |
|
1223 aAction.Append(action); |
|
1224 } |
|
1225 else if(aOptionRequest == KTelnetProtOptionLogoff) |
|
1226 { |
|
1227 // Client is forcing a logout |
|
1228 iLogout->SetRequestPermission |
|
1229 ( |
|
1230 TOptionFSM::EServerWill | TOptionFSM::EClientDo |
|
1231 ); |
|
1232 err = iLogout->RequestOption(TOptionFSM::EClientDo,action,event); |
|
1233 aEvent = event; |
|
1234 aAction.Append(action); |
|
1235 } |
|
1236 else if(aOptionRequest == KTelnetProtOptionWindowSize) |
|
1237 { |
|
1238 // Tell the Server we are prepared to send window size information |
|
1239 err = iWindowSize->RequestOption(TOptionFSM::EClientWill,action,event); |
|
1240 aEvent = event; |
|
1241 aAction.Append(action); |
|
1242 } |
|
1243 else if(aOptionRequest == KTelnetProtOptionTerminalType) |
|
1244 { |
|
1245 // Tell the server we are prepared to send terminal type information |
|
1246 err = iTerminalType->RequestOption(TOptionFSM::EClientWill,action,event); |
|
1247 aEvent = event; |
|
1248 aAction.Append(action); |
|
1249 } |
|
1250 else if(aOptionRequest == KTelnetProtOptionTerminalSpeed) |
|
1251 { |
|
1252 // Tell the server we are prepared to send terminal speed information |
|
1253 err = iSpeed->RequestOption(TOptionFSM::EClientWill,action,event); |
|
1254 aEvent = event; |
|
1255 aAction.Append(action); |
|
1256 } |
|
1257 else if(aOptionRequest == KTelnetProtOptionEcho) |
|
1258 { |
|
1259 // Echo is a special case where we toggle |
|
1260 if(iEcho->ReceiveEcho()) |
|
1261 // Server Echo is currently enabled on so tell server DONT |
|
1262 err = iEcho->RequestOption(TOptionFSM::EClientDont,action,event); |
|
1263 else |
|
1264 // Server Echo is currently disabled so tell server DO |
|
1265 err = iEcho->RequestOption(TOptionFSM::EClientDo,action,event); |
|
1266 aEvent = event; |
|
1267 aAction.Append(action); |
|
1268 } |
|
1269 |
|
1270 |
|
1271 return(err); |
|
1272 } |
|
1273 |
|
1274 TInt CProto::ProtoWrite(const TDesC8& aInBuffer,TDes8& aOutBuffer) |
|
1275 /** |
|
1276 Modifies the output stream :- |
|
1277 Escape EIAC in Binary mode. |
|
1278 PAD CR to CR NULL when not in binary mode |
|
1279 */ |
|
1280 { |
|
1281 if(iBinary->SendBinary()) |
|
1282 { |
|
1283 for(TInt i=0;i<aInBuffer.Length();i++) |
|
1284 { |
|
1285 if(aInBuffer[i] == KTelnetIAC) |
|
1286 aOutBuffer.Append(KTelnetIAC); |
|
1287 aOutBuffer.Append(aInBuffer[i]); |
|
1288 } |
|
1289 } |
|
1290 else |
|
1291 { |
|
1292 for(TInt i=0;i<aInBuffer.Length();i++) |
|
1293 { |
|
1294 aOutBuffer.Append(aInBuffer[i]); |
|
1295 if(aInBuffer[i] == KTelnetCR && (i == (aInBuffer.Length() - 1) || aInBuffer[i+1] != KTelnetLF)) |
|
1296 { |
|
1297 aOutBuffer.Append(KTelnetNULL); |
|
1298 } |
|
1299 } |
|
1300 } |
|
1301 return(KErrNone); |
|
1302 } |
|
1303 |
|
1304 TInt CProto::ProtoWrite(const TTelnetUserControl& aControlCode,TDes8& aBuffer,TDes8& aUrgentBuffer) |
|
1305 /** |
|
1306 Writes a Telnet 854 defined control code to the server |
|
1307 In the case of an Interrupt Process we need to send urgent data |
|
1308 */ |
|
1309 { |
|
1310 TInt err; |
|
1311 if(aControlCode == KTelnetIP) |
|
1312 // Interrupt Process, supported in Binary and NVT mode |
|
1313 { |
|
1314 aUrgentBuffer.Append(KTelnetIAC); // Interpret As Command *** URGENT *** |
|
1315 aUrgentBuffer.Append(KTelnetIP); // Interrupt Process *** URGENT *** |
|
1316 aUrgentBuffer.Append(KTelnetIAC); // Interpret As Command *** URGENT *** |
|
1317 aBuffer.Append(KTelnetDM); // Data Mark |
|
1318 err = KErrNone; |
|
1319 } |
|
1320 else |
|
1321 { |
|
1322 // All codes valid when not in binary |
|
1323 if(!iBinary->SendBinary()) |
|
1324 { |
|
1325 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoWrite() Normal Send Control = %d"),aControlCode); |
|
1326 aBuffer.Append(KTelnetIAC); // Interpret As Command |
|
1327 aBuffer.Append((TInt8)aControlCode); // Code |
|
1328 err = KErrNone; |
|
1329 } |
|
1330 else if(aControlCode == KTelnetAYT || aControlCode == KTelnetAO) |
|
1331 // In binary Are You There and Abort Output only |
|
1332 { |
|
1333 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoWrite() Binary Send Control = %d"),aControlCode); |
|
1334 aBuffer.Append(KTelnetIAC); // Interpret As Command |
|
1335 aBuffer.Append((TInt8)aControlCode); // Code |
|
1336 err = KErrNone; |
|
1337 } |
|
1338 else |
|
1339 { |
|
1340 err = KErrGeneral; |
|
1341 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoWrite() ERROR Illegal Code in Binary")); |
|
1342 } |
|
1343 } |
|
1344 return(err); |
|
1345 } |
|
1346 |
|
1347 |
|
1348 TInt CProto::ProtoRead(const TDesC8& aInBuffer,TDes8& aClientOutBuffer,TDes8& aProtoOutBuffer) |
|
1349 /** |
|
1350 Process data received from the Telnet Server |
|
1351 Contains receive state machine plus sub-state machine for suboptions |
|
1352 */ |
|
1353 { |
|
1354 // TBuf8<64> action; |
|
1355 TBuf8<128> subOptions; |
|
1356 TInt32 numEvents = 0; |
|
1357 // Loop through the input buffer byte by byte |
|
1358 for(TInt i=0;i<aInBuffer.Length();i++) |
|
1359 { |
|
1360 switch(iReceiveState) |
|
1361 { |
|
1362 case ENormal : |
|
1363 // Check for Interpret as command |
|
1364 if(aInBuffer[i] == KTelnetIAC) |
|
1365 { |
|
1366 // Reset the object protocol receive buffer |
|
1367 iProtReadBuffer.SetLength(0); |
|
1368 // Set the state |
|
1369 iReceiveState = EIAC; |
|
1370 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() IAC")); |
|
1371 } |
|
1372 // Check for first character of a RFC 854 Sync |
|
1373 else if(aInBuffer[i] == KTelnetIP) |
|
1374 { |
|
1375 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() IP")); |
|
1376 } |
|
1377 // Check for Data Mark that follows Sync and ends urgent processing |
|
1378 else if(aInBuffer[i] == KTelnetDM && iUrgentFlag) |
|
1379 { |
|
1380 iUrgentFlag = FALSE; |
|
1381 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() DM")); |
|
1382 } |
|
1383 // Check we are not discarding during urgent receive waiting for DM |
|
1384 else if(!iUrgentFlag) |
|
1385 { |
|
1386 // Pass to client |
|
1387 // Normal data received, just write it to the output buffer |
|
1388 aClientOutBuffer.Append(aInBuffer[i]); |
|
1389 } |
|
1390 else |
|
1391 { |
|
1392 // Discard |
|
1393 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Discard During Urgent")); |
|
1394 } |
|
1395 break; |
|
1396 |
|
1397 case EIAC : |
|
1398 // Last character received was an Interpret As Command |
|
1399 // Check for DO WILL WONT DONT |
|
1400 if(aInBuffer[i] == KTelnetDO || aInBuffer[i] == KTelnetWILL || aInBuffer[i] == KTelnetDONT || aInBuffer[i] == KTelnetWONT) |
|
1401 { |
|
1402 // Add it to the protocol buffer |
|
1403 iProtReadBuffer.Append(aInBuffer[i]); |
|
1404 iReceiveState = ECommand; |
|
1405 } |
|
1406 else if(aInBuffer[i] == KTelnetSB) |
|
1407 { |
|
1408 // Suboption Start |
|
1409 iReceiveState = ESubOpt; |
|
1410 iSubOptState = ESB; |
|
1411 } |
|
1412 else |
|
1413 { |
|
1414 // Interpret As Command followed by Interpret As Command |
|
1415 if(aInBuffer[i] == KTelnetIAC) |
|
1416 { |
|
1417 // Previous Interpret As Command is Escaping a genuine 255 , legal in Binary Mode |
|
1418 if(iBinary->ReceiveBinary() && !iUrgentFlag) |
|
1419 { |
|
1420 // Pass to client |
|
1421 aClientOutBuffer.Append(aInBuffer[i]); |
|
1422 } |
|
1423 else |
|
1424 { |
|
1425 // Discard whilst in urgent or illegal in NVT mode |
|
1426 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Illegal IAC Urgent = %d"),iUrgentFlag); |
|
1427 } |
|
1428 } |
|
1429 else |
|
1430 { |
|
1431 // Unsupported command |
|
1432 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Unsupported Command = %d"),aInBuffer[i]); |
|
1433 } |
|
1434 // Back to normal state |
|
1435 iReceiveState = ENormal; |
|
1436 } |
|
1437 break; |
|
1438 |
|
1439 case ESubOpt : |
|
1440 // Receiving a Suboption sequence |
|
1441 if(iSubOptState == ESB) |
|
1442 { |
|
1443 // TERMINAL-TYPE,TERMINAL-SPEED,STATUS |
|
1444 iProtReadBuffer.Append(aInBuffer[i]); |
|
1445 iSubOptState = EOption; |
|
1446 } |
|
1447 else if(iSubOptState == EOption) |
|
1448 { |
|
1449 // SEND or IS |
|
1450 iProtReadBuffer.Append(aInBuffer[i]); |
|
1451 iSubOptState = ERequest; |
|
1452 } |
|
1453 else if(iSubOptState == ERequest) |
|
1454 { |
|
1455 // IAC or STATUS info from the server |
|
1456 if(aInBuffer[i] == KTelnetIAC) |
|
1457 { |
|
1458 iSubOptState = EEndIAC; |
|
1459 } |
|
1460 iProtReadBuffer.Append(aInBuffer[i]); |
|
1461 } |
|
1462 else if(iSubOptState == EEndIAC && aInBuffer[i] == KTelnetSE) |
|
1463 { |
|
1464 // SE Suboption End |
|
1465 // Scan through the sequence we have just received |
|
1466 // Currently we support sending Window Size ,Terminal Speed and Status Information |
|
1467 if(iProtReadBuffer[0] == KTelnetProtOptionTerminalType) |
|
1468 { |
|
1469 // Get our window size |
|
1470 iTerminalType->GetTelnetSubOption(aProtoOutBuffer); |
|
1471 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SE Term Type")); |
|
1472 } |
|
1473 else if(iProtReadBuffer[0] == KTelnetProtOptionTerminalSpeed) |
|
1474 { |
|
1475 // Get our speed |
|
1476 iSpeed->GetTelnetSubOption(aProtoOutBuffer); |
|
1477 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SE Term Speed")); |
|
1478 } |
|
1479 else if(iProtReadBuffer[0] == KTelnetProtOptionStatus) |
|
1480 { |
|
1481 // Check whether it's a request for us to send or it's status info from the server |
|
1482 if(iProtReadBuffer[1] == KTelnetCommandSEND) |
|
1483 { |
|
1484 // Server wants our status |
|
1485 GetOptionStatus(aProtoOutBuffer); |
|
1486 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SE STATUS SEND")); |
|
1487 } |
|
1488 else if(iProtReadBuffer[1] == KTelnetCommandIS) |
|
1489 { |
|
1490 // Status info from the server |
|
1491 // We are currently doing nothing with it but in case |
|
1492 // the client wants to know the server's perceived state of the connection |
|
1493 // store it in the object |
|
1494 iServerStatus = iProtReadBuffer; |
|
1495 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SE STATUS IS")); |
|
1496 } |
|
1497 else |
|
1498 { |
|
1499 // Corruption |
|
1500 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() STATUS SubOption ERROR")); |
|
1501 } |
|
1502 } |
|
1503 iReceiveState = ENormal; |
|
1504 } |
|
1505 else |
|
1506 { |
|
1507 iReceiveState = ENormal; |
|
1508 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() SubOption Unexpected Receive ERROR")); |
|
1509 } |
|
1510 |
|
1511 break; |
|
1512 |
|
1513 case ECommand : |
|
1514 // Last byte received was a DO, WILL, WONT or DONT |
|
1515 { |
|
1516 TInt32 event = TOptionFSM::ENoEvent; |
|
1517 TOptionFSM::TRequests request = TOptionFSM::ENoOption; |
|
1518 TBuf8<64> action; |
|
1519 |
|
1520 // Map to our internal command code |
|
1521 if(iProtReadBuffer[0] == KTelnetDO) |
|
1522 request = TOptionFSM::EServerDo; |
|
1523 else if(iProtReadBuffer[0] == KTelnetWILL) |
|
1524 request = TOptionFSM::EServerWill; |
|
1525 else if(iProtReadBuffer[0] == KTelnetWONT) |
|
1526 request = TOptionFSM::EServerWont; |
|
1527 else if(iProtReadBuffer[0] == KTelnetDONT) |
|
1528 request = TOptionFSM::EServerDont; |
|
1529 |
|
1530 // switch on the RFC option |
|
1531 // Most cases get a possible action and a possible event |
|
1532 switch(aInBuffer[i]) |
|
1533 { |
|
1534 case KTelnetProtOptionEcho : |
|
1535 iEcho->RequestOption(request,action,event); |
|
1536 if(action.Length()) |
|
1537 aProtoOutBuffer.Append(action); |
|
1538 __FLOG_STATIC2(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Echo Event = %d Request = %d"),event,request); |
|
1539 if(event != TOptionFSM::ENoEvent) |
|
1540 numEvents++; |
|
1541 break; |
|
1542 |
|
1543 case KTelnetProtOptionSuppressGA : |
|
1544 iGA->RequestOption(request,action,event); |
|
1545 if(action.Length()) |
|
1546 aProtoOutBuffer.Append(action); |
|
1547 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() GA Event = %d"),event); |
|
1548 break; |
|
1549 |
|
1550 case KTelnetProtOptionBinary : |
|
1551 iBinary->RequestOption(request,action,event); |
|
1552 if(action.Length()) |
|
1553 aProtoOutBuffer.Append(action); |
|
1554 __FLOG_STATIC2(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Binary Event = %d request = %d"),event,request); |
|
1555 if(event != TOptionFSM::ENoEvent) |
|
1556 numEvents++; |
|
1557 break; |
|
1558 |
|
1559 case KTelnetProtOptionTerminalSpeed : |
|
1560 iSpeed->RequestOption(request,action,event); |
|
1561 if(action.Length()) |
|
1562 aProtoOutBuffer.Append(action); |
|
1563 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Terminal Speed Event = %d"),event); |
|
1564 if(event != TOptionFSM::ENoEvent) |
|
1565 numEvents++; |
|
1566 break; |
|
1567 |
|
1568 case KTelnetProtOptionTerminalType : |
|
1569 iTerminalType->RequestOption(request,action,event); |
|
1570 if(action.Length()) |
|
1571 aProtoOutBuffer.Append(action); |
|
1572 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Terminal Type Event = %d"),event); |
|
1573 if(event != TOptionFSM::ENoEvent) |
|
1574 numEvents++; |
|
1575 break; |
|
1576 |
|
1577 case KTelnetProtOptionWindowSize : |
|
1578 // Winbdow size, send our window size if it's enabled |
|
1579 iWindowSize->RequestOption(request,action,event); |
|
1580 if(action.Length()) |
|
1581 aProtoOutBuffer.Append(action); |
|
1582 if(event == TOptionFSM::EClientEnabled) |
|
1583 { |
|
1584 iWindowSize->GetTelnetSubOption(subOptions); |
|
1585 } |
|
1586 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Window Size Event = %d"),event); |
|
1587 if(event != TOptionFSM::ENoEvent) |
|
1588 numEvents++; |
|
1589 break; |
|
1590 |
|
1591 case KTelnetProtOptionLogoff : |
|
1592 // Server may want to log us out |
|
1593 iLogout->RequestOption(request,action,event); |
|
1594 if(action.Length()) |
|
1595 aProtoOutBuffer.Append(action); |
|
1596 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Logout Event = %d"),event); |
|
1597 break; |
|
1598 |
|
1599 case KTelnetProtOptionStatus : |
|
1600 iStatus->RequestOption(request,action,event); |
|
1601 if(action.Length()) |
|
1602 aProtoOutBuffer.Append(action); |
|
1603 __FLOG_STATIC2(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Status Event = %d request = %d"),event,request); |
|
1604 if(event != TOptionFSM::ENoEvent) |
|
1605 numEvents++; |
|
1606 break; |
|
1607 |
|
1608 default : |
|
1609 iUnknown->RequestUnknown(aInBuffer[i],request,action,event); |
|
1610 if(action.Length()) |
|
1611 aProtoOutBuffer.Append(action); |
|
1612 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Unsupported Option = %d"),aInBuffer[i]); |
|
1613 break; |
|
1614 |
|
1615 } |
|
1616 } |
|
1617 iReceiveState = ENormal; |
|
1618 break; |
|
1619 |
|
1620 default : |
|
1621 break; |
|
1622 } |
|
1623 } |
|
1624 // If any option events have occured then tell the client side so it can retrieve the status |
|
1625 // if it's interested |
|
1626 if(numEvents) |
|
1627 iNotifier->ProtoEvent(); |
|
1628 |
|
1629 if(subOptions.Length()) |
|
1630 { |
|
1631 aProtoOutBuffer.Append(subOptions); |
|
1632 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::ProtoRead() Add SubOpt Length = %d"),subOptions.Length()); |
|
1633 } |
|
1634 return(KErrNone); |
|
1635 } |
|
1636 |
|
1637 void CProto::Reset() |
|
1638 /** |
|
1639 Clear states |
|
1640 Don't bother to zero buffers as state machine does them |
|
1641 */ |
|
1642 { |
|
1643 iReceiveState = ENormal; |
|
1644 iUrgentFlag = FALSE; |
|
1645 |
|
1646 iBinary->Reset(); |
|
1647 iLogout->Reset(); |
|
1648 iWindowSize->Reset(); |
|
1649 iSpeed->Reset(); |
|
1650 iStatus->Reset(); |
|
1651 iTerminalType->Reset(); |
|
1652 iEcho->Reset(); |
|
1653 iGA->Reset(); |
|
1654 } |
|
1655 |
|
1656 |
|
1657 CProto::CProto() |
|
1658 /** |
|
1659 Constructor |
|
1660 */ |
|
1661 { |
|
1662 } |
|
1663 |
|
1664 |
|
1665 CProto::~CProto() |
|
1666 /** |
|
1667 Destructor |
|
1668 */ |
|
1669 { |
|
1670 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CProto::D'Tor")); |
|
1671 |
|
1672 delete iUnknown; |
|
1673 delete iStatus; |
|
1674 delete iGA; |
|
1675 delete iSpeed; |
|
1676 delete iLogout; |
|
1677 delete iTerminalType; |
|
1678 delete iWindowSize; |
|
1679 delete iEcho; |
|
1680 delete iBinary; |
|
1681 } |