/*++

Copyright (c) 1996 Microsoft Corporation

Module Name:

    tcnotify.c

Abstract:

    This module contains the notification interaction with WMI

Author:

    Shreedhar Madhavapeddi ( shreem )   Jan 12, 1999.

Revision History:

--*/

#include "precomp.h"


int 
IsEqualGUIDx(
                LPGUID guid1, 
                LPGUID guid2
                )
{
    return !memcmp(guid1, guid2, sizeof(GUID));
}

//
// Add the guid/ifchandle to the NotificationList.
// Although it shouldn't happen - check for dupes before adding it.
// Interface handle leads to Client handle 
// 
ULONG
TcipAddToNotificationList(
                          IN LPGUID             Guid,
                          IN PINTERFACE_STRUC   IfcHandle,
                          IN ULONG              Flags        
                          )
{
    PLIST_ENTRY             pCurrent;
    PNOTIFICATION_ELEMENT   pNotifyElem, pNewElem;
    int i = 0;
    //
    // Take the List Lock.
    // 
    pNotifyElem = NULL;
    GetLock(NotificationListLock);
    pCurrent = NotificationListHead.Flink;

    while (&NotificationListHead != pCurrent) {
        
        pNotifyElem = CONTAINING_RECORD(pCurrent, NOTIFICATION_ELEMENT, Linkage.Flink);
        
        if ((pNotifyElem->IfcHandle != IfcHandle) || 
            (FALSE == IsEqualGUIDx(&pNotifyElem->NotificationGuid, Guid))) {
            
            pCurrent = pNotifyElem->Linkage.Flink;

        } else {
            
            //
            // We found a guid/ifchandle combo already!
            
            //DEBUGBREAK();
            goto exit;

        }

        
    }

    //
    // If we are here, we couldnt find the GUID/IfcHAndle combo
    // Allocate a new element and add it to the list, return TRUE;
    //
    
    AllocMem(&pNewElem, sizeof(NOTIFICATION_ELEMENT));
    if (!pNewElem) {
        
        // cant alloc memory;
        goto exit;

    }
    pNewElem->IfcHandle = IfcHandle;
    pNewElem->NotificationGuid      = *Guid;

    InsertHeadList(&NotificationListHead, &pNewElem->Linkage);
    FreeLock(NotificationListLock);
    return TRUE;

exit:

    FreeLock(NotificationListLock);
    return FALSE;
}

//
// Remove the guid/ifchandle from the NotificationListHead.
// If DBG - check for more than one entries.
// 
ULONG
TcipDeleteFromNotificationList(
                             IN LPGUID              Guid,
                             IN PINTERFACE_STRUC    IfcHandle,
                             IN ULONG               Flags        
                             )
{

    PLIST_ENTRY             pCurrent;
    PNOTIFICATION_ELEMENT   pNotifyElem;


    pNotifyElem = NULL;

    GetLock(NotificationListLock);
    pCurrent = NotificationListHead.Flink;

    while (&NotificationListHead != pCurrent) {

        pNotifyElem = CONTAINING_RECORD(pCurrent, NOTIFICATION_ELEMENT, Linkage.Flink);
        
        if ((pNotifyElem->IfcHandle == IfcHandle) && 
            (TRUE == IsEqualGUIDx(&pNotifyElem->NotificationGuid, Guid))) {
            
            //
            // We found the guid/ifchandle combo - remove it.
            RemoveEntryList(&pNotifyElem->Linkage);
            FreeMem(pNotifyElem);
            break;



        } else {

            pCurrent = pNotifyElem->Linkage.Flink;            

        }

    }

    FreeLock(NotificationListLock);
    return TRUE;

}

// Take a Interface & GUID that has a notification from WMI, and
// find if this Client registered to be notified.
ULONG
TcipClientRegisteredForNotification(
                            IN LPGUID               Guid,
                            IN PINTERFACE_STRUC     IfcHandle,
                            IN ULONG                Flags        
                            )
{
    PLIST_ENTRY             pCurrent;
    PNOTIFICATION_ELEMENT   pNotifyElem;

    pNotifyElem = NULL;

    // make sure the list doesn't change under us.
    GetLock(NotificationListLock);
    pCurrent = NotificationListHead.Flink;

    while (&NotificationListHead != pCurrent) {
        
        pNotifyElem = CONTAINING_RECORD(pCurrent, NOTIFICATION_ELEMENT, Linkage.Flink);
        
        if ((pNotifyElem->IfcHandle == IfcHandle) && 
            (IsEqualGUIDx(&pNotifyElem->NotificationGuid, Guid))) {

            FreeLock(NotificationListLock);
            return TRUE;
        }

        pCurrent = pNotifyElem->Linkage.Flink;
    
    }

    FreeLock(NotificationListLock);

    return FALSE;

}

//
// Remove the guid/ifchandle from the NotificationListHead.
// 
ULONG
TcipDeleteInterfaceFromNotificationList(
                                        IN PINTERFACE_STRUC    IfcHandle,
                                        IN ULONG               Flags        
                                        )
{

    PLIST_ENTRY             pCurrent;
    PNOTIFICATION_ELEMENT   pNotifyElem;

    pNotifyElem = NULL;
    ASSERT(IfcHandle);
    
    GetLock(NotificationListLock);
    pCurrent = NotificationListHead.Flink;

    while (&NotificationListHead != pCurrent) {

        pNotifyElem = CONTAINING_RECORD(pCurrent, NOTIFICATION_ELEMENT, Linkage.Flink);
        
        if (pNotifyElem->IfcHandle == IfcHandle) {
            
            pCurrent = pNotifyElem->Linkage.Flink;            
            
            //
            // We found the guid/ifchandle combo - remove it.
            RemoveEntryList(&pNotifyElem->Linkage);
            FreeMem(pNotifyElem);

        } else {

            pCurrent = pNotifyElem->Linkage.Flink;            

        }

    }


    FreeLock(NotificationListLock);
    return TRUE;

}