<commit_before>#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <kms++/kms++.h>

namespace py = pybind11;

using namespace kms;
using namespace std;

void init_pykmsbase(py::module &m)
{
	py::class_<Card>(m, "Card")
			.def(py::init<>())
			.def_property_readonly("fd", &Card::fd)
			.def_property_readonly("get_first_connected_connector", &Card::get_first_connected_connector)

			// XXX pybind11 can't handle vector<T*> where T is non-copyable, and complains:
			// RuntimeError: return_value_policy = move, but the object is neither movable nor copyable!
			// So we do this manually.
			.def_property_readonly("connectors", [](Card* self) {
				vector<unique_ptr<Connector, py::nodelete>> v;
				for (Connector* p : self->get_connectors())
					v.push_back(unique_ptr<Connector, py::nodelete>(p));
				return v;
			})

			.def_property_readonly("planes", [](Card* self) {
				vector<unique_ptr<Plane, py::nodelete>> v;
				for (Plane* p : self->get_planes())
					v.push_back(unique_ptr<Plane, py::nodelete>(p));
				return v;
			})

			.def_property_readonly("has_atomic", &Card::has_atomic)
			.def("get_prop", (Property* (Card::*)(uint32_t) const)&Card::get_prop)
			;

	py::class_<DrmObject, unique_ptr<DrmObject, py::nodelete>>(m, "DrmObject")
			.def_property_readonly("id", &DrmObject::id)
			.def_property_readonly("idx", &DrmObject::idx)
			.def_property_readonly("card", &DrmObject::card)
			;

	py::class_<DrmPropObject, DrmObject, unique_ptr<DrmPropObject, py::nodelete>>(m, "DrmPropObject")
			.def("refresh_props", &DrmPropObject::refresh_props)
			.def_property_readonly("prop_map", &DrmPropObject::get_prop_map)
			.def("get_prop_value", (uint64_t (DrmPropObject::*)(const string&) const)&DrmPropObject::get_prop_value)
			.def("set_prop_value",(int (DrmPropObject::*)(const string&, uint64_t)) &DrmPropObject::set_prop_value)
			.def("get_prop_value_as_blob", &DrmPropObject::get_prop_value_as_blob)
			.def("get_prop", &DrmPropObject::get_prop)
			;

	py::class_<Connector, DrmPropObject, unique_ptr<Connector, py::nodelete>>(m, "Connector")
			.def_property_readonly("fullname", &Connector::fullname)
			.def("get_default_mode", &Connector::get_default_mode)
			.def("get_current_crtc", &Connector::get_current_crtc)
			.def("get_possible_crtcs", [](Connector* self) {
				vector<unique_ptr<Crtc, py::nodelete>> v;
				for (Crtc* p : self->get_possible_crtcs())
					v.push_back(unique_ptr<Crtc, py::nodelete>(p));
				return v;
			})
			.def("get_modes", &Connector::get_modes)
			.def("get_mode", (Videomode (Connector::*)(const string& mode) const)&Connector::get_mode)
			.def("get_mode", (Videomode (Connector::*)(unsigned xres, unsigned yres, float refresh, bool ilace) const)&Connector::get_mode)
			.def("connected", &Connector::connected)
			.def("__repr__", [](const Connector& o) { return "<pykms.Connector " + to_string(o.id()) + ">"; })
			.def("refresh", &Connector::refresh)
			;

	py::class_<Crtc, DrmPropObject, unique_ptr<Crtc, py::nodelete>>(m, "Crtc")
			.def("set_mode", (int (Crtc::*)(Connector*, const Videomode&))&Crtc::set_mode)
			.def("set_mode", (int (Crtc::*)(Connector*, Framebuffer&, const Videomode&))&Crtc::set_mode)
			.def("disable_mode", &Crtc::disable_mode)
			.def("page_flip",
			     [](Crtc* self, Framebuffer& fb, uint32_t data)
				{
					self->page_flip(fb, (void*)(intptr_t)data);
				}, py::arg("fb"), py::arg("data") = 0)
			.def("set_plane", &Crtc::set_plane)
			.def_property_readonly("possible_planes", &Crtc::get_possible_planes)
			.def_property_readonly("primary_plane", &Crtc::get_primary_plane)
			.def_property_readonly("mode", &Crtc::mode)
			.def_property_readonly("mode_valid", &Crtc::mode_valid)
			.def("__repr__", [](const Crtc& o) { return "<pykms.Crtc " + to_string(o.id()) + ">"; })
			.def("refresh", &Crtc::refresh)
			;

	py::class_<Encoder, DrmPropObject, unique_ptr<Encoder, py::nodelete>>(m, "Encoder")
			.def("refresh", &Encoder::refresh)
			;

	py::class_<Plane, DrmPropObject, unique_ptr<Plane, py::nodelete>>(m, "Plane")
			.def("supports_crtc", &Plane::supports_crtc)
			.def_property_readonly("formats", &Plane::get_formats)
			.def_property_readonly("plane_type", &Plane::plane_type)
			.def("__repr__", [](const Plane& o) { return "<pykms.Plane " + to_string(o.id()) + ">"; })
			;

	py::enum_<PlaneType>(m, "PlaneType")
			.value("Overlay", PlaneType::Overlay)
			.value("Primary", PlaneType::Primary)
			.value("Cursor", PlaneType::Cursor)
			;

	py::class_<Property, DrmObject, unique_ptr<Property, py::nodelete>>(m, "Property")
			.def_property_readonly("name", &Property::name)
			.def_property_readonly("enums", &Property::get_enums)
			;

	py::class_<Blob>(m, "Blob")
			.def("__init__", [](Blob& instance, Card& card, py::buffer buf) {
					py::buffer_info info = buf.request();
					if (info.ndim != 1)
						throw std::runtime_error("Incompatible buffer dimension!");

					new (&instance) Blob(card, info.ptr, info.size * info.itemsize);
				},
				py::keep_alive<1, 3>())	// Keep Card alive until this is destructed

			.def_property_readonly("data", &Blob::data)

			// XXX pybind11 doesn't support a base object (DrmObject) with custom holder-type,
			// and a subclass with standard holder-type.
			// So we just copy the DrmObject members here.
			// Note that this means that python thinks we don't derive from DrmObject
			.def_property_readonly("id", &DrmObject::id)
			.def_property_readonly("idx", &DrmObject::idx)
			.def_property_readonly("card", &DrmObject::card)
			;

	py::class_<Framebuffer>(m, "Framebuffer")
			.def_property_readonly("width", &Framebuffer::width)
			.def_property_readonly("height", &Framebuffer::height)

			// XXX pybind11 doesn't support a base object (DrmObject) with custom holder-type,
			// and a subclass with standard holder-type.
			// So we just copy the DrmObject members here.
			// Note that this means that python thinks we don't derive from DrmObject
			.def_property_readonly("id", &DrmObject::id)
			.def_property_readonly("idx", &DrmObject::idx)
			.def_property_readonly("card", &DrmObject::card)
			;

	py::class_<DumbFramebuffer, Framebuffer>(m, "DumbFramebuffer")
			.def(py::init<Card&, uint32_t, uint32_t, const string&>(),
			     py::keep_alive<1, 2>())	// Keep Card alive until this is destructed
			.def(py::init<Card&, uint32_t, uint32_t, PixelFormat>(),
			     py::keep_alive<1, 2>())	// Keep Card alive until this is destructed
			.def_property_readonly("format", &DumbFramebuffer::format)
			.def_property_readonly("num_planes", &DumbFramebuffer::num_planes)
			.def("fd", &DumbFramebuffer::prime_fd)
			.def("stride", &DumbFramebuffer::stride)
			.def("offset", &DumbFramebuffer::offset)
			;

	py::class_<ExtFramebuffer, Framebuffer>(m, "ExtFramebuffer")
			.def(py::init<Card&, uint32_t, uint32_t, PixelFormat, vector<int>, vector<uint32_t>, vector<uint32_t>>(),
			     py::keep_alive<1, 2>())	// Keep Card alive until this is destructed
			;

	py::enum_<PixelFormat>(m, "PixelFormat")
			.value("Undefined", PixelFormat::Undefined)

			.value("NV12", PixelFormat::NV12)
			.value("NV21", PixelFormat::NV21)

			.value("UYVY", PixelFormat::UYVY)
			.value("YUYV", PixelFormat::YUYV)
			.value("YVYU", PixelFormat::YVYU)
			.value("VYUY", PixelFormat::VYUY)

			.value("XRGB8888", PixelFormat::XRGB8888)
			.value("XBGR8888", PixelFormat::XBGR8888)
			.value("ARGB8888", PixelFormat::ARGB8888)
			.value("ABGR8888", PixelFormat::ABGR8888)

			.value("RGB888", PixelFormat::RGB888)
			.value("BGR888", PixelFormat::BGR888)

			.value("RGB565", PixelFormat::RGB565)
			.value("BGR565", PixelFormat::BGR565)
			;

	py::enum_<SyncPolarity>(m, "SyncPolarity")
			.value("Undefined", SyncPolarity::Undefined)
			.value("Positive", SyncPolarity::Positive)
			.value("Negative", SyncPolarity::Negative)
			;

	py::class_<Videomode>(m, "Videomode")
			.def(py::init<>())

			.def_readwrite("name", &Videomode::name)

			.def_readwrite("clock", &Videomode::clock)

			.def_readwrite("hdisplay", &Videomode::hdisplay)
			.def_readwrite("hsync_start", &Videomode::hsync_start)
			.def_readwrite("hsync_end", &Videomode::hsync_end)
			.def_readwrite("htotal", &Videomode::htotal)

			.def_readwrite("vdisplay", &Videomode::vdisplay)
			.def_readwrite("vsync_start", &Videomode::vsync_start)
			.def_readwrite("vsync_end", &Videomode::vsync_end)
			.def_readwrite("vtotal", &Videomode::vtotal)

			.def_readwrite("vrefresh", &Videomode::vrefresh)

			.def_readwrite("flags", &Videomode::flags)
			.def_readwrite("type", &Videomode::type)

			.def("__repr__", [](const Videomode& vm) { return "<pykms.Videomode " + to_string(vm.hdisplay) + "x" + to_string(vm.vdisplay) + ">"; })

			.def("to_blob", &Videomode::to_blob)

			.def_property("hsync", &Videomode::hsync, &Videomode::set_hsync)
			.def_property("vsync", &Videomode::vsync, &Videomode::set_vsync)
			;

	m.def("videomode_from_timings", &videomode_from_timings);

	py::class_<AtomicReq>(m, "AtomicReq")
			.def(py::init<Card&>(),
			     py::keep_alive<1, 2>())	// Keep Card alive until this is destructed
			.def("add", (void (AtomicReq::*)(DrmPropObject*, const string&, uint64_t)) &AtomicReq::add)
			.def("add", (void (AtomicReq::*)(DrmPropObject*, const map<string, uint64_t>&)) &AtomicReq::add)
			.def("test", &AtomicReq::test, py::arg("allow_modeset") = false)
			.def("commit",
			     [](AtomicReq* self, uint32_t data, bool allow)
				{
					return self->commit((void*)(intptr_t)data, allow);
				}, py::arg("data") = 0, py::arg("allow_modeset") = false)
			.def("commit_sync", &AtomicReq::commit_sync, py::arg("allow_modeset") = false)
			;
}
<commit_msg>py: Add Card crtcs and encoders properties back to the Python bindings<commit_after>#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <kms++/kms++.h>

namespace py = pybind11;

using namespace kms;
using namespace std;

void init_pykmsbase(py::module &m)
{
	py::class_<Card>(m, "Card")
			.def(py::init<>())
			.def_property_readonly("fd", &Card::fd)
			.def_property_readonly("get_first_connected_connector", &Card::get_first_connected_connector)

			// XXX pybind11 can't handle vector<T*> where T is non-copyable, and complains:
			// RuntimeError: return_value_policy = move, but the object is neither movable nor copyable!
			// So we do this manually.
			.def_property_readonly("connectors", [](Card* self) {
				vector<unique_ptr<Connector, py::nodelete>> v;
				for (Connector* p : self->get_connectors())
					v.push_back(unique_ptr<Connector, py::nodelete>(p));
				return v;
			})

			.def_property_readonly("crtcs", [](Card* self) {
				vector<unique_ptr<Crtc, py::nodelete>> v;
				for (Crtc* p : self->get_crtcs())
					v.push_back(unique_ptr<Crtc, py::nodelete>(p));
				return v;
			})

			.def_property_readonly("encoders", [](Card* self) {
				vector<unique_ptr<Encoder, py::nodelete>> v;
				for (Encoder* p : self->get_encoders())
					v.push_back(unique_ptr<Encoder, py::nodelete>(p));
				return v;
			})

			.def_property_readonly("planes", [](Card* self) {
				vector<unique_ptr<Plane, py::nodelete>> v;
				for (Plane* p : self->get_planes())
					v.push_back(unique_ptr<Plane, py::nodelete>(p));
				return v;
			})

			.def_property_readonly("has_atomic", &Card::has_atomic)
			.def("get_prop", (Property* (Card::*)(uint32_t) const)&Card::get_prop)
			;

	py::class_<DrmObject, unique_ptr<DrmObject, py::nodelete>>(m, "DrmObject")
			.def_property_readonly("id", &DrmObject::id)
			.def_property_readonly("idx", &DrmObject::idx)
			.def_property_readonly("card", &DrmObject::card)
			;

	py::class_<DrmPropObject, DrmObject, unique_ptr<DrmPropObject, py::nodelete>>(m, "DrmPropObject")
			.def("refresh_props", &DrmPropObject::refresh_props)
			.def_property_readonly("prop_map", &DrmPropObject::get_prop_map)
			.def("get_prop_value", (uint64_t (DrmPropObject::*)(const string&) const)&DrmPropObject::get_prop_value)
			.def("set_prop_value",(int (DrmPropObject::*)(const string&, uint64_t)) &DrmPropObject::set_prop_value)
			.def("get_prop_value_as_blob", &DrmPropObject::get_prop_value_as_blob)
			.def("get_prop", &DrmPropObject::get_prop)
			;

	py::class_<Connector, DrmPropObject, unique_ptr<Connector, py::nodelete>>(m, "Connector")
			.def_property_readonly("fullname", &Connector::fullname)
			.def("get_default_mode", &Connector::get_default_mode)
			.def("get_current_crtc", &Connector::get_current_crtc)
			.def("get_possible_crtcs", [](Connector* self) {
				vector<unique_ptr<Crtc, py::nodelete>> v;
				for (Crtc* p : self->get_possible_crtcs())
					v.push_back(unique_ptr<Crtc, py::nodelete>(p));
				return v;
			})
			.def("get_modes", &Connector::get_modes)
			.def("get_mode", (Videomode (Connector::*)(const string& mode) const)&Connector::get_mode)
			.def("get_mode", (Videomode (Connector::*)(unsigned xres, unsigned yres, float refresh, bool ilace) const)&Connector::get_mode)
			.def("connected", &Connector::connected)
			.def("__repr__", [](const Connector& o) { return "<pykms.Connector " + to_string(o.id()) + ">"; })
			.def("refresh", &Connector::refresh)
			;

	py::class_<Crtc, DrmPropObject, unique_ptr<Crtc, py::nodelete>>(m, "Crtc")
			.def("set_mode", (int (Crtc::*)(Connector*, const Videomode&))&Crtc::set_mode)
			.def("set_mode", (int (Crtc::*)(Connector*, Framebuffer&, const Videomode&))&Crtc::set_mode)
			.def("disable_mode", &Crtc::disable_mode)
			.def("page_flip",
			     [](Crtc* self, Framebuffer& fb, uint32_t data)
				{
					self->page_flip(fb, (void*)(intptr_t)data);
				}, py::arg("fb"), py::arg("data") = 0)
			.def("set_plane", &Crtc::set_plane)
			.def_property_readonly("possible_planes", &Crtc::get_possible_planes)
			.def_property_readonly("primary_plane", &Crtc::get_primary_plane)
			.def_property_readonly("mode", &Crtc::mode)
			.def_property_readonly("mode_valid", &Crtc::mode_valid)
			.def("__repr__", [](const Crtc& o) { return "<pykms.Crtc " + to_string(o.id()) + ">"; })
			.def("refresh", &Crtc::refresh)
			;

	py::class_<Encoder, DrmPropObject, unique_ptr<Encoder, py::nodelete>>(m, "Encoder")
			.def("refresh", &Encoder::refresh)
			;

	py::class_<Plane, DrmPropObject, unique_ptr<Plane, py::nodelete>>(m, "Plane")
			.def("supports_crtc", &Plane::supports_crtc)
			.def_property_readonly("formats", &Plane::get_formats)
			.def_property_readonly("plane_type", &Plane::plane_type)
			.def("__repr__", [](const Plane& o) { return "<pykms.Plane " + to_string(o.id()) + ">"; })
			;

	py::enum_<PlaneType>(m, "PlaneType")
			.value("Overlay", PlaneType::Overlay)
			.value("Primary", PlaneType::Primary)
			.value("Cursor", PlaneType::Cursor)
			;

	py::class_<Property, DrmObject, unique_ptr<Property, py::nodelete>>(m, "Property")
			.def_property_readonly("name", &Property::name)
			.def_property_readonly("enums", &Property::get_enums)
			;

	py::class_<Blob>(m, "Blob")
			.def("__init__", [](Blob& instance, Card& card, py::buffer buf) {
					py::buffer_info info = buf.request();
					if (info.ndim != 1)
						throw std::runtime_error("Incompatible buffer dimension!");

					new (&instance) Blob(card, info.ptr, info.size * info.itemsize);
				},
				py::keep_alive<1, 3>())	// Keep Card alive until this is destructed

			.def_property_readonly("data", &Blob::data)

			// XXX pybind11 doesn't support a base object (DrmObject) with custom holder-type,
			// and a subclass with standard holder-type.
			// So we just copy the DrmObject members here.
			// Note that this means that python thinks we don't derive from DrmObject
			.def_property_readonly("id", &DrmObject::id)
			.def_property_readonly("idx", &DrmObject::idx)
			.def_property_readonly("card", &DrmObject::card)
			;

	py::class_<Framebuffer>(m, "Framebuffer")
			.def_property_readonly("width", &Framebuffer::width)
			.def_property_readonly("height", &Framebuffer::height)

			// XXX pybind11 doesn't support a base object (DrmObject) with custom holder-type,
			// and a subclass with standard holder-type.
			// So we just copy the DrmObject members here.
			// Note that this means that python thinks we don't derive from DrmObject
			.def_property_readonly("id", &DrmObject::id)
			.def_property_readonly("idx", &DrmObject::idx)
			.def_property_readonly("card", &DrmObject::card)
			;

	py::class_<DumbFramebuffer, Framebuffer>(m, "DumbFramebuffer")
			.def(py::init<Card&, uint32_t, uint32_t, const string&>(),
			     py::keep_alive<1, 2>())	// Keep Card alive until this is destructed
			.def(py::init<Card&, uint32_t, uint32_t, PixelFormat>(),
			     py::keep_alive<1, 2>())	// Keep Card alive until this is destructed
			.def_property_readonly("format", &DumbFramebuffer::format)
			.def_property_readonly("num_planes", &DumbFramebuffer::num_planes)
			.def("fd", &DumbFramebuffer::prime_fd)
			.def("stride", &DumbFramebuffer::stride)
			.def("offset", &DumbFramebuffer::offset)
			;

	py::class_<ExtFramebuffer, Framebuffer>(m, "ExtFramebuffer")
			.def(py::init<Card&, uint32_t, uint32_t, PixelFormat, vector<int>, vector<uint32_t>, vector<uint32_t>>(),
			     py::keep_alive<1, 2>())	// Keep Card alive until this is destructed
			;

	py::enum_<PixelFormat>(m, "PixelFormat")
			.value("Undefined", PixelFormat::Undefined)

			.value("NV12", PixelFormat::NV12)
			.value("NV21", PixelFormat::NV21)

			.value("UYVY", PixelFormat::UYVY)
			.value("YUYV", PixelFormat::YUYV)
			.value("YVYU", PixelFormat::YVYU)
			.value("VYUY", PixelFormat::VYUY)

			.value("XRGB8888", PixelFormat::XRGB8888)
			.value("XBGR8888", PixelFormat::XBGR8888)
			.value("ARGB8888", PixelFormat::ARGB8888)
			.value("ABGR8888", PixelFormat::ABGR8888)

			.value("RGB888", PixelFormat::RGB888)
			.value("BGR888", PixelFormat::BGR888)

			.value("RGB565", PixelFormat::RGB565)
			.value("BGR565", PixelFormat::BGR565)
			;

	py::enum_<SyncPolarity>(m, "SyncPolarity")
			.value("Undefined", SyncPolarity::Undefined)
			.value("Positive", SyncPolarity::Positive)
			.value("Negative", SyncPolarity::Negative)
			;

	py::class_<Videomode>(m, "Videomode")
			.def(py::init<>())

			.def_readwrite("name", &Videomode::name)

			.def_readwrite("clock", &Videomode::clock)

			.def_readwrite("hdisplay", &Videomode::hdisplay)
			.def_readwrite("hsync_start", &Videomode::hsync_start)
			.def_readwrite("hsync_end", &Videomode::hsync_end)
			.def_readwrite("htotal", &Videomode::htotal)

			.def_readwrite("vdisplay", &Videomode::vdisplay)
			.def_readwrite("vsync_start", &Videomode::vsync_start)
			.def_readwrite("vsync_end", &Videomode::vsync_end)
			.def_readwrite("vtotal", &Videomode::vtotal)

			.def_readwrite("vrefresh", &Videomode::vrefresh)

			.def_readwrite("flags", &Videomode::flags)
			.def_readwrite("type", &Videomode::type)

			.def("__repr__", [](const Videomode& vm) { return "<pykms.Videomode " + to_string(vm.hdisplay) + "x" + to_string(vm.vdisplay) + ">"; })

			.def("to_blob", &Videomode::to_blob)

			.def_property("hsync", &Videomode::hsync, &Videomode::set_hsync)
			.def_property("vsync", &Videomode::vsync, &Videomode::set_vsync)
			;

	m.def("videomode_from_timings", &videomode_from_timings);

	py::class_<AtomicReq>(m, "AtomicReq")
			.def(py::init<Card&>(),
			     py::keep_alive<1, 2>())	// Keep Card alive until this is destructed
			.def("add", (void (AtomicReq::*)(DrmPropObject*, const string&, uint64_t)) &AtomicReq::add)
			.def("add", (void (AtomicReq::*)(DrmPropObject*, const map<string, uint64_t>&)) &AtomicReq::add)
			.def("test", &AtomicReq::test, py::arg("allow_modeset") = false)
			.def("commit",
			     [](AtomicReq* self, uint32_t data, bool allow)
				{
					return self->commit((void*)(intptr_t)data, allow);
				}, py::arg("data") = 0, py::arg("allow_modeset") = false)
			.def("commit_sync", &AtomicReq::commit_sync, py::arg("allow_modeset") = false)
			;
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2016-17, Universidad de Almeria
 *  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 Willow Garage, Inc. 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.
 */

/*Beginning of Auto generated code by Atmel studio */
#include <Arduino.h>
/*End of auto generated code by Atmel studio */

#include "arduinodaq_declarations.h"

#include "mod_dac_max5500.h"

// Originally designed for atmega328P.
// --------------------------------------

#include <Wire.h>
#include <SPI.h>

//Beginning of Auto generated function prototypes by Atmel Studio
//End of Auto generated function prototypes by Atmel Studio

// Fixed pins configuration for this hardware:
#include "config.h"

void flash_led(int ntimes, int nms)
{
	pinMode(PIN_LED,OUTPUT);
	for (int i=0;i<ntimes;i++)
	{
		digitalWrite(PIN_LED, HIGH); delay(nms);
		digitalWrite(PIN_LED, LOW); delay(nms);
	}
}

static void send_simple_opcode_frame(const uint8_t op)
{
	const uint8_t rx[] = { FRAME_START_FLAG, op, 0x00, 0x00, FRAME_END_FLAG };
	Serial.write(rx,sizeof(rx));
}

void process_command(const uint8_t opcode, const uint8_t datalen, const uint8_t*data)
{
	switch (opcode)
	{
	case OP_SET_DAC:
	{
		if (datalen!=sizeof(TFrameCMD_SetDAC_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		// Init upon first usage:
		static bool dac_init = false;
		if (!dac_init)
		{
			mod_dac_max5500_init();
			dac_init = true;
		}
		const uint8_t dac_idx = data[0];
		const uint16_t dac_value = (uint16_t(data[1]) << 8)  | data[2];
		mod_dac_max5500_update_single_DAC(dac_idx,dac_value);

		// send answer back:
		send_simple_opcode_frame(RESP_SET_DAC);
	}
	break;
	case OP_SET_GPIO:
	{
		if (datalen!=sizeof(TFrameCMD_GPIO_output_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		const uint8_t pin_no = data[0];
		const uint8_t pin_val = data[1];
		pinMode(pin_no, OUTPUT);
		digitalWrite(pin_no, pin_val);

		// send answer back:
		send_simple_opcode_frame(RESP_SET_GPIO);
	}
	break;
	case OP_GET_GPIO:
	{
		if (datalen!=sizeof(TFrameCMD_GPIO_read_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		const uint8_t pin_no = data[0];
		pinMode(pin_no, INPUT);
		const uint8_t val = digitalRead(pin_no);

		// send answer back:
		const uint8_t rx[] = { FRAME_START_FLAG, RESP_GET_GPIO, 0x01, pin_no, val, 0x00 +pin_no+ val/*checksum*/, FRAME_END_FLAG };
		Serial.write(rx,sizeof(rx));
	}
	break;

	case OP_START_CONT_ADC:
	{
		if (datalen!=sizeof(TFrameCMD_ADC_start_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		TFrameCMD_ADC_start_payload_t adc_req;
		memcpy(&adc_req,data, sizeof(adc_req));

		// Setup vars for ADC task:
		num_active_ADC_channels = 0;
		for (int i=0;i<8;i++) {
			ADC_active_channels[i] = 0;
			if (adc_req.active_channels[i]>=0) {
				ADC_active_channels[i] = adc_req.active_channels[i];
				num_active_ADC_channels++;
			}
		}
		ADC_sampling_period_ms = adc_req.measure_period_ms;

		// Enable ADC with internal/default reference:
		analogReference( adc_req.use_internal_refvolt ? INTERNAL : DEFAULT );

		// send answer back:
		send_simple_opcode_frame(RESP_START_CONT_ADC);
	}
	break;

	case OP_STOP_CONT_ADC:
	{
		if (datalen!=sizeof(TFrameCMD_ADC_stop_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		num_active_ADC_channels = 0;

		// send answer back:
		send_simple_opcode_frame(RESP_STOP_CONT_ADC);
	}
	break;

	case OP_SET_PWM:
	{
		if (datalen!=sizeof(TFrameCMD_SET_PWM_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		TFrameCMD_SET_PWM_payload_t pwm_req;
		memcpy(&pwm_req,data, sizeof(pwm_req));

		pinMode(pwm_req.pin_index, OUTPUT);
		analogWrite(pwm_req.pin_index, pwm_req.analog_value);

		// send answer back:
		send_simple_opcode_frame(RESP_SET_PWM);
	}
	break;

	case OP_START_ENCODERS:
	{
		if (datalen!=sizeof(TFrameCMD_ENCODERS_start_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		TFrameCMD_ENCODERS_start_payload_t enc_req;
		memcpy(&enc_req,data, sizeof(enc_req));

		init_encoders(enc_req);

		// send answer back:
		send_simple_opcode_frame(RESP_START_ENCODERS);
	}
	break;

	case OP_STOP_ENCODERS:
	{
		TFrameCMD_ENCODERS_start_payload_t cmd_empty;
		init_encoders(cmd_empty);

		// send answer back:
		send_simple_opcode_frame(RESP_STOP_ENCODERS);
	}
	break;

	default:
	{
		// Error:
		send_simple_opcode_frame(RESP_UNKNOWN_OPCODE);
	}
	break;
	};
}
<commit_msg>Propuesta para el cambio de la frecuencia del PWM<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2016-17, Universidad de Almeria
 *  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 Willow Garage, Inc. 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.
 */

/*Beginning of Auto generated code by Atmel studio */
#include <Arduino.h>
/*End of auto generated code by Atmel studio */

#include "arduinodaq_declarations.h"

#include "mod_dac_max5500.h"

// Originally designed for atmega328P.
// --------------------------------------

#include <Wire.h>
#include <SPI.h>

//Beginning of Auto generated function prototypes by Atmel Studio
//End of Auto generated function prototypes by Atmel Studio

// Fixed pins configuration for this hardware:
#include "config.h"

/*
void setPwmFrequency(int pin, int divisor) {
	byte mode;
	if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
		switch(divisor) {
			case 1: mode = 0x01; break;
			case 8: mode = 0x02; break;
			case 64: mode = 0x03; break;
			case 256: mode = 0x04; break;
			case 1024: mode = 0x05; break;
			default: return;
		}
		if(pin == 5 || pin == 6) {
			TCCR0B = TCCR0B & 0b11111000 | mode;
			} else {
			TCCR1B = TCCR1B & 0b11111000 | mode;
		}
		} else if(pin == 3 || pin == 11) {
		switch(divisor) {
			case 1: mode = 0x01; break;
			case 8: mode = 0x02; break;
			case 32: mode = 0x03; break;
			case 64: mode = 0x04; break;
			case 128: mode = 0x05; break;
			case 256: mode = 0x06; break;
			case 1024: mode = 0x07; break;
			default: return;
		}
		TCCR2B = TCCR2B & 0b11111000 | mode;
	}
}
*/

void flash_led(int ntimes, int nms)
{
	pinMode(PIN_LED,OUTPUT);
	for (int i=0;i<ntimes;i++)
	{
		digitalWrite(PIN_LED, HIGH); delay(nms);
		digitalWrite(PIN_LED, LOW); delay(nms);
	}
}

static void send_simple_opcode_frame(const uint8_t op)
{
	const uint8_t rx[] = { FRAME_START_FLAG, op, 0x00, 0x00, FRAME_END_FLAG };
	Serial.write(rx,sizeof(rx));
}

void process_command(const uint8_t opcode, const uint8_t datalen, const uint8_t*data)
{
	switch (opcode)
	{
	case OP_SET_DAC:
	{
		if (datalen!=sizeof(TFrameCMD_SetDAC_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		// Init upon first usage:
		static bool dac_init = false;
		if (!dac_init)
		{
			mod_dac_max5500_init();
			dac_init = true;
		}
		const uint8_t dac_idx = data[0];
		const uint16_t dac_value = (uint16_t(data[1]) << 8)  | data[2];
		mod_dac_max5500_update_single_DAC(dac_idx,dac_value);

		// send answer back:
		send_simple_opcode_frame(RESP_SET_DAC);
	}
	break;
	case OP_SET_GPIO:
	{
		if (datalen!=sizeof(TFrameCMD_GPIO_output_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		const uint8_t pin_no = data[0];
		const uint8_t pin_val = data[1];
		pinMode(pin_no, OUTPUT);
		digitalWrite(pin_no, pin_val);

		// send answer back:
		send_simple_opcode_frame(RESP_SET_GPIO);
	}
	break;
	case OP_GET_GPIO:
	{
		if (datalen!=sizeof(TFrameCMD_GPIO_read_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		const uint8_t pin_no = data[0];
		pinMode(pin_no, INPUT);
		const uint8_t val = digitalRead(pin_no);

		// send answer back:
		const uint8_t rx[] = { FRAME_START_FLAG, RESP_GET_GPIO, 0x01, pin_no, val, 0x00 +pin_no+ val/*checksum*/, FRAME_END_FLAG };
		Serial.write(rx,sizeof(rx));
	}
	break;

	case OP_START_CONT_ADC:
	{
		if (datalen!=sizeof(TFrameCMD_ADC_start_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		TFrameCMD_ADC_start_payload_t adc_req;
		memcpy(&adc_req,data, sizeof(adc_req));

		// Setup vars for ADC task:
		num_active_ADC_channels = 0;
		for (int i=0;i<8;i++) {
			ADC_active_channels[i] = 0;
			if (adc_req.active_channels[i]>=0) {
				ADC_active_channels[i] = adc_req.active_channels[i];
				num_active_ADC_channels++;
			}
		}
		ADC_sampling_period_ms = adc_req.measure_period_ms;

		// Enable ADC with internal/default reference:
		analogReference( adc_req.use_internal_refvolt ? INTERNAL : DEFAULT );

		// send answer back:
		send_simple_opcode_frame(RESP_START_CONT_ADC);
	}
	break;

	case OP_STOP_CONT_ADC:
	{
		if (datalen!=sizeof(TFrameCMD_ADC_stop_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		num_active_ADC_channels = 0;

		// send answer back:
		send_simple_opcode_frame(RESP_STOP_CONT_ADC);
	}
	break;

	case OP_SET_PWM:
	{
		if (datalen!=sizeof(TFrameCMD_SET_PWM_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		TFrameCMD_SET_PWM_payload_t pwm_req;
		memcpy(&pwm_req,data, sizeof(pwm_req));

		/*setPwmFrequency(pwm_req.pin_index, 1); // Cambia la frecuencia del PWM a 31.25kHz*/
		pinMode(pwm_req.pin_index, OUTPUT);
		analogWrite(pwm_req.pin_index, pwm_req.analog_value);

		// send answer back:
		send_simple_opcode_frame(RESP_SET_PWM);
	}
	break;

	case OP_START_ENCODERS:
	{
		if (datalen!=sizeof(TFrameCMD_ENCODERS_start_payload_t)) return send_simple_opcode_frame(RESP_WRONG_LEN);

		TFrameCMD_ENCODERS_start_payload_t enc_req;
		memcpy(&enc_req,data, sizeof(enc_req));

		init_encoders(enc_req);

		// send answer back:
		send_simple_opcode_frame(RESP_START_ENCODERS);
	}
	break;

	case OP_STOP_ENCODERS:
	{
		TFrameCMD_ENCODERS_start_payload_t cmd_empty;
		init_encoders(cmd_empty);

		// send answer back:
		send_simple_opcode_frame(RESP_STOP_ENCODERS);
	}
	break;

	default:
	{
		// Error:
		send_simple_opcode_frame(RESP_UNKNOWN_OPCODE);
	}
	break;
	};
}
<|endoftext|>


<commit_before>#include "StableHeaders.hpp"
#include "SHA256.hpp"
#include "RIPEMD160.hpp"
#include "BigInt.hpp"

#ifdef _DEBUG
#  define INTEGRITY_ERROR { assert(false); return false; }
#else
#  define INTEGRITY_ERROR { return false; }
#endif

static bool doSHA256Checks() {
  SHA256 hasher;

  // empty test
  hasher.hash(std::string(""));
  if (hasher.toString() != "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") INTEGRITY_ERROR;

  // 1 char test
  hasher.hash(std::string("a"));
  if (hasher.toString() != "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb") INTEGRITY_ERROR;

  // 1 chunk, < 448 bits
  hasher.hash(std::string("The quick brown fox jumps over the lazy dog."));
  if (hasher.toString() != "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c") INTEGRITY_ERROR;

  // 2 chunk, > 448 bits
  hasher.hash(std::string("Pneumonoultramicroscopicsilicovolcanoconiosis"));
  if (hasher.toString() != "0984363991e13bb6c2c6a9442d2ae50ec3b86843131fc02889f4ee2d1c8ca65c") INTEGRITY_ERROR;

  // 2 chunk
  hasher.hash(std::string("Pneumonoultramicroscopicsilicovolcanoconiosis is a really, really, really long word."));
  if (hasher.toString() != "15064c79fd7d70624a804acc001c0fb4529d2907f82e1af2f231b4832a93a573") INTEGRITY_ERROR;

  return true;
}

static bool doRIPEMD160Checks() {
  RIPEMD160 hasher;

  hasher.hash(std::string(""));
  if (hasher.toString() != "9c1185a5c5e9fc54612808977ee8f548b2258d31") INTEGRITY_ERROR;

  hasher.hash(std::string("a"));
  if (hasher.toString() != "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe") INTEGRITY_ERROR;

  hasher.hash(std::string("abc"));
  if (hasher.toString() != "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc") INTEGRITY_ERROR;

  hasher.hash(std::string("message digest"));
  if (hasher.toString() != "5d0689ef49d2fae572b881b123a85ffa21595f36") INTEGRITY_ERROR;

  hasher.hash(std::string("abcdefghijklmnopqrstuvwxyz"));
  if (hasher.toString() != "f71c27109c692c1b56bbdceb5b9d2865b3708dbc") INTEGRITY_ERROR;

  hasher.hash(std::string("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"));
  if (hasher.toString() != "12a053384a9c0c88e405a06c27dcf49ada62eb2b") INTEGRITY_ERROR;

  hasher.hash(std::string("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));
  if (hasher.toString() != "b0e20b6e3116640286ed3a87a5713079b21f5189") INTEGRITY_ERROR;

hasher.hash(std::string("12345678901234567890123456789012345678901234567890123456789012345678901234567890"));
  if (hasher.toString() != "9b752e45573d4b39f4dbd3323cab82bf63326bfb") INTEGRITY_ERROR;

  return true;
}

static bool doBigIntChecks() {
  BigInt a = 0;
  BigInt b = 0;
  BigInt c = 0;

  a = 0;
  b = 0;
  c = a + b;
  if (c.str() != "0") INTEGRITY_ERROR;

  a = 1;
  b = 2;
  c = a + b;
  if (c.str() != "3") INTEGRITY_ERROR;

  a = 0xFFFFFFFF;
  b = 0xFFFFFFFF;
  c = a + b;
  if (c.str() != "1fffffffe") INTEGRITY_ERROR;

  a = "";
  if (a.str() != "0") INTEGRITY_ERROR;
  a = "1";
  if (a.str() != "1") INTEGRITY_ERROR;
  a = "+1";
  if (a.str() != "1") INTEGRITY_ERROR;
  a = "-1";
  if (a.str() != "-1") INTEGRITY_ERROR;
  a = "-123";
  if (a.str() != "-123") INTEGRITY_ERROR;
  a = "123";
  if (a.str() != "123") INTEGRITY_ERROR;
  a = "1fffffffe";
  if (a.str() != "1fffffffe") INTEGRITY_ERROR;
  a = "-1fffffffe";
  if (a.str() != "-1fffffffe") INTEGRITY_ERROR;
  // secp256k1 constants
  a = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f";
  if (a.str() != "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f") INTEGRITY_ERROR;
  a = "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";
  if (a.str() != "479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8") INTEGRITY_ERROR;

  a = 123;
  b = -345;
  c = -222;
  if ((a + b) != c) INTEGRITY_ERROR;
  a = -123;
  b = 345;
  c = 222;
  if ((a + b) != c) INTEGRITY_ERROR;
  a = -123;
  b = -345;
  c = -468;
  if ((a + b) != c) INTEGRITY_ERROR;

  a = 123;
  b = -345;
  c = 468;
  if ((a - b) != c) INTEGRITY_ERROR;
  a = -123;
  b = 345;
  c = -468;
  if ((a - b) != c) INTEGRITY_ERROR;
  a = 123;
  b = 345;
  c = -222;
  if ((a - b) != c) INTEGRITY_ERROR;
  a = -123;
  b = -345;
  c = 222;
  if ((a - b) != c) INTEGRITY_ERROR;

  a = 16;
  b = 16;
  c = 256;
  if ((a * b) != c) INTEGRITY_ERROR;

  a = "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";
  c = "0x1407d8be78249cd888f879013ad89d61b056e492ef173394d08a50a202635bc21ec11e40557bb9e35f5a9a0849c78ee8badaef6f710f44dda54e03094e29715c1a67053cad5f3bd952bccfafce1e187df36ad35d1c70fcd7df6a337b6772d2bfd9c372d1541278bdcbe4f80e3d9e8b333f432bee128fd65b7c0ac2a7cc17c14440";
  if ((a * a) != c) INTEGRITY_ERROR;

  return true;
}

static bool doIntegrityChecks() {
  if (!doSHA256Checks()) {
    std::cerr << "The SHA256 hash algorithm is not working correctly!\n";
    return false;
  }

  if (!doRIPEMD160Checks()) {
    std::cerr << "The RIPEMD160 hash algorithm is not working correctly!\n";
    return false;
  }

  if (!doBigIntChecks()) {
    std::cerr << "The big integer implementation is not working correctly\n";
    return false;
  }

  return true;
}

int main(int argc, char* argv) {
  if (!doIntegrityChecks()) {
    return 1;
  }

  return 0;
}
<commit_msg>remove 0x prefix<commit_after>#include "StableHeaders.hpp"
#include "SHA256.hpp"
#include "RIPEMD160.hpp"
#include "BigInt.hpp"

#ifdef _DEBUG
#  define INTEGRITY_ERROR { assert(false); return false; }
#else
#  define INTEGRITY_ERROR { return false; }
#endif

static bool doSHA256Checks() {
  SHA256 hasher;

  // empty test
  hasher.hash(std::string(""));
  if (hasher.toString() != "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") INTEGRITY_ERROR;

  // 1 char test
  hasher.hash(std::string("a"));
  if (hasher.toString() != "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb") INTEGRITY_ERROR;

  // 1 chunk, < 448 bits
  hasher.hash(std::string("The quick brown fox jumps over the lazy dog."));
  if (hasher.toString() != "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c") INTEGRITY_ERROR;

  // 2 chunk, > 448 bits
  hasher.hash(std::string("Pneumonoultramicroscopicsilicovolcanoconiosis"));
  if (hasher.toString() != "0984363991e13bb6c2c6a9442d2ae50ec3b86843131fc02889f4ee2d1c8ca65c") INTEGRITY_ERROR;

  // 2 chunk
  hasher.hash(std::string("Pneumonoultramicroscopicsilicovolcanoconiosis is a really, really, really long word."));
  if (hasher.toString() != "15064c79fd7d70624a804acc001c0fb4529d2907f82e1af2f231b4832a93a573") INTEGRITY_ERROR;

  return true;
}

static bool doRIPEMD160Checks() {
  RIPEMD160 hasher;

  hasher.hash(std::string(""));
  if (hasher.toString() != "9c1185a5c5e9fc54612808977ee8f548b2258d31") INTEGRITY_ERROR;

  hasher.hash(std::string("a"));
  if (hasher.toString() != "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe") INTEGRITY_ERROR;

  hasher.hash(std::string("abc"));
  if (hasher.toString() != "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc") INTEGRITY_ERROR;

  hasher.hash(std::string("message digest"));
  if (hasher.toString() != "5d0689ef49d2fae572b881b123a85ffa21595f36") INTEGRITY_ERROR;

  hasher.hash(std::string("abcdefghijklmnopqrstuvwxyz"));
  if (hasher.toString() != "f71c27109c692c1b56bbdceb5b9d2865b3708dbc") INTEGRITY_ERROR;

  hasher.hash(std::string("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"));
  if (hasher.toString() != "12a053384a9c0c88e405a06c27dcf49ada62eb2b") INTEGRITY_ERROR;

  hasher.hash(std::string("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));
  if (hasher.toString() != "b0e20b6e3116640286ed3a87a5713079b21f5189") INTEGRITY_ERROR;

hasher.hash(std::string("12345678901234567890123456789012345678901234567890123456789012345678901234567890"));
  if (hasher.toString() != "9b752e45573d4b39f4dbd3323cab82bf63326bfb") INTEGRITY_ERROR;

  return true;
}

static bool doBigIntChecks() {
  BigInt a = 0;
  BigInt b = 0;
  BigInt c = 0;

  a = 0;
  b = 0;
  c = a + b;
  if (c.str() != "0") INTEGRITY_ERROR;

  a = 1;
  b = 2;
  c = a + b;
  if (c.str() != "3") INTEGRITY_ERROR;

  a = 0xFFFFFFFF;
  b = 0xFFFFFFFF;
  c = a + b;
  if (c.str() != "1fffffffe") INTEGRITY_ERROR;

  a = "";
  if (a.str() != "0") INTEGRITY_ERROR;
  a = "1";
  if (a.str() != "1") INTEGRITY_ERROR;
  a = "+1";
  if (a.str() != "1") INTEGRITY_ERROR;
  a = "-1";
  if (a.str() != "-1") INTEGRITY_ERROR;
  a = "-123";
  if (a.str() != "-123") INTEGRITY_ERROR;
  a = "123";
  if (a.str() != "123") INTEGRITY_ERROR;
  a = "1fffffffe";
  if (a.str() != "1fffffffe") INTEGRITY_ERROR;
  a = "-1fffffffe";
  if (a.str() != "-1fffffffe") INTEGRITY_ERROR;
  // secp256k1 constants
  a = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f";
  if (a.str() != "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f") INTEGRITY_ERROR;
  a = "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";
  if (a.str() != "479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8") INTEGRITY_ERROR;

  a = 123;
  b = -345;
  c = -222;
  if ((a + b) != c) INTEGRITY_ERROR;
  a = -123;
  b = 345;
  c = 222;
  if ((a + b) != c) INTEGRITY_ERROR;
  a = -123;
  b = -345;
  c = -468;
  if ((a + b) != c) INTEGRITY_ERROR;

  a = 123;
  b = -345;
  c = 468;
  if ((a - b) != c) INTEGRITY_ERROR;
  a = -123;
  b = 345;
  c = -468;
  if ((a - b) != c) INTEGRITY_ERROR;
  a = 123;
  b = 345;
  c = -222;
  if ((a - b) != c) INTEGRITY_ERROR;
  a = -123;
  b = -345;
  c = 222;
  if ((a - b) != c) INTEGRITY_ERROR;

  a = 16;
  b = 16;
  c = 256;
  if ((a * b) != c) INTEGRITY_ERROR;

  a = "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";
  c = "1407d8be78249cd888f879013ad89d61b056e492ef173394d08a50a202635bc21ec11e40557bb9e35f5a9a0849c78ee8badaef6f710f44dda54e03094e29715c1a67053cad5f3bd952bccfafce1e187df36ad35d1c70fcd7df6a337b6772d2bfd9c372d1541278bdcbe4f80e3d9e8b333f432bee128fd65b7c0ac2a7cc17c14440";
  if ((a * a) != c) INTEGRITY_ERROR;

  return true;
}

static bool doIntegrityChecks() {
  if (!doSHA256Checks()) {
    std::cerr << "The SHA256 hash algorithm is not working correctly!\n";
    return false;
  }

  if (!doRIPEMD160Checks()) {
    std::cerr << "The RIPEMD160 hash algorithm is not working correctly!\n";
    return false;
  }

  if (!doBigIntChecks()) {
    std::cerr << "The big integer implementation is not working correctly\n";
    return false;
  }

  return true;
}

int main(int argc, char* argv) {
  if (!doIntegrityChecks()) {
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "data_mock.hpp"
#include "firmware_handler.hpp"
#include "image_mock.hpp"

#include <phosphor-logging/test/sdjournal_mock.hpp>
#include <sdbusplus/test/sdbus_mock.hpp>

#include <gtest/gtest.h>

using namespace phosphor::logging;

namespace blobs
{
using ::testing::Return;
using ::testing::StrEq;
using ::testing::StrictMock;

TEST(FirmwareHandlerBlobTest, VerifyFirmareCounts)
{
    /* Verify the firmware count must be greater than zero. */

    DataHandlerMock dataMock;
    ImageHandlerMock imageMock;
    //    StrictMock<SdJournalMock> journalMock;
    //    SwapJouralHandler(&journalMock);

    std::vector<HandlerPack> blobs = {
        {FirmwareBlobHandler::hashBlobID, &imageMock},
    };

    std::vector<DataHandlerPack> data = {
        {FirmwareBlobHandler::UpdateFlags::ipmi, nullptr},
        {FirmwareBlobHandler::UpdateFlags::lpc, &dataMock},
    };

    sdbusplus::SdBusMock sdbus_mock;
    auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock);

    //    TODO: Once we can test across log<> paths again, re-enable this test
    //    as a failure test instead of a success one. EXPECT_CALL(journalMock,
    //    journal_send_call(StrEq("PRIORITY=%d")))
    //        .WillOnce(Return(0));

    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(
        std::move(bus_mock), blobs, data);

    //    EXPECT_EQ(handler, nullptr);
    EXPECT_FALSE(handler == nullptr);
}

} // namespace blobs
<commit_msg>test: typo fix: firmware<commit_after>#include "data_mock.hpp"
#include "firmware_handler.hpp"
#include "image_mock.hpp"

#include <phosphor-logging/test/sdjournal_mock.hpp>
#include <sdbusplus/test/sdbus_mock.hpp>

#include <gtest/gtest.h>

using namespace phosphor::logging;

namespace blobs
{
using ::testing::Return;
using ::testing::StrEq;
using ::testing::StrictMock;

TEST(FirmwareHandlerBlobTest, VerifyFirmwareCounts)
{
    /* Verify the firmware count must be greater than zero. */

    DataHandlerMock dataMock;
    ImageHandlerMock imageMock;
    //    StrictMock<SdJournalMock> journalMock;
    //    SwapJouralHandler(&journalMock);

    std::vector<HandlerPack> blobs = {
        {FirmwareBlobHandler::hashBlobID, &imageMock},
    };

    std::vector<DataHandlerPack> data = {
        {FirmwareBlobHandler::UpdateFlags::ipmi, nullptr},
        {FirmwareBlobHandler::UpdateFlags::lpc, &dataMock},
    };

    sdbusplus::SdBusMock sdbus_mock;
    auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock);

    //    TODO: Once we can test across log<> paths again, re-enable this test
    //    as a failure test instead of a success one. EXPECT_CALL(journalMock,
    //    journal_send_call(StrEq("PRIORITY=%d")))
    //        .WillOnce(Return(0));

    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(
        std::move(bus_mock), blobs, data);

    //    EXPECT_EQ(handler, nullptr);
    EXPECT_FALSE(handler == nullptr);
}

} // namespace blobs
<|endoftext|>


<commit_before>#include "envoy/api/v2/cds.pb.h"
#include "envoy/api/v2/discovery.pb.h"
#include "envoy/grpc/status.h"
#include "envoy/stats/scope.h"

#include "common/config/protobuf_link_hacks.h"
#include "common/config/resources.h"
#include "common/protobuf/protobuf.h"
#include "common/protobuf/utility.h"

#include "test/common/grpc/grpc_client_integration.h"
#include "test/integration/http_integration.h"
#include "test/integration/utility.h"
#include "test/mocks/server/mocks.h"
#include "test/test_common/network_utility.h"
#include "test/test_common/simulated_time_system.h"
#include "test/test_common/utility.h"

#include "absl/synchronization/notification.h"
#include "gtest/gtest.h"

using testing::AssertionResult;

namespace Envoy {
namespace {

const char ClusterName1[] = "cluster_1";
const char ClusterName2[] = "cluster_2";
const int UpstreamIndex1 = 1;
const int UpstreamIndex2 = 2;

class CdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public HttpIntegrationTest {
public:
  CdsIntegrationTest()
      : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, ipVersion(),
                            ConfigHelper::discoveredClustersBootstrap(
                                sotwOrDelta() == Grpc::SotwOrDelta::Sotw ? "GRPC" : "DELTA_GRPC")) {
    use_lds_ = false;
    sotw_or_delta_ = sotwOrDelta();
  }

  void TearDown() override {
    if (!test_skipped_) {
      cleanUpXdsConnection();
      test_server_.reset();
      fake_upstreams_.clear();
    }
  }

  // Overridden to insert this stuff into the initialize() at the very beginning of
  // HttpIntegrationTest::testRouterHeaderOnlyRequestAndResponse().
  void initialize() override {
    use_lds_ = false;
    test_skipped_ = false;
    // Controls how many fake_upstreams_.emplace_back(new FakeUpstream) will happen in
    // BaseIntegrationTest::createUpstreams() (which is part of initialize()).
    // Make sure this number matches the size of the 'clusters' repeated field in the bootstrap
    // config that you use!
    setUpstreamCount(1);                                  // the CDS cluster
    setUpstreamProtocol(FakeHttpConnection::Type::HTTP2); // CDS uses gRPC uses HTTP2.

    // HttpIntegrationTest::initialize() does many things:
    // 1) It appends to fake_upstreams_ as many as you asked for via setUpstreamCount().
    // 2) It updates your bootstrap config with the ports your fake upstreams are actually listening
    //    on (since you're supposed to leave them as 0).
    // 3) It creates and starts an IntegrationTestServer - the thing that wraps the almost-actual
    //    Envoy used in the tests.
    // 4) Bringing up the server usually entails waiting to ensure that any listeners specified in
    //    the bootstrap config have come up, and registering them in a port map (see lookupPort()).
    //    However, this test needs to defer all of that to later.
    defer_listener_finalization_ = true;
    HttpIntegrationTest::initialize();

    // Create the regular (i.e. not an xDS server) upstreams. We create them manually here after
    // initialize() because finalize() expects all fake_upstreams_ to correspond to a static
    // cluster in the bootstrap config - which we don't want since we're testing dynamic CDS!
    fake_upstreams_.emplace_back(new FakeUpstream(0, FakeHttpConnection::Type::HTTP2, version_,
                                                  timeSystem(), enable_half_close_));
    fake_upstreams_[UpstreamIndex1]->set_allow_unexpected_disconnects(false);
    fake_upstreams_.emplace_back(new FakeUpstream(0, FakeHttpConnection::Type::HTTP2, version_,
                                                  timeSystem(), enable_half_close_));
    fake_upstreams_[UpstreamIndex2]->set_allow_unexpected_disconnects(false);
    cluster1_ = ConfigHelper::buildCluster(
        ClusterName1, fake_upstreams_[UpstreamIndex1]->localAddress()->ip()->port(),
        Network::Test::getLoopbackAddressString(ipVersion()));
    cluster2_ = ConfigHelper::buildCluster(
        ClusterName2, fake_upstreams_[UpstreamIndex2]->localAddress()->ip()->port(),
        Network::Test::getLoopbackAddressString(ipVersion()));

    // Let Envoy establish its connection to the CDS server.
    acceptXdsConnection();

    // Do the initial compareDiscoveryRequest / sendDiscoveryResponse for cluster_1.
    EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "", {}, {}, {}, true));
    sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {cluster1_},
                                                   {cluster1_}, {}, "55");

    // We can continue the test once we're sure that Envoy's ClusterManager has made use of
    // the DiscoveryResponse describing cluster_1 that we sent.
    // 2 because the statically specified CDS server itself counts as a cluster.
    test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2);

    // Wait for our statically specified listener to become ready, and register its port in the
    // test framework's downstream listener port map.
    test_server_->waitUntilListenersReady();
    registerTestServerPorts({"http"});
  }

  void acceptXdsConnection() {
    AssertionResult result = // xds_connection_ is filled with the new FakeHttpConnection.
        fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, xds_connection_);
    RELEASE_ASSERT(result, result.message());
    result = xds_connection_->waitForNewStream(*dispatcher_, xds_stream_);
    RELEASE_ASSERT(result, result.message());
    xds_stream_->startGrpcStream();
    fake_upstreams_[0]->set_allow_unexpected_disconnects(true);
  }

  envoy::api::v2::Cluster cluster1_;
  envoy::api::v2::Cluster cluster2_;
  // True if we decided not to run the test after all.
  bool test_skipped_{true};
};

INSTANTIATE_TEST_SUITE_P(IpVersionsClientTypeDelta, CdsIntegrationTest,
                         DELTA_SOTW_GRPC_CLIENT_INTEGRATION_PARAMS);

// 1) Envoy starts up with no static clusters (other than the CDS-over-gRPC server).
// 2) Envoy is told of a cluster via CDS.
// 3) We send Envoy a request, which we verify is properly proxied to and served by that cluster.
// 4) Envoy is told that cluster is gone.
// 5) We send Envoy a request, which should 503.
// 6) Envoy is told that the cluster is back.
// 7) We send Envoy a request, which we verify is properly proxied to and served by that cluster.
TEST_P(CdsIntegrationTest, CdsClusterUpDownUp) {
  // Calls our initialize(), which includes establishing a listener, route, and cluster.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");

  // Tell Envoy that cluster_1 is gone.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "55", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {}, {},
                                                 {ClusterName1}, "42");
  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse that says cluster_1 is gone.
  test_server_->waitForCounterGe("cluster_manager.cluster_removed", 1);

  // Now that cluster_1 is gone, the listener (with its routing to cluster_1) should 503.
  BufferingStreamDecoderPtr response = IntegrationUtil::makeSingleRequest(
      lookupPort("http"), "GET", "/cluster1", "", downstream_protocol_, version_, "foo.com");
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("503", response->headers().Status()->value().getStringView());

  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Tell Envoy that cluster_1 is back.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "42", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {cluster1_},
                                                 {cluster1_}, {}, "413");

  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse describing cluster_1 that we sent. Again, 2 includes CDS server.
  test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2);

  // Does *not* call our initialize().
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");

  cleanupUpstreamAndDownstream();
}

// Tests adding a cluster, adding another, then removing the first.
TEST_P(CdsIntegrationTest, TwoClusters) {
  // Calls our initialize(), which includes establishing a listener, route, and cluster.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");

  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Tell Envoy that cluster_2 is here.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "55", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster,
                                                 {cluster1_, cluster2_}, {cluster2_}, {}, "42");
  // The '3' includes the fake CDS server.
  test_server_->waitForGaugeGe("cluster_manager.active_clusters", 3);

  // A request for cluster_2 should be fine.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex2, "/cluster2");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Tell Envoy that cluster_1 is gone.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "42", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {cluster2_}, {},
                                                 {ClusterName1}, "42");
  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse that says cluster_1 is gone.
  test_server_->waitForCounterGe("cluster_manager.cluster_removed", 1);

  // Even with cluster_1 gone, a request for cluster_2 should be fine.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex2, "/cluster2");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Tell Envoy that cluster_1 is back.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "42", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster,
                                                 {cluster1_, cluster2_}, {cluster1_}, {}, "413");

  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse describing cluster_1 that we sent. Again, 3 includes CDS server.
  test_server_->waitForGaugeGe("cluster_manager.active_clusters", 3);

  // Does *not* call our initialize().
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");

  cleanupUpstreamAndDownstream();
}

// Tests that when Envoy's delta xDS stream dis/reconnects, Envoy can inform the server of the
// resources it already has: the reconnected stream need not start with a state-of-the-world update.
TEST_P(CdsIntegrationTest, VersionsRememberedAfterReconnect) {
  SKIP_IF_XDS_IS(Grpc::SotwOrDelta::Sotw);

  // Calls our initialize(), which includes establishing a listener, route, and cluster.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Close the connection carrying Envoy's xDS gRPC stream...
  AssertionResult result = xds_connection_->close();
  RELEASE_ASSERT(result, result.message());
  result = xds_connection_->waitForDisconnect();
  RELEASE_ASSERT(result, result.message());
  xds_connection_.reset();
  // ...and reconnect it.
  acceptXdsConnection();

  // Upon reconnecting, the Envoy should tell us its current resource versions.
  envoy::api::v2::DeltaDiscoveryRequest request;
  result = xds_stream_->waitForGrpcMessage(*dispatcher_, request);
  RELEASE_ASSERT(result, result.message());
  const auto& initial_resource_versions = request.initial_resource_versions();
  EXPECT_EQ("55", initial_resource_versions.at(std::string(ClusterName1)));
  EXPECT_EQ(1, initial_resource_versions.size());

  // Tell Envoy that cluster_2 is here. This update does *not* need to include cluster_1,
  // which Envoy should already know about despite the disconnect.
  sendDeltaDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {cluster2_},
                                                      {}, "42");
  // The '3' includes the fake CDS server.
  test_server_->waitForGaugeGe("cluster_manager.active_clusters", 3);

  // A request for cluster_1 should be fine.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();
  // A request for cluster_2 should be fine.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex2, "/cluster2");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();
}

} // namespace
} // namespace Envoy
<commit_msg>config: regression test for wrong xDS gRPC method descriptor (#8945)<commit_after>#include "envoy/api/v2/cds.pb.h"
#include "envoy/api/v2/discovery.pb.h"
#include "envoy/grpc/status.h"
#include "envoy/stats/scope.h"

#include "common/config/protobuf_link_hacks.h"
#include "common/config/resources.h"
#include "common/protobuf/protobuf.h"
#include "common/protobuf/utility.h"

#include "test/common/grpc/grpc_client_integration.h"
#include "test/integration/http_integration.h"
#include "test/integration/utility.h"
#include "test/mocks/server/mocks.h"
#include "test/test_common/network_utility.h"
#include "test/test_common/simulated_time_system.h"
#include "test/test_common/utility.h"

#include "absl/synchronization/notification.h"
#include "gtest/gtest.h"

using testing::AssertionResult;

namespace Envoy {
namespace {

const char ClusterName1[] = "cluster_1";
const char ClusterName2[] = "cluster_2";
const int UpstreamIndex1 = 1;
const int UpstreamIndex2 = 2;

class CdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public HttpIntegrationTest {
public:
  CdsIntegrationTest()
      : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, ipVersion(),
                            ConfigHelper::discoveredClustersBootstrap(
                                sotwOrDelta() == Grpc::SotwOrDelta::Sotw ? "GRPC" : "DELTA_GRPC")) {
    use_lds_ = false;
    sotw_or_delta_ = sotwOrDelta();
  }

  void TearDown() override {
    if (!test_skipped_) {
      cleanUpXdsConnection();
      test_server_.reset();
      fake_upstreams_.clear();
    }
  }

  // Overridden to insert this stuff into the initialize() at the very beginning of
  // HttpIntegrationTest::testRouterHeaderOnlyRequestAndResponse().
  void initialize() override {
    use_lds_ = false;
    test_skipped_ = false;
    // Controls how many fake_upstreams_.emplace_back(new FakeUpstream) will happen in
    // BaseIntegrationTest::createUpstreams() (which is part of initialize()).
    // Make sure this number matches the size of the 'clusters' repeated field in the bootstrap
    // config that you use!
    setUpstreamCount(1);                                  // the CDS cluster
    setUpstreamProtocol(FakeHttpConnection::Type::HTTP2); // CDS uses gRPC uses HTTP2.

    // HttpIntegrationTest::initialize() does many things:
    // 1) It appends to fake_upstreams_ as many as you asked for via setUpstreamCount().
    // 2) It updates your bootstrap config with the ports your fake upstreams are actually listening
    //    on (since you're supposed to leave them as 0).
    // 3) It creates and starts an IntegrationTestServer - the thing that wraps the almost-actual
    //    Envoy used in the tests.
    // 4) Bringing up the server usually entails waiting to ensure that any listeners specified in
    //    the bootstrap config have come up, and registering them in a port map (see lookupPort()).
    //    However, this test needs to defer all of that to later.
    defer_listener_finalization_ = true;
    HttpIntegrationTest::initialize();

    // Create the regular (i.e. not an xDS server) upstreams. We create them manually here after
    // initialize() because finalize() expects all fake_upstreams_ to correspond to a static
    // cluster in the bootstrap config - which we don't want since we're testing dynamic CDS!
    fake_upstreams_.emplace_back(new FakeUpstream(0, FakeHttpConnection::Type::HTTP2, version_,
                                                  timeSystem(), enable_half_close_));
    fake_upstreams_[UpstreamIndex1]->set_allow_unexpected_disconnects(false);
    fake_upstreams_.emplace_back(new FakeUpstream(0, FakeHttpConnection::Type::HTTP2, version_,
                                                  timeSystem(), enable_half_close_));
    fake_upstreams_[UpstreamIndex2]->set_allow_unexpected_disconnects(false);
    cluster1_ = ConfigHelper::buildCluster(
        ClusterName1, fake_upstreams_[UpstreamIndex1]->localAddress()->ip()->port(),
        Network::Test::getLoopbackAddressString(ipVersion()));
    cluster2_ = ConfigHelper::buildCluster(
        ClusterName2, fake_upstreams_[UpstreamIndex2]->localAddress()->ip()->port(),
        Network::Test::getLoopbackAddressString(ipVersion()));

    // Let Envoy establish its connection to the CDS server.
    acceptXdsConnection();

    // Do the initial compareDiscoveryRequest / sendDiscoveryResponse for cluster_1.
    EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "", {}, {}, {}, true));
    sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {cluster1_},
                                                   {cluster1_}, {}, "55");

    // We can continue the test once we're sure that Envoy's ClusterManager has made use of
    // the DiscoveryResponse describing cluster_1 that we sent.
    // 2 because the statically specified CDS server itself counts as a cluster.
    test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2);

    // Wait for our statically specified listener to become ready, and register its port in the
    // test framework's downstream listener port map.
    test_server_->waitUntilListenersReady();
    registerTestServerPorts({"http"});
  }

  // Regression test to catch the code declaring a gRPC service method for {SotW,delta}
  // when the user's bootstrap config asks for the other type.
  void verifyGrpcServiceMethod() {
    EXPECT_TRUE(xds_stream_->waitForHeadersComplete());
    Envoy::Http::LowerCaseString path_string(":path");
    std::string expected_method(sotwOrDelta() == Grpc::SotwOrDelta::Sotw
                                    ? "/envoy.api.v2.ClusterDiscoveryService/StreamClusters"
                                    : "/envoy.api.v2.ClusterDiscoveryService/DeltaClusters");
    EXPECT_EQ(xds_stream_->headers().get(path_string)->value(), expected_method);
  }

  void acceptXdsConnection() {
    AssertionResult result = // xds_connection_ is filled with the new FakeHttpConnection.
        fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, xds_connection_);
    RELEASE_ASSERT(result, result.message());
    result = xds_connection_->waitForNewStream(*dispatcher_, xds_stream_);
    RELEASE_ASSERT(result, result.message());
    xds_stream_->startGrpcStream();
    verifyGrpcServiceMethod();
    fake_upstreams_[0]->set_allow_unexpected_disconnects(true);
  }

  envoy::api::v2::Cluster cluster1_;
  envoy::api::v2::Cluster cluster2_;
  // True if we decided not to run the test after all.
  bool test_skipped_{true};
};

INSTANTIATE_TEST_SUITE_P(IpVersionsClientTypeDelta, CdsIntegrationTest,
                         DELTA_SOTW_GRPC_CLIENT_INTEGRATION_PARAMS);

// 1) Envoy starts up with no static clusters (other than the CDS-over-gRPC server).
// 2) Envoy is told of a cluster via CDS.
// 3) We send Envoy a request, which we verify is properly proxied to and served by that cluster.
// 4) Envoy is told that cluster is gone.
// 5) We send Envoy a request, which should 503.
// 6) Envoy is told that the cluster is back.
// 7) We send Envoy a request, which we verify is properly proxied to and served by that cluster.
TEST_P(CdsIntegrationTest, CdsClusterUpDownUp) {
  // Calls our initialize(), which includes establishing a listener, route, and cluster.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");

  // Tell Envoy that cluster_1 is gone.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "55", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {}, {},
                                                 {ClusterName1}, "42");
  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse that says cluster_1 is gone.
  test_server_->waitForCounterGe("cluster_manager.cluster_removed", 1);

  // Now that cluster_1 is gone, the listener (with its routing to cluster_1) should 503.
  BufferingStreamDecoderPtr response = IntegrationUtil::makeSingleRequest(
      lookupPort("http"), "GET", "/cluster1", "", downstream_protocol_, version_, "foo.com");
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("503", response->headers().Status()->value().getStringView());

  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Tell Envoy that cluster_1 is back.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "42", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {cluster1_},
                                                 {cluster1_}, {}, "413");

  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse describing cluster_1 that we sent. Again, 2 includes CDS server.
  test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2);

  // Does *not* call our initialize().
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");

  cleanupUpstreamAndDownstream();
}

// Tests adding a cluster, adding another, then removing the first.
TEST_P(CdsIntegrationTest, TwoClusters) {
  // Calls our initialize(), which includes establishing a listener, route, and cluster.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");

  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Tell Envoy that cluster_2 is here.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "55", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster,
                                                 {cluster1_, cluster2_}, {cluster2_}, {}, "42");
  // The '3' includes the fake CDS server.
  test_server_->waitForGaugeGe("cluster_manager.active_clusters", 3);

  // A request for cluster_2 should be fine.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex2, "/cluster2");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Tell Envoy that cluster_1 is gone.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "42", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {cluster2_}, {},
                                                 {ClusterName1}, "42");
  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse that says cluster_1 is gone.
  test_server_->waitForCounterGe("cluster_manager.cluster_removed", 1);

  // Even with cluster_1 gone, a request for cluster_2 should be fine.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex2, "/cluster2");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Tell Envoy that cluster_1 is back.
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "42", {}, {}, {}));
  sendDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster,
                                                 {cluster1_, cluster2_}, {cluster1_}, {}, "413");

  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse describing cluster_1 that we sent. Again, 3 includes CDS server.
  test_server_->waitForGaugeGe("cluster_manager.active_clusters", 3);

  // Does *not* call our initialize().
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");

  cleanupUpstreamAndDownstream();
}

// Tests that when Envoy's delta xDS stream dis/reconnects, Envoy can inform the server of the
// resources it already has: the reconnected stream need not start with a state-of-the-world update.
TEST_P(CdsIntegrationTest, VersionsRememberedAfterReconnect) {
  SKIP_IF_XDS_IS(Grpc::SotwOrDelta::Sotw);

  // Calls our initialize(), which includes establishing a listener, route, and cluster.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();

  // Close the connection carrying Envoy's xDS gRPC stream...
  AssertionResult result = xds_connection_->close();
  RELEASE_ASSERT(result, result.message());
  result = xds_connection_->waitForDisconnect();
  RELEASE_ASSERT(result, result.message());
  xds_connection_.reset();
  // ...and reconnect it.
  acceptXdsConnection();

  // Upon reconnecting, the Envoy should tell us its current resource versions.
  envoy::api::v2::DeltaDiscoveryRequest request;
  result = xds_stream_->waitForGrpcMessage(*dispatcher_, request);
  RELEASE_ASSERT(result, result.message());
  const auto& initial_resource_versions = request.initial_resource_versions();
  EXPECT_EQ("55", initial_resource_versions.at(std::string(ClusterName1)));
  EXPECT_EQ(1, initial_resource_versions.size());

  // Tell Envoy that cluster_2 is here. This update does *not* need to include cluster_1,
  // which Envoy should already know about despite the disconnect.
  sendDeltaDiscoveryResponse<envoy::api::v2::Cluster>(Config::TypeUrl::get().Cluster, {cluster2_},
                                                      {}, "42");
  // The '3' includes the fake CDS server.
  test_server_->waitForGaugeGe("cluster_manager.active_clusters", 3);

  // A request for cluster_1 should be fine.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex1, "/cluster1");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();
  // A request for cluster_2 should be fine.
  testRouterHeaderOnlyRequestAndResponse(nullptr, UpstreamIndex2, "/cluster2");
  cleanupUpstreamAndDownstream();
  codec_client_->waitForDisconnect();
}

} // namespace
} // namespace Envoy
<|endoftext|>


<commit_before>/*
    Copyright (c) 2008 Tobias Koenig <tokoe@kde.org>
    Copyright (c) 2008 Bertjan Broeksema <b.broeksema@kdemail.net>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "vcarddirresource.h"

#include "settingsadaptor.h"
#include "settingsdialog.h"

#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtCore/QFile>

#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>

using namespace Akonadi;

VCardDirResource::VCardDirResource( const QString &id )
  : ResourceBase( id )
{
  // setup the resource
  new SettingsAdaptor( Settings::self() );
  QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ),
                            Settings::self(), QDBusConnection::ExportAdaptors );

  changeRecorder()->itemFetchScope().fetchFullPayload();
}

VCardDirResource::~VCardDirResource()
{
  // clear cache
  mAddressees.clear();
}

void VCardDirResource::aboutToQuit()
{
  Settings::self()->writeConfig();
}

void VCardDirResource::configure( WId windowId )
{
  SettingsDialog dlg( windowId );
  if ( dlg.exec() ) {
    clearCache();
    initializeVCardDirectory();
    loadAddressees();
  }
}

bool VCardDirResource::loadAddressees()
{
  mAddressees.clear();

  QDirIterator it( vCardDirectoryName() );
  while ( it.hasNext() ) {
    it.next();
    if ( it.fileName() != "." && it.fileName() != ".." && it.fileName() != "WARNING_README.txt" ) {
      QFile file( it.filePath() );
      file.open( QIODevice::ReadOnly );
      const QByteArray data = file.readAll();
      file.close();

      const KABC::Addressee addr = mConverter.parseVCard( data );
      if ( !addr.isEmpty() ) {
        mAddressees.insert( addr.uid(), addr );
      }
    }
  }

  emit status( Idle );

  return true;
}

bool VCardDirResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray>& )
{
  const QString remoteId = item.remoteId();
  if ( !mAddressees.contains( remoteId ) ) {
    emit error( QString( "Contact with uid '%1' not found!" ).arg( remoteId ) );
    return false;
  }

  Item newItem( item );
  newItem.setPayload<KABC::Addressee>( mAddressees.value( remoteId ) );
  itemRetrieved( newItem );

  return true;
}

void VCardDirResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection& )
{
  if ( Settings::self()->readOnly() ) {
    emit error( i18n( "Trying to write to a read-only directory: '%1'", vCardDirectoryName() ) );
    cancelTask();
    return;
  }

  KABC::Addressee addressee;
  if ( item.hasPayload<KABC::Addressee>() )
    addressee  = item.payload<KABC::Addressee>();

  if ( !addressee.isEmpty() ) {
    // add it to the cache...
    mAddressees.insert( addressee.uid(), addressee );

    // ... and write it through to the file system
    const QByteArray data = mConverter.createVCard( addressee );

    QFile file( vCardDirectoryFileName( addressee.uid() ) );
    file.open( QIODevice::WriteOnly );
    file.write( data );
    file.close();

    // report everything ok
    Item newItem( item );
    newItem.setRemoteId( addressee.uid() );
    changeCommitted( newItem );

  } else {
    changeProcessed();
  }
}

void VCardDirResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& )
{
  if ( Settings::self()->readOnly() ) {
    emit error( i18n( "Trying to write to a read-only directory: '%1'", vCardDirectoryName() ) );
    cancelTask();
    return;
  }

  KABC::Addressee addressee;
  if ( item.hasPayload<KABC::Addressee>() )
    addressee  = item.payload<KABC::Addressee>();

  if ( !addressee.isEmpty() ) {
    // change it in the cache...
    mAddressees.insert( addressee.uid(), addressee );

    // ... and write it through to the file system
    const QByteArray data = mConverter.createVCard( addressee );

    QFile file( vCardDirectoryFileName( addressee.uid() ) );
    file.open( QIODevice::WriteOnly );
    file.write( data );
    file.close();

    Item newItem( item );
    newItem.setRemoteId( addressee.uid() );
    changeCommitted( newItem );

  } else {
    changeProcessed();
  }
}

void VCardDirResource::itemRemoved( const Akonadi::Item &item )
{
  if ( Settings::self()->readOnly() ) {
    emit error( i18n( "Trying to write to a read-only directory: '%1'", vCardDirectoryName() ) );
    cancelTask();
    return;
  }

  // remove it from the cache...
  if ( mAddressees.contains( item.remoteId() ) )
    mAddressees.remove( item.remoteId() );

  // ... and remove it from the file system
  QFile::remove( vCardDirectoryFileName( item.remoteId() ) );

  changeProcessed();
}

void VCardDirResource::retrieveCollections()
{
  Collection c;
  c.setParent( Collection::root() );
  c.setRemoteId( vCardDirectoryName() );
  c.setName( name() );
  QStringList mimeTypes;
  mimeTypes << KABC::Addressee::mimeType();
  c.setContentMimeTypes( mimeTypes );
  if ( Settings::self()->readOnly() ) {
    c.setRights( Collection::CanChangeCollection );
  } else {
    Collection::Rights rights;
    rights |= Collection::CanChangeItem;
    rights |= Collection::CanCreateItem;
    rights |= Collection::CanDeleteItem;
    rights |= Collection::CanChangeCollection;
    c.setRights( rights );
  }
  Collection::List list;
  list << c;
  collectionsRetrieved( list );
}

void VCardDirResource::retrieveItems( const Akonadi::Collection& )
{
  Item::List items;

  foreach ( const KABC::Addressee &addressee, mAddressees ) {
    Item item;
    item.setRemoteId( addressee.uid() );
    item.setMimeType( KABC::Addressee::mimeType() );
    items.append( item );
  }

  itemsRetrieved( items );
}

QString VCardDirResource::vCardDirectoryName() const
{
  return Settings::self()->path().mid( 7 );
}

QString VCardDirResource::vCardDirectoryFileName( const QString &file ) const
{
  return Settings::self()->path().mid( 7 ) + QDir::separator() + file;
}

void VCardDirResource::initializeVCardDirectory() const
{
  QDir dir( vCardDirectoryName() );

  // if folder does not exists, create it
  if ( !dir.exists() )
    QDir::root().mkpath( dir.absolutePath() );

  // check whether warning file is in place...
  QFile file( dir.absolutePath() + QDir::separator() + "WARNING_README.txt" );
  if ( !file.exists() ) {
    // ... if not, create it
    file.open( QIODevice::WriteOnly );
    file.write( "Important Warning!!!\n\n"
                "Don't create or copy vCards inside this folder manually, they are managed by the Akonadi framework!\n" );
    file.close();
  }
}

AKONADI_RESOURCE_MAIN( VCardDirResource )

#include "vcarddirresource.moc"
<commit_msg>Set address book icon for resource collection<commit_after>/*
    Copyright (c) 2008 Tobias Koenig <tokoe@kde.org>
    Copyright (c) 2008 Bertjan Broeksema <b.broeksema@kdemail.net>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "vcarddirresource.h"

#include "settingsadaptor.h"
#include "settingsdialog.h"

#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtCore/QFile>

#include <akonadi/changerecorder.h>
#include <akonadi/entitydisplayattribute.h>
#include <akonadi/itemfetchscope.h>

using namespace Akonadi;

VCardDirResource::VCardDirResource( const QString &id )
  : ResourceBase( id )
{
  // setup the resource
  new SettingsAdaptor( Settings::self() );
  QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ),
                            Settings::self(), QDBusConnection::ExportAdaptors );

  changeRecorder()->itemFetchScope().fetchFullPayload();
}

VCardDirResource::~VCardDirResource()
{
  // clear cache
  mAddressees.clear();
}

void VCardDirResource::aboutToQuit()
{
  Settings::self()->writeConfig();
}

void VCardDirResource::configure( WId windowId )
{
  SettingsDialog dlg( windowId );
  if ( dlg.exec() ) {
    clearCache();
    initializeVCardDirectory();
    loadAddressees();
  }
}

bool VCardDirResource::loadAddressees()
{
  mAddressees.clear();

  QDirIterator it( vCardDirectoryName() );
  while ( it.hasNext() ) {
    it.next();
    if ( it.fileName() != "." && it.fileName() != ".." && it.fileName() != "WARNING_README.txt" ) {
      QFile file( it.filePath() );
      file.open( QIODevice::ReadOnly );
      const QByteArray data = file.readAll();
      file.close();

      const KABC::Addressee addr = mConverter.parseVCard( data );
      if ( !addr.isEmpty() ) {
        mAddressees.insert( addr.uid(), addr );
      }
    }
  }

  emit status( Idle );

  return true;
}

bool VCardDirResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray>& )
{
  const QString remoteId = item.remoteId();
  if ( !mAddressees.contains( remoteId ) ) {
    emit error( QString( "Contact with uid '%1' not found!" ).arg( remoteId ) );
    return false;
  }

  Item newItem( item );
  newItem.setPayload<KABC::Addressee>( mAddressees.value( remoteId ) );
  itemRetrieved( newItem );

  return true;
}

void VCardDirResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection& )
{
  if ( Settings::self()->readOnly() ) {
    emit error( i18n( "Trying to write to a read-only directory: '%1'", vCardDirectoryName() ) );
    cancelTask();
    return;
  }

  KABC::Addressee addressee;
  if ( item.hasPayload<KABC::Addressee>() )
    addressee  = item.payload<KABC::Addressee>();

  if ( !addressee.isEmpty() ) {
    // add it to the cache...
    mAddressees.insert( addressee.uid(), addressee );

    // ... and write it through to the file system
    const QByteArray data = mConverter.createVCard( addressee );

    QFile file( vCardDirectoryFileName( addressee.uid() ) );
    file.open( QIODevice::WriteOnly );
    file.write( data );
    file.close();

    // report everything ok
    Item newItem( item );
    newItem.setRemoteId( addressee.uid() );
    changeCommitted( newItem );

  } else {
    changeProcessed();
  }
}

void VCardDirResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& )
{
  if ( Settings::self()->readOnly() ) {
    emit error( i18n( "Trying to write to a read-only directory: '%1'", vCardDirectoryName() ) );
    cancelTask();
    return;
  }

  KABC::Addressee addressee;
  if ( item.hasPayload<KABC::Addressee>() )
    addressee  = item.payload<KABC::Addressee>();

  if ( !addressee.isEmpty() ) {
    // change it in the cache...
    mAddressees.insert( addressee.uid(), addressee );

    // ... and write it through to the file system
    const QByteArray data = mConverter.createVCard( addressee );

    QFile file( vCardDirectoryFileName( addressee.uid() ) );
    file.open( QIODevice::WriteOnly );
    file.write( data );
    file.close();

    Item newItem( item );
    newItem.setRemoteId( addressee.uid() );
    changeCommitted( newItem );

  } else {
    changeProcessed();
  }
}

void VCardDirResource::itemRemoved( const Akonadi::Item &item )
{
  if ( Settings::self()->readOnly() ) {
    emit error( i18n( "Trying to write to a read-only directory: '%1'", vCardDirectoryName() ) );
    cancelTask();
    return;
  }

  // remove it from the cache...
  if ( mAddressees.contains( item.remoteId() ) )
    mAddressees.remove( item.remoteId() );

  // ... and remove it from the file system
  QFile::remove( vCardDirectoryFileName( item.remoteId() ) );

  changeProcessed();
}

void VCardDirResource::retrieveCollections()
{
  Collection c;
  c.setParent( Collection::root() );
  c.setRemoteId( vCardDirectoryName() );
  c.setName( name() );
  QStringList mimeTypes;
  mimeTypes << KABC::Addressee::mimeType();
  c.setContentMimeTypes( mimeTypes );
  if ( Settings::self()->readOnly() ) {
    c.setRights( Collection::CanChangeCollection );
  } else {
    Collection::Rights rights;
    rights |= Collection::CanChangeItem;
    rights |= Collection::CanCreateItem;
    rights |= Collection::CanDeleteItem;
    rights |= Collection::CanChangeCollection;
    c.setRights( rights );
  }

  EntityDisplayAttribute* attr = c.attribute<EntityDisplayAttribute>( Collection::AddIfMissing );
  attr->setIconName( "x-office-address-book" );

  Collection::List list;
  list << c;
  collectionsRetrieved( list );
}

void VCardDirResource::retrieveItems( const Akonadi::Collection& )
{
  Item::List items;

  foreach ( const KABC::Addressee &addressee, mAddressees ) {
    Item item;
    item.setRemoteId( addressee.uid() );
    item.setMimeType( KABC::Addressee::mimeType() );
    items.append( item );
  }

  itemsRetrieved( items );
}

QString VCardDirResource::vCardDirectoryName() const
{
  return Settings::self()->path().mid( 7 );
}

QString VCardDirResource::vCardDirectoryFileName( const QString &file ) const
{
  return Settings::self()->path().mid( 7 ) + QDir::separator() + file;
}

void VCardDirResource::initializeVCardDirectory() const
{
  QDir dir( vCardDirectoryName() );

  // if folder does not exists, create it
  if ( !dir.exists() )
    QDir::root().mkpath( dir.absolutePath() );

  // check whether warning file is in place...
  QFile file( dir.absolutePath() + QDir::separator() + "WARNING_README.txt" );
  if ( !file.exists() ) {
    // ... if not, create it
    file.open( QIODevice::WriteOnly );
    file.write( "Important Warning!!!\n\n"
                "Don't create or copy vCards inside this folder manually, they are managed by the Akonadi framework!\n" );
    file.close();
  }
}

AKONADI_RESOURCE_MAIN( VCardDirResource )

#include "vcarddirresource.moc"
<|endoftext|>