<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "VehicleGPSPosition.hpp"

#include <px4_platform_common/log.h>
#include <lib/ecl/geo/geo.h>
#include <lib/mathlib/mathlib.h>

namespace sensors
{
using namespace matrix;
using math::constrain;

VehicleGPSPosition::VehicleGPSPosition() :
	ModuleParams(nullptr),
	ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::nav_and_controllers)
{
}

VehicleGPSPosition::~VehicleGPSPosition()
{
	Stop();
	perf_free(_cycle_perf);
}

bool VehicleGPSPosition::Start()
{
	// force initial updates
	ParametersUpdate(true);

	ScheduleNow();

	return true;
}

void VehicleGPSPosition::Stop()
{
	Deinit();

	// clear all registered callbacks
	for (auto &sub : _sensor_gps_sub) {
		sub.unregisterCallback();
	}
}

void VehicleGPSPosition::ParametersUpdate(bool force)
{
	// Check if parameters have changed
	if (_parameter_update_sub.updated() || force) {
		// clear update
		parameter_update_s param_update;
		_parameter_update_sub.copy(&param_update);

		updateParams();

		if (_param_sens_gps_mask.get() == 0) {
			_sensor_gps_sub[0].registerCallback();

		} else {
			for (auto &sub : _sensor_gps_sub) {
				sub.registerCallback();
			}
		}

		_gps_blending.setBlendingUseSpeedAccuracy(_param_sens_gps_mask.get() & BLEND_MASK_USE_SPD_ACC);
		_gps_blending.setBlendingUseHPosAccuracy(_param_sens_gps_mask.get() & BLEND_MASK_USE_HPOS_ACC);
		_gps_blending.setBlendingUseVPosAccuracy(_param_sens_gps_mask.get() & BLEND_MASK_USE_VPOS_ACC);
		_gps_blending.setBlendingTimeConstant(_param_sens_gps_tau.get());
	}
}

void VehicleGPSPosition::Run()
{
	perf_begin(_cycle_perf);
	ParametersUpdate();

	// GPS blending
	ScheduleDelayed(500_ms); // backup schedule

	// if disabled simply republish the first sensor_gps as vehicle_gps_position and return immediately
	if (_param_sens_gps_mask.get() == 0) {
		sensor_gps_s gps;

		if (_sensor_gps_sub[0].update(&gps)) {
			Publish(gps, 0);
		}

		perf_end(_cycle_perf);
		return;
	}

	// Check all GPS instance
	bool any_gps_updated = false;
	bool gps_updated = false;

	for (uint8_t i = 0; i < GPS_MAX_RECEIVERS; i++) {
		gps_updated = _sensor_gps_sub[i].updated();

		sensor_gps_s gps_data;

		if (gps_updated) {
			any_gps_updated = true;

			_sensor_gps_sub[i].copy(&gps_data);
			_gps_blending.setGpsData(gps_data, i);

			if (!_sensor_gps_sub[i].registered()) {
				_sensor_gps_sub[i].registerCallback();
			}
		}
	}

	if (any_gps_updated) {
		_gps_blending.update(hrt_absolute_time());

		if (_gps_blending.isNewOutputDataAvailable()) {
			Publish(_gps_blending.getOutputGpsData(), _gps_blending.getSelectedGps());
		}
	}

	perf_end(_cycle_perf);
}

void VehicleGPSPosition::Publish(const sensor_gps_s &gps, uint8_t selected)
{
	vehicle_gps_position_s gps_output{};

	gps_output.timestamp = gps.timestamp;
	gps_output.time_utc_usec = gps.time_utc_usec;
	gps_output.lat = gps.lat;
	gps_output.lon = gps.lon;
	gps_output.alt = gps.alt;
	gps_output.alt_ellipsoid = gps.alt_ellipsoid;
	gps_output.s_variance_m_s = gps.s_variance_m_s;
	gps_output.c_variance_rad = gps.c_variance_rad;
	gps_output.eph = gps.eph;
	gps_output.epv = gps.epv;
	gps_output.hdop = gps.hdop;
	gps_output.vdop = gps.vdop;
	gps_output.noise_per_ms = gps.noise_per_ms;
	gps_output.jamming_indicator = gps.jamming_indicator;
	gps_output.jamming_state = gps.jamming_state;
	gps_output.vel_m_s = gps.vel_m_s;
	gps_output.vel_n_m_s = gps.vel_n_m_s;
	gps_output.vel_e_m_s = gps.vel_e_m_s;
	gps_output.vel_d_m_s = gps.vel_d_m_s;
	gps_output.cog_rad = gps.cog_rad;
	gps_output.timestamp_time_relative = gps.timestamp_time_relative;
	gps_output.heading = gps.heading;
	gps_output.heading_offset = gps.heading_offset;
	gps_output.fix_type = gps.fix_type;
	gps_output.vel_ned_valid = gps.vel_ned_valid;
	gps_output.satellites_used = gps.satellites_used;

	gps_output.selected = selected;

	_vehicle_gps_position_pub.publish(gps_output);
}

void VehicleGPSPosition::PrintStatus()
{
	//PX4_INFO("selected GPS: %d", _gps_select_index);
}

}; // namespace sensors
<commit_msg>gps blend: always pass through GpsBlending class for selection<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "VehicleGPSPosition.hpp"

#include <px4_platform_common/log.h>
#include <lib/ecl/geo/geo.h>
#include <lib/mathlib/mathlib.h>

namespace sensors
{
using namespace matrix;
using math::constrain;

VehicleGPSPosition::VehicleGPSPosition() :
	ModuleParams(nullptr),
	ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::nav_and_controllers)
{
}

VehicleGPSPosition::~VehicleGPSPosition()
{
	Stop();
	perf_free(_cycle_perf);
}

bool VehicleGPSPosition::Start()
{
	// force initial updates
	ParametersUpdate(true);

	ScheduleNow();

	return true;
}

void VehicleGPSPosition::Stop()
{
	Deinit();

	// clear all registered callbacks
	for (auto &sub : _sensor_gps_sub) {
		sub.unregisterCallback();
	}
}

void VehicleGPSPosition::ParametersUpdate(bool force)
{
	// Check if parameters have changed
	if (_parameter_update_sub.updated() || force) {
		// clear update
		parameter_update_s param_update;
		_parameter_update_sub.copy(&param_update);

		updateParams();

		if (_param_sens_gps_mask.get() == 0) {
			_sensor_gps_sub[0].registerCallback();

		} else {
			for (auto &sub : _sensor_gps_sub) {
				sub.registerCallback();
			}
		}

		_gps_blending.setBlendingUseSpeedAccuracy(_param_sens_gps_mask.get() & BLEND_MASK_USE_SPD_ACC);
		_gps_blending.setBlendingUseHPosAccuracy(_param_sens_gps_mask.get() & BLEND_MASK_USE_HPOS_ACC);
		_gps_blending.setBlendingUseVPosAccuracy(_param_sens_gps_mask.get() & BLEND_MASK_USE_VPOS_ACC);
		_gps_blending.setBlendingTimeConstant(_param_sens_gps_tau.get());
	}
}

void VehicleGPSPosition::Run()
{
	perf_begin(_cycle_perf);
	ParametersUpdate();

	// GPS blending
	ScheduleDelayed(500_ms); // backup schedule

	// Check all GPS instance
	bool any_gps_updated = false;
	bool gps_updated = false;

	for (uint8_t i = 0; i < GPS_MAX_RECEIVERS; i++) {
		gps_updated = _sensor_gps_sub[i].updated();

		sensor_gps_s gps_data;

		if (gps_updated) {
			any_gps_updated = true;

			_sensor_gps_sub[i].copy(&gps_data);
			_gps_blending.setGpsData(gps_data, i);

			if (!_sensor_gps_sub[i].registered()) {
				_sensor_gps_sub[i].registerCallback();
			}
		}
	}

	if (any_gps_updated) {
		_gps_blending.update(hrt_absolute_time());

		if (_gps_blending.isNewOutputDataAvailable()) {
			Publish(_gps_blending.getOutputGpsData(), _gps_blending.getSelectedGps());
		}
	}

	perf_end(_cycle_perf);
}

void VehicleGPSPosition::Publish(const sensor_gps_s &gps, uint8_t selected)
{
	vehicle_gps_position_s gps_output{};

	gps_output.timestamp = gps.timestamp;
	gps_output.time_utc_usec = gps.time_utc_usec;
	gps_output.lat = gps.lat;
	gps_output.lon = gps.lon;
	gps_output.alt = gps.alt;
	gps_output.alt_ellipsoid = gps.alt_ellipsoid;
	gps_output.s_variance_m_s = gps.s_variance_m_s;
	gps_output.c_variance_rad = gps.c_variance_rad;
	gps_output.eph = gps.eph;
	gps_output.epv = gps.epv;
	gps_output.hdop = gps.hdop;
	gps_output.vdop = gps.vdop;
	gps_output.noise_per_ms = gps.noise_per_ms;
	gps_output.jamming_indicator = gps.jamming_indicator;
	gps_output.jamming_state = gps.jamming_state;
	gps_output.vel_m_s = gps.vel_m_s;
	gps_output.vel_n_m_s = gps.vel_n_m_s;
	gps_output.vel_e_m_s = gps.vel_e_m_s;
	gps_output.vel_d_m_s = gps.vel_d_m_s;
	gps_output.cog_rad = gps.cog_rad;
	gps_output.timestamp_time_relative = gps.timestamp_time_relative;
	gps_output.heading = gps.heading;
	gps_output.heading_offset = gps.heading_offset;
	gps_output.fix_type = gps.fix_type;
	gps_output.vel_ned_valid = gps.vel_ned_valid;
	gps_output.satellites_used = gps.satellites_used;

	gps_output.selected = selected;

	_vehicle_gps_position_pub.publish(gps_output);
}

void VehicleGPSPosition::PrintStatus()
{
	//PX4_INFO("selected GPS: %d", _gps_select_index);
}

}; // namespace sensors
<|endoftext|>


<commit_before>/*
 * ExecSCM.cc
 *
 * Guile Scheme bindings for the execution links
 * Copyright (c) 2008, 2014, 2015 Linas Vepstas <linas@linas.org>
 */

#ifdef HAVE_GUILE

#include <cstddef>
#include <opencog/atoms/base/Link.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/execution/EvaluationLink.h>
#include <opencog/atoms/execution/Instantiator.h>
#include <opencog/atoms/reduct/FoldLink.h>
#include <opencog/guile/SchemeModule.h>

#include "ExecSCM.h"

// ========================================================

using namespace opencog;

/**
 * cog-execute! executes any/all FunctionLinks
 */
static ValuePtr ss_execute(AtomSpace* atomspace, const Handle& h)
{
	Instantiator inst(atomspace);
	ValuePtr pap(inst.execute(h));
	Handle rh(HandleCast(pap));
	if (NULL != rh)
		pap = atomspace->add_atom(rh);
	return pap;
}

/**
 * cog-evaluate! evaluates an EvaluationLink with a GPN in it.
 */
static TruthValuePtr ss_evaluate(AtomSpace* atomspace, const Handle& h)
{
	return EvaluationLink::do_evaluate(atomspace, h);
}

// ========================================================

// XXX HACK ALERT This needs to be static, in order for python to
// work correctly.  The problem is that python keeps creating and
// destroying this class, but it expects things to stick around.
// Oh well. I guess that's OK, since the definition is meant to be
// for the lifetime of the server, anyway.
std::vector<FunctionWrap*>* ExecSCM::_binders = nullptr;

ExecSCM::ExecSCM(void) :
	ModuleWrap("opencog exec")
{}

/// This is called while (opencog exec) is the current module.
/// Thus, all the definitions below happen in that module.
void ExecSCM::init(void)
{
	_binders = new std::vector<FunctionWrap*>();
	_binders->push_back(new FunctionWrap(ss_execute,
	                   "cog-execute!", "exec"));

	_binders->push_back(new FunctionWrap(ss_evaluate,
	                   "cog-evaluate!", "exec"));
}

ExecSCM::~ExecSCM()
{
#if PYTHON_BUG_IS_FIXED
	for (FunctionWrap* pw : *_binders)
		delete pw;
	delete _binders;
#endif
}

void opencog_exec_init(void)
{
	static ExecSCM exy;
	exy.module_init();
}
#endif // HAVE_GUILE
<commit_msg>Minor performance improvement<commit_after>/*
 * ExecSCM.cc
 *
 * Guile Scheme bindings for the execution links
 * Copyright (c) 2008, 2014, 2015 Linas Vepstas <linas@linas.org>
 */

#ifdef HAVE_GUILE

#include <cstddef>
#include <opencog/atoms/base/Link.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/execution/EvaluationLink.h>
#include <opencog/atoms/execution/Instantiator.h>
#include <opencog/atoms/reduct/FoldLink.h>
#include <opencog/guile/SchemeModule.h>

#include "ExecSCM.h"

// ========================================================

using namespace opencog;

/**
 * cog-execute! executes any/all FunctionLinks
 */
static ValuePtr ss_execute(AtomSpace* atomspace, const Handle& h)
{
	Instantiator inst(atomspace);
	ValuePtr pap(inst.execute(h));
	if (pap and pap->is_atom())
		pap = atomspace->add_atom(HandleCast(pap));
	return pap;
}

/**
 * cog-evaluate! evaluates an EvaluationLink with a GPN in it.
 */
static TruthValuePtr ss_evaluate(AtomSpace* atomspace, const Handle& h)
{
	return EvaluationLink::do_evaluate(atomspace, h);
}

// ========================================================

// XXX HACK ALERT This needs to be static, in order for python to
// work correctly.  The problem is that python keeps creating and
// destroying this class, but it expects things to stick around.
// XXX FIXME: can we fix cython to not do this, already?
// Oh well. I guess that's OK, since the definition is meant to be
// for the lifetime of the process, anyway.
std::vector<FunctionWrap*>* ExecSCM::_binders = nullptr;

ExecSCM::ExecSCM(void) :
	ModuleWrap("opencog exec")
{}

/// This is called while (opencog exec) is the current module.
/// Thus, all the definitions below happen in that module.
void ExecSCM::init(void)
{
	_binders = new std::vector<FunctionWrap*>();
	_binders->push_back(new FunctionWrap(ss_execute,
	                   "cog-execute!", "exec"));

	_binders->push_back(new FunctionWrap(ss_evaluate,
	                   "cog-evaluate!", "exec"));
}

ExecSCM::~ExecSCM()
{
#if PYTHON_BUG_IS_FIXED
	for (FunctionWrap* pw : *_binders)
		delete pw;
	delete _binders;
#endif
}

void opencog_exec_init(void)
{
	static ExecSCM exy;
	exy.module_init();
}
#endif // HAVE_GUILE
<|endoftext|>


<commit_before>/*
 * opencog/cython/PyScheme.cc
 *
 * Copyright (C) 2013 by OpenCog Foundation
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "PyScheme.h"

#include <opencog/util/oc_assert.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/guile/SchemeEval.h>

using std::string;

using namespace opencog;

// Convenience wrapper, for stand-alone usage.
std::string opencog::eval_scheme(AtomSpace* as, const std::string &s)
{
#ifdef HAVE_GUILE
	OC_ASSERT(nullptr != as, "Cython failed to specify an atomspace!");
	SchemeEval* evaluator = SchemeEval::get_evaluator(as);
	std::string scheme_return_value = evaluator->eval(s);

	// If there's an error, the scheme_return_value will contain
	// a backtrace.  Be sure to display that to the user.
	if (evaluator->eval_error())
		throw RuntimeException(TRACE_INFO,
		       "Python-Scheme Wrapper: Failed to execute '%s'\n%s",
		       s.c_str(), scheme_return_value.c_str());

	if (evaluator->input_pending())
		throw RuntimeException(TRACE_INFO,
		      "Python-Scheme Wrapper: Syntax error in input: '%s'", s.c_str());

	return scheme_return_value;
#else // HAVE_GUILE
	return "Error: Compiled without Guile support";
#endif // HAVE_GUILE
}

// Convenience wrapper, for stand-alone usage.
Handle opencog::eval_scheme_h(AtomSpace* as, const std::string &s)
{
#ifdef HAVE_GUILE
	OC_ASSERT(nullptr != as, "Cython failed to specify an atomspace!");

	SchemeEval* evaluator = SchemeEval::get_evaluator(as);
	Handle scheme_return_value = evaluator->eval_h(s);

	if (evaluator->eval_error())
		throw RuntimeException(TRACE_INFO,
		       "Python-Scheme Wrapper: Failed to execute '%s'", s.c_str());

	return scheme_return_value;
#else // HAVE_GUILE
	return Handle();
#endif // HAVE_GUILE
}

// Convenience wrapper, for stand-alone usage.
AtomSpace* opencog::eval_scheme_as(const std::string &s)
{
#ifdef HAVE_GUILE
	SchemeEval* evaluator = SchemeEval::get_evaluator(nullptr);
	AtomSpace* as = evaluator->eval_as(s);

	if (nullptr == as)
		throw RuntimeException(TRACE_INFO,
		       "Python-Scheme Wrapper: Null atomspace for '%s'", s.c_str());

	if (evaluator->eval_error())
		throw RuntimeException(TRACE_INFO,
		       "Python-Scheme Wrapper: Failed to execute '%s'", s.c_str());

	return as;
#else // HAVE_GUILE
	return nullptr;
#endif // HAVE_GUILE
}
<commit_msg>Add missing opencog initialization<commit_after>/*
 * opencog/cython/PyScheme.cc
 *
 * Copyright (C) 2013 by OpenCog Foundation
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "PyScheme.h"

#include <atomic>
#include <opencog/util/oc_assert.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/guile/SchemeEval.h>

using namespace opencog;

static void do_init()
{
	// It should be enough to do this only once, instead of once
	// per thread; so this is a belt-and-suspenders strategy for
	// making sure python initialization doesn't fall down.
	static thread_local bool thread_is_inited = false;
	if (thread_is_inited) return;
	thread_is_inited = true;

	SchemeEval* evaluator = SchemeEval::get_evaluator(nullptr);
	evaluator->eval(
		"(define cog-initial-as (cog-atomspace))"
		"(if (eq? cog-initial-as #f)"
		"	(begin "
		"		(set! cog-initial-as (cog-new-atomspace))"
		"		(cog-set-atomspace! cog-initial-as)))");
}

// Convenience wrapper, for stand-alone usage.
std::string opencog::eval_scheme(AtomSpace* as, const std::string &s)
{
#ifdef HAVE_GUILE
	do_init();
	OC_ASSERT(nullptr != as, "Cython failed to specify an atomspace!");
	SchemeEval* evaluator = SchemeEval::get_evaluator(as);
	std::string scheme_return_value = evaluator->eval(s);

	// If there's an error, the scheme_return_value will contain
	// a backtrace.  Be sure to display that to the user.
	if (evaluator->eval_error())
		throw RuntimeException(TRACE_INFO,
		       "Python-Scheme Wrapper: Failed to execute '%s'\n%s",
		       s.c_str(), scheme_return_value.c_str());

	if (evaluator->input_pending())
		throw RuntimeException(TRACE_INFO,
		      "Python-Scheme Wrapper: Syntax error in input: '%s'", s.c_str());

	return scheme_return_value;
#else // HAVE_GUILE
	return "Error: Compiled without Guile support";
#endif // HAVE_GUILE
}

// Convenience wrapper, for stand-alone usage.
Handle opencog::eval_scheme_h(AtomSpace* as, const std::string &s)
{
#ifdef HAVE_GUILE
	do_init();
	OC_ASSERT(nullptr != as, "Cython failed to specify an atomspace!");

	SchemeEval* evaluator = SchemeEval::get_evaluator(as);
	Handle scheme_return_value = evaluator->eval_h(s);

	if (evaluator->eval_error())
		throw RuntimeException(TRACE_INFO,
		       "Python-Scheme Wrapper: Failed to execute '%s'", s.c_str());

	return scheme_return_value;
#else // HAVE_GUILE
	return Handle();
#endif // HAVE_GUILE
}

// Convenience wrapper, for stand-alone usage.
AtomSpace* opencog::eval_scheme_as(const std::string &s)
{
#ifdef HAVE_GUILE
	do_init();
	SchemeEval* evaluator = SchemeEval::get_evaluator(nullptr);
	AtomSpace* as = evaluator->eval_as(s);

	if (nullptr == as)
		throw RuntimeException(TRACE_INFO,
		       "Python-Scheme Wrapper: Null atomspace for '%s'", s.c_str());

	if (evaluator->eval_error())
		throw RuntimeException(TRACE_INFO,
		       "Python-Scheme Wrapper: Failed to execute '%s'", s.c_str());

	return as;
#else // HAVE_GUILE
	return nullptr;
#endif // HAVE_GUILE
}
<|endoftext|>


<commit_before>
#include <iostream>

//GlEW, before GLFW

#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>
// Should make it cross platform

// glm
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// SOIL
#include <soil/SOIL.h>

// GL includes
#include "Classes/Shader.h"
#include "Classes/Model.h"

// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;
int textureWidth, textureHeight;

void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mode)
{

	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);
}

void DrawPolygon(std::string type, Shader &shader,
				 const GLuint &VAO, const bool &wireFramed,
				 bool drawWithTexture, GLuint &texture1, GLuint &texture2)
{
	shader.Use();
	if (drawWithTexture)
	{
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texture1);
		glUniform1i(glGetUniformLocation(shader.Program, "ourTexture1"), 0);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture2);
		glUniform1i(glGetUniformLocation(shader.Program, "ourTexture2"), 1);
	}

	glBindVertexArray(VAO);

	if (wireFramed)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}
	else
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}

	if (type == "triangle")
	{
		glDrawArrays(GL_TRIANGLES, 0, 3); // Arg1 0 start index of vertex array
										  // Arg2 3 vertices are to be drawn
	}
	else if (type == "rectangle")
	{
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // Arg2 6 indices
															 // Arg4 0 offset in EBO
	}
	else if (type == "cube")
	{
		glDrawArrays(GL_TRIANGLES, 0, 36);
	}
	else
	{
		std::cout << "Wrong type of polygon in call to DrawPolygon(). " << std::endl;
	}

	glBindVertexArray(0);
}

bool InitGlfwAndGlew(GLFWwindow* &window)
{
	std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
	// Init GLFW and set all its required options
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Use OpenGl 3.3
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Don't use old functionality
	//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Necessary for Mac OSX

	// Init GLFWwindow object
	window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return false;
	}
	glfwMakeContextCurrent(window);
	glfwSetKeyCallback(window, KeyCallback);

	// Init GLEW to setup function pointers for OpenGl

	glewExperimental = GL_TRUE; // Use core profile modern OpenGL techniques
	if (glewInit() != GLEW_OK)
	{
		std::cout << "Failed to init GLEW" << std::endl;
		return false;
	}

	// Define width and height for OpenGL (viewport dimensions)
	// OpenGL uses this data to map from processed coordinates in range (-1,1) to (0,800) and (0,600)
	int width, height;
	glfwGetFramebufferSize(window, &width, &height); // Framebuffer size in pixels instead of screen coordinates
	glViewport(0, 0, width, height); // (0, 0) = Southwest corner of window

	return true;
}

void RotatePolygon(glm::mat4 model, GLuint &modelLoc, Shader &shader, double time)
{
	model = glm::rotate(model, (GLfloat)time * 50.0f, glm::vec3(0.5, 1.0, 0.0));

	shader.Use();
	modelLoc = glGetUniformLocation(shader.Program, "model");
	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); // GL_FALSE means not transpose

}

void InitGeometryTransformations(glm::mat4 &model, GLuint &modelLoc,
							   Shader &shader, GLfloat scale, GLfloat degrees,
							   glm::mat4 &view, GLuint &viewLoc, glm::mat4 &proj, GLuint &projLoc)
{

	proj = glm::perspective(45.0f, (float)WIDTH / (float)HEIGHT, 0.1f, 100.0f);
	view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));

	model = glm::rotate(model, degrees, glm::vec3(1.0, 0.0, 0.0));
	model = glm::scale(model, glm::vec3(scale, scale, scale));

	shader.Use();
	modelLoc = glGetUniformLocation(shader.Program, "model");
	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); // GL_FALSE means not transpose

	viewLoc = glGetUniformLocation(shader.Program, "view");
	glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));

	projLoc = glGetUniformLocation(shader.Program, "proj");
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
}

void InitTexture(const char* path, GLuint &texture)
{
	unsigned char* image;

	// Load image from file
	image = SOIL_load_image(path, &textureWidth, &textureHeight, 0, SOIL_LOAD_RGB);

	if (image == NULL)
	{
		std::cout << "Error: Failed to load image: " << path << std::endl;
	}

	// Generate texture
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	// Set the texture wrapping parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	// Set texture wrapping to GL_REPEAT (usually basic wrapping method)
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	// Set texture filtering parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureWidth, textureHeight, 0,
				 GL_RGB, GL_UNSIGNED_BYTE, image);
	glGenerateMipmap(GL_TEXTURE_2D);

	SOIL_free_image_data(image);
	glBindTexture(GL_TEXTURE_2D, 0); // Unbind
}

void InitHandleVertexInformation(GLuint &VBO,GLuint &VAO,GLuint &EBO)
{

	// Init triangle VBO to store vertices in GPU memory, rectangle EBO to index vertices
	// and VAO to collect all states

	const GLuint* vertices[3]; // Just since model

	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Copies vertex data to GPU
	// GL_STATIC_DRAW since the data most likely
	// will not change
	// The VBO is stored in VAO
	//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Stored in VAO
	//glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	// Specify how vertex data is to be interpreted...........................................
	// Position attributes
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); // Arg1 0 since position is layout 0
																					  // Arg2 3 since position data vec3
																					  // Arg4 false since already normalized values
																					  // Arg5 Space between attribute sets
																					  // Arg6 No data offset in buffer
	glEnableVertexAttribArray(0); // Vertex attribute location is 0 for position

	// Color attributes
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
	//glEnableVertexAttribArray(1); // Vertex attribute location is 1 for color

	// Texture attributes

	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
	glEnableVertexAttribArray(2);

	glBindVertexArray(0); // Unbind vertex array to not risk misconfiguring later on
}

int main()
{
	GLFWwindow* window;
	bool initGlfwGlewSuccess;
	initGlfwGlewSuccess = InitGlfwAndGlew(window);
	if (!initGlfwGlewSuccess) { return -1; }

	glEnable(GL_DEPTH_TEST);

	Shader modelShader("./Shaders/model_loading.vert", "./Shaders/model_loading.frag");

	Model ourModel("./Models/nanosuit/nanosuit.obj");

	// Init transformations and matrices
	glm::mat4 model, view, proj;
	GLuint modelLoc, viewLoc, projLoc;
	InitGeometryTransformations(model, modelLoc, modelShader, 1.0f, -65.0f,
							   view, viewLoc, proj, projLoc);

	// Ugly deformation
	int firstIteration = 1;
	double oldTime= 0;
	double currentTime;

	// Game loop
	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents(); // Check if events have been activated

		// Rendering commands
		glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		// Rotate over time
		RotatePolygon(model, modelLoc, modelShader, glfwGetTime());

		/*if (firstIteration == 100)
		{
			ourModel.DeformModel();
		}
		firstIteration++;

		if (firstIteration > 300)
		{
			currentTime = glfwGetTime();
			double timeDiff = currentTime - oldTime;
			ourModel.RestoreDeformedModel(timeDiff);
			oldTime = currentTime;
		}*/
		ourModel.Draw(modelShader);

		glfwSwapBuffers(window);
	}
	glfwTerminate(); // Clear allocated resources
	return 0;
}
<commit_msg>Just smaller model scaling<commit_after>
#include <iostream>

//GlEW, before GLFW

#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>
// Should make it cross platform

// glm
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// SOIL
#include <soil/SOIL.h>

// GL includes
#include "Classes/Shader.h"
#include "Classes/Model.h"

// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;
int textureWidth, textureHeight;

void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mode)
{

	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);
}

void DrawPolygon(std::string type, Shader &shader,
				 const GLuint &VAO, const bool &wireFramed,
				 bool drawWithTexture, GLuint &texture1, GLuint &texture2)
{
	shader.Use();
	if (drawWithTexture)
	{
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texture1);
		glUniform1i(glGetUniformLocation(shader.Program, "ourTexture1"), 0);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture2);
		glUniform1i(glGetUniformLocation(shader.Program, "ourTexture2"), 1);
	}

	glBindVertexArray(VAO);

	if (wireFramed)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}
	else
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}

	if (type == "triangle")
	{
		glDrawArrays(GL_TRIANGLES, 0, 3); // Arg1 0 start index of vertex array
										  // Arg2 3 vertices are to be drawn
	}
	else if (type == "rectangle")
	{
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // Arg2 6 indices
															 // Arg4 0 offset in EBO
	}
	else if (type == "cube")
	{
		glDrawArrays(GL_TRIANGLES, 0, 36);
	}
	else
	{
		std::cout << "Wrong type of polygon in call to DrawPolygon(). " << std::endl;
	}

	glBindVertexArray(0);
}

bool InitGlfwAndGlew(GLFWwindow* &window)
{
	std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
	// Init GLFW and set all its required options
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Use OpenGl 3.3
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Don't use old functionality
	//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Necessary for Mac OSX

	// Init GLFWwindow object
	window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return false;
	}
	glfwMakeContextCurrent(window);
	glfwSetKeyCallback(window, KeyCallback);

	// Init GLEW to setup function pointers for OpenGl

	glewExperimental = GL_TRUE; // Use core profile modern OpenGL techniques
	if (glewInit() != GLEW_OK)
	{
		std::cout << "Failed to init GLEW" << std::endl;
		return false;
	}

	// Define width and height for OpenGL (viewport dimensions)
	// OpenGL uses this data to map from processed coordinates in range (-1,1) to (0,800) and (0,600)
	int width, height;
	glfwGetFramebufferSize(window, &width, &height); // Framebuffer size in pixels instead of screen coordinates
	glViewport(0, 0, width, height); // (0, 0) = Southwest corner of window

	return true;
}

void RotatePolygon(glm::mat4 model, GLuint &modelLoc, Shader &shader, double time)
{
	model = glm::rotate(model, (GLfloat)time * 50.0f, glm::vec3(0.5, 1.0, 0.0));

	shader.Use();
	modelLoc = glGetUniformLocation(shader.Program, "model");
	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); // GL_FALSE means not transpose

}

void InitGeometryTransformations(glm::mat4 &model, GLuint &modelLoc,
							   Shader &shader, GLfloat scale, GLfloat degrees,
							   glm::mat4 &view, GLuint &viewLoc, glm::mat4 &proj, GLuint &projLoc)
{

	proj = glm::perspective(45.0f, (float)WIDTH / (float)HEIGHT, 0.1f, 100.0f);
	view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));

	model = glm::rotate(model, degrees, glm::vec3(1.0, 0.0, 0.0));
	model = glm::scale(model, glm::vec3(scale, scale, scale));

	shader.Use();
	modelLoc = glGetUniformLocation(shader.Program, "model");
	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); // GL_FALSE means not transpose

	viewLoc = glGetUniformLocation(shader.Program, "view");
	glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));

	projLoc = glGetUniformLocation(shader.Program, "proj");
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
}

void InitTexture(const char* path, GLuint &texture)
{
	unsigned char* image;

	// Load image from file
	image = SOIL_load_image(path, &textureWidth, &textureHeight, 0, SOIL_LOAD_RGB);

	if (image == NULL)
	{
		std::cout << "Error: Failed to load image: " << path << std::endl;
	}

	// Generate texture
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	// Set the texture wrapping parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	// Set texture wrapping to GL_REPEAT (usually basic wrapping method)
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	// Set texture filtering parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureWidth, textureHeight, 0,
				 GL_RGB, GL_UNSIGNED_BYTE, image);
	glGenerateMipmap(GL_TEXTURE_2D);

	SOIL_free_image_data(image);
	glBindTexture(GL_TEXTURE_2D, 0); // Unbind
}

void InitHandleVertexInformation(GLuint &VBO,GLuint &VAO,GLuint &EBO)
{

	// Init triangle VBO to store vertices in GPU memory, rectangle EBO to index vertices
	// and VAO to collect all states

	const GLuint* vertices[3]; // Just since model

	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Copies vertex data to GPU
	// GL_STATIC_DRAW since the data most likely
	// will not change
	// The VBO is stored in VAO
	//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Stored in VAO
	//glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	// Specify how vertex data is to be interpreted...........................................
	// Position attributes
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); // Arg1 0 since position is layout 0
																					  // Arg2 3 since position data vec3
																					  // Arg4 false since already normalized values
																					  // Arg5 Space between attribute sets
																					  // Arg6 No data offset in buffer
	glEnableVertexAttribArray(0); // Vertex attribute location is 0 for position

	// Color attributes
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
	//glEnableVertexAttribArray(1); // Vertex attribute location is 1 for color

	// Texture attributes

	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
	glEnableVertexAttribArray(2);

	glBindVertexArray(0); // Unbind vertex array to not risk misconfiguring later on
}

int main()
{
	GLFWwindow* window;
	bool initGlfwGlewSuccess;
	initGlfwGlewSuccess = InitGlfwAndGlew(window);
	if (!initGlfwGlewSuccess) { return -1; }

	glEnable(GL_DEPTH_TEST);

	Shader modelShader("./Shaders/model_loading.vert", "./Shaders/model_loading.frag");

	Model ourModel("./Models/nanosuit/nanosuit.obj");

	// Init transformations and matrices
	glm::mat4 model, view, proj;
	GLuint modelLoc, viewLoc, projLoc;
	InitGeometryTransformations(model, modelLoc, modelShader, 0.2f, -65.0f,
							   view, viewLoc, proj, projLoc);

	// Ugly deformation
	int firstIteration = 1;
	double oldTime= 0;
	double currentTime;

	// Game loop
	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents(); // Check if events have been activated

		// Rendering commands
		glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		// Rotate over time
		RotatePolygon(model, modelLoc, modelShader, glfwGetTime());

		/*if (firstIteration == 100)
		{
			ourModel.DeformModel();
		}
		firstIteration++;

		if (firstIteration > 300)
		{
			currentTime = glfwGetTime();
			double timeDiff = currentTime - oldTime;
			ourModel.RestoreDeformedModel(timeDiff);
			oldTime = currentTime;
		}*/
		ourModel.Draw(modelShader);

		glfwSwapBuffers(window);
	}
	glfwTerminate(); // Clear allocated resources
	return 0;
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2005-2006 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2005-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2005 Pingtel Corp.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
////////////////////////////////////////////////////////////////////////

// Cloned from syslogviewer

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#if defined(_WIN32)
#   include <io.h>
#   include <string.h>
#elif defined(__pingtel_on_posix__)
#   include <unistd.h>
#endif

#define BUFFER_SIZE 8192

#include <os/OsDefs.h>
#include <os/OsSysLog.h>
#include <net/NameValueTokenizer.h>
#include <net/SipMessage.h>

void writeMessageNodesBegin(int outputFileDescriptor)
{
    UtlString nodeBegin("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<sipTrace>\n");
    write(outputFileDescriptor, nodeBegin.data(), nodeBegin.length());
}

void writeMessageNodesEnd(int outputFileDescriptor)
{
    UtlString nodeEnd("</sipTrace>\n");
    write(outputFileDescriptor, nodeEnd.data(), nodeEnd.length());

}

void writeBranchNodeBegin(int outputFileDescriptor)
{
    UtlString nodeBegin("\t<branchNode>\n");
    write(outputFileDescriptor, nodeBegin.data(), nodeBegin.length());

}

void writeBranchNodeEnd(int outputFileDescriptor)
{
    UtlString nodeEnd("\t</branchNode>\n");
    write(outputFileDescriptor, nodeEnd.data(), nodeEnd.length());

}

void writeBranchSetBegin(int outputFileDescriptor)
{
    UtlString nodeBegin("\t\t<branchIdSet>\n");
    write(outputFileDescriptor, nodeBegin.data(), nodeBegin.length());

}

void writeBranchSetEnd(int outputFileDescriptor)
{
    UtlString nodeEnd("\t\t</branchIdSet>\n");
    write(outputFileDescriptor, nodeEnd.data(), nodeEnd.length());

}

void writeBranchId(int outputFileDescriptor,
                   UtlString& branchId)
{
    NameValueTokenizer::frontBackTrim(&branchId, " \t\n\r");
    UtlString node("\t\t\t<branchId>");
    node.append(branchId);
    node.append("</branchId>\n");

    write(outputFileDescriptor, node.data(), node.length());
}

void writeBranchNodeData(int outputFileDescriptor,
                      UtlString& time,
                      UtlString& source,
                      UtlString& destination,
                      UtlString& sourceAddress,
                      UtlString& destinationAddress,
                      UtlString& transactionId,
                      UtlString& frameId,
                      UtlString& method,
                      UtlString& responseCode,
                      UtlString& responseText,
                      UtlString& message)
{
    NameValueTokenizer::frontBackTrim(&time, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&source, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&destination, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&sourceAddress, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&destinationAddress, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&transactionId, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&frameId, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&method, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&responseCode, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&responseText, " \t\n\r");
    //NameValueTokenizer::frontBackTrim(&message, " \t\n\r");

    UtlString node("\t\t<time>");
    node.append(time);
    node.append("</time>\n");

    if(!source.isNull())
    {
        node.append("\t\t<source>");
        node.append(source);
        node.append("</source>\n");
    }

    if(!destination.isNull())
    {
        node.append("\t\t<destination>");
        node.append(destination);
        node.append("</destination>\n");
    }

    node.append("\t\t<sourceAddress>");
    node.append(sourceAddress);
    node.append("</sourceAddress>\n");

    node.append("\t\t<destinationAddress>");
    node.append(destinationAddress);
    node.append("</destinationAddress>\n");

    node.append("\t\t<transactionId>");
    node.append(transactionId);
    node.append("</transactionId>\n");

    if(!method.isNull())
    {
        node.append("\t\t<method>");
        node.append(method);
        node.append("</method>\n");
    }
    else
    {
        node.append("\t\t<responseCode>");
        node.append(responseCode);
        node.append("</responseCode>\n");

        node.append("\t\t<responseText>");
        node.append(responseText);
        node.append("</responseText>\n");
    }

    node.append("\t\t<frameId>");
    node.append(frameId);
    node.append("</frameId>\n");

    node.append("\t\t<message><![CDATA[");
    node.append(message);
    node.append("]]></message>\n");

    write(outputFileDescriptor, node.data(), node.length());
}

void getMessageData(UtlString& content,
                   UtlBoolean isOutgoing,
                   UtlString& date,
                   UtlString& hostname,
                   UtlString& eventCount,
                   int outputFileDescriptor)
{
    UtlString remoteHost;
    UtlString remoteAddress;
    UtlString remotePort;
    UtlString remoteSourceAddress;
    UtlString message;
    UtlString branchId;
    UtlString transactionId;
    UtlString method;
    UtlString responseCode;
    UtlString responseText;
    UtlBoolean failed = FALSE;

    int hostIndex = content.index("----Remote Host:");
    if(hostIndex > 0)
    {
        hostIndex += 16;
        int hostEnd = content.index("----", hostIndex);
        remoteHost.append(&(content.data()[hostIndex]),
                          hostEnd - hostIndex);

        remoteAddress = remoteHost;

        remoteHost.append(":");

        int portIndex = hostEnd + 11;
        int portEnd = content.index("----", portIndex);
        remotePort.append(&(content.data()[portIndex]),
                          portEnd - portIndex);
        remoteHost.append(remotePort);

        int messageIndex = portEnd + 5;
        unsigned int messageEnd;
        if(isOutgoing)
        {
            messageEnd = content.index("--------------------END", messageIndex);
            // Record whether the send failed or not.
            failed = (content.index("User Agent failed to send message") !=
                      UTL_NOT_FOUND);
         }
        else
        {
            messageEnd = content.index("====================END", messageIndex);
        }
        if ( UTL_NOT_FOUND == messageEnd )
        {
           messageEnd = content.length();
        }

        message.append(&(content.data()[messageIndex]),
                          messageEnd - messageIndex);

        SipMessage sipMsg(message);

        remoteSourceAddress = remoteHost;

        if(sipMsg.isResponse())
        {
            sipMsg.getFirstHeaderLinePart(1, &responseCode);
            if (failed)
            {
               responseCode = responseCode + " FAILED";
            }
            sipMsg.getFirstHeaderLinePart(2, &responseText);

            if(!isOutgoing)
            {
                remoteHost.remove(0);
            }
        }
        else
        {
            // Get the method.
            sipMsg.getRequestMethod(&method);

            // If it is a re-INVITE, make that clear.
            if (method.compareTo("INVITE", UtlString::ignoreCase) == 0)
            {
               Url to;
               sipMsg.getToUrl(to);
               UtlString toTag;
               to.getFieldParameter("tag", toTag);
               if (!toTag.isNull())
               {
                  method = "re-INVITE";
               }
            }

            // Prepend FAILED if it is a failed transmission.
            if (failed)
            {
               method = "FAILED " + method;
            }

            //We can derive the source entity from the via in
            // incoming requests
            if(!isOutgoing)
            {
                UtlString viaAddress;
                UtlString protocol;
                int viaPortNum;

                sipMsg.getLastVia(&viaAddress,
                                  &viaPortNum,
                                  &protocol);
                char numBuff[30];
                sprintf(numBuff, "%d", viaPortNum);
                UtlString viaPort(numBuff);

                remoteHost = remoteAddress + ":" + viaPort;

            }
        }

        // transaction token: cseq,call-id,from-tag,to=tag
        int cseq;
        UtlString cseqMethod;
        sipMsg.getCSeqField(&cseq, &cseqMethod);
        char numBuf[20];
        sprintf(numBuf, "%d", cseq);
        UtlString callId;
        sipMsg.getCallIdField(&callId);
        Url to;
        sipMsg.getToUrl(to);
        UtlString toTag;
        to.getFieldParameter("tag", toTag);
        Url from;
        sipMsg.getFromUrl(from);
        UtlString fromTag;
        from.getFieldParameter("tag", fromTag);

        transactionId = numBuf;
        transactionId.append(",");
        transactionId.append(callId);
        transactionId.append(",");
        transactionId.append(fromTag);
        transactionId.append(",");
        transactionId.append(toTag);

        // Write all the stuff out

        // Write out the node container start
        writeBranchNodeBegin(outputFileDescriptor);

        // Write out the branchId container start
        writeBranchSetBegin(outputFileDescriptor);

        // Write out the branchIds
        int viaIndex = 0;
        UtlString topVia;
        while(sipMsg.getViaFieldSubField(&topVia, viaIndex))
        {
            SipMessage::getViaTag(topVia.data(),
                                  "branch",
                                  branchId);
            writeBranchId(outputFileDescriptor, branchId);
            viaIndex++;
        }

        // Write out the branchId container finish
        writeBranchSetEnd(outputFileDescriptor);

        // Write out the rest of the node data
        writeBranchNodeData(outputFileDescriptor,
                 date,
                 isOutgoing ? hostname : remoteHost,
                 isOutgoing ? remoteHost : hostname,
                 isOutgoing ? hostname : remoteSourceAddress,
                 isOutgoing ? remoteSourceAddress : hostname,
                 transactionId,
                 eventCount,
                 method,
                 responseCode,
                 responseText,
                 message);

        // Write out the node container finish
        writeBranchNodeEnd(outputFileDescriptor);
    }
}

void convertToXml(UtlString& bufferString, int outputFileDescriptor)
{
    UtlString date;
    UtlString eventCount;
    UtlString facility;
    UtlString priority;
    UtlString hostname;
    UtlString taskname;
    UtlString taskId;
    UtlString processId;
    UtlString content;

    OsSysLog::parseLogString(bufferString.data(),
                             date,
                             eventCount,
                             facility,
                             priority,
                             hostname,
                             taskname,
                             taskId,
                             processId,
                             content);

    if(facility.compareTo("OUTGOING") == 0)
    {
        hostname.append("-");
        hostname.append(processId);

        getMessageData(content,
                       TRUE,
                       date,
                       hostname,
                       eventCount,
                       outputFileDescriptor);

    }

    else if(facility.compareTo("INCOMING") == 0)
    {
        hostname.append("-");
        hostname.append(processId);

        getMessageData(content,
                       FALSE,
                       date,
                       hostname,
                       eventCount,
                       outputFileDescriptor);

    }
}

int main(int argc, char * argv[])
{
   int i;
   // Input file descriptor.  Default is stdin.
   int ifd = 0;
   // Output file descriptor.  Default is stdout.
   int ofd = 1;

   // Parse the arguments.
   for(i = 1; i < argc; i++)
   {
      if(!strcmp(argv[i], "-h"))
      {
         // If an argument is -h, print the usage message and exit.
         fprintf(stderr, "Usage:\n\t%s [-h] [if=input] [of=output]\n",
                 argv[0]);
         return 0;
      }
      else if(!strncmp(argv[i], "if=", 3))
      {
         // if= designates the input file.
         ifd = open(&argv[i][3], O_RDONLY);
         if(ifd == -1)
         {
            fprintf(stderr, "%s: %s\n", &argv[i][3], strerror(errno));
            return 1;
         }
      }
      else if(!strncmp(argv[i], "of=", 3))
      {
         // of= designates the output file.
#ifdef _WIN32
         ofd = open(&argv[i][3], O_BINARY | O_WRONLY | O_CREAT, 0644);
#else
         /* No such thing as a "binary" file on POSIX */
         ofd = open(&argv[i][3], O_WRONLY | O_CREAT, 0644);
#endif
         if(ofd == -1)
         {
            fprintf(stderr, "%s: %s\n", &argv[i][3], strerror(errno));
            return 1;
         }
      }
      else
      {
         // All other options are errors.
         fprintf(stderr, "Unknown option: %s\n", argv[i]);
         return 1;
      }
   }

   writeMessageNodesBegin(ofd);

   char inputBuffer[BUFFER_SIZE + 1];
   UtlString bufferString;
   int lineLen;
   int nextLineStart;

   do
   {
      i = read(ifd, inputBuffer, BUFFER_SIZE);

      if(i > 0)
      {
         inputBuffer[i] = '\0';
         bufferString.append(inputBuffer);
      }

      do
      {
         lineLen =
            NameValueTokenizer::findNextLineTerminator(bufferString.data(),
                                                       bufferString.length(),
                                                       &nextLineStart);

         // If a new line was found
         if(nextLineStart > 0)
         {
            UtlString line;
            line.append(bufferString, lineLen);
            bufferString.remove(0, nextLineStart);

            convertToXml(line, ofd);
         }
      }
      while(nextLineStart > 0);
   } while(i && i != -1);

   // Last line without a newline
   convertToXml(bufferString, ofd);

   writeMessageNodesEnd(ofd);

   close(ofd);

   return 0;
}
<commit_msg>Remove an odd fragment of code that loses information about the source address of incoming responses.<commit_after>//
// Copyright (C) 2005-2006 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2005-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2005 Pingtel Corp.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
////////////////////////////////////////////////////////////////////////

// Cloned from syslogviewer

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#if defined(_WIN32)
#   include <io.h>
#   include <string.h>
#elif defined(__pingtel_on_posix__)
#   include <unistd.h>
#endif

#define BUFFER_SIZE 8192

#include <os/OsDefs.h>
#include <os/OsSysLog.h>
#include <net/NameValueTokenizer.h>
#include <net/SipMessage.h>

void writeMessageNodesBegin(int outputFileDescriptor)
{
    UtlString nodeBegin("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<sipTrace>\n");
    write(outputFileDescriptor, nodeBegin.data(), nodeBegin.length());
}

void writeMessageNodesEnd(int outputFileDescriptor)
{
    UtlString nodeEnd("</sipTrace>\n");
    write(outputFileDescriptor, nodeEnd.data(), nodeEnd.length());

}

void writeBranchNodeBegin(int outputFileDescriptor)
{
    UtlString nodeBegin("\t<branchNode>\n");
    write(outputFileDescriptor, nodeBegin.data(), nodeBegin.length());

}

void writeBranchNodeEnd(int outputFileDescriptor)
{
    UtlString nodeEnd("\t</branchNode>\n");
    write(outputFileDescriptor, nodeEnd.data(), nodeEnd.length());

}

void writeBranchSetBegin(int outputFileDescriptor)
{
    UtlString nodeBegin("\t\t<branchIdSet>\n");
    write(outputFileDescriptor, nodeBegin.data(), nodeBegin.length());

}

void writeBranchSetEnd(int outputFileDescriptor)
{
    UtlString nodeEnd("\t\t</branchIdSet>\n");
    write(outputFileDescriptor, nodeEnd.data(), nodeEnd.length());

}

void writeBranchId(int outputFileDescriptor,
                   UtlString& branchId)
{
    NameValueTokenizer::frontBackTrim(&branchId, " \t\n\r");
    UtlString node("\t\t\t<branchId>");
    node.append(branchId);
    node.append("</branchId>\n");

    write(outputFileDescriptor, node.data(), node.length());
}

void writeBranchNodeData(int outputFileDescriptor,
                      UtlString& time,
                      UtlString& source,
                      UtlString& destination,
                      UtlString& sourceAddress,
                      UtlString& destinationAddress,
                      UtlString& transactionId,
                      UtlString& frameId,
                      UtlString& method,
                      UtlString& responseCode,
                      UtlString& responseText,
                      UtlString& message)
{
    NameValueTokenizer::frontBackTrim(&time, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&source, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&destination, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&sourceAddress, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&destinationAddress, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&transactionId, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&frameId, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&method, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&responseCode, " \t\n\r");
    NameValueTokenizer::frontBackTrim(&responseText, " \t\n\r");
    //NameValueTokenizer::frontBackTrim(&message, " \t\n\r");

    UtlString node("\t\t<time>");
    node.append(time);
    node.append("</time>\n");

    if(!source.isNull())
    {
        node.append("\t\t<source>");
        node.append(source);
        node.append("</source>\n");
    }

    if(!destination.isNull())
    {
        node.append("\t\t<destination>");
        node.append(destination);
        node.append("</destination>\n");
    }

    node.append("\t\t<sourceAddress>");
    node.append(sourceAddress);
    node.append("</sourceAddress>\n");

    node.append("\t\t<destinationAddress>");
    node.append(destinationAddress);
    node.append("</destinationAddress>\n");

    node.append("\t\t<transactionId>");
    node.append(transactionId);
    node.append("</transactionId>\n");

    if(!method.isNull())
    {
        node.append("\t\t<method>");
        node.append(method);
        node.append("</method>\n");
    }
    else
    {
        node.append("\t\t<responseCode>");
        node.append(responseCode);
        node.append("</responseCode>\n");

        node.append("\t\t<responseText>");
        node.append(responseText);
        node.append("</responseText>\n");
    }

    node.append("\t\t<frameId>");
    node.append(frameId);
    node.append("</frameId>\n");

    node.append("\t\t<message><![CDATA[");
    node.append(message);
    node.append("]]></message>\n");

    write(outputFileDescriptor, node.data(), node.length());
}

void getMessageData(UtlString& content,
                   UtlBoolean isOutgoing,
                   UtlString& date,
                   UtlString& hostname,
                   UtlString& eventCount,
                   int outputFileDescriptor)
{
    UtlString remoteHost;
    UtlString remoteAddress;
    UtlString remotePort;
    UtlString remoteSourceAddress;
    UtlString message;
    UtlString branchId;
    UtlString transactionId;
    UtlString method;
    UtlString responseCode;
    UtlString responseText;
    UtlBoolean failed = FALSE;

    int hostIndex = content.index("----Remote Host:");
    if(hostIndex > 0)
    {
        hostIndex += 16;
        int hostEnd = content.index("----", hostIndex);
        remoteHost.append(&(content.data()[hostIndex]),
                          hostEnd - hostIndex);

        remoteAddress = remoteHost;

        remoteHost.append(":");

        int portIndex = hostEnd + 11;
        int portEnd = content.index("----", portIndex);
        remotePort.append(&(content.data()[portIndex]),
                          portEnd - portIndex);
        remoteHost.append(remotePort);

        int messageIndex = portEnd + 5;
        unsigned int messageEnd;
        if(isOutgoing)
        {
            messageEnd = content.index("--------------------END", messageIndex);
            // Record whether the send failed or not.
            failed = (content.index("User Agent failed to send message") !=
                      UTL_NOT_FOUND);
        }
        else
        {
            messageEnd = content.index("====================END", messageIndex);
        }
        if ( UTL_NOT_FOUND == messageEnd )
        {
           messageEnd = content.length();
        }

        message.append(&(content.data()[messageIndex]),
                          messageEnd - messageIndex);

        SipMessage sipMsg(message);

        remoteSourceAddress = remoteHost;

        if(sipMsg.isResponse())
        {
            sipMsg.getFirstHeaderLinePart(1, &responseCode);
            if (failed)
            {
               responseCode = responseCode + " FAILED";
            }
            sipMsg.getFirstHeaderLinePart(2, &responseText);
        }
        else
        {
            // Get the method.
            sipMsg.getRequestMethod(&method);

            // If it is a re-INVITE, make that clear.
            if (method.compareTo("INVITE", UtlString::ignoreCase) == 0)
            {
               Url to;
               sipMsg.getToUrl(to);
               UtlString toTag;
               to.getFieldParameter("tag", toTag);
               if (!toTag.isNull())
               {
                  method = "re-INVITE";
               }
            }

            // Prepend FAILED if it is a failed transmission.
            if (failed)
            {
               method = "FAILED " + method;
            }

            // We can derive the source entity from the via in
            // incoming requests
            if(!isOutgoing)
            {
                UtlString viaAddress;
                UtlString protocol;
                int viaPortNum;

                sipMsg.getLastVia(&viaAddress,
                                  &viaPortNum,
                                  &protocol);
                char numBuff[30];
                sprintf(numBuff, "%d", viaPortNum);
                UtlString viaPort(numBuff);

                remoteHost = remoteAddress + ":" + viaPort;

            }
        }

        // transaction token: cseq,call-id,from-tag,to=tag
        int cseq;
        UtlString cseqMethod;
        sipMsg.getCSeqField(&cseq, &cseqMethod);
        char numBuf[20];
        sprintf(numBuf, "%d", cseq);
        UtlString callId;
        sipMsg.getCallIdField(&callId);
        Url to;
        sipMsg.getToUrl(to);
        UtlString toTag;
        to.getFieldParameter("tag", toTag);
        Url from;
        sipMsg.getFromUrl(from);
        UtlString fromTag;
        from.getFieldParameter("tag", fromTag);

        transactionId = numBuf;
        transactionId.append(",");
        transactionId.append(callId);
        transactionId.append(",");
        transactionId.append(fromTag);
        transactionId.append(",");
        transactionId.append(toTag);

        // Write all the stuff out

        // Write out the node container start
        writeBranchNodeBegin(outputFileDescriptor);

        // Write out the branchId container start
        writeBranchSetBegin(outputFileDescriptor);

        // Write out the branchIds
        int viaIndex = 0;
        UtlString topVia;
        while(sipMsg.getViaFieldSubField(&topVia, viaIndex))
        {
            SipMessage::getViaTag(topVia.data(),
                                  "branch",
                                  branchId);
            writeBranchId(outputFileDescriptor, branchId);
            viaIndex++;
        }

        // Write out the branchId container finish
        writeBranchSetEnd(outputFileDescriptor);

        // Write out the rest of the node data
        writeBranchNodeData(outputFileDescriptor,
                 date,
                 isOutgoing ? hostname : remoteHost,
                 isOutgoing ? remoteHost : hostname,
                 isOutgoing ? hostname : remoteSourceAddress,
                 isOutgoing ? remoteSourceAddress : hostname,
                 transactionId,
                 eventCount,
                 method,
                 responseCode,
                 responseText,
                 message);

        // Write out the node container finish
        writeBranchNodeEnd(outputFileDescriptor);
    }
}

void convertToXml(UtlString& bufferString, int outputFileDescriptor)
{
    UtlString date;
    UtlString eventCount;
    UtlString facility;
    UtlString priority;
    UtlString hostname;
    UtlString taskname;
    UtlString taskId;
    UtlString processId;
    UtlString content;

    OsSysLog::parseLogString(bufferString.data(),
                             date,
                             eventCount,
                             facility,
                             priority,
                             hostname,
                             taskname,
                             taskId,
                             processId,
                             content);

    if(facility.compareTo("OUTGOING") == 0)
    {
        hostname.append("-");
        hostname.append(processId);

        getMessageData(content,
                       TRUE,
                       date,
                       hostname,
                       eventCount,
                       outputFileDescriptor);

    }

    else if(facility.compareTo("INCOMING") == 0)
    {
        hostname.append("-");
        hostname.append(processId);

        getMessageData(content,
                       FALSE,
                       date,
                       hostname,
                       eventCount,
                       outputFileDescriptor);

    }
}

int main(int argc, char * argv[])
{
   int i;
   // Input file descriptor.  Default is stdin.
   int ifd = 0;
   // Output file descriptor.  Default is stdout.
   int ofd = 1;

   // Parse the arguments.
   for(i = 1; i < argc; i++)
   {
      if(!strcmp(argv[i], "-h"))
      {
         // If an argument is -h, print the usage message and exit.
         fprintf(stderr, "Usage:\n\t%s [-h] [if=input] [of=output]\n",
                 argv[0]);
         return 0;
      }
      else if(!strncmp(argv[i], "if=", 3))
      {
         // if= designates the input file.
         ifd = open(&argv[i][3], O_RDONLY);
         if(ifd == -1)
         {
            fprintf(stderr, "%s: %s\n", &argv[i][3], strerror(errno));
            return 1;
         }
      }
      else if(!strncmp(argv[i], "of=", 3))
      {
         // of= designates the output file.
#ifdef _WIN32
         ofd = open(&argv[i][3], O_BINARY | O_WRONLY | O_CREAT, 0644);
#else
         /* No such thing as a "binary" file on POSIX */
         ofd = open(&argv[i][3], O_WRONLY | O_CREAT, 0644);
#endif
         if(ofd == -1)
         {
            fprintf(stderr, "%s: %s\n", &argv[i][3], strerror(errno));
            return 1;
         }
      }
      else
      {
         // All other options are errors.
         fprintf(stderr, "Unknown option: %s\n", argv[i]);
         return 1;
      }
   }

   writeMessageNodesBegin(ofd);

   char inputBuffer[BUFFER_SIZE + 1];
   UtlString bufferString;
   int lineLen;
   int nextLineStart;

   do
   {
      i = read(ifd, inputBuffer, BUFFER_SIZE);

      if(i > 0)
      {
         inputBuffer[i] = '\0';
         bufferString.append(inputBuffer);
      }

      do
      {
         lineLen =
            NameValueTokenizer::findNextLineTerminator(bufferString.data(),
                                                       bufferString.length(),
                                                       &nextLineStart);

         // If a new line was found
         if(nextLineStart > 0)
         {
            UtlString line;
            line.append(bufferString, lineLen);
            bufferString.remove(0, nextLineStart);

            convertToXml(line, ofd);
         }
      }
      while(nextLineStart > 0);
   } while(i && i != -1);

   // Last line without a newline
   convertToXml(bufferString, ofd);

   writeMessageNodesEnd(ofd);

   close(ofd);

   return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
 *
 * 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 <gtest/gtest.h>
#include <gmock/gmock.h>

#include <QDateTime>
#include <QProcess>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTemporaryDir>
#include <QTextStream>

#include <memory>

#define Z do { if (::testing::Test::HasFatalFailure()) { std::cerr << "At: " << __FILE__ << ":" << __LINE__ << std::endl; return; } } while (0)

namespace {

template <typename Device>
class IO {
public:
	IO(Device* device, bool verbose = false) : m_device(device), m_verbose(verbose) {}
	virtual ~IO() {}
	void ReadUntil(QByteArray pattern) {
		auto deadline = QDateTime::currentDateTime().addSecs(30);
		while (true) {
			int search = m_readed.indexOf(pattern);
			if (search != -1) {
				m_readed.remove(0, search + pattern.length());
				return;
			}
			if (m_readed.length() > pattern.length()) {
				m_readed = m_readed.right(pattern.length());
			}
			const int timeout_ms = QDateTime::currentDateTime().msecsTo(deadline);
			ASSERT_GT(timeout_ms, 0) << "Wanted:" << pattern.toStdString();
			ASSERT_TRUE(m_device->waitForReadyRead(timeout_ms)) << "Wanted: " << pattern.toStdString();
			QByteArray chunk = m_device->readAll();
			if (m_verbose) {
				std::cout << chunk.toStdString() << std::flush;
			}
			m_readed += chunk;
		}
	}
	void Write(QString s = "", bool new_line = true) {
		if (!m_device) return;
		if (m_verbose) {
			std::cout << s.toStdString() << std::flush;
			if (new_line) {
				std::cout << std::endl;
			}
		}
		s += "\n";
		{
			QTextStream str(m_device);
			str << s;
		}
		FlushIfCan(m_device);
	}
	void Close() {
#ifdef __CYGWIN__
#ifdef __x86_64__
		// Qt on cygwin64 silently doesn't send the rest of buffer from socket without this line
		sleep(1);
#endif
#endif
		m_device->disconnectFromHost();
	}

private:
	// QTextStream doesn't flush QTcpSocket, and QIODevice doesn't have flush() at all...
	static void FlushIfCan(QIODevice*) {}
	static void FlushIfCan(QTcpSocket* sock) {
		sock->flush();
	}

	Device* m_device;
	bool m_verbose;
	QByteArray m_readed;
};

template <typename Device>
IO<Device> WrapIO(Device* d) {
	return IO<Device>(d);
}

using Socket = IO<QTcpSocket>;

class Process : public IO<QProcess> {
public:
	Process(QString cmd, QStringList args, bool interactive) : IO(&m_proc, true) {
		if (!interactive) {
			m_proc.setProcessChannelMode(QProcess::ForwardedChannels);
		}
		m_proc.start(cmd, args);
	}
	~Process() {
		if (m_kill) m_proc.terminate();
		[this]() { ASSERT_TRUE(m_proc.waitForFinished()); }();
	}
	void ShouldFinishItself() {
		m_kill = false;
	}

private:
	bool m_kill = true;
	QProcess m_proc;
};

void WriteConfig(QString path) {
	Process p("./znc", QStringList() << "--debug" << "--datadir" << path << "--makeconf", true);
	p.ReadUntil("Listen on port");Z;          p.Write("12345");
	p.ReadUntil("Listen using SSL");Z;        p.Write();
	p.ReadUntil("IPv6");Z;                    p.Write();
	p.ReadUntil("Username");Z;                p.Write("user");
	p.ReadUntil("password");Z;                p.Write("hunter2", false);
	p.ReadUntil("Confirm");Z;                 p.Write("hunter2", false);
	p.ReadUntil("Nick [user]");Z;             p.Write();
	p.ReadUntil("Alternate nick [user_]");Z;  p.Write();
	p.ReadUntil("Ident [user]");Z;            p.Write();
	p.ReadUntil("Real name");Z;               p.Write();
	p.ReadUntil("Bind host");Z;               p.Write();
	p.ReadUntil("Set up a network?");Z;       p.Write();
	p.ReadUntil("Name [freenode]");Z;         p.Write("test");
	p.ReadUntil("Server host (host only)");Z; p.Write("127.0.0.1");
	p.ReadUntil("Server uses SSL?");Z;        p.Write();
	p.ReadUntil("6667");Z;                    p.Write();
	p.ReadUntil("password");Z;                p.Write();
	p.ReadUntil("channels");Z;                p.Write();
	p.ReadUntil("Launch ZNC now?");Z;         p.Write("no");
	p.ShouldFinishItself();
}

TEST(Config, AlreadyExists) {
	QTemporaryDir dir;
	WriteConfig(dir.path());Z;
	Process p("./znc", QStringList() << "--debug" << "--datadir" << dir.path() << "--makeconf", true);
	p.ReadUntil("already exists");Z;
}

class ZNCTest : public testing::Test {
protected:
	void SetUp() override {
		WriteConfig(m_dir.path());Z;
		ASSERT_TRUE(m_server.listen(QHostAddress::LocalHost, 6667)) << m_server.errorString().toStdString();Z;
	}

	Socket ConnectIRCd() {
		[this]{ ASSERT_TRUE(m_server.waitForNewConnection(30000 /* msec */)); }();
		return WrapIO(m_server.nextPendingConnection());
	}

	Socket ConnectClient() {
		m_clients.emplace_back();
		QTcpSocket& sock = m_clients.back();
		sock.connectToHost("127.0.0.1", 12345);
		[&]{ ASSERT_TRUE(sock.waitForConnected()) << sock.errorString().toStdString(); }();
		return WrapIO(&sock);
	}

	std::unique_ptr<Process> Run() {
		return std::unique_ptr<Process>(new Process("./znc", QStringList() << "--debug" << "--datadir" << m_dir.path(), false));
	}

	Socket LoginClient() {
		auto client = ConnectClient();
		client.Write("PASS :hunter2");
		client.Write("NICK nick");
		client.Write("USER user/test x x :x");
		return client;
	}

	QTemporaryDir m_dir;
	QTcpServer m_server;
	std::list<QTcpSocket> m_clients;
};

TEST_F(ZNCTest, Connect) {
	auto znc = Run();Z;

	auto ircd = ConnectIRCd();Z;
	ircd.ReadUntil("CAP LS");Z;

	auto client = ConnectClient();Z;
	client.Write("PASS :hunter2");
	client.Write("NICK nick");
	client.Write("USER user/test x x :x");
	client.ReadUntil("Welcome");Z;
	client.Close();

	client = ConnectClient();Z;
	client.Write("PASS :user:hunter2");
	client.Write("NICK nick");
	client.Write("USER u x x x");
	client.ReadUntil("Welcome");Z;
	client.Close();

	client = ConnectClient();Z;
	client.Write("NICK nick");
	client.Write("USER user x x x");
	client.ReadUntil("Configure your client to send a server password");
	client.Close();

	ircd.Write(":server 001 nick :Hello");
	ircd.ReadUntil("WHO");Z;
}

TEST_F(ZNCTest, Channel) {
	auto znc = Run();Z;
	auto ircd = ConnectIRCd();Z;

	auto client = LoginClient();Z;
	client.ReadUntil("Welcome");Z;
	client.Write("JOIN #znc");
	client.Close();

	ircd.Write(":server 001 nick :Hello");
	ircd.ReadUntil("JOIN #znc");Z;
	ircd.Write(":nick JOIN #znc nick :Real");
	ircd.Write(":server 353 nick #znc :nick");
	ircd.Write(":server 366 nick #znc :End of /NAMES list");

	client = LoginClient();Z;
	client.ReadUntil(":nick JOIN :#znc");Z;
}

}  // namespace
<commit_msg>Add test for fix of #528<commit_after>/*
 * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
 *
 * 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 <gtest/gtest.h>
#include <gmock/gmock.h>

#include <QCoreApplication>
#include <QDateTime>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QProcess>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTemporaryDir>
#include <QTextStream>
#include <QTimer>
#include <QUrl>
#include <QUrlQuery>

#include <memory>

#define Z do { if (::testing::Test::HasFatalFailure()) { std::cerr << "At: " << __FILE__ << ":" << __LINE__ << std::endl; return; } } while (0)

using testing::HasSubstr;

namespace {

template <typename Device>
class IO {
public:
	IO(Device* device, bool verbose = false) : m_device(device), m_verbose(verbose) {}
	virtual ~IO() {}
	void ReadUntil(QByteArray pattern) {
		auto deadline = QDateTime::currentDateTime().addSecs(30);
		while (true) {
			int search = m_readed.indexOf(pattern);
			if (search != -1) {
				m_readed.remove(0, search + pattern.length());
				return;
			}
			if (m_readed.length() > pattern.length()) {
				m_readed = m_readed.right(pattern.length());
			}
			const int timeout_ms = QDateTime::currentDateTime().msecsTo(deadline);
			ASSERT_GT(timeout_ms, 0) << "Wanted:" << pattern.toStdString();
			ASSERT_TRUE(m_device->waitForReadyRead(timeout_ms)) << "Wanted: " << pattern.toStdString();
			QByteArray chunk = m_device->readAll();
			if (m_verbose) {
				std::cout << chunk.toStdString() << std::flush;
			}
			m_readed += chunk;
		}
	}
	void Write(QString s = "", bool new_line = true) {
		if (!m_device) return;
		if (m_verbose) {
			std::cout << s.toStdString() << std::flush;
			if (new_line) {
				std::cout << std::endl;
			}
		}
		s += "\n";
		{
			QTextStream str(m_device);
			str << s;
		}
		FlushIfCan(m_device);
	}
	void Close() {
#ifdef __CYGWIN__
#ifdef __x86_64__
		// Qt on cygwin64 silently doesn't send the rest of buffer from socket without this line
		sleep(1);
#endif
#endif
		m_device->disconnectFromHost();
	}

private:
	// QTextStream doesn't flush QTcpSocket, and QIODevice doesn't have flush() at all...
	static void FlushIfCan(QIODevice*) {}
	static void FlushIfCan(QTcpSocket* sock) {
		sock->flush();
	}

	Device* m_device;
	bool m_verbose;
	QByteArray m_readed;
};

template <typename Device>
IO<Device> WrapIO(Device* d) {
	return IO<Device>(d);
}

using Socket = IO<QTcpSocket>;

class Process : public IO<QProcess> {
public:
	Process(QString cmd, QStringList args, bool interactive) : IO(&m_proc, true) {
		if (!interactive) {
			m_proc.setProcessChannelMode(QProcess::ForwardedChannels);
		}
		m_proc.start(cmd, args);
	}
	~Process() {
		if (m_kill) m_proc.terminate();
		[this]() { ASSERT_TRUE(m_proc.waitForFinished()); }();
	}
	void ShouldFinishItself() {
		m_kill = false;
	}

private:
	bool m_kill = true;
	QProcess m_proc;
};

void WriteConfig(QString path) {
	Process p("./znc", QStringList() << "--debug" << "--datadir" << path << "--makeconf", true);
	p.ReadUntil("Listen on port");Z;          p.Write("12345");
	p.ReadUntil("Listen using SSL");Z;        p.Write();
	p.ReadUntil("IPv6");Z;                    p.Write();
	p.ReadUntil("Username");Z;                p.Write("user");
	p.ReadUntil("password");Z;                p.Write("hunter2", false);
	p.ReadUntil("Confirm");Z;                 p.Write("hunter2", false);
	p.ReadUntil("Nick [user]");Z;             p.Write();
	p.ReadUntil("Alternate nick [user_]");Z;  p.Write();
	p.ReadUntil("Ident [user]");Z;            p.Write();
	p.ReadUntil("Real name");Z;               p.Write();
	p.ReadUntil("Bind host");Z;               p.Write();
	p.ReadUntil("Set up a network?");Z;       p.Write();
	p.ReadUntil("Name [freenode]");Z;         p.Write("test");
	p.ReadUntil("Server host (host only)");Z; p.Write("127.0.0.1");
	p.ReadUntil("Server uses SSL?");Z;        p.Write();
	p.ReadUntil("6667");Z;                    p.Write();
	p.ReadUntil("password");Z;                p.Write();
	p.ReadUntil("channels");Z;                p.Write();
	p.ReadUntil("Launch ZNC now?");Z;         p.Write("no");
	p.ShouldFinishItself();
}

TEST(Config, AlreadyExists) {
	QTemporaryDir dir;
	WriteConfig(dir.path());Z;
	Process p("./znc", QStringList() << "--debug" << "--datadir" << dir.path() << "--makeconf", true);
	p.ReadUntil("already exists");Z;
}

// Can't use QEventLoop without existing QCoreApplication
class App {
public:
	App() : m_argv(new char{}), m_app(m_argc, &m_argv) {}
	~App() { delete m_argv; }
private:
	int m_argc = 1;
	char* m_argv;
	QCoreApplication m_app;
};

class ZNCTest : public testing::Test {
protected:
	void SetUp() override {
		WriteConfig(m_dir.path());Z;
		ASSERT_TRUE(m_server.listen(QHostAddress::LocalHost, 6667)) << m_server.errorString().toStdString();Z;
	}

	Socket ConnectIRCd() {
		[this]{ ASSERT_TRUE(m_server.waitForNewConnection(30000 /* msec */)); }();
		return WrapIO(m_server.nextPendingConnection());
	}

	Socket ConnectClient() {
		m_clients.emplace_back();
		QTcpSocket& sock = m_clients.back();
		sock.connectToHost("127.0.0.1", 12345);
		[&]{ ASSERT_TRUE(sock.waitForConnected()) << sock.errorString().toStdString(); }();
		return WrapIO(&sock);
	}

	std::unique_ptr<Process> Run() {
		return std::unique_ptr<Process>(new Process("./znc", QStringList() << "--debug" << "--datadir" << m_dir.path(), false));
	}

	Socket LoginClient() {
		auto client = ConnectClient();
		client.Write("PASS :hunter2");
		client.Write("NICK nick");
		client.Write("USER user/test x x :x");
		return client;
	}

	std::unique_ptr<QNetworkReply> HttpGet(QNetworkRequest request) {
		return HandleHttp(m_network.get(request));
	}
	std::unique_ptr<QNetworkReply> HttpPost(QNetworkRequest request, QList<QPair<QString, QString>> data) {
		request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
		QUrlQuery q;
		q.setQueryItems(data);
		return HandleHttp(m_network.post(request, q.toString().toUtf8()));
	}
	std::unique_ptr<QNetworkReply> HandleHttp(QNetworkReply* reply) {
		QEventLoop loop;
		QObject::connect(reply, &QNetworkReply::finished, [&]() {
			loop.quit();
		});
		QObject::connect(reply, static_cast<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), [&](QNetworkReply::NetworkError e) {
			ADD_FAILURE() << reply->errorString().toStdString();
		});
		QTimer::singleShot(30000 /* msec */, &loop, [&]() {
			ADD_FAILURE() << "connection timeout";
			loop.quit();
		});
		loop.exec();
		return std::unique_ptr<QNetworkReply>(reply);
	}

	App m_app;
	QNetworkAccessManager m_network;
	QTemporaryDir m_dir;
	QTcpServer m_server;
	std::list<QTcpSocket> m_clients;
};

TEST_F(ZNCTest, Connect) {
	auto znc = Run();Z;

	auto ircd = ConnectIRCd();Z;
	ircd.ReadUntil("CAP LS");Z;

	auto client = ConnectClient();Z;
	client.Write("PASS :hunter2");
	client.Write("NICK nick");
	client.Write("USER user/test x x :x");
	client.ReadUntil("Welcome");Z;
	client.Close();

	client = ConnectClient();Z;
	client.Write("PASS :user:hunter2");
	client.Write("NICK nick");
	client.Write("USER u x x x");
	client.ReadUntil("Welcome");Z;
	client.Close();

	client = ConnectClient();Z;
	client.Write("NICK nick");
	client.Write("USER user x x x");
	client.ReadUntil("Configure your client to send a server password");
	client.Close();

	ircd.Write(":server 001 nick :Hello");
	ircd.ReadUntil("WHO");Z;
}

TEST_F(ZNCTest, Channel) {
	auto znc = Run();Z;
	auto ircd = ConnectIRCd();Z;

	auto client = LoginClient();Z;
	client.ReadUntil("Welcome");Z;
	client.Write("JOIN #znc");
	client.Close();

	ircd.Write(":server 001 nick :Hello");
	ircd.ReadUntil("JOIN #znc");Z;
	ircd.Write(":nick JOIN #znc nick :Real");
	ircd.Write(":server 353 nick #znc :nick");
	ircd.Write(":server 366 nick #znc :End of /NAMES list");

	client = LoginClient();Z;
	client.ReadUntil(":nick JOIN :#znc");Z;
}

TEST_F(ZNCTest, HTTP) {
	auto znc = Run();Z;
	auto ircd = ConnectIRCd();Z;
	auto reply = HttpGet(QNetworkRequest(QUrl("http://127.0.0.1:12345/")));Z;
	EXPECT_THAT(reply->rawHeader("Server").toStdString(), HasSubstr("ZNC"));
}

TEST_F(ZNCTest, FixCVE20149403) {
	auto znc = Run();Z;
	auto ircd = ConnectIRCd();Z;
	ircd.Write(":server 001 nick :Hello");
	ircd.Write(":server 005 nick CHANTYPES=# :supports");
	ircd.Write(":server PING :1");
	ircd.ReadUntil("PONG 1");Z;

	QNetworkRequest request;
	request.setRawHeader("Authorization", "Basic " + QByteArray("user:hunter2").toBase64());
	request.setUrl(QUrl("http://127.0.0.1:12345/mods/global/webadmin/addchan"));
	HttpPost(request, {
		{"user", "user"},
		{"network", "test"},
		{"submitted", "1"},
		{"name", "znc"},
	});
	ircd.ReadUntil("JOIN #znc");Z;
	EXPECT_THAT(HttpPost(request, {
		{"user", "user"},
		{"network", "test"},
		{"submitted", "1"},
		{"name", "znc"},
	})->readAll().toStdString(), HasSubstr("Channel [#znc] already exists"));
}

TEST_F(ZNCTest, FixFixOfCVE20149403) {
	auto znc = Run();Z;
	auto ircd = ConnectIRCd();Z;
	ircd.Write(":server 001 nick :Hello");
	ircd.Write(":nick JOIN @#znc nick :Real");
	ircd.ReadUntil("MODE @#znc");Z;
	ircd.Write(":server 005 nick STATUSMSG=@ :supports");
	ircd.Write(":server PING :12345");
	ircd.ReadUntil("PONG 12345");Z;

	QNetworkRequest request;
	request.setRawHeader("Authorization", "Basic " + QByteArray("user:hunter2").toBase64());
	request.setUrl(QUrl("http://127.0.0.1:12345/mods/global/webadmin/addchan"));
	auto reply = HttpPost(request, {
		{"user", "user"},
		{"network", "test"},
		{"submitted", "1"},
		{"name", "@#znc"},
	});
	EXPECT_THAT(reply->readAll().toStdString(), HasSubstr("Could not add channel [@#znc]"));
}

}  // namespace
<|endoftext|>