<commit_before>#include "binaryninjaapi.h"

using namespace BinaryNinja;
using namespace std;

ScriptingOutputListener::ScriptingOutputListener()
{
	m_callbacks.context = this;
	m_callbacks.output = OutputCallback;
	m_callbacks.error = ErrorCallback;
	m_callbacks.inputReadyStateChanged = InputReadyStateChangedCallback;
}

void ScriptingOutputListener::OutputCallback(void* ctxt, const char* text)
{
	ScriptingOutputListener* listener = (ScriptingOutputListener*)ctxt;
	listener->NotifyOutput(text);
}

void ScriptingOutputListener::ErrorCallback(void* ctxt, const char* text)
{
	ScriptingOutputListener* listener = (ScriptingOutputListener*)ctxt;
	listener->NotifyError(text);
}

void ScriptingOutputListener::InputReadyStateChangedCallback(void* ctxt, BNScriptingProviderInputReadyState state)
{
	ScriptingOutputListener* listener = (ScriptingOutputListener*)ctxt;
	listener->NotifyInputReadyStateChanged(state);
}

void ScriptingOutputListener::NotifyOutput(const string&) {}

void ScriptingOutputListener::NotifyError(const string&) {}

void ScriptingOutputListener::NotifyInputReadyStateChanged(BNScriptingProviderInputReadyState) {}

ScriptingInstance::ScriptingInstance(ScriptingProvider* provider)
{
	BNScriptingInstanceCallbacks cb;
	cb.context = this;
	cb.destroyInstance = DestroyInstanceCallback;
	cb.externalRefTaken = nullptr;
	cb.externalRefReleased = nullptr;
	cb.executeScriptInput = ExecuteScriptInputCallback;
	cb.cancelScriptInput = CancelScriptInputCallback;
	cb.setCurrentBinaryView = SetCurrentBinaryViewCallback;
	cb.setCurrentFunction = SetCurrentFunctionCallback;
	cb.setCurrentBasicBlock = SetCurrentBasicBlockCallback;
	cb.setCurrentAddress = SetCurrentAddressCallback;
	cb.setCurrentSelection = SetCurrentSelectionCallback;
	cb.completeInput = CompleteInputCallback;
	cb.stop = StopCallback;
	AddRefForRegistration();
	m_object = BNInitScriptingInstance(provider->GetObject(), &cb);
}

ScriptingInstance::ScriptingInstance(BNScriptingInstance* instance)
{
	m_object = instance;
}

void ScriptingInstance::DestroyInstanceCallback(void* ctxt)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->DestroyInstance();
}

BNScriptingProviderExecuteResult ScriptingInstance::ExecuteScriptInputCallback(void* ctxt, const char* input)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	return instance->ExecuteScriptInput(input);
}

void ScriptingInstance::CancelScriptInputCallback(void* ctxt)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->CancelScriptInput();
}

void ScriptingInstance::SetCurrentBinaryViewCallback(void* ctxt, BNBinaryView* view)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->SetCurrentBinaryView(view ? new BinaryView(BNNewViewReference(view)) : nullptr);
}

void ScriptingInstance::SetCurrentFunctionCallback(void* ctxt, BNFunction* func)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->SetCurrentFunction(func ? new Function(BNNewFunctionReference(func)) : nullptr);
}

void ScriptingInstance::SetCurrentBasicBlockCallback(void* ctxt, BNBasicBlock* block)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->SetCurrentBasicBlock(block ? new BasicBlock(BNNewBasicBlockReference(block)) : nullptr);
}

void ScriptingInstance::SetCurrentAddressCallback(void* ctxt, uint64_t addr)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->SetCurrentAddress(addr);
}

void ScriptingInstance::SetCurrentSelectionCallback(void* ctxt, uint64_t begin, uint64_t end)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->SetCurrentSelection(begin, end);
}

char* ScriptingInstance::CompleteInputCallback(void* ctxt, const char* text, uint64_t state)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	std::string completed = instance->CompleteInput(text, state);
	if (completed.c_str() == nullptr)
	{
		LogWarn("ScriptingInstance::CompleteInput returned nullptr; replacing with empty string.");
		completed = "";
	}
	return BNAllocString(completed.c_str());
}

void ScriptingInstance::StopCallback(void* ctxt)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->Stop();
}

void ScriptingInstance::DestroyInstance()
{
	ReleaseForRegistration();
}

void ScriptingInstance::CancelScriptInput() {}

void ScriptingInstance::SetCurrentBinaryView(BinaryView*) {}

void ScriptingInstance::SetCurrentFunction(Function*) {}

void ScriptingInstance::SetCurrentBasicBlock(BasicBlock*) {}

void ScriptingInstance::SetCurrentAddress(uint64_t) {}

void ScriptingInstance::SetCurrentSelection(uint64_t, uint64_t) {}

std::string ScriptingInstance::CompleteInput(const std::string&, uint64_t)
{
	return "";
}

void ScriptingInstance::Output(const string& text)
{
	BNNotifyOutputForScriptingInstance(m_object, text.c_str());
}

void ScriptingInstance::Error(const string& text)
{
	BNNotifyErrorForScriptingInstance(m_object, text.c_str());
}

void ScriptingInstance::InputReadyStateChanged(BNScriptingProviderInputReadyState state)
{
	BNNotifyInputReadyStateForScriptingInstance(m_object, state);
}

BNScriptingProviderInputReadyState ScriptingInstance::GetInputReadyState()
{
	return BNGetScriptingInstanceInputReadyState(m_object);
}

void ScriptingInstance::RegisterOutputListener(ScriptingOutputListener* listener)
{
	BNRegisterScriptingInstanceOutputListener(m_object, &listener->GetCallbacks());
}

void ScriptingInstance::UnregisterOutputListener(ScriptingOutputListener* listener)
{
	BNUnregisterScriptingInstanceOutputListener(m_object, &listener->GetCallbacks());
}

std::string ScriptingInstance::GetDelimiters()
{
	return BNGetScriptingInstanceDelimiters(m_object);
}

void ScriptingInstance::SetDelimiters(const std::string& delimiters)
{
	BNSetScriptingInstanceDelimiters(m_object, delimiters.c_str());
}

void ScriptingInstance::Stop() {}

CoreScriptingInstance::CoreScriptingInstance(BNScriptingInstance* instance) : ScriptingInstance(instance) {}

BNScriptingProviderExecuteResult CoreScriptingInstance::ExecuteScriptInput(const string& input)
{
	return BNExecuteScriptInput(m_object, input.c_str());
}

BNScriptingProviderExecuteResult CoreScriptingInstance::ExecuteScriptInputFromFilename(const string& filename)
{
	return BNExecuteScriptInputFromFilename(m_object, filename.c_str());
}

void CoreScriptingInstance::CancelScriptInput()
{
	BNCancelScriptInput(m_object);
}

void CoreScriptingInstance::SetCurrentBinaryView(BinaryView* view)
{
	BNSetScriptingInstanceCurrentBinaryView(m_object, view ? view->GetObject() : nullptr);
}

void CoreScriptingInstance::SetCurrentFunction(Function* func)
{
	BNSetScriptingInstanceCurrentFunction(m_object, func ? func->GetObject() : nullptr);
}

void CoreScriptingInstance::SetCurrentBasicBlock(BasicBlock* block)
{
	BNSetScriptingInstanceCurrentBasicBlock(m_object, block ? block->GetObject() : nullptr);
}

void CoreScriptingInstance::SetCurrentAddress(uint64_t addr)
{
	BNSetScriptingInstanceCurrentAddress(m_object, addr);
}

void CoreScriptingInstance::SetCurrentSelection(uint64_t begin, uint64_t end)
{
	BNSetScriptingInstanceCurrentSelection(m_object, begin, end);
}

std::string CoreScriptingInstance::CompleteInput(const std::string& text, uint64_t state)
{
	char* result = BNScriptingInstanceCompleteInput(m_object, text.c_str(), state);
	std::string ret = result;
	BNFreeString(result);
	return ret;
}

void CoreScriptingInstance::Stop()
{
	BNStopScriptingInstance(m_object);
}

ScriptingProvider::ScriptingProvider(const string& name, const string& apiName) :
    m_nameForRegister(name), m_apiNameForRegister(apiName)
{}

ScriptingProvider::ScriptingProvider(BNScriptingProvider* provider)
{
	m_object = provider;
}

BNScriptingInstance* ScriptingProvider::CreateInstanceCallback(void* ctxt)
{
	ScriptingProvider* provider = (ScriptingProvider*)ctxt;
	Ref<ScriptingInstance> instance = provider->CreateNewInstance();
	return instance ? BNNewScriptingInstanceReference(instance->GetObject()) : nullptr;
}

bool ScriptingProvider::LoadModuleCallback(void* ctxt, const char* repository, const char* module, bool force)
{
	ScriptingProvider* provider = (ScriptingProvider*)ctxt;
	return BNLoadScriptingProviderModule(provider->GetObject(), repository, module, force);
}

bool ScriptingProvider::InstallModulesCallback(void* ctxt, const char* modules)
{
	ScriptingProvider* provider = (ScriptingProvider*)ctxt;
	return BNInstallScriptingProviderModules(provider->GetObject(), modules);
}

string ScriptingProvider::GetName()
{
	char* providerNameRaw = BNGetScriptingProviderName(m_object);
	string providerName(providerNameRaw);
	BNFreeString(providerNameRaw);
	return providerName;
}

string ScriptingProvider::GetAPIName()
{
	char* providerNameRaw = BNGetScriptingProviderAPIName(m_object);
	string providerName(providerNameRaw);
	BNFreeString(providerNameRaw);
	return providerName;
}

vector<Ref<ScriptingProvider>> ScriptingProvider::GetList()
{
	size_t count;
	BNScriptingProvider** list = BNGetScriptingProviderList(&count);
	vector<Ref<ScriptingProvider>> result;
	for (size_t i = 0; i < count; i++)
		result.push_back(new CoreScriptingProvider(list[i]));
	BNFreeScriptingProviderList(list);
	return result;
}

Ref<ScriptingProvider> ScriptingProvider::GetByName(const string& name)
{
	BNScriptingProvider* result = BNGetScriptingProviderByName(name.c_str());
	if (!result)
		return nullptr;
	return new CoreScriptingProvider(result);
}

Ref<ScriptingProvider> ScriptingProvider::GetByAPIName(const string& name)
{
	BNScriptingProvider* result = BNGetScriptingProviderByAPIName(name.c_str());
	if (!result)
		return nullptr;
	return new CoreScriptingProvider(result);
}

void ScriptingProvider::Register(ScriptingProvider* provider)
{
	BNScriptingProviderCallbacks cb;
	cb.context = provider;
	cb.createInstance = CreateInstanceCallback;
	cb.loadModule = LoadModuleCallback;
	cb.installModules = InstallModulesCallback;
	provider->m_object =
	    BNRegisterScriptingProvider(provider->m_nameForRegister.c_str(), provider->m_apiNameForRegister.c_str(), &cb);
}

CoreScriptingProvider::CoreScriptingProvider(BNScriptingProvider* provider) : ScriptingProvider(provider) {}

Ref<ScriptingInstance> CoreScriptingProvider::CreateNewInstance()
{
	BNScriptingInstance* result = BNCreateScriptingProviderInstance(m_object);
	if (!result)
		return nullptr;
	return new CoreScriptingInstance(result);
}

bool CoreScriptingProvider::LoadModule(const std::string& repository, const std::string& module, bool force)
{
	return BNLoadScriptingProviderModule(m_object, repository.c_str(), module.c_str(), force);
}

bool CoreScriptingProvider::InstallModules(const std::string& modules)
{
	return BNInstallScriptingProviderModules(m_object, modules.c_str());
}
<commit_msg>Fix memory leak issue related to ScriptingInstance. Close https://github.com/Vector35/binaryninja-api/issues/3461.<commit_after>#include "binaryninjaapi.h"

using namespace BinaryNinja;
using namespace std;

ScriptingOutputListener::ScriptingOutputListener()
{
	m_callbacks.context = this;
	m_callbacks.output = OutputCallback;
	m_callbacks.error = ErrorCallback;
	m_callbacks.inputReadyStateChanged = InputReadyStateChangedCallback;
}

void ScriptingOutputListener::OutputCallback(void* ctxt, const char* text)
{
	ScriptingOutputListener* listener = (ScriptingOutputListener*)ctxt;
	listener->NotifyOutput(text);
}

void ScriptingOutputListener::ErrorCallback(void* ctxt, const char* text)
{
	ScriptingOutputListener* listener = (ScriptingOutputListener*)ctxt;
	listener->NotifyError(text);
}

void ScriptingOutputListener::InputReadyStateChangedCallback(void* ctxt, BNScriptingProviderInputReadyState state)
{
	ScriptingOutputListener* listener = (ScriptingOutputListener*)ctxt;
	listener->NotifyInputReadyStateChanged(state);
}

void ScriptingOutputListener::NotifyOutput(const string&) {}

void ScriptingOutputListener::NotifyError(const string&) {}

void ScriptingOutputListener::NotifyInputReadyStateChanged(BNScriptingProviderInputReadyState) {}

ScriptingInstance::ScriptingInstance(ScriptingProvider* provider)
{
	BNScriptingInstanceCallbacks cb;
	cb.context = this;
	cb.destroyInstance = DestroyInstanceCallback;
	cb.externalRefTaken = nullptr;
	cb.externalRefReleased = nullptr;
	cb.executeScriptInput = ExecuteScriptInputCallback;
	cb.cancelScriptInput = CancelScriptInputCallback;
	cb.setCurrentBinaryView = SetCurrentBinaryViewCallback;
	cb.setCurrentFunction = SetCurrentFunctionCallback;
	cb.setCurrentBasicBlock = SetCurrentBasicBlockCallback;
	cb.setCurrentAddress = SetCurrentAddressCallback;
	cb.setCurrentSelection = SetCurrentSelectionCallback;
	cb.completeInput = CompleteInputCallback;
	cb.stop = StopCallback;
	AddRefForRegistration();
	m_object = BNInitScriptingInstance(provider->GetObject(), &cb);
}

ScriptingInstance::ScriptingInstance(BNScriptingInstance* instance)
{
	m_object = instance;
}

void ScriptingInstance::DestroyInstanceCallback(void* ctxt)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->DestroyInstance();
}

BNScriptingProviderExecuteResult ScriptingInstance::ExecuteScriptInputCallback(void* ctxt, const char* input)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	return instance->ExecuteScriptInput(input);
}

void ScriptingInstance::CancelScriptInputCallback(void* ctxt)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->CancelScriptInput();
}

void ScriptingInstance::SetCurrentBinaryViewCallback(void* ctxt, BNBinaryView* view)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	Ref<BinaryView> object = view ? new BinaryView(BNNewViewReference(view)) : nullptr;
	instance->SetCurrentBinaryView(object);
}

void ScriptingInstance::SetCurrentFunctionCallback(void* ctxt, BNFunction* func)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	Ref<Function> object = func ? new Function(BNNewFunctionReference(func)) : nullptr;
	instance->SetCurrentFunction(object);
}

void ScriptingInstance::SetCurrentBasicBlockCallback(void* ctxt, BNBasicBlock* block)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	Ref<BasicBlock> object = block ? new BasicBlock(BNNewBasicBlockReference(block)) : nullptr;
	instance->SetCurrentBasicBlock(object);
}

void ScriptingInstance::SetCurrentAddressCallback(void* ctxt, uint64_t addr)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->SetCurrentAddress(addr);
}

void ScriptingInstance::SetCurrentSelectionCallback(void* ctxt, uint64_t begin, uint64_t end)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->SetCurrentSelection(begin, end);
}

char* ScriptingInstance::CompleteInputCallback(void* ctxt, const char* text, uint64_t state)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	std::string completed = instance->CompleteInput(text, state);
	if (completed.c_str() == nullptr)
	{
		LogWarn("ScriptingInstance::CompleteInput returned nullptr; replacing with empty string.");
		completed = "";
	}
	return BNAllocString(completed.c_str());
}

void ScriptingInstance::StopCallback(void* ctxt)
{
	ScriptingInstance* instance = (ScriptingInstance*)ctxt;
	instance->Stop();
}

void ScriptingInstance::DestroyInstance()
{
	ReleaseForRegistration();
}

void ScriptingInstance::CancelScriptInput() {}

void ScriptingInstance::SetCurrentBinaryView(BinaryView*) {}

void ScriptingInstance::SetCurrentFunction(Function*) {}

void ScriptingInstance::SetCurrentBasicBlock(BasicBlock*) {}

void ScriptingInstance::SetCurrentAddress(uint64_t) {}

void ScriptingInstance::SetCurrentSelection(uint64_t, uint64_t) {}

std::string ScriptingInstance::CompleteInput(const std::string&, uint64_t)
{
	return "";
}

void ScriptingInstance::Output(const string& text)
{
	BNNotifyOutputForScriptingInstance(m_object, text.c_str());
}

void ScriptingInstance::Error(const string& text)
{
	BNNotifyErrorForScriptingInstance(m_object, text.c_str());
}

void ScriptingInstance::InputReadyStateChanged(BNScriptingProviderInputReadyState state)
{
	BNNotifyInputReadyStateForScriptingInstance(m_object, state);
}

BNScriptingProviderInputReadyState ScriptingInstance::GetInputReadyState()
{
	return BNGetScriptingInstanceInputReadyState(m_object);
}

void ScriptingInstance::RegisterOutputListener(ScriptingOutputListener* listener)
{
	BNRegisterScriptingInstanceOutputListener(m_object, &listener->GetCallbacks());
}

void ScriptingInstance::UnregisterOutputListener(ScriptingOutputListener* listener)
{
	BNUnregisterScriptingInstanceOutputListener(m_object, &listener->GetCallbacks());
}

std::string ScriptingInstance::GetDelimiters()
{
	return BNGetScriptingInstanceDelimiters(m_object);
}

void ScriptingInstance::SetDelimiters(const std::string& delimiters)
{
	BNSetScriptingInstanceDelimiters(m_object, delimiters.c_str());
}

void ScriptingInstance::Stop() {}

CoreScriptingInstance::CoreScriptingInstance(BNScriptingInstance* instance) : ScriptingInstance(instance) {}

BNScriptingProviderExecuteResult CoreScriptingInstance::ExecuteScriptInput(const string& input)
{
	return BNExecuteScriptInput(m_object, input.c_str());
}

BNScriptingProviderExecuteResult CoreScriptingInstance::ExecuteScriptInputFromFilename(const string& filename)
{
	return BNExecuteScriptInputFromFilename(m_object, filename.c_str());
}

void CoreScriptingInstance::CancelScriptInput()
{
	BNCancelScriptInput(m_object);
}

void CoreScriptingInstance::SetCurrentBinaryView(BinaryView* view)
{
	BNSetScriptingInstanceCurrentBinaryView(m_object, view ? view->GetObject() : nullptr);
}

void CoreScriptingInstance::SetCurrentFunction(Function* func)
{
	BNSetScriptingInstanceCurrentFunction(m_object, func ? func->GetObject() : nullptr);
}

void CoreScriptingInstance::SetCurrentBasicBlock(BasicBlock* block)
{
	BNSetScriptingInstanceCurrentBasicBlock(m_object, block ? block->GetObject() : nullptr);
}

void CoreScriptingInstance::SetCurrentAddress(uint64_t addr)
{
	BNSetScriptingInstanceCurrentAddress(m_object, addr);
}

void CoreScriptingInstance::SetCurrentSelection(uint64_t begin, uint64_t end)
{
	BNSetScriptingInstanceCurrentSelection(m_object, begin, end);
}

std::string CoreScriptingInstance::CompleteInput(const std::string& text, uint64_t state)
{
	char* result = BNScriptingInstanceCompleteInput(m_object, text.c_str(), state);
	std::string ret = result;
	BNFreeString(result);
	return ret;
}

void CoreScriptingInstance::Stop()
{
	BNStopScriptingInstance(m_object);
}

ScriptingProvider::ScriptingProvider(const string& name, const string& apiName) :
    m_nameForRegister(name), m_apiNameForRegister(apiName)
{}

ScriptingProvider::ScriptingProvider(BNScriptingProvider* provider)
{
	m_object = provider;
}

BNScriptingInstance* ScriptingProvider::CreateInstanceCallback(void* ctxt)
{
	ScriptingProvider* provider = (ScriptingProvider*)ctxt;
	Ref<ScriptingInstance> instance = provider->CreateNewInstance();
	return instance ? BNNewScriptingInstanceReference(instance->GetObject()) : nullptr;
}

bool ScriptingProvider::LoadModuleCallback(void* ctxt, const char* repository, const char* module, bool force)
{
	ScriptingProvider* provider = (ScriptingProvider*)ctxt;
	return BNLoadScriptingProviderModule(provider->GetObject(), repository, module, force);
}

bool ScriptingProvider::InstallModulesCallback(void* ctxt, const char* modules)
{
	ScriptingProvider* provider = (ScriptingProvider*)ctxt;
	return BNInstallScriptingProviderModules(provider->GetObject(), modules);
}

string ScriptingProvider::GetName()
{
	char* providerNameRaw = BNGetScriptingProviderName(m_object);
	string providerName(providerNameRaw);
	BNFreeString(providerNameRaw);
	return providerName;
}

string ScriptingProvider::GetAPIName()
{
	char* providerNameRaw = BNGetScriptingProviderAPIName(m_object);
	string providerName(providerNameRaw);
	BNFreeString(providerNameRaw);
	return providerName;
}

vector<Ref<ScriptingProvider>> ScriptingProvider::GetList()
{
	size_t count;
	BNScriptingProvider** list = BNGetScriptingProviderList(&count);
	vector<Ref<ScriptingProvider>> result;
	for (size_t i = 0; i < count; i++)
		result.push_back(new CoreScriptingProvider(list[i]));
	BNFreeScriptingProviderList(list);
	return result;
}

Ref<ScriptingProvider> ScriptingProvider::GetByName(const string& name)
{
	BNScriptingProvider* result = BNGetScriptingProviderByName(name.c_str());
	if (!result)
		return nullptr;
	return new CoreScriptingProvider(result);
}

Ref<ScriptingProvider> ScriptingProvider::GetByAPIName(const string& name)
{
	BNScriptingProvider* result = BNGetScriptingProviderByAPIName(name.c_str());
	if (!result)
		return nullptr;
	return new CoreScriptingProvider(result);
}

void ScriptingProvider::Register(ScriptingProvider* provider)
{
	BNScriptingProviderCallbacks cb;
	cb.context = provider;
	cb.createInstance = CreateInstanceCallback;
	cb.loadModule = LoadModuleCallback;
	cb.installModules = InstallModulesCallback;
	provider->m_object =
	    BNRegisterScriptingProvider(provider->m_nameForRegister.c_str(), provider->m_apiNameForRegister.c_str(), &cb);
}

CoreScriptingProvider::CoreScriptingProvider(BNScriptingProvider* provider) : ScriptingProvider(provider) {}

Ref<ScriptingInstance> CoreScriptingProvider::CreateNewInstance()
{
	BNScriptingInstance* result = BNCreateScriptingProviderInstance(m_object);
	if (!result)
		return nullptr;
	return new CoreScriptingInstance(result);
}

bool CoreScriptingProvider::LoadModule(const std::string& repository, const std::string& module, bool force)
{
	return BNLoadScriptingProviderModule(m_object, repository.c_str(), module.c_str(), force);
}

bool CoreScriptingProvider::InstallModules(const std::string& modules)
{
	return BNInstallScriptingProviderModules(m_object, modules.c_str());
}
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2020 Google LLC.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <map>
#include <limits>
#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
#include <Weave/Profiles/data-management/Current/GenericTraitCatalogImpl.h>
#include <Weave/Profiles/data-management/Current/GenericTraitCatalogImpl.ipp>

namespace nl {
namespace Weave {
namespace Profiles {
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
template class GenericTraitCatalogImpl<TraitDataSink>;
template class GenericTraitCatalogImpl<TraitDataSource>;
}; // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
}; // namespace Profiles
}; // namespace Weave
}; // namespace nl
<commit_msg>Guard the template instantiation for generictraitcatalogimpl<commit_after>/*
 *
 *    Copyright (c) 2020 Google LLC.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#if WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
#include <map>
#include <limits>
#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
#include <Weave/Profiles/data-management/Current/GenericTraitCatalogImpl.h>
#include <Weave/Profiles/data-management/Current/GenericTraitCatalogImpl.ipp>

namespace nl {
namespace Weave {
namespace Profiles {
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
template class GenericTraitCatalogImpl<TraitDataSink>;
template class GenericTraitCatalogImpl<TraitDataSource>;
}; // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
}; // namespace Profiles
}; // namespace Weave
}; // namespace nl
#endif
<|endoftext|>


<commit_before>/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "pluginproxy.h"

#include <sys/types.h>
#include <pwd.h>

#include <QStringList>
#include <QThreadStorage>
#include <QThread>

#include "SignOn/uisessiondata_priv.h"
#include "SignOn/signonplugincommon.h"

/*
 *   TODO: remove the "SignOn/authpluginif.h" include below after the removal
 *         of the deprecated error handling (needed here only for the deprecated
 *         AuthPluginError::PLUGIN_ERROR_GENERAL).
 */
#include "SignOn/authpluginif.h"

using namespace SignOn;

//TODO get this from config
#define REMOTEPLUGIN_BIN_PATH QLatin1String("/usr/bin/signonpluginprocess")
#define PLUGINPROCESS_START_TIMEOUT 5000
#define PLUGINPROCESS_STOP_TIMEOUT 1000

namespace SignonDaemonNS {

    PluginProcess::PluginProcess(QObject *parent) : QProcess(parent)
    {
    }

    PluginProcess::~PluginProcess()
    {
    }

    void PluginProcess::setupChildProcess()
    {
        // Drop all root privileges in the child process and switch to signon user
#ifndef NO_SIGNON_USER
        //get uid and gid
        struct passwd *passwdRecord = getpwnam("signon");
        if ( !passwdRecord ){
            fprintf(stderr, "failed to get user: signon\n");
            emit QProcess::finished(2, QProcess::NormalExit);
            exit(2);
        }
#ifdef SIGNOND_TRACE
        //this is run in remote plugin process, so trace should go to stderr
        fprintf(stderr, "got user: %s with uid: %d\n", passwdRecord->pw_name, passwdRecord->pw_uid);
#endif
        if (( ::setgid(passwdRecord->pw_gid))
                || (::setuid(passwdRecord->pw_uid))
                || (::getuid() != passwdRecord->pw_uid)
                ) {
            fprintf(stderr, "failed to set user: %s with uid: %d", passwdRecord->pw_name, passwdRecord->pw_uid);
            emit QProcess::finished(2, QProcess::NormalExit);
            exit(2);
        }
 #endif
    }

    PluginProxy::PluginProxy(QString type, QObject *parent)
            : QObject(parent)
    {
        TRACE();

        m_type = type;
        m_isProcessing = false;
        m_process = new PluginProcess(this);

        connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(onReadStandardError()));

        /*
         * TODO: some error handling should be added here, at least remove of current
         * request data from the top of the queue and reply an error code
         * */
        connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onExit(int, QProcess::ExitStatus)));
        connect(m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError)));
    }

    PluginProxy::~PluginProxy()
    {
        if (m_process != NULL &&
            m_process->state() != QProcess::NotRunning)
        {
            if (m_isProcessing)
                cancel();

            stop();

            if (!m_process->waitForFinished(PLUGINPROCESS_STOP_TIMEOUT)) {
                qCritical() << "The signon plugin does not react on demand to stop: need to kill it!!!";
                m_process->kill();

                if (!m_process->waitForFinished(PLUGINPROCESS_STOP_TIMEOUT))
                {
                    if (m_process->pid()) {
                        qCritical() << "The signon plugin seems to ignore kill(), killing it from command line";
                        QString killProcessCommand(QString::fromLatin1("kill -9 %1").arg(m_process->pid()));
                        QProcess::execute(killProcessCommand);
                    }
                }
            }
        }
    }

    PluginProxy* PluginProxy::createNewPluginProxy(const QString &type)
    {
        PluginProxy *pp = new PluginProxy(type);

        QStringList args = QStringList() << pp->m_type;
        pp->m_process->start(REMOTEPLUGIN_BIN_PATH, args);

        QByteArray tmp;

        if (!pp->waitForStarted(PLUGINPROCESS_START_TIMEOUT)) {
            TRACE() << "The process cannot be started";
            delete pp;
            return NULL;
        }

        if (!pp->readOnReady(tmp, PLUGINPROCESS_START_TIMEOUT)) {
            TRACE() << "The process cannot load plugin";
            delete pp;
            return NULL;
        }

        pp->m_type = pp->queryType();
        pp->m_mechanisms = pp->queryMechanisms();

        connect(pp->m_process, SIGNAL(readyReadStandardOutput()), pp, SLOT(onReadStandardOutput()));

        TRACE() << "The process is started";
        return pp;
    }

   bool PluginProxy::process(const QString &cancelKey, const QVariantMap &inData, const QString &mechanism)
   {
        TRACE();
        if (!restartIfRequired())
            return false;

        m_cancelKey = cancelKey;
        QVariant value = inData.value(SSOUI_KEY_UIPOLICY);
        m_uiPolicy = value.toInt();

        QDataStream in(m_process);
        in << (quint32)PLUGIN_OP_PROCESS;
        in << QVariant(inData);
        in << QVariant(mechanism);

        m_isProcessing = true;

        return true;
    }

   bool PluginProxy::processUi(const QString &cancelKey, const QVariantMap &inData)
   {
        TRACE() << inData;

        if (!restartIfRequired())
            return false;

        m_cancelKey = cancelKey;

        QDataStream in(m_process);

        in << (quint32)PLUGIN_OP_PROCESS_UI;
        in << QVariant(inData);

        m_isProcessing = true;

        return true;
    }

   bool PluginProxy::processRefresh(const QString &cancelKey, const QVariantMap &inData)
   {
        TRACE() << inData;

        if (!restartIfRequired())
            return false;

        m_cancelKey = cancelKey;

        QDataStream in(m_process);

        in << (quint32)PLUGIN_OP_REFRESH;
        in << QVariant(inData);

        m_isProcessing = true;

        return true;
    }

   void PluginProxy::cancel()
   {
       TRACE();
       QDataStream in(m_process);
       in << (quint32)PLUGIN_OP_CANCEL;
    }

   void PluginProxy::stop()
   {
       TRACE();
       QDataStream in(m_process);
       in << (quint32)PLUGIN_OP_STOP;
    }

    bool PluginProxy::readOnReady(QByteArray &buffer, int timeout)
    {
        bool ready = m_process->waitForReadyRead(timeout);

        if (ready) {
            if (!m_process->bytesAvailable())
                return false;

            while (m_process->bytesAvailable())
                buffer += m_process->readAllStandardOutput();
        }

        return ready;
    }

    bool PluginProxy::isProcessing()
    {
        return m_isProcessing;
    }

    void PluginProxy::onReadStandardOutput()
    {
        disconnect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadStandardOutput()));

        QByteArray token;

        QVariant infoVa;
        QVariantMap info;

        if (!m_process->bytesAvailable()) {
            qCritical() << "No information available on process";
            m_isProcessing = false;
            emit processError(m_cancelKey, Error::InternalServer, QString());
            return;
        }

        QByteArray buffer;

        while (m_process->bytesAvailable())
            buffer += m_process->readAllStandardOutput();

        /*
         * we need to analyze the whole buffer
         * and if it contains error then emit only error
         * otherwise process/emit the incoming information
         * one by one
         * */
        QDataStream out(buffer);
        bool isResultObtained = false;

        while (out.status() == QDataStream::Ok) {
            quint32 opres;
            out >> opres; //result of operation: error code

            TRACE() << opres;

            if (opres == PLUGIN_RESPONSE_RESULT) {
                TRACE() << "PLUGIN_RESPONSE_RESULT";
                out >> infoVa; //SessionData in QVariant
                info = infoVa.toMap();
                m_isProcessing = false;

                if (!isResultObtained)
                    emit processResultReply(m_cancelKey, info);
                else
                    BLAME() << "Unexpected plugin response: " << info;

                isResultObtained = true;
            } else if (opres == PLUGIN_RESPONSE_STORE) {
                TRACE() << "PLUGIN_RESPONSE_STORE";
                out >> infoVa; //SessionData in QVariant
                info = infoVa.toMap();

                if (!isResultObtained)
                    emit processStore(m_cancelKey, info);
                else
                    BLAME() << "Unexpected plugin store: " << info;

            } else if (opres == PLUGIN_RESPONSE_UI) {
                TRACE() << "PLUGIN_RESPONSE_UI";
                out >> infoVa; //UiSessionData in QVariant
                info = infoVa.toMap();

                if (!isResultObtained) {
                    bool allowed = true;

                    if (m_uiPolicy == NoUserInteractionPolicy)
                        allowed = false;

                    if (m_uiPolicy == ValidationPolicy) {
                        bool credentialsQueried =
                            (info.contains(SSOUI_KEY_QUERYUSERNAME)
                            || info.contains(SSOUI_KEY_QUERYPASSWORD));

                        bool captchaQueried  =
                            (info.contains(SSOUI_KEY_CAPTCHAIMG)
                             || info.contains(SSOUI_KEY_CAPTCHAURL));

                        if (credentialsQueried && !captchaQueried)
                            allowed = false;
                    }

                    if (!allowed) {
                        //set error and return;
                        TRACE() << "ui policy prevented ui launch";
                        info.insert(SSOUI_KEY_ERROR, QUERY_ERROR_FORBIDDEN);
                        processUi(m_cancelKey, info);
                    } else {
                        TRACE() << "open ui";
                        emit processUiRequest(m_cancelKey, info);
                    }
                } else {
                    BLAME() << "Unexpected plugin ui response: " << info;
                }
            } else if (opres == PLUGIN_RESPONSE_REFRESHED) {
                TRACE() << "PLUGIN_RESPONSE_REFRESHED";
                out >> infoVa; //UiSessionData in QVariant
                info = infoVa.toMap();

                if (!isResultObtained)
                    emit processRefreshRequest(m_cancelKey, info);
                else
                    BLAME() << "Unexpected plugin ui response: " << info;
            } else if (opres == PLUGIN_RESPONSE_ERROR) {
                TRACE() << "PLUGIN_RESPONSE_ERROR";
                quint32 err;
                QString errorMessage;
                out >> err;
                out >> errorMessage;
                m_isProcessing = false;

                if (!isResultObtained)
                    emit processError(m_cancelKey, (int)err, errorMessage);
                else
                    BLAME() << "Unexpected plugin error: " << errorMessage;

                isResultObtained = true;
            } else if (opres == PLUGIN_RESPONSE_SIGNAL) {
                TRACE() << "PLUGIN_RESPONSE_SIGNAL";
                quint32 state;
                QString message;

                out >> state;
                out >> message;

                if (!isResultObtained)
                    emit stateChanged(m_cancelKey, (int)state, message);
                else
                    BLAME() << "Unexpected plugin signal: " << state << " " << message;
            }
        }

        connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadStandardOutput()));
    }

    void PluginProxy::onReadStandardError()
    {
        QString ba = QString::fromLatin1(m_process->readAllStandardError());
        TRACE() << ba;
    }

    void PluginProxy::onExit(int exitCode, QProcess::ExitStatus exitStatus)
    {
        TRACE() << "Plugin process exit with code " << exitCode << " : " << exitStatus;

        if (m_isProcessing || exitStatus == QProcess::CrashExit) {
            qCritical() << "Challenge produces CRASH!";
            emit processError(m_cancelKey, Error::InternalServer, QLatin1String("plugin processed crashed"));
        }
        if (exitCode == 2) {
            TRACE() << "plugin process terminated because cannot change user";
        }

        m_isProcessing = false;
    }

    void PluginProxy::onError(QProcess::ProcessError err)
    {
        TRACE() << "Error: " << err;
    }

    QString PluginProxy::queryType()
    {
        TRACE();

        if (!restartIfRequired())
            return QString();

        QDataStream ds(m_process);
        ds << (quint32)PLUGIN_OP_TYPE;

        QByteArray typeBa, buffer;
        bool result;

        if ((result = readOnReady(buffer, PLUGINPROCESS_START_TIMEOUT))) {
            QDataStream out(buffer);
            out >> typeBa;
        } else
            qCritical("PluginProxy returned NULL result");

        return QString::fromLatin1(typeBa);
    }

    QStringList PluginProxy::queryMechanisms()
    {
        TRACE();

        if (!restartIfRequired())
            return QStringList();

        QDataStream in(m_process);
        in << (quint32)PLUGIN_OP_MECHANISMS;

        QByteArray buffer;
        QStringList strList;
        bool result;

        if ((result = readOnReady(buffer, PLUGINPROCESS_START_TIMEOUT))) {
            QVariant mechanismsVar;
            QDataStream out(buffer);

            out >> mechanismsVar;
            QVariantList varList = mechanismsVar.toList();

            for (int i = 0; i < varList.count(); i++)
                    strList << varList.at(i).toString();

            TRACE() << strList;
        } else
            qCritical("PluginProxy returned NULL result");

        return strList;
    }

    bool PluginProxy::waitForStarted(int timeout)
    {
        return m_process->waitForStarted(timeout);
    }

    bool PluginProxy::waitForFinished(int timeout)
    {
        return m_process->waitForFinished(timeout);
    }

    bool PluginProxy::restartIfRequired()
    {
        if (m_process->state() == QProcess::NotRunning) {
            TRACE() << "RESTART REQUIRED";
            m_process->start(REMOTEPLUGIN_BIN_PATH, QStringList(m_type));

            QByteArray tmp;
            if (!waitForStarted(PLUGINPROCESS_START_TIMEOUT) || !readOnReady(tmp, PLUGINPROCESS_START_TIMEOUT))
                return false;
        }
        return true;
    }

} //namespace SignonDaemonNS
<commit_msg>Included common header.<commit_after>/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "pluginproxy.h"

#include <sys/types.h>
#include <pwd.h>

#include <QStringList>
#include <QThreadStorage>
#include <QThread>

#include "signond-common.h"
#include "SignOn/uisessiondata_priv.h"
#include "SignOn/signonplugincommon.h"

/*
 *   TODO: remove the "SignOn/authpluginif.h" include below after the removal
 *         of the deprecated error handling (needed here only for the deprecated
 *         AuthPluginError::PLUGIN_ERROR_GENERAL).
 */
#include "SignOn/authpluginif.h"

using namespace SignOn;

//TODO get this from config
#define REMOTEPLUGIN_BIN_PATH QLatin1String("/usr/bin/signonpluginprocess")
#define PLUGINPROCESS_START_TIMEOUT 5000
#define PLUGINPROCESS_STOP_TIMEOUT 1000

namespace SignonDaemonNS {

    PluginProcess::PluginProcess(QObject *parent) : QProcess(parent)
    {
    }

    PluginProcess::~PluginProcess()
    {
    }

    void PluginProcess::setupChildProcess()
    {
        // Drop all root privileges in the child process and switch to signon user
#ifndef NO_SIGNON_USER
        //get uid and gid
        struct passwd *passwdRecord = getpwnam("signon");
        if ( !passwdRecord ){
            fprintf(stderr, "failed to get user: signon\n");
            emit QProcess::finished(2, QProcess::NormalExit);
            exit(2);
        }
#ifdef SIGNOND_TRACE
        //this is run in remote plugin process, so trace should go to stderr
        fprintf(stderr, "got user: %s with uid: %d\n", passwdRecord->pw_name, passwdRecord->pw_uid);
#endif
        if (( ::setgid(passwdRecord->pw_gid))
                || (::setuid(passwdRecord->pw_uid))
                || (::getuid() != passwdRecord->pw_uid)
                ) {
            fprintf(stderr, "failed to set user: %s with uid: %d", passwdRecord->pw_name, passwdRecord->pw_uid);
            emit QProcess::finished(2, QProcess::NormalExit);
            exit(2);
        }
 #endif
    }

    PluginProxy::PluginProxy(QString type, QObject *parent)
            : QObject(parent)
    {
        TRACE();

        m_type = type;
        m_isProcessing = false;
        m_process = new PluginProcess(this);

        connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(onReadStandardError()));

        /*
         * TODO: some error handling should be added here, at least remove of current
         * request data from the top of the queue and reply an error code
         * */
        connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onExit(int, QProcess::ExitStatus)));
        connect(m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError)));
    }

    PluginProxy::~PluginProxy()
    {
        if (m_process != NULL &&
            m_process->state() != QProcess::NotRunning)
        {
            if (m_isProcessing)
                cancel();

            stop();

            if (!m_process->waitForFinished(PLUGINPROCESS_STOP_TIMEOUT)) {
                qCritical() << "The signon plugin does not react on demand to stop: need to kill it!!!";
                m_process->kill();

                if (!m_process->waitForFinished(PLUGINPROCESS_STOP_TIMEOUT))
                {
                    if (m_process->pid()) {
                        qCritical() << "The signon plugin seems to ignore kill(), killing it from command line";
                        QString killProcessCommand(QString::fromLatin1("kill -9 %1").arg(m_process->pid()));
                        QProcess::execute(killProcessCommand);
                    }
                }
            }
        }
    }

    PluginProxy* PluginProxy::createNewPluginProxy(const QString &type)
    {
        PluginProxy *pp = new PluginProxy(type);

        QStringList args = QStringList() << pp->m_type;
        pp->m_process->start(REMOTEPLUGIN_BIN_PATH, args);

        QByteArray tmp;

        if (!pp->waitForStarted(PLUGINPROCESS_START_TIMEOUT)) {
            TRACE() << "The process cannot be started";
            delete pp;
            return NULL;
        }

        if (!pp->readOnReady(tmp, PLUGINPROCESS_START_TIMEOUT)) {
            TRACE() << "The process cannot load plugin";
            delete pp;
            return NULL;
        }

        pp->m_type = pp->queryType();
        pp->m_mechanisms = pp->queryMechanisms();

        connect(pp->m_process, SIGNAL(readyReadStandardOutput()), pp, SLOT(onReadStandardOutput()));

        TRACE() << "The process is started";
        return pp;
    }

   bool PluginProxy::process(const QString &cancelKey, const QVariantMap &inData, const QString &mechanism)
   {
        TRACE();
        if (!restartIfRequired())
            return false;

        m_cancelKey = cancelKey;
        QVariant value = inData.value(SSOUI_KEY_UIPOLICY);
        m_uiPolicy = value.toInt();

        QDataStream in(m_process);
        in << (quint32)PLUGIN_OP_PROCESS;
        in << QVariant(inData);
        in << QVariant(mechanism);

        m_isProcessing = true;

        return true;
    }

   bool PluginProxy::processUi(const QString &cancelKey, const QVariantMap &inData)
   {
        TRACE() << inData;

        if (!restartIfRequired())
            return false;

        m_cancelKey = cancelKey;

        QDataStream in(m_process);

        in << (quint32)PLUGIN_OP_PROCESS_UI;
        in << QVariant(inData);

        m_isProcessing = true;

        return true;
    }

   bool PluginProxy::processRefresh(const QString &cancelKey, const QVariantMap &inData)
   {
        TRACE() << inData;

        if (!restartIfRequired())
            return false;

        m_cancelKey = cancelKey;

        QDataStream in(m_process);

        in << (quint32)PLUGIN_OP_REFRESH;
        in << QVariant(inData);

        m_isProcessing = true;

        return true;
    }

   void PluginProxy::cancel()
   {
       TRACE();
       QDataStream in(m_process);
       in << (quint32)PLUGIN_OP_CANCEL;
    }

   void PluginProxy::stop()
   {
       TRACE();
       QDataStream in(m_process);
       in << (quint32)PLUGIN_OP_STOP;
    }

    bool PluginProxy::readOnReady(QByteArray &buffer, int timeout)
    {
        bool ready = m_process->waitForReadyRead(timeout);

        if (ready) {
            if (!m_process->bytesAvailable())
                return false;

            while (m_process->bytesAvailable())
                buffer += m_process->readAllStandardOutput();
        }

        return ready;
    }

    bool PluginProxy::isProcessing()
    {
        return m_isProcessing;
    }

    void PluginProxy::onReadStandardOutput()
    {
        disconnect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadStandardOutput()));

        QByteArray token;

        QVariant infoVa;
        QVariantMap info;

        if (!m_process->bytesAvailable()) {
            qCritical() << "No information available on process";
            m_isProcessing = false;
            emit processError(m_cancelKey, Error::InternalServer, QString());
            return;
        }

        QByteArray buffer;

        while (m_process->bytesAvailable())
            buffer += m_process->readAllStandardOutput();

        /*
         * we need to analyze the whole buffer
         * and if it contains error then emit only error
         * otherwise process/emit the incoming information
         * one by one
         * */
        QDataStream out(buffer);
        bool isResultObtained = false;

        while (out.status() == QDataStream::Ok) {
            quint32 opres;
            out >> opres; //result of operation: error code

            TRACE() << opres;

            if (opres == PLUGIN_RESPONSE_RESULT) {
                TRACE() << "PLUGIN_RESPONSE_RESULT";
                out >> infoVa; //SessionData in QVariant
                info = infoVa.toMap();
                m_isProcessing = false;

                if (!isResultObtained)
                    emit processResultReply(m_cancelKey, info);
                else
                    BLAME() << "Unexpected plugin response: " << info;

                isResultObtained = true;
            } else if (opres == PLUGIN_RESPONSE_STORE) {
                TRACE() << "PLUGIN_RESPONSE_STORE";
                out >> infoVa; //SessionData in QVariant
                info = infoVa.toMap();

                if (!isResultObtained)
                    emit processStore(m_cancelKey, info);
                else
                    BLAME() << "Unexpected plugin store: " << info;

            } else if (opres == PLUGIN_RESPONSE_UI) {
                TRACE() << "PLUGIN_RESPONSE_UI";
                out >> infoVa; //UiSessionData in QVariant
                info = infoVa.toMap();

                if (!isResultObtained) {
                    bool allowed = true;

                    if (m_uiPolicy == NoUserInteractionPolicy)
                        allowed = false;

                    if (m_uiPolicy == ValidationPolicy) {
                        bool credentialsQueried =
                            (info.contains(SSOUI_KEY_QUERYUSERNAME)
                            || info.contains(SSOUI_KEY_QUERYPASSWORD));

                        bool captchaQueried  =
                            (info.contains(SSOUI_KEY_CAPTCHAIMG)
                             || info.contains(SSOUI_KEY_CAPTCHAURL));

                        if (credentialsQueried && !captchaQueried)
                            allowed = false;
                    }

                    if (!allowed) {
                        //set error and return;
                        TRACE() << "ui policy prevented ui launch";
                        info.insert(SSOUI_KEY_ERROR, QUERY_ERROR_FORBIDDEN);
                        processUi(m_cancelKey, info);
                    } else {
                        TRACE() << "open ui";
                        emit processUiRequest(m_cancelKey, info);
                    }
                } else {
                    BLAME() << "Unexpected plugin ui response: " << info;
                }
            } else if (opres == PLUGIN_RESPONSE_REFRESHED) {
                TRACE() << "PLUGIN_RESPONSE_REFRESHED";
                out >> infoVa; //UiSessionData in QVariant
                info = infoVa.toMap();

                if (!isResultObtained)
                    emit processRefreshRequest(m_cancelKey, info);
                else
                    BLAME() << "Unexpected plugin ui response: " << info;
            } else if (opres == PLUGIN_RESPONSE_ERROR) {
                TRACE() << "PLUGIN_RESPONSE_ERROR";
                quint32 err;
                QString errorMessage;
                out >> err;
                out >> errorMessage;
                m_isProcessing = false;

                if (!isResultObtained)
                    emit processError(m_cancelKey, (int)err, errorMessage);
                else
                    BLAME() << "Unexpected plugin error: " << errorMessage;

                isResultObtained = true;
            } else if (opres == PLUGIN_RESPONSE_SIGNAL) {
                TRACE() << "PLUGIN_RESPONSE_SIGNAL";
                quint32 state;
                QString message;

                out >> state;
                out >> message;

                if (!isResultObtained)
                    emit stateChanged(m_cancelKey, (int)state, message);
                else
                    BLAME() << "Unexpected plugin signal: " << state << " " << message;
            }
        }

        connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadStandardOutput()));
    }

    void PluginProxy::onReadStandardError()
    {
        QString ba = QString::fromLatin1(m_process->readAllStandardError());
        TRACE() << ba;
    }

    void PluginProxy::onExit(int exitCode, QProcess::ExitStatus exitStatus)
    {
        TRACE() << "Plugin process exit with code " << exitCode << " : " << exitStatus;

        if (m_isProcessing || exitStatus == QProcess::CrashExit) {
            qCritical() << "Challenge produces CRASH!";
            emit processError(m_cancelKey, Error::InternalServer, QLatin1String("plugin processed crashed"));
        }
        if (exitCode == 2) {
            TRACE() << "plugin process terminated because cannot change user";
        }

        m_isProcessing = false;
    }

    void PluginProxy::onError(QProcess::ProcessError err)
    {
        TRACE() << "Error: " << err;
    }

    QString PluginProxy::queryType()
    {
        TRACE();

        if (!restartIfRequired())
            return QString();

        QDataStream ds(m_process);
        ds << (quint32)PLUGIN_OP_TYPE;

        QByteArray typeBa, buffer;
        bool result;

        if ((result = readOnReady(buffer, PLUGINPROCESS_START_TIMEOUT))) {
            QDataStream out(buffer);
            out >> typeBa;
        } else
            qCritical("PluginProxy returned NULL result");

        return QString::fromLatin1(typeBa);
    }

    QStringList PluginProxy::queryMechanisms()
    {
        TRACE();

        if (!restartIfRequired())
            return QStringList();

        QDataStream in(m_process);
        in << (quint32)PLUGIN_OP_MECHANISMS;

        QByteArray buffer;
        QStringList strList;
        bool result;

        if ((result = readOnReady(buffer, PLUGINPROCESS_START_TIMEOUT))) {
            QVariant mechanismsVar;
            QDataStream out(buffer);

            out >> mechanismsVar;
            QVariantList varList = mechanismsVar.toList();

            for (int i = 0; i < varList.count(); i++)
                    strList << varList.at(i).toString();

            TRACE() << strList;
        } else
            qCritical("PluginProxy returned NULL result");

        return strList;
    }

    bool PluginProxy::waitForStarted(int timeout)
    {
        return m_process->waitForStarted(timeout);
    }

    bool PluginProxy::waitForFinished(int timeout)
    {
        return m_process->waitForFinished(timeout);
    }

    bool PluginProxy::restartIfRequired()
    {
        if (m_process->state() == QProcess::NotRunning) {
            TRACE() << "RESTART REQUIRED";
            m_process->start(REMOTEPLUGIN_BIN_PATH, QStringList(m_type));

            QByteArray tmp;
            if (!waitForStarted(PLUGINPROCESS_START_TIMEOUT) || !readOnReady(tmp, PLUGINPROCESS_START_TIMEOUT))
                return false;
        }
        return true;
    }

} //namespace SignonDaemonNS
<|endoftext|>


<commit_before>// RUN: cat %s | %cling -I%p | FileCheck %s

// This file should be used as regression test for the meta processing subsystem
// Reproducers of fixed bugs should be put here

// PR #93092
// Don't remove the spaces and tabs
.L     cling/Interpreter/Interpreter.h
.x ./DotXable.h(5)
// CHECK: 5
// End PR #93092

.X ./DotXable(10)
 // CHECK: 10
<commit_msg>Add sane test case testing capital x.<commit_after>// RUN: cat %s | %cling -I%p | FileCheck %s

// This file should be used as regression test for the meta processing subsystem
// Reproducers of fixed bugs should be put here

// PR #93092
// Don't remove the spaces and tabs
.L     cling/Interpreter/Interpreter.h
.X ./DotXable.h(5)
// CHECK: 5
// End PR #93092
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sync/test/fake_server/fake_server_verifier.h"

#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/test/fake_server/fake_server.h"
#include "testing/gtest/include/gtest/gtest.h"

using std::string;
using testing::AssertionFailure;
using testing::AssertionResult;
using testing::AssertionSuccess;

namespace {

AssertionResult DictionaryCreationAssertionFailure() {
  return AssertionFailure() << "FakeServer failed to create an entities "
                            << "dictionary.";
}

AssertionResult VerificationCountAssertionFailure(size_t actual_count,
                                                  size_t expected_count) {
  return AssertionFailure() << "Actual count: " << actual_count << "; "
                            << "Expected count: " << expected_count;
}

AssertionResult UnknownTypeAssertionFailure(const string& model_type) {
  return AssertionFailure() << "Verification not attempted. Unknown ModelType: "
                            << model_type;
}

}  // namespace

namespace fake_server {

FakeServerVerifier::FakeServerVerifier(FakeServer* fake_server)
    : fake_server_(fake_server) { }

FakeServerVerifier::~FakeServerVerifier() {}

AssertionResult FakeServerVerifier::VerifyEntityCountByType(
    size_t expected_count,
    syncer::ModelType model_type) const {
  scoped_ptr<base::DictionaryValue> entities =
      fake_server_->GetEntitiesAsDictionaryValue();
  if (!entities.get()) {
    return DictionaryCreationAssertionFailure();
  }

  string model_type_string = ModelTypeToString(model_type);
  base::ListValue* entity_list = NULL;
  if (!entities->GetList(model_type_string, &entity_list)) {
    return UnknownTypeAssertionFailure(model_type_string);
  } else if  (expected_count != entity_list->GetSize()) {
    return VerificationCountAssertionFailure(entity_list->GetSize(),
                                             expected_count);
  }

  return AssertionSuccess();
}

AssertionResult FakeServerVerifier::VerifyEntityCountByTypeAndName(
    size_t expected_count,
    syncer::ModelType model_type,
    const string& name) const {
  scoped_ptr<base::DictionaryValue> entities =
      fake_server_->GetEntitiesAsDictionaryValue();
  if (!entities.get()) {
    return DictionaryCreationAssertionFailure();
  }

  string model_type_string = ModelTypeToString(model_type);
  base::ListValue* entity_list = NULL;
  size_t actual_count = 0;
  if (entities->GetList(model_type_string, &entity_list)) {
    scoped_ptr<base::Value> name_value(new base::StringValue(name));
    for (base::ListValue::const_iterator it = entity_list->begin();
         it != entity_list->end(); ++it) {
      if (name_value->Equals(*it)) {
        actual_count++;
      }
    }
  }

  if (!entity_list) {
    return UnknownTypeAssertionFailure(model_type_string);
  } else if (actual_count != expected_count) {
    return VerificationCountAssertionFailure(actual_count, expected_count)
        << "; Name: " << name;
  }

  return AssertionSuccess();
}

}  // namespace fake_server
<commit_msg>Sync: Print FakeServer contents on test failure<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sync/test/fake_server/fake_server_verifier.h"

#include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/test/fake_server/fake_server.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::JSONWriter;
using std::string;
using testing::AssertionFailure;
using testing::AssertionResult;
using testing::AssertionSuccess;

namespace {

AssertionResult DictionaryCreationAssertionFailure() {
  return AssertionFailure() << "FakeServer failed to create an entities "
                            << "dictionary.";
}

AssertionResult VerificationCountAssertionFailure(size_t actual_count,
                                                  size_t expected_count) {
  return AssertionFailure() << "Actual count: " << actual_count << "; "
                            << "Expected count: " << expected_count;
}

AssertionResult UnknownTypeAssertionFailure(const string& model_type) {
  return AssertionFailure() << "Verification not attempted. Unknown ModelType: "
                            << model_type;
}

// Caller maintains ownership of |entities|.
string ConvertFakeServerContentsToString(
    const base::DictionaryValue& entities) {
  string entities_str;
  if (!JSONWriter::WriteWithOptions(&entities,
                                    JSONWriter::OPTIONS_PRETTY_PRINT,
                                    &entities_str)) {
    entities_str = "Could not convert FakeServer contents to string.";
  }
  return "FakeServer contents:\n" + entities_str;
}

}  // namespace

namespace fake_server {

FakeServerVerifier::FakeServerVerifier(FakeServer* fake_server)
    : fake_server_(fake_server) { }

FakeServerVerifier::~FakeServerVerifier() {}

AssertionResult FakeServerVerifier::VerifyEntityCountByType(
    size_t expected_count,
    syncer::ModelType model_type) const {
  scoped_ptr<base::DictionaryValue> entities =
      fake_server_->GetEntitiesAsDictionaryValue();
  if (!entities.get()) {
    return DictionaryCreationAssertionFailure();
  }

  string model_type_string = ModelTypeToString(model_type);
  base::ListValue* entity_list = NULL;
  if (!entities->GetList(model_type_string, &entity_list)) {
    return UnknownTypeAssertionFailure(model_type_string);
  } else if  (expected_count != entity_list->GetSize()) {
    return VerificationCountAssertionFailure(entity_list->GetSize(),
                                             expected_count)
        << "\n\n"
        << ConvertFakeServerContentsToString(*entities);
  }

  return AssertionSuccess();
}

AssertionResult FakeServerVerifier::VerifyEntityCountByTypeAndName(
    size_t expected_count,
    syncer::ModelType model_type,
    const string& name) const {
  scoped_ptr<base::DictionaryValue> entities =
      fake_server_->GetEntitiesAsDictionaryValue();
  if (!entities.get()) {
    return DictionaryCreationAssertionFailure();
  }

  string model_type_string = ModelTypeToString(model_type);
  base::ListValue* entity_list = NULL;
  size_t actual_count = 0;
  if (entities->GetList(model_type_string, &entity_list)) {
    scoped_ptr<base::Value> name_value(new base::StringValue(name));
    for (base::ListValue::const_iterator it = entity_list->begin();
         it != entity_list->end(); ++it) {
      if (name_value->Equals(*it)) {
        actual_count++;
      }
    }
  }

  if (!entity_list) {
    return UnknownTypeAssertionFailure(model_type_string);
  } else if (actual_count != expected_count) {
    return VerificationCountAssertionFailure(actual_count, expected_count)
        << "; Name: "
        << name
        << "\n\n"
        << ConvertFakeServerContentsToString(*entities);
  }

  return AssertionSuccess();
}

}  // namespace fake_server
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

//TESTED_COMPONENT=src/serviceframework

#include <QCoreApplication>
#include "qservicemanager.h"
#include "qservicefilter.h"
#include "service.h"
#include <QTimer>
#include <QMetaObject>
#include <QMetaMethod>
#include <QtTest/QtTest>
#include <qservice.h>
#include <qremoteserviceregister.h>
#include <QDebug>
#include <QByteArray>
#include <QDataStream>

#define QTRY_VERIFY(a)                       \
    for (int _i = 0; _i < 5000; _i += 100) {    \
        if (a) break;                  \
        QTest::qWait(100);                      \
    }                                           \
    QVERIFY(a)

QTM_USE_NAMESPACE
Q_DECLARE_METATYPE(QServiceFilter);
Q_DECLARE_METATYPE(QVariant);
Q_DECLARE_METATYPE(QList<QString>);

class tst_QServiceManager_IPC: public QObject
{
    Q_OBJECT
public:

private slots:
    void initTestCase();
    void cleanupTestCase();
    void checkCreateEntryWithEmptyServiceName();
    void checkOperators();
    void checkPublish();

private:
    QRemoteServiceRegister* serviceRegister;
    QRemoteServiceRegister::Entry uniqueEntry;
    QRemoteServiceRegister::Entry uniqueEntry2;
};

bool mySecurityFilterFunction(const void *p)
{
    const QRemoteServiceRegisterCredentials *cred = (const struct QRemoteServiceRegisterCredentials *)p;

    // allow the superuser
    if (cred->uid == 0)
        return true;

    return false;
}

void tst_QServiceManager_IPC::initTestCase()
{
    qRegisterMetaType<QServiceFilter>("QServiceFilter");
    qRegisterMetaTypeStreamOperators<QServiceFilter>("QServiceFilter");
    qRegisterMetaType<QList<QString> >("QList<QString>");
    qRegisterMetaTypeStreamOperators<QList<QString> >("QList<QString>");

    serviceRegister = new QRemoteServiceRegister();

    //Check setting of close on last instance
//    serviceRegister->setQuitOnLastInstanceClosed(false);
//    QVERIFY(serviceRegister->quitOnLastInstanceClosed() == false);
    serviceRegister->setQuitOnLastInstanceClosed(true);
    QVERIFY(serviceRegister->quitOnLastInstanceClosed() == true);

    //check setting a security filter
    serviceRegister->setSecurityFilter(mySecurityFilterFunction);

    QServiceManager* manager = new QServiceManager(this);

    // Symbian has auto registration
#ifndef Q_OS_SYMBIAN
    const QString path = QCoreApplication::applicationDirPath() + "/xmldata/rsrexampleservice.xml";
    bool r = manager->addService(path);
    if (!r)
        qWarning() << "Cannot register RSRExampleService" << path;
#endif

    // D-Bus auto registration
#ifndef QT_NO_DBUS
    const QString &file = QDir::homePath() + "/.local/share/dbus-1/services/" +
                                             "com.nokia.qt.rsrunittest.service";
    QFile data(file);
    if (data.open(QFile::WriteOnly)) {
        QTextStream out(&data);
        out << "[D-BUS Service]\n"
            << "Name=com.nokia.qtmobility.sfw.RSRExampleService" << '\n'
            << "Exec=" << QFileInfo("./qt_sfw_example_rsr_unittest").absoluteFilePath();
        data.close();
    }
#endif

    //register the unique service
    uniqueEntry = serviceRegister->createEntry<QRemoteServiceRegisterService>(
                "RSRExampleService", "com.nokia.qt.rsrunittest", "1.0");

    bool valid = uniqueEntry.isValid();
    QVERIFY(valid == true);

    uniqueEntry2 = serviceRegister->createEntry<QRemoteServiceRegisterService>(
                "RSRExampleService", "com.nokia.qt.rsrunittest", "1.0");

    valid = uniqueEntry2.isValid();
    QVERIFY(valid == true);
}

void tst_QServiceManager_IPC::cleanupTestCase()
{
#ifndef QT_NO_DBUS
    const QString &file = QDir::homePath() + "/.local/share/dbus-1/services/" +
                                             "com.nokia.qt.rsrunittest.service";
    QFile::remove(file);
#endif

    // clean up the unit, don't leave it registered
    QServiceManager m;
    m.removeService("RSRExampleService");
    delete serviceRegister;
}

void tst_QServiceManager_IPC::checkCreateEntryWithEmptyServiceName()
{
    QRemoteServiceRegister::Entry emptyservicename =
                serviceRegister->createEntry<QRemoteServiceRegisterService>(
                "", "", "");
    QVERIFY(emptyservicename.serviceName() == "");
    bool valid = emptyservicename.isValid();
    QVERIFY(valid == false);
}

void tst_QServiceManager_IPC::checkOperators()
{
    //== operator
    bool equal = (uniqueEntry == uniqueEntry2 ? true : false);
    QVERIFY(equal == true);

    //!= operator
    bool notequal = (uniqueEntry != uniqueEntry2 ? true : false);
    QVERIFY(notequal == false);

    //= operator
    QRemoteServiceRegister::Entry assignval;
    assignval = uniqueEntry;
    equal = (assignval == uniqueEntry ? true : false);
    QVERIFY(equal == true);

    //QDataStream << >>
#ifndef QT_NO_DATASTREAM
    QByteArray barray = QByteArray();
    QDataStream streamOut(&barray, QIODevice::WriteOnly);
    streamOut.setVersion(QDataStream::Qt_4_6);
    streamOut << uniqueEntry;
    QDataStream streamIn(&barray, QIODevice::ReadOnly);
    streamOut.setVersion(QDataStream::Qt_4_6);
    QRemoteServiceRegister::Entry streamedentry;
    streamIn >> streamedentry;
    QVERIFY(uniqueEntry.serviceName() == streamedentry.serviceName());
    QVERIFY(uniqueEntry.interfaceName() == streamedentry.interfaceName());
    QVERIFY(uniqueEntry.version() == streamedentry.version());
#endif
}

void tst_QServiceManager_IPC::checkPublish()
{
    //publish the registered services
    serviceRegister->publishEntries("qt_sfw_example_rsr_unittest");

    //check instantiation type
    //- default value
    QRemoteServiceRegister::InstanceType type = uniqueEntry.instantiationType();
    QRemoteServiceRegister::InstanceType type2 = uniqueEntry2.instantiationType();
    QVERIFY(type == QRemoteServiceRegister::InstanceType::PrivateInstance);
    QVERIFY(type2 == QRemoteServiceRegister::InstanceType::PrivateInstance);
    //check setting the type
    uniqueEntry2.setInstantiationType(QRemoteServiceRegister::InstanceType::GlobalInstance);
    type2 = uniqueEntry2.instantiationType();
    QVERIFY(type2 == QRemoteServiceRegister::InstanceType::GlobalInstance);
}

QTEST_MAIN(tst_QServiceManager_IPC);
#include "tst_qremoteserviceregister.moc"
<commit_msg>MOBILITY-2161 fix linux build.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

//TESTED_COMPONENT=src/serviceframework

#include <QCoreApplication>
#include "qservicemanager.h"
#include "qservicefilter.h"
#include "service.h"
#include <QTimer>
#include <QMetaObject>
#include <QMetaMethod>
#include <QtTest/QtTest>
#include <qservice.h>
#include <qremoteserviceregister.h>
#include <QDebug>
#include <QByteArray>
#include <QDataStream>

#define QTRY_VERIFY(a)                       \
    for (int _i = 0; _i < 5000; _i += 100) {    \
        if (a) break;                  \
        QTest::qWait(100);                      \
    }                                           \
    QVERIFY(a)

QTM_USE_NAMESPACE
Q_DECLARE_METATYPE(QServiceFilter);
Q_DECLARE_METATYPE(QVariant);
Q_DECLARE_METATYPE(QList<QString>);

class tst_QServiceManager_IPC: public QObject
{
    Q_OBJECT
public:

private slots:
    void initTestCase();
    void cleanupTestCase();
    void checkCreateEntryWithEmptyServiceName();
    void checkOperators();
    void checkPublish();

private:
    QRemoteServiceRegister* serviceRegister;
    QRemoteServiceRegister::Entry uniqueEntry;
    QRemoteServiceRegister::Entry uniqueEntry2;
};

bool mySecurityFilterFunction(const void *p)
{
    const QRemoteServiceRegisterCredentials *cred = (const struct QRemoteServiceRegisterCredentials *)p;

    // allow the superuser
    if (cred->uid == 0)
        return true;

    return false;
}

void tst_QServiceManager_IPC::initTestCase()
{
    qRegisterMetaType<QServiceFilter>("QServiceFilter");
    qRegisterMetaTypeStreamOperators<QServiceFilter>("QServiceFilter");
    qRegisterMetaType<QList<QString> >("QList<QString>");
    qRegisterMetaTypeStreamOperators<QList<QString> >("QList<QString>");

    serviceRegister = new QRemoteServiceRegister();

    //Check setting of close on last instance
//    serviceRegister->setQuitOnLastInstanceClosed(false);
//    QVERIFY(serviceRegister->quitOnLastInstanceClosed() == false);
    serviceRegister->setQuitOnLastInstanceClosed(true);
    QVERIFY(serviceRegister->quitOnLastInstanceClosed() == true);

    //check setting a security filter
    serviceRegister->setSecurityFilter(mySecurityFilterFunction);

    QServiceManager* manager = new QServiceManager(this);

    // Symbian has auto registration
#ifndef Q_OS_SYMBIAN
    const QString path = QCoreApplication::applicationDirPath() + "/xmldata/rsrexampleservice.xml";
    bool r = manager->addService(path);
    if (!r)
        qWarning() << "Cannot register RSRExampleService" << path;
#endif

    // D-Bus auto registration
#ifndef QT_NO_DBUS
    const QString &file = QDir::homePath() + "/.local/share/dbus-1/services/" +
                                             "com.nokia.qt.rsrunittest.service";
    QFile data(file);
    if (data.open(QFile::WriteOnly)) {
        QTextStream out(&data);
        out << "[D-BUS Service]\n"
            << "Name=com.nokia.qtmobility.sfw.RSRExampleService" << '\n'
            << "Exec=" << QFileInfo("./qt_sfw_example_rsr_unittest").absoluteFilePath();
        data.close();
    }
#endif

    //register the unique service
    uniqueEntry = serviceRegister->createEntry<QRemoteServiceRegisterService>(
                "RSRExampleService", "com.nokia.qt.rsrunittest", "1.0");

    bool valid = uniqueEntry.isValid();
    QVERIFY(valid == true);

    uniqueEntry2 = serviceRegister->createEntry<QRemoteServiceRegisterService>(
                "RSRExampleService", "com.nokia.qt.rsrunittest", "1.0");

    valid = uniqueEntry2.isValid();
    QVERIFY(valid == true);
}

void tst_QServiceManager_IPC::cleanupTestCase()
{
#ifndef QT_NO_DBUS
    const QString &file = QDir::homePath() + "/.local/share/dbus-1/services/" +
                                             "com.nokia.qt.rsrunittest.service";
    QFile::remove(file);
#endif

    // clean up the unit, don't leave it registered
    QServiceManager m;
    m.removeService("RSRExampleService");
    delete serviceRegister;
}

void tst_QServiceManager_IPC::checkCreateEntryWithEmptyServiceName()
{
    QRemoteServiceRegister::Entry emptyservicename =
                serviceRegister->createEntry<QRemoteServiceRegisterService>(
                "", "", "");
    QVERIFY(emptyservicename.serviceName() == "");
    bool valid = emptyservicename.isValid();
    QVERIFY(valid == false);
}

void tst_QServiceManager_IPC::checkOperators()
{
    //== operator
    bool equal = (uniqueEntry == uniqueEntry2 ? true : false);
    QVERIFY(equal == true);

    //!= operator
    bool notequal = (uniqueEntry != uniqueEntry2 ? true : false);
    QVERIFY(notequal == false);

    //= operator
    QRemoteServiceRegister::Entry assignval;
    assignval = uniqueEntry;
    equal = (assignval == uniqueEntry ? true : false);
    QVERIFY(equal == true);

    //QDataStream << >>
#ifndef QT_NO_DATASTREAM
    QByteArray barray = QByteArray();
    QDataStream streamOut(&barray, QIODevice::WriteOnly);
    streamOut.setVersion(QDataStream::Qt_4_6);
    streamOut << uniqueEntry;
    QDataStream streamIn(&barray, QIODevice::ReadOnly);
    streamOut.setVersion(QDataStream::Qt_4_6);
    QRemoteServiceRegister::Entry streamedentry;
    streamIn >> streamedentry;
    QVERIFY(uniqueEntry.serviceName() == streamedentry.serviceName());
    QVERIFY(uniqueEntry.interfaceName() == streamedentry.interfaceName());
    QVERIFY(uniqueEntry.version() == streamedentry.version());
#endif
}

void tst_QServiceManager_IPC::checkPublish()
{
    //publish the registered services
    serviceRegister->publishEntries("qt_sfw_example_rsr_unittest");

    //check instantiation type
    //- default value
    QRemoteServiceRegister::InstanceType type = uniqueEntry.instantiationType();
    QRemoteServiceRegister::InstanceType type2 = uniqueEntry2.instantiationType();
    QVERIFY(type == QRemoteServiceRegister::PrivateInstance);
    QVERIFY(type2 == QRemoteServiceRegister::PrivateInstance);
    //check setting the type
    uniqueEntry2.setInstantiationType(QRemoteServiceRegister::GlobalInstance);
    type2 = uniqueEntry2.instantiationType();
    QVERIFY(type2 == QRemoteServiceRegister::GlobalInstance);
}

QTEST_MAIN(tst_QServiceManager_IPC);
#include "tst_qremoteserviceregister.moc"
<|endoftext|>