<commit_before>#include "galaxy.h"
#include "args.h"

void Simulator::pause(int id) {
	if(pid_ != -1 && pid_ > id)
		return;
	pid_ = id;
	if(paused_)
		return;
	pause_ = true;
	std::unique_lock<std::mutex> lk(mupd_);
	while(!paused_)
		cvpd_.wait(lk);
}

void Simulator::unpause(int id) {
	if(!paused_ || pid_ != id)
		return;
	pid_ = -1;
	pause_ = false;
	cvp_.notify_one();
	std::unique_lock<std::mutex> lk(mupd_);
	while(paused_)
		cvpd_.wait(lk);
}

void Simulator::stop() {
	std::cerr << "Simulator stopping\n";
	stop_ = true;
	if(!stopped_) {
		std::unique_lock<std::mutex> lk(mustop_);
		while(!stopped_)
			cvstop_.wait(lk);
	}
	std::cerr << "Simulator stopped\n";
}

std::array<std::mutex, 3> mu;
std::array<std::condition_variable, 3> cv;
std::array<std::atomic_bool, 3> go;
std::atomic_bool die;
std::mutex mudone;
std::condition_variable cvdone;
std::atomic_int running;

void calcLoop(Galaxy& g, BHTree& tree, const int tid) {
	for(;;) {
		if(!go[tid]) {
			std::unique_lock<std::mutex> lk(mu[tid]);
			while(!go[tid])
				cv[tid].wait(lk);
		}
		if(die) {
			std::cerr << "Calcloop " << tid << " dying\n";
			return;
		}
		go[tid] = false;

		auto nbody = g.bodies.size()/4;
		auto start = g.bodies.begin() + nbody*tid;
		auto end = g.bodies.begin() + nbody*(tid+1);
		for(auto& i = start; i < end; ++i)
			tree.calcforce(*i);

		--running;
		if(running == 0)
			cvdone.notify_one();
	}
}

void goThreads() {
	running = 3;
	for(auto i = 0; i < 3; ++i) {
		go[i] = true;
		cv[i].notify_one();
	}
}

void Simulator::simLoop(Galaxy& g, UI& ui) {
	BHTree tree;
	for(auto i = 0; i < 3; i++) {
		auto t = std::thread([&g, &tree, i] { calcLoop(g, tree, i); });
		t.detach();
	}
	for(;;) {
		if(pause_) {
			paused_ = true;
			cvpd_.notify_one();
			std::unique_lock<std::mutex> lk(mup_);
			while(pause_)
				cvp_.wait(lk);
			paused_ = false;
			cvpd_.notify_one();
		}

		if(stop_) {
			stopped_ = true;
			die = true;
			goThreads();
			cvstop_.notify_one();
			std::cerr << "simLoop returning\n";
			return;
		}

		ui.draw(g);

		tree.insert(g);

		goThreads();

		auto nbody = g.bodies.size()/4;
		auto i = g.bodies.begin() + nbody*3;
		while(i < g.bodies.end())
			tree.calcforce(*i++);

		if(running > 0) {
			std::unique_lock<std::mutex> lk(mudone);
			while(running > 0)
				cvdone.wait(lk);
		}

		for(auto& b : g.bodies) {
			b.p += b.v * dt + b.a * dt² / 2;
			b.v += (b.a + b.newa) * dt / 2;
			g.checkLimit(b.p);
		}
	}
}

void Simulator::simulate(Galaxy& g, UI& ui) {
	auto t = std::thread([this, &g, &ui] { simLoop(g, ui); });
	t.detach();
}

void load(Galaxy& g, UI& ui, Simulator& sim, std::istream& is) {
	for(;;) {
		ReadCmd rc;
		is >> rc;
		Body b;
		switch(rc) {
		case ReadCmd::body:
			if(is >> b) {
				g.bodies.push_back(b);
				g.checkLimit(b.p);
			}
			break;
		case ReadCmd::orig:
			is >> ui.orig_;
			break;
		case ReadCmd::dt:
			is >> sim.dt;
			sim.dt² = sim.dt * sim.dt;
			break;
		case ReadCmd::scale:
			is >> ui.scale_;
			break;
		case ReadCmd::grav:
		case ReadCmd::nocmd:
			if(is.eof()) {
				is.clear();
				return;
			}
			break;
		}
	}
}

char* argv0;

void usage() {
	std::cerr << "Usage: " << argv0 << " [-i] [-n]\n";
	exit(1);
}

int main(int argc, char** argv) {
	argv0 = argv[0];
	args::Args args(argc, argv);
	if(args.get("help") || args.get("h"))
		usage();

	int n;
	args.get<int>(n, "n", 0);

try {
	Simulator sim;
	UI ui(sim);

	Galaxy glxy;
	if(args.get("i")) {
		load(glxy, ui, sim, std::cin);
		glxy.center();
	}

	if(args.flags().size() > 0)
		usage();

	sim.simulate(glxy, ui);
	ui.loop(glxy);
} catch (const std::runtime_error& e) {
	std::cerr << "Runtime error: " << e.what() << '\n';
	return 1;
}

	std::cerr << "Program done\n";
	return 0;
}
<commit_msg>modularize parallelization<commit_after>#include "galaxy.h"
#include "args.h"

void Simulator::pause(int id) {
	if(pid_ != -1 && pid_ > id)
		return;
	pid_ = id;
	if(paused_)
		return;
	pause_ = true;
	std::unique_lock<std::mutex> lk(mupd_);
	while(!paused_)
		cvpd_.wait(lk);
}

void Simulator::unpause(int id) {
	if(!paused_ || pid_ != id)
		return;
	pid_ = -1;
	pause_ = false;
	cvp_.notify_one();
	std::unique_lock<std::mutex> lk(mupd_);
	while(paused_)
		cvpd_.wait(lk);
}

void Simulator::stop() {
	stop_ = true;
	if(!stopped_) {
		std::unique_lock<std::mutex> lk(mustop_);
		while(!stopped_)
			cvstop_.wait(lk);
	}
}

template <int n>
struct Parallel {
	std::array<std::mutex, n> mu;
	std::array<std::condition_variable, n> cv;
	std::array<std::atomic_bool, n> go;
	std::atomic_bool die;
	std::mutex mudone;
	std::condition_variable cvdone;
	std::atomic_int running;

	void goThreads() {
		running = n;
		for(auto i = 0; i < n; ++i) {
			go[i] = true;
			cv[i].notify_one();
		}
	}
};

Parallel<3> par;

void calcLoop(Galaxy& g, BHTree& tree, const int tid) {
	for(;;) {
		if(!par.go[tid]) {
			std::unique_lock<std::mutex> lk(par.mu[tid]);
			while(!par.go[tid])
				par.cv[tid].wait(lk);
		}
		if(par.die) {
			std::cerr << "Calcloop " << tid << " dying\n";
			return;
		}
		par.go[tid] = false;

		auto nbody = g.bodies.size()/4;
		auto start = g.bodies.begin() + nbody*tid;
		auto end = g.bodies.begin() + nbody*(tid+1);
		for(auto& i = start; i < end; ++i)
			tree.calcforce(*i);

		if(--par.running == 0)
			par.cvdone.notify_one();
	}
}

void Simulator::simLoop(Galaxy& g, UI& ui) {
	BHTree tree;
	for(auto i = 0; i < 3; i++) {
		auto t = std::thread([&g, &tree, i] { calcLoop(g, tree, i); });
		t.detach();
	}
	for(;;) {
		if(pause_) {
			paused_ = true;
			cvpd_.notify_one();
			std::unique_lock<std::mutex> lk(mup_);
			while(pause_)
				cvp_.wait(lk);
			paused_ = false;
			cvpd_.notify_one();
		}

		if(stop_) {
			stopped_ = true;
			par.die = true;
			par.goThreads();
			cvstop_.notify_one();
			return;
		}

		ui.draw(g);

		tree.insert(g);

		par.goThreads();

		auto nbody = g.bodies.size()/4;
		auto i = g.bodies.begin() + nbody*3;
		while(i < g.bodies.end())
			tree.calcforce(*i++);

		if(par.running > 0) {
			std::unique_lock<std::mutex> lk(par.mudone);
			while(par.running > 0)
				par.cvdone.wait(lk);
		}

		for(auto& b : g.bodies) {
			b.p += b.v * dt + b.a * dt² / 2;
			b.v += (b.a + b.newa) * dt / 2;
			g.checkLimit(b.p);
		}
	}
}

void Simulator::simulate(Galaxy& g, UI& ui) {
	auto t = std::thread([this, &g, &ui] { simLoop(g, ui); });
	t.detach();
}

void load(Galaxy& g, UI& ui, Simulator& sim, std::istream& is) {
	for(;;) {
		ReadCmd rc;
		is >> rc;
		Body b;
		switch(rc) {
		case ReadCmd::body:
			if(is >> b) {
				g.bodies.push_back(b);
				g.checkLimit(b.p);
			}
			break;
		case ReadCmd::orig:
			is >> ui.orig_;
			break;
		case ReadCmd::dt:
			is >> sim.dt;
			sim.dt² = sim.dt * sim.dt;
			break;
		case ReadCmd::scale:
			is >> ui.scale_;
			break;
		case ReadCmd::grav:
		case ReadCmd::nocmd:
			if(is.eof()) {
				is.clear();
				return;
			}
			break;
		}
	}
}

char* argv0;

void usage() {
	std::cerr << "Usage: " << argv0 << " [-i] [-n]\n";
	exit(1);
}

int main(int argc, char** argv) {
	argv0 = argv[0];
	args::Args args(argc, argv);
	if(args.get("help") || args.get("h"))
		usage();

	int n;
	args.get<int>(n, "n", 0);

try {
	Simulator sim;
	UI ui(sim);

	Galaxy glxy;
	if(args.get("i")) {
		load(glxy, ui, sim, std::cin);
		glxy.center();
	}

	if(args.flags().size() > 0)
		usage();

	sim.simulate(glxy, ui);
	ui.loop(glxy);
} catch (const std::runtime_error& e) {
	std::cerr << "Runtime error: " << e.what() << '\n';
	return 1;
}

	std::cerr << "Program done\n";
	return 0;
}
<|endoftext|>


<commit_before>#include "midiio.h"

#include "lpd8_sysex.h"
#include "midiportsmodel.h"

#include <QGuiApplication>
#include <QSocketNotifier>
#include <QtDebug>
#include <QStandardItemModel>
#include <QThread>

#include <exception>

MidiIO::MidiIO(QObject *parent) : QObject(parent),
    m_seq_handle(Q_NULLPTR),
    m_pfds(Q_NULLPTR),
    m_seq_port(-1),
    m_ports_model(Q_NULLPTR)
{
    qDebug() << "Opening MIDI sequencer";

    if (snd_seq_open(&m_seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
        throw std::runtime_error("Failed opening sequencer");
    }

    // Poll

    int npfd = snd_seq_poll_descriptors_count(m_seq_handle, POLLIN);
    m_pfds = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
    int npfdf = snd_seq_poll_descriptors(m_seq_handle, m_pfds, npfd, POLLIN);

    for (int i = 0 ; i < npfdf ; ++i) {
        qDebug() << "Enabling MIDI poll descriptor" << i;
        QSocketNotifier* n = new QSocketNotifier(m_pfds[i].fd, QSocketNotifier::Read);
        connect(qGuiApp,
                &QGuiApplication::aboutToQuit,
                [=]() {
                    qDebug() << "Disabling MIDI poll descriptor" << i;
                    n->setEnabled(false);
                }
        );
        connect(n,
                &QSocketNotifier::activated,
                this,
                &MidiIO::readEvents
        );
    }

    //    snd_seq_set_client_event_filter(m_seq_handle, SND_SEQ_EVENT_SYSEX);

    // Try qUtf8Printable
    if (snd_seq_set_client_name(m_seq_handle, qPrintable(qApp->applicationName())) < 0) {
        throw std::runtime_error("Failed setting sequencer name");
    }

    // In port
    m_seq_port = snd_seq_create_simple_port(
                m_seq_handle,
                qPrintable(qGuiApp->applicationName()),
                SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_DUPLEX | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE,
                SND_SEQ_PORT_TYPE_APPLICATION);
    if (m_seq_port < 0) {
        throw std::runtime_error("Failed setting sequencer port");
    }

//    m_ports_model = new MidiPortsModel(m_seq_handle, m_seq_port, this);
    m_ports_model = new QStandardItemModel(this);
}

MidiIO::~MidiIO() {
    qDebug() << "Closing MIDI sequencer";
    if (snd_seq_delete_simple_port(m_seq_handle, m_seq_port) >= 0) {
        m_seq_port = -1;
    } else {
        qWarning() << "Failed deleting sequencer port";
    }

    if (snd_seq_close(m_seq_handle) >= 0) {
        m_seq_handle = Q_NULLPTR;
    } else {
        qWarning() << "Failed closing sequencer";
    }
}

QAbstractItemModel* MidiIO::midiPortsModel() const {
    Q_CHECK_PTR(m_ports_model);

    return m_ports_model;
}

void MidiIO::readEvents()
{
    qDebug();
    while (snd_seq_event_input_pending(m_seq_handle, 1) > 0) {
        snd_seq_event_t *ev;
        snd_seq_event_input(m_seq_handle, &ev);
        processEvent(ev);
    }
}

void MidiIO::processEvent(snd_seq_event_t* ev)
{
    switch (ev->type) {
    case SND_SEQ_EVENT_PORT_SUBSCRIBED:
        processPortSubscribed(ev);
        break;
    case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
        break;
    case SND_SEQ_EVENT_PORT_START:
        break;
    case SND_SEQ_EVENT_PORT_EXIT:
        break;
    case SND_SEQ_EVENT_PORT_CHANGE:
        break;
    case SND_SEQ_EVENT_SYSEX:
        processSysex(ev);
    default:
        break;
    }
}

void MidiIO::processPortSubscribed(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED);

//    sendIdRequest();
}

void MidiIO::processSysex(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_SYSEX);

    QByteArray s(
        static_cast<const char*>(ev->data.ext.ptr),
        ev->data.ext.len);

    switch (sysex::type(s)) {
    case sysex::TypeProgram:
        emit programReceived(sysex::toProgram(s));
        break;
    default:
        break;
    }
    emit sysexReceived(s);
}

void MidiIO::sendIdRequest() const
{
    const unsigned char b[] = {0xF0, 0x7E, 0x00, 0x06, 0x01, 0xF7};
    const QByteArray sysex(reinterpret_cast<const char*>(b), sizeof(b));
    sendSysex(sysex);
}

void MidiIO::sendSysex(QByteArray sysex) const
{
    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);
    snd_seq_ev_set_source(&ev, m_seq_port);
    snd_seq_ev_set_sysex(&ev, sysex.length(), sysex.data());

    int err = snd_seq_event_output(m_seq_handle, &ev);
    if (err < 0) {
        throw std::runtime_error(snd_strerror(err));
    }
    err = 1;
    while (err > 0) {
        err = snd_seq_drain_output(m_seq_handle);
        if (err < 0) {
            throw std::runtime_error(snd_strerror(err));
        }
    }
}

void MidiIO::getPrograms() const {
    for (int i = 1 ; i <= 4 ; ++i) {
        sendSysex(sysex::getProgram(i));
    }
}

void MidiIO::sendProgram(pProgram program) const
{
    QByteArray s = sysex::setProgram(program);
    sendSysex(s);
}

void MidiIO::getProgram(int id) const {
    Q_ASSERT(id >= 1 && id <= 4);

    sendSysex(sysex::getProgram(id));
    QThread::sleep(1);
}

enum MidiPortRole {
    ClientRole = Qt::UserRole + 1,
    PortRole
};

// Template it, baby
void setClient(QStandardItem* item, int client) {
    Q_CHECK_PTR(item);

    item->setData(client, ClientRole);
}

int client(const QStandardItem* item) {
    Q_CHECK_PTR(item);

    return item->data(ClientRole).toInt();
}

void setPort(QStandardItem* item, int port) {
    Q_CHECK_PTR(item);

    item->setData(port, PortRole);
}

int port(const QStandardItem* item) {
    Q_CHECK_PTR(item);

    return item->data(PortRole).toInt();
}

void MidiIO::rescanPorts() {
    Q_CHECK_PTR(m_seq_handle);
    Q_CHECK_PTR(m_ports_model);

    snd_seq_client_info_t *cinfo;
    snd_seq_port_info_t *pinfo;

    snd_seq_client_info_alloca(&cinfo);
    snd_seq_port_info_alloca(&pinfo);
    snd_seq_client_info_set_client(cinfo, -1);
    while (snd_seq_query_next_client(m_seq_handle, cinfo) >= 0) {
        const int id = snd_seq_client_info_get_client(cinfo);
        snd_seq_port_info_set_client(pinfo, id);
        snd_seq_port_info_set_port(pinfo, -1);

        while (snd_seq_query_next_port(m_seq_handle, pinfo) >= 0) {
            QStandardItem* item = new QStandardItem();
            item->setText(snd_seq_port_info_get_name(pinfo));
            const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(pinfo);
            Q_CHECK_PTR(addr);
            setClient(item, addr->client);
            setPort(item, addr->port);
            m_ports_model->appendRow(item);
        }
    }
}

void MidiIO::connectPort(const QModelIndex& index) {
    Q_CHECK_PTR(m_ports_model);
    Q_ASSERT(m_seq_port >= 0);

    QStandardItem* item = m_ports_model->itemFromIndex(index);
    Q_CHECK_PTR(item);

    const int c = client(item);
    const int p = port(item);

    if (snd_seq_connect_from(m_seq_handle, m_seq_port, c, p) < 0) {
        qDebug() << "Cannot connect from";
    }

    if (snd_seq_connect_to(m_seq_handle, m_seq_port, c, p) < 0) {
        qDebug() << "Cannot connect to";
    }
}
<commit_msg>Implement device rescan<commit_after>#include "midiio.h"

#include "lpd8_sysex.h"
#include "midiportsmodel.h"

#include <QGuiApplication>
#include <QSocketNotifier>
#include <QtDebug>
#include <QStandardItemModel>
#include <QThread>

#include <exception>

MidiIO::MidiIO(QObject *parent) : QObject(parent),
    m_seq_handle(Q_NULLPTR),
    m_pfds(Q_NULLPTR),
    m_seq_port(-1),
    m_ports_model(Q_NULLPTR)
{
    qDebug() << "Opening MIDI sequencer";

    if (snd_seq_open(&m_seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
        throw std::runtime_error("Failed opening sequencer");
    }

    // Poll

    int npfd = snd_seq_poll_descriptors_count(m_seq_handle, POLLIN);
    m_pfds = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
    int npfdf = snd_seq_poll_descriptors(m_seq_handle, m_pfds, npfd, POLLIN);

    for (int i = 0 ; i < npfdf ; ++i) {
        qDebug() << "Enabling MIDI poll descriptor" << i;
        QSocketNotifier* n = new QSocketNotifier(m_pfds[i].fd, QSocketNotifier::Read);
        connect(qGuiApp,
                &QGuiApplication::aboutToQuit,
                [=]() {
                    qDebug() << "Disabling MIDI poll descriptor" << i;
                    n->setEnabled(false);
                }
        );
        connect(n,
                &QSocketNotifier::activated,
                this,
                &MidiIO::readEvents
        );
    }

    //    snd_seq_set_client_event_filter(m_seq_handle, SND_SEQ_EVENT_SYSEX);

    // Try qUtf8Printable
    if (snd_seq_set_client_name(m_seq_handle, qPrintable(qApp->applicationName())) < 0) {
        throw std::runtime_error("Failed setting sequencer name");
    }

    // In port
    m_seq_port = snd_seq_create_simple_port(
                m_seq_handle,
                qPrintable(qGuiApp->applicationName()),
                SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_DUPLEX | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE,
                SND_SEQ_PORT_TYPE_APPLICATION);
    if (m_seq_port < 0) {
        throw std::runtime_error("Failed setting sequencer port");
    }

//    m_ports_model = new MidiPortsModel(m_seq_handle, m_seq_port, this);
    m_ports_model = new QStandardItemModel(this);
}

MidiIO::~MidiIO() {
    qDebug() << "Closing MIDI sequencer";
    if (snd_seq_delete_simple_port(m_seq_handle, m_seq_port) >= 0) {
        m_seq_port = -1;
    } else {
        qWarning() << "Failed deleting sequencer port";
    }

    if (snd_seq_close(m_seq_handle) >= 0) {
        m_seq_handle = Q_NULLPTR;
    } else {
        qWarning() << "Failed closing sequencer";
    }
}

QAbstractItemModel* MidiIO::midiPortsModel() const {
    Q_CHECK_PTR(m_ports_model);

    return m_ports_model;
}

void MidiIO::readEvents()
{
    qDebug();
    while (snd_seq_event_input_pending(m_seq_handle, 1) > 0) {
        snd_seq_event_t *ev;
        snd_seq_event_input(m_seq_handle, &ev);
        processEvent(ev);
    }
}

void MidiIO::processEvent(snd_seq_event_t* ev)
{
    switch (ev->type) {
    case SND_SEQ_EVENT_PORT_SUBSCRIBED:
        processPortSubscribed(ev);
        break;
    case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
        break;
    case SND_SEQ_EVENT_PORT_START:
        break;
    case SND_SEQ_EVENT_PORT_EXIT:
        break;
    case SND_SEQ_EVENT_PORT_CHANGE:
        break;
    case SND_SEQ_EVENT_SYSEX:
        processSysex(ev);
    default:
        break;
    }
}

void MidiIO::processPortSubscribed(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED);

//    sendIdRequest();
}

void MidiIO::processSysex(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_SYSEX);

    QByteArray s(
        static_cast<const char*>(ev->data.ext.ptr),
        ev->data.ext.len);

    switch (sysex::type(s)) {
    case sysex::TypeProgram:
        emit programReceived(sysex::toProgram(s));
        break;
    default:
        break;
    }
    emit sysexReceived(s);
}

void MidiIO::sendIdRequest() const
{
    const unsigned char b[] = {0xF0, 0x7E, 0x00, 0x06, 0x01, 0xF7};
    const QByteArray sysex(reinterpret_cast<const char*>(b), sizeof(b));
    sendSysex(sysex);
}

void MidiIO::sendSysex(QByteArray sysex) const
{
    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);
    snd_seq_ev_set_source(&ev, m_seq_port);
    snd_seq_ev_set_sysex(&ev, sysex.length(), sysex.data());

    int err = snd_seq_event_output(m_seq_handle, &ev);
    if (err < 0) {
        throw std::runtime_error(snd_strerror(err));
    }
    err = 1;
    while (err > 0) {
        err = snd_seq_drain_output(m_seq_handle);
        if (err < 0) {
            throw std::runtime_error(snd_strerror(err));
        }
    }
}

void MidiIO::getPrograms() const {
    for (int i = 1 ; i <= 4 ; ++i) {
        sendSysex(sysex::getProgram(i));
    }
}

void MidiIO::sendProgram(pProgram program) const
{
    QByteArray s = sysex::setProgram(program);
    sendSysex(s);
}

void MidiIO::getProgram(int id) const {
    Q_ASSERT(id >= 1 && id <= 4);

    sendSysex(sysex::getProgram(id));
    QThread::sleep(1);
}

enum MidiPortRole {
    ClientRole = Qt::UserRole + 1,
    PortRole
};

// Template it, baby
template<typename T, int Role>
void set(QStandardItem* item, T v) {
    Q_CHECK_PTR(item);

    item->setData(v, Role);
}

template<typename T, int Role>
T get(const QStandardItem* item) {
    Q_CHECK_PTR(item);

    return item->data(Role).value<T>();
}

void (&setClient)(QStandardItem*, int) = set<int, ClientRole>;
void (&setPort)(QStandardItem*, int) = set<int, PortRole>;
int (&client)(const QStandardItem*) = get<int, ClientRole>;
int (&port)(const QStandardItem*) = get<int, PortRole>;

QStandardItem* takeItemFromAlsaAddress(QList<QStandardItem*>& items, const snd_seq_addr_t* addr) {
    Q_CHECK_PTR(addr);

    QStandardItem* item = Q_NULLPTR;
    foreach (item, items) {
        if (client(item) == addr->client && port(item) == addr->port) {
            break;
        }
    }
    if (item) {
        items.removeAt(items.indexOf(item));
    }
    return item;
}

void MidiIO::rescanPorts() {
    Q_CHECK_PTR(m_seq_handle);
    Q_CHECK_PTR(m_ports_model);

    // Existing items
    QList<QStandardItem*> existing;
    for (int i = 0 ; i < m_ports_model->rowCount() ; ++i) {
        existing << m_ports_model->item(i);
    }

    snd_seq_client_info_t *cinfo;
    snd_seq_port_info_t *pinfo;

    snd_seq_client_info_alloca(&cinfo);
    snd_seq_port_info_alloca(&pinfo);
    snd_seq_client_info_set_client(cinfo, -1);
    while (snd_seq_query_next_client(m_seq_handle, cinfo) >= 0) {
        const int id = snd_seq_client_info_get_client(cinfo);
        snd_seq_port_info_set_client(pinfo, id);
        snd_seq_port_info_set_port(pinfo, -1);

        while (snd_seq_query_next_port(m_seq_handle, pinfo) >= 0) {
            const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(pinfo);
            Q_CHECK_PTR(addr);

            QStandardItem* item = takeItemFromAlsaAddress(existing, addr);
            if (!item) {
                item = new QStandardItem();
                setClient(item, addr->client);
                setPort(item, addr->port);
                m_ports_model->appendRow(item);
            }
            item->setText(snd_seq_port_info_get_name(pinfo));
        }
    }

    // Remove old items
    int rc = m_ports_model->rowCount();
    QStandardItem* item = Q_NULLPTR;
    foreach (item, existing) {
        const QModelIndex index = m_ports_model->indexFromItem(item);
        Q_ASSERT(index.isValid());

        QStandardItem* rowItem = Q_NULLPTR;
        foreach (rowItem, m_ports_model->takeRow(index.row())) {
            Q_CHECK_PTR(rowItem);
            delete rowItem;
        }
        rc = m_ports_model->rowCount();
        Q_UNUSED(rc);
    }
}

void MidiIO::connectPort(const QModelIndex& index) {
    Q_CHECK_PTR(m_ports_model);
    Q_ASSERT(m_seq_port >= 0);

    QStandardItem* item = m_ports_model->itemFromIndex(index);
    Q_CHECK_PTR(item);

    const int c = client(item);
    const int p = port(item);

    if (snd_seq_connect_from(m_seq_handle, m_seq_port, c, p) < 0) {
        qDebug() << "Cannot connect from";
    }

    if (snd_seq_connect_to(m_seq_handle, m_seq_port, c, p) < 0) {
        qDebug() << "Cannot connect to";
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

#pragma once

#if !defined(DEBUG_BUILD) && !defined(RELEASE_BUILD)
#  error Either DEBUG_BUILD or RELEASE_BUILD must be defined
#endif

#include <ch.hpp>
#include <hal.h>
#include <type_traits>
#include "execute_once.hpp"

#ifndef STRINGIZE
#  define STRINGIZE2(x)         #x
#  define STRINGIZE(x)          STRINGIZE2(x)
#endif

#if defined(DEBUG_BUILD) && DEBUG_BUILD
# define MAKE_ASSERT_MSG_(x)      (__FILE__ ":" STRINGIZE(__LINE__) ":" STRINGIZE(x))
#else
# define MAKE_ASSERT_MSG_(x)      (STRINGIZE(__LINE__))
#endif

#define ASSERT_ALWAYS(x)                                    \
    do {                                                    \
        if ((x) == 0) {                                     \
            chSysHalt(MAKE_ASSERT_MSG_(x));                 \
        }                                                   \
    } while (0)

#define LIKELY(x)       (__builtin_expect((x), true))
#define UNLIKELY(x)     (__builtin_expect((x), false))

#if defined(DEBUG_BUILD) && DEBUG_BUILD
# define DEBUG_LOG(...)         ::os::lowsyslog(__VA_ARGS__)
#else
# define DEBUG_LOG(...)         ((void)0)
#endif

namespace os
{

static constexpr unsigned DefaultStdIOByteWriteTimeoutMSec = 1;

/**
 * NuttX-like console print; should be used instead of printf()/chprintf()
 * This function always outputs into the debug UART regardless of the current stdout configuration.
 * TODO: use type safe version based on variadic templates.
 */
__attribute__ ((format (printf, 1, 2)))
void lowsyslog(const char* format, ...);

/**
 * Changes current stdout stream and its write timeout.
 * This setting does not affect @ref lowsyslog().
 */
void setStdIOStream(::BaseChannel* stream, unsigned byte_write_timeout_msec = DefaultStdIOByteWriteTimeoutMSec);
::BaseChannel* getStdIOStream();

/**
 * Provides access to the stdout mutex.
 */
chibios_rt::Mutex& getStdIOMutex();

/**
 * Emergency termination hook that can be overriden by the application.
 * The hook must return immediately after bringing the hardware into a safe state.
 */
extern void applicationHaltHook(void);

/**
 * Replacement for chThdSleepUntil() that accepts timestamps from the past.
 * http://sourceforge.net/p/chibios/bugs/292/#ec7c
 */
void sleepUntilChTime(systime_t sleep_until);

namespace impl_
{

class MutexLockerImpl
{
    chibios_rt::Mutex& mutex_;
public:
    MutexLockerImpl(chibios_rt::Mutex& m) : mutex_(m)
    {
        mutex_.lock();
    }
    ~MutexLockerImpl()
    {
        mutex_.unlock();
    }
};

class CriticalSectionLockerImpl
{
    volatile const syssts_t st_ = chSysGetStatusAndLockX();
public:
    ~CriticalSectionLockerImpl() { chSysRestoreStatusX(st_); }
};

} // namespace impl_

/**
 * RAII mutex locker.
 * Must be volatile in order to prevent the optimizer from throwing it away.
 */
using MutexLocker = volatile impl_::MutexLockerImpl;

/**
 * RAII critical section locker.
 * Must be volatile in order to prevent the optimizer from throwing it away.
 */
using CriticalSectionLocker = volatile impl_::CriticalSectionLockerImpl;

/**
 * Converts any unsigned integer to string and returns it by value.
 * The argument must be unsigned, otherwise the call will be rejected by SFINAE.
 */
template <typename T, typename std::enable_if<std::is_unsigned<T>::value>::type...>
inline auto uintToString(T num)
{
    struct
    {
        char storage_[22];                                      // len(str(2**64)) + 1
        char* begin_ptr_ = &storage_[0] + sizeof(storage_) - 1;
        const char* c_str() const { return begin_ptr_; }
        operator const char* () const { return this->c_str(); }
    } container;
    *container.begin_ptr_ = '\0';
    do { *--container.begin_ptr_ = char(num % 10U + 0x30U); } while (num /= 10U);
    return container;
};

}
<commit_msg>Stdout write timeout increased to suit 115200 baud interface<commit_after>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

#pragma once

#if !defined(DEBUG_BUILD) && !defined(RELEASE_BUILD)
#  error Either DEBUG_BUILD or RELEASE_BUILD must be defined
#endif

#include <ch.hpp>
#include <hal.h>
#include <type_traits>
#include "execute_once.hpp"

#ifndef STRINGIZE
#  define STRINGIZE2(x)         #x
#  define STRINGIZE(x)          STRINGIZE2(x)
#endif

#if defined(DEBUG_BUILD) && DEBUG_BUILD
# define MAKE_ASSERT_MSG_(x)      (__FILE__ ":" STRINGIZE(__LINE__) ":" STRINGIZE(x))
#else
# define MAKE_ASSERT_MSG_(x)      (STRINGIZE(__LINE__))
#endif

#define ASSERT_ALWAYS(x)                                    \
    do {                                                    \
        if ((x) == 0) {                                     \
            chSysHalt(MAKE_ASSERT_MSG_(x));                 \
        }                                                   \
    } while (0)

#define LIKELY(x)       (__builtin_expect((x), true))
#define UNLIKELY(x)     (__builtin_expect((x), false))

#if defined(DEBUG_BUILD) && DEBUG_BUILD
# define DEBUG_LOG(...)         ::os::lowsyslog(__VA_ARGS__)
#else
# define DEBUG_LOG(...)         ((void)0)
#endif

namespace os
{

static constexpr unsigned DefaultStdIOByteWriteTimeoutMSec = 2;		///< Enough for 115200 baud and higher

/**
 * NuttX-like console print; should be used instead of printf()/chprintf()
 * This function always outputs into the debug UART regardless of the current stdout configuration.
 * TODO: use type safe version based on variadic templates.
 */
__attribute__ ((format (printf, 1, 2)))
void lowsyslog(const char* format, ...);

/**
 * Changes current stdout stream and its write timeout.
 * This setting does not affect @ref lowsyslog().
 */
void setStdIOStream(::BaseChannel* stream, unsigned byte_write_timeout_msec = DefaultStdIOByteWriteTimeoutMSec);
::BaseChannel* getStdIOStream();

/**
 * Provides access to the stdout mutex.
 */
chibios_rt::Mutex& getStdIOMutex();

/**
 * Emergency termination hook that can be overriden by the application.
 * The hook must return immediately after bringing the hardware into a safe state.
 */
extern void applicationHaltHook(void);

/**
 * Replacement for chThdSleepUntil() that accepts timestamps from the past.
 * http://sourceforge.net/p/chibios/bugs/292/#ec7c
 */
void sleepUntilChTime(systime_t sleep_until);

namespace impl_
{

class MutexLockerImpl
{
    chibios_rt::Mutex& mutex_;
public:
    MutexLockerImpl(chibios_rt::Mutex& m) : mutex_(m)
    {
        mutex_.lock();
    }
    ~MutexLockerImpl()
    {
        mutex_.unlock();
    }
};

class CriticalSectionLockerImpl
{
    volatile const syssts_t st_ = chSysGetStatusAndLockX();
public:
    ~CriticalSectionLockerImpl() { chSysRestoreStatusX(st_); }
};

} // namespace impl_

/**
 * RAII mutex locker.
 * Must be volatile in order to prevent the optimizer from throwing it away.
 */
using MutexLocker = volatile impl_::MutexLockerImpl;

/**
 * RAII critical section locker.
 * Must be volatile in order to prevent the optimizer from throwing it away.
 */
using CriticalSectionLocker = volatile impl_::CriticalSectionLockerImpl;

/**
 * Converts any unsigned integer to string and returns it by value.
 * The argument must be unsigned, otherwise the call will be rejected by SFINAE.
 */
template <typename T, typename std::enable_if<std::is_unsigned<T>::value>::type...>
inline auto uintToString(T num)
{
    struct
    {
        char storage_[22];                                      // len(str(2**64)) + 1
        char* begin_ptr_ = &storage_[0] + sizeof(storage_) - 1;
        const char* c_str() const { return begin_ptr_; }
        operator const char* () const { return this->c_str(); }
    } container;
    *container.begin_ptr_ = '\0';
    do { *--container.begin_ptr_ = char(num % 10U + 0x30U); } while (num /= 10U);
    return container;
};

}
<|endoftext|>


<commit_before>#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <chrono>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <unistd.h>

#include "entity.h"
#include "character.h"
#include "monster.h"
#include "spell.h"
#include "item.h"
#include "tile.h"
#include "timetable.h"
#include "mailbox.h"

using namespace std;

//Structure for HTTP form data
struct FormInfo{
	string Key;
	string Value;
};

vector<Tile> Map; //[][]
vector<Enemy> SpawnedEnemies; // []
vector<Character> Players;

//Vector to hold Key / Value pairs after processing
vector<FormInfo> FormData;

void getFormData(string Env);
string GetValueFromKey(string FindKey);

int main(){
	//Setup Game state
	TimeTable TimeTable;
	Mailbox Mailbox;
	bool Done = false;
	string Message;
	string Action;

	//Load maps

	//Load definitions
	cout << "Beginning main loop\n" << flush;
	cout << "Mailbox: " << Mailbox.SetupSuccessful() << "\n" << flush;
	//Main Loop
	while (!Done){
		FormData.clear();
		Action = "";

		//Check Time table.  Perform function for all expired times

		//Check and Process Messages
		Message = Mailbox.GetNextMessage();
		if (Message.size() != "") { cout << Message; }
		getFormData(Message);
		Action = GetValueFromKey("Action");

		if (Action == "EnterGame"){
			Character NewChar(GetValueFromKey("u"), GetValueFromKey("c"), stoi(GetValueFromKey("Box")));
			Mailbox.OpenUserBox(NewChar.Box);
			//Mailbox.BroadcastMessage("This is a test of the server.");
			Mailbox.SendMessageToBox("Specific User Message", NewChar.Box);
			cout << "Intelligence:" << NewChar.GetStat(Intelligence, true) << "\n";
			cout << "Number of Open Boxes:" << Mailbox.BoxCount() << "\n";
			cout << "Number of Messages:" << Mailbox.MessageCount() << "\n";
			Players.push_back(NewChar);
		}

		if (Action == "LeaveGame"){
		}

		if (Action == "Move"){
		}

		if (Action == "CastSpell"){
		}

		if (Action == "EquipItem"){
		}

		if (Action == "UseItem"){
		}

		if (Action == "Attack"){
		}
		//Game in progress action

		//Perform a character action

		//Perform an inventory action

		//Perform a world action

		//Perform targetting action

		//Sleep 10 milliseconds before looping again.

	}

}

string GetValueFromKey(string FindKey){
	for (int i = 0; i < FormData.size(); i++){
		if (!FormData[i].Key.compare(FindKey)){ return FormData[i].Value; }
	}
	return "";
}

void getFormData(string Env){
	int EnvLen = Env.size();
	int Start = 1;
	int Mid = 0;
	FormInfo NewData;

	//Split Key-Value pairs and place in the FormData structure.
	for (int i = 1; i < EnvLen; i++){
	if (Env[i] == '='){Mid = i + 1;}
		if (Env[i] == '&' || i == EnvLen - 1){
			if (i == EnvLen - 1) i++;  //Get last character
			NewData.Key = Env.substr(Start,Mid-Start-1);
			NewData.Value = Env.substr(Mid, i - Mid);
			FormData.push_back(NewData);
			Start = i + 1;
		}
	}
}

<commit_msg>Server/Client setup<commit_after>#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <chrono>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <unistd.h>

#include "entity.h"
#include "character.h"
#include "monster.h"
#include "spell.h"
#include "item.h"
#include "tile.h"
#include "timetable.h"
#include "mailbox.h"

using namespace std;

//Structure for HTTP form data
struct FormInfo{
	string Key;
	string Value;
};

vector<Tile> Map; //[][]
vector<Enemy> SpawnedEnemies; // []
vector<Character> Players;

//Vector to hold Key / Value pairs after processing
vector<FormInfo> FormData;

void getFormData(string Env);
string GetValueFromKey(string FindKey);

int main(){
	//Setup Game state
	TimeTable TimeTable;
	Mailbox Mailbox;
	bool Done = false;
	string Message;
	string Action;

	//Load maps

	//Load definitions
	cout << "Beginning main loop\n" << flush;
	cout << "Mailbox: " << Mailbox.SetupSuccessful() << "\n" << flush;
	//Main Loop
	while (!Done){
		FormData.clear();
		Action = "";

		//Check Time table.  Perform function for all expired times

		//Check and Process Messages
		Message = Mailbox.GetNextMessage();
		if (Message != "") { cout << Message; }
		getFormData(Message);
		Action = GetValueFromKey("Action");

		if (Action == "EnterGame"){
			Character NewChar(GetValueFromKey("u"), GetValueFromKey("c"), stoi(GetValueFromKey("Box")));
			Mailbox.OpenUserBox(NewChar.Box);
			//Mailbox.BroadcastMessage("This is a test of the server.");
			Mailbox.SendMessageToBox("Specific User Message", NewChar.Box);
			cout << "Intelligence:" << NewChar.GetStat(Intelligence, true) << "\n";
			cout << "Number of Open Boxes:" << Mailbox.BoxCount() << "\n";
			cout << "Number of Messages:" << Mailbox.MessageCount() << "\n";
			Players.push_back(NewChar);
		}

		if (Action == "LeaveGame"){
		}

		if (Action == "Move"){
		}

		if (Action == "CastSpell"){
		}

		if (Action == "EquipItem"){
		}

		if (Action == "UseItem"){
		}

		if (Action == "Attack"){
		}
		//Game in progress action

		//Perform a character action

		//Perform an inventory action

		//Perform a world action

		//Perform targetting action

		//Sleep 10 milliseconds before looping again.

	}

}

string GetValueFromKey(string FindKey){
	for (int i = 0; i < FormData.size(); i++){
		if (!FormData[i].Key.compare(FindKey)){ return FormData[i].Value; }
	}
	return "";
}

void getFormData(string Env){
	int EnvLen = Env.size();
	int Start = 1;
	int Mid = 0;
	FormInfo NewData;

	//Split Key-Value pairs and place in the FormData structure.
	for (int i = 1; i < EnvLen; i++){
	if (Env[i] == '='){Mid = i + 1;}
		if (Env[i] == '&' || i == EnvLen - 1){
			if (i == EnvLen - 1) i++;  //Get last character
			NewData.Key = Env.substr(Start,Mid-Start-1);
			NewData.Value = Env.substr(Mid, i - Mid);
			FormData.push_back(NewData);
			Start = i + 1;
		}
	}
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *	Manjeet Dahiya
 *
 * Source:
 *	http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "rosterItemSortFilterProxyModel.h"
#include "rosterItem.h"
#include "utils.h"

rosterItemSortFilterProxyModel::rosterItemSortFilterProxyModel(QObject* parent):
                QSortFilterProxyModel(parent),
                m_showOfflineContacts(true),
                m_sortByName(false)
{
    setDynamicSortFilter(true);
    setFilterRole(Qt::DisplayRole);
    setFilterCaseSensitivity(Qt::CaseInsensitive);
}

bool rosterItemSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
    if(m_sortByName)
    {
        int compare = left.data().toString().compare(right.data().toString(), Qt::CaseInsensitive);
        if(compare < 0)
            return true;
        else
            return false;
    }
    else
    {
        int leftPresenceType = sourceModel()->data(left, rosterItem::PresenceType).toInt();
        int leftStatusType = sourceModel()->data(left, rosterItem::StatusType).toInt();
        int rightPresenceType = sourceModel()->data(right, rosterItem::PresenceType).toInt();
        int rightStatusType = sourceModel()->data(right, rosterItem::StatusType).toInt();

        if(leftPresenceType == rightPresenceType)
        {
            if(leftStatusType == rightStatusType)
            {
                // based on display text
                int compare = left.data().toString().compare(right.data().toString(), Qt::CaseInsensitive);
                if(compare < 0)
                    return true;
                else
                    return false;
            }
            else
            {
                return comparisonWeightsPresenceStatusType(static_cast<QXmppPresence::Status::Type>(leftStatusType)) <
                        comparisonWeightsPresenceStatusType(static_cast<QXmppPresence::Status::Type>(rightStatusType));
            }
        }
        else
            return comparisonWeightsPresenceType(static_cast<QXmppPresence::Type>(leftPresenceType)) <
                    comparisonWeightsPresenceType(static_cast<QXmppPresence::Type>(rightPresenceType));
    }
}

bool rosterItemSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
    if(m_showOfflineContacts)
        return true;

    QModelIndex index = sourceModel()->index(source_row, 0, source_parent);

    int presenceType = sourceModel()->data(index, rosterItem::PresenceType).toInt();

    if(presenceType == QXmppPresence::Available)
        return true;
    else
        return false;
}

void rosterItemSortFilterProxyModel::setShowOfflineContacts(bool showOfflineContacts)
{
    m_showOfflineContacts = showOfflineContacts;
    invalidateFilter();
}

void rosterItemSortFilterProxyModel::sortByName(bool sortByName)
{
    m_sortByName = sortByName;
    invalidate();
}
<commit_msg>make contact search working again<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *	Manjeet Dahiya
 *
 * Source:
 *	http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "rosterItemSortFilterProxyModel.h"
#include "rosterItem.h"
#include "utils.h"

rosterItemSortFilterProxyModel::rosterItemSortFilterProxyModel(QObject* parent):
                QSortFilterProxyModel(parent),
                m_showOfflineContacts(true),
                m_sortByName(false)
{
    setDynamicSortFilter(true);
    setFilterRole(Qt::DisplayRole);
    setFilterCaseSensitivity(Qt::CaseInsensitive);
}

bool rosterItemSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
    if(m_sortByName)
    {
        int compare = left.data().toString().compare(right.data().toString(), Qt::CaseInsensitive);
        if(compare < 0)
            return true;
        else
            return false;
    }
    else
    {
        int leftPresenceType = sourceModel()->data(left, rosterItem::PresenceType).toInt();
        int leftStatusType = sourceModel()->data(left, rosterItem::StatusType).toInt();
        int rightPresenceType = sourceModel()->data(right, rosterItem::PresenceType).toInt();
        int rightStatusType = sourceModel()->data(right, rosterItem::StatusType).toInt();

        if(leftPresenceType == rightPresenceType)
        {
            if(leftStatusType == rightStatusType)
            {
                // based on display text
                int compare = left.data().toString().compare(right.data().toString(), Qt::CaseInsensitive);
                if(compare < 0)
                    return true;
                else
                    return false;
            }
            else
            {
                return comparisonWeightsPresenceStatusType(static_cast<QXmppPresence::Status::Type>(leftStatusType)) <
                        comparisonWeightsPresenceStatusType(static_cast<QXmppPresence::Status::Type>(rightStatusType));
            }
        }
        else
            return comparisonWeightsPresenceType(static_cast<QXmppPresence::Type>(leftPresenceType)) <
                    comparisonWeightsPresenceType(static_cast<QXmppPresence::Type>(rightPresenceType));
    }
}

bool rosterItemSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
    if(!filterRegExp().isEmpty())
        return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);

    if(m_showOfflineContacts)
        return true;

    QModelIndex index = sourceModel()->index(source_row, 0, source_parent);

    int presenceType = sourceModel()->data(index, rosterItem::PresenceType).toInt();

    if(presenceType == QXmppPresence::Available)
        return true;
    else
        return false;
}

void rosterItemSortFilterProxyModel::setShowOfflineContacts(bool showOfflineContacts)
{
    m_showOfflineContacts = showOfflineContacts;
    invalidateFilter();
}

void rosterItemSortFilterProxyModel::sortByName(bool sortByName)
{
    m_sortByName = sortByName;
    invalidate();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2009 Rony Shapiro <ronys@users.sourceforge.net>.
 * All rights reserved. Use of the code is allowed under the
 * Artistic License 2.0 terms, as specified in the LICENSE file
 * distributed with this code, or available from
 * http://www.opensource.org/licenses/artistic-license-2.0.php
 */

/** \file PWSTreeCtrl.cpp
*
*/
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

////@begin includes
////@end includes
#include <utility> // for make_pair
#include <vector>

#include "PWStree.h"
#include "pwsdca.h"

////@begin XPM images
////@end XPM images

/*!
 * PWSTreeCtrl type definition
 */

IMPLEMENT_CLASS( PWSTreeCtrl, wxTreeCtrl )

/*!
 * PWSTreeCtrl event table definition
 */

BEGIN_EVENT_TABLE( PWSTreeCtrl, wxTreeCtrl )

////@begin PWSTreeCtrl event table entries
  EVT_TREE_ITEM_ACTIVATED( ID_TREECTRL, PWSTreeCtrl::OnTreectrlItemActivated )
  EVT_RIGHT_DOWN( PWSTreeCtrl::OnRightDown )

////@end PWSTreeCtrl event table entries

END_EVENT_TABLE()

// helper class to match CItemData with wxTreeItemId
class PWTreeItemData : public wxTreeItemData
{
public:
  PWTreeItemData(const CItemData &item)
  {
    item.GetUUID(m_uuid);
  }
  const uuid_array_t &GetUUID() const {return m_uuid;}
private:
  uuid_array_t m_uuid;
};

/*!
 * PWSTreeCtrl constructors
 */

PWSTreeCtrl::PWSTreeCtrl(PWScore &core) : m_core(core)
{
  Init();
}

PWSTreeCtrl::PWSTreeCtrl(wxWindow* parent, PWScore &core,
                         wxWindowID id, const wxPoint& pos,
                         const wxSize& size, long style) : m_core(core)
{
  Init();
  Create(parent, id, pos, size, style);
}

/*!
 * PWSTreeCtrl creator
 */

bool PWSTreeCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
{
////@begin PWSTreeCtrl creation
  wxTreeCtrl::Create(parent, id, pos, size, style);
  CreateControls();
////@end PWSTreeCtrl creation
  return true;
}

/*!
 * PWSTreeCtrl destructor
 */

PWSTreeCtrl::~PWSTreeCtrl()
{
////@begin PWSTreeCtrl destruction
////@end PWSTreeCtrl destruction
}

/*!
 * Member initialisation
 */

void PWSTreeCtrl::Init()
{
////@begin PWSTreeCtrl member initialisation
////@end PWSTreeCtrl member initialisation
}

/*!
 * Control creation for PWSTreeCtrl
 */

void PWSTreeCtrl::CreateControls()
{
////@begin PWSTreeCtrl content construction
////@end PWSTreeCtrl content construction
}

// XXX taken from Windows PWSTreeCtrl.cpp
// XXX move to corelib
static StringX GetPathElem(StringX &path)
{
  // Get first path element and chop it off, i.e., if
  // path = "a.b.c.d"
  // will return "a" and path will be "b.c.d"
  // (assuming GROUP_SEP is '.')
  const char GROUP_SEP = '.';

  StringX retval;
  StringX::size_type N = path.find(GROUP_SEP);
  if (N == StringX::npos) {
    retval = path;
    path = _T("");
  } else {
    const StringX::size_type Len = path.length();
    retval = path.substr(0, N);
    path = path.substr(Len - N - 1);
  }
  return retval;
}

bool PWSTreeCtrl::ExistsInTree(wxTreeItemId node,
                               const StringX &s, wxTreeItemId &si)
{
  // returns true iff s is a direct descendant of node
  wxTreeItemIdValue cookie;
  wxTreeItemId ti = GetFirstChild(node, cookie);

  while (ti) {
    const wxString itemText = GetItemText(ti);
    if (itemText == s.c_str()) {
      si = ti;
      return true;
    }
    ti = GetNextSibling(ti);
  }
  return false;
}

wxTreeItemId PWSTreeCtrl::AddGroup(const StringX &group)
{
  wxTreeItemId ti = GetRootItem();
  // Add a group at the end of path
  wxTreeItemId si;
  if (!group.empty()) {
    StringX path = group;
    StringX s;
    do {
      s = GetPathElem(path);
      if (!ExistsInTree(ti, s, si)) {
        ti = AppendItem(ti, s.c_str());
        // SetItemImage(ti, CPWTreeCtrl::NODE, CPWTreeCtrl::NODE);
      } else
        ti = si;
    } while (!path.empty());
  }
  return ti;
}

wxString PWSTreeCtrl::ItemDisplayString(const CItemData &item) const
{
  wxString title = item.GetTitle().c_str();
  wxString user = item.GetUser().c_str();
  wxString disp = title;
  if (!user.empty())
    disp += _T(" [") + user + _("]");
  return disp;
}

wxString PWSTreeCtrl::GetPath(const wxTreeItemId &node) const
{
  wxString retval;
  std::vector<wxString> v;
  const wxTreeItemId root = GetRootItem();
  wxTreeItemId parent = GetItemParent(node);

  while (parent != root) {
    v.push_back(GetItemText(parent));
    parent = GetItemParent(parent);
  }
  std::vector<wxString>::reverse_iterator iter;
  for(iter = v.rbegin(); iter != v.rend(); iter++) {
    retval += *iter;
    if ((iter + 1) != v.rend())
      retval += _(".");
  }
  return retval;
}

void PWSTreeCtrl::UpdateItem(const CItemData &item)
{
  const wxTreeItemId node = Find(item);
  if (node.IsOk()) {
    const wxString oldGroup = GetPath(node);
    const wxString newGroup = item.GetGroup().c_str();
    if (oldGroup == newGroup) {
      const wxString disp = ItemDisplayString(item);
      SetItemText(node, disp);
    } else { // uh-oh - group's changed
      uuid_array_t uuid;
      item.GetUUID(uuid);
      // remove old item
      m_item_map.erase(CUUIDGen(uuid));
      Delete(node);
      // add new group
      AddItem(item);
    }
    Update();
  }
}

void PWSTreeCtrl::AddItem(const CItemData &item)
{
  wxTreeItemData *data = new PWTreeItemData(item);
  wxTreeItemId gnode = AddGroup(item.GetGroup());
  const wxString disp = ItemDisplayString(item);
  wxTreeItemId titem = AppendItem(gnode, disp, -1, -1, data);
  uuid_array_t uuid;
  item.GetUUID(uuid);
  m_item_map.insert(std::make_pair(CUUIDGen(uuid), titem));
}

const CItemData *PWSTreeCtrl::GetItem(const wxTreeItemId &id) const
{
  if (!id.IsOk())
    return NULL;

  PWTreeItemData *itemData = dynamic_cast<PWTreeItemData *>(GetItemData(id));
  // return if a group is selected
  if (itemData == NULL)
    return NULL;

  ItemListConstIter citer = m_core.Find(itemData->GetUUID());
  if (citer == m_core.GetEntryEndIter())
    return NULL;
  return &citer->second;

}

wxTreeItemId PWSTreeCtrl::Find(const uuid_array_t &uuid) const
{
  wxTreeItemId fail;
  CUUIDGen cuuid(uuid);
  UUIDTIMapT::const_iterator iter = m_item_map.find(cuuid);
  if (iter != m_item_map.end())
    return iter->second;
  else
    return fail;
}

wxTreeItemId PWSTreeCtrl::Find(const CItemData &item) const
{
  uuid_array_t uuid;
  item.GetUUID(uuid);
  return Find(uuid);
}

bool PWSTreeCtrl::Remove(const uuid_array_t &uuid)
{
  wxTreeItemId id = Find(uuid);
  if (id.IsOk()) {
    m_item_map.erase(CUUIDGen(uuid));
    Delete(id);
    Refresh();
    Update();
    return true;
  } else {
    return false;
  }
}

/*!
 * wxEVT_COMMAND_TREE_ITEM_ACTIVATED event handler for ID_TREECTRL
 */

void PWSTreeCtrl::OnTreectrlItemActivated( wxTreeEvent& event )
{
  const CItemData *item = GetItem(event.GetItem());
  if (item != NULL)
    PWSdca::Doit(*item);
}

/*!
 * wxEVT_RIGHT_DOWN event handler for ID_TREECTRL
 */

void PWSTreeCtrl::OnRightDown( wxMouseEvent& event )
{
////@begin wxEVT_RIGHT_DOWN event handler for ID_TREECTRL in PWSTreeCtrl.
  // Before editing this code, remove the block markers.
  wxMessageBox(_("RightClick!"));
////@end wxEVT_RIGHT_DOWN event handler for ID_TREECTRL in PWSTreeCtrl.
}

<commit_msg>Add the root item if it doesn't exist, before adding other items<commit_after>/*
 * Copyright (c) 2003-2009 Rony Shapiro <ronys@users.sourceforge.net>.
 * All rights reserved. Use of the code is allowed under the
 * Artistic License 2.0 terms, as specified in the LICENSE file
 * distributed with this code, or available from
 * http://www.opensource.org/licenses/artistic-license-2.0.php
 */

/** \file PWSTreeCtrl.cpp
*
*/
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

////@begin includes
////@end includes
#include <utility> // for make_pair
#include <vector>

#include "PWStree.h"
#include "pwsdca.h"

////@begin XPM images
////@end XPM images

/*!
 * PWSTreeCtrl type definition
 */

IMPLEMENT_CLASS( PWSTreeCtrl, wxTreeCtrl )

/*!
 * PWSTreeCtrl event table definition
 */

BEGIN_EVENT_TABLE( PWSTreeCtrl, wxTreeCtrl )

////@begin PWSTreeCtrl event table entries
  EVT_TREE_ITEM_ACTIVATED( ID_TREECTRL, PWSTreeCtrl::OnTreectrlItemActivated )
  EVT_RIGHT_DOWN( PWSTreeCtrl::OnRightDown )

////@end PWSTreeCtrl event table entries

END_EVENT_TABLE()

// helper class to match CItemData with wxTreeItemId
class PWTreeItemData : public wxTreeItemData
{
public:
  PWTreeItemData(const CItemData &item)
  {
    item.GetUUID(m_uuid);
  }
  const uuid_array_t &GetUUID() const {return m_uuid;}
private:
  uuid_array_t m_uuid;
};

/*!
 * PWSTreeCtrl constructors
 */

PWSTreeCtrl::PWSTreeCtrl(PWScore &core) : m_core(core)
{
  Init();
}

PWSTreeCtrl::PWSTreeCtrl(wxWindow* parent, PWScore &core,
                         wxWindowID id, const wxPoint& pos,
                         const wxSize& size, long style) : m_core(core)
{
  Init();
  Create(parent, id, pos, size, style);
}

/*!
 * PWSTreeCtrl creator
 */

bool PWSTreeCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
{
////@begin PWSTreeCtrl creation
  wxTreeCtrl::Create(parent, id, pos, size, style);
  CreateControls();
////@end PWSTreeCtrl creation
  return true;
}

/*!
 * PWSTreeCtrl destructor
 */

PWSTreeCtrl::~PWSTreeCtrl()
{
////@begin PWSTreeCtrl destruction
////@end PWSTreeCtrl destruction
}

/*!
 * Member initialisation
 */

void PWSTreeCtrl::Init()
{
////@begin PWSTreeCtrl member initialisation
////@end PWSTreeCtrl member initialisation
}

/*!
 * Control creation for PWSTreeCtrl
 */

void PWSTreeCtrl::CreateControls()
{
////@begin PWSTreeCtrl content construction
////@end PWSTreeCtrl content construction
}

// XXX taken from Windows PWSTreeCtrl.cpp
// XXX move to corelib
static StringX GetPathElem(StringX &path)
{
  // Get first path element and chop it off, i.e., if
  // path = "a.b.c.d"
  // will return "a" and path will be "b.c.d"
  // (assuming GROUP_SEP is '.')
  const char GROUP_SEP = '.';

  StringX retval;
  StringX::size_type N = path.find(GROUP_SEP);
  if (N == StringX::npos) {
    retval = path;
    path = _T("");
  } else {
    const StringX::size_type Len = path.length();
    retval = path.substr(0, N);
    path = path.substr(Len - N - 1);
  }
  return retval;
}

bool PWSTreeCtrl::ExistsInTree(wxTreeItemId node,
                               const StringX &s, wxTreeItemId &si)
{
  // returns true iff s is a direct descendant of node
  wxTreeItemIdValue cookie;
  wxTreeItemId ti = GetFirstChild(node, cookie);

  while (ti) {
    const wxString itemText = GetItemText(ti);
    if (itemText == s.c_str()) {
      si = ti;
      return true;
    }
    ti = GetNextSibling(ti);
  }
  return false;
}

wxTreeItemId PWSTreeCtrl::AddGroup(const StringX &group)
{
  wxTreeItemId ti = GetRootItem();
  if (!ti.IsOk())
    ti=AddRoot(wxString());

  // Add a group at the end of path
  wxTreeItemId si;
  if (!group.empty()) {
    StringX path = group;
    StringX s;
    do {
      s = GetPathElem(path);
      if (!ExistsInTree(ti, s, si)) {
        ti = AppendItem(ti, s.c_str());
        // SetItemImage(ti, CPWTreeCtrl::NODE, CPWTreeCtrl::NODE);
      } else
        ti = si;
    } while (!path.empty());
  }
  return ti;
}

wxString PWSTreeCtrl::ItemDisplayString(const CItemData &item) const
{
  wxString title = item.GetTitle().c_str();
  wxString user = item.GetUser().c_str();
  wxString disp = title;
  if (!user.empty())
    disp += _T(" [") + user + _("]");
  return disp;
}

wxString PWSTreeCtrl::GetPath(const wxTreeItemId &node) const
{
  wxString retval;
  std::vector<wxString> v;
  const wxTreeItemId root = GetRootItem();
  wxTreeItemId parent = GetItemParent(node);

  while (parent != root) {
    v.push_back(GetItemText(parent));
    parent = GetItemParent(parent);
  }
  std::vector<wxString>::reverse_iterator iter;
  for(iter = v.rbegin(); iter != v.rend(); iter++) {
    retval += *iter;
    if ((iter + 1) != v.rend())
      retval += _(".");
  }
  return retval;
}

void PWSTreeCtrl::UpdateItem(const CItemData &item)
{
  const wxTreeItemId node = Find(item);
  if (node.IsOk()) {
    const wxString oldGroup = GetPath(node);
    const wxString newGroup = item.GetGroup().c_str();
    if (oldGroup == newGroup) {
      const wxString disp = ItemDisplayString(item);
      SetItemText(node, disp);
    } else { // uh-oh - group's changed
      uuid_array_t uuid;
      item.GetUUID(uuid);
      // remove old item
      m_item_map.erase(CUUIDGen(uuid));
      Delete(node);
      // add new group
      AddItem(item);
    }
    Update();
  }
}

void PWSTreeCtrl::AddItem(const CItemData &item)
{
  wxTreeItemData *data = new PWTreeItemData(item);
  wxTreeItemId gnode = AddGroup(item.GetGroup());
  const wxString disp = ItemDisplayString(item);
  wxTreeItemId titem = AppendItem(gnode, disp, -1, -1, data);
  uuid_array_t uuid;
  item.GetUUID(uuid);
  m_item_map.insert(std::make_pair(CUUIDGen(uuid), titem));
}

const CItemData *PWSTreeCtrl::GetItem(const wxTreeItemId &id) const
{
  if (!id.IsOk())
    return NULL;

  PWTreeItemData *itemData = dynamic_cast<PWTreeItemData *>(GetItemData(id));
  // return if a group is selected
  if (itemData == NULL)
    return NULL;

  ItemListConstIter citer = m_core.Find(itemData->GetUUID());
  if (citer == m_core.GetEntryEndIter())
    return NULL;
  return &citer->second;

}

wxTreeItemId PWSTreeCtrl::Find(const uuid_array_t &uuid) const
{
  wxTreeItemId fail;
  CUUIDGen cuuid(uuid);
  UUIDTIMapT::const_iterator iter = m_item_map.find(cuuid);
  if (iter != m_item_map.end())
    return iter->second;
  else
    return fail;
}

wxTreeItemId PWSTreeCtrl::Find(const CItemData &item) const
{
  uuid_array_t uuid;
  item.GetUUID(uuid);
  return Find(uuid);
}

bool PWSTreeCtrl::Remove(const uuid_array_t &uuid)
{
  wxTreeItemId id = Find(uuid);
  if (id.IsOk()) {
    m_item_map.erase(CUUIDGen(uuid));
    Delete(id);
    Refresh();
    Update();
    return true;
  } else {
    return false;
  }
}

/*!
 * wxEVT_COMMAND_TREE_ITEM_ACTIVATED event handler for ID_TREECTRL
 */

void PWSTreeCtrl::OnTreectrlItemActivated( wxTreeEvent& event )
{
  const CItemData *item = GetItem(event.GetItem());
  if (item != NULL)
    PWSdca::Doit(*item);
}

/*!
 * wxEVT_RIGHT_DOWN event handler for ID_TREECTRL
 */

void PWSTreeCtrl::OnRightDown( wxMouseEvent& event )
{
////@begin wxEVT_RIGHT_DOWN event handler for ID_TREECTRL in PWSTreeCtrl.
  // Before editing this code, remove the block markers.
  wxMessageBox(_("RightClick!"));
////@end wxEVT_RIGHT_DOWN event handler for ID_TREECTRL in PWSTreeCtrl.
}

<|endoftext|>


<commit_before>#include <boost/optional.hpp>

#include "move.hh"
#include "../../../src/contents.hh"

namespace vick {
namespace move {

boost::optional< std::shared_ptr<change> > mvsot(contents& contents, boost::optional<int>) {
    contents.x = 0;
    for(auto x : contents.cont[contents.y]) {
        if(x == ' ' || x == '\t') contents.x++;
        else break;
    }
    return boost::none;
}

}
}
<commit_msg>`mvsot()` will set `contents.waiting_for_desired` to false.<commit_after>#include <boost/optional.hpp>

#include "move.hh"
#include "../../../src/contents.hh"

namespace vick {
namespace move {

boost::optional< std::shared_ptr<change> > mvsot(contents& contents, boost::optional<int>) {
    contents.waiting_for_desired = false;
    contents.x = 0;
    for(auto x : contents.cont[contents.y]) {
        if(x == ' ' || x == '\t') contents.x++;
        else break;
    }
    return boost::none;
}

}
}
<|endoftext|>


<commit_before>

#include "daemon.hpp"
#include "signals.hpp"

// posix
#include <syslog.h>
#include <unistd.h> // optarg
#include <getopt.h> // for getopt_long

// libc
#include <csignal>
#include <cassert>

// std
#include <fstream> // read config file
#include <iostream> // read config file
#include <string>

struct config{
	// put here all configurations of the service
	unsigned int delay = 0;
	std::string conf_file_name;
};

const char daemon_name[] = "my_daemon";

std::pair<bool, config> read_conf_file(const std::string& conf_file_name)
{
	config cfg;
	std::fstream myfile(conf_file_name, std::ios_base::in);
	unsigned int a;
	bool ok = false;
	if (myfile >> a)
	{
		ok = true;
		cfg.delay = a;
	}

	return {ok,cfg};
}

int main(const int argc, char* const argv[]) try {
	const option options[] = {
	    {"config_file", required_argument, nullptr, 'c'},
	    {"help", no_argument, nullptr, 'h'},
	    {"daemon", no_argument, nullptr, 'd'},
	    {"pid_file", required_argument, nullptr, 'p'},
	    {nullptr, 0, 0, 0}
	};
	int value = 0;
	int option_index = 0;
	std::string pid_file_name;
	bool daemonize = false; // easier to debug since it avoid forking

	config conf;

	// FIXME: process all command line arguments
	while ((value = getopt_long(argc, argv, "c:p:d:h", options, &option_index)) != -1) {
		switch (value) {
			case 'c':
				conf.conf_file_name = optarg;
				break;
			case 'l':
				break;
			case 'p':
				pid_file_name = optarg;
				break;
			case 'd':
				daemonize = true;
				break;
			case 'h':
			case '?':
				// show help and exit
				return EXIT_SUCCESS;
			default:
				std::cerr << "unrecognized value: " << static_cast<char>(value) << "\n";
				return EXIT_FAILURE;
		}
	}

	// When daemonizing is requested at command line.
	if(daemonize){
		::daemonize();
	}
	locked_file lf;

	if(!pid_file_name.empty()){
		lf = create_pid_file(pid_file_name);
	}

	// Open system log and write message to it
	openlog(daemon_name, LOG_PID|LOG_CONS, LOG_DAEMON);
	const syslog_closer cl;
	syslog(LOG_INFO, "%s has been started", daemon_name);

	// Read configuration from config file (before registering signal for reloading configuration, otherwise update global flag)
	auto res = read_conf_file(conf.conf_file_name);
	if(res.first){
		conf = res.second;
	}else{
		syslog(LOG_ERR, "error while loading configuration");
		return EXIT_FAILURE;
	}

	// register signals
	signal(SIGINT, handle_SIGINT);
	signal(SIGHUP, handle_SIGHUP);
	syslog(LOG_INFO, "registered signals");

	// This global variable can be changed in function handling signal
	g_sig_int_flag = sig_int_stat::not_received;

	// Never ending loop of server
	int counter = 0;
	while (g_sig_int_flag == sig_int_stat::not_received) {
		// check if we need to reload configuration
		if(g_reload_conf_flag == reload_conf_stat::reload){
			const update_flag up(g_reload_conf_flag, reload_conf_stat::reloading, reload_conf_stat::done);
			const auto conf_tmp = read_conf_file(conf.conf_file_name);
			if(conf_tmp.first){
				syslog(LOG_INFO, "configuration reloaded successfully");
				conf = conf_tmp.second;
			}else{
				syslog(LOG_ERR, "error while reloading configuration");
			}
		}

		// do something useful here
		{
			syslog(LOG_INFO, "daemon running (%d)", counter++);
		}

		// Real server should use select() or poll() for waiting at async event.
		// Note: sleep() is interrupted, when signal is received.
		sleep(conf.delay);

	}

	assert(g_sig_int_flag == sig_int_stat::received && "we should have received a sig_int signal!");
	syslog(LOG_INFO, "stopping daemon");

	// Write system log and close it.
	syslog(LOG_INFO, "Stopped %s", daemon_name);

	return EXIT_SUCCESS;
}catch(const std::exception& ex){
	std::cerr << "Failed with ex: " << ex.what() << "\n";
	return EXIT_FAILURE;
}catch(...){
std::cerr << "Failed with unknown exception\n";
throw; // rethrow, we may get some further information from the runtime
}
<commit_msg>removed configuration file name from structure in order to avoid to overwrite it<commit_after>

#include "daemon.hpp"
#include "signals.hpp"

// posix
#include <syslog.h>
#include <unistd.h> // optarg
#include <getopt.h> // for getopt_long

// libc
#include <csignal>
#include <cassert>

// std
#include <fstream> // read config file
#include <iostream> // read config file
#include <string>

struct config{
	// put here all configurations of the service
	unsigned int delay = 0;
};
std::string conf_file_name;

const char daemon_name[] = "my_daemon";

std::pair<bool, config> read_conf_file(const std::string& conf_file_name)
{
	config cfg;
	std::fstream myfile(conf_file_name, std::ios_base::in);
	unsigned int a;
	bool ok = false;
	if (myfile >> a)
	{
		ok = true;
		cfg.delay = a;
	}

	return {ok,cfg};
}

int main(const int argc, char* const argv[]) try {
	const option options[] = {
	    {"config_file", required_argument, nullptr, 'c'},
	    {"help", no_argument, nullptr, 'h'},
	    {"daemon", no_argument, nullptr, 'd'},
	    {"pid_file", required_argument, nullptr, 'p'},
	    {nullptr, 0, 0, 0}
	};
	int value = 0;
	int option_index = 0;
	std::string pid_file_name;
	bool daemonize = false; // easier to debug since it avoid forking

	config conf;

	// FIXME: process all command line arguments
	while ((value = getopt_long(argc, argv, "c:p:d:h", options, &option_index)) != -1) {
		switch (value) {
			case 'c':
				conf_file_name = optarg;
				break;
			case 'l':
				break;
			case 'p':
				pid_file_name = optarg;
				break;
			case 'd':
				daemonize = true;
				break;
			case 'h':
			case '?':
				// show help and exit
				return EXIT_SUCCESS;
			default:
				std::cerr << "unrecognized value: " << static_cast<char>(value) << "\n";
				return EXIT_FAILURE;
		}
	}

	// When daemonizing is requested at command line.
	if(daemonize){
		::daemonize();
	}
	locked_file lf;

	if(!pid_file_name.empty()){
		lf = create_pid_file(pid_file_name);
	}

	// Open system log and write message to it
	openlog(daemon_name, LOG_PID|LOG_CONS, LOG_DAEMON);
	const syslog_closer cl;
	syslog(LOG_INFO, "%s has been started", daemon_name);

	// Read configuration from config file (before registering signal for reloading configuration, otherwise update global flag)
	auto res = read_conf_file(conf_file_name);
	if(res.first){
		conf = res.second;
	}else{
		syslog(LOG_ERR, "error while loading configuration");
		return EXIT_FAILURE;
	}

	// register signals
	signal(SIGINT, handle_SIGINT);
	signal(SIGHUP, handle_SIGHUP);
	syslog(LOG_INFO, "registered signals");

	// This global variable can be changed in function handling signal
	g_sig_int_flag = sig_int_stat::not_received;

	// Never ending loop of server
	int counter = 0;
	while (g_sig_int_flag == sig_int_stat::not_received) {
		// check if we need to reload configuration
		if(g_reload_conf_flag == reload_conf_stat::reload){
			const update_flag up(g_reload_conf_flag, reload_conf_stat::reloading, reload_conf_stat::done);
			const auto conf_tmp = read_conf_file(conf_file_name);
			if(conf_tmp.first){
				syslog(LOG_INFO, "configuration reloaded successfully");
				conf = conf_tmp.second;
			}else{
				syslog(LOG_ERR, "error while reloading configuration");
			}
		}

		// do something useful here
		{
			syslog(LOG_INFO, "daemon running (%d)", counter++);
		}

		// Real server should use select() or poll() for waiting at async event.
		// Note: sleep() is interrupted, when signal is received.
		sleep(conf.delay);

	}

	assert(g_sig_int_flag == sig_int_stat::received && "we should have received a sig_int signal!");
	syslog(LOG_INFO, "stopping daemon");

	// Write system log and close it.
	syslog(LOG_INFO, "Stopped %s", daemon_name);

	return EXIT_SUCCESS;
}catch(const std::exception& ex){
	std::cerr << "Failed with ex: " << ex.what() << "\n";
	return EXIT_FAILURE;
}catch(...){
std::cerr << "Failed with unknown exception\n";
throw; // rethrow, we may get some further information from the runtime
}
<|endoftext|>


<commit_before>#include <fc/crypto/elliptic_r1.hpp>
#include <fc/crypto/openssl.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/crypto/signature.hpp>
#include <fc/crypto/public_key.hpp>

#include <boost/program_options.hpp>

#include <Security/Security.h>

#include <array>
#include "r1_signature_compactor.hpp"

#include <fc/crypto/public_key.hpp>
#include <fc/crypto/private_key.hpp>
#include <fc/crypto/signature.hpp>

namespace po = boost::program_options;
using namespace std;
using namespace fc::crypto::r1;

//get a copy of our key info, should it exist in the keychain
CFDictionaryRef CopyOurKeyInfo() {
   const void* keyAttrKeys[] = {
      kSecClass,
      kSecAttrKeyClass,
      kSecAttrApplicationTag,
      kSecReturnAttributes,
      kSecReturnRef
   };
   const void* keyAttrValues[] = {
      kSecClassKey,
      kSecAttrKeyClassPrivate,
      CFSTR("one.block.applesedemo"),
      kCFBooleanTrue,
      kCFBooleanTrue
   };
   CFDictionaryRef keyAttrDic = CFDictionaryCreate(nullptr, keyAttrKeys, keyAttrValues, sizeof(keyAttrKeys)/sizeof(keyAttrKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

   CFDictionaryRef attributes = nullptr;
   OSStatus ret = SecItemCopyMatching(keyAttrDic, (CFTypeRef*)&attributes);

   CFRelease(keyAttrDic);
   return attributes;
}

SecKeyRef CopyOurKey() {
   CFDictionaryRef attributes = CopyOurKeyInfo();
   if(!attributes)
      return nullptr;
   SecKeyRef key = (SecKeyRef)CFDictionaryGetValue(attributes, kSecValueRef);
   if(key)
      CFRetain(key);
   CFRelease(attributes);
   return key;
}

public_key_data get_compressed_pub_for_key(SecKeyRef key) {
   SecKeyRef pubkey = SecKeyCopyPublicKey(key);

   CFErrorRef error = nullptr;
   CFDataRef keyrep = SecKeyCopyExternalRepresentation(pubkey, &error);
   assert(CFDataGetLength(keyrep) == 65);

   public_key_data pub_key_data;
   const UInt8* cfdata = CFDataGetBytePtr(keyrep);

   memcpy(pub_key_data.data+1, cfdata+1, 32);
   pub_key_data.data[0] = 0x02 + (cfdata[64]&1);

   CFRelease(keyrep);
   CFRelease(pubkey);

   return pub_key_data;
}

void print_pub_for_key(SecKeyRef key) {
   fc::crypto::checksummed_data<fc::crypto::r1::public_key_data> pub_wrapper;
   pub_wrapper.data = get_compressed_pub_for_key(key);
   pub_wrapper.check = fc::crypto::checksummed_data<fc::crypto::r1::public_key_data>::calculate_checksum(pub_wrapper.data, "R1");
   std::vector<char> checksummed = fc::raw::pack(pub_wrapper);

   cout << "public_key(EOSR1" << fc::to_base58(checksummed.data(), checksummed.size()) << ")" << endl;
}

void print_attributes() {
   CFDictionaryRef key_info = CopyOurKeyInfo();
   if(!key_info)
      cout << "No key currently in SE" << endl;
   else {
      CFShow(key_info);
      CFRelease(key_info);
   }

   SecKeyRef key = CopyOurKey();
   print_pub_for_key(key);
   CFRelease(key);
}

void remove() {
   SecKeyRef key = CopyOurKey();
   if(!key) {
      cout << "No key current in SE" << endl;
      return;
   }
   CFRelease(key);
   //hmmm. previously I was trying to delete based on the key reference; no such luck

   const void* deleteKeys[] = {
      kSecClass,
      kSecAttrApplicationTag,
   };
   const void* deleteValues[] = {
      kSecClassKey,
      CFSTR("one.block.applesedemo"),
   };
   CFDictionaryRef deleteDic = CFDictionaryCreate(nullptr, deleteKeys, deleteValues, sizeof(deleteKeys)/sizeof(deleteKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

   OSStatus ret = SecItemDelete(deleteDic);
   if(!ret)
      cout << "Successfully removed key" << endl;
   else
      cout << "Error removing key " << ret << endl;

   CFRelease(deleteDic);
}

void create(SecAccessControlCreateFlags flags) {
   SecKeyRef key = CopyOurKey();
   if(key) {
      cout << "Already have a key in SE; not creating more" << endl;
      CFRelease(key);
      return;
   }

   SecAccessControlRef accessControlRef = SecAccessControlCreateWithFlags(nullptr, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, flags | kSecAccessControlPrivateKeyUsage, nullptr);

   int keySizeValue = 256;
   CFNumberRef keySizeNumber = CFNumberCreate(NULL, kCFNumberIntType, &keySizeValue);

   const void* keyAttrKeys[] = {
      kSecAttrIsPermanent,
      kSecAttrApplicationTag,
      kSecAttrAccessControl
   };
   const void* keyAttrValues[] = {
      kCFBooleanTrue,
      CFSTR("one.block.applesedemo"),
      accessControlRef
   };
   CFDictionaryRef keyAttrDic = CFDictionaryCreate(NULL, keyAttrKeys, keyAttrValues, sizeof(keyAttrKeys)/sizeof(keyAttrKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

   const void* attrKeys[] = {
      kSecAttrKeyType,
      kSecAttrKeySizeInBits,
      kSecAttrTokenID,
      kSecPrivateKeyAttrs
   };
   const void* atrrValues[] = {
      kSecAttrKeyTypeECSECPrimeRandom,
      keySizeNumber,
      kSecAttrTokenIDSecureEnclave,
      keyAttrDic
   };
   CFDictionaryRef attributesDic = CFDictionaryCreate(NULL, attrKeys, atrrValues, sizeof(attrKeys)/sizeof(atrrValues[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

   CFErrorRef error = NULL;
   SecKeyRef privateKey = SecKeyCreateRandomKey(attributesDic, &error);
   if(error) {
      cout << "Failed" << endl;
      CFShow(error);
   }
   else {
      cout << "Successfully created" << endl;
      print_pub_for_key(privateKey);
      CFRelease(privateKey);
   }

   CFRelease(attributesDic);
   CFRelease(keyAttrDic);
   CFRelease(keySizeNumber);
   CFRelease(accessControlRef);
}

void sign(const string& hex) {
   SecKeyRef key = CopyOurKey();
   if(!key) {
      cout << "No key currently in SE" << endl;
      return;
   }

   fc::ecdsa_sig sig = ECDSA_SIG_new();
   const UInt8* der_bytes = nullptr;
   fc::sha256 digest(hex);
   CFErrorRef error = nullptr;
   fc::crypto::r1::compact_signature compacted;
   public_key_data pub;
   fc::crypto::checksummed_data<fc::crypto::r1::compact_signature> signature_wrapper;
   std::vector<char> checksummed;
   std::string blah;

   CFDataRef digestData = CFDataCreateWithBytesNoCopy(nullptr, (UInt8*)digest.data(), digest.data_size(), kCFAllocatorNull);

   //the X9.62 representation of r & s must be exactly 32 bytes or otherwise the "canonical" check fails
   while(true) {
      CFDataRef signature = SecKeyCreateSignature(key, kSecKeyAlgorithmECDSASignatureDigestX962SHA256, digestData, &error);
      if(error) {
         cout << "Failed to sign" << endl;
         CFShow(error);
         goto err;
      }

      der_bytes = CFDataGetBytePtr(signature);
      assert(der_bytes[0] == 0x30);
      assert(der_bytes[2] == 0x02);
      assert(der_bytes[4+der_bytes[3]] == 0x02);

      UInt8 rLen, sLen;
      rLen = der_bytes[3];
      sLen = der_bytes[5+32];
      CFRelease(signature);
      if(rLen == 32 && sLen == 32)
         break;
   }

   BN_bin2bn(der_bytes+4, der_bytes[3], sig->r);
   BN_bin2bn(der_bytes+6+der_bytes[3], der_bytes[4+der_bytes[3]+1], sig->s);

   pub = get_compressed_pub_for_key(key);

   signature_wrapper.data = compact_r1(pub, sig, digest);
   signature_wrapper.check = fc::crypto::checksummed_data<fc::crypto::r1::compact_signature>::calculate_checksum(signature_wrapper.data, "R1");
   checksummed = fc::raw::pack(signature_wrapper);

   cout << "signature(EOSR1" << fc::to_base58(checksummed.data(), checksummed.size()) << ")" << endl;

err:
   CFRelease(key);
   CFRelease(digestData);
}

void recover(vector<string> params) {
   fc::sha256 digest(params[0]);
   fc::crypto::signature sig(params[1]);

   cout << fc::crypto::public_key(sig, digest) << endl;
}

int main(int argc, char* argv[]) {
   pid_t pid = getpid();
   SecCodeRef code = nullptr;
   CFNumberRef pidnumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pid);
   CFDictionaryRef piddict = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&kSecGuestAttributePid, (const void**)&pidnumber, 1, nullptr, nullptr);
   if(!SecCodeCopyGuestWithAttributes(nullptr, piddict, kSecCSDefaultFlags, &code)) {
      if(SecCodeCheckValidity(code, kSecCSDefaultFlags, 0)) {
         cout << "This application is NOT signed. For access to the secure enclave the application must be signed. Exiting." << endl;
         return 1;
      }
      CFRelease(code);
   }
   CFRelease(piddict);
   CFRelease(pidnumber);

   po::options_description desc_help;
   desc_help.add_options()("help", "halp");

   po::options_description desc_create("Create and store a key; This application only allows a single key to be stored at a time");
   desc_create.add_options()
      ("create-se", "Create a key to be stored in Secure Enclave; no TouchID requirements")
      ("create-se-interactive", "Create a key to be stored in Secure Enclave; fingerprint or password required on use")
      ("create-se-touch-only", "Create a key to be stored in Secure Enclave; fingerprint required on use");

   po::options_description desc_key("Other key operations");
   desc_key.add_options()
      ("print-attributes", "Print the attributes and public key of the stored key")
      ("remove", "Remove the key");

   po::options_description sign_key("Signing & Key Recovery");
   sign_key.add_options()
      ("sign", po::value<string>()->value_name("DIGEST"), "Sign sha256 via SE")
      ("recover", po::value<vector<string>>()->multitoken()->value_name("DIGEST COMPACT_SIG"), "Recover and print pubkey");

   po::options_description all_desc;
   all_desc.add(desc_create).add(desc_key).add(sign_key);
   po::options_description all_desc_and_help;
   all_desc_and_help.add(all_desc).add(desc_help);

   po::variables_map vm;
   po::store(po::parse_command_line(argc, argv, all_desc_and_help), vm);
   po::notify(vm);

   if(vm.count("create-se"))
      create(0);
   else if(vm.count("create-se-touch-only"))
      create(kSecAccessControlTouchIDAny);
   else if(vm.count("create-se-interactive"))
      create(kSecAccessControlUserPresence);
   else if(vm.count("print-attributes"))
      print_attributes();
   else if(vm.count("remove"))
      remove();
   else if(vm.count("sign"))
      sign(vm["sign"].as<string>());
   else if (!vm["recover"].empty() && vm["recover"].as<vector<string>>().size() == 2)
      recover(vm["recover"].as<vector<string>>());
   else
      cout << all_desc << endl;

   return 0;
}<commit_msg>Remove a couple of includes that are not required any more<commit_after>#include <fc/crypto/elliptic_r1.hpp>
#include <fc/crypto/openssl.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/crypto/signature.hpp>
#include <fc/crypto/public_key.hpp>

#include <boost/program_options.hpp>

#include <Security/Security.h>

#include <array>
#include "r1_signature_compactor.hpp"

namespace po = boost::program_options;
using namespace std;
using namespace fc::crypto::r1;

//get a copy of our key info, should it exist in the keychain
CFDictionaryRef CopyOurKeyInfo() {
   const void* keyAttrKeys[] = {
      kSecClass,
      kSecAttrKeyClass,
      kSecAttrApplicationTag,
      kSecReturnAttributes,
      kSecReturnRef
   };
   const void* keyAttrValues[] = {
      kSecClassKey,
      kSecAttrKeyClassPrivate,
      CFSTR("one.block.applesedemo"),
      kCFBooleanTrue,
      kCFBooleanTrue
   };
   CFDictionaryRef keyAttrDic = CFDictionaryCreate(nullptr, keyAttrKeys, keyAttrValues, sizeof(keyAttrKeys)/sizeof(keyAttrKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

   CFDictionaryRef attributes = nullptr;
   OSStatus ret = SecItemCopyMatching(keyAttrDic, (CFTypeRef*)&attributes);

   CFRelease(keyAttrDic);
   return attributes;
}

SecKeyRef CopyOurKey() {
   CFDictionaryRef attributes = CopyOurKeyInfo();
   if(!attributes)
      return nullptr;
   SecKeyRef key = (SecKeyRef)CFDictionaryGetValue(attributes, kSecValueRef);
   if(key)
      CFRetain(key);
   CFRelease(attributes);
   return key;
}

public_key_data get_compressed_pub_for_key(SecKeyRef key) {
   SecKeyRef pubkey = SecKeyCopyPublicKey(key);

   CFErrorRef error = nullptr;
   CFDataRef keyrep = SecKeyCopyExternalRepresentation(pubkey, &error);
   assert(CFDataGetLength(keyrep) == 65);

   public_key_data pub_key_data;
   const UInt8* cfdata = CFDataGetBytePtr(keyrep);

   memcpy(pub_key_data.data+1, cfdata+1, 32);
   pub_key_data.data[0] = 0x02 + (cfdata[64]&1);

   CFRelease(keyrep);
   CFRelease(pubkey);

   return pub_key_data;
}

void print_pub_for_key(SecKeyRef key) {
   fc::crypto::checksummed_data<fc::crypto::r1::public_key_data> pub_wrapper;
   pub_wrapper.data = get_compressed_pub_for_key(key);
   pub_wrapper.check = fc::crypto::checksummed_data<fc::crypto::r1::public_key_data>::calculate_checksum(pub_wrapper.data, "R1");
   std::vector<char> checksummed = fc::raw::pack(pub_wrapper);

   cout << "public_key(EOSR1" << fc::to_base58(checksummed.data(), checksummed.size()) << ")" << endl;
}

void print_attributes() {
   CFDictionaryRef key_info = CopyOurKeyInfo();
   if(!key_info)
      cout << "No key currently in SE" << endl;
   else {
      CFShow(key_info);
      CFRelease(key_info);
   }

   SecKeyRef key = CopyOurKey();
   print_pub_for_key(key);
   CFRelease(key);
}

void remove() {
   SecKeyRef key = CopyOurKey();
   if(!key) {
      cout << "No key current in SE" << endl;
      return;
   }
   CFRelease(key);
   //hmmm. previously I was trying to delete based on the key reference; no such luck

   const void* deleteKeys[] = {
      kSecClass,
      kSecAttrApplicationTag,
   };
   const void* deleteValues[] = {
      kSecClassKey,
      CFSTR("one.block.applesedemo"),
   };
   CFDictionaryRef deleteDic = CFDictionaryCreate(nullptr, deleteKeys, deleteValues, sizeof(deleteKeys)/sizeof(deleteKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

   OSStatus ret = SecItemDelete(deleteDic);
   if(!ret)
      cout << "Successfully removed key" << endl;
   else
      cout << "Error removing key " << ret << endl;

   CFRelease(deleteDic);
}

void create(SecAccessControlCreateFlags flags) {
   SecKeyRef key = CopyOurKey();
   if(key) {
      cout << "Already have a key in SE; not creating more" << endl;
      CFRelease(key);
      return;
   }

   SecAccessControlRef accessControlRef = SecAccessControlCreateWithFlags(nullptr, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, flags | kSecAccessControlPrivateKeyUsage, nullptr);

   int keySizeValue = 256;
   CFNumberRef keySizeNumber = CFNumberCreate(NULL, kCFNumberIntType, &keySizeValue);

   const void* keyAttrKeys[] = {
      kSecAttrIsPermanent,
      kSecAttrApplicationTag,
      kSecAttrAccessControl
   };
   const void* keyAttrValues[] = {
      kCFBooleanTrue,
      CFSTR("one.block.applesedemo"),
      accessControlRef
   };
   CFDictionaryRef keyAttrDic = CFDictionaryCreate(NULL, keyAttrKeys, keyAttrValues, sizeof(keyAttrKeys)/sizeof(keyAttrKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

   const void* attrKeys[] = {
      kSecAttrKeyType,
      kSecAttrKeySizeInBits,
      kSecAttrTokenID,
      kSecPrivateKeyAttrs
   };
   const void* atrrValues[] = {
      kSecAttrKeyTypeECSECPrimeRandom,
      keySizeNumber,
      kSecAttrTokenIDSecureEnclave,
      keyAttrDic
   };
   CFDictionaryRef attributesDic = CFDictionaryCreate(NULL, attrKeys, atrrValues, sizeof(attrKeys)/sizeof(atrrValues[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

   CFErrorRef error = NULL;
   SecKeyRef privateKey = SecKeyCreateRandomKey(attributesDic, &error);
   if(error) {
      cout << "Failed" << endl;
      CFShow(error);
   }
   else {
      cout << "Successfully created" << endl;
      print_pub_for_key(privateKey);
      CFRelease(privateKey);
   }

   CFRelease(attributesDic);
   CFRelease(keyAttrDic);
   CFRelease(keySizeNumber);
   CFRelease(accessControlRef);
}

void sign(const string& hex) {
   SecKeyRef key = CopyOurKey();
   if(!key) {
      cout << "No key currently in SE" << endl;
      return;
   }

   fc::ecdsa_sig sig = ECDSA_SIG_new();
   const UInt8* der_bytes = nullptr;
   fc::sha256 digest(hex);
   CFErrorRef error = nullptr;
   fc::crypto::r1::compact_signature compacted;
   public_key_data pub;
   fc::crypto::checksummed_data<fc::crypto::r1::compact_signature> signature_wrapper;
   std::vector<char> checksummed;
   std::string blah;

   CFDataRef digestData = CFDataCreateWithBytesNoCopy(nullptr, (UInt8*)digest.data(), digest.data_size(), kCFAllocatorNull);

   //the X9.62 representation of r & s must be exactly 32 bytes or otherwise the "canonical" check fails
   while(true) {
      CFDataRef signature = SecKeyCreateSignature(key, kSecKeyAlgorithmECDSASignatureDigestX962SHA256, digestData, &error);
      if(error) {
         cout << "Failed to sign" << endl;
         CFShow(error);
         goto err;
      }

      der_bytes = CFDataGetBytePtr(signature);
      assert(der_bytes[0] == 0x30);
      assert(der_bytes[2] == 0x02);
      assert(der_bytes[4+der_bytes[3]] == 0x02);

      UInt8 rLen, sLen;
      rLen = der_bytes[3];
      sLen = der_bytes[5+32];
      CFRelease(signature);
      if(rLen == 32 && sLen == 32)
         break;
   }

   BN_bin2bn(der_bytes+4, der_bytes[3], sig->r);
   BN_bin2bn(der_bytes+6+der_bytes[3], der_bytes[4+der_bytes[3]+1], sig->s);

   pub = get_compressed_pub_for_key(key);

   signature_wrapper.data = compact_r1(pub, sig, digest);
   signature_wrapper.check = fc::crypto::checksummed_data<fc::crypto::r1::compact_signature>::calculate_checksum(signature_wrapper.data, "R1");
   checksummed = fc::raw::pack(signature_wrapper);

   cout << "signature(EOSR1" << fc::to_base58(checksummed.data(), checksummed.size()) << ")" << endl;

err:
   CFRelease(key);
   CFRelease(digestData);
}

void recover(vector<string> params) {
   fc::sha256 digest(params[0]);
   fc::crypto::signature sig(params[1]);

   cout << fc::crypto::public_key(sig, digest) << endl;
}

int main(int argc, char* argv[]) {
   pid_t pid = getpid();
   SecCodeRef code = nullptr;
   CFNumberRef pidnumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pid);
   CFDictionaryRef piddict = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&kSecGuestAttributePid, (const void**)&pidnumber, 1, nullptr, nullptr);
   if(!SecCodeCopyGuestWithAttributes(nullptr, piddict, kSecCSDefaultFlags, &code)) {
      if(SecCodeCheckValidity(code, kSecCSDefaultFlags, 0)) {
         cout << "This application is NOT signed. For access to the secure enclave the application must be signed. Exiting." << endl;
         return 1;
      }
      CFRelease(code);
   }
   CFRelease(piddict);
   CFRelease(pidnumber);

   po::options_description desc_help;
   desc_help.add_options()("help", "halp");

   po::options_description desc_create("Create and store a key; This application only allows a single key to be stored at a time");
   desc_create.add_options()
      ("create-se", "Create a key to be stored in Secure Enclave; no TouchID requirements")
      ("create-se-interactive", "Create a key to be stored in Secure Enclave; fingerprint or password required on use")
      ("create-se-touch-only", "Create a key to be stored in Secure Enclave; fingerprint required on use");

   po::options_description desc_key("Other key operations");
   desc_key.add_options()
      ("print-attributes", "Print the attributes and public key of the stored key")
      ("remove", "Remove the key");

   po::options_description sign_key("Signing & Key Recovery");
   sign_key.add_options()
      ("sign", po::value<string>()->value_name("DIGEST"), "Sign sha256 via SE")
      ("recover", po::value<vector<string>>()->multitoken()->value_name("DIGEST COMPACT_SIG"), "Recover and print pubkey");

   po::options_description all_desc;
   all_desc.add(desc_create).add(desc_key).add(sign_key);
   po::options_description all_desc_and_help;
   all_desc_and_help.add(all_desc).add(desc_help);

   po::variables_map vm;
   po::store(po::parse_command_line(argc, argv, all_desc_and_help), vm);
   po::notify(vm);

   if(vm.count("create-se"))
      create(0);
   else if(vm.count("create-se-touch-only"))
      create(kSecAccessControlTouchIDAny);
   else if(vm.count("create-se-interactive"))
      create(kSecAccessControlUserPresence);
   else if(vm.count("print-attributes"))
      print_attributes();
   else if(vm.count("remove"))
      remove();
   else if(vm.count("sign"))
      sign(vm["sign"].as<string>());
   else if (!vm["recover"].empty() && vm["recover"].as<vector<string>>().size() == 2)
      recover(vm["recover"].as<vector<string>>());
   else
      cout << all_desc << endl;

   return 0;
}<|endoftext|>