/*
Copyright © 1991-2021 Amebis
This file is part of MSICA.
MSICA is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
MSICA is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MSICA. If not, see .
*/
#include "pch.h"
namespace MSICA {
////////////////////////////////////////////////////////////////////////////
// COpWLANProfile
////////////////////////////////////////////////////////////////////////////
COpWLANProfile::COpWLANProfile(const GUID &guidInterface, LPCWSTR pszProfileName, int iTicks) :
COpTypeSingleString(pszProfileName, iTicks),
m_guidInterface(guidInterface)
{
}
////////////////////////////////////////////////////////////////////////////
// COpWLANProfileDelete
////////////////////////////////////////////////////////////////////////////
COpWLANProfileDelete::COpWLANProfileDelete(const GUID &guidInterface, LPCWSTR pszProfileName, int iTicks) : COpWLANProfile(guidInterface, pszProfileName, iTicks)
{
}
HRESULT COpWLANProfileDelete::Execute(CSession *pSession)
{
if (::pfnWlanOpenHandle && ::pfnWlanCloseHandle && ::pfnWlanGetProfile && ::pfnWlanDeleteProfile && ::pfnWlanFreeMemory) {
DWORD dwError, dwNegotiatedVersion;
HANDLE hClientHandle;
dwError = ::pfnWlanOpenHandle(2, NULL, &dwNegotiatedVersion, &hClientHandle);
if (dwError == NO_ERROR) {
if (pSession->m_bRollbackEnabled) {
LPWSTR pszProfileXML = NULL;
DWORD dwFlags = 0, dwGrantedAccess = 0;
// Get profile settings as XML first.
dwError = ::pfnWlanGetProfile(hClientHandle, &m_guidInterface, m_sValue.c_str(), NULL, &pszProfileXML, &dwFlags, &dwGrantedAccess);
if (dwError == NO_ERROR) {
// Delete the profile.
dwError = ::pfnWlanDeleteProfile(hClientHandle, &m_guidInterface, m_sValue.c_str(), NULL);
if (dwError == NO_ERROR) {
// Order rollback action to recreate it.
pSession->m_olRollback.push_front(new COpWLANProfileSet(m_guidInterface, dwFlags, m_sValue.c_str(), pszProfileXML));
}
::pfnWlanFreeMemory(pszProfileXML);
}
} else {
// Delete the profile.
dwError = ::pfnWlanDeleteProfile(hClientHandle, &m_guidInterface, m_sValue.c_str(), NULL);
}
::pfnWlanCloseHandle(hClientHandle, NULL);
}
if (dwError == NO_ERROR || dwError == ERROR_NOT_FOUND)
return S_OK;
else {
PMSIHANDLE hRecordProg = ::MsiCreateRecord(4);
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_PROFILE_DELETE );
::MsiRecordSetStringW(hRecordProg, 2, winstd::wstring_guid(m_guidInterface).c_str());
::MsiRecordSetStringW(hRecordProg, 3, m_sValue.c_str() );
::MsiRecordSetInteger(hRecordProg, 4, dwError );
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
return HRESULT_FROM_WIN32(dwError);
}
} else {
PMSIHANDLE hRecordProg = ::MsiCreateRecord(1);
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_NOT_INSTALLED);
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
return E_NOTIMPL;
}
}
////////////////////////////////////////////////////////////////////////////
// COpWLANProfileSet
////////////////////////////////////////////////////////////////////////////
COpWLANProfileSet::COpWLANProfileSet(const GUID &guidInterface, DWORD dwFlags, LPCWSTR pszProfileName, LPCWSTR pszProfileXML, int iTicks) :
COpWLANProfile(guidInterface, pszProfileName, iTicks),
m_dwFlags(dwFlags),
m_sProfileXML(pszProfileXML)
{
}
HRESULT COpWLANProfileSet::Execute(CSession *pSession)
{
if (::pfnWlanOpenHandle && ::pfnWlanCloseHandle && ::pfnWlanSetProfile && ::pfnWlanReasonCodeToString) {
DWORD dwError, dwNegotiatedVersion;
HANDLE hClientHandle;
WLAN_REASON_CODE wlrc = 0;
{
// Delete existing profile first.
// Since deleting a profile is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it.
// Don't worry, COpWLANProfileDelete::Execute() returns S_OK if profile doesn't exist.
COpWLANProfileDelete opDelete(m_guidInterface, m_sValue.c_str());
HRESULT hr = opDelete.Execute(pSession);
if (FAILED(hr)) return hr;
}
dwError = ::pfnWlanOpenHandle(2, NULL, &dwNegotiatedVersion, &hClientHandle);
if (dwError == NO_ERROR) {
// Set the profile.
dwError = ::pfnWlanSetProfile(hClientHandle, &m_guidInterface, m_dwFlags, m_sProfileXML.c_str(), NULL, TRUE, NULL, &wlrc);
if (dwError == NO_ERROR && pSession->m_bRollbackEnabled) {
// Order rollback action to delete it.
pSession->m_olRollback.push_front(new COpWLANProfileDelete(m_guidInterface, m_sValue.c_str()));
}
::pfnWlanCloseHandle(hClientHandle, NULL);
}
if (dwError == NO_ERROR)
return S_OK;
else {
PMSIHANDLE hRecordProg = ::MsiCreateRecord(5);
std::wstring sReason;
std::unique_ptr szBuffer(new WCHAR[1024]);
if (szBuffer && ::pfnWlanReasonCodeToString(wlrc, 1024, szBuffer.get(), NULL) == NO_ERROR)
sReason.assign(szBuffer.get(), wcsnlen(szBuffer.get(), 1024));
else
sprintf(sReason, L"0x%x", wlrc);
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_PROFILE_SET);
::MsiRecordSetStringW(hRecordProg, 2, winstd::wstring_guid(m_guidInterface).c_str());
::MsiRecordSetStringW(hRecordProg, 3, m_sValue.c_str() );
::MsiRecordSetStringW(hRecordProg, 4, sReason.c_str() );
::MsiRecordSetInteger(hRecordProg, 5, dwError );
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
return HRESULT_FROM_WIN32(dwError);
}
} else {
PMSIHANDLE hRecordProg = ::MsiCreateRecord(1);
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_NOT_INSTALLED);
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
return E_NOTIMPL;
}
}
} // namespace MSICA