<commit_before>/** @file le_sim.c
 *
 * This file contains the data structures and the source code of the high level SIM APIs.
 *
 * Copyright (C) Sierra Wireless Inc.
 */


#include "legato.h"
#include "interfaces.h"
#include "pa_sim.h"


//--------------------------------------------------------------------------------------------------
// Symbol and Enum definitions.
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
/**
 *  Enumeration for Subscription type.
 */
//--------------------------------------------------------------------------------------------------
typedef enum
{
    COMMERCIAL,           ///< Commercial subscription.
    ECS,                  ///< Emergency Call subscription.
    UNKNOWN_SUBSCRIPTION, ///< Unknown subscription.
    SUBSCRIPTION_MAX
}
Subscription_t;


//--------------------------------------------------------------------------------------------------
// Data structures.
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
/**
 * SIM structure.
 */
//--------------------------------------------------------------------------------------------------
typedef struct le_sim_Obj
{
    le_sim_Id_t      simId;                      ///< SIM identifier.
    char             ICCID[LE_SIM_ICCID_BYTES];  ///< Integrated circuit card identifier.
    char             IMSI[LE_SIM_IMSI_BYTES];    ///< International mobile subscriber identity.
    char             PIN[LE_SIM_PIN_MAX_BYTES];  ///< PIN code.
    char             PUK[LE_SIM_PUK_MAX_BYTES];  ///< PUK code.
    char             phoneNumber[LE_MDMDEFS_PHONE_NUM_MAX_BYTES]; /// < The Phone Number.
    bool             isPresent;                  ///< 'isPresent' flag.
    Subscription_t   Subscription;               ///< Subscription type
}
Sim_t;

//--------------------------------------------------------------------------------------------------
/**
 * SIM state event.
 */
//--------------------------------------------------------------------------------------------------
typedef struct
{
    le_sim_Id_t      simId;   ///< SIM identififier
    le_sim_States_t  state;   ///< SIM state.
}
Sim_Event_t;

//--------------------------------------------------------------------------------------------------
/**
 * List of all SIM objects.
 */
//--------------------------------------------------------------------------------------------------
static Sim_t SimList[LE_SIM_ID_MAX];

//--------------------------------------------------------------------------------------------------
/**
 * APDU message structure.
 *
 */
//--------------------------------------------------------------------------------------------------
typedef struct
{
    uint32_t apduLength;
    uint8_t  apduReq[16];
}
ApduMsg_t;


//--------------------------------------------------------------------------------------------------
//                                       Static declarations
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
/**
 * Current selected SIM card.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_sim_Id_t  SelectedCard;

//--------------------------------------------------------------------------------------------------
/**
 * Event ID for New SIM state notification.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_event_Id_t NewSimStateEventId;

//--------------------------------------------------------------------------------------------------
/**
 * Event ID for SIM Toolkit notification.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_event_Id_t SimToolkitEventId;

//--------------------------------------------------------------------------------------------------
/**
 * ECounter for SIM Toolkit event handlers.
 *
 */
//--------------------------------------------------------------------------------------------------
static uint32_t SimToolkitHandlerCount = 0;

//--------------------------------------------------------------------------------------------------
/**
 * PA SIM Toolkit handler reference.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_event_HandlerRef_t PaSimToolkitHandlerRef = NULL;

//--------------------------------------------------------------------------------------------------
/**
 * The APDU messages to swap to Emergency Call subscription.
 */
//--------------------------------------------------------------------------------------------------
static ApduMsg_t EcsSwapApduReq[LE_SIM_MANUFACTURER_MAX] =
{
    // OBERTHUR
    { 10 , {0x80, 0xC2, 0x00, 0x00, 0x05, 0xEE, 0x03, 0xEF, 0x01, 0x20} },
    // GEMALTO
    { 14, {0x80, 0xC2, 0x00, 0x00, 0x09, 0xD3, 0x07, 0x02, 0x02, 0x01, 0x81, 0x10, 0x01, 0x7E} },
    // G_AND_D
    { 5, {0x00, 0xB6, 0x01, 0x00, 0x00} },
    // MORPHO
    { 13, {0x80, 0xC2, 0x00, 0x00, 0x08, 0xCF, 0x06, 0x19, 0x01, 0x99, 0x5F, 0x01, 0x81} },
    // VALID
    { 13 , {0x80, 0xC2, 0x00, 0x00, 0x08, 0xCF, 0x06, 0x19, 0x01, 0x80, 0x58, 0x01, 0x81} }
};

//--------------------------------------------------------------------------------------------------
/**
 * The APDU messages to swap to Commercial subscription.
 */
//--------------------------------------------------------------------------------------------------
static ApduMsg_t CommercialSwapApduReq[LE_SIM_MANUFACTURER_MAX] =
{
    // OBERTHUR
    { 10, {0x80, 0xC2, 0x00, 0x00, 0x05, 0xEE, 0x03, 0xEF, 0x01, 0x24} },
    // GEMALTO
    { 14, {0x80, 0xC2, 0x00, 0x00, 0x09, 0xD3, 0x07, 0x02, 0x02, 0x01, 0x81, 0x10, 0x01, 0x7F} },
    // G_AND_D
    { 5, {0x00, 0xB6, 0x02, 0x00, 0x00} },
    // MORPHO
    { 13, {0x80, 0xC2, 0x00, 0x00, 0x08, 0xCF, 0x06, 0x19, 0x01, 0x99, 0x5F, 0x01, 0x80} },
    // VALID
    { 13 , {0x80, 0xC2, 0x00, 0x00, 0x08, 0xCF, 0x06, 0x19, 0x01, 0x80, 0x58, 0x01, 0x80} }
};

//--------------------------------------------------------------------------------------------------
/**
 * This function must be called to request the multi-profile eUICC to swap to commercial or ECS
 * subscription and to refresh.
 * The User's application must wait for eUICC reboot to be finished and network connection
 * available.
 *
 * @return
 *      - LE_OK on success
 *      - LE_BUSY when a profile swap is already in progress
 *      - LE_FAULT for unexpected error
 */
//--------------------------------------------------------------------------------------------------
static le_result_t LocalSwap
(
    le_sim_Manufacturer_t manufacturer,   ///< [IN] The card manufacturer.
    uint8_t*              swapApduReqPtr, ///< [IN] The swap APDU message.
    uint32_t              swapApduLen     ///< [IN] The swap APDU message length in bytes.
)
{
    uint8_t  channel = 0;

    // Get the logical channel to send APDu command.
    if (pa_sim_OpenLogicalChannel(&channel) != LE_OK)
    {
        LE_ERROR("Cannot open Logical Channel!");
        return LE_FAULT;
    }

    if (LE_SIM_G_AND_D == manufacturer)
    {
        uint8_t  pduReq[] = {0x00, 0xA4, 0x04, 0x00, 0x10, 0xD2, 0x76, 0x00,
                             0x01, 0x18, 0x00, 0x02, 0xFF, 0x34, 0x10, 0x25,
                             0x89, 0xC0, 0x02, 0x10, 0x01};

        pduReq[0] = channel;
        if (pa_sim_SendApdu(channel, pduReq, sizeof(pduReq),
                            NULL, NULL) != LE_OK)
        {
            LE_ERROR("Cannot send APDU message!");
            return LE_FAULT;
        }
        swapApduReqPtr[0] = channel;
    }

    if (pa_sim_SendApdu(channel,
                        swapApduReqPtr,
                        swapApduLen,
                        NULL, NULL) != LE_OK)
    {
        LE_ERROR("Cannot swap subscription!");
        return LE_FAULT;
    }

    if (pa_sim_CloseLogicalChannel(channel) != LE_OK)
    {
        LE_ERROR("Cannot close Logical Channel!");
        return LE_FAULT;
    }

    if ( (manufacturer == LE_SIM_OBERTHUR)
         || (manufacturer == LE_SIM_MORPHO) )
    {
        return LE_OK;
    }
    else
    {
        return pa_sim_Refresh();
    }
}

//--------------------------------------------------------------------------------------------------
/**
 * Get the SIM card information.
 *
 */
//--------------------------------------------------------------------------------------------------
static void GetSimCardInformation
(
    Sim_t*          simPtr,
    le_sim_States_t state
)
{
    pa_sim_CardId_t   iccid;
    pa_sim_Imsi_t     imsi;

    switch(state)
    {
        case LE_SIM_ABSENT:
            simPtr->ICCID[0] = '\0';
            simPtr->IMSI[0] = '\0';
            simPtr->isPresent = false;
            break;

        case LE_SIM_INSERTED:
        case LE_SIM_BLOCKED:
            simPtr->isPresent = true;
            simPtr->IMSI[0] = '\0';
            if(pa_sim_GetCardIdentification(iccid) != LE_OK)
            {
                LE_ERROR("Failed to get the ICCID of sim identifier %d.", simPtr->simId);
                simPtr->ICCID[0] = '\0';
            }
            else
            {
                le_utf8_Copy(simPtr->ICCID, iccid, sizeof(simPtr->ICCID), NULL);
            }
            break;

        case LE_SIM_READY:
            simPtr->isPresent = true;
            // Get identification information
            if(pa_sim_GetCardIdentification(iccid) != LE_OK)
            {
                LE_ERROR("Failed to get the ICCID of sim identifier %d.", simPtr->simId);
                simPtr->ICCID[0] = '\0';
            }
            else
            {
                le_utf8_Copy(simPtr->ICCID, iccid, sizeof(simPtr->ICCID), NULL);
            }

            if(pa_sim_GetIMSI(imsi) != LE_OK)
            {
                LE_ERROR("Failed to get the IMSI of sim identifier %d.", simPtr->simId);
                simPtr->IMSI[0] = '\0';
            }
            else
            {
                le_utf8_Copy(simPtr->IMSI, imsi, sizeof(simPtr->IMSI), NULL);
            }
            break;

        case LE_SIM_BUSY:
        case LE_SIM_STATE_UNKNOWN:
            simPtr->isPresent = true;
            break;
    }
}

//--------------------------------------------------------------------------------------------------
/**
 * SIM card selector.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_result_t SelectSIMCard
(
    le_sim_Id_t simId    ///< [IN] The SIM identifier.
)
{
    if(simId != SelectedCard)
    {
        // Select the SIM card
        LE_DEBUG("Try to select sim identifier.%d", simId);
        if(pa_sim_SelectCard(simId) != LE_OK)
        {
            LE_ERROR("Failed to select sim identifier.%d", simId);
            return LE_NOT_FOUND;
        }
        SelectedCard = simId;
    }
    return LE_OK;
}

//--------------------------------------------------------------------------------------------------
/**
 * The first-layer New SIM state notification Handler.
 *
 */
//--------------------------------------------------------------------------------------------------
static void FirstLayerNewSimStateHandler
(
    void* reportPtr,
    void* secondLayerHandlerFunc
)
{
    Sim_Event_t*                  simEvent = reportPtr;

    le_sim_NewStateHandlerFunc_t clientHandlerFunc = secondLayerHandlerFunc;

    clientHandlerFunc(simEvent->simId, simEvent->state, le_event_GetContextPtr());
}

//--------------------------------------------------------------------------------------------------
/**
 * Handler function for new SIM state notification.
 *
 */
//--------------------------------------------------------------------------------------------------
static void NewSimStateHandler
(
    pa_sim_Event_t* eventPtr
)
{
    Sim_t*           simPtr;
    Sim_Event_t      simEvent;

    LE_DEBUG("New SIM state.%d for sim identifier.%d (eventPtr %p)", eventPtr->state,
        eventPtr->simId, eventPtr);
    simPtr = &SimList[eventPtr->simId];
    GetSimCardInformation(simPtr, eventPtr->state);

    // Discard transitional states
    switch (eventPtr->state)
    {
        case LE_SIM_BUSY:
        case LE_SIM_STATE_UNKNOWN:
            LE_DEBUG("Discarding report for sim identifie.%d, state.%d",
                            eventPtr->simId, eventPtr->state);
            return;

        default:
            break;
    }

    if ( eventPtr->simId != SelectedCard )
    {
        LE_DEBUG("New selected card");
        SelectedCard = eventPtr->simId;
    }

    // Notify all the registered client handlers
    simEvent.simId = eventPtr->simId;
    simEvent.state = eventPtr->state;
    le_event_Report(NewSimStateEventId, &simEvent, sizeof(simEvent));
    LE_DEBUG("Report state %d on SIM Id %d", simEvent.state, simEvent.simId);

    le_mem_Release(eventPtr);
}

//--------------------------------------------------------------------------------------------------
/**
 * The first-layer SIM Toolkit events Handler.
 *
 */
//--------------------------------------------------------------------------------------------------
static void FirstLayerSimToolkitHandler
(
    void* reportPtr,
    void* secondLayerHandlerFunc
)
{
    pa_sim_StkEvent_t*                  stkEventPtr = reportPtr;
    le_sim_SimToolkitEventHandlerFunc_t clientHandlerFunc = secondLayerHandlerFunc;

    LE_DEBUG("Report stkEvent %d on SIM Id %d", stkEventPtr->stkEvent, stkEventPtr->simId);

    clientHandlerFunc(stkEventPtr->simId, stkEventPtr->stkEvent, le_event_GetContextPtr());
}

//--------------------------------------------------------------------------------------------------
/**
 * Handler function for SIM Toolkit events.
 *
 */
//--------------------------------------------------------------------------------------------------
static void SimToolkitHandler
(
    pa_sim_StkEvent_t* eventPtr
)
{
    LE_DEBUG("Report stkEvent %d on SIM Id %d", eventPtr->stkEvent, eventPtr->simId);
    le_event_Report(SimToolkitEventId, eventPtr, sizeof(pa_sim_StkEvent_t));
}

//--------------------------------------------------------------------------------------------------
/**
 * This function tests the SIM validity
 *
 * @return LE_OK            On success.
 * @return LE_NOT_FOUND     The function failed to select the SIM card for this operation.
 * @return LE_BAD_PARAMETER Invalid SIM identifier.
 * @return LE_FAULT         The function failed to get the number of remaining PIN insertion tries.
 */
//--------------------------------------------------------------------------------------------------
static le_result_t CheckSimValidity
(
    le_sim_Id_t simId   ///< [IN] The SIM identifier.
)
{
    Sim_t*    simPtr;
    if (simId >= LE_SIM_ID_MAX)
    {
        LE_ERROR("Invalid simId (%d) provided!", simId);
        return LE_BAD_PARAMETER;
    }

    if (LE_OK != SelectSIMCard(simId))
    {
        return LE_NOT_FOUND;
    }

    simPtr = &SimList[simId];

    if (!simPtr->isPresent)
    {
        return LE_NOT_FOUND;
    }

    return LE_OK;
}

//--------------------------------------------------------------------------------------------------
// APIs.
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
/**
 * This function must be called to initialize the SIM operations component
 *
 * @return LE_FAULT  The function failed.
 * @return LE_OK     The function succeed.
 */
//--------------------------------------------------------------------------------------------------
le_result_t le_sim_Init
(
    void
)
{
    int i;

    // Initialize the SIM list
    for (i = 0; i < LE_SIM_ID_MAX; i++)
    {
        SimList[i].simId = i;
        SimList[i].ICCID[0] = '\0';
        SimList[i].IMSI[0] = '\0';
        SimList[i].isPresent = false;
        SimList[i].Subscription = UNKNOWN_SUBSCRIPTION;
        GetSimCardInformation(&SimList[i], LE_SIM_ABSENT);
    }

    // Create an event Id for new SIM state notifications
    NewSimStateEventId = le_event_CreateId("NewSimStateEventId", sizeof(Sim_Event_t));

    // Create an event Id for SIM Toolkit notifications
    SimToolkitEventId = le_event_CreateId("SimToolkitEventId", sizeof(pa_sim_StkEvent_t));

    SimToolkitHandlerCount = 0;
    PaSimToolkitHandlerRef = NULL;

    // Register a handler function for new SIM state notification
    if (pa_sim_AddNewStateHandler(NewSimStateHandler) == NULL)
    {
        LE_CRIT("Add new SIM state handler failed");
        return LE_FAULT;
    }

    if (pa_sim_GetSelectedCard(&SelectedCard) != LE_OK)
    {
        LE_CRIT("Unable to get selected card.");<commit_msg>Clear sim phone number object<commit_after>/** @file le_sim.c
 *
 * This file contains the data structures and the source code of the high level SIM APIs.
 *
 * Copyright (C) Sierra Wireless Inc.
 */


#include "legato.h"
#include "interfaces.h"
#include "pa_sim.h"


//--------------------------------------------------------------------------------------------------
// Symbol and Enum definitions.
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
/**
 *  Enumeration for Subscription type.
 */
//--------------------------------------------------------------------------------------------------
typedef enum
{
    COMMERCIAL,           ///< Commercial subscription.
    ECS,                  ///< Emergency Call subscription.
    UNKNOWN_SUBSCRIPTION, ///< Unknown subscription.
    SUBSCRIPTION_MAX
}
Subscription_t;


//--------------------------------------------------------------------------------------------------
// Data structures.
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
/**
 * SIM structure.
 */
//--------------------------------------------------------------------------------------------------
typedef struct le_sim_Obj
{
    le_sim_Id_t      simId;                      ///< SIM identifier.
    char             ICCID[LE_SIM_ICCID_BYTES];  ///< Integrated circuit card identifier.
    char             IMSI[LE_SIM_IMSI_BYTES];    ///< International mobile subscriber identity.
    char             PIN[LE_SIM_PIN_MAX_BYTES];  ///< PIN code.
    char             PUK[LE_SIM_PUK_MAX_BYTES];  ///< PUK code.
    char             phoneNumber[LE_MDMDEFS_PHONE_NUM_MAX_BYTES]; /// < The Phone Number.
    bool             isPresent;                  ///< 'isPresent' flag.
    Subscription_t   Subscription;               ///< Subscription type
}
Sim_t;

//--------------------------------------------------------------------------------------------------
/**
 * SIM state event.
 */
//--------------------------------------------------------------------------------------------------
typedef struct
{
    le_sim_Id_t      simId;   ///< SIM identififier
    le_sim_States_t  state;   ///< SIM state.
}
Sim_Event_t;

//--------------------------------------------------------------------------------------------------
/**
 * List of all SIM objects.
 */
//--------------------------------------------------------------------------------------------------
static Sim_t SimList[LE_SIM_ID_MAX];

//--------------------------------------------------------------------------------------------------
/**
 * APDU message structure.
 *
 */
//--------------------------------------------------------------------------------------------------
typedef struct
{
    uint32_t apduLength;
    uint8_t  apduReq[16];
}
ApduMsg_t;


//--------------------------------------------------------------------------------------------------
//                                       Static declarations
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
/**
 * Current selected SIM card.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_sim_Id_t  SelectedCard;

//--------------------------------------------------------------------------------------------------
/**
 * Event ID for New SIM state notification.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_event_Id_t NewSimStateEventId;

//--------------------------------------------------------------------------------------------------
/**
 * Event ID for SIM Toolkit notification.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_event_Id_t SimToolkitEventId;

//--------------------------------------------------------------------------------------------------
/**
 * ECounter for SIM Toolkit event handlers.
 *
 */
//--------------------------------------------------------------------------------------------------
static uint32_t SimToolkitHandlerCount = 0;

//--------------------------------------------------------------------------------------------------
/**
 * PA SIM Toolkit handler reference.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_event_HandlerRef_t PaSimToolkitHandlerRef = NULL;

//--------------------------------------------------------------------------------------------------
/**
 * The APDU messages to swap to Emergency Call subscription.
 */
//--------------------------------------------------------------------------------------------------
static ApduMsg_t EcsSwapApduReq[LE_SIM_MANUFACTURER_MAX] =
{
    // OBERTHUR
    { 10 , {0x80, 0xC2, 0x00, 0x00, 0x05, 0xEE, 0x03, 0xEF, 0x01, 0x20} },
    // GEMALTO
    { 14, {0x80, 0xC2, 0x00, 0x00, 0x09, 0xD3, 0x07, 0x02, 0x02, 0x01, 0x81, 0x10, 0x01, 0x7E} },
    // G_AND_D
    { 5, {0x00, 0xB6, 0x01, 0x00, 0x00} },
    // MORPHO
    { 13, {0x80, 0xC2, 0x00, 0x00, 0x08, 0xCF, 0x06, 0x19, 0x01, 0x99, 0x5F, 0x01, 0x81} },
    // VALID
    { 13 , {0x80, 0xC2, 0x00, 0x00, 0x08, 0xCF, 0x06, 0x19, 0x01, 0x80, 0x58, 0x01, 0x81} }
};

//--------------------------------------------------------------------------------------------------
/**
 * The APDU messages to swap to Commercial subscription.
 */
//--------------------------------------------------------------------------------------------------
static ApduMsg_t CommercialSwapApduReq[LE_SIM_MANUFACTURER_MAX] =
{
    // OBERTHUR
    { 10, {0x80, 0xC2, 0x00, 0x00, 0x05, 0xEE, 0x03, 0xEF, 0x01, 0x24} },
    // GEMALTO
    { 14, {0x80, 0xC2, 0x00, 0x00, 0x09, 0xD3, 0x07, 0x02, 0x02, 0x01, 0x81, 0x10, 0x01, 0x7F} },
    // G_AND_D
    { 5, {0x00, 0xB6, 0x02, 0x00, 0x00} },
    // MORPHO
    { 13, {0x80, 0xC2, 0x00, 0x00, 0x08, 0xCF, 0x06, 0x19, 0x01, 0x99, 0x5F, 0x01, 0x80} },
    // VALID
    { 13 , {0x80, 0xC2, 0x00, 0x00, 0x08, 0xCF, 0x06, 0x19, 0x01, 0x80, 0x58, 0x01, 0x80} }
};

//--------------------------------------------------------------------------------------------------
/**
 * This function must be called to request the multi-profile eUICC to swap to commercial or ECS
 * subscription and to refresh.
 * The User's application must wait for eUICC reboot to be finished and network connection
 * available.
 *
 * @return
 *      - LE_OK on success
 *      - LE_BUSY when a profile swap is already in progress
 *      - LE_FAULT for unexpected error
 */
//--------------------------------------------------------------------------------------------------
static le_result_t LocalSwap
(
    le_sim_Manufacturer_t manufacturer,   ///< [IN] The card manufacturer.
    uint8_t*              swapApduReqPtr, ///< [IN] The swap APDU message.
    uint32_t              swapApduLen     ///< [IN] The swap APDU message length in bytes.
)
{
    uint8_t  channel = 0;

    // Get the logical channel to send APDu command.
    if (pa_sim_OpenLogicalChannel(&channel) != LE_OK)
    {
        LE_ERROR("Cannot open Logical Channel!");
        return LE_FAULT;
    }

    if (LE_SIM_G_AND_D == manufacturer)
    {
        uint8_t  pduReq[] = {0x00, 0xA4, 0x04, 0x00, 0x10, 0xD2, 0x76, 0x00,
                             0x01, 0x18, 0x00, 0x02, 0xFF, 0x34, 0x10, 0x25,
                             0x89, 0xC0, 0x02, 0x10, 0x01};

        pduReq[0] = channel;
        if (pa_sim_SendApdu(channel, pduReq, sizeof(pduReq),
                            NULL, NULL) != LE_OK)
        {
            LE_ERROR("Cannot send APDU message!");
            return LE_FAULT;
        }
        swapApduReqPtr[0] = channel;
    }

    if (pa_sim_SendApdu(channel,
                        swapApduReqPtr,
                        swapApduLen,
                        NULL, NULL) != LE_OK)
    {
        LE_ERROR("Cannot swap subscription!");
        return LE_FAULT;
    }

    if (pa_sim_CloseLogicalChannel(channel) != LE_OK)
    {
        LE_ERROR("Cannot close Logical Channel!");
        return LE_FAULT;
    }

    if ( (manufacturer == LE_SIM_OBERTHUR)
         || (manufacturer == LE_SIM_MORPHO) )
    {
        return LE_OK;
    }
    else
    {
        return pa_sim_Refresh();
    }
}

//--------------------------------------------------------------------------------------------------
/**
 * Get the SIM card information.
 *
 */
//--------------------------------------------------------------------------------------------------
static void GetSimCardInformation
(
    Sim_t*          simPtr,
    le_sim_States_t state
)
{
    pa_sim_CardId_t   iccid;
    pa_sim_Imsi_t     imsi;

    switch(state)
    {
        case LE_SIM_ABSENT:
            simPtr->ICCID[0] = '\0';
            simPtr->IMSI[0] = '\0';
            simPtr->phoneNumber[0] = '\0';
            simPtr->isPresent = false;
            break;

        case LE_SIM_INSERTED:
        case LE_SIM_BLOCKED:
            simPtr->isPresent = true;
            simPtr->IMSI[0] = '\0';
            if(pa_sim_GetCardIdentification(iccid) != LE_OK)
            {
                LE_ERROR("Failed to get the ICCID of sim identifier %d.", simPtr->simId);
                simPtr->ICCID[0] = '\0';
            }
            else
            {
                le_utf8_Copy(simPtr->ICCID, iccid, sizeof(simPtr->ICCID), NULL);
            }
            break;

        case LE_SIM_READY:
            simPtr->isPresent = true;
            // Get identification information
            if(pa_sim_GetCardIdentification(iccid) != LE_OK)
            {
                LE_ERROR("Failed to get the ICCID of sim identifier %d.", simPtr->simId);
                simPtr->ICCID[0] = '\0';
            }
            else
            {
                le_utf8_Copy(simPtr->ICCID, iccid, sizeof(simPtr->ICCID), NULL);
            }

            if(pa_sim_GetIMSI(imsi) != LE_OK)
            {
                LE_ERROR("Failed to get the IMSI of sim identifier %d.", simPtr->simId);
                simPtr->IMSI[0] = '\0';
            }
            else
            {
                le_utf8_Copy(simPtr->IMSI, imsi, sizeof(simPtr->IMSI), NULL);
            }
            break;

        case LE_SIM_BUSY:
        case LE_SIM_STATE_UNKNOWN:
            simPtr->isPresent = true;
            break;
    }
}

//--------------------------------------------------------------------------------------------------
/**
 * SIM card selector.
 *
 */
//--------------------------------------------------------------------------------------------------
static le_result_t SelectSIMCard
(
    le_sim_Id_t simId    ///< [IN] The SIM identifier.
)
{
    if(simId != SelectedCard)
    {
        // Select the SIM card
        LE_DEBUG("Try to select sim identifier.%d", simId);
        if(pa_sim_SelectCard(simId) != LE_OK)
        {
            LE_ERROR("Failed to select sim identifier.%d", simId);
            return LE_NOT_FOUND;
        }
        SelectedCard = simId;
    }
    return LE_OK;
}

//--------------------------------------------------------------------------------------------------
/**
 * The first-layer New SIM state notification Handler.
 *
 */
//--------------------------------------------------------------------------------------------------
static void FirstLayerNewSimStateHandler
(
    void* reportPtr,
    void* secondLayerHandlerFunc
)
{
    Sim_Event_t*                  simEvent = reportPtr;

    le_sim_NewStateHandlerFunc_t clientHandlerFunc = secondLayerHandlerFunc;

    clientHandlerFunc(simEvent->simId, simEvent->state, le_event_GetContextPtr());
}

//--------------------------------------------------------------------------------------------------
/**
 * Handler function for new SIM state notification.
 *
 */
//--------------------------------------------------------------------------------------------------
static void NewSimStateHandler
(
    pa_sim_Event_t* eventPtr
)
{
    Sim_t*           simPtr;
    Sim_Event_t      simEvent;

    LE_DEBUG("New SIM state.%d for sim identifier.%d (eventPtr %p)", eventPtr->state,
        eventPtr->simId, eventPtr);
    simPtr = &SimList[eventPtr->simId];
    GetSimCardInformation(simPtr, eventPtr->state);

    // Discard transitional states
    switch (eventPtr->state)
    {
        case LE_SIM_BUSY:
        case LE_SIM_STATE_UNKNOWN:
            LE_DEBUG("Discarding report for sim identifie.%d, state.%d",
                            eventPtr->simId, eventPtr->state);
            return;

        default:
            break;
    }

    if ( eventPtr->simId != SelectedCard )
    {
        LE_DEBUG("New selected card");
        SelectedCard = eventPtr->simId;
    }

    // Notify all the registered client handlers
    simEvent.simId = eventPtr->simId;
    simEvent.state = eventPtr->state;
    le_event_Report(NewSimStateEventId, &simEvent, sizeof(simEvent));
    LE_DEBUG("Report state %d on SIM Id %d", simEvent.state, simEvent.simId);

    le_mem_Release(eventPtr);
}

//--------------------------------------------------------------------------------------------------
/**
 * The first-layer SIM Toolkit events Handler.
 *
 */
//--------------------------------------------------------------------------------------------------
static void FirstLayerSimToolkitHandler
(
    void* reportPtr,
    void* secondLayerHandlerFunc
)
{
    pa_sim_StkEvent_t*                  stkEventPtr = reportPtr;
    le_sim_SimToolkitEventHandlerFunc_t clientHandlerFunc = secondLayerHandlerFunc;

    LE_DEBUG("Report stkEvent %d on SIM Id %d", stkEventPtr->stkEvent, stkEventPtr->simId);

    clientHandlerFunc(stkEventPtr->simId, stkEventPtr->stkEvent, le_event_GetContextPtr());
}

//--------------------------------------------------------------------------------------------------
/**
 * Handler function for SIM Toolkit events.
 *
 */
//--------------------------------------------------------------------------------------------------
static void SimToolkitHandler
(
    pa_sim_StkEvent_t* eventPtr
)
{
    LE_DEBUG("Report stkEvent %d on SIM Id %d", eventPtr->stkEvent, eventPtr->simId);
    le_event_Report(SimToolkitEventId, eventPtr, sizeof(pa_sim_StkEvent_t));
}

//--------------------------------------------------------------------------------------------------
/**
 * This function tests the SIM validity
 *
 * @return LE_OK            On success.
 * @return LE_NOT_FOUND     The function failed to select the SIM card for this operation.
 * @return LE_BAD_PARAMETER Invalid SIM identifier.
 * @return LE_FAULT         The function failed to get the number of remaining PIN insertion tries.
 */
//--------------------------------------------------------------------------------------------------
static le_result_t CheckSimValidity
(
    le_sim_Id_t simId   ///< [IN] The SIM identifier.
)
{
    Sim_t*    simPtr;
    if (simId >= LE_SIM_ID_MAX)
    {
        LE_ERROR("Invalid simId (%d) provided!", simId);
        return LE_BAD_PARAMETER;
    }

    if (LE_OK != SelectSIMCard(simId))
    {
        return LE_NOT_FOUND;
    }

    simPtr = &SimList[simId];

    if (!simPtr->isPresent)
    {
        return LE_NOT_FOUND;
    }

    return LE_OK;
}

//--------------------------------------------------------------------------------------------------
// APIs.
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
/**
 * This function must be called to initialize the SIM operations component
 *
 * @return LE_FAULT  The function failed.
 * @return LE_OK     The function succeed.
 */
//--------------------------------------------------------------------------------------------------
le_result_t le_sim_Init
(
    void
)
{
    int i;

    // Initialize the SIM list
    for (i = 0; i < LE_SIM_ID_MAX; i++)
    {
        SimList[i].simId = i;
        SimList[i].ICCID[0] = '\0';
        SimList[i].IMSI[0] = '\0';
        SimList[i].phoneNumber[0] = '\0';
        SimList[i].isPresent = false;
        SimList[i].Subscription = UNKNOWN_SUBSCRIPTION;
        GetSimCardInformation(&SimList[i], LE_SIM_ABSENT);
    }

    // Create an event Id for new SIM state notifications
    NewSimStateEventId = le_event_CreateId("NewSimStateEventId", sizeof(Sim_Event_t));

    // Create an event Id for SIM Toolkit notifications
    SimToolkitEventId = le_event_CreateId("SimToolkitEventId", sizeof(pa_sim_StkEvent_t));

    SimToolkitHandlerCount = 0;
    PaSimToolkitHandlerRef = NULL;

    // Register a handler function for new SIM state notification
    if (pa_sim_AddNewStateHandler(NewSimStateHandler) == NULL)
    {
        LE_CRIT("Add new SIM state handler failed");
        return LE_FAULT;
    }

    if (pa_sim_GetSelectedCard(&SelectedCard) != LE_OK)
    {
        LE_CRIT("Unable to get selected card.");
{'fraction_non_alphanumeric': 0.3685745108901653, 'fraction_numerical': 0.024083739102545413, 'mean_word_length': 0.944000453437624, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 84, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6531427', 'n_tokens_mistral': 9447, 'n_tokens_neox': 8606, 'n_words': 1977}