|
1 // Copyright (c) 1998-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 // |
|
15 |
|
16 // Tiny Telnet - A simple telnet client to test CTelnetSession API |
|
17 #include "TTELNET.H" |
|
18 //#include <debug.h> |
|
19 |
|
20 |
|
21 // Device driver names |
|
22 #if defined (__WINS__) |
|
23 #define PDD_NAME _L("ECDRV") |
|
24 #define LDD_NAME _L("ECOMM") |
|
25 #else |
|
26 #define PDD_NAME _L("EUART1") |
|
27 #define LDD_NAME _L("ECOMM") |
|
28 #endif |
|
29 |
|
30 static CConsoleBase* console; |
|
31 |
|
32 |
|
33 |
|
34 LOCAL_C void CommInitL() |
|
35 // |
|
36 // Initialisation code - loads the serial LDD and PDD |
|
37 // starts the comm subsystem (for EPOC32 builds) |
|
38 // On a full EPOC implementation, this code would not |
|
39 // be required because higher level components (EIKON) |
|
40 // automatically start the services. |
|
41 // |
|
42 { |
|
43 // Load the physical device driver |
|
44 // The OS will automatically append .PDD and |
|
45 // search /System/Libs on all drives. |
|
46 TInt r=User::LoadPhysicalDevice(PDD_NAME); |
|
47 if (r != KErrNone && r!= KErrAlreadyExists) |
|
48 User::Leave(r); |
|
49 //test(r==KErrNone || r==KErrAlreadyExists); |
|
50 |
|
51 // Similarly for the Logical device driver |
|
52 r=User::LoadLogicalDevice(LDD_NAME); |
|
53 if (r != KErrNone && r != KErrAlreadyExists) |
|
54 User::Leave(r); |
|
55 //test(r==KErrNone|| r==KErrAlreadyExists); |
|
56 |
|
57 } |
|
58 |
|
59 |
|
60 |
|
61 void DriveEngineL(); |
|
62 void SetupConsoleL(); |
|
63 |
|
64 GLDEF_C TInt E32Main() // main function called by E32 |
|
65 { |
|
66 __UHEAP_MARK; |
|
67 CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack |
|
68 TRAPD(error,SetupConsoleL()); // more initialization, then do example |
|
69 __ASSERT_ALWAYS(!error,User::Panic(_L("TTiny Telnet"),error)); |
|
70 delete cleanup; // destroy clean-up stack |
|
71 |
|
72 __UHEAP_MARKEND; |
|
73 return 0; // and return |
|
74 } |
|
75 |
|
76 void SetupConsoleL() // initialize and call example code under cleanup stack |
|
77 { |
|
78 console=Console::NewL(_L("Tiny Telnet"), |
|
79 TSize(KDefaultConsWidth,KDefaultConsHeight)); |
|
80 CleanupStack::PushL(console); |
|
81 TRAPD(error,DriveEngineL()); // perform example function |
|
82 if (error) console->Printf(_L("failed: leave code=%d"), error); |
|
83 else console->Printf(_L("ok")); |
|
84 console->Printf(_L(" [press any key]")); |
|
85 console->Getch(); // get and ignore character |
|
86 CleanupStack::PopAndDestroy(); // close console |
|
87 } |
|
88 |
|
89 /* |
|
90 TTelnet Test code starts here |
|
91 */ |
|
92 |
|
93 void DriveEngineL() |
|
94 { |
|
95 |
|
96 //initialization for COMM port |
|
97 CommInitL(); |
|
98 |
|
99 // Setup Active Scheduler |
|
100 CActiveScheduler* myActiveScheduler = new(ELeave) CActiveScheduler; |
|
101 CleanupStack::PushL(myActiveScheduler); |
|
102 CActiveScheduler::Install(myActiveScheduler); |
|
103 |
|
104 // Create Tiny Telnet |
|
105 CTinyTelnet* aTinyTelnet = CTinyTelnet::NewLC(console); |
|
106 //.. and post request to object |
|
107 aTinyTelnet->RequestCharacter(); |
|
108 |
|
109 myActiveScheduler->Start(); |
|
110 |
|
111 CleanupStack::PopAndDestroy(2); //aTinyTelnet, myActiveScheduler |
|
112 } |
|
113 |
|
114 CTinyTelnet::CTinyTelnet() : CActiveConsole (EPriorityStandard) |
|
115 { |
|
116 } |
|
117 |
|
118 CTinyTelnet::~CTinyTelnet() |
|
119 { |
|
120 delete iTelnetSession; |
|
121 delete iCommandLine; |
|
122 } |
|
123 |
|
124 CTinyTelnet* CTinyTelnet::NewLC(CConsoleBase* aConsole) |
|
125 { |
|
126 CTinyTelnet* self = new (ELeave) CTinyTelnet(); |
|
127 CleanupStack::PushL(self); |
|
128 self->ConstructL(aConsole); |
|
129 return self; |
|
130 } |
|
131 |
|
132 void CTinyTelnet::ConstructL(CConsoleBase* aConsole) |
|
133 { |
|
134 CActiveConsole::ConstructL(aConsole); |
|
135 |
|
136 iState = EComplete; |
|
137 iLocalEcho = FALSE; |
|
138 iBinaryOnOff = FALSE; |
|
139 |
|
140 iCommandLine=CLineEdit::NewL(iConsole,10); |
|
141 // TODO |
|
142 // Modify iTelnetConfig members here for different speed window size etc |
|
143 // iConfig.iTermType = _L8("vt100"); |
|
144 iConfig.iServerEcho = TRUE; |
|
145 iTelnetSession = CTelnetSession::NewL(iConfig,this); |
|
146 iConsole->Printf(_L("'<ESC>' for command prompt\n")); |
|
147 }; |
|
148 |
|
149 void CTinyTelnet::Error(TInt aError) |
|
150 { |
|
151 iConsole->Printf(_L("Error(%d)\n"),aError); |
|
152 } |
|
153 |
|
154 void CTinyTelnet::ReadComplete(const TDesC8& aBuffer) |
|
155 { |
|
156 // I know the driver won't chuck more than 128 bytes at us |
|
157 // The real code should use variable descriptors on the heap |
|
158 TBuf<128> tmpBuffer; |
|
159 // For unicode, use the overloaded copy |
|
160 tmpBuffer.Copy(aBuffer); |
|
161 iConsole->Printf(_L("%S"),&tmpBuffer); |
|
162 Read(); |
|
163 } |
|
164 |
|
165 void CTinyTelnet::WriteComplete() |
|
166 { |
|
167 // Request another character |
|
168 RequestCharacter(); |
|
169 return; |
|
170 } |
|
171 |
|
172 void CTinyTelnet::ConnectionClosed() |
|
173 { |
|
174 iState = EDisconnected; |
|
175 iConsole->Printf(_L("ConnectionClosed()\n")); |
|
176 } |
|
177 |
|
178 void CTinyTelnet::OptionsChanged() |
|
179 { |
|
180 TOptionStatus status; |
|
181 if(iState != EConnected) |
|
182 { |
|
183 iConsole->Printf(_L("No Connection , status not valid\n")); |
|
184 } |
|
185 else |
|
186 iTelnetSession->OptionStatus(status); |
|
187 } |
|
188 |
|
189 void CTinyTelnet::Connected() |
|
190 { |
|
191 iConsole->Printf(_L("Connected()")); |
|
192 Read(); |
|
193 iState = EConnected; |
|
194 } |
|
195 |
|
196 void CTinyTelnet::DisplayOptionStates() |
|
197 // It's debatable whether a user would ever want to see this stuff |
|
198 // It's just here as demo of the call |
|
199 { |
|
200 if(iState != EConnected) |
|
201 { |
|
202 iConsole->Printf(_L("No Connection , status not valid\n")); |
|
203 } |
|
204 else |
|
205 { |
|
206 TOptionStatus aStatus; |
|
207 iTelnetSession->OptionStatus(aStatus); |
|
208 |
|
209 iConsole->Printf(_L("Server Send Binary Option = %d\n"),aStatus.iServerBinary); |
|
210 iConsole->Printf(_L("Client Send Binary Option = %d\n"),aStatus.iClientBinary); |
|
211 iConsole->Printf(_L("Server Echo Data Option = %d\n"),aStatus.iEcho); |
|
212 iConsole->Printf(_L("Client Supply Window Size Option = %d\n"),aStatus.iNAWS); |
|
213 iConsole->Printf(_L("Client Supply Terminal Speed Option = %d\n"),aStatus.iTerminalSpeed); |
|
214 iConsole->Printf(_L("Client Supply Terminal Type Option = %d\n"),aStatus.iTerminalType); |
|
215 iConsole->Printf(_L("Server Supply Status Option = %d\n"),aStatus.iServerStatus); |
|
216 iConsole->Printf(_L("Client Supply Status Option = %d\n"),aStatus.iClientStatus); |
|
217 } |
|
218 } |
|
219 |
|
220 void CTinyTelnet::ProcessKeyPress(TChar aChar) |
|
221 { |
|
222 if (aChar != EKeyEscape) |
|
223 { |
|
224 // Send input Character to echo host |
|
225 if(Write(aChar) != KErrNone) |
|
226 { |
|
227 RequestCharacter(); |
|
228 } |
|
229 else |
|
230 { |
|
231 if(iLocalEcho) |
|
232 iConsole->Printf(_L("%C"), TUint(aChar)); |
|
233 } |
|
234 } |
|
235 else |
|
236 { |
|
237 if(DoCommand()) |
|
238 RequestCharacter(); |
|
239 } |
|
240 } |
|
241 |
|
242 TBool CTinyTelnet::DoCommand() |
|
243 // Handle command strings from the user |
|
244 // Demo only |
|
245 { |
|
246 iCommandLine->Edit(_L("\nTinyTelnet>"), &iCommand); |
|
247 |
|
248 // Seperate Command from Command Arguments. |
|
249 TInt commandEnd; |
|
250 TBuf<80> commandArgs; |
|
251 TBool ret = TRUE; |
|
252 |
|
253 iCommand.TrimAll(); // Remove leading/trailing/double white spaces |
|
254 |
|
255 commandEnd = iCommand.Locate(' '); |
|
256 |
|
257 if ( (commandEnd != iCommand.Length()) && (commandEnd != KErrNotFound) ) |
|
258 { |
|
259 commandArgs = iCommand.Mid(commandEnd+1); |
|
260 iCommand.SetLength(commandEnd); |
|
261 } |
|
262 |
|
263 if(iCommand.Length()==0) |
|
264 Cancel(); // do nothing |
|
265 else if ( iCommand.MatchF(_L("open")) == 0 ) |
|
266 // Attempt to open a telnet session |
|
267 Open(commandArgs); |
|
268 else if ( iCommand.MatchF(_L("status")) == 0 ) |
|
269 { |
|
270 // Display the state of the Telnet RFC options |
|
271 DisplayOptionStates(); |
|
272 } |
|
273 else if ( iCommand.MatchF(_L("openip")) == 0 ) |
|
274 // Other open |
|
275 OpenIP(commandArgs); |
|
276 else if ( iCommand.MatchF(_L("close")) == 0 ) |
|
277 // Close a connection |
|
278 Close(commandArgs); |
|
279 else if ( iCommand.MatchF(_L("help")) == 0 ) |
|
280 Help(commandArgs); |
|
281 else if ( iCommand.MatchF(_L("echo")) == 0 ) |
|
282 { |
|
283 // Toggle local echo |
|
284 LocalEcho(commandArgs); |
|
285 (iConfig.iServerEcho == TRUE) ? (iConfig.iServerEcho = FALSE) : (iConfig.iServerEcho = TRUE); |
|
286 iTelnetSession->DoModifyConfig(iConfig); |
|
287 } |
|
288 else if ( iCommand.MatchF(_L("Logout")) == 0 ) |
|
289 // Force Telnet level logout to the host ,host could refuse |
|
290 iTelnetSession->DoForceLogout(); |
|
291 else if ( iCommand.MatchF(_L("AllowLogout")) == 0 ) |
|
292 // Demo only Toggle allow server to logout option |
|
293 { |
|
294 (iConfig.iAllowLogout == TRUE) ? (iConfig.iAllowLogout = FALSE) : (iConfig.iAllowLogout = TRUE); |
|
295 iTelnetSession->DoModifyConfig(iConfig); |
|
296 } |
|
297 else if ( iCommand.MatchF(_L("Window")) == 0) |
|
298 // Demo only, changes the window size |
|
299 { |
|
300 iConfig.iWindowSize.x = 60; |
|
301 iConfig.iWindowSize.y = 20; |
|
302 iTelnetSession->DoModifyConfig(iConfig); |
|
303 } |
|
304 else if ( iCommand.MatchF(_L("Speed")) == 0) |
|
305 // Demo only, sets the speed |
|
306 { |
|
307 iConfig.iTermSpeed = _L8("9600"); |
|
308 iTelnetSession->DoModifyConfig(iConfig); |
|
309 } |
|
310 else if ( iCommand.MatchF(_L("Type")) == 0) |
|
311 // Demo only, changes the terminal type |
|
312 // See API document implementation of terminal type configuration |
|
313 { |
|
314 iConfig.iTermType = _L8("vt100"); |
|
315 iTelnetSession->DoModifyConfig(iConfig); |
|
316 } |
|
317 |
|
318 else if(iCommand.MatchF(_L("exit")) == 0) |
|
319 { |
|
320 // Clean exit, all destructors called |
|
321 ret = FALSE; |
|
322 CActiveScheduler::Stop(); |
|
323 } |
|
324 else |
|
325 { |
|
326 iConsole->Printf(_L("command = %S.\n"),&iCommand); |
|
327 iConsole->Printf(_L("unknown command\n")); |
|
328 } |
|
329 return ret; |
|
330 } |
|
331 |
|
332 void CTinyTelnet::DoCancel() |
|
333 { |
|
334 |
|
335 } |
|
336 |
|
337 void CTinyTelnet::Open(TDesC& aCommandArg) |
|
338 { |
|
339 TInt err; |
|
340 iCommandArg = aCommandArg; |
|
341 err = iTelnetSession->Connect(iCommandArg); |
|
342 if(err != KErrNone) |
|
343 iState = EConnecting; |
|
344 iConsole->Printf(_L("Connect returned - %d\n"), err); |
|
345 } |
|
346 |
|
347 void CTinyTelnet::Help(TDesC& /*aCommandArg*/) |
|
348 { |
|
349 iConsole->Printf(_L("\nHelp\n")); |
|
350 iConsole->Printf(_L("----\n\n")); |
|
351 iConsole->Printf(_L(" <esc> - command prompt\n")); |
|
352 iConsole->Printf(_L(" open <server> - connect to server on telnet port 23\n")); |
|
353 iConsole->Printf(_L(" openip <aa.bb.cc.dd> - connect to server on telnet port 23\n")); |
|
354 iConsole->Printf(_L(" close - disconnect connection\n")); |
|
355 iConsole->Printf(_L(" echo - toggle local echo on/off\n")); |
|
356 iConsole->Printf(_L(" status - print option status\n\n")); |
|
357 } |
|
358 |
|
359 void CTinyTelnet::LocalEcho(TDesC& /*aCommandArg*/) |
|
360 { |
|
361 iLocalEcho = (!iLocalEcho); |
|
362 } |
|
363 |
|
364 void CTinyTelnet::Logout(TDesC& /*aCommandArg*/) |
|
365 { |
|
366 iTelnetSession->DoForceLogout(); |
|
367 } |
|
368 |
|
369 void CTinyTelnet::OpenIP(TDesC& aCommandArg) |
|
370 { |
|
371 TInt err; |
|
372 iAddress.Input(aCommandArg); // Accepts a, a.b, a.b.c, a.b.c.d or 0xaabbccdd |
|
373 err = iTelnetSession->Connect(iAddress); |
|
374 iConsole->Printf(_L("Connect returned - %d\n"), err); |
|
375 } |
|
376 |
|
377 void CTinyTelnet::Read() |
|
378 { |
|
379 iTelnetSession->Read(); |
|
380 } |
|
381 |
|
382 |
|
383 TInt CTinyTelnet::Write(TChar aChar) |
|
384 // Write characters to the Server |
|
385 // For Demo, we are trapping :- |
|
386 // CTRL+A AO (Abort Output) |
|
387 // CTRL+B AYT (Are You There) |
|
388 // CTRL+C IP (Interrupt Process) |
|
389 // CTRL+D EC (Erase Character, NVT only) |
|
390 // CTRL+E EL (Erase Line, NVT only) |
|
391 // CTRL+F BRK (Break) |
|
392 { |
|
393 |
|
394 TInt ret = KErrNone; |
|
395 TTelnetUserControl code; |
|
396 if (iState==EConnected) |
|
397 { |
|
398 TBuf8<10> buffer; |
|
399 buffer.SetLength(0); |
|
400 |
|
401 if(aChar == 1) |
|
402 { |
|
403 // ABORT OUTPUT |
|
404 code = EAo; |
|
405 ret = iTelnetSession->Write(code); |
|
406 } |
|
407 else if(aChar == 2) |
|
408 { |
|
409 // ARE YOU THERE |
|
410 code = EAyt; |
|
411 ret = iTelnetSession->Write(code); |
|
412 } |
|
413 else if(aChar == 3) |
|
414 { |
|
415 // INTERRUPT PROCESS |
|
416 code = EIp; |
|
417 ret = iTelnetSession->Write(code); |
|
418 } |
|
419 else if(aChar == 4) |
|
420 { |
|
421 // ERASE CHARACTER |
|
422 code = EEc; |
|
423 ret = iTelnetSession->Write(code); |
|
424 } |
|
425 else if(aChar == 5) |
|
426 { |
|
427 // ERASE LINE |
|
428 code = EEl; |
|
429 ret = iTelnetSession->Write(code); |
|
430 } |
|
431 else if(aChar == 6) |
|
432 { |
|
433 // BREAK |
|
434 code = EBrk; |
|
435 ret = iTelnetSession->Write(code); |
|
436 } |
|
437 else |
|
438 { |
|
439 buffer.Append(aChar); |
|
440 ret = iTelnetSession->Write(buffer); |
|
441 } |
|
442 |
|
443 |
|
444 //iConsole->Printf(_L("Write returned - (%d)\n"), err); |
|
445 } |
|
446 else |
|
447 { |
|
448 ret = KErrDisconnected; |
|
449 iConsole->Printf(_L("Not connected [write failed]\n")); |
|
450 } |
|
451 return ret; |
|
452 } |
|
453 |
|
454 void CTinyTelnet::Close(TDesC& /*aCommandArg*/) |
|
455 { |
|
456 TInt err; |
|
457 err = iTelnetSession->Disconnect(); |
|
458 iConsole->Printf(_L("Disconnect returned - %d\n"), err); |
|
459 } |
|
460 |
|
461 |
|
462 // |
|
463 // CActiveConsole Implementation |
|
464 // |
|
465 void CActiveConsole::ConstructL(CConsoleBase* aConsole) |
|
466 { |
|
467 iConsole = aConsole; |
|
468 CActiveScheduler::Add(this); |
|
469 } |
|
470 |
|
471 CActiveConsole::~CActiveConsole() |
|
472 { |
|
473 Cancel(); |
|
474 } |
|
475 |
|
476 void CActiveConsole::RequestCharacter() |
|
477 { |
|
478 __ASSERT_DEBUG(!IsActive(), User::Panic(_L("CActiveConsole::RequestCharacter()"), KRequestPending)); |
|
479 iConsole->Read(iStatus); |
|
480 SetActive(); |
|
481 } |
|
482 |
|
483 void CActiveConsole::RunL() |
|
484 { |
|
485 ProcessKeyPress(TChar(iConsole->KeyCode())); |
|
486 } |
|
487 |
|
488 void CActiveConsole::DoCancel() |
|
489 { |
|
490 iConsole->ReadCancel(); |
|
491 } |