/******************************************************************
   Copyright (c) 1999 Microsoft Corporation

   GotNet.CPP -- WMI provider class implementation

   Generated by Microsoft WMI Code Generation Engine
  
   TO DO: - See individual function headers
          - When linking, make sure you link to framedyd.lib & 
            msvcrtd.lib (debug) or framedyn.lib & msvcrt.lib (retail).

   Description: 
   
  
  
******************************************************************/

#include "stdpch.h"
#pragma hdrstop
#include "GotNet.h"

#include "host.h"   // CHost
#include "output.h" // COutput
#include "diag.h"

#include "oe.h"
#include "proxy.h"
#include "connect.h"    // ConnectToPort

// TO DO: Replace "NameSpace" with the appropriate namespace for your
//        provider instance.  For instance:  "root\\default or "root\\cimv2".
//===================================================================
//CGotNet MyGotNetSet (PROVIDER_NAME_GOTNET, L"root\\default") ;

// Property names
//===============

const static WCHAR* pid           = L"id" ;
const static WCHAR* pbIEProxy     = L"bIEProxy" ;
const static WCHAR* pIEProxy      = L"IEProxy" ;
const static WCHAR* pIEProxyPort  = L"IEProxyPort" ;

// Counts the number of times the com object is referenced
//
long g_nModuleRef = 0;

void 
AddRefModule() 
/*++

Routine Description
    This routine is counts the number of time the dll/COM is being refernce.
    Increments the ref count

Arguments
    none 

Return Value
    none

--*/
{
    InterlockedIncrement(&g_nModuleRef);
}

void 
ReleaseModule()
/*++

Routine Description
    This routine is decrements the ref count.

Arguments
    none 

Return Value
    none

--*/
{
    InterlockedDecrement(&g_nModuleRef);
}

/*****************************************************************************
 *
 *  FUNCTION    :   CGotNet::CGotNet
 *
 *  DESCRIPTION :   Constructor
 *
 *  INPUTS      :   none
 *
 *  RETURNS     :   nothing
 *
 *  COMMENTS    :   Calls the Provider constructor.
 *
 *****************************************************************************/
CGotNet::CGotNet ()
{
    AddRefModule();
}

/*****************************************************************************
 *
 *  FUNCTION    :   CGotNet::~CGotNet
 *
 *  DESCRIPTION :   Destructor
 *
 *  INPUTS      :   none
 *
 *  RETURNS     :   nothing
 *
 *  COMMENTS    : 
 *
 *****************************************************************************/
CGotNet::~CGotNet ()
{
    ReleaseModule();
}
//***************************************************************************
//
// CGotNet::QueryInterface
// CGotNet::AddRef
// CGotNet::Release
//
// Purpose: IUnknown members for CInstPro object.
//***************************************************************************


STDMETHODIMP CGotNet::QueryInterface(REFIID riid, LPVOID* ppv)
{
    *ppv=NULL;

    // Since we have dual inheritance, it is necessary to cast the return type

    if(riid== IID_IWbemServices)
       *ppv=(IWbemServices*)this;

    if(IID_IUnknown==riid || riid== IID_IWbemProviderInit)
       *ppv=(IWbemProviderInit*)this;
    

    if (NULL!=*ppv) {
        AddRef();
        return NOERROR;
        }
    else
        return E_NOINTERFACE;
  
}


STDMETHODIMP_(ULONG) CGotNet::AddRef(void)
{
    return ++m_cRef;
}

STDMETHODIMP_(ULONG) CGotNet::Release(void)
{
    ULONG nNewCount = InterlockedDecrement((long *)&m_cRef);
    if (0L == nNewCount)
        delete this;
    
    return nNewCount;
}

/***********************************************************************
*                                                                      *
*   CInstPro::Initialize                                                *
*                                                                      *
*   Purpose: This is the implementation of IWbemProviderInit. The method  *
*   is need to initialize with CIMOM.                                    *
*                                                                      *
***********************************************************************/

STDMETHODIMP CGotNet::Initialize(LPWSTR pszUser, LONG lFlags,
                                    LPWSTR pszNamespace, LPWSTR pszLocale,
                                    IWbemServices *pNamespace, 
                                    IWbemContext *pCtx,
                                    IWbemProviderInitSink *pInitSink)
{
    if(pNamespace)
        pNamespace->AddRef();

    m_pNamespace = pNamespace;

    //Let CIMOM know you are initialized
    //==================================
    
    pInitSink->SetStatus(WBEM_S_INITIALIZED,0);
    return WBEM_S_NO_ERROR;
}

//***************************************************************************
//
// CInstPro::CreateInstanceEnumAsync
//
// Purpose: Asynchronously enumerates the instances.  
//
//***************************************************************************

SCODE CGotNet::CreateInstanceEnumAsync( const BSTR RefStr, long lFlags, IWbemContext *pCtx,
       IWbemObjectSink FAR* pHandler)
{
    SCODE sc;
    int iCnt;
    IWbemClassObject FAR* pNewInst;
    HRESULT hr;

    // Do a check of arguments and make sure we have pointer to Namespace
    if(pHandler == NULL || m_pNamespace == NULL)
        return WBEM_E_INVALID_PARAMETER;

    hr = CoImpersonateClient();
    if( hr != S_OK )
    {
        return hr;
    }

    for(iCnt=0; iCnt < 1; iCnt++)
    {
        sc = CreateInst(
                m_pNamespace,
                &pNewInst,
                RefStr,
                pCtx);

        
        if(sc != S_OK)
            break;

        sc = AddProps(pNewInst);

        if(sc != S_OK)
            break;

        // Send the object to the caller

        pHandler->Indicate(1,&pNewInst);
        pNewInst->Release();
    }

    // Set status

    pHandler->SetStatus(0,sc,NULL, NULL);

    CoRevertToSelf();
    return sc;
}


//***************************************************************************
//
// CGotNet::GetObjectByPath
// CGetNet::GetObjectByPathAsync
//
// Purpose: Creates an instance given a particular path value.
//
//***************************************************************************
SCODE CGotNet::GetObjectAsync(const BSTR ObjectPath, long lFlags,IWbemContext  *pCtx,
                    IWbemObjectSink FAR* pHandler)
{

    SCODE sc;
    IWbemClassObject FAR* pObj;
    BOOL bOK = FALSE;

    // Do a check of arguments and make sure we have pointer to Namespace

    if(ObjectPath == NULL || pHandler == NULL || m_pNamespace == NULL)
        return WBEM_E_INVALID_PARAMETER;

    // do the get, pass the object on to the notify
    
    sc = GetByPath(ObjectPath,&pObj, pCtx);
    if(sc == S_OK) 
    {
        pHandler->Indicate(1,&pObj);
        pObj->Release();
        bOK = TRUE;
    }

    sc = (bOK) ? S_OK : WBEM_E_NOT_FOUND;

    // Set Status

    pHandler->SetStatus(0,sc, NULL, NULL);

    return sc;
}
 
//***************************************************************************
//
// CGotNet::GetByPath
//
// Purpose: Creates an instance given a particular Path value.
//
//***************************************************************************

SCODE
CGotNet::GetByPath(
    BSTR ObjectPath, 
    IWbemClassObject FAR* FAR* ppObj,
    IWbemContext  *pCtx)
{
    SCODE sc = S_OK;
    
    if(!_wcsicmp(L"NetDiagnostics=@", ObjectPath))
    {
        sc = CreateInst(
                m_pNamespace,
                ppObj, 
                L"NetDiagnostics", 
                pCtx);

        return sc;
    }

    return WBEM_E_NOT_FOUND;
}
 
HRESULT STDMETHODCALLTYPE
CGotNet::ExecMethodAsync(
    const BSTR ObjectPath, 
    const BSTR MethodName, 
    long lFlags, 
    IWbemContext* pCtx, 
    IWbemClassObject* pInParams, 
    IWbemObjectSink* pResultSink)
{
    if(0 == _wcsicmp(MethodName, L"Ping"))
    {
        return WMIPing(lFlags, pCtx, pInParams, pResultSink);
    }
    else if (0 == _wcsicmp(MethodName, L"ConnectToPort"))
    {
        return WMIConnectToPort(lFlags, pCtx, pInParams, pResultSink);
    }
    else
    {
        return WBEM_E_INVALID_PARAMETER;
    }
}

HRESULT CGotNet::WMIPing(
        long lFlags, 
        IWbemContext* pCtx, 
        IWbemClassObject* pInParams, 
        IWbemObjectSink* pResultSink)
{
    HRESULT hr;    
    IWbemClassObject * pClass = NULL;
    IWbemClassObject * pOutClass = NULL;    
    IWbemClassObject* pOutParams = NULL;
    TEST_INFO ping;
    CHost host;
    char buffer[100];
    WSADATA wsa;

    WSAStartup(MAKEWORD(2,1), &wsa);


    hr = CoImpersonateClient();
    if( hr != S_OK )
    {
        WSACleanup();	
        return hr;
    }


    // Allocate some BSTRs
    
    BSTR ClassName = SysAllocString(L"NetDiagnostics");    
    BSTR InputArgName = SysAllocString(L"sInAddr");
    BSTR OutputArgName = SysAllocString(L"sOutArg");
    BSTR retValName = SysAllocString(L"ReturnValue");

    // Get the class object, this is hard coded and matches the class
    // in the MOF.  A more sophisticated example would parse the 
    // ObjectPath to determine the class and possibly the instance.

    hr = m_pNamespace->GetObject(ClassName, 0, pCtx, &pClass, NULL);
	if(hr != S_OK)
	{
		pResultSink->SetStatus(0,hr, NULL, NULL);
        WSACleanup();	
        CoRevertToSelf();	  
        return WBEM_S_NO_ERROR;
	}
 

    // This method returns values, and so create an instance of the
    // output argument class.

    hr = pClass->GetMethod(L"Ping", 0, NULL, &pOutClass);
    pOutClass->SpawnInstance(0, &pOutParams);

    // Copy the input argument into the output object    
    
    auto_var var;

    // Get the input argument
    pInParams->Get(InputArgName, 0, &var, NULL, NULL);   

    wcstombs(buffer, var.bstrVal, 100);
    ping.host.SetHost(buffer);
    CheckPing(&ping);
    WaitForSingleObject(ping.hEvent, INFINITE);

    
    // put it into the output object
    _variant_t v ((bool)(ping.dwErr == S_OK));

    pOutParams->Put(retValName , 0, &v, 0);      

    v = ping.output.Status();
    pOutParams->Put(OutputArgName , 0, &v, 0); 

    // Send the output object back to the client via the sink. Then 
    // release the pointers and free the strings.

    hr = pResultSink->Indicate(1, &pOutParams);    
    pOutParams->Release();
    pOutClass->Release();    
    pClass->Release();    
    SysFreeString(ClassName);
    SysFreeString(InputArgName);    
    SysFreeString(OutputArgName);
    SysFreeString(retValName);     
    
    // all done now, set the status
    hr = pResultSink->SetStatus(0,WBEM_S_NO_ERROR,NULL,NULL);
    CoRevertToSelf();

    WSACleanup();
    return WBEM_S_NO_ERROR;

}

HRESULT CGotNet::WMIConnectToPort(
    long lFlags, 
    IWbemContext* pCtx, 
    IWbemClassObject* pInParams, 
    IWbemObjectSink* pResultSink)
{
    HRESULT hr;    
    IWbemClassObject * pClass = NULL;
    IWbemClassObject * pOutClass = NULL;    
    IWbemClassObject* pOutParams = NULL;
    TEST_INFO ping;
    CHost host;
    char buffer[100];
    bool bConnect = false;

    hr = CoImpersonateClient();
    if( hr != S_OK )
    {
        return hr;
    }

    // Allocate some BSTRs
    
    BSTR ClassName = SysAllocString(L"NetDiagnostics");    
    BSTR AddrArgName = SysAllocString(L"sInAddr");
    BSTR PortArgName = SysAllocString(L"port");
    BSTR OutputArgName = SysAllocString(L"sOutArg");
    BSTR retValName = SysAllocString(L"ReturnValue");

    // Get the class object, this is hard coded and matches the class
    // in the MOF.  A more sophisticated example would parse the 
    // ObjectPath to determine the class and possibly the instance.

    hr = m_pNamespace->GetObject(ClassName, 0, pCtx, &pClass, NULL);
	if(hr != S_OK)
	{
		pResultSink->SetStatus(0,hr, NULL, NULL);
        CoRevertToSelf();
		
        return WBEM_S_NO_ERROR;
	}
 

    // This method returns values, and so create an instance of the
    // output argument class.

    hr = pClass->GetMethod(L"ConnectToPort", 0, NULL, &pOutClass);
    pOutClass->SpawnInstance(0, &pOutParams);

    // Copy the input argument into the output object    
    
    auto_var addr;
    auto_var port;
    
    // Get the input argument
    pInParams->Get(AddrArgName, 0, &addr, NULL, NULL);   
    pInParams->Get(PortArgName, 0, &port, NULL, NULL);   

    wcstombs(buffer, addr.bstrVal, 100);

    host.SetHost(buffer);

    Connect(host, port.lVal, bConnect);
    
    // put it into the output object
    _variant_t v (bConnect);

    pOutParams->Put(retValName , 0, &v, 0);      

    v = ping.output.Status();
    pOutParams->Put(OutputArgName , 0, &v, 0); 

    // Send the output object back to the client via the sink. Then 
    // release the pointers and free the strings.

    hr = pResultSink->Indicate(1, &pOutParams);    
    pOutParams->Release();
    pOutClass->Release();    
    pClass->Release();    
    SysFreeString(ClassName);
    SysFreeString(AddrArgName);    
    SysFreeString(PortArgName);    
    SysFreeString(OutputArgName);
    SysFreeString(retValName);     
    
    // all done now, set the status
    hr = pResultSink->SetStatus(0,WBEM_S_NO_ERROR,NULL,NULL);
    CoRevertToSelf();

    return WBEM_S_NO_ERROR;
}


HRESULT CGotNet::AddProps(IWbemClassObject* pInstance)
{
    HRESULT hRes = WBEM_S_NO_ERROR;
    CHost host;
    DWORD dwPort = 0;
    DWORD dwProxyPort = 0;
    DWORD dwProxyEnabled = 0;
    _variant_t v;

    v.Clear();
/*
    //
    // Grab all the mail server information
    ///////////////////////////////////////

    CHost InBoundMailHost, OutBoundMailHost;
    DWORD dwInBoundPort, dwOutBoundPort;
    WCHAR wszInBoundMailType, wszOutBoundMailType;

    hRes = GetOEDefaultMailServer(InBoundMailHost,  
                                  dwInBoundPort, 
                                  wszInBoundMailType,
                                  OutBoundMailHost, 
                                  dwOutBoundPort,
                                  wszOutBoundMailType);
    if( SUCCEEDED(hRes) )
    {
        v = InBoundMailHost.GetHost();
        pInstance->Put(pInBoundMailServer, 0, &v, 0);      

        v = (long)dwInBoundPort;
        pInstance->Put(pInBoundMailPort, 0, &v, 0);

        v = wszInBoundMailType
        pInstance->Put(pInBoundMailType, 0, &v, 0);      


        v = OutBoundMailHost.GetHost();
        pInstance->Put(pOutBoundMailServer, 0, &v, 0);      

        v = (long)dwOutBoundPort;
        pInstance->Put(pOutBoundMailPort, 0, &v, 0);

        v = wszOutBoundMailType
        pInstance->Put(pOutBoundMailType, 0, &v, 0);      

    }
*/
    //
    // Grab all the news server information
    ///////////////////////////////////////
    v.Clear();
    hRes = GetOEDefaultNewsServer(host, dwPort);
    v = host.GetHost();
    pInstance->Put(pNewsServer,  0, &v, 0);
    
    v = (long)dwPort;
    pInstance->Put(pNewsNNTPPort, 0, &v, 0);
    

    v.Clear();
    if (FindProxy(&host, &dwProxyPort, &dwProxyEnabled))
    {
        v = (bool)(dwProxyEnabled == TRUE);
        pInstance->Put(pbIEProxy, 0, &v, 0);

        v.Clear();
        v = host.GetHost();
        pInstance->Put(pIEProxy, 0, &v, 0);

        v.Clear();
        v = (long)dwProxyPort;
        pInstance->Put(pIEProxyPort, 0, &v, 0);
    }
    else
    {
        v = (bool)FALSE;
        pInstance->Put(pbIEProxy, 0, &v, 0);
        pInstance->Put(pIEProxy, 0, NULL, 0);
        pInstance->Put(pIEProxyPort, 0, NULL, 0);
    }
    
    return hRes;
}
