Msrp/MsrpServer/src/CMSRPMsgParser.cpp
author Petteri Saari <petteri.saari@digia.com>
Thu, 02 Dec 2010 15:23:48 +0200
branchMSRP_FrameWork
changeset 60 7634585a4347
parent 58 cdb720e67852
permissions -rw-r--r--
This release addresses the following: - Multiple concurrent file transfer bug fixes. i.e. one device is concurrently receiving multiple files from multiple devices

/*
* 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"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html."
* Initial Contributors:
* Nokia Corporation - initial contribution.
* Contributors:
*
* Description:
* MSRP Implementation
*
*/

// INCLUDES

// CLASS HEADER
#include "CMSRPMsgParser.h"
#include "MSRPCommon.h"

#include "CMSRPMessage.h"
#include "CMSRPToPathHeader.h"

// -----------------------------------------------------------------------------
// CMSRPMsgParser::NewL
// Static constructor
// -----------------------------------------------------------------------------
//
/*static*/CMSRPMsgParser* CMSRPMsgParser::NewL(MMSRPParserObserver& aConnection)
    {
    MSRPLOG( "CMSRPMsgParser::NewL enter" )
    CMSRPMsgParser* self = new (ELeave) CMSRPMsgParser(aConnection );
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    MSRPLOG( "CMSRPMsgParser::NewL exit" )
    return self;
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::CMSRPMsgParser
// Constructor
// -----------------------------------------------------------------------------
//
CMSRPMsgParser::CMSRPMsgParser(MMSRPParserObserver& aConnection)        
    : iConnection( aConnection )
    {  
    
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::~CMSRPMsgParser
// Destructor
// -----------------------------------------------------------------------------
//
CMSRPMsgParser::~CMSRPMsgParser()
    {
    MSRPLOG( "CMSRPMsgParser::~CMSRPMsgParser enter" )
    delete iLocalBuf;
    delete iEndToken;
    delete iMessage;
    iParseBuffers.ResetAndDestroy();
    iParseBuffers.Close();    
    iIncomingMessageChunks.ResetAndDestroy();
    iIncomingMessageChunks.Close();
    MSRPLOG( "CMSRPMsgParser::~CMSRPMsgParser exit" )
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::ConstructL
// 2nd phase constructor
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::ConstructL()
    {
    iState = ETitleLine;
    //to avoid leak on newl leave
    RMsrpBuf buf(iBufPool.ProvideBufferL());
    iLocalBuf = new (ELeave) RMsrpBuf(buf);
    //iLocalBuf = new (ELeave) RMsrpBuf(iBufPool.ProvideBufferL());
    iEndToken = HBufC8::NewL(KMSRPEndTokenMax);   
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::ParseL
// -----------------------------------------------------------------------------
//
TBool CMSRPMsgParser::ParseL()
    {
    TMatchType match = EFullMatch;
    TBool ret = TRUE;
    iByteRangeHeaderFound = EFalse;

    /*parse until a parse element spans buffers. 
      if parse element completes exactly at buffer boundaries,
      might end up parsing greater than bufsize+1_element in one runl. 
      to avoid, use transitioned flag (set in handle full match)*/
    while (match == EFullMatch) 
    //while (ret == TRUE)/*parse all parseable data*/
        {    
        MSRPLOG2( "CMSRPMsgParser::ParseL enter,count= %d", iParseBuffers.Count() )    
        MSRPLOG2( "CMSRPMsgParser::ParseL enter,state = %d", iState )    
        if(!iParseBuffers.Count())
		{
			MSRPLOG( "CMSRPMsgParser::ParseL exit" ) 
            return FALSE;
		}
                               
        TPtrC8 token(KCRAndLF());        
        if (iState == EBody)
            {
            token.Set(iEndToken->Des());                
            }   
        
        TInt matchPos( 0 );
        #ifdef _DEBUG
        TBuf<100> koe;
        koe.Copy( iParseBuffers[0]->Ptr().Left( 100 ) );
        MSRPLOG2( "ST=%S", &koe )    
        koe.Copy( iParseBuffers[0]->Ptr().Right( 100 ) );
        MSRPLOG2( "ST=%S", &koe )
        #endif
        match = FindToken(iParseBuffers[0]->Ptr(),token,matchPos);    
        if(match == EFullMatch)
            {
            ret = HandleFullMatchL(token, matchPos);
            }
        else if (match == EPartialMatch)
            {
            ret = HandlePartialMatchL(token, matchPos);    
            }
        else //if (match == ENoMatch)        
            {              
            ret = HandleNoMatchL(token, matchPos);
            }
        }
    MSRPLOG( "CMSRPMsgParser::ParseL exit" )
    return ret;
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleFullMatchL
// -----------------------------------------------------------------------------
//
TBool CMSRPMsgParser::HandleFullMatchL(TPtrC8& aToken, TInt aMatchPos, TBool aCopyToLocal)
    {
    MSRPLOG( "CMSRPMsgParser::HandleFullMatchL enter" )
    
    TPtrC8 buf = iParseBuffers[0]->Ptr().Left(aMatchPos + aToken.Length());
    if(aCopyToLocal)
        {        
        iLocalBuf->Append(buf);
        }
    else
        {
        HandleStateL(buf, aMatchPos);
        }
    
    if((aMatchPos + aToken.Length()) != iParseBuffers[0]->Ptr().Length())
        {
        iParseBuffers[0]->MsrpMidTPtr(aMatchPos + aToken.Length());
        }
    else
        {
        //transitioned
        RMsrpBuf* headBuf = iParseBuffers[0];
        iParseBuffers.Remove(0);
        delete headBuf;
        if(!iParseBuffers.Count())
            return FALSE;
        }
    MSRPLOG( "CMSRPMsgParser::HandleFullMatchL exit" )
    return TRUE;
    }
    
    

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandlePartialMatchL
// -----------------------------------------------------------------------------
//
TBool CMSRPMsgParser::HandlePartialMatchL(TPtrC8& aToken, TInt aCurBufMatchPos)
    {
    MSRPLOG( "CMSRPMsgParser::HandlePartialMatchL enter" )
    TBool ret = TRUE;
    TInt matchTokenLen = iParseBuffers[0]->Ptr().Length()- aCurBufMatchPos;
    TPtrC8 matchToken = aToken.Left(matchTokenLen);
    TPtrC8 remainingToken = aToken.Mid(matchTokenLen);
    TPtrC8 emptyToken;
    
    if(iParseBuffers.Count() < 2)
        {
        if (iState == EBody && aCurBufMatchPos)
            //if some bytes to return in body, return now (xcluding token part) rather than parse again 
            {            
            ret = HandleFullMatchL(emptyToken, aCurBufMatchPos);//parse true return nxt parse false
            }
        return FALSE;//buffer count greater than 0 but content size smaller than complete lexical element  
        }
    
    //Look to complete token
    TInt nxtBufMatchPos;
    TMatchType match;                      
    TPtrC8 headOfNxtBuf = iParseBuffers[1]->Ptr().Left(remainingToken.Length());                    
    match = FindToken(headOfNxtBuf, remainingToken, nxtBufMatchPos);                       
    
    if(nxtBufMatchPos!=0) //nxt buf does not complete token
        {
        if (iState != EBody)
            {
            User::LeaveIfError(KErrCorrupt);
            }
        //false partial alarm for body, dont retain token part
        //need to update curbuf as false tokenpart also needs to be returned
        aCurBufMatchPos += matchToken.Length();
        //ret = HandleFullMatchL(matchToken, aCurBufMatchPos);//parse true return true
        ret = HandleFullMatchL(emptyToken, aCurBufMatchPos);
        }
    else
        {
        if(match == EPartialMatch) //completes part token but bytes insufficient
            {
            if (iState == EBody && aCurBufMatchPos)
                {
                ret = HandleFullMatchL(emptyToken, aCurBufMatchPos);//parse true ret false                                   
                }            
            return FALSE;
            }
        else //complete token
            {  
            TBool addToLocal = FALSE;
            if(iState != EBody)
                {
                addToLocal = TRUE;                
                }

            ret = HandleFullMatchL(matchToken, aCurBufMatchPos, addToLocal);
            ret = HandleFullMatchL(remainingToken, nxtBufMatchPos, addToLocal);//if token.length() and matches state token upto length, transition state
            //ret cud be false, if nxtbuf exactly completes token

            if(addToLocal == TRUE)
                {
                HandleStateL(*iLocalBuf, aCurBufMatchPos+nxtBufMatchPos);//nxtBuf==0, just token
                iLocalBuf->Zero();
                }            
            }
        }
    MSRPLOG( "CMSRPMsgParser::HandlePartialMatchL exit" )
    return ret;
    }



// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleNoMatchL
// -----------------------------------------------------------------------------
//
TBool CMSRPMsgParser::HandleNoMatchL(TPtrC8& aToken, TInt aCurBufMatchPos)
    {
    MSRPLOG( "CMSRPMsgParser::HandleNoMatchL enter" )

    TPtrC8 emptyToken;    
    TBool ret = FALSE;
    
    aCurBufMatchPos = iParseBuffers[0]->Ptr().Length();
    
    if (iState == EBody /*&& aCurBufMatchPos*/)
        {        
        ret = HandleFullMatchL(emptyToken, aCurBufMatchPos);        
        }        
    else if(iParseBuffers.Count() >= 2)
        {
        //if header find token in nxt buf
        TInt nxtBufMatchPos;
        TMatchType match;                      
        match = FindToken(iParseBuffers[1]->Ptr(),aToken,nxtBufMatchPos);
        
        if(match == EFullMatch)
            {       
            ret = HandleFullMatchL(emptyToken, aCurBufMatchPos, TRUE);
            ret = HandleFullMatchL(aToken, nxtBufMatchPos, TRUE);
            HandleStateL(*iLocalBuf, aCurBufMatchPos+nxtBufMatchPos);
            iLocalBuf->Zero();
            }
        else if (iParseBuffers.Count()>2)
            {
            User::LeaveIfError(KErrCorrupt);        
            }
        //else count==2, bytes insufficient in nxt buf, return false        
        }
    MSRPLOG( "CMSRPMsgParser::HandleNoMatchL exit" )
    return ret;
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleStateL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::HandleStateL(const TDesC8& aString, TInt aMatchPos)
    {
    MSRPLOG( "CMSRPMsgParser::HandleStateL enter" )
    switch(iState)
         {
         case ETitleLine:
             HandleTitleLineL(aString, aMatchPos);             
             break;
         
         case EToPath:
         case EFromPath:    
         //case EMandatoryHeader:
             HandleHeaderL(aString, aMatchPos);            
             break;
                          
         case EOptionalHeaders:
             HandleOptionalHeaderL(aString, aMatchPos);
             break;
                                      
         case EExtraCRLF:
             HandleXtraCrlfL(aString, aMatchPos);
             break;
             
         case EBody:
             HandleBodyL(aString, aMatchPos);
             break;             
             
         case EEndofEndLine:
             HandleEndofEndLineL(aString, aMatchPos);
             break;
                          
         default:
             User::LeaveIfError(KErrUnknown);
             break;        
         }   
    MSRPLOG( "CMSRPMsgParser::HandleStateL exit" )
    }


// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleTitleLineL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::HandleTitleLineL(const TDesC8& aString, TInt /*aMatchPos*/)
    {
    MSRPLOG( "CMSRPMsgParser::HandleTitleLineL enter" )
    
    TPtrC8 msrp(aString.Left(KMSRP().Length()));
    if(msrp.Compare(KMSRP()))
        User::LeaveIfError(KErrCorrupt);
    if(aString[KMSRP().Length()] != ' ')
        User::LeaveIfError(KErrCorrupt);
    
    TPtrC8 trans_id = aString.Mid(KMSRP().Length()+1);    
    TInt pos = trans_id.Locate(MSRP_SPACE);
    /*if(pos == KErrNotFound)
        User::LeaveIfError(KErrCorrupt);*/    
    if (pos < KMSRPIDLenMin || pos > KMSRPIDLenMax)
        User::LeaveIfError(KErrCorrupt);           
    trans_id.Set(trans_id.Left(pos));
    
    TPtr8 ptr = iEndToken->Des();
    ptr.Zero();
    ptr.Append(KCRAndLF);
    ptr.Append(KDashLine());
    ptr.Append(trans_id);
    
    TPtrC8 method = aString.Mid(KMSRP().Length()+1+trans_id.Length()+1);
    pos = method.Locate(MSRP_SPACE);
    
    if(pos == KErrNotFound)
        {
        pos = method.Locate(MSRP_CARRIAGE);        
    
        if(pos == KErrNotFound)
            User::LeaveIfError(KErrCorrupt);
        
        method.Set(method.Left(pos));
                
        delete iMessage;
        iMessage = NULL;
         if (!method.Compare(KMSRPSend()))
             {
             iMessage = CMSRPMessageHandler::NewL(MMSRPIncomingMessage::EMSRPMessage);
             MSRPLOG2( "CMSRPMsgParser::HandleTitleLineL new message = %d", iMessage )
             }
         else if ( !method.Compare( KMSRPReport() ) )
             {
             iMessage = CMSRPMessageHandler::NewL( MMSRPIncomingMessage::EMSRPReport );
             MSRPLOG2( "CMSRPMsgParser::HandleTitleLineL new report = %d", iMessage )
             }
         else //extn
             {
             iMessage = CMSRPMessageHandler::NewL(MMSRPIncomingMessage::EMSRPNotDefined);
             MSRPLOG2( "CMSRPMsgParser::HandleTitleLineL new not defined = %d", iMessage )
             }        
        }
    else //response
        {
        TPtrC8 null;
        method.Set(method.Left(pos));
        delete iMessage;
        iMessage = NULL;
        iMessage = CMSRPMessageHandler::NewL(MMSRPIncomingMessage::EMSRPResponse);
        MSRPLOG2( "CMSRPMsgParser::HandleTitleLineL new response = %d", iMessage )
        iMessage->SetStatusOfResponseL(method, null);
        }    
    iMessage->SetTransactionId(trans_id);
    iState = EToPath;    
    MSRPLOG( "CMSRPMsgParser::HandleTitleLineL exit" )
    }

#if 0
// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleTitleLineL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::HandleTitleLineL(const TDesC8& aString, TInt /*aMatchPos*/)
    {
    MSRPLOG( "CMSRPMsgParser::HandleTitleLineL enter" )
    TLex8 lex(aString);

    //MSRP
    lex.Mark();
    lex.SkipCharacters();
    if(lex.TokenLength() != 4)
        {   
        User::LeaveIfError(KErrCorrupt);
        }    
    TPtrC8 first_token = lex.MarkedToken();        
    if (first_token.Compare(KMSRP()))
        {
        User::LeaveIfError(KErrCorrupt);
        }
    
    //SP
    if(lex.Peek() != MSRP_SPACE)
    {
    User::LeaveIfError(KErrCorrupt);
    }
    lex.Inc();
    
    //trans-id
    lex.Mark();
    lex.SkipCharacters();    
    if (lex.TokenLength() < KMSRPIDLenMin || lex.TokenLength() > KMSRPIDLenMax)
        {
        User::LeaveIfError(KErrCorrupt);
        }
    
    //SP
    if(lex.Peek() != MSRP_SPACE)
    {
    User::LeaveIfError(KErrCorrupt);
    }
    lex.Inc();
    
    TPtrC8 trans_id = lex.MarkedToken();
    TPtr8 ptr = iEndToken->Des();
    ptr.Zero();
    ptr.Append(kEndMarker());
    ptr.Append(trans_id);
    
    //method
    lex.Mark();
    lex.SkipCharacters();
    if(lex.TokenLength() != 0)
        {   
        User::LeaveIfError(KErrCorrupt);
        }      
    TPtrC8 method = lex.MarkedToken();      
    
    //create msg
    //set trans_id
    if (!method.Compare(KMSRPSend()))
        {
        //type = ESend        
        //set type
        }
    else if (!method.Compare(KMSRPReport()))
        {
        //type = EReport        
        //set type
        }
    else //if 3 digit string
        { 
        //type = EResponse
        //set type
        //set status code
        
        //remaining SP comment\r\n
        /*ignore comment*/
                     
        }
    //else extn method
    
    //remaining \r\n
    //TODO: comment, extn method and check remaining bytes is as xpected
        
    iState = EToPath;
    
    MSRPLOG( "CMSRPMsgParser::HandleTitleLineL exit" )
    }
#endif

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleHeaderL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::HandleHeaderL(const TDesC8& aString, TInt /*aMatchPos*/)
    {
    MSRPLOG( "CMSRPMsgParser::HandleHeaderL enter" )
    TInt pos = aString.Locate(MSRP_COLON);
    if(pos == KErrNotFound)
        User::LeaveIfError(KErrCorrupt);
    
    TPtrC8 header_name = aString.Left(pos);
    TUint8 nxtChar = aString[pos+1];
       
    if(nxtChar != MSRP_SPACE)
        User::LeaveIfError(KErrCorrupt);
    
    TPtrC8 header_val = aString.Mid(pos+2); 
    header_val.Set(header_val.Left(header_val.Length()-2));
    
    if(!header_val.Length())
        User::LeaveIfError(KErrCorrupt);

    MMSRPMessageHandler::TMsrpHeaderType headerType = MMSRPMessageHandler::EHeaderUnknown;
    if(iState == EToPath)
        {        
        if(header_name.Compare(KMSRPToPath()))
            User::LeaveIfError(KErrCorrupt);
        headerType = MMSRPMessageHandler::EToPath;
        iState = EFromPath;
        }
    else if(iState == EFromPath)
        {
        headerType = MMSRPMessageHandler::EFromPath;
        if(header_name.Compare(KMSRPFromPath()))
            User::LeaveIfError(KErrCorrupt);  
        iState = EOptionalHeaders;
        }
    else //find header id
        {
        if(!header_name.Compare(KMSRPMessageID()))
            {            
            headerType = MMSRPMessageHandler::EMessageId;
            }
        else if(!header_name.Compare(KMSRPByteRange()))
            {
            iByteRangeHeaderFound = ETrue;
            headerType = MMSRPMessageHandler::EByteRange;
            }
        else if(!header_name.Compare(KMSRPSuccessReport()))
            {
            headerType = MMSRPMessageHandler::ESuccessReport;
            }            
        else if(!header_name.Compare(KMSRPFailureReport()))
            {
            headerType = MMSRPMessageHandler::EFailureReport;
            }            
        else if(!header_name.Compare(KMSRPStatus()))
            {
            headerType = MMSRPMessageHandler::EStatus;
            }
        else if(!header_name.Compare(KMSRPContentType()))
            {
            headerType = MMSRPMessageHandler::EContentType;
            iState = EExtraCRLF;             
            }           
        }      
    
    //message->add_header
    TPtrC8 fullHeader(aString);
    iMessage->AddHeaderL(headerType, header_val, fullHeader);
    if ( headerType == MMSRPMessageHandler::EMessageId )
        {
        // let's check if this message chunk belong to one
        // of the chunks already received. If so, combine
        // the messages
        CheckMessageChunkL( );
        }
    //TODO: //only for to-path from-path add_header error
    //switch iState = EBody, mode = EError //essentially start looking for end token
    //if mode is error don't issue callbacks, on transition from EndofEndLine,
    //delete message and switch to normal mode
    
    MSRPLOG( "CMSRPMsgParser::HandleHeaderL exit" )
        
    }
    
// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleOptionalHeaderL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::CheckMessageChunkL( )
    {
    MSRPLOG( "-> CMSRPMsgParser::HandleHeaderL" )
    for ( TInt i = 0; i < iIncomingMessageChunks.Count(); i++ )
        {
        if ( iMessage->CheckMessageChunkL( *iIncomingMessageChunks[ i ] ) )
            {
            delete iMessage;
            iMessage = iIncomingMessageChunks[ i ];
            iIncomingMessageChunks.Remove( i );
            break;
            }
        }
    MSRPLOG( "<- CMSRPMsgParser::HandleHeaderL" )
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleOptionalHeaderL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::HandleOptionalHeaderL(const TDesC8& aString, TInt aMatchPos)
    {
    MSRPLOG( "CMSRPMsgParser::HandleOptionalHeaderL enter" )
    TPtrC8 endTokenwoStartCrlf = (*iEndToken).Mid(KCRAndLF().Length()); 
    TPtrC8 fullToken(aString.Left(endTokenwoStartCrlf.Length()));
    if (fullToken.Compare(endTokenwoStartCrlf))
        {
        HandleHeaderL(aString,aMatchPos);
        return;
        }
    //iState = EEndOfEndLine;
    aMatchPos -= fullToken.Length();
    HandleEndofEndLineL(aString.Mid(fullToken.Length()),aMatchPos);
    MSRPLOG( "CMSRPMsgParser::HandleOptionalHeaderL exit" )
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleXtraCrlfL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::HandleXtraCrlfL(const TDesC8& /*aString*/, TInt aMatchPos)
    {
    MSRPLOG( "CMSRPMsgParser::HandleXtraCrlfL enter" )
    if(aMatchPos)
        User::LeaveIfError(KErrCorrupt);
    iState = EBody;
    MSRPLOG( "CMSRPMsgParser::HandleXtraCrlfL exit" )
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleBodyL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::HandleBodyL(const TDesC8& aString, TInt aMatchPos)
    {
    MSRPLOG( "CMSRPMsgParser::HandleBodyL enter" )
    TPtrC8 token = aString.Mid(aMatchPos);
    
    //if(!aString.Length())
     //   return;
    
    if(aMatchPos!=0)
        {
        TPtrC8 content(aString.Left(aMatchPos));
        if ( !iMessage->IsTransmissionTerminated() )
            {
            MSRPLOG2( "CMSRPMsgParser::HandleBodyL instance = %d", iMessage )
            iMessage->AddContentL( content, iByteRangeHeaderFound ); 
            iConnection.ReportReceiveprogressL( iMessage );
            }
        }

    //partial or full match
    if(token.Length())
        {   
        MSRPLOG( "CMSRPMsgParser::HandleBodyL enter partial/token" )
         
        //if(aMatchPos == 0)
            {
            //TPtrC8 firstPart = (*iEndToken).Left(token.Length());
            TPtrC8 lastPart = (*iEndToken).Right(token.Length());
            
            //if(firstPart == lastPart)
            /*Solns: set iFlagFirstPartMatch on first match and then transition                      
              false transition to endline and transition back to body on endline parse error
              add initial \r\n (disallowed in trans_id) to searchEndToken on transition to body - 
              for optional header, token has no init crlf*/                    
            
            
            
            if (!token.Compare(lastPart))
                {
                iState = EEndofEndLine;
                }
            /*else if(!token.Compare(firstPart)); 
            else User::LeaveIfError(KErrCorrupt);*/                                                        
            }
        //else //full token matches
        }
    MSRPLOG( "CMSRPMsgParser::HandleBodyL exit" )
    return; 
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleEndofEndLineL
// -----------------------------------------------------------------------------
//
void CMSRPMsgParser::HandleEndofEndLineL(const TDesC8& aString, TInt aMatchPos)
    {
    MSRPLOG2( "CMSRPMsgParser::HandleEndofEndLineL enter, char = %d", aString[0] )
    if(aMatchPos != 1)
        User::LeaveIfError(KErrCorrupt);
    
    MMSRPMessageHandler::TMsrpMsgEndStatus endType = MMSRPMessageHandler::EMessageEnd;  
    if(aString[0] == MSRP_END)
        endType = MMSRPMessageHandler::EMessageEnd;        
    else if (aString[0] == MSRP_CONTINUE)
        endType = MMSRPMessageHandler::EMessageContinues;
    else if (aString[0] == MSRP_TERMINATE)
        endType = MMSRPMessageHandler::EMessageTerminated;
    else
        User::LeaveIfError(KErrCorrupt);
    
    if ( !iMessage->IsTransmissionTerminated() )
        {
        MSRPLOG2( "CMSRPMsgParser::HandleEndofEndLineL instance = %d", iMessage )
        iMessage->EndOfMessageL( endType );
        TInt status = iConnection.ParseStatusL( iMessage, KErrNone );
        if ( endType == MMSRPMessageHandler::EMessageContinues &&
            status == MMSRPParserObserver::EParseStatusMessageHandled ) 
            {
            iIncomingMessageChunks.AppendL( iMessage );
            }
        else if ( status == MMSRPParserObserver::EParseStatusError )
            {
            delete iMessage;
            iMessage = NULL;
            }
        iMessage = NULL;
        }
        
    iState = ETitleLine;
    MSRPLOG( "CMSRPMsgParser::HandleEndofEndLineL exit" )    
    }


// -----------------------------------------------------------------------------
// CMSRPMsgParser::FindToken
// -----------------------------------------------------------------------------
//
CMSRPMsgParser::TMatchType CMSRPMsgParser::FindToken( const TDesC8& aString, const TDesC8& aToken, TInt& aMatchPos)
    {
    MSRPLOG( "CMSRPMsgParser::FindToken enter" )
    TMatchType ret = ENoMatch;
    aMatchPos = KErrNotFound;
    if(!aString.Length() || !aToken.Length())
        return ret;
    aMatchPos = aString.Find(aToken);
    
    if(aMatchPos == KErrNotFound)
        {
        TUint8 lastChar = aString[aString.Length()-1];
        TPtrC8 tempToken;
        tempToken.Set(aToken);
        
        TInt tokenPos = tempToken.LocateReverse(lastChar);
        while (tokenPos != KErrNotFound)
            {
            TPtrC8 headPartofToken = tempToken.Left(tokenPos+1);
            TPtrC8 tailPartofString = aString.Right(tokenPos+1);
             if(!headPartofToken.Compare(tailPartofString))
                 break;            
             tempToken.Set(tempToken.Left(tokenPos)); //if 0
             tokenPos = tempToken.LocateReverse(lastChar);
            }
        if(tokenPos != KErrNotFound)
            {
            ret = EPartialMatch;
            aMatchPos = aString.Length() - (tokenPos+1);
            }
        return ret;
        }    
    MSRPLOG( "CMSRPMsgParser::FindToken exit" )
    return EFullMatch;    
    }

//test cases
//shyamprasad, prasad, xyz, add, dan, shyamprasad
//pr, prasad

#if 0
// -----------------------------------------------------------------------------
// CMSRPMsgParser::ExecuteStateL
// -----------------------------------------------------------------------------
//
CMSRPMsgParser::TDataCheck CMSRPMsgParser::ExecuteStateL()
    {         
    TDataCheck ret = EWaitForDataPost; 
    
    switch(iState)
        {
        case ETitleLine:
            ret = HandleTitleLineL();
            break;
        
        case EToPath:
        case EFromPath:    
        case EMandatoryHeader:
            ret = HandleMandatoryHeaderL();            
            break;
            
            
        case EOptionalHeaders:
            //ret = HandleOptionalHeaderL();
            break;
            
            
        case EBody:
            
            break;
            
        default:
            User::LeaveIfError(KErrUnknown);
            break;        
        }    
      return ret;     
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleTitleLineL
// -----------------------------------------------------------------------------
//
CMSRPMsgParser::TDataCheck CMSRPMsgParser::HandleTitleLineL()
    {
    TDataCheck ret;
    
    VARS(lex, transitioned, base_offset, lex_bytesdone);
    SET_LEX(lex);
        
    TOKEN(first_token);            
    ret = GetNextToken(lex, transitioned, first_token, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_SPACE);//if transitioned, set mode local, being done above based on local buf length
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
    
    
    if(first_token.iLength == 4)
        {        
        FETCH_TOKENSTRING(first_string, first_token, transitioned);
        if (first_string.Compare(KMSRP()))
            {
            User::LeaveIfError(KErrCorrupt);
            }        
        }        
    else
        {
        User::LeaveIfError(KErrCorrupt);
        }
    
    TOKEN(trans_id);
    ret =  GetNextToken(lex, transitioned, trans_id, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_SPACE);
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
    
    if (trans_id.iLength < KMSRPIDLenMin || trans_id.iLength > KMSRPIDLenMax)
        {
        User::LeaveIfError(KErrCorrupt);
        }
    
    TOKEN(method);
    ret =  GetNextToken(lex, transitioned, method, base_offset, lex_bytesdone);
    FETCH_TOKENSTRING(method_string, method, transitioned);
      
    if (!method_string.Compare(KMSRPSend()))
        {
        RET_CHECK(ret,lex,MSRP_CARRIAGE);
        LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
        //create msg with correct type
        }
    else if (!method_string.Compare(KMSRPReport))
        {
        RET_CHECK(ret,lex,MSRP_CARRIAGE);
        LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
        //create msg with correct type
        }
    else //if 3 digit string
        {        
        RET_CHECK_LENIENT(ret,lex,MSRP_SPACE,val);
        if (val)
            {
            LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
            TOKEN(reason);
            ret =  GetNextToken(lex, transitioned, reason, base_offset, lex_bytesdone);
            }
        RET_CHECK(ret,lex,MSRP_CARRIAGE);
        LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
        //create msg with correct type
        //set status code == method_string
        }
    //else extn method, TODO
    
    //set trans_id
        
    //EOL data sufficiency and increment
    ret = IsDataSufficient(lex, transitioned, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_NEWLINE);
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
             
    STATE_COMPLETE(EToPath, lex_bytesdone);    
    return ret;    
    }


// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleMandatoryHeaderL
// -----------------------------------------------------------------------------
//
CMSRPMsgParser::TDataCheck CMSRPMsgParser::HandleMandatoryHeaderL()
    {
    TDataCheck ret;    
    VARS(lex, transitioned, base_offset, lex_bytesdone);
    SET_LEX(lex);
        
    TOKEN(header);            
    ret = GetNextToken(lex, transitioned, header, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_SPACE);
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
    
    TOKEN(header_val);
    ret =  GetNextToken(lex, transitioned, header_val, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_CARRIAGE);
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);

    //EOL data sufficiency and increment
    ret = IsDataSufficient(lex, transitioned, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_NEWLINE);
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
    
    FETCH_TOKENSTRING(header_string, header, transitioned);
    FETCH_TOKENSTRING(val_string, header_val, transitioned);
    
    //check last char is colon and reduce string len by 1
    //HEADER_CHECK(header_string);
            
    switch (iState)
        {
        case EToPath:
            if (header_string.Compare(KMSRPToPath()))
                {
                User::LeaveIfError(KErrCorrupt);
                }
            //AddHeader callback
            STATE_COMPLETE(EFromPath, lex_bytesdone);            
            break;
            
        case EFromPath:
            if (header_string.Compare(KMSRPFromPath()))
                {
                User::LeaveIfError(KErrCorrupt);
                }               
            //AddHeader callback
            STATE_COMPLETE(EMandatoryHeader, lex_bytesdone); 
            break;
            
        case EMandatoryHeader:
            //Findheaderid and give appropriate callback
            STATE_COMPLETE(EOptionalHeaders, lex_bytesdone);
            break;
            
        default:
            User::LeaveIfError(KErrUnknown);
            break;
        }       
    return ret; 
    }

// -----------------------------------------------------------------------------
// CMSRPMsgParser::HandleOptionalHeaderL
// -----------------------------------------------------------------------------
//
#if 0
CMSRPMsgParser::TDataCheck CMSRPMsgParser::HandleOptionalHeaderL()
    {
    //get first token compare against endline
    //if yes msg done and handover bodiless msg to conn
    //if not, get next token and give header callback
    
    TDataCheck ret;    
    VARS(lex, transitioned, base_offset, lex_bytesdone);
    SET_LEX(lex);
        
    TOKEN(header);            
    ret = GetNextToken(lex, transitioned, header, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_SPACE);
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
    
    TOKEN(header_val);
    ret =  GetNextToken(lex, transitioned, header_val, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_CARRIAGE);
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);

    //EOL data sufficiency and increment
    ret = IsDataSufficient(lex, transitioned, base_offset, lex_bytesdone);
    RET_CHECK(ret,lex,MSRP_NEWLINE);
    LEX_INC_AVAILABLE(lex, lex_bytesdone, transitioned);
    
    FETCH_TOKENSTRING(header_string, header, transitioned);
    FETCH_TOKENSTRING(val_string, header_val, transitioned);
    
    //check last char is colon and reduce string len by 1
    HEADER_CHECK(header_string);
            
    switch (iState)
        {
        case EToPath:
            if (header_string.Compare(KMSRPToPath()))
                {
                User::LeaveIfError(KErrCorrupt);
                }
            //AddHeader callback
            STATE_COMPLETE(EFromPath, lex_bytesdone);            
            break;
            
        case EFromPath:
            if (header_string.Compare(KMSRPFromPath()))
                {
                User::LeaveIfError(KErrCorrupt);
                }               
            //AddHeader callback
            STATE_COMPLETE(EMandatoryHeader, lex_bytesdone); 
            break;
            
        case EMandatoryHeader:
            //Findheaderid and give appropriate callback
            STATE_COMPLETE(EOptionalHeaders, lex_bytesdone);
            break;
            
        default:
            User::LeaveIfError(KErrUnknown);
            break;
        }       
    return ret; 
    }

#endif

    
// -----------------------------------------------------------------------------
// CMSRPMsgParser::GetNextToken
// -----------------------------------------------------------------------------
//
//TBD: convert to macros
CMSRPMsgParser::TDataCheck CMSRPMsgParser::GetNextToken(TLex8& aLex, TBool& aTransitioned, TToken& aToken, TInt& aBaseOffset, TInt& aLexBytesDone)
    {
    TDataCheck ret = EContinueNormal;
    
    aLex.Mark();
    aToken.iOffset += aBaseOffset + aLex.MarkedOffset();
    do
        {
        aLex.SkipCharacters();        
        if (aLex.TokenLength() > 0)
            {    
            aLexBytesDone += aLex.TokenLength();
            aToken.iLength += aLex.TokenLength();
            TPtrC8 tokenString = aLex.MarkedToken();
            if(aTransitioned)
                {
                //TODO: leave or parse error if append not possible 
                iLocalBuf->Ptr().Append(tokenString);
                }                        
            }            
        ret = IsDataSufficient(aLex, aTransitioned, aBaseOffset, aLexBytesDone); 
        //if(ret == EContinueTransitioned) aBytesParsed = 0;        
        } while (ret == EContinueTransitioned);
        
    return ret;
    }


// -----------------------------------------------------------------------------
// CMSRPMsgParser::IsDataSufficient
// not called if in Body, only header data sufficiency check
// -----------------------------------------------------------------------------
//TBD: convert to macro
CMSRPMsgParser::TDataCheck CMSRPMsgParser::IsDataSufficient(TLex8& aLex, TBool& aTransitioned, TInt& aBaseOffset, TInt& aLexBytesDone)
    {
    if(aLex.Peek() == 0)
        {  
        /*iParseBuffers[0] being parsed*/
        aBaseOffset += iParseBuffers[0]->Ptr().Length();
        aLexBytesDone = 0;
        if(aTransitioned)
            {
            delete iParseBuffers[0];
            }
        else
            {
            if (iMode == EQueueBuf)
                {
                /*non collated buffer existence means spanning across buf pools*/  
                if (iParseBuffers.Count() < 2)
                    return EWaitForDataPost; //aLexBytesDone =0, nothing copied to local buf
                else if (iSthgParsed)
                    return EContinueInNextParse; //aLexBytesDone =0
                else
                    iLocalBuf->Ptr().Append(*iParseBuffers[0]);
                }    
            /*in case of localbuf, we are about to begin parsing first buf and copy tokens*/
            aTransitioned = TRUE;
            }
        
#if 0        
        /*for queuebuf avoid copying till bufpool spanning of a parse element can be confirmed*/
        if (iMode == EQueueBuf)
            {
            if (!aTransitioned)
                {
                /*non collated buffer existence means spanning across buf pools*/  
                if (iParseBuffers.Count() < 2)
                    return EWaitForDataPost; //aLexBytesDone =0, nothing copied to local buf
                else if (iSthgParsed)
                    return EContinueInNextParse; //aLexBytesDone =0
                else
                    {                    
                    //copy to local
                    aTransitioned = TRUE;
                    iLocalBuf->Ptr().Append(*iParseBuffers[0]);
                    aBaseOffset += iParseBuffers[0]->Ptr().Length();
                    aLexBytesDone = 0;
                    delete iParseBuffers[0];                    
                    }
                }
            else //once transitioned tokens are being copied,iParseBuffers[0] being parsed, hence no existence check            
                {
                //only free
                aBaseOffset += iParseBuffers[0]->Ptr().Length();
                aLexBytesDone = 0;
                delete iParseBuffers[0];                    
                }            
            }
        else //if (iMode == ELocalBuf)
            {
            if (!aTransitioned)
               {
               /*sthg parsed is always false for local buf*/
               /*also if not transitioned in this pass, means count of buffers in queue is atleast 1*/               
               /*if (iParseBuffers.Count() < 1)
                   return EWaitForDataPost;
               else if (iSthgParsed)
                   return EContinueInNextParse;*/
               //no action  
               aTransitioned = TRUE;
               aBaseOffset += iParseBuffers[0]->Ptr().Length();
               aLexBytesDone = 0;
               }
           else //once transitioned tokens are being copied,iParseBuffers[0] being parsed, hence no existence check
               {
               //only free  
               aBaseOffset += iParseBuffers[0]->Ptr().Length();
               aLexBytesDone = 0;
               //delete iParseBuffers[0];
               }                    
            }
#endif                       
        if(!iParseBuffers.Count())
            return EWaitForDataPost; //aLexBytesDone = 0 //no rbuf to delete
                                                        
        //reassign lex to zeroth
        aLex.Assign(*iParseBuffers[0]);
        
        return EContinueTransitioned;
        }
    return EContinueNormal;
    }
    
#endif