localconnectivityservice/dun/atext/src/DunAtCmdHandler.cpp
changeset 18 6743bfee309e
parent 16 c3bac82c6ce0
child 21 23264c07fd05
--- a/localconnectivityservice/dun/atext/src/DunAtCmdHandler.cpp	Mon May 03 13:21:36 2010 +0300
+++ b/localconnectivityservice/dun/atext/src/DunAtCmdHandler.cpp	Fri May 14 16:44:53 2010 +0300
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
@@ -35,7 +35,8 @@
 #include "DunDownstream.h"
 #include "DunDebug.h"
 
-const TInt8 KDunCancel = 24;
+const TInt8 KDunCancel = 24;  // Used for line editing, cancel character
+const TInt8 KDunEscape = 27;  // Used for editor ending, escape character
 
 // ---------------------------------------------------------------------------
 // Two-phased constructor.
@@ -79,6 +80,8 @@
     Stop();
     // NewL()
     DeletePluginHandlers();
+    delete iCmdEchoer;
+    iCmdEchoer = NULL;
     delete iNvramListen;
     iNvramListen = NULL;
     delete iModeListen;
@@ -145,7 +148,16 @@
     FTRACE(FPrint( _L("CDunAtCmdHandler::ParseCommand()") ));
     FTRACE(FPrint( _L("CDunAtCmdHandler::ParseCommand() received:") ));
     FTRACE(FPrintRaw(aCommand) );
-    iCommand = &aCommand;
+    TBool editorMode = iCmdPusher->EditorMode();
+    if ( editorMode )
+        {
+        // Note: return here with "no partial input" and some error to fool
+        // CDunUpstream into not reissuing the read request.
+        iCmdPusher->IssueRequest( aCommand, EFalse );
+        aPartialInput = EFalse;
+        return KErrGeneral;
+        }
+    iCommand = &aCommand;  // iCommand only for normal mode
     // Manage partial AT command
     TBool needsCarriage = ETrue;
     TBool okToExit = ManagePartialCommand( aCommand, needsCarriage );
@@ -180,7 +192,7 @@
     iDecodeInfo.iFirstDecode = ETrue;
     iDecodeInfo.iDecodeIndex = 0;
     HandleNextDecodedCommand();
-    FTRACE(FPrint( _L("CDunAtCmdHandler::ParseCommand() (not supported) complete") ));
+    FTRACE(FPrint( _L("CDunAtCmdHandler::ParseCommand() complete") ));
     aPartialInput = EFalse;
     return KErrNone;
     }
@@ -210,6 +222,19 @@
     }
 
 // ---------------------------------------------------------------------------
+// Sends a character to be echoed
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CDunAtCmdHandler::SendEchoCharacter( const TDesC8* aInput,
+                                                   MDunAtCmdEchoer* aCallback )
+    {
+    FTRACE(FPrint( _L("CDunAtCmdHandler::SendEchoCharacter()") ));
+    TInt retVal = iCmdEchoer->SendEchoCharacter( aInput, aCallback );
+    FTRACE(FPrint( _L("CDunAtCmdHandler::SendEchoCharacter() complete") ));
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
 // Stops sending of AT command from parse buffer
 // ---------------------------------------------------------------------------
 //
@@ -223,7 +248,12 @@
         return KErrNotReady;
         }
     iCmdPusher->Stop();
-    iHandleState = EDunStateIdle;
+    // The line below is used in the case when this function is called by
+    // CDunUpstream as a result of "data mode ON" change notification.
+    // In this case it is possible that HandleNextDecodedCommand() returns
+    // without resetting the iInputBuffer because of the way it checks the
+    // iHandleState.
+    ManageEndOfCmdHandling( EFalse, ETrue, ETrue );
     FTRACE(FPrint( _L("CDunAtCmdHandler::Stop() complete") ));
     return KErrNone;
     }
@@ -313,28 +343,21 @@
     CreateSpecialCommandsL();
     // Create the plugin handlers
     CreatePluginHandlersL();
+    // Create the echo handler
+    iCmdEchoer = CDunAtCmdEchoer::NewL( iDownstream );
     // Create the listeners
-    CDunAtEcomListen* ecomListen = CDunAtEcomListen::NewLC( &iAtCmdExt, this );
-    CDunAtModeListen* modeListen = CDunAtModeListen::NewLC( &iAtCmdExtCommon,
-                                                           this );
-    CDunAtNvramListen* nvramListen = CDunAtNvramListen::NewLC( &iAtCmdExt,
-                                                               &iAtCmdExtCommon );
+    iEcomListen = CDunAtEcomListen::NewL( &iAtCmdExt, this );
+    iModeListen = CDunAtModeListen::NewL( &iAtCmdExtCommon, this );
+    iNvramListen = CDunAtNvramListen::NewL( &iAtCmdExt, &iAtCmdExtCommon );
+    iAtSpecialCmdHandler = CDunAtSpecialCmdHandler::NewL();
     // Set the default modes (+report) and characters
     GetAndSetDefaultSettingsL();
     // Start listening
-    ecomListen->IssueRequest();
-    modeListen->IssueRequest();
-    nvramListen->IssueRequest();
-    CleanupStack::Pop( nvramListen );
-    CleanupStack::Pop( modeListen );
-    CleanupStack::Pop( ecomListen );
+    iEcomListen->IssueRequest();
+    iModeListen->IssueRequest();
+    iNvramListen->IssueRequest();
     CleanupStack::Pop( &iAtCmdExtCommon );
     CleanupStack::Pop( &iAtCmdExt );
-    iEcomListen = ecomListen;
-    iModeListen = modeListen;
-    iNvramListen = nvramListen;
-    
-    iAtSpecialCmdHandler = CDunAtSpecialCmdHandler::NewL();
     FTRACE(FPrint( _L("CDunAtCmdHandler::ConstructL() complete") ));
     }
 
@@ -356,6 +379,7 @@
     iDecodeInfo.iDecodeIndex = KErrNotFound;
     iDecodeInfo.iPrevChar = 0;
     iDecodeInfo.iPrevExists = EFalse;
+    iEditorModeInfo.iContentFound = EFalse;
     iCmdPusher = NULL;
     iEcomListen = NULL;
     iModeListen = NULL;
@@ -791,6 +815,34 @@
     }
 
 // ---------------------------------------------------------------------------
+// Finds the start of the next command
+// ---------------------------------------------------------------------------
+//
+TInt CDunAtCmdHandler::FindStartOfNextCommand()
+    {
+    FTRACE(FPrint( _L("CDunAtCmdHandler::FindStartOfNextCommand()") ));
+    // Note: here we need to avoid internal recursion when parsing the
+    // multiple IsEndOfCommand() and IsDelimiterCharacter() markers inside the
+    // same upstream block.
+    // Skip all the extra markers except the one we already know to exist.
+    TInt i;
+    TInt startVal = iEndIndex + 1;
+    TInt foundIndex = KErrNotFound;
+    TInt count = iCommand->Length();
+    for ( i=startVal; i<count; i++ )
+        {
+        TChar character = (*iCommand)[i];
+        if ( !(IsEndOfCommand(character)||IsDelimiterCharacter(character)) )
+            {
+            foundIndex = i;
+            break;
+            }
+        }
+    FTRACE(FPrint( _L("CDunAtCmdHandler::FindStartOfNextCommand() complete") ));
+    return foundIndex;
+    }
+
+// ---------------------------------------------------------------------------
 // Manages end of AT command handling
 // ---------------------------------------------------------------------------
 //
@@ -814,23 +866,7 @@
         FTRACE(FPrint( _L("CDunAtCmdHandler::ManageEndOfCmdHandling() (no external) complete") ));
         return;
         }
-    // Note: here we need to avoid internal recursion when parsing the
-    // multiple IsEndOfCommand() and IsDelimiterCharacter() markers inside the
-    // same upstream block.
-    // Skip all the extra markers except the one we already know to exist.
-    TInt i;
-    TInt startVal = iEndIndex + 1;
-    TInt foundIndex = KErrNotFound;
-    TInt count = iCommand->Length();
-    for ( i=startVal; i<count; i++ )
-        {
-        TChar character = (*iCommand)[i];
-        if ( !(IsEndOfCommand(character)||IsDelimiterCharacter(character)) )
-            {
-            foundIndex = i;
-            break;
-            }
-        }
+    TInt foundIndex = FindStartOfNextCommand();
     iUpstream->NotifyAtCmdHandlingEnd( foundIndex );
     FTRACE(FPrint( _L("CDunAtCmdHandler::ManageEndOfCmdHandling() complete") ));
     }
@@ -923,6 +959,7 @@
     FTRACE(FPrint( _L("CDunAtCmdHandler::RestoreOldDecodeInfo()") ));
     if ( aPeek )
         {
+        iEditorModeInfo.iPeekInfo = iDecodeInfo;
         iDecodeInfo = aOldInfo;
         }
     FTRACE(FPrint( _L("CDunAtCmdHandler::RestoreOldDecodeInfo() complete") ));
@@ -1529,6 +1566,65 @@
     }
 
 // ---------------------------------------------------------------------------
+// Manages editor mode reply
+// ---------------------------------------------------------------------------
+//
+TInt CDunAtCmdHandler::ManageEditorModeReply( TBool aStart )
+    {
+    FTRACE(FPrint( _L("CDunAtCmdHandler::ManageEditorModeReply()" ) ));
+    // Two modes possible here:
+    // 1) Sending data directly from DTE to DCE, i.e. no subsequent data in
+    //    the input buffer -> Reissue read request from DTE.
+    // 2) Sending data from input buffer to DCE -> Do not reissue read request
+    //    from DTE: send the data in a loop
+    // In summary: send data byte-by-byte in editor mode until end of input.
+    // When end of input notify CDunUpstream to reissue the read request.
+    TBool nextContentFound = FindNextContent( aStart );
+    if ( !nextContentFound )
+        {
+        iUpstream->NotifyEditorModeReply( aStart );
+        FTRACE(FPrint( _L("CDunAtCmdHandler::NotifyEditorModeReply() complete") ));
+        return KErrNone;
+        }
+    // In block mode end the block mode by sending <ESC> and hope it works.
+    iEscapeBuffer.Zero();
+    iEscapeBuffer.Append( KDunEscape );
+    iCmdPusher->IssueRequest( iEscapeBuffer, EFalse );
+    FTRACE(FPrint( _L("CDunAtCmdHandler::ManageEditorModeReply() complete" ) ));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Finds the next content from the input data
+// ---------------------------------------------------------------------------
+//
+TBool CDunAtCmdHandler::FindNextContent( TBool aStart )
+    {
+    FTRACE(FPrint( _L("CDunAtCmdHandler::FindNextContent()" ) ));
+    if ( !aStart )
+        {
+        FTRACE(FPrint( _L("CDunAtCmdHandler::FindNextContent() (skip) complete" ) ));
+        return iEditorModeInfo.iContentFound;
+        }
+    iEditorModeInfo.iContentFound = EFalse;
+    TInt foundCmdIndex = KErrNotFound;
+    TBool nextContentFound = ExtractNextDecodedCommand( ETrue );  // peek
+    if ( !nextContentFound )
+        {
+        // Check the next subblock
+        foundCmdIndex = FindStartOfNextCommand();
+        }
+    if ( !nextContentFound && foundCmdIndex<0 )
+        {
+        FTRACE(FPrint( _L("CDunAtCmdHandler::FindNextContent() (not found) complete") ));
+        return EFalse;
+        }
+    iEditorModeInfo.iContentFound = ETrue;
+    FTRACE(FPrint( _L("CDunAtCmdHandler::FindNextContent() complete" ) ));
+    return ETrue;
+    }
+
+// ---------------------------------------------------------------------------
 // From class MDunAtCmdPusher.
 // Notifies about end of AT command processing. This is after all reply data
 // for an AT command is multiplexed to the downstream.
@@ -1537,6 +1633,13 @@
 TInt CDunAtCmdHandler::NotifyEndOfProcessing( TInt /*aError*/ )
     {
     FTRACE(FPrint( _L("CDunAtCmdHandler::NotifyEndOfProcessing()" ) ));
+    TBool editorMode = iCmdPusher->EditorMode();
+    if ( editorMode )
+        {
+        ManageEditorModeReply( ETrue );
+        FTRACE(FPrint( _L("CDunAtCmdHandler::NotifyEndOfProcessing() (editor) complete" ) ));
+        return KErrNone;
+        }
     HandleNextDecodedCommand();
     FTRACE(FPrint( _L("CDunAtCmdHandler::NotifyEndOfProcessing() complete" ) ));
     return KErrNone;
@@ -1571,6 +1674,19 @@
     }
 
 // ---------------------------------------------------------------------------
+// From class MDunAtCmdPusher.
+// Notifies about editor mode reply
+// ---------------------------------------------------------------------------
+//
+TInt CDunAtCmdHandler::NotifyEditorModeReply()
+    {
+    FTRACE(FPrint( _L("CDunAtCmdHandler::NotifyEditorModeReply()") ));
+    TInt retVal = ManageEditorModeReply( EFalse );
+    FTRACE(FPrint( _L("CDunAtCmdHandler::NotifyEditorModeReply() complete") ));
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
 // From class MDunAtEcomListen.
 // Notifies about new plugin installation
 // ---------------------------------------------------------------------------