telutils/phoneparser/src/CPhoneGsmSsParser.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 19 Mar 2010 09:40:14 +0200
changeset 12 ae8abd0db65c
parent 0 ff3b6d0fd310
child 13 e32024264ebb
permissions -rw-r--r--
Revision: 201007 Kit: 201011

/*
* Copyright (c) 2002 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:  Principal parser for supplementary service procedures.
*
*/


// INCLUDE FILES
#include    <bldvariant.hrh>
#include    <featmgr.h>
#include    <nwdefs.h>

#include    "CPhoneGsmSsParser.h" 
#include    "cphonegsmparserresult.h" 
#include    "phonegsmparser.h" 
#include    "CPhoneGsmOptionContainer.h" 
#include    "CPhoneParserFeatures.h" 

// CONSTANTS

// Granularity of service array
const TInt KPhoneServiceArrayGranularity = 20;

// Activation starts with *. See also registration.
_LIT( KPhoneSsActivation, "*" );

// Deactivation starts with #.
_LIT( KPhoneSsDeactivation, "#" );

// Interrogation starts with *#.
_LIT( KPhoneSsInterrogation, "*#" );

// Registration starts with ** OR *. Case * is handled in the code.
_LIT( KPhoneSsRegistration, "**" );

// Erasure starts with ##.
_LIT( KPhoneSsErasure, "##" );

// It defines characters that can be used in these prefixes (see above).
_LIT( KPhoneSsActionCharacters, "*#" );

// It defines string that ends all ss requests.
_LIT( KPhoneSsEnd, "#" );

// It defines characters that are considered to be digits.
_LIT( KPhoneSsDigits, "1234567890" );

// Asterisk.
const TInt KPhoneSsAsterisk = '*';

// Hash.
const TInt KPhoneSsHash = '#';

// Plus.
const TInt KPhoneSsPlus = '+';

// Remainder: single character
const TInt KPhoneSsRemainderSingle = 1;

// Remainder: still a parameter, but ok ss
const TInt KPhoneSsRemainderMinLength = 2; // something + #

const TInt KPhoneSsPasswordLength = 4; 

// Remainder: passwordk, ok ss
const TInt KPhoneSsRemainderPasswordMinLength = 5; // four digits + #

// Maximum length of directory number.
const TInt KPhoneSsDirectoryNumberMaxLength = 38;
// Maximum length of basic service code.
const TInt KPhoneSsBasicCodeMaxLength = 2;
// Maximum length of group code.
const TInt KPhoneSsGroupCodeMaxLength = 4;
// Maximum length of timer.
const TInt KPhoneSsTimerMaxLength = 2;

// The only acceptable group code (change of barring password)
const TUint KPhoneSsOnlyAllowedGroupCode = 330;

// Pack: shift
const TInt KPhoneGsmPackShift = 8;

// Pack: mask
const TInt KPhoneGsmPackMask = 255;

// -----------------------------------------------------------------------------
// Syntax:
//    
//      SC      Service code
//      A       Activation
//      D       Deactivation
//      I       Interrogation
//      R       Registration
//      E       Erasure
//
//     Text string must contain each of these in the following order
//     "SC A D I R E" (separated by space). Following values correspond
//      
//
//     0 - ENotAllowed       
//     1 - ENoParameters
//     2 - EEmptyOrBasicCode
//     3 - ENumberOptBasicCodeOptTimer
//     4 - ENumberOptBasicCode     
//     5 - EPasswordOptBasicCode
//     6 - EOptGroupCodePasswordNewPasswordNewPassword    
//     7 - EEmptyOrBasicCode2         
// -----------------------------------------------------------------------------
_LIT( KPhoneUidForwardingAllCode,                                   "002 2 2 0 3 2" );
_LIT( KPhoneUidForwardingAllConditionalCode,                        "004 2 2 0 3 2" );
_LIT( KPhoneUidForwardingUnconditionalCode,                         "21  2 2 2 4 2" );
_LIT( KPhoneUidForwardingNoReplyCode,                               "61  2 2 2 3 2" );
_LIT( KPhoneUidForwardingNotReachableCode,                          "62  2 2 2 4 2" );
_LIT( KPhoneUidForwardingBusyCode,                                  "67  2 2 2 4 2" );
_LIT( KPhoneUidBarringAllOutgoingCallsCode,                         "33  5 5 1 0 0" );
_LIT( KPhoneUidBarringAllIncomingCallsCode,                         "35  5 5 1 0 0" );
_LIT( KPhoneUidBarringAllServicesCode,                              "330 0 5 0 0 0" );
_LIT( KPhoneUidBarringAllOutgoingInternationalCallsCode,            "331 5 5 1 0 0" );
_LIT( KPhoneUidBarringAllOutgoingInternationalCallsExceptHomeCode,  "332 5 5 1 0 0" );
_LIT( KPhoneUidBarringAllOutgoingServicesCode,                      "333 0 5 0 0 0" );
_LIT( KPhoneUidBarringAllIncomingCallsWhenRoamingCode,              "351 5 5 1 0 0" );
_LIT( KPhoneUidBarringAllIncomingServicesCode,                      "353 0 5 0 0 0" );
_LIT( KPhoneUidWaitingCode,                                         "43  7 7 7 0 0" );
_LIT( KPhoneUidCallingLineIdentificationPresentationCode,           "30  0 0 1 0 0" );
_LIT( KPhoneUidCallingLineIdentificationRestrictionCode,            "31  0 0 1 0 0" );
_LIT( KPhoneUidConnectedLinePresentationCode,                       "76  0 0 1 0 0" );
_LIT( KPhoneUidConnectedLinePresentationRestrictionCode,            "77  0 0 1 0 0" ); 
_LIT( KPhoneUidPasswordCode,                                        "03  6 0 0 6 0" );
_LIT( KPhoneUidCallingNamePresentationCode,                         "300 0 0 1 0 0" );

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::CPhoneGsmSsParser
// -----------------------------------------------------------------------------
//
CPhoneGsmSsParser::CPhoneGsmSsParser()
    {
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::ConstructL
// -----------------------------------------------------------------------------
//
void CPhoneGsmSsParser::ConstructL()
    {
    iArray = 
        new ( ELeave ) CServiceArray( 
            KPhoneServiceArrayGranularity );

    // Check AddL method for details what these really mean.
    
    // Forwarding
    AddL( KPhoneUidForwardingAllCode, 
        KPhoneUidForwardingAll );
    AddL( KPhoneUidForwardingAllConditionalCode, 
        KPhoneUidForwardingAllConditional );
    AddL( KPhoneUidForwardingUnconditionalCode, 
        KPhoneUidForwardingUnconditional );
    AddL( KPhoneUidForwardingNoReplyCode, 
        KPhoneUidForwardingNoReply );
    AddL( KPhoneUidForwardingNotReachableCode, 
        KPhoneUidForwardingNotReachable );
    AddL( KPhoneUidForwardingBusyCode, 
        KPhoneUidForwardingBusy );

    // Barring
    AddL( KPhoneUidBarringAllOutgoingCallsCode, 
        KPhoneUidBarringAllOutgoingCalls );
    AddL( KPhoneUidBarringAllIncomingCallsCode, 
        KPhoneUidBarringAllIncomingCalls );
    AddL( KPhoneUidBarringAllServicesCode, 
        KPhoneUidBarringAllServices );
    AddL( KPhoneUidBarringAllOutgoingInternationalCallsCode, 
        KPhoneUidBarringAllOutgoingInternationalCalls );
    AddL( KPhoneUidBarringAllOutgoingInternationalCallsExceptHomeCode, 
        KPhoneUidBarringAllOutgoingInternationalCallsExceptHome );
    AddL( KPhoneUidBarringAllOutgoingServicesCode, 
        KPhoneUidBarringAllOutgoingServices );
    AddL( KPhoneUidBarringAllIncomingCallsWhenRoamingCode, 
        KPhoneUidBarringAllIncomingCallsWhenRoaming );
    AddL( KPhoneUidBarringAllIncomingServicesCode, 
        KPhoneUidBarringAllIncomingServices );
    
    // Waiting
    AddL( KPhoneUidWaitingCode, 
        KPhoneUidWaiting );

    // Calling line identification presentation
    AddL( KPhoneUidCallingLineIdentificationPresentationCode, 
        KPhoneUidCallingLineIdentificationPresentation );

    // Calling line identification restriction
    AddL( KPhoneUidCallingLineIdentificationRestrictionCode, 
        KPhoneUidCallingLineIdentificationRestriction );

    // Connected line presentation
    AddL( KPhoneUidConnectedLinePresentationCode, 
        KPhoneUidConnectedLinePresentation );

    // Connected line presentation restriction.
    AddL( KPhoneUidConnectedLinePresentationRestrictionCode, 
        KPhoneUidConnectedLinePresentationRestriction );

    // CNAP.  
    if ( CPhoneParserFeatures::FeatureSupported( KFeatureIdPhoneCnap ) )
        {
        AddL( KPhoneUidCallingNamePresentationCode, 
            KPhoneUidCallingNamePresentation );
        }

    // Password
    AddL( KPhoneUidPasswordCode, 
        KPhoneUidPassword );

    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::NewLC
// -----------------------------------------------------------------------------
//
CPhoneGsmSsParser* CPhoneGsmSsParser::NewLC()
    {
    CPhoneGsmSsParser* self = new ( ELeave ) CPhoneGsmSsParser;
    
    CleanupStack::PushL( self );
    self->ConstructL();
    
    return self;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::~CPhoneGsmSsParser
// -----------------------------------------------------------------------------
//
CPhoneGsmSsParser::~CPhoneGsmSsParser()
    {
    delete iArray;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::ParseL
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::ParseL( 
        const TDesC& aString, 
        CPhoneGsmParserResult& aResult,
        CPhoneGsmOptionContainerBase& aOptions )
    {
    TBool result = EFalse;
    aResult.ClearL();      
// All operations require SEND.
// If VoIP call no action needed here.
    if ( !aOptions.FindOptionStatus( KPhoneOptionSend ) ||
         aOptions.FindOptionStatus( KPhoneOptionVoipCall ) )
        {
        return EFalse;
        }

    TLex input( aString );
    TPtrC action( 
        FindString( 
            input, 
            KPhoneSsActionCharacters() ) );

    // Check if action is proper for service requests.
    TServiceType type = EServiceActivation;
    
    // This variable will indicate if action was ok.
    TBool ok = ETrue;

    // Fill type.
    if ( action == KPhoneSsActivation )
        {
        type = EServiceActivation;
        }
    else if ( action == KPhoneSsDeactivation )
        {
        type = EServiceDeactivation;
        }
    else if ( action == KPhoneSsInterrogation )
        {
        type = EServiceInterrogation;
        }
    else if ( action == KPhoneSsRegistration )
        {
        type = EServiceRegistration;
        }
    else if ( action == KPhoneSsErasure )
        {
        type = EServiceErasure;
        }
    else 
        {
        // Not ok.
        ok = EFalse;
        }

    // Prefix must be one of the service types.
    if ( ok )
        {
        TPtrC serviceCode( FindString( input, KPhoneSsDigits() ) );
        
        // Check that service code is not too long.
        if ( serviceCode.Length() > KPhoneGsmSsServiceCodeMaxLength )
            {
            return EFalse;
            }

        TKeyArrayFix key( _FOFF( TServiceInfo, iCode ), ECmpNormal );
        TServiceInfo info;
        TInt position;       
        info.iCode = serviceCode;

        // Check if the string can be a service request.
        if ( !iArray->FindIsq( info, key, position ) )
            {
            info = iArray->At( position );
            }
        else
            {
            // Not found.
            return EFalse;
            }

        TServiceSyntax syntax = ESyntaxNotAllowed;

        // Take syntax from info record.
        switch ( type )
            {
            case EServiceActivation:
                syntax = info.iActivation;
                break;

            case EServiceDeactivation:
                syntax = info.iDeactivation;
                break;

            case EServiceInterrogation:
                syntax = info.iInterrogation;
                break;

            case EServiceRegistration:
                syntax = info.iRegistration;
                break;

            case EServiceErasure:
                syntax = info.iErasure;
                break;

            default:
                PhoneGsmParser::Panic( PhoneGsmParser::EShouldNeverHappen );
                break;
            }

        TUint data;
        PackData( data, type, syntax );

        aResult.SetUid( info.iUid );
        aResult.SetAuxInformation( data );
        
        // We may have to backtrack in case HandleParametersL fails.
        TLexMark mark;
        input.Mark( mark );

        // First attempt
        result = HandleParametersL( input, aResult, syntax );

        // If action was activation and result was failure, then try registration.
        if ( !result && type == EServiceActivation )
            {
            // Backtrack.
            input.UnGetToMark( mark );

            // Clear previous results & fill information again.

            type = EServiceRegistration;
            syntax = info.iRegistration;
            PackData( data, type, syntax );

            aResult.ClearL();
            aResult.SetUid( info.iUid );
            aResult.SetAuxInformation( data );

            // Try again. If this fails, then it is really failure.
            result = HandleParametersL( input, aResult, syntax );
            }
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::PackData
//
// Combine data to integer.
// -----------------------------------------------------------------------------
//
void CPhoneGsmSsParser::PackData(
        TUint& aResult,
        TServiceType aType,
        TServiceSyntax aSyntax )
    {
    aResult = 
        ( ( ( TUint )aType ) << KPhoneGsmPackShift ) + ( ( TUint )aSyntax );
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::UnpackData
// 
// Take data from integer.
// -----------------------------------------------------------------------------
//
void CPhoneGsmSsParser::UnpackData(
        TUint aData,
        TServiceType& aResultType,
        TServiceSyntax& aResultSyntax )
    {
    aResultSyntax = 
        CPhoneGsmSsParser::TServiceSyntax( aData & KPhoneGsmPackMask );
    aResultType = 
        CPhoneGsmSsParser::TServiceType( 
            ( aData >> KPhoneGsmPackShift ) & 
            KPhoneGsmPackMask );
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleParametersL
//
// Selects correct function by syntax information.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleParametersL( 
        TLex& aInput, 
        CPhoneGsmParserResult& aResult,
        TServiceSyntax aSyntax )
    {
    TBool result = EFalse;

    switch ( aSyntax )
        {
        case ESyntaxNotAllowed:
            result = 
                HandleNotAllowedL( aInput, aResult );
            break;

        case ESyntaxNoParameters:
            result = 
                HandleNoParametersL( aInput, aResult );
            break;

        case ESyntaxEmptyOrBasicCode:
            result = 
                HandleEmptyOrBasicCodeL( aInput, aResult );
            break;
            
        case ESyntaxNumberOptBasicCodeOptTimer:
            result = 
                HandleNumberOptBasicCodeOptTimerL( 
                    aInput, 
                    aResult );
            break;

        case ESyntaxNumberOptBasicCode:
            result = 
                HandleNumberOptBasicCodeL( 
                    aInput, 
                    aResult );
            break;

        case ESyntaxPasswordOptBasicCode:
            result = 
                HandlePasswordOptBasicCodeL( 
                    aInput, 
                    aResult );
            break;
            
        case ESyntaxOptGroupCodePasswordNewPasswordNewPassword:
            result = 
                HandleOptGroupCodePasswordNewPasswordNewPasswordL( 
                    aInput, 
                    aResult );
            break;

        case ESyntaxEmptyOrBasicCode2:
            result = 
                HandleEmptyOrBasicCode2L( 
                    aInput, 
                    aResult );
            break;

        default:
            break;
        }          

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleNotAllowedL
//
// Just clear the result and return that parsing failed.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleNotAllowedL( 
        TLex& /*aInput*/, 
        CPhoneGsmParserResult& aResult )
    {
    aResult.ClearL();
    
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleNoParametersL
//
// Handle no more parameters, only hash 
// as the last character.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleNoParametersL( 
        TLex& aInput, 
        CPhoneGsmParserResult& /*aResult*/ )
    {
    // Next character is last character and it is hash character.
    TBool result = EFalse;
    TPtrC ptr = aInput.Remainder();

    if ( ptr.Length() == KPhoneSsRemainderSingle )
        {
        result = ( ptr[0] == KPhoneSsHash );
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleEmptyOrBasicCodeL
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleEmptyOrBasicCodeL( 
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    TBool result = EFalse;

    if ( HandleNoParametersL( aInput, aResult ) )
        {
        aResult.AddParameterL( KNullDesC );
        aResult.AddParameterL( KNullDesC );
        result = ETrue;
        }
    else
        {
        result = HandleEmptyParameterL( aInput, aResult );

        if ( result )
            {
            result = HandleBasicCodeL( aInput, aResult );
            result = result && HandleNoParametersL( aInput, aResult );
            }
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleNumberOptBasicCodeOptTimerL
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleNumberOptBasicCodeOptTimerL(
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    TBool result = EFalse;
    
    if ( HandleNumberL( aInput, aResult ) )
        {
        if ( HandleNoParametersL( aInput, aResult ) )
            {
            // Add basic code and timer.
            aResult.AddParameterL( KNullDesC ); 
            aResult.AddParameterL( KNullDesC ); 
            result = ETrue;
            }
        else 
            {
            if ( HandleBasicCodeL( aInput, aResult ) )
                {
                if ( HandleTimerL( aInput, aResult ) )
                    {
                    result = HandleNoParametersL( aInput, aResult );
                    }
                else
                    {
                    result = HandleNoParametersL( aInput, aResult );
                    aResult.AddParameterL( KNullDesC );
                    }
                }
            else if ( HandleEmptyParameterL( aInput, aResult ) )
                {
                result = HandleTimerL( aInput, aResult );
                result = result && 
                         HandleNoParametersL( aInput, aResult );
                }
            }
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleNumberOptBasicCodeL
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleNumberOptBasicCodeL(
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    TBool result = EFalse;
    
    if ( HandleNumberL( aInput, aResult ) )
        {
        if ( HandleNoParametersL( aInput, aResult ) )
            {
            aResult.AddParameterL( KNullDesC );
            result = ETrue;
            }
        else
            {
            result = HandleBasicCodeL( aInput, aResult );
            result = result && HandleNoParametersL( aInput, aResult );
            }
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandlePasswordOptBasicCodeL
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandlePasswordOptBasicCodeL(
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    TBool result = EFalse;

    if ( HandlePasswordL( aInput, aResult ) )
        {
        if ( HandleNoParametersL( aInput, aResult ) )
            {
            aResult.AddParameterL( KNullDesC );
            result = ETrue;
            }
        else
            {
            result = HandleBasicCodeL( aInput, aResult );
            result = result && HandleNoParametersL( aInput, aResult );
            }
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::
// HandleOptGroupCodePasswordNewPasswordNewPasswordL
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::
    HandleOptGroupCodePasswordNewPasswordNewPasswordL(
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    TBool result = HandleGroupCodeL( aInput, aResult );

    if ( !result )
        {
        result = HandleEmptyParameterL( aInput, aResult );
        }

    result = result && HandlePasswordL( aInput, aResult );
    result = result && HandlePasswordL( aInput, aResult );
    result = result && HandlePasswordL( aInput, aResult );
    result = result && HandleNoParametersL( aInput, aResult );

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleEmptyOrBasicCode2L
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleEmptyOrBasicCode2L(
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    TBool result = HandleNoParametersL( aInput, aResult );

    if ( result )
        {
        aResult.AddParameterL( KNullDesC );
        }
    else
        {
        result = HandleBasicCodeL( aInput, aResult );
        result = result && HandleNoParametersL( aInput, aResult );
        }
    
    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleEmptyParameterL
//
// Handle empty parameter, two consecutive asterisks.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleEmptyParameterL( 
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    TBool result = EFalse;
    aInput.Mark();

    if ( aInput.Peek() == KPhoneSsAsterisk )
        {
        aInput.Inc();

        result = ( aInput.Peek() == KPhoneSsAsterisk );
        
        if ( result )
            {
            aResult.AddParameterL( KNullDesC );
            }
        }

    if ( !result )
        {
        aInput.UnGetToMark();
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleBasicCodeL
//
// Basically, basic service code is a two digit string.
// In this method, only explicit
// values are handled (parameter might be empty).
//
// The method checks that the first character is * and then
// it is followed by two digits. And there must not be more
// than two digits.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleBasicCodeL( 
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {   
    TBool result = EFalse;
    TLexMark start;

    aInput.Mark( start );

    if ( aInput.Peek() == KPhoneSsAsterisk )
        {
        aInput.Inc();
    
        TLexMark mark;
        aInput.Mark( mark );
        
        if ( aInput.Peek().IsDigit() )
            {
            aInput.Inc();

            if ( aInput.Peek().IsDigit() )
                {
                aInput.Inc();

                if ( !aInput.Peek().IsDigit() )
                    {
                    TPtrC code = aInput.MarkedToken( mark );

                    result = CheckBasicCode( code );

                    if ( result )
                        {
                        aResult.AddParameterL( code );
                        }
                    }
                }
            }

        // Check empty parameters.
        if ( !result )
            {
            aInput.UnGetToMark( mark );
            
            if ( aInput.Remainder() == KPhoneSsEnd )
                {
                aResult.AddParameterL( KNullDesC );
                result = ETrue;
                }
            }
        }

    if ( !result )
        {
        aInput.UnGetToMark( start );
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleNumberL
//
// Directory number as a parameter must be present. It can
// contain at most 38 digits. Digits and '+' characters
// are allowed, but '+' character is allowed to be only in the 
// beginning of the string.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleNumberL( 
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    if ( aInput.Remainder().Length() < KPhoneSsRemainderMinLength )
        {
        return EFalse;
        }

    TInt maxLength = KPhoneSsDirectoryNumberMaxLength;
    TBool result = EFalse;
    TLexMark start;

    aInput.Mark( start );

    if ( aInput.Peek() == KPhoneSsAsterisk )
        {
        aInput.Inc();
       
        TLexMark mark;
        aInput.Mark( mark );

        if ( aInput.Peek() == KPhoneSsPlus )
            {
            aInput.Inc();
            maxLength++;
            }

        while ( aInput.Peek().IsDigit() )
            {
            aInput.Inc();
            }

        TPtrC number = aInput.MarkedToken( mark );
        if ( number.Length() <= maxLength )
            {  
            aResult.AddParameterL( number );
            result = ETrue;
            }
        }

    if ( !result )
        {
        aInput.UnGetToMark( start );
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleTimerL
//
// The method checks if the next part is 'no reply timer'.
// It is at most two digits. Value is expected to be present.
// Value is checked in CheckTimer method.
//
// (if value is not present, then it is handled in calling
//  method)
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleTimerL( 
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    TBool result = EFalse;
    TLexMark start;
    aInput.Mark( start );

    if ( aInput.Peek() == KPhoneSsAsterisk )
        {
        aInput.Inc();

        TLexMark mark;
        aInput.Mark( mark );
        
        while ( aInput.Peek().IsDigit() )
            {
            aInput.Inc();
            }
        
        TPtrC timer( aInput.MarkedToken( mark ) );
        
        if ( CheckTimer( timer ) )
            {
            aResult.AddParameterL( timer );
            result = ETrue;
            }

        // Check empty parameters.
        if ( !result )
            {
            aInput.UnGetToMark( mark );
            
            if ( aInput.Remainder() == KPhoneSsEnd )
                {
                aResult.AddParameterL( KNullDesC );
                result = ETrue;
                }
            }
        }

    if ( !result )
        {
        aInput.UnGetToMark( start );
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandlePasswordL
//
// Password is four digit string.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandlePasswordL( 
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    if ( aInput.Remainder().Length() <
         KPhoneSsRemainderPasswordMinLength )
        {
        return EFalse;
        }

    TBool result = EFalse;
    TLexMark start;
    aInput.Mark( start );

    if ( aInput.Peek() == KPhoneSsAsterisk )
        {
        aInput.Inc();

        TLexMark mark;
        aInput.Mark( mark );

        while( aInput.Peek().IsDigit() )
            {
            aInput.Inc();
            }

        TPtrC password( aInput.MarkedToken( mark ) );
        
        if ( password.Length() == KPhoneSsPasswordLength )
            {
            aResult.AddParameterL( password );
            result = ETrue;
            }
        }

    if ( !result )
        {
        aInput.UnGetToMark( start );
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::HandleGroupCodeL
//
// The method handles password group codes. However, code 
// must be one to four digits. 
//
// (if group code is null, then it is handled in calling
//  method)
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::HandleGroupCodeL( 
        TLex& aInput,
        CPhoneGsmParserResult& aResult )
    {
    if ( aInput.Remainder().Length() <= KPhoneSsRemainderMinLength )
        {
        return EFalse;
        }

    TBool result = EFalse; 
    TLexMark start;

    aInput.Mark( start );

    if ( aInput.Peek() == KPhoneSsAsterisk )
        {
        aInput.Inc();
        
        TLexMark mark;
        aInput.Mark( mark );

        while ( aInput.Peek().IsDigit() )
            {
            aInput.Inc();
            }

        TPtrC groupCode( aInput.MarkedToken( mark ) );

        if ( CheckGroupCode( groupCode ) )
            {
            aResult.AddParameterL( groupCode );
            result = ETrue;
            }
        }

    if ( !result )
        {
        aInput.UnGetToMark( start );
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::CheckBasicCode
//
// Check that basic code is appropriate
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::CheckBasicCode( const TDesC& aCode )
    {
    TLex lex( aCode );
    TUint value;
    
    if ( aCode.Length() <= KPhoneSsBasicCodeMaxLength )
        {
        if ( lex.Val( value, EDecimal ) != KErrNone )
            {
            return EFalse;
            }
        }
    else
        {
        return EFalse;
        }

    TBool result = EFalse;
  
    switch ( value )
        {
        // TELESERVICES
        case EAllTele:          // GSM: All tele and bearer services
        case ETelephony:        // GSM: Teleservices
        case EAllDataTele:      // GSM: All data teleservices
        case EFax:              // GSM: Facsimile services
        case ESms:              // GSM: Short message services
        case EAllTeleExcSms:    // GSM: All teleservices except SMS
        case EAltTele:          // PCN: Alternate line service

        // BEARER SERVICES
        case EAllBearer:        // GSM: All bearer services
        case EAllAsync:         // GSM: All async services
        case EAllSync:          // GSM: All sync services
        case ESyncData:         // GSM: All data circuit sync
        case EAsyncData:        // GSM: All data circuit async
        case EPacketData:       // GSM: All dedicated packet access
        case EPadAccess:        // GSM: All dedicated PAD access

            result = ETrue;
            break;

        // PLMN specific teleservices and bearer services
        default:
            
            // GSM: PLMN specific teleservices
            if ( value >= EAllPlmnTele && value <= EPlmnTeleF )
                {
                result = ETrue;
                }
            // GSM: PLMN specific bearer services
            else if ( value >= EAllPlmnBearer && value <= EPlmnBearerServF )
                {
                result = ETrue;
                }

            // Otherwise, result == EFalse and it's OK.
            break;
        }
    
    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::CheckTimer
//
// Check if timer value is ok.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::CheckTimer( const TDesC& aCode )
    {
    TLex lex( aCode );
    TUint value;
    
    if ( aCode.Length() <= KPhoneSsTimerMaxLength )
        {
        if ( lex.Val( value, EDecimal ) != KErrNone )
            {
            return EFalse;
            }
        }
    else 
        {
        return EFalse;
        }

    TBool result = EFalse;

    switch ( value )
        {
        case 5:
        case 10:
        case 15:
        case 20:
        case 25:
        case 30:
            result = ETrue;
            break;

        default:
            break;
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::CheckGroupCode
//
// Check if group code is ok.
// -----------------------------------------------------------------------------
//
TBool CPhoneGsmSsParser::CheckGroupCode( const TDesC& aCode )
    {
    TLex lex( aCode );
    TUint value;
    TBool result = EFalse;

    if ( aCode.Length() <= KPhoneSsGroupCodeMaxLength )
        {
        if ( lex.Val( value, EDecimal ) == KErrNone )
            {
            result = ( value == KPhoneSsOnlyAllowedGroupCode );
            }
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::FindString
// -----------------------------------------------------------------------------
//
TPtrC CPhoneGsmSsParser::FindString( 
        TLex& aInput,
        const TDesC& aAllowedCharacters )
    {
    TLexMark mark;
    aInput.Mark( mark );

    // Return string containing characters that appear in 
    // aAllowedCharacters.
    while ( aAllowedCharacters.Locate( aInput.Peek() ) != 
            KErrNotFound )
        {
        aInput.Inc();
        }
    
    return aInput.MarkedToken( mark );
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::AddL
//
// Parse service description and add it.
//
// -----------------------------------------------------------------------------
//
void CPhoneGsmSsParser::AddL( 
        const TDesC& aService, 
        TUint aUid )
    {
    // There must be six positive integers in aService.   
    TLex input( aService );

    // First number is service code.
    TPtrC serviceCode( NextNumber( input ) );

    // And then next five are syntax descriptions.
    TServiceSyntax activation = 
        ConvertToServiceSyntax( NextNumberAsValue( input ) );
    TServiceSyntax deactivation = 
        ConvertToServiceSyntax( NextNumberAsValue( input ) );
    TServiceSyntax interrogation = 
        ConvertToServiceSyntax( NextNumberAsValue( input ) );
    TServiceSyntax registration = 
        ConvertToServiceSyntax( NextNumberAsValue( input ) );
    TServiceSyntax erasure = 
        ConvertToServiceSyntax( NextNumberAsValue( input ) );
   
    // Add to array.
    AddServiceL( 
        serviceCode,
        activation,
        deactivation,
        interrogation,
        registration,
        erasure,
        aUid );
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::AddServiceL
// -----------------------------------------------------------------------------
//
void CPhoneGsmSsParser::AddServiceL( 
        const TDesC& aServiceCode,
        TServiceSyntax aActivation,
        TServiceSyntax aDeactivation,
        TServiceSyntax aInterrogation,
        TServiceSyntax aRegistration,
        TServiceSyntax aErasure,
        TUint aUid )
    {   
    TServiceInfo info;

    // Fill information to info structure.
    info.iCode = aServiceCode;
    info.iActivation = aActivation;
    info.iDeactivation = aDeactivation;
    info.iInterrogation = aInterrogation;
    info.iRegistration = aRegistration;
    info.iErasure = aErasure;
    info.iUid = aUid;

    TKeyArrayFix key( _FOFF( TServiceInfo, iCode ), ECmpNormal );

    // Add it to the array.
    TRAPD( err, iArray->InsertIsqL( info, key ) ); 

    if ( err != KErrNone && err != KErrNoMemory )
        {
        PhoneGsmParser::Panic( 
            PhoneGsmParser::EIncorrectServiceDescription );
        }

    // Just leave if no memory.
    if ( err == KErrNoMemory )
        {
        User::Leave( err );
        }
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::NextNumber
//
// Skip spaces and then get next number.
// -----------------------------------------------------------------------------
//
TPtrC CPhoneGsmSsParser::NextNumber( 
        TLex& aLex )
    {
    // Skip whites.
    aLex.SkipSpace();

    // Go over digits.
    aLex.Mark();
    while ( aLex.Peek().IsDigit() )
        {
        aLex.Inc();
        }

    // Check if we got proper number.
    if ( !aLex.TokenLength() )
        {
        PhoneGsmParser::Panic( 
            PhoneGsmParser::EIncorrectServiceDescription );
        }
    
    return aLex.MarkedToken();       
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::NextNumberAsValue
//
// Get number and convert it to value.
// -----------------------------------------------------------------------------
//
TUint CPhoneGsmSsParser::NextNumberAsValue( 
        TLex& aLex )
    {
    // Get number.
    TPtrC number( NextNumber( aLex ) );
    TLex input( number );
    TUint value;

    // Parse number.
    if ( input.Val( value, EDecimal ) != KErrNone )
        {
        PhoneGsmParser::Panic( 
            PhoneGsmParser::EIncorrectServiceDescription );
        }

    return value;
    }

// -----------------------------------------------------------------------------
// CPhoneGsmSsParser::ConvertToServiceSyntax
//
// Convert value to a service syntax enumeration.
// -----------------------------------------------------------------------------
//
CPhoneGsmSsParser::TServiceSyntax 
    CPhoneGsmSsParser::ConvertToServiceSyntax( 
        TUint aService )
    {
    TServiceSyntax service = ESyntaxNotAllowed;

    switch ( aService )
        {
        case 0:
            service = ESyntaxNotAllowed;        
            break;
        case 1:
            service = ESyntaxNoParameters;
            break;
        case 2:
            service = ESyntaxEmptyOrBasicCode;
            break;
        case 3:
            service = ESyntaxNumberOptBasicCodeOptTimer;
            break;
        case 4:
            service = ESyntaxNumberOptBasicCode;
            break;
        case 5:
            service = ESyntaxPasswordOptBasicCode;
            break;
        case 6:
            service = ESyntaxOptGroupCodePasswordNewPasswordNewPassword;
            break;
        case 7:
            service = ESyntaxEmptyOrBasicCode2;
            break;
        default:
            PhoneGsmParser::Panic( 
                PhoneGsmParser::EIncorrectServiceDescription );       
        }

    return service;
    }

//  End of File