<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: skeletoncpp.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2006-03-15 09:20:25 $
 *
 *  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 INCLUDED_UNODEVTOOLS_SOURCE_SKELETONMAKER_SKELETONCPP_HXX
#define INCLUDED_UNODEVTOOLS_SOURCE_SKELETONMAKER_SKELETONCPP_HXX

#include <fstream>

#ifndef INCLUDED_CODEMAKER_GENERATEDTYPESET_HXX
#include "codemaker/generatedtypeset.hxx"
#endif
#ifndef INCLUDED_UNODEVTOOLS_SOURCE_SKELETONMAKER_SKELETONCOMMON_HXX
#include "skeletoncommon.hxx"
#endif

namespace skeletonmaker { namespace cpp {

// referenceType
// 0 = no reference
// 1 = use of css::uno::Reference for interfaces
// 2 = reference (includes css::uno::Reference for interfaces)
// 4 = const reference  (includes css::uno::Reference for interfaces)
// 8 = default construction for example for return types, means "return <type>();"
// 16 = default member initialization in a constructor
void printType(std::ostream & o,
               ProgramOptions const & options, TypeManager const & manager,
               codemaker::UnoType::Sort sort, RTTypeClass typeClass,
               rtl::OString const & name, sal_Int32 rank,
               std::vector< rtl::OString > const & arguments,
               short referenceType, bool defaultvalue=false);

void printType(std::ostream & o,
               ProgramOptions const & options, TypeManager const & manager,
               rtl::OString const & type, short referenceType,
               bool defaultvalue=false);

bool printConstructorParameters(std::ostream & o,
                                ProgramOptions const & options,
                                TypeManager const & manager,
                                typereg::Reader const & reader,
                                typereg::Reader const & outerReader,
                                std::vector< rtl::OString > const & arguments);

void printConstructor(std::ostream & o,
                      ProgramOptions const & options,
                      TypeManager const & manager,
                      typereg::Reader const & reader,
                      std::vector< rtl::OString > const & arguments);

void printMethodParameters(std::ostream & o,
                           ProgramOptions const & options,
                           TypeManager const & manager,
                           typereg::Reader const & reader,
                           sal_uInt16 method, bool previous,
                           bool withtype);

void printExceptionSpecification(std::ostream & o,
                                 ProgramOptions const & options,
                                 TypeManager const & manager,
                                 typereg::Reader const & reader,
                                 sal_uInt16 method);

void printMethods(std::ostream & o,
                  ProgramOptions const & options, TypeManager const & manager,
                  typereg::Reader const & reader,
                  codemaker::GeneratedTypeSet & generated,
                  rtl::OString const & delegate,
                  rtl::OString const & classname=rtl::OString(),
                  rtl::OString const & indentation=rtl::OString(),
                  bool defaultvalue=false,
                  rtl::OString const & propertyhelper=rtl::OString());

void printConstructionMethods(std::ostream & o,
                              ProgramOptions const & options,
                              TypeManager const & manager,
                              typereg::Reader const & reader);

void printServiceMembers(std::ostream & o,
                         ProgramOptions const & options,
                         TypeManager const & manager,
                         typereg::Reader const & reader,
                         rtl::OString const & type,
                         rtl::OString const & delegate);

void printMapsToCppType(std::ostream & o,
                        ProgramOptions const & options,
                        TypeManager const & manager,
                        codemaker::UnoType::Sort sort,
                        RTTypeClass typeClass,
                        rtl::OString const & name,
                        sal_Int32 rank,
                        std::vector< rtl::OString > const & arguments,
                        const char * cppTypeSort);

void generateDocumentation(std::ostream & o,
                           ProgramOptions const & options,
                           TypeManager const & manager,
                           rtl::OString const & type,
                           rtl::OString const & delegate);

void generateSkeleton(ProgramOptions const & options,
                      TypeManager const & manager,
                      std::vector< rtl::OString > const & types,
                      rtl::OString const & delegate);

void generateCalcAddin(ProgramOptions const & options,
                       TypeManager const & manager,
                       std::vector< rtl::OString > const & types,
                       rtl::OString const & delegate);

} }

#endif // INCLUDED_UNODEVTOOLS_SOURCE_SKELETONMAKER_SKELETONCPP_HXX

<commit_msg>INTEGRATION: CWS warnings01 (1.3.2); FILE MERGED 2006/04/20 14:25:56 sb 1.3.2.1: #i53898# Made code warning-free again after resync to SRC680m162.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: skeletoncpp.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 00:50:58 $
 *
 *  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 INCLUDED_UNODEVTOOLS_SOURCE_SKELETONMAKER_SKELETONCPP_HXX
#define INCLUDED_UNODEVTOOLS_SOURCE_SKELETONMAKER_SKELETONCPP_HXX

#include <fstream>

#ifndef INCLUDED_CODEMAKER_GENERATEDTYPESET_HXX
#include "codemaker/generatedtypeset.hxx"
#endif
#ifndef INCLUDED_UNODEVTOOLS_SOURCE_SKELETONMAKER_SKELETONCOMMON_HXX
#include "skeletoncommon.hxx"
#endif

namespace skeletonmaker { namespace cpp {

// referenceType
// 0 = no reference
// 1 = use of css::uno::Reference for interfaces
// 2 = reference (includes css::uno::Reference for interfaces)
// 4 = const reference  (includes css::uno::Reference for interfaces)
// 8 = default construction for example for return types, means "return <type>();"
// 16 = default member initialization in a constructor
void printType(std::ostream & o,
               ProgramOptions const & options, TypeManager const & manager,
               codemaker::UnoType::Sort sort, RTTypeClass typeClass,
               rtl::OString const & name, sal_Int32 rank,
               std::vector< rtl::OString > const & arguments,
               short referenceType, bool defaultvalue=false);

void printType(std::ostream & o,
               ProgramOptions const & options, TypeManager const & manager,
               rtl::OString const & type, short referenceType,
               bool defaultvalue=false);

bool printConstructorParameters(std::ostream & o,
                                ProgramOptions const & options,
                                TypeManager const & manager,
                                typereg::Reader const & reader,
                                typereg::Reader const & outerReader,
                                std::vector< rtl::OString > const & arguments);

void printConstructor(std::ostream & o,
                      ProgramOptions const & options,
                      TypeManager const & manager,
                      typereg::Reader const & reader,
                      std::vector< rtl::OString > const & arguments);

void printMethodParameters(std::ostream & o,
                           ProgramOptions const & options,
                           TypeManager const & manager,
                           typereg::Reader const & reader,
                           sal_uInt16 method, bool previous,
                           bool withtype);

void printExceptionSpecification(std::ostream & o,
                                 ProgramOptions const & options,
                                 TypeManager const & manager,
                                 typereg::Reader const & reader,
                                 sal_uInt16 method);

void printMethods(std::ostream & o,
                  ProgramOptions const & options, TypeManager const & manager,
                  typereg::Reader const & reader,
                  codemaker::GeneratedTypeSet & generated,
                  rtl::OString const & delegate,
                  rtl::OString const & classname=rtl::OString(),
                  rtl::OString const & indentation=rtl::OString(),
                  bool defaultvalue=false,
                  rtl::OString const & propertyhelper=rtl::OString());

void printConstructionMethods(std::ostream & o,
                              ProgramOptions const & options,
                              TypeManager const & manager,
                              typereg::Reader const & reader);

void printServiceMembers(std::ostream & o,
                         ProgramOptions const & options,
                         TypeManager const & manager,
                         typereg::Reader const & reader,
                         rtl::OString const & type,
                         rtl::OString const & delegate);

void printMapsToCppType(std::ostream & o,
                        ProgramOptions const & options,
                        TypeManager const & manager,
                        codemaker::UnoType::Sort sort,
                        RTTypeClass typeClass,
                        rtl::OString const & name,
                        sal_Int32 rank,
                        std::vector< rtl::OString > const & arguments,
                        const char * cppTypeSort);

void generateDocumentation(std::ostream & o,
                           ProgramOptions const & options,
                           TypeManager const & manager,
                           rtl::OString const & type,
                           rtl::OString const & delegate);

void generateSkeleton(ProgramOptions const & options,
                      TypeManager const & manager,
                      std::vector< rtl::OString > const & types,
                      rtl::OString const & delegate);

void generateCalcAddin(ProgramOptions const & options,
                       TypeManager const & manager,
                       std::vector< rtl::OString > const & types);

} }

#endif // INCLUDED_UNODEVTOOLS_SOURCE_SKELETONMAKER_SKELETONCPP_HXX

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author 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 <boost/version.hpp>

#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif

#include <boost/bind.hpp>

#include "libtorrent/socket.hpp"
#include "libtorrent/enum_net.hpp"
#include "libtorrent/broadcast_socket.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	bool is_local(address const& a)
	{
		if (a.is_v6()) return a.to_v6().is_link_local();
		address_v4 a4 = a.to_v4();
		unsigned long ip = a4.to_ulong();
		return ((ip & 0xff000000) == 0x0a000000
			|| (ip & 0xfff00000) == 0xac100000
			|| (ip & 0xffff0000) == 0xc0a80000);
	}

	bool is_loopback(address const& addr)
	{
		if (addr.is_v4())
		  return addr.to_v4() == address_v4::loopback();
		else
			return addr.to_v6() == address_v6::loopback();
	}

	bool is_multicast(address const& addr)
	{
		if (addr.is_v4())
			return addr.to_v4().is_multicast();
		else
			return addr.to_v6().is_multicast();
	}

	bool is_any(address const& addr)
	{
		if (addr.is_v4())
			return addr.to_v4() == address_v4::any();
		else if (addr.to_v6().is_v4_mapped())
			return (addr.to_v6().to_v4() == address_v4::any());
		else
			return addr.to_v6() == address_v6::any();
	}

	address guess_local_address(io_service& ios)
	{
		// make a best guess of the interface we're using and its IP
		error_code ec;
		std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec);
		address ret = address_v4::any();
		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			address const& a = i->interface_address;
			if (is_loopback(a)
				|| is_multicast(a)
				|| is_any(a)) continue;

			// prefer a v4 address, but return a v6 if
			// there are no v4
			if (a.is_v4()) return a;

			if (ret != address_v4::any())
				ret = a;
		}
		return ret;
	}

	// count the length of the common bit prefix
	int common_bits(unsigned char const* b1
		, unsigned char const* b2, int n)
	{
		for (int i = 0; i < n; ++i, ++b1, ++b2)
		{
			unsigned char a = *b1 ^ *b2;
			if (a == 0) continue;
			int ret = i * 8 + 8;
			for (; a > 0; a >>= 1) --ret;
			return ret;
		}
		return n * 8;
	}

	// returns the number of bits in that differ from the right
	// between the addresses.
	int cidr_distance(address const& a1, address const& a2)
	{
		if (a1.is_v4() == a2.is_v4())
		{
			// both are v4
			address_v4::bytes_type b1 = a1.to_v4().to_bytes();
			address_v4::bytes_type b2 = a2.to_v4().to_bytes();
			return address_v4::bytes_type::static_size * 8
				- common_bits(b1.c_array(), b2.c_array(), b1.size());
		}

		address_v6::bytes_type b1;
		address_v6::bytes_type b2;
		if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
		else b1 = a1.to_v6().to_bytes();
		if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
		else b2 = a2.to_v6().to_bytes();
		return address_v6::bytes_type::static_size * 8
			- common_bits(b1.c_array(), b2.c_array(), b1.size());
	}

	broadcast_socket::broadcast_socket(io_service& ios
		, udp::endpoint const& multicast_endpoint
		, receive_handler_t const& handler
		, bool loopback)
		: m_multicast_endpoint(multicast_endpoint)
		, m_on_receive(handler)
	{
		TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address()));

		using namespace asio::ip::multicast;

		error_code ec;
		std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec);

		if (multicast_endpoint.address().is_v4())
			open_multicast_socket(ios, address_v4::any(), loopback);
		else
			open_multicast_socket(ios, address_v6::any(), loopback);

		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			// only broadcast to IPv4 addresses that are not local
			if (is_local(i->interface_address)) continue;
			// only multicast on compatible networks
			if (i->interface_address.is_v4() != multicast_endpoint.address().is_v4()) continue;
			// ignore any loopback interface
			if (is_loopback(i->interface_address)) continue;

#ifndef NDEBUG
//			std::cerr << "broadcast socket [ if: " << i->to_v4().to_string()
//				<< " group: " << multicast_endpoint.address() << " ]" << std::endl;
#endif
			open_unicast_socket(ios, i->interface_address);
		}
	}

	void broadcast_socket::open_multicast_socket(io_service& ios
		, address const& addr, bool loopback)
	{
		using namespace asio::ip::multicast;

		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		if (addr.is_v4())
			s->open(udp::v4(), ec);
		else
			s->open(udp::v6(), ec);
		if (ec) return;
		s->set_option(datagram_socket::reuse_address(true), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, m_multicast_endpoint.port()), ec);
		if (ec) return;
		s->set_option(join_group(m_multicast_endpoint.address()), ec);
		if (ec) return;
		s->set_option(hops(255), ec);
		if (ec) return;
		s->set_option(enable_loopback(loopback), ec);
		if (ec) return;
		m_sockets.push_back(socket_entry(s));
		socket_entry& se = m_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr)
	{
		using namespace asio::ip::multicast;
		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, 0), ec);
		if (ec) return;
		if (addr.is_v4())
			s->set_option(outbound_interface(addr.to_v4()), ec);
		if (ec) return;
		m_unicast_sockets.push_back(socket_entry(s));
		socket_entry& se = m_unicast_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::send(char const* buffer, int size, error_code& ec)
	{
		for (std::list<socket_entry>::iterator i = m_unicast_sockets.begin()
			, end(m_unicast_sockets.end()); i != end; ++i)
		{
			if (!i->socket) continue;
			error_code e;
			i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG
//			std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << " to: " << m_multicast_endpoint << std::endl;
#endif
			if (e)
			{
				i->socket->close(e);
				i->socket.reset();
			}
		}
	}

	void broadcast_socket::on_receive(socket_entry* s, error_code const& ec
		, std::size_t bytes_transferred)
	{
		if (ec || bytes_transferred == 0 || !m_on_receive) return;
		m_on_receive(s->remote, s->buffer, bytes_transferred);
		if (!s->socket) return;
		s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
			, s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
	}

	void broadcast_socket::close()
	{
		std::for_each(m_sockets.begin(), m_sockets.end(), bind(&socket_entry::close, _1));
		std::for_each(m_unicast_sockets.begin(), m_unicast_sockets.end(), bind(&socket_entry::close, _1));

		m_on_receive.clear();
	}
}

<commit_msg>fixed bug where broadcast socket would not send messages on interfaces with addresses in local network ranges<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author 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 <boost/version.hpp>

#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif

#include <boost/bind.hpp>

#include "libtorrent/socket.hpp"
#include "libtorrent/enum_net.hpp"
#include "libtorrent/broadcast_socket.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	bool is_local(address const& a)
	{
		if (a.is_v6()) return a.to_v6().is_link_local();
		address_v4 a4 = a.to_v4();
		unsigned long ip = a4.to_ulong();
		return ((ip & 0xff000000) == 0x0a000000
			|| (ip & 0xfff00000) == 0xac100000
			|| (ip & 0xffff0000) == 0xc0a80000);
	}

	bool is_loopback(address const& addr)
	{
		if (addr.is_v4())
		  return addr.to_v4() == address_v4::loopback();
		else
			return addr.to_v6() == address_v6::loopback();
	}

	bool is_multicast(address const& addr)
	{
		if (addr.is_v4())
			return addr.to_v4().is_multicast();
		else
			return addr.to_v6().is_multicast();
	}

	bool is_any(address const& addr)
	{
		if (addr.is_v4())
			return addr.to_v4() == address_v4::any();
		else if (addr.to_v6().is_v4_mapped())
			return (addr.to_v6().to_v4() == address_v4::any());
		else
			return addr.to_v6() == address_v6::any();
	}

	address guess_local_address(io_service& ios)
	{
		// make a best guess of the interface we're using and its IP
		error_code ec;
		std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec);
		address ret = address_v4::any();
		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			address const& a = i->interface_address;
			if (is_loopback(a)
				|| is_multicast(a)
				|| is_any(a)) continue;

			// prefer a v4 address, but return a v6 if
			// there are no v4
			if (a.is_v4()) return a;

			if (ret != address_v4::any())
				ret = a;
		}
		return ret;
	}

	// count the length of the common bit prefix
	int common_bits(unsigned char const* b1
		, unsigned char const* b2, int n)
	{
		for (int i = 0; i < n; ++i, ++b1, ++b2)
		{
			unsigned char a = *b1 ^ *b2;
			if (a == 0) continue;
			int ret = i * 8 + 8;
			for (; a > 0; a >>= 1) --ret;
			return ret;
		}
		return n * 8;
	}

	// returns the number of bits in that differ from the right
	// between the addresses.
	int cidr_distance(address const& a1, address const& a2)
	{
		if (a1.is_v4() == a2.is_v4())
		{
			// both are v4
			address_v4::bytes_type b1 = a1.to_v4().to_bytes();
			address_v4::bytes_type b2 = a2.to_v4().to_bytes();
			return address_v4::bytes_type::static_size * 8
				- common_bits(b1.c_array(), b2.c_array(), b1.size());
		}

		address_v6::bytes_type b1;
		address_v6::bytes_type b2;
		if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
		else b1 = a1.to_v6().to_bytes();
		if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
		else b2 = a2.to_v6().to_bytes();
		return address_v6::bytes_type::static_size * 8
			- common_bits(b1.c_array(), b2.c_array(), b1.size());
	}

	broadcast_socket::broadcast_socket(io_service& ios
		, udp::endpoint const& multicast_endpoint
		, receive_handler_t const& handler
		, bool loopback)
		: m_multicast_endpoint(multicast_endpoint)
		, m_on_receive(handler)
	{
		TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address()));

		using namespace asio::ip::multicast;

		error_code ec;
		std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec);

		if (multicast_endpoint.address().is_v4())
			open_multicast_socket(ios, address_v4::any(), loopback);
		else
			open_multicast_socket(ios, address_v6::any(), loopback);

		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			// only multicast on compatible networks
			if (i->interface_address.is_v4() != multicast_endpoint.address().is_v4()) continue;
			// ignore any loopback interface
			if (is_loopback(i->interface_address)) continue;

#ifndef NDEBUG
//			std::cerr << "broadcast socket [ if: " << i->interface_address.to_v4().to_string()
//				<< " group: " << multicast_endpoint.address() << " ]" << std::endl;
#endif
			open_unicast_socket(ios, i->interface_address);
		}
	}

	void broadcast_socket::open_multicast_socket(io_service& ios
		, address const& addr, bool loopback)
	{
		using namespace asio::ip::multicast;

		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		if (addr.is_v4())
			s->open(udp::v4(), ec);
		else
			s->open(udp::v6(), ec);
		if (ec) return;
		s->set_option(datagram_socket::reuse_address(true), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, m_multicast_endpoint.port()), ec);
		if (ec) return;
		s->set_option(join_group(m_multicast_endpoint.address()), ec);
		if (ec) return;
		s->set_option(hops(255), ec);
		if (ec) return;
		s->set_option(enable_loopback(loopback), ec);
		if (ec) return;
		m_sockets.push_back(socket_entry(s));
		socket_entry& se = m_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr)
	{
		using namespace asio::ip::multicast;
		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, 0), ec);
		if (ec) return;
		if (addr.is_v4())
			s->set_option(outbound_interface(addr.to_v4()), ec);
		if (ec) return;
		m_unicast_sockets.push_back(socket_entry(s));
		socket_entry& se = m_unicast_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::send(char const* buffer, int size, error_code& ec)
	{
		for (std::list<socket_entry>::iterator i = m_unicast_sockets.begin()
			, end(m_unicast_sockets.end()); i != end; ++i)
		{
			if (!i->socket) continue;
			error_code e;
			i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG
//			std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << " to: " << m_multicast_endpoint << std::endl;
#endif
			if (e)
			{
				i->socket->close(e);
				i->socket.reset();
			}
		}
	}

	void broadcast_socket::on_receive(socket_entry* s, error_code const& ec
		, std::size_t bytes_transferred)
	{
		if (ec || bytes_transferred == 0 || !m_on_receive) return;
		m_on_receive(s->remote, s->buffer, bytes_transferred);
		if (!s->socket) return;
		s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
			, s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
	}

	void broadcast_socket::close()
	{
		std::for_each(m_sockets.begin(), m_sockets.end(), bind(&socket_entry::close, _1));
		std::for_each(m_unicast_sockets.begin(), m_unicast_sockets.end(), bind(&socket_entry::close, _1));

		m_on_receive.clear();
	}
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author 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 <boost/version.hpp>

#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif

#include <boost/bind.hpp>

#include "libtorrent/socket.hpp"
#include "libtorrent/enum_net.hpp"
#include "libtorrent/broadcast_socket.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	bool is_local(address const& a)
	{
#if TORRENT_USE_IPV6
		if (a.is_v6()) return a.to_v6().is_link_local();
#endif
		address_v4 a4 = a.to_v4();
		unsigned long ip = a4.to_ulong();
		return ((ip & 0xff000000) == 0x0a000000
			|| (ip & 0xfff00000) == 0xac100000
			|| (ip & 0xffff0000) == 0xc0a80000);
	}

	bool is_loopback(address const& addr)
	{
#if TORRENT_USE_IPV6
		if (addr.is_v4())
			return addr.to_v4() == address_v4::loopback();
		else
			return addr.to_v6() == address_v6::loopback();
#else
		return addr.to_v4() == address_v4::loopback();
#endif
	}

	bool is_multicast(address const& addr)
	{
#if TORRENT_USE_IPV6
		if (addr.is_v4())
			return addr.to_v4().is_multicast();
		else
			return addr.to_v6().is_multicast();
#else
		return addr.to_v4().is_multicast();
#endif
	}

	bool is_any(address const& addr)
	{
#if TORRENT_USE_IPV6
		if (addr.is_v4())
			return addr.to_v4() == address_v4::any();
		else if (addr.to_v6().is_v4_mapped())
			return (addr.to_v6().to_v4() == address_v4::any());
		else
			return addr.to_v6() == address_v6::any();
#else
		return addr.to_v4() == address_v4::any();
#endif
	}

	bool supports_ipv6()
	{
#if TORRENT_USE_IPV6
		error_code ec;
		address::from_string("::1", ec);
		return !ec;
#else
		return false;
#endif
	}

	address guess_local_address(io_service& ios)
	{
		// make a best guess of the interface we're using and its IP
		error_code ec;
		std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec);
		address ret = address_v4::any();
		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			address const& a = i->interface_address;
			if (is_loopback(a)
				|| is_multicast(a)
				|| is_any(a)) continue;

			// prefer a v4 address, but return a v6 if
			// there are no v4
			if (a.is_v4()) return a;

			if (ret != address_v4::any())
				ret = a;
		}
		return ret;
	}

	// count the length of the common bit prefix
	int common_bits(unsigned char const* b1
		, unsigned char const* b2, int n)
	{
		for (int i = 0; i < n; ++i, ++b1, ++b2)
		{
			unsigned char a = *b1 ^ *b2;
			if (a == 0) continue;
			int ret = i * 8 + 8;
			for (; a > 0; a >>= 1) --ret;
			return ret;
		}
		return n * 8;
	}

	// returns the number of bits in that differ from the right
	// between the addresses.
	int cidr_distance(address const& a1, address const& a2)
	{
#if TORRENT_USE_IPV6
		if (a1.is_v4() && a2.is_v4())
		{
#endif
			// both are v4
			address_v4::bytes_type b1 = a1.to_v4().to_bytes();
			address_v4::bytes_type b2 = a2.to_v4().to_bytes();
			return address_v4::bytes_type::static_size * 8
				- common_bits(b1.c_array(), b2.c_array(), b1.size());
#if TORRENT_USE_IPV6
		}

		address_v6::bytes_type b1;
		address_v6::bytes_type b2;
		if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
		else b1 = a1.to_v6().to_bytes();
		if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
		else b2 = a2.to_v6().to_bytes();
		return address_v6::bytes_type::static_size * 8
			- common_bits(b1.c_array(), b2.c_array(), b1.size());
#endif
	}

	broadcast_socket::broadcast_socket(io_service& ios
		, udp::endpoint const& multicast_endpoint
		, receive_handler_t const& handler
		, bool loopback)
		: m_multicast_endpoint(multicast_endpoint)
		, m_on_receive(handler)
	{
		TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address()));

		using namespace asio::ip::multicast;

		error_code ec;
		std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec);

#if TORRENT_USE_IPV6
		if (multicast_endpoint.address().is_v4())
#endif
			open_multicast_socket(ios, address_v4::any(), loopback);
#if TORRENT_USE_IPV6
		else
			open_multicast_socket(ios, address_v6::any(), loopback);
#endif

		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			// only multicast on compatible networks
			if (i->interface_address.is_v4() != multicast_endpoint.address().is_v4()) continue;
			// ignore any loopback interface
			if (is_loopback(i->interface_address)) continue;

#ifndef NDEBUG
//			std::cerr << "broadcast socket [ if: " << i->interface_address.to_v4().to_string()
//				<< " group: " << multicast_endpoint.address() << " ]" << std::endl;
#endif
			open_unicast_socket(ios, i->interface_address);
		}
	}

	void broadcast_socket::open_multicast_socket(io_service& ios
		, address const& addr, bool loopback)
	{
		using namespace asio::ip::multicast;

		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->set_option(datagram_socket::reuse_address(true), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, m_multicast_endpoint.port()), ec);
		if (ec) return;
		s->set_option(join_group(m_multicast_endpoint.address()), ec);
		if (ec) return;
		s->set_option(hops(255), ec);
		if (ec) return;
		s->set_option(enable_loopback(loopback), ec);
		if (ec) return;
		m_sockets.push_back(socket_entry(s));
		socket_entry& se = m_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr)
	{
		using namespace asio::ip::multicast;
		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, 0), ec);
		if (ec) return;
		m_unicast_sockets.push_back(socket_entry(s));
		socket_entry& se = m_unicast_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::send(char const* buffer, int size, error_code& ec)
	{
		for (std::list<socket_entry>::iterator i = m_unicast_sockets.begin()
			, end(m_unicast_sockets.end()); i != end; ++i)
		{
			if (!i->socket) continue;
			error_code e;
			i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG
//			std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << " to: " << m_multicast_endpoint << std::endl;
#endif
			if (e)
			{
				i->socket->close(e);
				i->socket.reset();
			}
		}
	}

	void broadcast_socket::on_receive(socket_entry* s, error_code const& ec
		, std::size_t bytes_transferred)
	{
		if (ec || bytes_transferred == 0 || !m_on_receive) return;
		m_on_receive(s->remote, s->buffer, bytes_transferred);
		if (!s->socket) return;
		s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
			, s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
	}

	void broadcast_socket::close()
	{
		std::for_each(m_sockets.begin(), m_sockets.end(), bind(&socket_entry::close, _1));
		std::for_each(m_unicast_sockets.begin(), m_unicast_sockets.end(), bind(&socket_entry::close, _1));

		m_on_receive.clear();
	}
}

<commit_msg>include self-assigned address range in what's considered 'local'<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author 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 <boost/version.hpp>

#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif

#include <boost/bind.hpp>

#include "libtorrent/socket.hpp"
#include "libtorrent/enum_net.hpp"
#include "libtorrent/broadcast_socket.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	bool is_local(address const& a)
	{
#if TORRENT_USE_IPV6
		if (a.is_v6()) return a.to_v6().is_link_local();
#endif
		address_v4 a4 = a.to_v4();
		unsigned long ip = a4.to_ulong();
		return ((ip & 0xff000000) == 0x0a000000 // 10.x.x.x
			|| (ip & 0xfff00000) == 0xac100000 // 172.16.x.x
			|| (ip & 0xffff0000) == 0xc0a80000 // 192.168.x.x
			|| (ip & 0xa9fe0000) == 0xa9fe0000); // 169.254.x.x
	}

	bool is_loopback(address const& addr)
	{
#if TORRENT_USE_IPV6
		if (addr.is_v4())
			return addr.to_v4() == address_v4::loopback();
		else
			return addr.to_v6() == address_v6::loopback();
#else
		return addr.to_v4() == address_v4::loopback();
#endif
	}

	bool is_multicast(address const& addr)
	{
#if TORRENT_USE_IPV6
		if (addr.is_v4())
			return addr.to_v4().is_multicast();
		else
			return addr.to_v6().is_multicast();
#else
		return addr.to_v4().is_multicast();
#endif
	}

	bool is_any(address const& addr)
	{
#if TORRENT_USE_IPV6
		if (addr.is_v4())
			return addr.to_v4() == address_v4::any();
		else if (addr.to_v6().is_v4_mapped())
			return (addr.to_v6().to_v4() == address_v4::any());
		else
			return addr.to_v6() == address_v6::any();
#else
		return addr.to_v4() == address_v4::any();
#endif
	}

	bool supports_ipv6()
	{
#if TORRENT_USE_IPV6
		error_code ec;
		address::from_string("::1", ec);
		return !ec;
#else
		return false;
#endif
	}

	address guess_local_address(io_service& ios)
	{
		// make a best guess of the interface we're using and its IP
		error_code ec;
		std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec);
		address ret = address_v4::any();
		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			address const& a = i->interface_address;
			if (is_loopback(a)
				|| is_multicast(a)
				|| is_any(a)) continue;

			// prefer a v4 address, but return a v6 if
			// there are no v4
			if (a.is_v4()) return a;

			if (ret != address_v4::any())
				ret = a;
		}
		return ret;
	}

	// count the length of the common bit prefix
	int common_bits(unsigned char const* b1
		, unsigned char const* b2, int n)
	{
		for (int i = 0; i < n; ++i, ++b1, ++b2)
		{
			unsigned char a = *b1 ^ *b2;
			if (a == 0) continue;
			int ret = i * 8 + 8;
			for (; a > 0; a >>= 1) --ret;
			return ret;
		}
		return n * 8;
	}

	// returns the number of bits in that differ from the right
	// between the addresses.
	int cidr_distance(address const& a1, address const& a2)
	{
#if TORRENT_USE_IPV6
		if (a1.is_v4() && a2.is_v4())
		{
#endif
			// both are v4
			address_v4::bytes_type b1 = a1.to_v4().to_bytes();
			address_v4::bytes_type b2 = a2.to_v4().to_bytes();
			return address_v4::bytes_type::static_size * 8
				- common_bits(b1.c_array(), b2.c_array(), b1.size());
#if TORRENT_USE_IPV6
		}

		address_v6::bytes_type b1;
		address_v6::bytes_type b2;
		if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
		else b1 = a1.to_v6().to_bytes();
		if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
		else b2 = a2.to_v6().to_bytes();
		return address_v6::bytes_type::static_size * 8
			- common_bits(b1.c_array(), b2.c_array(), b1.size());
#endif
	}

	broadcast_socket::broadcast_socket(io_service& ios
		, udp::endpoint const& multicast_endpoint
		, receive_handler_t const& handler
		, bool loopback)
		: m_multicast_endpoint(multicast_endpoint)
		, m_on_receive(handler)
	{
		TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address()));

		using namespace asio::ip::multicast;

		error_code ec;
		std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec);

#if TORRENT_USE_IPV6
		if (multicast_endpoint.address().is_v4())
#endif
			open_multicast_socket(ios, address_v4::any(), loopback);
#if TORRENT_USE_IPV6
		else
			open_multicast_socket(ios, address_v6::any(), loopback);
#endif

		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			// only multicast on compatible networks
			if (i->interface_address.is_v4() != multicast_endpoint.address().is_v4()) continue;
			// ignore any loopback interface
			if (is_loopback(i->interface_address)) continue;

#ifndef NDEBUG
//			std::cerr << "broadcast socket [ if: " << i->interface_address.to_v4().to_string()
//				<< " group: " << multicast_endpoint.address() << " ]" << std::endl;
#endif
			open_unicast_socket(ios, i->interface_address);
		}
	}

	void broadcast_socket::open_multicast_socket(io_service& ios
		, address const& addr, bool loopback)
	{
		using namespace asio::ip::multicast;

		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->set_option(datagram_socket::reuse_address(true), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, m_multicast_endpoint.port()), ec);
		if (ec) return;
		s->set_option(join_group(m_multicast_endpoint.address()), ec);
		if (ec) return;
		s->set_option(hops(255), ec);
		if (ec) return;
		s->set_option(enable_loopback(loopback), ec);
		if (ec) return;
		m_sockets.push_back(socket_entry(s));
		socket_entry& se = m_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr)
	{
		using namespace asio::ip::multicast;
		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, 0), ec);
		if (ec) return;
		m_unicast_sockets.push_back(socket_entry(s));
		socket_entry& se = m_unicast_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::send(char const* buffer, int size, error_code& ec)
	{
		for (std::list<socket_entry>::iterator i = m_unicast_sockets.begin()
			, end(m_unicast_sockets.end()); i != end; ++i)
		{
			if (!i->socket) continue;
			error_code e;
			i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG
//			std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << " to: " << m_multicast_endpoint << std::endl;
#endif
			if (e)
			{
				i->socket->close(e);
				i->socket.reset();
			}
		}
	}

	void broadcast_socket::on_receive(socket_entry* s, error_code const& ec
		, std::size_t bytes_transferred)
	{
		if (ec || bytes_transferred == 0 || !m_on_receive) return;
		m_on_receive(s->remote, s->buffer, bytes_transferred);
		if (!s->socket) return;
		s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
			, s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
	}

	void broadcast_socket::close()
	{
		std::for_each(m_sockets.begin(), m_sockets.end(), bind(&socket_entry::close, _1));
		std::for_each(m_unicast_sockets.begin(), m_unicast_sockets.end(), bind(&socket_entry::close, _1));

		m_on_receive.clear();
	}
}

<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#pragma warning( 4: 4786)
#endif

#include "CursesUI.h"

// add this UI to the map
UIAdder CursesUI::uiAdder("curses", &CursesUI::creator);

CursesUI::CursesUI(const PlayerIdMap& p, PlayerId m) :
  menuState(0), menu(p), players(p), me(m), maxHistory(20),
  currentHistory(0), maxBufferSize(300), scrollOffset(0) {

  // initialize ncurses
  initscr();
  start_color();
#ifdef HAVE_NCURSES_H
  use_default_colors();
#endif
  init_pair(Default, -1, -1);
  init_pair(White, COLOR_WHITE, -1);
  init_pair(Red, COLOR_RED, -1);
  init_pair(Green, COLOR_GREEN, -1);
  init_pair(Blue, COLOR_BLUE, -1);
  init_pair(Purple, COLOR_MAGENTA, -1);
  init_pair(Yellow, COLOR_YELLOW, -1);
  init_pair(Cyan, COLOR_CYAN, -1);
  nonl();
  cbreak();
  noecho();

  // create main output window
  mainWin = newwin(LINES - 5, 0, 0, 0);
  wsetscrreg(mainWin, 0, LINES - 2);
  scrollok(mainWin, TRUE);
  wrefresh(mainWin);

  // create target window
  targetWin = newwin(1, 0, LINES - 2, 0);
  wattron(targetWin, A_UNDERLINE);
  targetIter = players.begin();
  updateTargetWin();

  // create command window
  cmdWin = newwin(0, 0, LINES - 1, 0);
  keypad(cmdWin, TRUE);
  nodelay(cmdWin, TRUE);
  updateCmdWin();

  // initialize the menu
  menu.setUpdateCallback(initMainMenu);

  // register commands for tab completion
  comp.registerWord("/ban ");
  comp.registerWord("/banlist");
  comp.registerWord("/countdown");
  comp.registerWord("/deregister");
  comp.registerWord("/flag ");
  comp.registerWord("reset");
  comp.registerWord("up");
  comp.registerWord("show");
  comp.registerWord("/flaghistory");
  comp.registerWord("/gameover");
  comp.registerWord("/ghost ");
  comp.registerWord("/groupperms");
  comp.registerWord("/help");
  comp.registerWord("/identify ");
  comp.registerWord("/idlestats");
  comp.registerWord("/kick ");
  comp.registerWord("/lagstats");
  comp.registerWord("/lagwarn ");
  comp.registerWord("/password ");
  comp.registerWord("/playerlist");
  comp.registerWord("/poll ");
  comp.registerWord("ban");
  comp.registerWord("kick");
  comp.registerWord("/quit");
  comp.registerWord("/register ");
  comp.registerWord("/reload");
  comp.registerWord("/removegroup ");
  comp.registerWord("/report ");
  comp.registerWord("/reset");
  comp.registerWord("/set");
  comp.registerWord("/setgroup ");
  comp.registerWord("/setpass ");
  comp.registerWord("/shutdownserver");
  comp.registerWord("/superkill");
  comp.registerWord("/unban ");
  comp.registerWord("/veto");
  comp.registerWord("/vote");
}

CursesUI::~CursesUI() {
  endwin();
}

void CursesUI::outputMessage(const std::string& msg, ColorCode color) {
  // add message to the message buffer, remove the oldest message if it's full
  if (msgBuffer.size() == maxBufferSize)
    msgBuffer.erase(msgBuffer.begin());
  std::pair<std::string, ColorCode> p(msg, color);
  msgBuffer.push_back(p);

  // if we have scrolled away from the bottom, don't show the new message
  if (scrollOffset == 0) {
    wattron(mainWin, COLOR_PAIR(color));
    waddstr(mainWin, (msg + "\n").c_str());
    wattroff(mainWin, COLOR_PAIR(color));
    wrefresh(mainWin);
  }
}

bool CursesUI::checkCommand(std::string& str) {
  wrefresh(cmdWin);
  str = "";
  int i;

  // get a character and do checks that are always needed
  int c = wgetch(cmdWin);
  switch (c) {
#ifdef HAVE_NCURSES_H
   case KEY_RESIZE:
     handleResize(LINES, COLS);
     return false;
#endif
  case KEY_F(2):
    toggleMenu();
    return false;
  case ERR:
    return false;
  }

  // if the menu is active, use the keystrokes for that
  if (menuState == 1)
    return menu.handleKey(c, str);

  // if not, go ahead and parse commands
  switch (c) {

    // clear command (21 is Ctrl-U)
  case 21:
    cmd = "";
    updateCmdWin();
    currentHistory = history.size();

    // delete last character
  case KEY_BACKSPACE:
  case KEY_DC:
  case 127:
    cmd = cmd.substr(0, cmd.size() - 1);
    updateCmdWin();
    return false;

    // redraw command (12 is ctrl-l)
  case 12:
    wclear(cmdWin);
    wclear(targetWin);
    updateCmdWin();
    updateTargetWin();
    return false;

    // send command
  case '\n': // works with PDCurses
  case 13:   // works with ncurses
    if (history.size() == maxHistory)
      history.erase(history.begin());
    history.push_back(cmd);
    str = cmd;
    cmd = "";
    currentHistory = history.size();
    updateCmdWin();
    return true;

    // scroll main window
  case KEY_NPAGE:
    scrollOffset = (scrollOffset < unsigned(LINES - 2) / 2 ?
		    0 : scrollOffset - (LINES - 2) / 2);
    updateMainWinFromBuffer(LINES - 2);
    return false;
  case KEY_PPAGE:
    if (msgBuffer.size() < unsigned(LINES - 2))
      scrollOffset = 0;
    else if (scrollOffset > msgBuffer.size() - (LINES - 2) - (LINES - 2) / 2)
      scrollOffset = msgBuffer.size() - (LINES - 2);
    else
      scrollOffset += (LINES - 2) / 2;
    updateMainWinFromBuffer(LINES - 2);
    return false;

    // change target
  case KEY_LEFT:
    if (targetIter == players.begin())
      for (unsigned int i = 0; i < players.size() - 1; i++)
	++targetIter;
    else
      targetIter--;
    updateTargetWin();
    return false;
  case KEY_RIGHT:
    targetIter++;
    if (targetIter == players.end())
      targetIter = players.begin();
    updateTargetWin();
    return false;

    // command history
  case KEY_UP:
    if (currentHistory == 0 || history.size() == 0)
      return false;
    --currentHistory;
    cmd = history[currentHistory];
    updateCmdWin();
    return false;
  case KEY_DOWN:
    if (currentHistory < history.size())
      ++currentHistory;
    if (currentHistory == history.size())
      cmd = "";
    else
      cmd = history[currentHistory];
    updateCmdWin();
    return false;

    // kick target
  case KEY_F(5):
    if (targetIter != players.end() && targetIter->first != me) {
      cmd = "/kick ";
      cmd += targetIter->second.name;
      targetIter = players.find(me);
      updateCmdWin();
      updateTargetWin();
    }
    return false;

    // ban target (only works if we have done /playerlist earlier)
  case KEY_F(6):
    if (targetIter != players.end() && targetIter->first != me) {
      if (targetIter->second.ip != "") {
	cmd = "/ban ";
	cmd += targetIter->second.ip;
	targetIter = players.find(me);
	updateCmdWin();
	updateTargetWin();
      }
      else {
	std::string msg = "--- Can't ban ";
	msg += targetIter->second.name + ", you don't have the IP address";
	outputMessage(msg, Red);
	outputMessage("--- Trying to fetch IP addresses...", Red);
	str = "/playerlist";
	return true;
      }
    }
    return false;

    // tab - autocomplete
  case '\t':
    i = cmd.find_last_of(" \t");
    cmd = cmd.substr(0, i+1) + comp.complete(cmd.substr(i+1));
    updateCmdWin();
    return false;

  default:
    if (c < 32 || c > 127 || cmd.size() >= CMDLENGTH)
      return false;
    cmd += char(c);
    updateCmdWin();
    return false;
  }
}

void CursesUI::addedPlayer(PlayerId p) {
  PlayerIdMap::const_iterator iter = players.find(p);
  comp.registerWord(iter->second.name);
  if (p == me)
    targetIter = iter;
}

void CursesUI::removingPlayer(PlayerId p) {
  if (targetIter->first == p) {
    targetIter = players.find(me);
    updateTargetWin();
  }
  comp.unregisterWord(players.find(p)->second.name);
}

PlayerId CursesUI::getTarget() const {
  if (targetIter->first == me)
    return AllPlayers;
  return targetIter->first;
}

void CursesUI::handleResize(int lines, int cols) {
#ifdef HAVE_NCURSES_H
  resizeterm(lines, cols);
  wresize(mainWin, lines - 2, cols);
#endif
  updateMainWinFromBuffer(lines - 2);
  mvwin(targetWin, lines - 2, 0);
#ifdef HAVE_NCURSES_H
  wresize(targetWin, 1, cols);
#endif
  mvwin(cmdWin, lines - 1, 0);
#ifdef HAVE_NCURSES_H
  wresize(cmdWin, 1, cols);
#endif
  updateTargetWin();
  updateCmdWin();
  wrefresh(mainWin);
}

void CursesUI::updateMainWinFromBuffer(unsigned int numberOfMessages) {
  wclear(mainWin);
  int start = msgBuffer.size() - numberOfMessages - scrollOffset;
  start = (start < 0 ? 0 : start);
  unsigned int end = start + numberOfMessages;
  end = (end >= msgBuffer.size() ? msgBuffer.size() : end);
  for (unsigned int i = start ; i < end; ++i) {
    wattron(mainWin, COLOR_PAIR(msgBuffer[i].second));
    waddstr(mainWin, (msgBuffer[i].first + "\n").c_str());
    wattroff(mainWin, COLOR_PAIR(msgBuffer[i].second));
  }
  wrefresh(mainWin);
}

void CursesUI::updateTargetWin() {
  werase(targetWin);
  wmove(targetWin, 0, 0);
  wmove(targetWin, 1, 1);
  std::string tmp = "Send to ";
  tmp = tmp + (targetIter == players.end() || targetIter->first == me ?
	       "all" : targetIter->second.name) + ":";
  waddstr(targetWin, tmp.c_str());
  wrefresh(targetWin);
}

void CursesUI::updateCmdWin() {
  werase(cmdWin);
  wmove(cmdWin, 1, 1);
  waddstr(cmdWin, cmd.c_str());
  wmove(cmdWin, 1, 1 + cmd.size());
  wrefresh(cmdWin);
}

void CursesUI::toggleMenu() {
  if (menuState == 0) {
    menuState = 1;
    curs_set(0);
    const int menuWinSize = (LINES - 2) / 2;
#ifdef HAVE_NCURSES_H
    wresize(mainWin, LINES - 2 - menuWinSize, COLS);
#endif
    mvwin(mainWin, menuWinSize, 0);
    updateMainWinFromBuffer(LINES - 2 - menuWinSize);
    menuWin = newwin(menuWinSize, 0, 0, 0);
    menu.setWindow(menuWin);
    menu.showMenu();
  }
  else if (menuState == 1) {
    menuState = 2;
    curs_set(1);
  }
  else {
    menuState = 0;
    menu.setWindow(NULL);
    delwin(menuWin);
#ifdef HAVE_NCURSES_H
    wresize(mainWin, LINES - 2, COLS);
#endif
    mvwin(mainWin, 0, 0);
    updateMainWinFromBuffer(LINES - 2);
  }
  wrefresh(targetWin);
  wrefresh(cmdWin);
}

void CursesUI::initMainMenu(CursesMenu& menu) {
  menu.setHeader("MAIN MENU");
  menu.clear();
  menu.addItem(new SubmenuCMItem("Show players",
				  &CursesUI::initPlayerMenu));
  //menu.addItem(new SubmenuCMItem("Edit banlist",
  //				  &CursesUI::initBanMenu));
  menu.addItem(new SubmenuCMItem("Edit server variables",
				  &CursesUI::initServerVarMenu));
  //menu.addItem(new SubmenuCMItem("Edit message filter",
  //				  &CursesUI::initFilterMenu));
}

void CursesUI::initPlayerMenu(CursesMenu& menu) {
  menu.setHeader("PLAYERLIST");
  menu.clear();
  PlayerIdMap::const_iterator it;
  for (it = menu.players.begin(); it != menu.players.end(); ++it)
    menu.addItem(new PlayerCMItem(menu.players, it->first));
  menu.addItem(new CommandCMItem("Reload playerlist", "/playerlist", true));
  menu.addItem(new SubmenuCMItem("Back to main menu",
				  &CursesUI::initMainMenu));
}

void CursesUI::initBanMenu(CursesMenu& menu) {
  menu.setHeader("BANLIST");
  menu.clear();
  menu.addItem(new SubmenuCMItem("Not implemented - go back",
				  &CursesUI::initMainMenu));
}

void CursesUI::initServerVarMenu(CursesMenu& menu) {
  menu.setHeader("SERVER VARIABLE EDITOR");
  menu.clear();
  BZDB.iterate(&CursesUI::addBZDBCMItem, &menu);
  menu.addItem(new SubmenuCMItem("Back to main menu",
				 &CursesUI::initMainMenu));
}

void CursesUI::addBZDBCMItem(const std::string& name, void* menu) {
  ((CursesMenu*)menu)->addItem(new BZDBCMItem(name));
}

void CursesUI::initFilterMenu(CursesMenu& menu) {
  menu.setHeader("MESSAGE FILTER EDITOR");
  menu.clear();
  menu.addItem(new SubmenuCMItem("Not implemented - go back",
				  &CursesUI::initMainMenu));
}

BZAdminUI* CursesUI::creator(const PlayerIdMap& players,
			     PlayerId me) {
  return new CursesUI(players, me);
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Don't name unused parameters<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#pragma warning( 4: 4786)
#endif

#include "CursesUI.h"

// add this UI to the map
UIAdder CursesUI::uiAdder("curses", &CursesUI::creator);

CursesUI::CursesUI(const PlayerIdMap& p, PlayerId m) :
  menuState(0), menu(p), players(p), me(m), maxHistory(20),
  currentHistory(0), maxBufferSize(300), scrollOffset(0) {

  // initialize ncurses
  initscr();
  start_color();
#ifdef HAVE_NCURSES_H
  use_default_colors();
#endif
  init_pair(Default, -1, -1);
  init_pair(White, COLOR_WHITE, -1);
  init_pair(Red, COLOR_RED, -1);
  init_pair(Green, COLOR_GREEN, -1);
  init_pair(Blue, COLOR_BLUE, -1);
  init_pair(Purple, COLOR_MAGENTA, -1);
  init_pair(Yellow, COLOR_YELLOW, -1);
  init_pair(Cyan, COLOR_CYAN, -1);
  nonl();
  cbreak();
  noecho();

  // create main output window
  mainWin = newwin(LINES - 5, 0, 0, 0);
  wsetscrreg(mainWin, 0, LINES - 2);
  scrollok(mainWin, TRUE);
  wrefresh(mainWin);

  // create target window
  targetWin = newwin(1, 0, LINES - 2, 0);
  wattron(targetWin, A_UNDERLINE);
  targetIter = players.begin();
  updateTargetWin();

  // create command window
  cmdWin = newwin(0, 0, LINES - 1, 0);
  keypad(cmdWin, TRUE);
  nodelay(cmdWin, TRUE);
  updateCmdWin();

  // initialize the menu
  menu.setUpdateCallback(initMainMenu);

  // register commands for tab completion
  comp.registerWord("/ban ");
  comp.registerWord("/banlist");
  comp.registerWord("/countdown");
  comp.registerWord("/deregister");
  comp.registerWord("/flag ");
  comp.registerWord("reset");
  comp.registerWord("up");
  comp.registerWord("show");
  comp.registerWord("/flaghistory");
  comp.registerWord("/gameover");
  comp.registerWord("/ghost ");
  comp.registerWord("/groupperms");
  comp.registerWord("/help");
  comp.registerWord("/identify ");
  comp.registerWord("/idlestats");
  comp.registerWord("/kick ");
  comp.registerWord("/lagstats");
  comp.registerWord("/lagwarn ");
  comp.registerWord("/password ");
  comp.registerWord("/playerlist");
  comp.registerWord("/poll ");
  comp.registerWord("ban");
  comp.registerWord("kick");
  comp.registerWord("/quit");
  comp.registerWord("/register ");
  comp.registerWord("/reload");
  comp.registerWord("/removegroup ");
  comp.registerWord("/report ");
  comp.registerWord("/reset");
  comp.registerWord("/set");
  comp.registerWord("/setgroup ");
  comp.registerWord("/setpass ");
  comp.registerWord("/shutdownserver");
  comp.registerWord("/superkill");
  comp.registerWord("/unban ");
  comp.registerWord("/veto");
  comp.registerWord("/vote");
}

CursesUI::~CursesUI() {
  endwin();
}

void CursesUI::outputMessage(const std::string& msg, ColorCode color) {
  // add message to the message buffer, remove the oldest message if it's full
  if (msgBuffer.size() == maxBufferSize)
    msgBuffer.erase(msgBuffer.begin());
  std::pair<std::string, ColorCode> p(msg, color);
  msgBuffer.push_back(p);

  // if we have scrolled away from the bottom, don't show the new message
  if (scrollOffset == 0) {
    wattron(mainWin, COLOR_PAIR(color));
    waddstr(mainWin, (msg + "\n").c_str());
    wattroff(mainWin, COLOR_PAIR(color));
    wrefresh(mainWin);
  }
}

bool CursesUI::checkCommand(std::string& str) {
  wrefresh(cmdWin);
  str = "";
  int i;

  // get a character and do checks that are always needed
  int c = wgetch(cmdWin);
  switch (c) {
#ifdef HAVE_NCURSES_H
   case KEY_RESIZE:
     handleResize(LINES, COLS);
     return false;
#endif
  case KEY_F(2):
    toggleMenu();
    return false;
  case ERR:
    return false;
  }

  // if the menu is active, use the keystrokes for that
  if (menuState == 1)
    return menu.handleKey(c, str);

  // if not, go ahead and parse commands
  switch (c) {

    // clear command (21 is Ctrl-U)
  case 21:
    cmd = "";
    updateCmdWin();
    currentHistory = history.size();

    // delete last character
  case KEY_BACKSPACE:
  case KEY_DC:
  case 127:
    cmd = cmd.substr(0, cmd.size() - 1);
    updateCmdWin();
    return false;

    // redraw command (12 is ctrl-l)
  case 12:
    wclear(cmdWin);
    wclear(targetWin);
    updateCmdWin();
    updateTargetWin();
    return false;

    // send command
  case '\n': // works with PDCurses
  case 13:   // works with ncurses
    if (history.size() == maxHistory)
      history.erase(history.begin());
    history.push_back(cmd);
    str = cmd;
    cmd = "";
    currentHistory = history.size();
    updateCmdWin();
    return true;

    // scroll main window
  case KEY_NPAGE:
    scrollOffset = (scrollOffset < unsigned(LINES - 2) / 2 ?
		    0 : scrollOffset - (LINES - 2) / 2);
    updateMainWinFromBuffer(LINES - 2);
    return false;
  case KEY_PPAGE:
    if (msgBuffer.size() < unsigned(LINES - 2))
      scrollOffset = 0;
    else if (scrollOffset > msgBuffer.size() - (LINES - 2) - (LINES - 2) / 2)
      scrollOffset = msgBuffer.size() - (LINES - 2);
    else
      scrollOffset += (LINES - 2) / 2;
    updateMainWinFromBuffer(LINES - 2);
    return false;

    // change target
  case KEY_LEFT:
    if (targetIter == players.begin())
      for (unsigned int i = 0; i < players.size() - 1; i++)
	++targetIter;
    else
      targetIter--;
    updateTargetWin();
    return false;
  case KEY_RIGHT:
    targetIter++;
    if (targetIter == players.end())
      targetIter = players.begin();
    updateTargetWin();
    return false;

    // command history
  case KEY_UP:
    if (currentHistory == 0 || history.size() == 0)
      return false;
    --currentHistory;
    cmd = history[currentHistory];
    updateCmdWin();
    return false;
  case KEY_DOWN:
    if (currentHistory < history.size())
      ++currentHistory;
    if (currentHistory == history.size())
      cmd = "";
    else
      cmd = history[currentHistory];
    updateCmdWin();
    return false;

    // kick target
  case KEY_F(5):
    if (targetIter != players.end() && targetIter->first != me) {
      cmd = "/kick ";
      cmd += targetIter->second.name;
      targetIter = players.find(me);
      updateCmdWin();
      updateTargetWin();
    }
    return false;

    // ban target (only works if we have done /playerlist earlier)
  case KEY_F(6):
    if (targetIter != players.end() && targetIter->first != me) {
      if (targetIter->second.ip != "") {
	cmd = "/ban ";
	cmd += targetIter->second.ip;
	targetIter = players.find(me);
	updateCmdWin();
	updateTargetWin();
      }
      else {
	std::string msg = "--- Can't ban ";
	msg += targetIter->second.name + ", you don't have the IP address";
	outputMessage(msg, Red);
	outputMessage("--- Trying to fetch IP addresses...", Red);
	str = "/playerlist";
	return true;
      }
    }
    return false;

    // tab - autocomplete
  case '\t':
    i = cmd.find_last_of(" \t");
    cmd = cmd.substr(0, i+1) + comp.complete(cmd.substr(i+1));
    updateCmdWin();
    return false;

  default:
    if (c < 32 || c > 127 || cmd.size() >= CMDLENGTH)
      return false;
    cmd += char(c);
    updateCmdWin();
    return false;
  }
}

void CursesUI::addedPlayer(PlayerId p) {
  PlayerIdMap::const_iterator iter = players.find(p);
  comp.registerWord(iter->second.name);
  if (p == me)
    targetIter = iter;
}

void CursesUI::removingPlayer(PlayerId p) {
  if (targetIter->first == p) {
    targetIter = players.find(me);
    updateTargetWin();
  }
  comp.unregisterWord(players.find(p)->second.name);
}

PlayerId CursesUI::getTarget() const {
  if (targetIter->first == me)
    return AllPlayers;
  return targetIter->first;
}

void CursesUI::handleResize(int lines, int) {
#ifdef HAVE_NCURSES_H
  resizeterm(lines, cols);
  wresize(mainWin, lines - 2, cols);
#endif
  updateMainWinFromBuffer(lines - 2);
  mvwin(targetWin, lines - 2, 0);
#ifdef HAVE_NCURSES_H
  wresize(targetWin, 1, cols);
#endif
  mvwin(cmdWin, lines - 1, 0);
#ifdef HAVE_NCURSES_H
  wresize(cmdWin, 1, cols);
#endif
  updateTargetWin();
  updateCmdWin();
  wrefresh(mainWin);
}

void CursesUI::updateMainWinFromBuffer(unsigned int numberOfMessages) {
  wclear(mainWin);
  int start = msgBuffer.size() - numberOfMessages - scrollOffset;
  start = (start < 0 ? 0 : start);
  unsigned int end = start + numberOfMessages;
  end = (end >= msgBuffer.size() ? msgBuffer.size() : end);
  for (unsigned int i = start ; i < end; ++i) {
    wattron(mainWin, COLOR_PAIR(msgBuffer[i].second));
    waddstr(mainWin, (msgBuffer[i].first + "\n").c_str());
    wattroff(mainWin, COLOR_PAIR(msgBuffer[i].second));
  }
  wrefresh(mainWin);
}

void CursesUI::updateTargetWin() {
  werase(targetWin);
  wmove(targetWin, 0, 0);
  wmove(targetWin, 1, 1);
  std::string tmp = "Send to ";
  tmp = tmp + (targetIter == players.end() || targetIter->first == me ?
	       "all" : targetIter->second.name) + ":";
  waddstr(targetWin, tmp.c_str());
  wrefresh(targetWin);
}

void CursesUI::updateCmdWin() {
  werase(cmdWin);
  wmove(cmdWin, 1, 1);
  waddstr(cmdWin, cmd.c_str());
  wmove(cmdWin, 1, 1 + cmd.size());
  wrefresh(cmdWin);
}

void CursesUI::toggleMenu() {
  if (menuState == 0) {
    menuState = 1;
    curs_set(0);
    const int menuWinSize = (LINES - 2) / 2;
#ifdef HAVE_NCURSES_H
    wresize(mainWin, LINES - 2 - menuWinSize, COLS);
#endif
    mvwin(mainWin, menuWinSize, 0);
    updateMainWinFromBuffer(LINES - 2 - menuWinSize);
    menuWin = newwin(menuWinSize, 0, 0, 0);
    menu.setWindow(menuWin);
    menu.showMenu();
  }
  else if (menuState == 1) {
    menuState = 2;
    curs_set(1);
  }
  else {
    menuState = 0;
    menu.setWindow(NULL);
    delwin(menuWin);
#ifdef HAVE_NCURSES_H
    wresize(mainWin, LINES - 2, COLS);
#endif
    mvwin(mainWin, 0, 0);
    updateMainWinFromBuffer(LINES - 2);
  }
  wrefresh(targetWin);
  wrefresh(cmdWin);
}

void CursesUI::initMainMenu(CursesMenu& menu) {
  menu.setHeader("MAIN MENU");
  menu.clear();
  menu.addItem(new SubmenuCMItem("Show players",
				  &CursesUI::initPlayerMenu));
  //menu.addItem(new SubmenuCMItem("Edit banlist",
  //				  &CursesUI::initBanMenu));
  menu.addItem(new SubmenuCMItem("Edit server variables",
				  &CursesUI::initServerVarMenu));
  //menu.addItem(new SubmenuCMItem("Edit message filter",
  //				  &CursesUI::initFilterMenu));
}

void CursesUI::initPlayerMenu(CursesMenu& menu) {
  menu.setHeader("PLAYERLIST");
  menu.clear();
  PlayerIdMap::const_iterator it;
  for (it = menu.players.begin(); it != menu.players.end(); ++it)
    menu.addItem(new PlayerCMItem(menu.players, it->first));
  menu.addItem(new CommandCMItem("Reload playerlist", "/playerlist", true));
  menu.addItem(new SubmenuCMItem("Back to main menu",
				  &CursesUI::initMainMenu));
}

void CursesUI::initBanMenu(CursesMenu& menu) {
  menu.setHeader("BANLIST");
  menu.clear();
  menu.addItem(new SubmenuCMItem("Not implemented - go back",
				  &CursesUI::initMainMenu));
}

void CursesUI::initServerVarMenu(CursesMenu& menu) {
  menu.setHeader("SERVER VARIABLE EDITOR");
  menu.clear();
  BZDB.iterate(&CursesUI::addBZDBCMItem, &menu);
  menu.addItem(new SubmenuCMItem("Back to main menu",
				 &CursesUI::initMainMenu));
}

void CursesUI::addBZDBCMItem(const std::string& name, void* menu) {
  ((CursesMenu*)menu)->addItem(new BZDBCMItem(name));
}

void CursesUI::initFilterMenu(CursesMenu& menu) {
  menu.setHeader("MESSAGE FILTER EDITOR");
  menu.clear();
  menu.addItem(new SubmenuCMItem("Not implemented - go back",
				  &CursesUI::initMainMenu));
}

BZAdminUI* CursesUI::creator(const PlayerIdMap& players,
			     PlayerId me) {
  return new CursesUI(players, me);
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>