<commit_before>#ifndef ATL_GC_GC_HPP
#define ATL_GC_GC_HPP

// @file /home/ryan/programming/atl/gc.hpp
// @author Ryan Domigan <ryan_domigan@sutdents@uml.edu>
// Created on Jan 08, 2014
//
// A garbage collected environment.

#include <limits>
#include <algorithm>
#include <functional>
#include <list>
#include <memory>
#include <iterator>

#include <boost/mpl/map.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/mpl/value_type.hpp>

#include "./debug.hpp"
#include "./byte_code.hpp"

#include <gc/ast_pool.hpp>
#include <gc/pool.hpp>
#include <gc/ast_builder.hpp>
#include <gc/marked.hpp>
#include <gc/vm_closure.hpp>

namespace atl
{
	/*****************/
	/*	 ____  ____  */
	/*	/ ___|/ ___| */
	/* | |  _| |     */
	/* | |_| | |___  */
	/*	\____|\____| */
	/*****************/
	struct GC;

	namespace gc_detail
	{
		struct Counter
		{
			size_t& count;
			GC* gc;

			Counter(GC *gc_, size_t& count_) : count(count_), gc(gc_) {}

			template<class Mem>
			void operator()(Mem const&)
			{
				auto &mem = gc->*Mem::value;
				count += mem.num_allocated();
			}
		};

		struct Sweeper
		{
			GC* gc;

			Sweeper(GC *gc_) : gc(gc_) {}

			template<class Mem>
			void operator()(Mem const&)
			{
				auto &mem = gc->*Mem::value;
				mem.sweep();
			}
		};

		// Class needs to implement MarkBase to get marked by the GC
		template<class GC>
		struct MarkBase;

		// Manage the lifespan of the GC's reference to a MarkBase
		// instance.
		template<class GC>
		struct ManageMarking
		{
			MarkBase<GC>* container;
			GC* gc;
			typename GC::MarkBaseList::iterator itr;

			ManageMarking(GC* gc_, MarkBase<GC>* container_)
				: container(container_),
				  gc(gc_)
			{ itr = gc->add_mark_base(container); }

			void drop()
			{
				if(gc) { gc->remove_mark_base(itr); }
			}

			void take(ManageMarking&& other, MarkBase<GC>* container_)
			{
				container = container_;
				gc = other.gc;
				itr = other.itr;
				*itr = container;
				other.gc = nullptr;
			}

			ManageMarking(ManageMarking&& other, MarkBase<GC>* container_)
			{ take(std::move(other), container_); }

			ManageMarking()=delete;
			ManageMarking(ManageMarking const&)=delete;
			ManageMarking(ManageMarking&&)=delete;

			~ManageMarking()
			{ drop(); }
		};

		template<class GC>
		struct MarkBase
		{
			ManageMarking<GC> manage_marking;
			MarkBase(GC& gc)
				: manage_marking(&gc, this)
			{}
			MarkBase(MarkBase const& other)
				: manage_marking(other.manage_marking.gc, this)
			{}
			MarkBase(MarkBase&& other)
				: manage_marking(std::move(other.manage_marking), this)
			{}

			MarkBase& operator=(MarkBase&& other)
			{
				manage_marking.drop();
				manage_marking.take(std::move(other.manage_marking), this);
				return *this;
			}

			virtual void mark()=0;
		};
	}

	struct GC
	{
		typedef ::atl::gc_detail::MarkBase<GC> MarkBase;
		typedef std::function<void (GC&)> MarkCallback;
		typedef std::list<MarkCallback> RootsType;
		typedef std::list<MarkBase*> MarkBaseList;

		typedef ::atl::AstPool<GC> AstPool;
		typedef ::atl::ast_builder::AstBuilder<AstPool> AstBuilder;

		typedef std::function<void (AstBuilder&)> ast_composer;

		RootsType _roots;
		MarkBaseList _mark_bases;
		Marked<Any> *_cxx_stack;

		// Adds callbacks which will be invoked during the mark phase of the GC.
		// @param fn: the callback
		RootsType::iterator add_marker(MarkCallback const& fn)
		{
			_roots.push_front(fn);
			return _roots.begin();
		}

		void remove_marker(RootsType::iterator itr) { _roots.erase(itr); }

		MarkBaseList::iterator add_mark_base(MarkBase* item)
		{
			_mark_bases.push_front(item);
			return _mark_bases.begin();
		}

		void remove_mark_base(MarkBaseList::iterator itr) { _mark_bases.erase(itr); }

		AstPool _ast_pool;
		ClosurePool _closure_pool;

		memory_pool::Pool< LambdaMetadata > _lambda_metadata_heap;
		memory_pool::Pool< String > _string_heap;
		memory_pool::Pool< CxxFunctor > _primitive_recursive_heap;
		memory_pool::Pool< Symbol > _symbol_heap;
		memory_pool::Pool< Scheme > _scheme_heap;

		bool _gc_in_progress;

		template< class T,  memory_pool::Pool<T> GC::*member >
		struct MemberPtr {
			typedef memory_pool::Pool<T> GC::* PoolType;
			/* man this would be easier with inline definitions. */
			const static PoolType value;
		};

		typedef mpl::map< mpl::pair< LambdaMetadata , MemberPtr<LambdaMetadata, &GC::_lambda_metadata_heap > >
		                  , mpl::pair< String , MemberPtr<String, &GC::_string_heap > >
		                  , mpl::pair< CxxFunctor,
		                               MemberPtr<CxxFunctor, &GC::_primitive_recursive_heap > >
		                  , mpl::pair< Symbol,	MemberPtr<Symbol, &GC::_symbol_heap > >
		                  , mpl::pair< Scheme,	MemberPtr<Scheme, &GC::_scheme_heap > >
		                  > PoolMap;

		template<class T>
		T* alloc_from(memory_pool::Pool<T> &pool)
		{
			auto result = pool.alloc();

			if(result == nullptr) {
				gc();
				result = pool.alloc();
				if(result == nullptr)
					{ throw std::string("out of memory"); }
			}

			return result;
		}

		GC() : _cxx_stack(nullptr), _ast_pool(*this), _gc_in_progress(false) {}

		// Mark everything the GC knows about.  This method was broken
		// out for testing; use the 'gc()' method.
		void _mark()
		{
			_ast_pool.gc_start();
			_ast_pool.mark();

			for(auto& i : _roots) { i(*this); }
			for(auto& i : _mark_bases) { i->mark(); }

			auto marked = _cxx_stack;
			while(marked)
				{
					mark(marked->any);
					marked = marked->_up;
				}
		}

		// Sweep marked objects.  This method was broken out for
		// testing; use the gc() method.
		void _sweep()
		{
			auto sweeper = gc_detail::Sweeper(this);
			mpl::for_each
				<PoolMap,
				 typename mpl::lambda< mpl::value_type<PoolMap, mpl::_1 > >::type
				 >(sweeper);
			_ast_pool.gc_finish();
		}

		void gc()
		{
			assert(!_gc_in_progress);
			_gc_in_progress = true;
			_mark();
			_sweep();
			_gc_in_progress = false;
		}

		void mark(String& str)
		{ _string_heap.mark(&str); }

		void mark(CxxFunctor& functor)
		{
			_primitive_recursive_heap.mark(&functor);
			mark(functor.type);
		}

		void mark(Scheme& scheme)
		{
			_scheme_heap.mark(&scheme);
			mark(scheme.type);
		}

		void mark(Symbol& sym)
		{
			_symbol_heap.mark(&sym);
			mark(sym.value);
			// The Scheme is on the Symbol, not the Scheme heap, so
			// just check its type part.
			mark(sym.scheme.type);
		}

		void mark(LambdaMetadata& metadata)
		{
			_lambda_metadata_heap.mark(&metadata);

			if(metadata.has_closure_values)
				{ mark(metadata.closure_values); }

			for(auto sym : metadata.closure)
				{ mark(*sym); }

			mark(metadata.formals);
			mark(metadata.return_type);
		}

		void mark(Ast& ast)
		{ ast = _ast_pool.move(ast); }

		void mark(Any& aa)
		{
			switch(aa._tag)
				{
				case tag<Lambda>::value:
					if(aa.value) { mark(*unwrap<Lambda>(aa).value); }
					break;

				case tag<LambdaMetadata>::value:
					mark(unwrap<LambdaMetadata>(aa));
					break;

				case tag<String>::value:
					mark(unwrap<String>(aa));
					break;

				case tag<CxxFunctor>::value:
					mark(unwrap<CxxFunctor>(aa));
					break;

				case tag<Symbol>::value:
					mark(unwrap<Symbol>(aa));
					break;

				case tag<Scheme>::value:
					mark(unwrap<Scheme>(aa));
					break;

				case tag<Ast>::value:
					mark(unwrap<Ast>(aa));
					break;

				default:
					break;
				}
		}

		/*****************************/
		/**  __	 __	      _	        **/
		/** |  \/  | __ _| | _____  **/
		/** | |\/| |/ _` | |/ / _ \ **/
		/** | |	 | | (_| |   <	__/ **/
		/** |_|	 |_|\__,_|_|\_\___| **/
		/*****************************/
		template<class T>
		T* alloc()
		{
			static_assert( mpl::has_key<PoolMap, T>::value,
			               "GC::Type does not have corrosponding pool." );
			return alloc_from( (this->*mpl::at<PoolMap,T>::type::value) );
		}

		template<class Type, class ... Types>
		Type* raw_make(Types ... args)
		{ return new (alloc<Type>()) Type (args...); }

		template<class Type, class ... Types>
		Any amake(Types ... args)
		{ return Any(tag<Type>::value , raw_make<Type>(args...)); }

		// Unpacks any of the `args` which are of Marked type before
		// passing them to the constructor
		template<class Type, class ... Types>
		Marked<Type> make(Types ... args)
		{
			return Marked<Type>(_cxx_stack,
			                    Any(tag<Type>::value,
			                        raw_make<Type>(unpack_marked(args)...)));
		}

		template<class T>
		Marked<T> marked(T& thing)
		{ return Marked<T>(_cxx_stack, thing); }

		Marked<Ast> marked(Ast thing)
		{ return Marked<Ast>(_cxx_stack, wrap(thing)); }

		Marked<Any> marked(Any thing)
		{ return Marked<Any>(_cxx_stack, thing); }

		AstBuilder ast_builder()
		{ return AstBuilder(_ast_pool, _ast_pool.ast_backer()); }

		AstBuilder ast_builder(size_t nn)
		{ return AstBuilder(_ast_pool, _ast_pool.ast_backer(nn)); }

		Ast raw_ast(ast_composer const& func)
		{
			auto ast = ast_builder();
			func(ast);
			return ast.root();
		}

		Marked<Ast> operator()(ast_composer const& func)
		{
			auto ast = ast_builder();
			func(ast);
			return Marked<Ast>(_cxx_stack, wrap(ast.root()));
		}

		size_t cells_allocated()
		{
			size_t count = 0;
			auto counter = gc_detail::Counter(this, count);
			mpl::for_each
				<PoolMap,
				 typename mpl::lambda< mpl::value_type<PoolMap, mpl::_1 > >::type
				 >(counter);

			return count + _ast_pool.size();
		}

		pcode::value_type* closure(pcode::value_type body_location,
		                           size_t formals,
		                           size_t captures)
		{ return _closure_pool.closure(body_location, formals, captures); }
	};

	template< class T,	memory_pool::Pool<T> GC::*member >
	const typename GC::MemberPtr<T,member>::PoolType GC::MemberPtr<T,member>::value = member;

	typedef GC::AstBuilder AstBuilder;
	typedef ast_builder::NestAst<AstBuilder> NestAst;
	typedef GC::ast_composer ast_composer;
	typedef GC::MarkBase MarkBase;
}

#endif
<commit_msg>gc: Keep a compile-time set of the types which require marking<commit_after>#ifndef ATL_GC_GC_HPP
#define ATL_GC_GC_HPP

// @file /home/ryan/programming/atl/gc.hpp
// @author Ryan Domigan <ryan_domigan@sutdents@uml.edu>
// Created on Jan 08, 2014
//
// A garbage collected environment.

#include <limits>
#include <algorithm>
#include <functional>
#include <list>
#include <memory>
#include <iterator>

#include <boost/mpl/map.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/value_type.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/apply.hpp>

#include "./debug.hpp"
#include "./byte_code.hpp"

#include <gc/ast_pool.hpp>
#include <gc/pool.hpp>
#include <gc/ast_builder.hpp>
#include <gc/marked.hpp>
#include <gc/vm_closure.hpp>

namespace atl
{
	/*****************/
	/*	 ____  ____  */
	/*	/ ___|/ ___| */
	/* | |  _| |     */
	/* | |_| | |___  */
	/*	\____|\____| */
	/*****************/
	struct GC;

	namespace gc_detail
	{
		struct Counter
		{
			size_t& count;
			GC* gc;

			Counter(GC *gc_, size_t& count_) : count(count_), gc(gc_) {}

			template<class Mem>
			void operator()(Mem const&)
			{
				auto &mem = gc->*Mem::value;
				count += mem.num_allocated();
			}
		};

		struct Sweeper
		{
			GC* gc;

			Sweeper(GC *gc_) : gc(gc_) {}

			template<class Mem>
			void operator()(Mem const&)
			{
				auto &mem = gc->*Mem::value;
				mem.sweep();
			}
		};

		// Class needs to implement MarkBase to get marked by the GC
		template<class GC>
		struct MarkBase;

		// Manage the lifespan of the GC's reference to a MarkBase
		// instance.
		template<class GC>
		struct ManageMarking
		{
			MarkBase<GC>* container;
			GC* gc;
			typename GC::MarkBaseList::iterator itr;

			ManageMarking(GC* gc_, MarkBase<GC>* container_)
				: container(container_),
				  gc(gc_)
			{ itr = gc->add_mark_base(container); }

			void drop()
			{
				if(gc) { gc->remove_mark_base(itr); }
			}

			void take(ManageMarking&& other, MarkBase<GC>* container_)
			{
				container = container_;
				gc = other.gc;
				itr = other.itr;
				*itr = container;
				other.gc = nullptr;
			}

			ManageMarking(ManageMarking&& other, MarkBase<GC>* container_)
			{ take(std::move(other), container_); }

			ManageMarking()=delete;
			ManageMarking(ManageMarking const&)=delete;
			ManageMarking(ManageMarking&&)=delete;

			~ManageMarking()
			{ drop(); }
		};

		template<class GC>
		struct MarkBase
		{
			ManageMarking<GC> manage_marking;
			MarkBase(GC& gc)
				: manage_marking(&gc, this)
			{}
			MarkBase(MarkBase const& other)
				: manage_marking(other.manage_marking.gc, this)
			{}
			MarkBase(MarkBase&& other)
				: manage_marking(std::move(other.manage_marking), this)
			{}

			MarkBase& operator=(MarkBase&& other)
			{
				manage_marking.drop();
				manage_marking.take(std::move(other.manage_marking), this);
				return *this;
			}

			virtual void mark()=0;
		};
	}

	namespace pl = ::boost::mpl::placeholders;

	struct GC
	{
		typedef ::atl::gc_detail::MarkBase<GC> MarkBase;
		typedef std::function<void (GC&)> MarkCallback;
		typedef std::list<MarkCallback> RootsType;
		typedef std::list<MarkBase*> MarkBaseList;

		typedef ::atl::AstPool<GC> AstPool;
		typedef ::atl::ast_builder::AstBuilder<AstPool> AstBuilder;

		typedef std::function<void (AstBuilder&)> ast_composer;

		RootsType _roots;
		MarkBaseList _mark_bases;
		Marked<Any> *_cxx_stack;

		// Adds callbacks which will be invoked during the mark phase of the GC.
		// @param fn: the callback
		RootsType::iterator add_marker(MarkCallback const& fn)
		{
			_roots.push_front(fn);
			return _roots.begin();
		}

		void remove_marker(RootsType::iterator itr) { _roots.erase(itr); }

		MarkBaseList::iterator add_mark_base(MarkBase* item)
		{
			_mark_bases.push_front(item);
			return _mark_bases.begin();
		}

		void remove_mark_base(MarkBaseList::iterator itr) { _mark_bases.erase(itr); }

		AstPool _ast_pool;
		ClosurePool _closure_pool;

		memory_pool::Pool< LambdaMetadata > _lambda_metadata_heap;
		memory_pool::Pool< String > _string_heap;
		memory_pool::Pool< CxxFunctor > _primitive_recursive_heap;
		memory_pool::Pool< Symbol > _symbol_heap;
		memory_pool::Pool< Scheme > _scheme_heap;

		bool _gc_in_progress;

		template< class T,  memory_pool::Pool<T> GC::*member >
		struct MemberPtr {
			typedef memory_pool::Pool<T> GC::* PoolType;
			/* man this would be easier with inline definitions. */
			const static PoolType value;
		};

		typedef mpl::map< mpl::pair< LambdaMetadata , MemberPtr<LambdaMetadata, &GC::_lambda_metadata_heap > >
		                  , mpl::pair< String , MemberPtr<String, &GC::_string_heap > >
		                  , mpl::pair< CxxFunctor,
		                               MemberPtr<CxxFunctor, &GC::_primitive_recursive_heap > >
		                  , mpl::pair< Symbol,	MemberPtr<Symbol, &GC::_symbol_heap > >
		                  , mpl::pair< Scheme,	MemberPtr<Scheme, &GC::_scheme_heap > >
		                  > PoolMap;

		typedef typename mpl::fold<PoolMap,
		                           mpl::set<>,
		                           mpl::lambda< mpl::insert<pl::_1, mpl::first<pl::_2> > >
		                           >::type BasicPoolTypes;

		typedef typename tmpl::Apply<mpl::insert,
		                             mpl::insert<BasicPoolTypes, Ast>,
		                             tmpl::Identity<Any> >::type MarkableTypes;

		template<class T>
		T* alloc_from(memory_pool::Pool<T> &pool)
		{
			auto result = pool.alloc();

			if(result == nullptr) {
				gc();
				result = pool.alloc();
				if(result == nullptr)
					{ throw std::string("out of memory"); }
			}

			return result;
		}

		GC() : _cxx_stack(nullptr), _ast_pool(*this), _gc_in_progress(false) {}

		// Mark everything the GC knows about.  This method was broken
		// out for testing; use the 'gc()' method.
		void _mark()
		{
			_ast_pool.gc_start();
			_ast_pool.mark();

			for(auto& i : _roots) { i(*this); }
			for(auto& i : _mark_bases) { i->mark(); }

			auto marked = _cxx_stack;
			while(marked)
				{
					mark(marked->any);
					marked = marked->_up;
				}
		}

		// Sweep marked objects.  This method was broken out for
		// testing; use the gc() method.
		void _sweep()
		{
			auto sweeper = gc_detail::Sweeper(this);
			mpl::for_each
				<PoolMap,
				 typename mpl::lambda< mpl::value_type<PoolMap, mpl::_1 > >::type
				 >(sweeper);
			_ast_pool.gc_finish();
		}

		void gc()
		{
			assert(!_gc_in_progress);
			_gc_in_progress = true;
			_mark();
			_sweep();
			_gc_in_progress = false;
		}

		void mark(String& str)
		{ _string_heap.mark(&str); }

		void mark(CxxFunctor& functor)
		{
			_primitive_recursive_heap.mark(&functor);
			mark(functor.type);
		}

		void mark(Scheme& scheme)
		{
			_scheme_heap.mark(&scheme);
			mark(scheme.type);
		}

		void mark(Symbol& sym)
		{
			_symbol_heap.mark(&sym);
			mark(sym.value);
			// The Scheme is on the Symbol, not the Scheme heap, so
			// just check its type part.
			mark(sym.scheme.type);
		}

		void mark(LambdaMetadata& metadata)
		{
			_lambda_metadata_heap.mark(&metadata);

			if(metadata.has_closure_values)
				{ mark(metadata.closure_values); }

			for(auto sym : metadata.closure)
				{ mark(*sym); }

			mark(metadata.formals);
			mark(metadata.return_type);
		}

		void mark(Ast& ast)
		{ ast = _ast_pool.move(ast); }

		void mark(Any& aa)
		{
			switch(aa._tag)
				{
				case tag<Lambda>::value:
					if(aa.value) { mark(*unwrap<Lambda>(aa).value); }
					break;

				case tag<LambdaMetadata>::value:
					mark(unwrap<LambdaMetadata>(aa));
					break;

				case tag<String>::value:
					mark(unwrap<String>(aa));
					break;

				case tag<CxxFunctor>::value:
					mark(unwrap<CxxFunctor>(aa));
					break;

				case tag<Symbol>::value:
					mark(unwrap<Symbol>(aa));
					break;

				case tag<Scheme>::value:
					mark(unwrap<Scheme>(aa));
					break;

				case tag<Ast>::value:
					mark(unwrap<Ast>(aa));
					break;

				default:
					break;
				}
		}

		/*****************************/
		/**  __	 __	      _	        **/
		/** |  \/  | __ _| | _____  **/
		/** | |\/| |/ _` | |/ / _ \ **/
		/** | |	 | | (_| |   <	__/ **/
		/** |_|	 |_|\__,_|_|\_\___| **/
		/*****************************/
		template<class T>
		T* alloc()
		{
			static_assert( mpl::has_key<PoolMap, T>::value,
			               "GC::Type does not have corrosponding pool." );
			return alloc_from( (this->*mpl::at<PoolMap,T>::type::value) );
		}

		template<class Type, class ... Types>
		Type* raw_make(Types ... args)
		{ return new (alloc<Type>()) Type (args...); }

		template<class Type, class ... Types>
		Any amake(Types ... args)
		{ return Any(tag<Type>::value , raw_make<Type>(args...)); }

		// Unpacks any of the `args` which are of Marked type before
		// passing them to the constructor
		template<class Type, class ... Types>
		Marked<Type> make(Types ... args)
		{
			return Marked<Type>(_cxx_stack,
			                    Any(tag<Type>::value,
			                        raw_make<Type>(unpack_marked(args)...)));
		}

		template<class T>
		Marked<T> marked(T& thing)
		{ return Marked<T>(_cxx_stack, thing); }

		Marked<Ast> marked(Ast thing)
		{ return Marked<Ast>(_cxx_stack, wrap(thing)); }

		Marked<Any> marked(Any thing)
		{ return Marked<Any>(_cxx_stack, thing); }

		AstBuilder ast_builder()
		{ return AstBuilder(_ast_pool, _ast_pool.ast_backer()); }

		AstBuilder ast_builder(size_t nn)
		{ return AstBuilder(_ast_pool, _ast_pool.ast_backer(nn)); }

		Ast raw_ast(ast_composer const& func)
		{
			auto ast = ast_builder();
			func(ast);
			return ast.root();
		}

		Marked<Ast> operator()(ast_composer const& func)
		{
			auto ast = ast_builder();
			func(ast);
			return Marked<Ast>(_cxx_stack, wrap(ast.root()));
		}

		size_t cells_allocated()
		{
			size_t count = 0;
			auto counter = gc_detail::Counter(this, count);
			mpl::for_each
				<PoolMap,
				 typename mpl::lambda< mpl::value_type<PoolMap, mpl::_1 > >::type
				 >(counter);

			return count + _ast_pool.size();
		}

		pcode::value_type* closure(pcode::value_type body_location,
		                           size_t formals,
		                           size_t captures)
		{ return _closure_pool.closure(body_location, formals, captures); }
	};

	template< class T,	memory_pool::Pool<T> GC::*member >
	const typename GC::MemberPtr<T,member>::PoolType GC::MemberPtr<T,member>::value = member;

	typedef GC::AstBuilder AstBuilder;
	typedef ast_builder::NestAst<AstBuilder> NestAst;
	typedef GC::ast_composer ast_composer;
	typedef GC::MarkBase MarkBase;
}

#endif
<|endoftext|>


<commit_before>/*
qgvdial is a cross platform Google Voice Dialer
Copyright (C) 2009-2012  Yuvraaj Kelkar

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

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 Street, Fifth Floor, Boston, MA  02110-1301  USA

Contact: yuvraaj@gmail.com
*/

#include "QGVConnection.h"
#include "gen/connection_adapter.h"
#include "QGVTextChannel.h"

QGVConnection::QGVConnection(const QString &u, const QString &p,
                             QObject *parent /*= NULL*/)
: QObject(parent)
, m_user(u)
, m_pass(p)
, m_hasImmortalHandle(false)
, m_channelNumber(0)
, m_connStatus(QGVConnection::Disconnected)
{
    Q_DEBUG("Here");
}//QGVConnection::QGVConnection

QGVConnection::~QGVConnection()
{
    Q_DEBUG("Here");
}//QGVConnection::~QGVConnection

void
QGVConnection::AddClientInterest(const QStringList & /*Tokens*/)
{
    Q_DEBUG("Not implemented");
}//QGVConnection::AddClientInterest

void
QGVConnection::Connect()
{
    if (m_connStatus != QGVConnection::Connected) {
        m_connStatus = QGVConnection::Connected;
        emit StatusChanged (m_connStatus, QGVConnection::Requested);
        Q_DEBUG(QString("Connect requested for user %1").arg(m_user));
    } else {
        Q_WARN(QString("Duplicate connect for user %1").arg(m_user));
    }
}//QGVConnection::Connect

void
QGVConnection::Disconnect()
{
    if (m_connStatus != QGVConnection::Disconnected) {
        m_connStatus = QGVConnection::Disconnected;
        emit StatusChanged (m_connStatus, QGVConnection::Requested);
        Q_DEBUG(QString("Disconnect requested for user %1").arg(m_user));
    } else {
        Q_WARN(QString("Duplicate disconnect for user %1").arg(m_user));
    }
}//QGVConnection::Disconnect

QStringList
QGVConnection::GetInterfaces()
{
    QStringList rv;
    rv << ofdT_Conn_Iface_Requests;
    Q_DEBUG(QString("Returning interfaces: [%1]").arg(rv.join (", ")));
    return rv;
}//QGVConnection::GetInterfaces

QString
QGVConnection::GetProtocol()
{
    Q_DEBUG("Requested protocol");
    return QGV_ProtocolName;
}//QGVConnection::GetProtocol

uint
QGVConnection::GetSelfHandle()
{
    if (m_connStatus != QGVConnection::Connected) {
        sendErrorReply (ofdT_Err_Disconnected,
                        "Connection object not connected");
        Q_WARN("Not connected");
    } else {
        Q_DEBUG(QString("Returning self handle %1").arg(m_selfHandle));
    }
    return m_selfHandle;
}//QGVConnection::GetSelfHandle

uint
QGVConnection::GetStatus()
{
    Q_DEBUG(QString("Returning connection status %1").arg(m_connStatus));
    return m_connStatus;
}//QGVConnection::GetStatus

void
QGVConnection::HoldHandles(uint /*Handle_Type*/, const Qt_Type_au & /*Handles*/)
{
    if (m_connStatus != QGVConnection::Connected) {
        sendErrorReply (ofdT_Err_Disconnected,
                        "Connection object not connected");
        Q_WARN("Not connected");
        return;
    }

    // There's nothing really to "hold"
    Q_DEBUG("Not implemented");
}//QGVConnection::HoldHandles

QStringList
QGVConnection::InspectHandles(uint /*Handle_Type*/, const Qt_Type_au & /*Handles*/)
{
    QStringList rv;

    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("Inspect handles. I don't really know what to do here.");
    } while (0);

    return rv;
}//QGVConnection::InspectHandles

Qt_Type_a_osuu
QGVConnection::ListChannels()
{
    Qt_Type_a_osuu rv;

    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("No channels to list.");
    } while (0);

    return rv;
}//QGVConnection::ListChannels

void
QGVConnection::ReleaseHandles(uint /*Handle_Type*/, const Qt_Type_au & /*Handles*/)
{
    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("Release handles. I don't really know what to do here.");
    } while (0);
}//QGVConnection::ReleaseHandles

void
QGVConnection::RemoveClientInterest(const QStringList & /*Tokens*/)
{
    Q_DEBUG("Not implemented");
}//QGVConnection::RemoveClientInterest

QDBusObjectPath
QGVConnection::RequestChannel(const QString & /*Type*/, uint /*Handle_Type*/,
                              uint /*Handle*/, bool /*Suppress_Handler*/)
{
    QDBusObjectPath rv;

    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("Request channel. I don't really know what to do here.");
        sendErrorReply (ofdT_Err_NotImplemented, "Don't know how");
    } while (0);

    return rv;
}//QGVConnection::RequestChannel

Qt_Type_au
QGVConnection::RequestHandles(uint /*Handle_Type*/,
                              const QStringList & /*Identifiers*/)
{
    Qt_Type_au rv;

    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("Request handles. I don't really know what to do here.");
        sendErrorReply (ofdT_Err_NotImplemented, "Don't know how");
    } while (0);

    return rv;
}//QGVConnection::RequestHandles

void
QGVConnection::setSelfHandle(uint h)
{
    Q_DEBUG("Here");
    m_selfHandle = h;
}//QGVConnection::SetSelfHandle

int
QGVConnection::getSelfHandle()
{
    Q_DEBUG("Here");
    return m_selfHandle;
}//QGVConnection::getSelfHandle

QString
QGVConnection::getDBusObjectPath()
{
    return m_dbusObjectPath;
}//QGVConnection::getDBusObjectPath

QString
QGVConnection::getDBusBusName()
{
    return m_dbusBusName;
}//QGVConnection::getDBusBusName

bool
QGVConnection::registerObject()
{
    ConnectionAdaptor *ca = new ConnectionAdaptor(this);
    if (NULL == ca) {
        Q_WARN("Failed to create connection adapter object");
        return false;
    }
    RequestsAdaptor *ra = new RequestsAdaptor(this);
    if (NULL == ra) {
        Q_WARN("Failed to create connection adapter object");
        delete ca;
        return false;
    }

    bool connObjReg = false, connSrvReg = false;

    QString noAmpUser = m_user;
    noAmpUser.replace('@', '_');
    noAmpUser.replace('.', '_');

    m_dbusObjectPath = QGV_CONN_OP + noAmpUser;
    m_dbusBusName = QGV_CONN_SP "." + noAmpUser;

    QDBusConnection sessionBus = QDBusConnection::sessionBus();
    bool rv = false;
    do { // Begin cleanup block (not a loop)
        rv = sessionBus.registerObject(m_dbusObjectPath, this);
        if (!rv) {
            Q_WARN(QString("Couldn't register Connection object for user %1")
                    .arg(m_user));
            break;
        }
        connObjReg = true;

        rv = sessionBus.registerService (m_dbusBusName);
        if (!rv) {
            Q_WARN(QString("Couldn't register Connection bus for user %1")
                    .arg(m_user));
            break;
        }
        connSrvReg = true;

        Q_DEBUG(QString("Connection registered for user %1").arg(m_user));
    } while (0); // End cleanup block (not a loop)

    if (!rv) {
        if (connObjReg) {
            sessionBus.unregisterObject(m_dbusObjectPath);
        }
        if (connSrvReg) {
            sessionBus.unregisterService (m_dbusBusName);
        }
        m_dbusObjectPath.clear ();
        m_dbusBusName.clear ();
    }

    return rv;
}//QGVConnection::registerObject

void
QGVConnection::unregisterObject()
{
    QDBusConnection sessionBus = QDBusConnection::sessionBus();
    sessionBus.unregisterObject (m_dbusObjectPath);
    sessionBus.unregisterService (m_dbusBusName);
}//QGVConnection::unregisterObject

bool
QGVConnection::hasImmortalHandles() const
{
    Q_DEBUG("Here");
    return m_hasImmortalHandle;
}//QGVConnection::hasImmortalHandles

bool
QGVConnection::processChannel(const QVariantMap &request,
                              QDBusObjectPath &objPath)
{
    QVariant val;

    if (!request.contains (ofdT_Channel_TargetID)) {
        sendErrorReply (ofdT_Err_InvalidArgument,
                        "Target ID not present in request");
        Q_WARN("Target ID not present in request");
        return false;
    }

    val = request[ofdT_Channel_TargetID];
    QString strNum = val.toString ();
    if ((!val.isValid ()) || (strNum.isEmpty ())) {
        sendErrorReply (ofdT_Err_InvalidArgument,
                        "Target ID in request is not valid");
        Q_WARN("Target ID in request is not valid");
        return false;
    }

    if (!request.contains (ofdT_Channel_ChannelType)) {
        sendErrorReply (ofdT_Err_InvalidArgument,
                        "Channel type not present in request");
        Q_WARN("Target ID not present in request");
        return false;
    }

    val = request[ofdT_Channel_ChannelType];
    QString strType = val.toString ();
    if ((!val.isValid ()) || (strType.isEmpty ())) {
        sendErrorReply (ofdT_Err_InvalidArgument,
                        "Channel type in request is not valid");
        Q_WARN("Target ID in request is not valid");
        return false;
    }

    QStringList keys = request.keys ();
    foreach (QString key, keys) {
        Q_DEBUG(QString("[%1] = %2").arg(key, request[key].toString()));
    }

    bool success = false;
    if (strType == ofdT_ChannelType_StreamedMedia) {
        Q_DEBUG(QString("Call to %1").arg(strNum));

        QDBusInterface iface("org.QGVDial.APIServer", "/org/QGVDial/CallServer",
                             "", QDBusConnection::sessionBus());
        if (!iface.isValid()) {
            sendErrorReply(ofdT_Err_NetworkError,
                           "qgvtp - QGVDial call interface is not ready");
            Q_WARN("QGVDial call interface is not ready");
            return false;
        }
        iface.call("Call", strNum);

        Q_DEBUG("Call started successfully");
        sendErrorReply (ofdT_Err_NetworkError, "Channel created successfully");
        success = true;
    } else if (strType == ofdT_ChannelType_Text) {
        Q_DEBUG(QString("Text to %1.").arg(strNum));

        QString objName = m_dbusObjectPath
                           + QString("/%1").arg(++m_channelNumber);
        QGVTextChannel *textChan = new QGVTextChannel(objName, strNum, this);
        bool rv = textChan->registerObject ();
        if (rv) {
            objPath.setPath (objName);

            connect(textChan,
                    SIGNAL(pingNewChannel(QDBusObjectPath,QString,uint,uint,bool)),
                    this,
                    SLOT(onNewChannel(QDBusObjectPath,QString,uint,uint,bool)));

            Q_DEBUG("Text channel created.");
            success = true;
        } else {
            delete textChan;
            Q_WARN("Failed to create text channel");
            success = false;
        }

/*
        QDBusInterface iface("org.QGVDial.APIServer", "/org/QGVDial/TextServer",
                             "", QDBusConnection::sessionBus());
        if (!iface.isValid()) {
            sendErrorReply(ofdT_Err_NotAvailable,
                           "qgvtp - QGVDial text interface is not ready");
            Q_WARN("QGVDial text interface is not ready");
            return false;
        }

        QStringList listNumbers;
        listNumbers += strNum;
        iface.call("TextWithoutData", listNumbers);

        Q_DEBUG("Text initiated successfully");
        sendErrorReply (ofdT_Err_NetworkError, "Channel created successfully");
        success = true;
*/
    } else {
        sendErrorReply (ofdT_Err_UnsupportedMedia,
                        "Channel type in request is not valid");
        Q_WARN(QString("Unsupported channel type %1").arg(strType));
        return false;
    }

    return success;
}//QGVConnection::processChannel

void
QGVConnection::onNewChannel(const QDBusObjectPath &Object_Path,
                            const QString &Channel_Type, uint Handle_Type,
                            uint Handle, bool Suppress_Handler)
{
    Qt_Type_a_o_dict_sv chanInfoList;
    Struct_o_dict_sv chanInfo;

    Q_DEBUG("Time for a new channel");

    chanInfo.o = Object_Path;
    chanInfo.vmap[ofdT_Channel_ChannelType] = Channel_Type;
    chanInfo.vmap[ofdT_Channel_TargetHandleType] = Handle_Type;
    chanInfo.vmap[ofdT_Channel_TargetHandle] = Handle;
    chanInfo.vmap[ofdT_Channel_TargetID] = "";
    chanInfo.vmap[ofdT_Channel_Requested] = Suppress_Handler;

    chanInfoList << chanInfo;
    emit NewChannels (chanInfoList);
    emit NewChannel (Object_Path, Channel_Type, Handle_Type, Handle,
                     Suppress_Handler);
}//QGVConnection::onNewChannel

QDBusObjectPath
QGVConnection::CreateChannel(const QVariantMap &Request,    // IN
                             QVariantMap & /*Properties*/)  // OUT
{
    Q_DEBUG("Here");

    QDBusObjectPath objPath;
    bool success = processChannel (Request, objPath);
    return objPath;
}//QGVConnection::CreateChannel

bool
QGVConnection::EnsureChannel(const QVariantMap &Request,    // IN
                             QDBusObjectPath & Channel, // OUT
                             QVariantMap & /*Properties*/)  // OUT
{
    Q_DEBUG("Here");

    QDBusObjectPath objPath;
    bool success = processChannel (Request, objPath);
    if (success) {
        Channel = objPath;
    }

    return success;
}//QGVConnection::EnsureChannel

Qt_Type_a_o_dict_sv
QGVConnection::channels() const
{
    Qt_Type_a_o_dict_sv rv;
    // Always return an empty channels list
    Q_DEBUG("Returning empty channels list");
    return rv;
}//QGVConnection::channels

Qt_Type_a_dict_sv_as
QGVConnection::requestableChannelClasses() const
{
    Q_DEBUG("Here");

    uint hType(1);  // Handle type : Contact
    Struct_dict_sv_as r1, r2;

    r1.sv.insert (ofdT_Channel_TargetHandleType, hType);
    r1.sv.insert (ofdT_Channel_ChannelType, ofdT_ChannelType_StreamedMedia);
    r1.as.append (ofdT_Channel_TargetHandle);
    r1.as.append (ofdT_StreamedMedia_InitialAudio);

    r2.sv.insert (ofdT_Channel_TargetHandleType, hType);
    r2.sv.insert (ofdT_Channel_ChannelType, ofdT_ChannelType_Text);
    r2.as.append (ofdT_Channel_TargetHandle);

    Qt_Type_a_dict_sv_as rv;
    rv.append (r1);
    rv.append (r2);

    return rv;
}//QGVConnection::requestableChannelClasses
<commit_msg>maybe the immortal handles had something to do with it<commit_after>/*
qgvdial is a cross platform Google Voice Dialer
Copyright (C) 2009-2012  Yuvraaj Kelkar

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

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 Street, Fifth Floor, Boston, MA  02110-1301  USA

Contact: yuvraaj@gmail.com
*/

#include "QGVConnection.h"
#include "gen/connection_adapter.h"
#include "QGVTextChannel.h"

QGVConnection::QGVConnection(const QString &u, const QString &p,
                             QObject *parent /*= NULL*/)
: QObject(parent)
, m_user(u)
, m_pass(p)
, m_hasImmortalHandle(true)
, m_channelNumber(0)
, m_connStatus(QGVConnection::Disconnected)
{
    Q_DEBUG("Here");
}//QGVConnection::QGVConnection

QGVConnection::~QGVConnection()
{
    Q_DEBUG("Here");
}//QGVConnection::~QGVConnection

bool
QGVConnection::registerObject()
{
    ConnectionAdaptor *ca = new ConnectionAdaptor(this);
    if (NULL == ca) {
        Q_WARN("Failed to create connection adapter object");
        return false;
    }
    RequestsAdaptor *ra = new RequestsAdaptor(this);
    if (NULL == ra) {
        Q_WARN("Failed to create connection adapter object");
        delete ca;
        return false;
    }

    bool connObjReg = false, connSrvReg = false;

    QString noAmpUser = m_user;
    noAmpUser.replace('@', '_');
    noAmpUser.replace('.', '_');

    m_dbusObjectPath = QGV_CONN_OP + noAmpUser;
    m_dbusBusName = QGV_CONN_SP "." + noAmpUser;

    QDBusConnection sessionBus = QDBusConnection::sessionBus();
    bool rv = false;
    do { // Begin cleanup block (not a loop)
        rv = sessionBus.registerObject(m_dbusObjectPath, this);
        if (!rv) {
            Q_WARN(QString("Couldn't register Connection object for user %1")
                    .arg(m_user));
            break;
        }
        connObjReg = true;

        rv = sessionBus.registerService (m_dbusBusName);
        if (!rv) {
            Q_WARN(QString("Couldn't register Connection bus for user %1")
                    .arg(m_user));
            break;
        }
        connSrvReg = true;

        Q_DEBUG(QString("Connection registered for user %1").arg(m_user));
    } while (0); // End cleanup block (not a loop)

    if (!rv) {
        if (connObjReg) {
            sessionBus.unregisterObject(m_dbusObjectPath);
        }
        if (connSrvReg) {
            sessionBus.unregisterService (m_dbusBusName);
        }
        m_dbusObjectPath.clear ();
        m_dbusBusName.clear ();
    }

    return rv;
}//QGVConnection::registerObject

void
QGVConnection::unregisterObject()
{
    QDBusConnection sessionBus = QDBusConnection::sessionBus();
    sessionBus.unregisterObject (m_dbusObjectPath);
    sessionBus.unregisterService (m_dbusBusName);
}//QGVConnection::unregisterObject

void
QGVConnection::AddClientInterest(const QStringList & /*Tokens*/)
{
    Q_DEBUG("Not implemented");
}//QGVConnection::AddClientInterest

void
QGVConnection::Connect()
{
    if (m_connStatus != QGVConnection::Connected) {
        m_connStatus = QGVConnection::Connected;
        emit StatusChanged (m_connStatus, QGVConnection::Requested);
        Q_DEBUG(QString("Connect requested for user %1").arg(m_user));
    } else {
        Q_WARN(QString("Duplicate connect for user %1").arg(m_user));
    }
}//QGVConnection::Connect

void
QGVConnection::Disconnect()
{
    if (m_connStatus != QGVConnection::Disconnected) {
        m_connStatus = QGVConnection::Disconnected;
        emit StatusChanged (m_connStatus, QGVConnection::Requested);
        Q_DEBUG(QString("Disconnect requested for user %1").arg(m_user));
    } else {
        Q_WARN(QString("Duplicate disconnect for user %1").arg(m_user));
    }
}//QGVConnection::Disconnect

QStringList
QGVConnection::GetInterfaces()
{
    QStringList rv;
    rv << ofdT_Conn_Iface_Requests;
    Q_DEBUG(QString("Returning interfaces: [%1]").arg(rv.join (", ")));
    return rv;
}//QGVConnection::GetInterfaces

QString
QGVConnection::GetProtocol()
{
    Q_DEBUG("Requested protocol");
    return QGV_ProtocolName;
}//QGVConnection::GetProtocol

uint
QGVConnection::GetSelfHandle()
{
    if (m_connStatus != QGVConnection::Connected) {
        sendErrorReply (ofdT_Err_Disconnected,
                        "Connection object not connected");
        Q_WARN("Not connected");
    } else {
        Q_DEBUG(QString("Returning self handle %1").arg(m_selfHandle));
    }
    return m_selfHandle;
}//QGVConnection::GetSelfHandle

uint
QGVConnection::GetStatus()
{
    Q_DEBUG(QString("Returning connection status %1").arg(m_connStatus));
    return m_connStatus;
}//QGVConnection::GetStatus

void
QGVConnection::HoldHandles(uint /*Handle_Type*/, const Qt_Type_au & /*Handles*/)
{
    if (m_connStatus != QGVConnection::Connected) {
        sendErrorReply (ofdT_Err_Disconnected,
                        "Connection object not connected");
        Q_WARN("Not connected");
        return;
    }

    // There's nothing really to "hold"
    Q_DEBUG("Not implemented");
}//QGVConnection::HoldHandles

QStringList
QGVConnection::InspectHandles(uint /*Handle_Type*/, const Qt_Type_au & /*Handles*/)
{
    QStringList rv;

    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("Inspect handles. I don't really know what to do here.");
    } while (0);

    return rv;
}//QGVConnection::InspectHandles

Qt_Type_a_osuu
QGVConnection::ListChannels()
{
    Qt_Type_a_osuu rv;

    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("No channels to list.");
    } while (0);

    return rv;
}//QGVConnection::ListChannels

void
QGVConnection::ReleaseHandles(uint /*Handle_Type*/, const Qt_Type_au & /*Handles*/)
{
    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("Release handles. I don't really know what to do here.");
    } while (0);
}//QGVConnection::ReleaseHandles

void
QGVConnection::RemoveClientInterest(const QStringList & /*Tokens*/)
{
    Q_DEBUG("Not implemented");
}//QGVConnection::RemoveClientInterest

QDBusObjectPath
QGVConnection::RequestChannel(const QString & /*Type*/, uint /*Handle_Type*/,
                              uint /*Handle*/, bool /*Suppress_Handler*/)
{
    QDBusObjectPath rv;

    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("Request channel. I don't really know what to do here.");
        sendErrorReply (ofdT_Err_NotImplemented, "Don't know how");
    } while (0);

    return rv;
}//QGVConnection::RequestChannel

Qt_Type_au
QGVConnection::RequestHandles(uint /*Handle_Type*/,
                              const QStringList & /*Identifiers*/)
{
    Qt_Type_au rv;

    do {
        if (m_connStatus != QGVConnection::Connected) {
            Q_WARN("Not connected");
            sendErrorReply (ofdT_Err_Disconnected,
                            "Connection object not connected");
            break;
        }

        Q_DEBUG("Request handles. I don't really know what to do here.");
        sendErrorReply (ofdT_Err_NotImplemented, "Don't know how");
    } while (0);

    return rv;
}//QGVConnection::RequestHandles

void
QGVConnection::setSelfHandle(uint h)
{
    Q_DEBUG("Here");
    m_selfHandle = h;
}//QGVConnection::SetSelfHandle

int
QGVConnection::getSelfHandle()
{
    Q_DEBUG("Here");
    return m_selfHandle;
}//QGVConnection::getSelfHandle

QString
QGVConnection::getDBusObjectPath()
{
    return m_dbusObjectPath;
}//QGVConnection::getDBusObjectPath

QString
QGVConnection::getDBusBusName()
{
    return m_dbusBusName;
}//QGVConnection::getDBusBusName

bool
QGVConnection::hasImmortalHandles() const
{
    Q_DEBUG("Here");
    return m_hasImmortalHandle;
}//QGVConnection::hasImmortalHandles

bool
QGVConnection::processChannel(const QVariantMap &request,
                              QDBusObjectPath &objPath)
{
    QVariant val;

    if (!request.contains (ofdT_Channel_TargetID)) {
        sendErrorReply (ofdT_Err_InvalidArgument,
                        "Target ID not present in request");
        Q_WARN("Target ID not present in request");
        return false;
    }

    val = request[ofdT_Channel_TargetID];
    QString strNum = val.toString ();
    if ((!val.isValid ()) || (strNum.isEmpty ())) {
        sendErrorReply (ofdT_Err_InvalidArgument,
                        "Target ID in request is not valid");
        Q_WARN("Target ID in request is not valid");
        return false;
    }

    if (!request.contains (ofdT_Channel_ChannelType)) {
        sendErrorReply (ofdT_Err_InvalidArgument,
                        "Channel type not present in request");
        Q_WARN("Target ID not present in request");
        return false;
    }

    val = request[ofdT_Channel_ChannelType];
    QString strType = val.toString ();
    if ((!val.isValid ()) || (strType.isEmpty ())) {
        sendErrorReply (ofdT_Err_InvalidArgument,
                        "Channel type in request is not valid");
        Q_WARN("Target ID in request is not valid");
        return false;
    }

    QStringList keys = request.keys ();
    foreach (QString key, keys) {
        Q_DEBUG(QString("[%1] = %2").arg(key, request[key].toString()));
    }

    bool success = false;
    if (strType == ofdT_ChannelType_StreamedMedia) {
        Q_DEBUG(QString("Call to %1").arg(strNum));

        QDBusInterface iface("org.QGVDial.APIServer", "/org/QGVDial/CallServer",
                             "", QDBusConnection::sessionBus());
        if (!iface.isValid()) {
            sendErrorReply(ofdT_Err_NetworkError,
                           "qgvtp - QGVDial call interface is not ready");
            Q_WARN("QGVDial call interface is not ready");
            return false;
        }
        iface.call("Call", strNum);

        Q_DEBUG("Call started successfully");
        sendErrorReply (ofdT_Err_NetworkError, "Channel created successfully");
        success = true;
    } else if (strType == ofdT_ChannelType_Text) {
        Q_DEBUG(QString("Text to %1.").arg(strNum));

        QString objName = m_dbusObjectPath
                           + QString("/%1").arg(++m_channelNumber);
        QGVTextChannel *textChan = new QGVTextChannel(objName, strNum, this);
        bool rv = textChan->registerObject ();
        if (rv) {
            objPath.setPath (objName);

            connect(textChan,
                    SIGNAL(pingNewChannel(QDBusObjectPath,QString,uint,uint,bool)),
                    this,
                    SLOT(onNewChannel(QDBusObjectPath,QString,uint,uint,bool)));

            Q_DEBUG("Text channel created.");
            success = true;
        } else {
            delete textChan;
            Q_WARN("Failed to create text channel");
            success = false;
        }

/*
        QDBusInterface iface("org.QGVDial.APIServer", "/org/QGVDial/TextServer",
                             "", QDBusConnection::sessionBus());
        if (!iface.isValid()) {
            sendErrorReply(ofdT_Err_NotAvailable,
                           "qgvtp - QGVDial text interface is not ready");
            Q_WARN("QGVDial text interface is not ready");
            return false;
        }

        QStringList listNumbers;
        listNumbers += strNum;
        iface.call("TextWithoutData", listNumbers);

        Q_DEBUG("Text initiated successfully");
        sendErrorReply (ofdT_Err_NetworkError, "Channel created successfully");
        success = true;
*/
    } else {
        sendErrorReply (ofdT_Err_UnsupportedMedia,
                        "Channel type in request is not valid");
        Q_WARN(QString("Unsupported channel type %1").arg(strType));
        return false;
    }

    return success;
}//QGVConnection::processChannel

void
QGVConnection::onNewChannel(const QDBusObjectPath &Object_Path,
                            const QString &Channel_Type, uint Handle_Type,
                            uint Handle, bool Suppress_Handler)
{
    Qt_Type_a_o_dict_sv chanInfoList;
    Struct_o_dict_sv chanInfo;

    Q_DEBUG("Time for a new channel");

    chanInfo.o = Object_Path;
    chanInfo.vmap[ofdT_Channel_ChannelType] = Channel_Type;
    chanInfo.vmap[ofdT_Channel_TargetHandleType] = Handle_Type;
    chanInfo.vmap[ofdT_Channel_TargetHandle] = Handle;
    chanInfo.vmap[ofdT_Channel_TargetID] = "";
    chanInfo.vmap[ofdT_Channel_Requested] = Suppress_Handler;

    chanInfoList << chanInfo;
    emit NewChannels (chanInfoList);
    emit NewChannel (Object_Path, Channel_Type, Handle_Type, Handle,
                     Suppress_Handler);
}//QGVConnection::onNewChannel

QDBusObjectPath
QGVConnection::CreateChannel(const QVariantMap &Request,    // IN
                             QVariantMap & /*Properties*/)  // OUT
{
    Q_DEBUG("Here");

    QDBusObjectPath objPath;
    bool success = processChannel (Request, objPath);
    return objPath;
}//QGVConnection::CreateChannel

bool
QGVConnection::EnsureChannel(const QVariantMap &Request,    // IN
                             QDBusObjectPath & Channel, // OUT
                             QVariantMap & /*Properties*/)  // OUT
{
    Q_DEBUG("Here");

    QDBusObjectPath objPath;
    bool success = processChannel (Request, objPath);
    if (success) {
        Channel = objPath;
    }

    return success;
}//QGVConnection::EnsureChannel

Qt_Type_a_o_dict_sv
QGVConnection::channels() const
{
    Qt_Type_a_o_dict_sv rv;
    // Always return an empty channels list
    Q_DEBUG("Returning empty channels list");
    return rv;
}//QGVConnection::channels

Qt_Type_a_dict_sv_as
QGVConnection::requestableChannelClasses() const
{
    Q_DEBUG("Here");

    uint hType(1);  // Handle type : Contact
    Struct_dict_sv_as r1, r2;

    r1.sv.insert (ofdT_Channel_TargetHandleType, hType);
    r1.sv.insert (ofdT_Channel_ChannelType, ofdT_ChannelType_StreamedMedia);
    r1.as.append (ofdT_Channel_TargetHandle);
    r1.as.append (ofdT_StreamedMedia_InitialAudio);

    r2.sv.insert (ofdT_Channel_TargetHandleType, hType);
    r2.sv.insert (ofdT_Channel_ChannelType, ofdT_ChannelType_Text);
    r2.as.append (ofdT_Channel_TargetHandle);

    Qt_Type_a_dict_sv_as rv;
    rv.append (r1);
    rv.append (r2);

    return rv;
}//QGVConnection::requestableChannelClasses
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xmlencryption_nssimpl.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 17:35:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SAL_CONFIG_H_
#include <sal/config.h>
#endif

#ifndef _RTL_UUID_H_
#include <rtl/uuid.h>
#endif

#ifndef _XMLENCRYPTION_NSSIMPL_HXX_
#include "xmlencryption_nssimpl.hxx"
#endif

#ifndef _XMLDOCUMENTWRAPPER_XMLSECIMPL_HXX_
#include "xmldocumentwrapper_xmlsecimpl.hxx"
#endif

#ifndef _XMLELEMENTWRAPPER_XMLSECIMPL_HXX_
#include "xmlelementwrapper_xmlsecimpl.hxx"
#endif

#ifndef _SECURITYENVIRONMENT_NSSIMPL_HXX_
#include "securityenvironment_nssimpl.hxx"
#endif

#ifndef _ERRORCALLBACK_XMLSECIMPL_HXX_
#include "errorcallback.hxx"
#endif

#include "xmlsec/xmlsec.h"
#include "xmlsec/xmltree.h"
#include "xmlsec/xmlenc.h"
#include "xmlsec/crypto.h"

#ifdef UNX
#define stricmp strcasecmp
#endif

using namespace ::com::sun::star::uno ;
using namespace ::com::sun::star::lang ;
using ::com::sun::star::lang::XMultiServiceFactory ;
using ::com::sun::star::lang::XSingleServiceFactory ;
using ::rtl::OUString ;

using ::com::sun::star::xml::wrapper::XXMLElementWrapper ;
using ::com::sun::star::xml::wrapper::XXMLDocumentWrapper ;
using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
using ::com::sun::star::xml::crypto::XXMLEncryption ;
using ::com::sun::star::xml::crypto::XXMLEncryptionTemplate ;
using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
using ::com::sun::star::xml::crypto::XMLEncryptionException ;

XMLEncryption_NssImpl :: XMLEncryption_NssImpl( const Reference< XMultiServiceFactory >& aFactory ) : m_xServiceManager( aFactory ) {
}

XMLEncryption_NssImpl :: ~XMLEncryption_NssImpl() {
}

/* XXMLEncryption */
Reference< XXMLEncryptionTemplate >
SAL_CALL XMLEncryption_NssImpl :: encrypt(
    const Reference< XXMLEncryptionTemplate >& aTemplate ,
    const Reference< XSecurityEnvironment >& aEnvironment
) throw( com::sun::star::xml::crypto::XMLEncryptionException,
         com::sun::star::uno::SecurityException )
{
    xmlSecKeysMngrPtr pMngr = NULL ;
    xmlSecEncCtxPtr pEncCtx = NULL ;
    xmlNodePtr pEncryptedData = NULL ;
    xmlNodePtr pEncryptedKey = NULL ;
    xmlNodePtr pContent = NULL ;

    if( !aTemplate.is() )
        throw RuntimeException() ;

    if( !aEnvironment.is() )
        throw RuntimeException() ;

    //Get Keys Manager
    Reference< XUnoTunnel > xSecTunnel( aEnvironment , UNO_QUERY ) ;
    if( !xSecTunnel.is() ) {
         throw RuntimeException() ;
    }

#if 0
    XMLSecurityContext_NssImpl* pSecCtxt = ( XMLSecurityContext_NssImpl* )xSecTunnel->getSomething( XMLSecurityContext_NssImpl::getUnoTunnelId() ) ;
    if( pSecCtxt == NULL )
        throw RuntimeException() ;
#endif

    SecurityEnvironment_NssImpl* pSecEnv = ( SecurityEnvironment_NssImpl* )xSecTunnel->getSomething( SecurityEnvironment_NssImpl::getUnoTunnelId() ) ;
    if( pSecEnv == NULL )
        throw RuntimeException() ;

    //Get the encryption template
    Reference< XXMLElementWrapper > xTemplate = aTemplate->getTemplate() ;
    if( !xTemplate.is() ) {
        throw RuntimeException() ;
    }

    Reference< XUnoTunnel > xTplTunnel( xTemplate , UNO_QUERY ) ;
    if( !xTplTunnel.is() ) {
        throw RuntimeException() ;
    }

    XMLElementWrapper_XmlSecImpl* pTemplate = ( XMLElementWrapper_XmlSecImpl* )xTplTunnel->getSomething( XMLElementWrapper_XmlSecImpl::getUnoTunnelImplementationId() ) ;
    if( pTemplate == NULL ) {
        throw RuntimeException() ;
    }

    //MM : Get the element to be encrypted
    Reference< XXMLElementWrapper > xTarget = aTemplate->getTarget() ;
    if( !xTarget.is() ) {
        throw XMLEncryptionException() ;
    }

    Reference< XUnoTunnel > xTgtTunnel( xTarget , UNO_QUERY ) ;
    if( !xTgtTunnel.is() ) {
        throw XMLEncryptionException() ;
    }

    XMLElementWrapper_XmlSecImpl* pTarget = ( XMLElementWrapper_XmlSecImpl* )xTgtTunnel->getSomething( XMLElementWrapper_XmlSecImpl::getUnoTunnelImplementationId() ) ;
    if( pTarget == NULL ) {
        throw RuntimeException() ;
    }

    pContent = pTarget->getNativeElement() ;
    //MM : end

    if( pContent == NULL ) {
        throw XMLEncryptionException() ;
    }

    /* MM : remove the following 2 lines
    xmlUnlinkNode(pContent);
    xmlAddNextSibling(pEncryptedData, pContent);
    */

    //remember the position of the element to be signed
    sal_Bool isParentRef = sal_True;
    xmlNodePtr pParent = pEncryptedData->parent;
    xmlNodePtr referenceNode;

    if (pEncryptedData == pParent->children)
    {
        referenceNode = pParent;
    }
    else
    {
        referenceNode = pEncryptedData->prev;
        isParentRef = sal_False;
    }

     setErrorRecorder( aTemplate );

    pMngr = pSecEnv->createKeysManager() ; //i39448
    if( !pMngr ) {
        throw RuntimeException() ;
    }

    //Create Encryption context
    pEncCtx = xmlSecEncCtxCreate( pMngr ) ;
    if( pEncCtx == NULL )
    {
        pSecEnv->destroyKeysManager( pMngr ) ; //i39448
        //throw XMLEncryptionException() ;
        clearErrorRecorder();
        return aTemplate;
    }

    pEncryptedData = pTemplate->getNativeElement() ;

    //Find the element to be encrypted.
    /* MM : remove the old method to get the target element
    //This element is wrapped in the CipherValue sub-element.
    xmlNodePtr pCipherData = pEncryptedData->children;
    while (pCipherData != NULL && stricmp((const char *)(pCipherData->name), "CipherData"))
    {
        pCipherData = pCipherData->next;
    }

    if( pCipherData == NULL ) {
        xmlSecEncCtxDestroy( pEncCtx ) ;
        throw XMLEncryptionException() ;
    }

    xmlNodePtr pCipherValue = pCipherData->children;
    while (pCipherValue != NULL && stricmp((const char *)(pCipherValue->name), "CipherValue"))
    {
        pCipherValue = pCipherValue->next;
    }

    if( pCipherValue == NULL ) {
        xmlSecEncCtxDestroy( pEncCtx ) ;
        throw XMLEncryptionException() ;
    }

    pContent = pCipherValue->children;
    */

    //Encrypt the template
    if( xmlSecEncCtxXmlEncrypt( pEncCtx , pEncryptedData , pContent ) < 0 )
    {
        xmlSecEncCtxDestroy( pEncCtx ) ;
        pSecEnv->destroyKeysManager( pMngr ) ; //i39448

        //throw XMLEncryptionException() ;
        clearErrorRecorder();
        return aTemplate;
    }

    xmlSecEncCtxDestroy( pEncCtx ) ;
    pSecEnv->destroyKeysManager( pMngr ) ; //i39448

    //get the new EncryptedData element
    if (isParentRef)
    {
        pTemplate->setNativeElement(referenceNode->children) ;
    }
    else
    {
        pTemplate->setNativeElement(referenceNode->next);
    }

    return aTemplate ;
}

/* XXMLEncryption */
Reference< XXMLEncryptionTemplate >
SAL_CALL XMLEncryption_NssImpl :: decrypt(
    const Reference< XXMLEncryptionTemplate >& aTemplate ,
    const Reference< XXMLSecurityContext >& aSecurityCtx
) throw( com::sun::star::xml::crypto::XMLEncryptionException ,
         com::sun::star::uno::SecurityException) {
    xmlSecKeysMngrPtr pMngr = NULL ;
    xmlSecEncCtxPtr pEncCtx = NULL ;
    xmlNodePtr pEncryptedData = NULL ;
    xmlNodePtr pContent = NULL ;

    if( !aTemplate.is() )
        throw RuntimeException() ;

    if( !aSecurityCtx.is() )
        throw RuntimeException() ;

    //Get the encryption template
    Reference< XXMLElementWrapper > xTemplate = aTemplate->getTemplate() ;
    if( !xTemplate.is() ) {
        throw RuntimeException() ;
    }

    Reference< XUnoTunnel > xTplTunnel( xTemplate , UNO_QUERY ) ;
    if( !xTplTunnel.is() ) {
        throw RuntimeException() ;
    }

    XMLElementWrapper_XmlSecImpl* pTemplate = ( XMLElementWrapper_XmlSecImpl* )xTplTunnel->getSomething( XMLElementWrapper_XmlSecImpl::getUnoTunnelImplementationId() ) ;
    if( pTemplate == NULL ) {
        throw RuntimeException() ;
    }

    pEncryptedData = pTemplate->getNativeElement() ;

    //remember the position of the element to be signed
    sal_Bool isParentRef = sal_True;
    xmlNodePtr pParent = pEncryptedData->parent;
    xmlNodePtr referenceNode;

    if (pEncryptedData == pParent->children)
    {
        referenceNode = pParent;
    }
    else
    {
        referenceNode = pEncryptedData->prev;
        isParentRef = sal_False;
    }

     setErrorRecorder( aTemplate );

    sal_Int32 nSecurityEnvironment = aSecurityCtx->getSecurityEnvironmentNumber();
    sal_Int32 i;

    for (i=0; i<nSecurityEnvironment; ++i)
    {
        Reference< XSecurityEnvironment > aEnvironment = aSecurityCtx->getSecurityEnvironmentByIndex(i);

        //Get Keys Manager
        Reference< XUnoTunnel > xSecTunnel( aEnvironment , UNO_QUERY ) ;
        if( !aEnvironment.is() ) {
             throw RuntimeException() ;
        }

        SecurityEnvironment_NssImpl* pSecEnv = ( SecurityEnvironment_NssImpl* )xSecTunnel->getSomething( SecurityEnvironment_NssImpl::getUnoTunnelId() ) ;
        if( pSecEnv == NULL )
            throw RuntimeException() ;

        pMngr = pSecEnv->createKeysManager() ; //i39448
        if( !pMngr ) {
            throw RuntimeException() ;
        }

        //Create Encryption context
        pEncCtx = xmlSecEncCtxCreate( pMngr ) ;
        if( pEncCtx == NULL )
        {
            pSecEnv->destroyKeysManager( pMngr ) ; //i39448
            //throw XMLEncryptionException() ;
            clearErrorRecorder();
            return aTemplate;
        }

        //Decrypt the template
        if(!( xmlSecEncCtxDecrypt( pEncCtx , pEncryptedData ) < 0 || pEncCtx->result == NULL ))
        {
            //The decryption succeeds

            //Destroy the encryption context
            xmlSecEncCtxDestroy( pEncCtx ) ;
            pSecEnv->destroyKeysManager( pMngr ) ; //i39448

            //get the decrypted element
            XMLElementWrapper_XmlSecImpl * ret = new XMLElementWrapper_XmlSecImpl(isParentRef?
                (referenceNode->children):(referenceNode->next));

            //return ret;
            aTemplate->setTemplate(ret);
            break;
        }
        else
        {
            //The decryption fails, continue with the next security environment
            xmlSecEncCtxDestroy( pEncCtx ) ;
            pSecEnv->destroyKeysManager( pMngr ) ; //i39448
        }
    }

    clearErrorRecorder();
    return aTemplate;
}

/* XInitialization */
void SAL_CALL XMLEncryption_NssImpl :: initialize( const Sequence< Any >& aArguments ) throw( Exception, RuntimeException ) {
    // TBD
} ;

/* XServiceInfo */
OUString SAL_CALL XMLEncryption_NssImpl :: getImplementationName() throw( RuntimeException ) {
    return impl_getImplementationName() ;
}

/* XServiceInfo */
sal_Bool SAL_CALL XMLEncryption_NssImpl :: supportsService( const OUString& serviceName) throw( RuntimeException ) {
    Sequence< OUString > seqServiceNames = getSupportedServiceNames() ;
    const OUString* pArray = seqServiceNames.getConstArray() ;
    for( sal_Int32 i = 0 ; i < seqServiceNames.getLength() ; i ++ ) {
        if( *( pArray + i ) == serviceName )
            return sal_True ;
    }
    return sal_False ;
}

/* XServiceInfo */
Sequence< OUString > SAL_CALL XMLEncryption_NssImpl :: getSupportedServiceNames() throw( RuntimeException ) {
    return impl_getSupportedServiceNames() ;
}

//Helper for XServiceInfo
Sequence< OUString > XMLEncryption_NssImpl :: impl_getSupportedServiceNames() {
    ::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ) ;
    Sequence< OUString > seqServiceNames( 1 ) ;
    seqServiceNames.getArray()[0] = OUString::createFromAscii( "com.sun.star.xml.crypto.XMLEncryption" ) ;
    return seqServiceNames ;
}

OUString XMLEncryption_NssImpl :: impl_getImplementationName() throw( RuntimeException ) {
    return OUString::createFromAscii( "com.sun.star.xml.security.bridge.xmlsec.XMLEncryption_NssImpl" ) ;
}

//Helper for registry
Reference< XInterface > SAL_CALL XMLEncryption_NssImpl :: impl_createInstance( const Reference< XMultiServiceFactory >& aServiceManager ) throw( RuntimeException ) {
    return Reference< XInterface >( *new XMLEncryption_NssImpl( aServiceManager ) ) ;
}

Reference< XSingleServiceFactory > XMLEncryption_NssImpl :: impl_createFactory( const Reference< XMultiServiceFactory >& aServiceManager ) {
    //Reference< XSingleServiceFactory > xFactory ;
    //xFactory = ::cppu::createSingleFactory( aServiceManager , impl_getImplementationName , impl_createInstance , impl_getSupportedServiceNames ) ;
    //return xFactory ;
    return ::cppu::createSingleFactory( aServiceManager , impl_getImplementationName() , impl_createInstance , impl_getSupportedServiceNames() ) ;
}

<commit_msg>INTEGRATION: CWS xmlsec13 (1.4.28); FILE MERGED 2005/10/31 13:43:22 jl 1.4.28.2: RESYNC: (1.4-1.5); FILE MERGED 2005/10/25 10:59:33 jl 1.4.28.1: #i54495 errorhandling for verification and signing fixed<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xmlencryption_nssimpl.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-11-11 09:21:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SAL_CONFIG_H_
#include <sal/config.h>
#endif

#ifndef _RTL_UUID_H_
#include <rtl/uuid.h>
#endif

#ifndef _XMLENCRYPTION_NSSIMPL_HXX_
#include "xmlencryption_nssimpl.hxx"
#endif

#ifndef _XMLDOCUMENTWRAPPER_XMLSECIMPL_HXX_
#include "xmldocumentwrapper_xmlsecimpl.hxx"
#endif

#ifndef _XMLELEMENTWRAPPER_XMLSECIMPL_HXX_
#include "xmlelementwrapper_xmlsecimpl.hxx"
#endif

#ifndef _SECURITYENVIRONMENT_NSSIMPL_HXX_
#include "securityenvironment_nssimpl.hxx"
#endif

#ifndef _ERRORCALLBACK_XMLSECIMPL_HXX_
#include "errorcallback.hxx"
#endif

#include "xmlsec/xmlsec.h"
#include "xmlsec/xmltree.h"
#include "xmlsec/xmlenc.h"
#include "xmlsec/crypto.h"

#ifdef UNX
#define stricmp strcasecmp
#endif

using namespace ::com::sun::star::uno ;
using namespace ::com::sun::star::lang ;
using ::com::sun::star::lang::XMultiServiceFactory ;
using ::com::sun::star::lang::XSingleServiceFactory ;
using ::rtl::OUString ;

using ::com::sun::star::xml::wrapper::XXMLElementWrapper ;
using ::com::sun::star::xml::wrapper::XXMLDocumentWrapper ;
using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
using ::com::sun::star::xml::crypto::XXMLEncryption ;
using ::com::sun::star::xml::crypto::XXMLEncryptionTemplate ;
using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
using ::com::sun::star::xml::crypto::XMLEncryptionException ;

XMLEncryption_NssImpl :: XMLEncryption_NssImpl( const Reference< XMultiServiceFactory >& aFactory ) : m_xServiceManager( aFactory ) {
}

XMLEncryption_NssImpl :: ~XMLEncryption_NssImpl() {
}

/* XXMLEncryption */
Reference< XXMLEncryptionTemplate >
SAL_CALL XMLEncryption_NssImpl :: encrypt(
    const Reference< XXMLEncryptionTemplate >& aTemplate ,
    const Reference< XSecurityEnvironment >& aEnvironment
) throw( com::sun::star::xml::crypto::XMLEncryptionException,
         com::sun::star::uno::SecurityException )
{
    xmlSecKeysMngrPtr pMngr = NULL ;
    xmlSecEncCtxPtr pEncCtx = NULL ;
    xmlNodePtr pEncryptedData = NULL ;
    xmlNodePtr pEncryptedKey = NULL ;
    xmlNodePtr pContent = NULL ;

    if( !aTemplate.is() )
        throw RuntimeException() ;

    if( !aEnvironment.is() )
        throw RuntimeException() ;

    //Get Keys Manager
    Reference< XUnoTunnel > xSecTunnel( aEnvironment , UNO_QUERY ) ;
    if( !xSecTunnel.is() ) {
         throw RuntimeException() ;
    }

#if 0
    XMLSecurityContext_NssImpl* pSecCtxt = ( XMLSecurityContext_NssImpl* )xSecTunnel->getSomething( XMLSecurityContext_NssImpl::getUnoTunnelId() ) ;
    if( pSecCtxt == NULL )
        throw RuntimeException() ;
#endif

    SecurityEnvironment_NssImpl* pSecEnv = ( SecurityEnvironment_NssImpl* )xSecTunnel->getSomething( SecurityEnvironment_NssImpl::getUnoTunnelId() ) ;
    if( pSecEnv == NULL )
        throw RuntimeException() ;

    //Get the encryption template
    Reference< XXMLElementWrapper > xTemplate = aTemplate->getTemplate() ;
    if( !xTemplate.is() ) {
        throw RuntimeException() ;
    }

    Reference< XUnoTunnel > xTplTunnel( xTemplate , UNO_QUERY ) ;
    if( !xTplTunnel.is() ) {
        throw RuntimeException() ;
    }

    XMLElementWrapper_XmlSecImpl* pTemplate = ( XMLElementWrapper_XmlSecImpl* )xTplTunnel->getSomething( XMLElementWrapper_XmlSecImpl::getUnoTunnelImplementationId() ) ;
    if( pTemplate == NULL ) {
        throw RuntimeException() ;
    }

    //MM : Get the element to be encrypted
    Reference< XXMLElementWrapper > xTarget = aTemplate->getTarget() ;
    if( !xTarget.is() ) {
        throw XMLEncryptionException() ;
    }

    Reference< XUnoTunnel > xTgtTunnel( xTarget , UNO_QUERY ) ;
    if( !xTgtTunnel.is() ) {
        throw XMLEncryptionException() ;
    }

    XMLElementWrapper_XmlSecImpl* pTarget = ( XMLElementWrapper_XmlSecImpl* )xTgtTunnel->getSomething( XMLElementWrapper_XmlSecImpl::getUnoTunnelImplementationId() ) ;
    if( pTarget == NULL ) {
        throw RuntimeException() ;
    }

    pContent = pTarget->getNativeElement() ;
    //MM : end

    if( pContent == NULL ) {
        throw XMLEncryptionException() ;
    }

    /* MM : remove the following 2 lines
    xmlUnlinkNode(pContent);
    xmlAddNextSibling(pEncryptedData, pContent);
    */

    //remember the position of the element to be signed
    sal_Bool isParentRef = sal_True;
    xmlNodePtr pParent = pEncryptedData->parent;
    xmlNodePtr referenceNode;

    if (pEncryptedData == pParent->children)
    {
        referenceNode = pParent;
    }
    else
    {
        referenceNode = pEncryptedData->prev;
        isParentRef = sal_False;
    }

     setErrorRecorder( );

    pMngr = pSecEnv->createKeysManager() ; //i39448
    if( !pMngr ) {
        throw RuntimeException() ;
    }

    //Create Encryption context
    pEncCtx = xmlSecEncCtxCreate( pMngr ) ;
    if( pEncCtx == NULL )
    {
        pSecEnv->destroyKeysManager( pMngr ) ; //i39448
        //throw XMLEncryptionException() ;
        clearErrorRecorder();
        return aTemplate;
    }

    pEncryptedData = pTemplate->getNativeElement() ;

    //Find the element to be encrypted.
    /* MM : remove the old method to get the target element
    //This element is wrapped in the CipherValue sub-element.
    xmlNodePtr pCipherData = pEncryptedData->children;
    while (pCipherData != NULL && stricmp((const char *)(pCipherData->name), "CipherData"))
    {
        pCipherData = pCipherData->next;
    }

    if( pCipherData == NULL ) {
        xmlSecEncCtxDestroy( pEncCtx ) ;
        throw XMLEncryptionException() ;
    }

    xmlNodePtr pCipherValue = pCipherData->children;
    while (pCipherValue != NULL && stricmp((const char *)(pCipherValue->name), "CipherValue"))
    {
        pCipherValue = pCipherValue->next;
    }

    if( pCipherValue == NULL ) {
        xmlSecEncCtxDestroy( pEncCtx ) ;
        throw XMLEncryptionException() ;
    }

    pContent = pCipherValue->children;
    */

    //Encrypt the template
    if( xmlSecEncCtxXmlEncrypt( pEncCtx , pEncryptedData , pContent ) < 0 )
    {
        xmlSecEncCtxDestroy( pEncCtx ) ;
        pSecEnv->destroyKeysManager( pMngr ) ; //i39448

        //throw XMLEncryptionException() ;
        clearErrorRecorder();
        return aTemplate;
    }

    xmlSecEncCtxDestroy( pEncCtx ) ;
    pSecEnv->destroyKeysManager( pMngr ) ; //i39448

    //get the new EncryptedData element
    if (isParentRef)
    {
        pTemplate->setNativeElement(referenceNode->children) ;
    }
    else
    {
        pTemplate->setNativeElement(referenceNode->next);
    }

    return aTemplate ;
}

/* XXMLEncryption */
Reference< XXMLEncryptionTemplate >
SAL_CALL XMLEncryption_NssImpl :: decrypt(
    const Reference< XXMLEncryptionTemplate >& aTemplate ,
    const Reference< XXMLSecurityContext >& aSecurityCtx
) throw( com::sun::star::xml::crypto::XMLEncryptionException ,
         com::sun::star::uno::SecurityException) {
    xmlSecKeysMngrPtr pMngr = NULL ;
    xmlSecEncCtxPtr pEncCtx = NULL ;
    xmlNodePtr pEncryptedData = NULL ;
    xmlNodePtr pContent = NULL ;

    if( !aTemplate.is() )
        throw RuntimeException() ;

    if( !aSecurityCtx.is() )
        throw RuntimeException() ;

    //Get the encryption template
    Reference< XXMLElementWrapper > xTemplate = aTemplate->getTemplate() ;
    if( !xTemplate.is() ) {
        throw RuntimeException() ;
    }

    Reference< XUnoTunnel > xTplTunnel( xTemplate , UNO_QUERY ) ;
    if( !xTplTunnel.is() ) {
        throw RuntimeException() ;
    }

    XMLElementWrapper_XmlSecImpl* pTemplate = ( XMLElementWrapper_XmlSecImpl* )xTplTunnel->getSomething( XMLElementWrapper_XmlSecImpl::getUnoTunnelImplementationId() ) ;
    if( pTemplate == NULL ) {
        throw RuntimeException() ;
    }

    pEncryptedData = pTemplate->getNativeElement() ;

    //remember the position of the element to be signed
    sal_Bool isParentRef = sal_True;
    xmlNodePtr pParent = pEncryptedData->parent;
    xmlNodePtr referenceNode;

    if (pEncryptedData == pParent->children)
    {
        referenceNode = pParent;
    }
    else
    {
        referenceNode = pEncryptedData->prev;
        isParentRef = sal_False;
    }

     setErrorRecorder( );

    sal_Int32 nSecurityEnvironment = aSecurityCtx->getSecurityEnvironmentNumber();
    sal_Int32 i;

    for (i=0; i<nSecurityEnvironment; ++i)
    {
        Reference< XSecurityEnvironment > aEnvironment = aSecurityCtx->getSecurityEnvironmentByIndex(i);

        //Get Keys Manager
        Reference< XUnoTunnel > xSecTunnel( aEnvironment , UNO_QUERY ) ;
        if( !aEnvironment.is() ) {
             throw RuntimeException() ;
        }

        SecurityEnvironment_NssImpl* pSecEnv = ( SecurityEnvironment_NssImpl* )xSecTunnel->getSomething( SecurityEnvironment_NssImpl::getUnoTunnelId() ) ;
        if( pSecEnv == NULL )
            throw RuntimeException() ;

        pMngr = pSecEnv->createKeysManager() ; //i39448
        if( !pMngr ) {
            throw RuntimeException() ;
        }

        //Create Encryption context
        pEncCtx = xmlSecEncCtxCreate( pMngr ) ;
        if( pEncCtx == NULL )
        {
            pSecEnv->destroyKeysManager( pMngr ) ; //i39448
            //throw XMLEncryptionException() ;
            clearErrorRecorder();
            return aTemplate;
        }

        //Decrypt the template
        if(!( xmlSecEncCtxDecrypt( pEncCtx , pEncryptedData ) < 0 || pEncCtx->result == NULL ))
        {
            //The decryption succeeds

            //Destroy the encryption context
            xmlSecEncCtxDestroy( pEncCtx ) ;
            pSecEnv->destroyKeysManager( pMngr ) ; //i39448

            //get the decrypted element
            XMLElementWrapper_XmlSecImpl * ret = new XMLElementWrapper_XmlSecImpl(isParentRef?
                (referenceNode->children):(referenceNode->next));

            //return ret;
            aTemplate->setTemplate(ret);
            break;
        }
        else
        {
            //The decryption fails, continue with the next security environment
            xmlSecEncCtxDestroy( pEncCtx ) ;
            pSecEnv->destroyKeysManager( pMngr ) ; //i39448
        }
    }

    clearErrorRecorder();
    return aTemplate;
}

/* XInitialization */
void SAL_CALL XMLEncryption_NssImpl :: initialize( const Sequence< Any >& aArguments ) throw( Exception, RuntimeException ) {
    // TBD
} ;

/* XServiceInfo */
OUString SAL_CALL XMLEncryption_NssImpl :: getImplementationName() throw( RuntimeException ) {
    return impl_getImplementationName() ;
}

/* XServiceInfo */
sal_Bool SAL_CALL XMLEncryption_NssImpl :: supportsService( const OUString& serviceName) throw( RuntimeException ) {
    Sequence< OUString > seqServiceNames = getSupportedServiceNames() ;
    const OUString* pArray = seqServiceNames.getConstArray() ;
    for( sal_Int32 i = 0 ; i < seqServiceNames.getLength() ; i ++ ) {
        if( *( pArray + i ) == serviceName )
            return sal_True ;
    }
    return sal_False ;
}

/* XServiceInfo */
Sequence< OUString > SAL_CALL XMLEncryption_NssImpl :: getSupportedServiceNames() throw( RuntimeException ) {
    return impl_getSupportedServiceNames() ;
}

//Helper for XServiceInfo
Sequence< OUString > XMLEncryption_NssImpl :: impl_getSupportedServiceNames() {
    ::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ) ;
    Sequence< OUString > seqServiceNames( 1 ) ;
    seqServiceNames.getArray()[0] = OUString::createFromAscii( "com.sun.star.xml.crypto.XMLEncryption" ) ;
    return seqServiceNames ;
}

OUString XMLEncryption_NssImpl :: impl_getImplementationName() throw( RuntimeException ) {
    return OUString::createFromAscii( "com.sun.star.xml.security.bridge.xmlsec.XMLEncryption_NssImpl" ) ;
}

//Helper for registry
Reference< XInterface > SAL_CALL XMLEncryption_NssImpl :: impl_createInstance( const Reference< XMultiServiceFactory >& aServiceManager ) throw( RuntimeException ) {
    return Reference< XInterface >( *new XMLEncryption_NssImpl( aServiceManager ) ) ;
}

Reference< XSingleServiceFactory > XMLEncryption_NssImpl :: impl_createFactory( const Reference< XMultiServiceFactory >& aServiceManager ) {
    //Reference< XSingleServiceFactory > xFactory ;
    //xFactory = ::cppu::createSingleFactory( aServiceManager , impl_getImplementationName , impl_createInstance , impl_getSupportedServiceNames ) ;
    //return xFactory ;
    return ::cppu::createSingleFactory( aServiceManager , impl_getImplementationName() , impl_createInstance , impl_getSupportedServiceNames() ) ;
}

<|endoftext|>


<commit_before>#include <QGuiApplication>
#include <QtGui>
#include <QtQuick>
#include <QQmlApplicationEngine>

#include "VideoSurface.h"
#include "Comms.h"
#include "OS.h"
#include "Menus.h"

#include <android/log.h>
#include <thread>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    Q_INIT_RESOURCE(res);

    app.setQuitOnLastWindowClosed(true);

    QPalette palette = app.palette();
    palette.setColor(QPalette::Window, QColor(53,53,53));
    palette.setColor(QPalette::WindowText, QColor(0xECF0F1));
    palette.setColor(QPalette::Base, QColor(25,25,25));
    palette.setColor(QPalette::AlternateBase, QColor(53,53,53));
    palette.setColor(QPalette::ToolTipBase, QColor(0xECF0F1));
    palette.setColor(QPalette::ToolTipText, QColor(0xECF0F1));
    palette.setColor(QPalette::Text, QColor(0xECF0F1));
    palette.setColor(QPalette::Button, QColor(53,53,53));
    palette.setColor(QPalette::ButtonText, QColor(0xECF0F1));
    palette.setColor(QPalette::BrightText, Qt::white);
    palette.setColor(QPalette::Link, QColor(42, 130, 218));

    palette.setColor(QPalette::Highlight, QColor(42, 130, 218));
    palette.setColor(QPalette::HighlightedText, Qt::black);

    app.setPalette(palette);

    QQuickView view;

    OS os;

    Menus menus;
    menus.init(view);

    Comms comms;
    comms.init("192.168.42.1", 3333);

    qmlRegisterType<Comms>("com.silk.Comms", 1, 0, "Comms");
    view.engine()->rootContext()->setContextProperty("s_comms", &comms);
    view.engine()->rootContext()->setContextProperty("s_os", &os);
    view.engine()->rootContext()->setContextProperty("s_menus", &menus);
    qmlRegisterType<VideoSurface>("com.silk.VideoSurface", 0, 1, "VideoSurface");

    QSurfaceFormat format = view.format();
    format.setAlphaBufferSize(0);
    format.setRedBufferSize(8);
    format.setGreenBufferSize(8);
    format.setBlueBufferSize(8);
    format.setSamples(1);
    format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
    format.setSwapInterval(0);
    view.setFormat(format);

    view.setResizeMode(QQuickView::SizeRootObjectToView);
    //view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
    view.show();

    //menus.push("Splash.qml");
    menus.push("MM.qml");

    while (true)
    {
        app.processEvents();

//        {
//            static FILE* fff = nullptr;
//            if (!fff)
//            {
//                srand(time(nullptr));
//                fff = fopen("/storage/emulated/0/Download/sample.h264", "rb");
//                if (!fff)
//                {
//                    exit(1);
//                }
//            }

//            uint8_t data[32768];
//            size_t size = 100;
//            int r = fread(data, 1, size, fff);
//            if (r == 0)
//            {
//                __android_log_print(ANDROID_LOG_INFO, "Skptr", "DONE, REWIND!!!!!");
//                fseek(fff, 0, SEEK_SET);
//            }
//            if (r > 0)
//            {
//                VideoSurface::decodeVideo(data, r);
//            }
//        }

        comms.process();
        std::pair<void const*, size_t> videoData = comms.getVideoData();
        if (videoData.second > 0)
        {
            VideoSurface::addVideoData(videoData.first, videoData.second);
        }

        std::this_thread::sleep_for(std::chrono::microseconds(1));
    }

    return app.exec();
}
<commit_msg>Kill the app when put to background<commit_after>#include <QGuiApplication>
#include <QtGui>
#include <QtQuick>
#include <QQmlApplicationEngine>

#include "VideoSurface.h"
#include "Comms.h"
#include "OS.h"
#include "Menus.h"

#include <android/log.h>
#include <thread>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    Q_INIT_RESOURCE(res);

    app.setQuitOnLastWindowClosed(true);

    QPalette palette = app.palette();
    palette.setColor(QPalette::Window, QColor(53,53,53));
    palette.setColor(QPalette::WindowText, QColor(0xECF0F1));
    palette.setColor(QPalette::Base, QColor(25,25,25));
    palette.setColor(QPalette::AlternateBase, QColor(53,53,53));
    palette.setColor(QPalette::ToolTipBase, QColor(0xECF0F1));
    palette.setColor(QPalette::ToolTipText, QColor(0xECF0F1));
    palette.setColor(QPalette::Text, QColor(0xECF0F1));
    palette.setColor(QPalette::Button, QColor(53,53,53));
    palette.setColor(QPalette::ButtonText, QColor(0xECF0F1));
    palette.setColor(QPalette::BrightText, Qt::white);
    palette.setColor(QPalette::Link, QColor(42, 130, 218));

    palette.setColor(QPalette::Highlight, QColor(42, 130, 218));
    palette.setColor(QPalette::HighlightedText, Qt::black);

    app.setPalette(palette);

    QQuickView view;

    OS os;

    Menus menus;
    menus.init(view);

    Comms comms;
    comms.init("192.168.42.1", 3333);

    qmlRegisterType<Comms>("com.silk.Comms", 1, 0, "Comms");
    view.engine()->rootContext()->setContextProperty("s_comms", &comms);
    view.engine()->rootContext()->setContextProperty("s_os", &os);
    view.engine()->rootContext()->setContextProperty("s_menus", &menus);
    qmlRegisterType<VideoSurface>("com.silk.VideoSurface", 0, 1, "VideoSurface");

    QSurfaceFormat format = view.format();
    format.setAlphaBufferSize(0);
    format.setRedBufferSize(8);
    format.setGreenBufferSize(8);
    format.setBlueBufferSize(8);
    format.setSamples(1);
    format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
    format.setSwapInterval(0);
    view.setFormat(format);

    //https://github.com/jeanleflambeur/silkopter/issues/40
    //to prevent the app reverting to 60 FPS after focus lost
    QObject::connect(&app, &QGuiApplication::applicationStateChanged, [](Qt::ApplicationState state)
    {
        if (state == Qt::ApplicationInactive)
        {
            __android_log_print(ANDROID_LOG_INFO, "Skptr", "Viewer is inactive");
            exit(0); //abort, because QT will default to 60 FPS when coming back and I found no way to fix this
        }
    });

    view.setResizeMode(QQuickView::SizeRootObjectToView);
    //view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
    view.show();

    //menus.push("Splash.qml");
    menus.push("MM.qml");

    while (true)
    {
        app.processEvents();

//        {
//            static FILE* fff = nullptr;
//            if (!fff)
//            {
//                srand(time(nullptr));
//                fff = fopen("/storage/emulated/0/Download/sample.h264", "rb");
//                if (!fff)
//                {
//                    exit(1);
//                }
//            }

//            uint8_t data[32768];
//            size_t size = 100;
//            int r = fread(data, 1, size, fff);
//            if (r == 0)
//            {
//                __android_log_print(ANDROID_LOG_INFO, "Skptr", "DONE, REWIND!!!!!");
//                fseek(fff, 0, SEEK_SET);
//            }
//            if (r > 0)
//            {
//                VideoSurface::decodeVideo(data, r);
//            }
//        }

        comms.process();
        std::pair<void const*, size_t> videoData = comms.getVideoData();
        if (videoData.second > 0)
        {
            VideoSurface::addVideoData(videoData.first, videoData.second);
        }

        std::this_thread::sleep_for(std::chrono::microseconds(1));
    }

    return app.exec();
}
<|endoftext|>