<commit_before>//
// AllianceCore.cpp
// Project Spitfire
//
// Copyright (c) 2013 Daizee (rensiadz at gmail dot com)
//
// This file is part of Spitfire.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "includes.h"
#include "AllianceCore.h"
#include "Alliance.h"
#include "Server.h"
#include "Client.h"

AllianceCore::AllianceCore(Server * server)
{
	m_main = server;
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		m_alliances[i] = 0;
	}
}

AllianceCore::~AllianceCore()
{
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i])
			delete m_alliances[i];
	}
}

void AllianceCore::DeleteAlliance(Alliance * alliance)
{
	int32_t found = 0;
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i])
		{
			if (m_alliances[i]->m_allianceid != alliance->m_allianceid)
			{
				if (m_alliances[i]->IsAlly(alliance->m_allianceid))
					m_alliances[i]->UnAlly(alliance->m_allianceid);
				if (m_alliances[i]->IsNeutral(alliance->m_allianceid))
					m_alliances[i]->UnNeutral(alliance->m_allianceid);
				if (m_alliances[i]->IsEnemy(alliance->m_allianceid))
					m_alliances[i]->UnEnemy(alliance->m_allianceid);

				for (Client * client : m_main->players)
				{
					if (client)
					{
						if ((client->m_allianceapply == alliance->m_name))
						{
							client->m_allianceapply = "";
							client->m_allianceapplytime = 0;
						}
					}
				}
			}
			else
			{
				found = i;
			}
		}
	}
	alliance->m_invites.clear();
	delete m_alliances[found];
	m_alliances[found] = 0;
}

Alliance * AllianceCore::CreateAlliance(string name, int64_t ownerid, int64_t allianceid)
{
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i] == 0)
		{
			m_alliances[i] = new Alliance(m_main, name, ownerid);
			if (allianceid == 0)
				m_alliances[i]->m_allianceid = m_main->m_allianceid++;
			else
				m_alliances[i]->m_allianceid = allianceid;
			return m_alliances[i];
		}
	}
	return 0;
}

bool AllianceCore::JoinAlliance(uint32_t allianceid, Client * client)
{
	if (client->m_allianceid > 0)
	{
		return false; //already in an alliance
	}
	Alliance * alliance = AllianceById(allianceid);
	if (alliance == (Alliance*)-1)
	{
		return false; //alliance doesn't exist
	}

	if (alliance->AddMember(client->m_accountid, DEF_ALLIANCEMEMBER))
	{
		client->m_allianceid = alliance->m_allianceid;
		client->m_alliancename = alliance->m_name;
		client->m_alliancerank = DEF_ALLIANCEMEMBER;
		client->PlayerUpdate();
		return true;
	}
	return false;
}

bool AllianceCore::RemoveFromAlliance(uint32_t allianceid, Client * client)
{
	if (client->m_allianceid <= 0)
	{
		return false; //not in an alliance
	}
	Alliance * alliance = AllianceById(allianceid);
	if (alliance == (Alliance*)-1)
	{
		return false; //alliance doesn't exist
	}

	alliance->RemoveMember(client->m_accountid);

	client->m_allianceid = 0;
	client->m_alliancename = "";
	client->m_alliancerank = 0;

	client->PlayerUpdate();
	return true;
}

bool AllianceCore::SetRank(uint32_t allianceid, Client * client, int8_t rank)
{
	if (client->m_allianceid <= 0)
	{
		return false; //no alliance id given
	}
	Alliance * alliance = AllianceById(allianceid);
	if (alliance == (Alliance*)-1)
	{
		return false; //alliance doesn't exist
	}

	for (int i = 0; i < alliance->m_members.size(); ++i)
	{
		if (alliance->m_members[i].clientid == client->m_accountid)
		{
			client->m_alliancerank = rank;
			alliance->m_members[i].rank = rank;
			return true;
		}
	}
	return false;
}

bool AllianceCore::CheckName(string name)
{
// 	char * tempname;
// 	tempname = new char[strlen(name)+1];
// 	memset(tempname, 0, strlen(name)+1);
// 	for (int i = 0; i < strlen(name); ++i)
// 		tempname[i] = tolower(name[i]);

	std::transform(name.begin(), name.end(), name.begin(), ::tolower);

	if (name.find("penis") != string::npos)
		return false;
	if (name.find("cock") != string::npos)
		return false;
	if (name.find("dick") != string::npos)
		return false;
	if (name.find("asshole") != string::npos)
		return false;
	if (name.find("fuck") != string::npos)
		return false;
	if (name.find("shit") != string::npos)
		return false;
	if (name.find("bitch") != string::npos)
		return false;
	if (name.find("tits") != string::npos)
		return false;
	if (name.find("cunt") != string::npos)
		return false;
	if (name.find("testicle") != string::npos)
		return false;
	if (name.find("queer") != string::npos)
		return false;
	if (name.find("fag") != string::npos)
		return false;
	if (name.find("gay") != string::npos)
		return false;
	if (name.find("homo") != string::npos)
		return false;
	if (name.find("whore") != string::npos)
		return false;
	if (name.find("nigger") != string::npos)
		return false;
	return true;
}

int16_t AllianceCore::GetRelation(int64_t client1, int64_t client2)
{
	if (client1 == client2)
		return DEF_SELFRELATION;

	Client * c1 = m_main->GetClient(client1);
	Client * c2 = m_main->GetClient(client2);

	if (!c1 || !c2 || c1->m_allianceid < 0 || c2->m_allianceid < 0)
		return DEF_NORELATION;

	if (c1->m_allianceid == c2->m_allianceid)
		return DEF_ALLIANCE;

	if (c1->m_allianceid <= 0 || c2->m_allianceid <= 0)
		return DEF_NORELATION;

	Alliance * a1 = m_alliances[c1->m_allianceid];
	Alliance * a2 = m_alliances[c2->m_allianceid];

	if (a1->IsEnemy(c2->m_allianceid))
		return DEF_ENEMY;
	else if (a1->IsAlly(c2->m_allianceid))
		return DEF_ALLY;
	else if (a1->IsNeutral(c2->m_allianceid))
		return DEF_NEUTRAL;
	else
		return DEF_NORELATION;
}

bool comparemembers(stAlliance first, stAlliance second)
{
	if (first.members > second.members)
		return true;
	else
		return false;
}
bool compareprestige(stAlliance first, stAlliance second)
{
	if (first.prestige > second.prestige)
		return true;
	else
		return false;
}
bool comparehonor(stAlliance first, stAlliance second)
{
	if (first.honor > second.honor)
		return true;
	else
		return false;
}

void AllianceCore::SortAlliances()
{
	m_main->mtxlist.alliance.lock_shared();
	m_membersrank.clear();
	m_prestigerank.clear();
	m_honorrank.clear();

	stAlliance stmem;
	stAlliance stpre;
	stAlliance sthon;
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i])
		{
			sthon.honor = stpre.prestige = 0;
			stmem.id = stpre.id = sthon.id = m_alliances[i]->m_allianceid;
			stmem.members = m_alliances[i]->m_members.size();
			m_alliances[i]->m_citycount = 0;
			for (int k = 0; k < m_alliances[i]->m_members.size(); ++k)
			{
				Client * client = m_main->GetClient(m_alliances[i]->m_members[k].clientid);
				if (client)
				{
					sthon.honor += client->m_honor;
					stpre.prestige += client->m_prestige;
					m_alliances[i]->m_citycount += client->m_citycount;
				}
			}
			stmem.ref = m_alliances[i];
			stpre.ref = m_alliances[i];
			sthon.ref = m_alliances[i];
			m_membersrank.push_back(stmem);
			m_prestigerank.push_back(stpre);
			m_honorrank.push_back(sthon);
		}
	}

	m_membersrank.sort(comparemembers);
	m_prestigerank.sort(compareprestige);
	m_honorrank.sort(comparehonor);

	int num = 1;
	for (stAlliance & alliance : m_membersrank)
	{
		alliance.rank = alliance.ref->m_membersrank = num++;
	}
	num = 1;
	for (stAlliance & alliance : m_prestigerank)
	{
		alliance.rank = alliance.ref->m_prestigerank = num++;
		alliance.ref->m_prestige = alliance->prestige;
	}
	num = 1;
	for (stAlliance & alliance : m_honorrank)
	{
		alliance.rank = alliance.ref->m_honorrank = num++;
		alliance.ref->m_honor = alliance->honor;
	}
	m_main->mtxlist.alliance.unlock_shared();
}

Alliance * AllianceCore::AllianceById(uint32_t id)
{
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i] && m_alliances[i]->m_allianceid == id)
		{
			return m_alliances[i];
		}
	}
	return (Alliance*)-1;
}

Alliance * AllianceCore::AllianceByName(string name)
{
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i] && m_alliances[i]->m_name == name)
		{
			return m_alliances[i];
		}
	}
	return (Alliance*)-1;
}

/*
struct stHero
{
	int32_t m_id;
	int16_t m_level;
	int8_t m_loyalty;
	int16_t m_management;
	int16_t m_managementbuffadded;
	int16_t m_power;
	int16_t m_powerbuffadded;
	int16_t m_stratagem;
	int16_t m_stratagembuffadded;
	int8_t m_status;

};
struct stResources
{
	double food;
	double stone;
	double iron;
	double wood;
	double gold;
};
struct stForts
{
	int32_t traps;
	int32_t abatis;
	int32_t towers;
	int32_t logs;
	int32_t trebs;
};
struct stTroops
{
	int32_t worker;
	int32_t warrior;
	int32_t scout;
	int32_t pike;
	int32_t sword;
	int32_t archer;
	int32_t cavalry;
	int32_t cataphract;
	int32_t transporter;
	int32_t ballista;
	int32_t ram;
	int32_t catapult;
};
struct stResult
{
	stResources resources;
	bool attackerwon;
};
struct stBuff
{
	string id;
	double endtime;
} m_buffs;
struct stResearch
{
	int16_t level;
	double endtime;
} m_research;
struct stAttacker
{
	stTroops troops;
	stBuff ** buffs;
	stResearch ** techs;
	PlayerCity * city;
	stHero hero;
};
struct stDefender
{
	stTroops troops;
	stForts forts;
	stBuff ** buffs;
	stResearch ** techs;
	PlayerCity * city;
	stHero hero;
};
stResult * CalculateBattle(stAttacker & attacker, stDefender & defender)
{

}*/

<commit_msg>Build test<commit_after>//
// AllianceCore.cpp
// Project Spitfire
//
// Copyright (c) 2013 Daizee (rensiadz at gmail dot com)
//
// This file is part of Spitfire.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "includes.h"
#include "AllianceCore.h"
#include "Alliance.h"
#include "Server.h"
#include "Client.h"

AllianceCore::AllianceCore(Server * server)
{
	m_main = server;
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		m_alliances[i] = 0;
	}
}

AllianceCore::~AllianceCore()
{
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i])
			delete m_alliances[i];
	}
}

void AllianceCore::DeleteAlliance(Alliance * alliance)
{
	int32_t found = 0;
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i])
		{
			if (m_alliances[i]->m_allianceid != alliance->m_allianceid)
			{
				if (m_alliances[i]->IsAlly(alliance->m_allianceid))
					m_alliances[i]->UnAlly(alliance->m_allianceid);
				if (m_alliances[i]->IsNeutral(alliance->m_allianceid))
					m_alliances[i]->UnNeutral(alliance->m_allianceid);
				if (m_alliances[i]->IsEnemy(alliance->m_allianceid))
					m_alliances[i]->UnEnemy(alliance->m_allianceid);

				for (Client * client : m_main->players)
				{
					if (client)
					{
						if ((client->m_allianceapply == alliance->m_name))
						{
							client->m_allianceapply = "";
							client->m_allianceapplytime = 0;
						}
					}
				}
			}
			else
			{
				found = i;
			}
		}
	}
	alliance->m_invites.clear();
	delete m_alliances[found];
	m_alliances[found] = 0;
}

Alliance * AllianceCore::CreateAlliance(string name, int64_t ownerid, int64_t allianceid)
{
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i] == 0)
		{
			m_alliances[i] = new Alliance(m_main, name, ownerid);
			if (allianceid == 0)
				m_alliances[i]->m_allianceid = m_main->m_allianceid++;
			else
				m_alliances[i]->m_allianceid = allianceid;
			return m_alliances[i];
		}
	}
	return 0;
}

bool AllianceCore::JoinAlliance(uint32_t allianceid, Client * client)
{
	if (client->m_allianceid > 0)
	{
		return false; //already in an alliance
	}
	Alliance * alliance = AllianceById(allianceid);
	if (alliance == (Alliance*)-1)
	{
		return false; //alliance doesn't exist
	}

	if (alliance->AddMember(client->m_accountid, DEF_ALLIANCEMEMBER))
	{
		client->m_allianceid = alliance->m_allianceid;
		client->m_alliancename = alliance->m_name;
		client->m_alliancerank = DEF_ALLIANCEMEMBER;
		client->PlayerUpdate();
		return true;
	}
	return false;
}

bool AllianceCore::RemoveFromAlliance(uint32_t allianceid, Client * client)
{
	if (client->m_allianceid <= 0)
	{
		return false; //not in an alliance
	}
	Alliance * alliance = AllianceById(allianceid);
	if (alliance == (Alliance*)-1)
	{
		return false; //alliance doesn't exist
	}

	alliance->RemoveMember(client->m_accountid);

	client->m_allianceid = 0;
	client->m_alliancename = "";
	client->m_alliancerank = 0;

	client->PlayerUpdate();
	return true;
}

bool AllianceCore::SetRank(uint32_t allianceid, Client * client, int8_t rank)
{
	if (client->m_allianceid <= 0)
	{
		return false; //no alliance id given
	}
	Alliance * alliance = AllianceById(allianceid);
	if (alliance == (Alliance*)-1)
	{
		return false; //alliance doesn't exist
	}

	for (int i = 0; i < alliance->m_members.size(); ++i)
	{
		if (alliance->m_members[i].clientid == client->m_accountid)
		{
			client->m_alliancerank = rank;
			alliance->m_members[i].rank = rank;
			return true;
		}
	}
	return false;
}

bool AllianceCore::CheckName(string name)
{
// 	char * tempname;
// 	tempname = new char[strlen(name)+1];
// 	memset(tempname, 0, strlen(name)+1);
// 	for (int i = 0; i < strlen(name); ++i)
// 		tempname[i] = tolower(name[i]);

	std::transform(name.begin(), name.end(), name.begin(), ::tolower);

	if (name.find("penis") != string::npos)
		return false;
	if (name.find("cock") != string::npos)
		return false;
	if (name.find("dick") != string::npos)
		return false;
	if (name.find("asshole") != string::npos)
		return false;
	if (name.find("fuck") != string::npos)
		return false;
	if (name.find("shit") != string::npos)
		return false;
	if (name.find("bitch") != string::npos)
		return false;
	if (name.find("tits") != string::npos)
		return false;
	if (name.find("cunt") != string::npos)
		return false;
	if (name.find("testicle") != string::npos)
		return false;
	if (name.find("queer") != string::npos)
		return false;
	if (name.find("fag") != string::npos)
		return false;
	if (name.find("gay") != string::npos)
		return false;
	if (name.find("homo") != string::npos)
		return false;
	if (name.find("whore") != string::npos)
		return false;
	if (name.find("nigger") != string::npos)
		return false;
	return true;
}

int16_t AllianceCore::GetRelation(int64_t client1, int64_t client2)
{
	if (client1 == client2)
		return DEF_SELFRELATION;

	Client * c1 = m_main->GetClient(client1);
	Client * c2 = m_main->GetClient(client2);

	if (!c1 || !c2 || c1->m_allianceid < 0 || c2->m_allianceid < 0)
		return DEF_NORELATION;

	if (c1->m_allianceid == c2->m_allianceid)
		return DEF_ALLIANCE;

	if (c1->m_allianceid <= 0 || c2->m_allianceid <= 0)
		return DEF_NORELATION;

	Alliance * a1 = m_alliances[c1->m_allianceid];
	Alliance * a2 = m_alliances[c2->m_allianceid];

	if (a1->IsEnemy(c2->m_allianceid))
		return DEF_ENEMY;
	else if (a1->IsAlly(c2->m_allianceid))
		return DEF_ALLY;
	else if (a1->IsNeutral(c2->m_allianceid))
		return DEF_NEUTRAL;
	else
		return DEF_NORELATION;
}

bool comparemembers(stAlliance first, stAlliance second)
{
	if (first.members > second.members)
		return true;
	else
		return false;
}
bool compareprestige(stAlliance first, stAlliance second)
{
	if (first.prestige > second.prestige)
		return true;
	else
		return false;
}
bool comparehonor(stAlliance first, stAlliance second)
{
	if (first.honor > second.honor)
		return true;
	else
		return false;
}

void AllianceCore::SortAlliances()
{
	m_main->mtxlist.alliance.lock_shared();
	m_membersrank.clear();
	m_prestigerank.clear();
	m_honorrank.clear();

	stAlliance stmem;
	stAlliance stpre;
	stAlliance sthon;
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i])
		{
			sthon.honor = stpre.prestige = 0;
			stmem.id = stpre.id = sthon.id = m_alliances[i]->m_allianceid;
			stmem.members = m_alliances[i]->m_members.size();
			m_alliances[i]->m_citycount = 0;
			for (int k = 0; k < m_alliances[i]->m_members.size(); ++k)
			{
				Client * client = m_main->GetClient(m_alliances[i]->m_members[k].clientid);
				if (client)
				{
					sthon.honor += client->m_honor;
					stpre.prestige += client->m_prestige;
					m_alliances[i]->m_citycount += client->m_citycount;
				}
			}
			stmem.ref = m_alliances[i];
			stpre.ref = m_alliances[i];
			sthon.ref = m_alliances[i];
			m_membersrank.push_back(stmem);
			m_prestigerank.push_back(stpre);
			m_honorrank.push_back(sthon);
		}
	}

	m_membersrank.sort(comparemembers);
	m_prestigerank.sort(compareprestige);
	m_honorrank.sort(comparehonor);

	int num = 1;
	for (stAlliance & alliance : m_membersrank)
	{
		alliance.rank = alliance.ref->m_membersrank = num++;
	}
	num = 1;
	for (stAlliance & alliance : m_prestigerank)
	{
		alliance.rank = alliance.ref->m_prestigerank = num++;
		alliance.ref->m_prestige = alliance.prestige;
	}
	num = 1;
	for (stAlliance & alliance : m_honorrank)
	{
		alliance.rank = alliance.ref->m_honorrank = num++;
		alliance.ref->m_honor = alliance.honor;
	}
	m_main->mtxlist.alliance.unlock_shared();
}

Alliance * AllianceCore::AllianceById(uint32_t id)
{
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i] && m_alliances[i]->m_allianceid == id)
		{
			return m_alliances[i];
		}
	}
	return (Alliance*)-1;
}

Alliance * AllianceCore::AllianceByName(string name)
{
	for (int i = 0; i < DEF_MAXALLIANCES; ++i)
	{
		if (m_alliances[i] && m_alliances[i]->m_name == name)
		{
			return m_alliances[i];
		}
	}
	return (Alliance*)-1;
}

/*
struct stHero
{
	int32_t m_id;
	int16_t m_level;
	int8_t m_loyalty;
	int16_t m_management;
	int16_t m_managementbuffadded;
	int16_t m_power;
	int16_t m_powerbuffadded;
	int16_t m_stratagem;
	int16_t m_stratagembuffadded;
	int8_t m_status;

};
struct stResources
{
	double food;
	double stone;
	double iron;
	double wood;
	double gold;
};
struct stForts
{
	int32_t traps;
	int32_t abatis;
	int32_t towers;
	int32_t logs;
	int32_t trebs;
};
struct stTroops
{
	int32_t worker;
	int32_t warrior;
	int32_t scout;
	int32_t pike;
	int32_t sword;
	int32_t archer;
	int32_t cavalry;
	int32_t cataphract;
	int32_t transporter;
	int32_t ballista;
	int32_t ram;
	int32_t catapult;
};
struct stResult
{
	stResources resources;
	bool attackerwon;
};
struct stBuff
{
	string id;
	double endtime;
} m_buffs;
struct stResearch
{
	int16_t level;
	double endtime;
} m_research;
struct stAttacker
{
	stTroops troops;
	stBuff ** buffs;
	stResearch ** techs;
	PlayerCity * city;
	stHero hero;
};
struct stDefender
{
	stTroops troops;
	stForts forts;
	stBuff ** buffs;
	stResearch ** techs;
	PlayerCity * city;
	stHero hero;
};
stResult * CalculateBattle(stAttacker & attacker, stDefender & defender)
{

}*/

<|endoftext|>


<commit_before>//
//  Status.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 28/04/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

#ifndef InstructionSets_M68k_Status_h
#define InstructionSets_M68k_Status_h

namespace InstructionSet {
namespace M68k {

struct Status {
	/* b15 */
	uint_fast32_t trace_flag_ = 0;		// The trace flag is set if this value is non-zero.

	/* b13 */
	int is_supervisor_ = 0;				// 1 => processor is in supervisor mode; 0 => it isn't.

	/* b7–b9 */
	int interrupt_level_ = 0;			// The direct integer value of thee current interrupt level.

	/* b0–b4 */
	uint_fast32_t zero_result_ = 0;		// The zero flag is set if this value is zero.
	uint_fast32_t carry_flag_ = 0;		// The carry flag is set if this value is non-zero.
	uint_fast32_t extend_flag_ = 0;		// The extend flag is set if this value is non-zero.
	uint_fast32_t overflow_flag_ = 0;	// The overflow flag is set if this value is non-zero.
	uint_fast32_t negative_flag_ = 0;	// The negative flag is set if this value is non-zero.

	/// Gets the current condition codes.
	constexpr uint16_t ccr() const {
		return
			(carry_flag_ 	? 0x0001 : 0x0000) |
			(overflow_flag_	? 0x0002 : 0x0000) |
			(zero_result_	? 0x0000 : 0x0004) |
			(negative_flag_	? 0x0008 : 0x0000) |
			(extend_flag_	? 0x0010 : 0x0000);
	}

	/// Gets the current value of the status register.
	constexpr uint16_t status() const {
		return uint16_t(
			ccr() |
			(interrupt_level_ << 8) |
			(trace_flag_ ? 0x8000 : 0x0000) |
			(is_supervisor_ << 13)
		);
	}

	/// Sets the current condition codes.
	constexpr void set_ccr(uint16_t ccr) {
		carry_flag_			= (ccr) & 0x0001;
		overflow_flag_		= (ccr) & 0x0002;
		zero_result_		= ((ccr) & 0x0004) ^ 0x0004;
		negative_flag_		= (ccr) & 0x0008;
		extend_flag_		= (ccr) & 0x0010;
	}

	/// Sets the current value of the status register;
	/// @returns @c true if the processor finishes in supervisor mode; @c false otherwise.
	constexpr bool set_status(uint16_t status) {
		set_ccr(status);

		interrupt_level_ 	= (status >> 8) & 7;
		trace_flag_			= status & 0x8000;
		is_supervisor_		= (status >> 13) & 1;

		return is_supervisor_;
	}
};

}
}

#endif /* InstructionSets_M68k_Status_h */
<commit_msg>Add `evaluate_condition`, to check standard 68000 condition codes.<commit_after>//
//  Status.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 28/04/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

#ifndef InstructionSets_M68k_Status_h
#define InstructionSets_M68k_Status_h

namespace InstructionSet {
namespace M68k {

struct Status {
	/* b15 */
	uint_fast32_t trace_flag_ = 0;		// The trace flag is set if this value is non-zero.

	/* b13 */
	int is_supervisor_ = 0;				// 1 => processor is in supervisor mode; 0 => it isn't.

	/* b7–b9 */
	int interrupt_level_ = 0;			// The direct integer value of thee current interrupt level.

	/* b0–b4 */
	uint_fast32_t zero_result_ = 0;		// The zero flag is set if this value is zero.
	uint_fast32_t carry_flag_ = 0;		// The carry flag is set if this value is non-zero.
	uint_fast32_t extend_flag_ = 0;		// The extend flag is set if this value is non-zero.
	uint_fast32_t overflow_flag_ = 0;	// The overflow flag is set if this value is non-zero.
	uint_fast32_t negative_flag_ = 0;	// The negative flag is set if this value is non-zero.

	/// Gets the current condition codes.
	constexpr uint16_t ccr() const {
		return
			(carry_flag_ 	? 0x0001 : 0x0000) |
			(overflow_flag_	? 0x0002 : 0x0000) |
			(zero_result_	? 0x0000 : 0x0004) |
			(negative_flag_	? 0x0008 : 0x0000) |
			(extend_flag_	? 0x0010 : 0x0000);
	}

	/// Gets the current value of the status register.
	constexpr uint16_t status() const {
		return uint16_t(
			ccr() |
			(interrupt_level_ << 8) |
			(trace_flag_ ? 0x8000 : 0x0000) |
			(is_supervisor_ << 13)
		);
	}

	/// Sets the current condition codes.
	constexpr void set_ccr(uint16_t ccr) {
		carry_flag_			= (ccr) & 0x0001;
		overflow_flag_		= (ccr) & 0x0002;
		zero_result_		= ((ccr) & 0x0004) ^ 0x0004;
		negative_flag_		= (ccr) & 0x0008;
		extend_flag_		= (ccr) & 0x0010;
	}

	/// Sets the current value of the status register;
	/// @returns @c true if the processor finishes in supervisor mode; @c false otherwise.
	constexpr bool set_status(uint16_t status) {
		set_ccr(status);

		interrupt_level_ 	= (status >> 8) & 7;
		trace_flag_			= status & 0x8000;
		is_supervisor_		= (status >> 13) & 1;

		return is_supervisor_;
	}

	/// Evaluates the condition described in the low four bits of @c code
	template <typename IntT> bool evaluate_condition(IntT code) {
		switch(code & 0xf) {
			default:
			case 0x00:	return true;							// true
			case 0x01:	return false;							// false
			case 0x02:	return zero_result_ && !carry_flag_;	// high
			case 0x03:	return !zero_result_ || carry_flag_;	// low or same
			case 0x04:	return !carry_flag_;					// carry clear
			case 0x05:	return carry_flag_;						// carry set
			case 0x06:	return zero_result_;					// not equal
			case 0x07:	return !zero_result_;					// equal
			case 0x08:	return !overflow_flag_;					// overflow clear
			case 0x09:	return overflow_flag_;					// overflow set
			case 0x0a:	return !negative_flag_;					// positive
			case 0x0b:	return negative_flag_;					// negative
			case 0x0c:	// greater than or equal
				return (negative_flag_ && overflow_flag_) || (!negative_flag_ && !overflow_flag_);
			case 0x0d:	// less than
				return (negative_flag_ && !overflow_flag_) || (!negative_flag_ && overflow_flag_);
			case 0x0e:	// greater than
				return zero_result_ && ((negative_flag_ && overflow_flag_) || (!negative_flag_ && !overflow_flag_));
			case 0x0f:	// less than or equal
				return !zero_result_ || (negative_flag_ && !overflow_flag_) || (!negative_flag_ && overflow_flag_);
		}
	}
};

}
}

#endif /* InstructionSets_M68k_Status_h */
<|endoftext|>


<commit_before><commit_msg>fix regression caused by commit 5e42d4830<commit_after><|endoftext|>


<commit_before><commit_msg>Dependency graph crash minimum fix<commit_after><|endoftext|>


<commit_before>/*
  This file is part of KOrganizer.

  Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>

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

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "incidencechanger.h"
#include "kogroupware.h"
#include "koprefs.h"
#include "mailscheduler.h"

#include <KCal/AssignmentVisitor>
#include <KCal/CalendarResources>
#include <KCal/DndFactory>
#include <KCal/FreeBusy>
#include <KCal/Incidence>

#include <KDebug>
#include <KLocale>
#include <KMessageBox>

bool IncidenceChanger::beginChange( Incidence *incidence )
{
  if ( !incidence ) {
    return false;
  }
  kDebug() << "for incidence \"" << incidence->summary() << "\"";
  return mCalendar->beginChange( incidence );
}

bool IncidenceChanger::sendGroupwareMessage( KCal::Incidence *incidence,
                                             KCal::iTIPMethod method, bool deleting )
{
  if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) &&
       incidence->attendeeCount() > 0 &&
       !KOPrefs::instance()->mUseGroupwareCommunication ) {
    emit schedule( method, incidence );
    return true;
  } else if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
    // FIXME: Find a widget to use as parent, instead of 0
    return KOGroupware::instance()->sendICalMessage( 0, method, incidence, deleting );
  }
  return true;
}

void IncidenceChanger::cancelAttendees( Incidence *incidence )
{
  if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
    if ( KMessageBox::questionYesNo(
           0,
           i18n( "Some attendees were removed from the incidence. "
                 "Shall cancel messages be sent to these attendees?" ),
           i18n( "Attendees Removed" ), KGuiItem( i18n( "Send Messages" ) ),
           KGuiItem( i18n( "Do Not Send" ) ) ) == KMessageBox::Yes ) {
      // don't use KOGroupware::sendICalMessage here, because that asks just
      // a very general question "Other people are involved, send message to
      // them?", which isn't helpful at all in this situation. Afterwards, it
      // would only call the MailScheduler::performTransaction, so do this
      // manually.
      // FIXME: Groupware schedulling should be factored out to it's own class
      //        anyway
      MailScheduler scheduler( mCalendar );
      scheduler.performTransaction( incidence, iTIPCancel );
    }
  }
}

bool IncidenceChanger::endChange( Incidence *incidence )
{
  // FIXME: if that's a groupware incidence, and I'm not the organizer,
  // send out a mail to the organizer with a counterproposal instead
  // of actually changing the incidence. Then no locking is needed.
  // FIXME: if that's a groupware incidence, and the incidence was
  // never locked, we can't unlock it with endChange().
  if ( !incidence ) {
    return false;
  }

  kDebug() << "\"" << incidence->summary() << "\"";
  return mCalendar->endChange( incidence );
}

bool IncidenceChanger::deleteIncidence( Incidence *incidence )
{
  if ( !incidence ) {
    return true;
  }

  kDebug() << "\"" << incidence->summary() << "\"";
  bool doDelete = sendGroupwareMessage( incidence, KCal::iTIPCancel, true );
  if( doDelete ) {
    // @TODO: let Calendar::deleteIncidence do the locking...
    Incidence *tmp = incidence->clone();
    emit incidenceToBeDeleted( incidence );
    doDelete = mCalendar->deleteIncidence( incidence );
    if ( !KOPrefs::instance()->thatIsMe( tmp->organizer().email() ) ) {
      const QStringList myEmails = KOPrefs::instance()->allEmails();
      bool notifyOrganizer = false;
      for ( QStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
        QString email = *it;
        Attendee *me = tmp->attendeeByMail(email);
        if ( me ) {
          if ( me->status() == KCal::Attendee::Accepted ||
               me->status() == KCal::Attendee::Delegated ) {
            notifyOrganizer = true;
          }
          Attendee *newMe = new Attendee( *me );
          newMe->setStatus( KCal::Attendee::Declined );
          tmp->clearAttendees();
          tmp->addAttendee( newMe );
          break;
        }
      }

      if ( notifyOrganizer ) {
        MailScheduler scheduler( mCalendar );
        scheduler.performTransaction( tmp, KCal::iTIPReply );
      }
    }
    emit incidenceDeleted( incidence );
  }
  return doDelete;
}

bool IncidenceChanger::cutIncidence( Incidence *incidence )
{
  if ( !incidence ) {
    return true;
  }

  kDebug() << "\"" << incidence->summary() << "\"";
  bool doDelete = sendGroupwareMessage( incidence, KCal::iTIPCancel );
  if( doDelete ) {
    // @TODO: the factory needs to do the locking!
    DndFactory factory( mCalendar );
    emit incidenceToBeDeleted( incidence );
    factory.cutIncidence( incidence );
    emit incidenceDeleted( incidence );
  }
  return doDelete;
}

class IncidenceChanger::ComparisonVisitor : public IncidenceBase::Visitor
{
  public:
    ComparisonVisitor() {}
    bool act( IncidenceBase *incidence, IncidenceBase *inc2 )
    {
      mIncidence2 = inc2;
      if ( incidence ) {
        return incidence->accept( *this );
      } else {
        return inc2 == 0;
      }
    }

  protected:
    bool visit( Event *event )
    {
      Event *ev2 = dynamic_cast<Event*>(mIncidence2);
      if ( event && ev2 ) {
        return *event == *ev2;
      } else {
        // either both 0, or return false;
        return ev2 == event;
      }
    }
    bool visit( Todo *todo )
    {
      Todo *to2 = dynamic_cast<Todo*>( mIncidence2 );
      if ( todo && to2 ) {
        return *todo == *to2;
      } else {
        // either both 0, or return false;
        return todo == to2;
      }
    }
    bool visit( Journal *journal )
    {
      Journal *j2 = dynamic_cast<Journal*>( mIncidence2 );
      if ( journal && j2 ) {
        return *journal == *j2;
      } else {
        // either both 0, or return false;
        return journal == j2;
      }
    }
    bool visit( FreeBusy *fb )
    {
      FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 );
      if ( fb && fb2 ) {
        return *fb == *fb2;
      } else {
        // either both 0, or return false;
        return fb2 == fb;
      }
    }

  protected:
    IncidenceBase *mIncidence2;
};

bool IncidenceChanger::incidencesEqual( Incidence *inc1, Incidence *inc2 )
{
  ComparisonVisitor v;
  return ( v.act( inc1, inc2 ) );
}

bool IncidenceChanger::assignIncidence( Incidence *inc1, Incidence *inc2 )
{
  if ( !inc1 || !inc2 ) {
    return false;
  }

  AssignmentVisitor v;
  return v.assign( inc1, inc2 );
}

bool IncidenceChanger::myAttendeeStatusChanged( Incidence *oldInc, Incidence *newInc )
{
  Attendee *oldMe = oldInc->attendeeByMails( KOPrefs::instance()->allEmails() );
  Attendee *newMe = newInc->attendeeByMails( KOPrefs::instance()->allEmails() );
  if ( oldMe && newMe && ( oldMe->status() != newMe->status() ) ) {
    return true;
  }

  return false;
}

bool IncidenceChanger::changeIncidence( Incidence *oldinc, Incidence *newinc,
                                        int action )
{
  kDebug() << "for incidence \"" << newinc->summary() << "\""
           << "( old one was \"" << oldinc->summary() << "\")";

  if ( incidencesEqual( newinc, oldinc ) ) {
    // Don't do anything
    kDebug() << "Incidence not changed";
  } else {
    kDebug() << "Changing incidence";
    bool statusChanged = myAttendeeStatusChanged( oldinc, newinc );
    int revision = newinc->revision();
    newinc->setRevision( revision + 1 );
    // FIXME: Use a generic method for this! Ideally, have an interface class
    //        for group cheduling. Each implementation could then just do what
    //        it wants with the event. If no groupware is used,use the null
    //        pattern...
    bool success = true;
    if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
      success = KOGroupware::instance()->sendICalMessage( 0,
                                                          KCal::iTIPRequest,
                                                          newinc, false, statusChanged );
    }

    if ( success ) {
      // Accept the event changes
      if ( action < 0 ) {
        emit incidenceChanged( oldinc, newinc );
      } else {
        emit incidenceChanged( oldinc, newinc, action );
      }
    } else {
      // revert changes
      assignIncidence( newinc, oldinc );
      return false;
    }
  }
  return true;
}

bool IncidenceChanger::addIncidence( Incidence *incidence, QWidget *parent )
{
  kDebug() << "\"" << incidence->summary() << "\"";
  if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
    if ( !KOGroupware::instance()->sendICalMessage( parent,
                                                    KCal::iTIPRequest,
                                                    incidence ) ) {
      return false;
    }
  }
  // FIXME: This is a nasty hack, since we need to set a parent for the
  //        resource selection dialog. However, we don't have any UI methods
  //        in the calendar, only in the CalendarResources::DestinationPolicy
  //        So we need to type-cast it and extract it from the CalendarResources
  CalendarResources *stdcal = dynamic_cast<CalendarResources*>( mCalendar );
  QWidget *tmpparent = 0;
  if ( stdcal ) {
    tmpparent = stdcal->dialogParentWidget();
    stdcal->setDialogParentWidget( parent );
  }
  bool success = mCalendar->addIncidence( incidence );
  if ( stdcal ) {
    // Reset the parent widget, otherwise we'll end up with pointers to deleted
    // widgets sooner or later
    stdcal->setDialogParentWidget( tmpparent );
  }
  if ( !success ) {
    // We can have a failure if the user pressed [cancel] in the resource
    // selectdialog, so check the exception.
    ErrorFormat *e = stdcal->exception();
    if ( !e || ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel ) ) ) {
      KMessageBox::sorry( parent,
                          i18n( "Unable to save %1 \"%2\".",
                                i18n( incidence->type() ),
                                incidence->summary() ) );
    }
    return false;
  }
  emit incidenceAdded( incidence );
  return true;
}

#include "incidencechanger.moc"
<commit_msg>Fix potential crash<commit_after>/*
  This file is part of KOrganizer.

  Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>

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

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "incidencechanger.h"
#include "kogroupware.h"
#include "koprefs.h"
#include "mailscheduler.h"

#include <KCal/AssignmentVisitor>
#include <KCal/CalendarResources>
#include <KCal/DndFactory>
#include <KCal/FreeBusy>
#include <KCal/Incidence>

#include <KDebug>
#include <KLocale>
#include <KMessageBox>

bool IncidenceChanger::beginChange( Incidence *incidence )
{
  if ( !incidence ) {
    return false;
  }
  kDebug() << "for incidence \"" << incidence->summary() << "\"";
  return mCalendar->beginChange( incidence );
}

bool IncidenceChanger::sendGroupwareMessage( KCal::Incidence *incidence,
                                             KCal::iTIPMethod method, bool deleting )
{
  if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) &&
       incidence->attendeeCount() > 0 &&
       !KOPrefs::instance()->mUseGroupwareCommunication ) {
    emit schedule( method, incidence );
    return true;
  } else if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
    // FIXME: Find a widget to use as parent, instead of 0
    return KOGroupware::instance()->sendICalMessage( 0, method, incidence, deleting );
  }
  return true;
}

void IncidenceChanger::cancelAttendees( Incidence *incidence )
{
  if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
    if ( KMessageBox::questionYesNo(
           0,
           i18n( "Some attendees were removed from the incidence. "
                 "Shall cancel messages be sent to these attendees?" ),
           i18n( "Attendees Removed" ), KGuiItem( i18n( "Send Messages" ) ),
           KGuiItem( i18n( "Do Not Send" ) ) ) == KMessageBox::Yes ) {
      // don't use KOGroupware::sendICalMessage here, because that asks just
      // a very general question "Other people are involved, send message to
      // them?", which isn't helpful at all in this situation. Afterwards, it
      // would only call the MailScheduler::performTransaction, so do this
      // manually.
      // FIXME: Groupware schedulling should be factored out to it's own class
      //        anyway
      MailScheduler scheduler( mCalendar );
      scheduler.performTransaction( incidence, iTIPCancel );
    }
  }
}

bool IncidenceChanger::endChange( Incidence *incidence )
{
  // FIXME: if that's a groupware incidence, and I'm not the organizer,
  // send out a mail to the organizer with a counterproposal instead
  // of actually changing the incidence. Then no locking is needed.
  // FIXME: if that's a groupware incidence, and the incidence was
  // never locked, we can't unlock it with endChange().
  if ( !incidence ) {
    return false;
  }

  kDebug() << "\"" << incidence->summary() << "\"";
  return mCalendar->endChange( incidence );
}

bool IncidenceChanger::deleteIncidence( Incidence *incidence )
{
  if ( !incidence ) {
    return true;
  }

  kDebug() << "\"" << incidence->summary() << "\"";
  bool doDelete = sendGroupwareMessage( incidence, KCal::iTIPCancel, true );
  if( doDelete ) {
    // @TODO: let Calendar::deleteIncidence do the locking...
    Incidence *tmp = incidence->clone();
    emit incidenceToBeDeleted( incidence );
    doDelete = mCalendar->deleteIncidence( incidence );
    if ( !KOPrefs::instance()->thatIsMe( tmp->organizer().email() ) ) {
      const QStringList myEmails = KOPrefs::instance()->allEmails();
      bool notifyOrganizer = false;
      for ( QStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
        QString email = *it;
        Attendee *me = tmp->attendeeByMail(email);
        if ( me ) {
          if ( me->status() == KCal::Attendee::Accepted ||
               me->status() == KCal::Attendee::Delegated ) {
            notifyOrganizer = true;
          }
          Attendee *newMe = new Attendee( *me );
          newMe->setStatus( KCal::Attendee::Declined );
          tmp->clearAttendees();
          tmp->addAttendee( newMe );
          break;
        }
      }

      if ( notifyOrganizer ) {
        MailScheduler scheduler( mCalendar );
        scheduler.performTransaction( tmp, KCal::iTIPReply );
      }
    }
    emit incidenceDeleted( incidence );
  }
  return doDelete;
}

bool IncidenceChanger::cutIncidence( Incidence *incidence )
{
  if ( !incidence ) {
    return true;
  }

  kDebug() << "\"" << incidence->summary() << "\"";
  bool doDelete = sendGroupwareMessage( incidence, KCal::iTIPCancel );
  if( doDelete ) {
    // @TODO: the factory needs to do the locking!
    DndFactory factory( mCalendar );
    emit incidenceToBeDeleted( incidence );
    factory.cutIncidence( incidence );
    emit incidenceDeleted( incidence );
  }
  return doDelete;
}

class IncidenceChanger::ComparisonVisitor : public IncidenceBase::Visitor
{
  public:
    ComparisonVisitor() {}
    bool act( IncidenceBase *incidence, IncidenceBase *inc2 )
    {
      mIncidence2 = inc2;
      if ( incidence ) {
        return incidence->accept( *this );
      } else {
        return inc2 == 0;
      }
    }

  protected:
    bool visit( Event *event )
    {
      Event *ev2 = dynamic_cast<Event*>(mIncidence2);
      if ( event && ev2 ) {
        return *event == *ev2;
      } else {
        // either both 0, or return false;
        return ev2 == event;
      }
    }
    bool visit( Todo *todo )
    {
      Todo *to2 = dynamic_cast<Todo*>( mIncidence2 );
      if ( todo && to2 ) {
        return *todo == *to2;
      } else {
        // either both 0, or return false;
        return todo == to2;
      }
    }
    bool visit( Journal *journal )
    {
      Journal *j2 = dynamic_cast<Journal*>( mIncidence2 );
      if ( journal && j2 ) {
        return *journal == *j2;
      } else {
        // either both 0, or return false;
        return journal == j2;
      }
    }
    bool visit( FreeBusy *fb )
    {
      FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 );
      if ( fb && fb2 ) {
        return *fb == *fb2;
      } else {
        // either both 0, or return false;
        return fb2 == fb;
      }
    }

  protected:
    IncidenceBase *mIncidence2;
};

bool IncidenceChanger::incidencesEqual( Incidence *inc1, Incidence *inc2 )
{
  ComparisonVisitor v;
  return ( v.act( inc1, inc2 ) );
}

bool IncidenceChanger::assignIncidence( Incidence *inc1, Incidence *inc2 )
{
  if ( !inc1 || !inc2 ) {
    return false;
  }

  AssignmentVisitor v;
  return v.assign( inc1, inc2 );
}

bool IncidenceChanger::myAttendeeStatusChanged( Incidence *oldInc, Incidence *newInc )
{
  Attendee *oldMe = oldInc->attendeeByMails( KOPrefs::instance()->allEmails() );
  Attendee *newMe = newInc->attendeeByMails( KOPrefs::instance()->allEmails() );
  if ( oldMe && newMe && ( oldMe->status() != newMe->status() ) ) {
    return true;
  }

  return false;
}

bool IncidenceChanger::changeIncidence( Incidence *oldinc, Incidence *newinc,
                                        int action )
{
  kDebug() << "for incidence \"" << newinc->summary() << "\""
           << "( old one was \"" << oldinc->summary() << "\")";

  if ( incidencesEqual( newinc, oldinc ) ) {
    // Don't do anything
    kDebug() << "Incidence not changed";
  } else {
    kDebug() << "Changing incidence";
    bool statusChanged = myAttendeeStatusChanged( oldinc, newinc );
    int revision = newinc->revision();
    newinc->setRevision( revision + 1 );
    // FIXME: Use a generic method for this! Ideally, have an interface class
    //        for group cheduling. Each implementation could then just do what
    //        it wants with the event. If no groupware is used,use the null
    //        pattern...
    bool success = true;
    if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
      success = KOGroupware::instance()->sendICalMessage( 0,
                                                          KCal::iTIPRequest,
                                                          newinc, false, statusChanged );
    }

    if ( success ) {
      // Accept the event changes
      if ( action < 0 ) {
        emit incidenceChanged( oldinc, newinc );
      } else {
        emit incidenceChanged( oldinc, newinc, action );
      }
    } else {
      // revert changes
      assignIncidence( newinc, oldinc );
      return false;
    }
  }
  return true;
}

bool IncidenceChanger::addIncidence( Incidence *incidence, QWidget *parent )
{
  kDebug() << "\"" << incidence->summary() << "\"";
  if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
    if ( !KOGroupware::instance()->sendICalMessage( parent,
                                                    KCal::iTIPRequest,
                                                    incidence ) ) {
      return false;
    }
  }
  // FIXME: This is a nasty hack, since we need to set a parent for the
  //        resource selection dialog. However, we don't have any UI methods
  //        in the calendar, only in the CalendarResources::DestinationPolicy
  //        So we need to type-cast it and extract it from the CalendarResources
  CalendarResources *stdcal = dynamic_cast<CalendarResources*>( mCalendar );
  QWidget *tmpparent = 0;
  if ( stdcal ) {
    tmpparent = stdcal->dialogParentWidget();
    stdcal->setDialogParentWidget( parent );
  }
  bool success = mCalendar->addIncidence( incidence );
  if ( stdcal ) {
    // Reset the parent widget, otherwise we'll end up with pointers to deleted
    // widgets sooner or later
    stdcal->setDialogParentWidget( tmpparent );
  }
  if ( !success && stdcal ) {
    // We can have a failure if the user pressed [cancel] in the resource
    // selectdialog, so check the exception.
    ErrorFormat *e = stdcal->exception();
    if ( !e || ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel ) ) ) {
      KMessageBox::sorry( parent,
                          i18n( "Unable to save %1 \"%2\".",
                                i18n( incidence->type() ),
                                incidence->summary() ) );
    }
    return false;
  }
  emit incidenceAdded( incidence );
  return true;
}

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


<commit_before>/**
 * \file
 * \brief StaticThread class header
 *
 * \author Copyright (C) 2014-2017 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_STATICTHREAD_HPP_
#define INCLUDE_DISTORTOS_STATICTHREAD_HPP_

#include "distortos/assert.h"
#include "distortos/StaticSignalsReceiver.hpp"
#include "distortos/UndetachableThread.hpp"

namespace distortos
{

namespace internal
{

/**
 * \brief StaticThreadBase class is a templated common base for StaticThread
 *
 * \tparam Function is the function that will be executed in separate thread
 * \tparam Args are the arguments for \a Function
 */

template<typename Function, typename... Args>
class StaticThreadBase : public UndetachableThread
{
public:

	/// base of StaticThreadBase
	using Base = UndetachableThread;

	/**
	 * \brief StaticThreadBase's constructor
	 *
	 * \param [in] stackStorageUniquePointer is a rvalue reference to StackStorageUniquePointer with storage for stack
	 * (\a size bytes long) and appropriate deleter
	 * \param [in] size is the size of stack's storage, bytes
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] signalsReceiver is a pointer to SignalsReceiver object for this thread, nullptr to disable reception
	 * of signals for this thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThreadBase(StackStorageUniquePointer&& stackStorageUniquePointer, const size_t size, const uint8_t priority,
			const SchedulingPolicy schedulingPolicy, SignalsReceiver* const signalsReceiver, Function&& function,
			Args&&... args) :
					Base{{std::move(stackStorageUniquePointer), size}, priority, schedulingPolicy, nullptr,
							signalsReceiver},
					boundFunction_{std::bind(std::forward<Function>(function), std::forward<Args>(args)...)}
	{

	}

	StaticThreadBase(const StaticThreadBase&) = delete;
	StaticThreadBase(StaticThreadBase&&) = default;
	const StaticThreadBase& operator=(const StaticThreadBase&) = delete;
	StaticThreadBase& operator=(StaticThreadBase&&) = delete;

	/**
	 * \brief Starts the thread.
	 *
	 * This operation can be performed on threads in "New" state only.
	 *
	 * \return 0 on success, error code otherwise:
	 * - error codes returned by UndetachableThread::startInternal();
	 */

	int start()
	{
		return UndetachableThread::startInternal(run, nullptr, terminationHook);
	}

private:

	/**
	 * \brief Thread's "run" function.
	 *
	 * Executes bound function object.
	 *
	 * \param [in] thread is a reference to Thread object, this must be StaticThreadBase!
	 */

	static void run(Thread& thread)
	{
		static_cast<StaticThreadBase&>(thread).boundFunction_();
	}

	/// bound function object
	decltype(std::bind(std::declval<Function>(), std::declval<Args>()...)) boundFunction_;
};

}	// namespace internal

/// \addtogroup threads
/// \{

/**
 * \brief StaticThread class is a templated interface for thread that has automatic storage for stack.
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed in separate thread
 * \tparam Args are the arguments for \a Function
 */

template<size_t StackSize, bool CanReceiveSignals, size_t QueuedSignals, size_t SignalActions, typename Function,
		typename... Args>
class StaticThread : public internal::StaticThreadBase<Function, Args...>
{
public:

	/// base of StaticThread
	using Base = internal::StaticThreadBase<Function, Args...>;

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(uint8_t priority, SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args);

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, Function&& function, Args&&... args) :
			StaticThread{priority, SchedulingPolicy::roundRobin, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	StaticThread(const StaticThread&) = delete;
	StaticThread(StaticThread&&) = default;
	const StaticThread& operator=(const StaticThread&) = delete;
	StaticThread& operator=(StaticThread&&) = delete;

private:

	/// stack buffer
	typename std::aligned_storage<StackSize + internal::stackGuardSize>::type stack_;
};

/**
 * \brief StaticThread class is a templated interface for thread that has automatic storage for stack and internal
 * StaticSignalsReceiver object.
 *
 * Specialization for threads with enabled reception of signals (CanReceiveSignals == true)
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam QueuedSignals is the max number of queued signals for this thread, 0 to disable queuing of signals for this
 * thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed in separate thread
 * \tparam Args are the arguments for \a Function
 */

template<size_t StackSize, size_t QueuedSignals, size_t SignalActions, typename Function, typename... Args>
class StaticThread<StackSize, true, QueuedSignals, SignalActions, Function, Args...> :
		public internal::StaticThreadBase<Function, Args...>
{
public:

	/// base of StaticThread
	using Base = internal::StaticThreadBase<Function, Args...>;

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(uint8_t priority, SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args);

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, Function&& function, Args&&... args) :
			StaticThread{priority, SchedulingPolicy::roundRobin, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	StaticThread(const StaticThread&) = delete;
	StaticThread(StaticThread&&) = default;
	const StaticThread& operator=(const StaticThread&) = delete;
	StaticThread& operator=(StaticThread&&) = delete;

private:

	/// stack buffer
	typename std::aligned_storage<StackSize + internal::stackGuardSize>::type stack_;

	/// internal StaticSignalsReceiver object
	StaticSignalsReceiver<QueuedSignals, SignalActions> staticSignalsReceiver_;
};

/**
 * \brief Helper factory function to make StaticThread object with partially deduced template arguments
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed
 * \tparam Args are the arguments for \a Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] schedulingPolicy is the scheduling policy of the thread
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, size_t QueuedSignals = {}, size_t SignalActions = {},
		typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>
makeStaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args)
{
	return {priority, schedulingPolicy, std::forward<Function>(function), std::forward<Args>(args)...};
}

/**
 * \brief Helper factory function to make StaticThread object with partially deduced template arguments
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed
 * \tparam Args are the arguments for \a Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, size_t QueuedSignals = {}, size_t SignalActions = {},
		typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>
makeStaticThread(const uint8_t priority, Function&& function, Args&&... args)
{
	return {priority, std::forward<Function>(function), std::forward<Args>(args)...};
}

/**
 * \brief Helper factory function to make and start StaticThread object with partially deduced template arguments
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed
 * \tparam Args are the arguments for \a Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] schedulingPolicy is the scheduling policy of the thread
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, size_t QueuedSignals = {}, size_t SignalActions = {},
		typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>
makeAndStartStaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function,
		Args&&... args)
{
	auto thread = makeStaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions>(priority,
			schedulingPolicy, std::forward<Function>(function), std::forward<Args>(args)...);
	{
		const auto ret = thread.start();
		assert(ret == 0 && "Could not start thread!");
	}
	return thread;
}

/**
 * \brief Helper factory function to make and start StaticThread object with partially deduced template arguments
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed
 * \tparam Args are the arguments for \a Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, size_t QueuedSignals = {}, size_t SignalActions = {},
		typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>
makeAndStartStaticThread(const uint8_t priority, Function&& function, Args&&... args)
{
	auto thread = makeStaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions>(priority,
			std::forward<Function>(function), std::forward<Args>(args)...);
	{
		const auto ret = thread.start();
		assert(ret == 0 && "Could not start thread!");
	}
	return thread;
}

/// \}

template<size_t StackSize, bool CanReceiveSignals, size_t QueuedSignals, size_t SignalActions, typename Function,
		typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>::
StaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args) :
		Base{{&stack_, internal::dummyDeleter<decltype(stack_)>}, sizeof(stack_), priority, schedulingPolicy, nullptr,
				std::forward<Function>(function), std::forward<Args>(args)...}
{

}

template<size_t StackSize, size_t QueuedSignals, size_t SignalActions, typename Function, typename... Args>
StaticThread<StackSize, true, QueuedSignals, SignalActions, Function, Args...>::StaticThread(const uint8_t priority,
		const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args) :
		Base{{&stack_, internal::dummyDeleter<decltype(stack_)>}, sizeof(stack_), priority, schedulingPolicy,
				&static_cast<SignalsReceiver&>(staticSignalsReceiver_), std::forward<Function>(function),
				std::forward<Args>(args)...},
		staticSignalsReceiver_{}
{

}

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_STATICTHREAD_HPP_
<commit_msg>Move stack buffer from StaticThread to StaticThreadBase<commit_after>/**
 * \file
 * \brief StaticThread class header
 *
 * \author Copyright (C) 2014-2017 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_STATICTHREAD_HPP_
#define INCLUDE_DISTORTOS_STATICTHREAD_HPP_

#include "distortos/assert.h"
#include "distortos/StaticSignalsReceiver.hpp"
#include "distortos/UndetachableThread.hpp"

namespace distortos
{

namespace internal
{

/**
 * \brief StaticThreadBase class is a templated common base for StaticThread
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam Function is the function that will be executed in separate thread
 * \tparam Args are the arguments for \a Function
 */

template<size_t StackSize, typename Function, typename... Args>
class StaticThreadBase : public UndetachableThread
{
public:

	/// base of StaticThreadBase
	using Base = UndetachableThread;

	/**
	 * \brief StaticThreadBase's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] signalsReceiver is a pointer to SignalsReceiver object for this thread, nullptr to disable reception
	 * of signals for this thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThreadBase(const uint8_t priority, const SchedulingPolicy schedulingPolicy,
			SignalsReceiver* const signalsReceiver, Function&& function, Args&&... args) :
					Base{{{&stack_, internal::dummyDeleter<decltype(stack_)>}, sizeof(stack_)}, priority,
							schedulingPolicy, nullptr, signalsReceiver},
					boundFunction_{std::bind(std::forward<Function>(function), std::forward<Args>(args)...)}
	{

	}

	StaticThreadBase(const StaticThreadBase&) = delete;
	StaticThreadBase(StaticThreadBase&&) = default;
	const StaticThreadBase& operator=(const StaticThreadBase&) = delete;
	StaticThreadBase& operator=(StaticThreadBase&&) = delete;

	/**
	 * \brief Starts the thread.
	 *
	 * This operation can be performed on threads in "New" state only.
	 *
	 * \return 0 on success, error code otherwise:
	 * - error codes returned by UndetachableThread::startInternal();
	 */

	int start()
	{
		return UndetachableThread::startInternal(run, nullptr, terminationHook);
	}

private:

	/**
	 * \brief Thread's "run" function.
	 *
	 * Executes bound function object.
	 *
	 * \param [in] thread is a reference to Thread object, this must be StaticThreadBase!
	 */

	static void run(Thread& thread)
	{
		static_cast<StaticThreadBase&>(thread).boundFunction_();
	}

	/// stack buffer
	typename std::aligned_storage<StackSize + internal::stackGuardSize>::type stack_;

	/// bound function object
	decltype(std::bind(std::declval<Function>(), std::declval<Args>()...)) boundFunction_;
};

}	// namespace internal

/// \addtogroup threads
/// \{

/**
 * \brief StaticThread class is a templated interface for thread that has automatic storage for stack.
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed in separate thread
 * \tparam Args are the arguments for \a Function
 */

template<size_t StackSize, bool CanReceiveSignals, size_t QueuedSignals, size_t SignalActions, typename Function,
		typename... Args>
class StaticThread : public internal::StaticThreadBase<StackSize, Function, Args...>
{
public:

	/// base of StaticThread
	using Base = internal::StaticThreadBase<StackSize, Function, Args...>;

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(uint8_t priority, SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args);

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, Function&& function, Args&&... args) :
			StaticThread{priority, SchedulingPolicy::roundRobin, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	StaticThread(const StaticThread&) = delete;
	StaticThread(StaticThread&&) = default;
	const StaticThread& operator=(const StaticThread&) = delete;
	StaticThread& operator=(StaticThread&&) = delete;
};

/**
 * \brief StaticThread class is a templated interface for thread that has automatic storage for stack and internal
 * StaticSignalsReceiver object.
 *
 * Specialization for threads with enabled reception of signals (CanReceiveSignals == true)
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam QueuedSignals is the max number of queued signals for this thread, 0 to disable queuing of signals for this
 * thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed in separate thread
 * \tparam Args are the arguments for \a Function
 */

template<size_t StackSize, size_t QueuedSignals, size_t SignalActions, typename Function, typename... Args>
class StaticThread<StackSize, true, QueuedSignals, SignalActions, Function, Args...> :
		public internal::StaticThreadBase<StackSize, Function, Args...>
{
public:

	/// base of StaticThread
	using Base = internal::StaticThreadBase<StackSize, Function, Args...>;

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(uint8_t priority, SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args);

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, Function&& function, Args&&... args) :
			StaticThread{priority, SchedulingPolicy::roundRobin, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	StaticThread(const StaticThread&) = delete;
	StaticThread(StaticThread&&) = default;
	const StaticThread& operator=(const StaticThread&) = delete;
	StaticThread& operator=(StaticThread&&) = delete;

private:

	/// internal StaticSignalsReceiver object
	StaticSignalsReceiver<QueuedSignals, SignalActions> staticSignalsReceiver_;
};

/**
 * \brief Helper factory function to make StaticThread object with partially deduced template arguments
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed
 * \tparam Args are the arguments for \a Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] schedulingPolicy is the scheduling policy of the thread
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, size_t QueuedSignals = {}, size_t SignalActions = {},
		typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>
makeStaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args)
{
	return {priority, schedulingPolicy, std::forward<Function>(function), std::forward<Args>(args)...};
}

/**
 * \brief Helper factory function to make StaticThread object with partially deduced template arguments
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed
 * \tparam Args are the arguments for \a Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, size_t QueuedSignals = {}, size_t SignalActions = {},
		typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>
makeStaticThread(const uint8_t priority, Function&& function, Args&&... args)
{
	return {priority, std::forward<Function>(function), std::forward<Args>(args)...};
}

/**
 * \brief Helper factory function to make and start StaticThread object with partially deduced template arguments
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed
 * \tparam Args are the arguments for \a Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] schedulingPolicy is the scheduling policy of the thread
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, size_t QueuedSignals = {}, size_t SignalActions = {},
		typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>
makeAndStartStaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function,
		Args&&... args)
{
	auto thread = makeStaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions>(priority,
			schedulingPolicy, std::forward<Function>(function), std::forward<Args>(args)...);
	{
		const auto ret = thread.start();
		assert(ret == 0 && "Could not start thread!");
	}
	return thread;
}

/**
 * \brief Helper factory function to make and start StaticThread object with partially deduced template arguments
 *
 * \tparam StackSize is the size of stack, bytes
 * \tparam CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \tparam QueuedSignals is the max number of queued signals for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable queuing of signals for this thread
 * \tparam SignalActions is the max number of different SignalAction objects for this thread, relevant only if
 * CanReceiveSignals == true, 0 to disable catching of signals for this thread
 * \tparam Function is the function that will be executed
 * \tparam Args are the arguments for \a Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, size_t QueuedSignals = {}, size_t SignalActions = {},
		typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>
makeAndStartStaticThread(const uint8_t priority, Function&& function, Args&&... args)
{
	auto thread = makeStaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions>(priority,
			std::forward<Function>(function), std::forward<Args>(args)...);
	{
		const auto ret = thread.start();
		assert(ret == 0 && "Could not start thread!");
	}
	return thread;
}

/// \}

template<size_t StackSize, bool CanReceiveSignals, size_t QueuedSignals, size_t SignalActions, typename Function,
		typename... Args>
StaticThread<StackSize, CanReceiveSignals, QueuedSignals, SignalActions, Function, Args...>::
StaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args) :
		Base{priority, schedulingPolicy, nullptr, std::forward<Function>(function), std::forward<Args>(args)...}
{

}

template<size_t StackSize, size_t QueuedSignals, size_t SignalActions, typename Function, typename... Args>
StaticThread<StackSize, true, QueuedSignals, SignalActions, Function, Args...>::StaticThread(const uint8_t priority,
		const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args) :
		Base{priority, schedulingPolicy, &static_cast<SignalsReceiver&>(staticSignalsReceiver_),
				std::forward<Function>(function), std::forward<Args>(args)...},
		staticSignalsReceiver_{}
{

}

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_STATICTHREAD_HPP_
<|endoftext|>


<commit_before>#include "peercred.h"

// POSIX
#include <sys/socket.h>
#include <sys/un.h>

// PUT
#include <specialized/osdetect.h>
#include <cxxutils/posix_helpers.h>

#if defined(__solaris__) // Solaris
#pragma message("Information: using Solaris code")

#include <ucred.h>

int recv_cred(int socket, proccred_t& cred) noexcept
{
  uproccred_t* data = nullptr;

  int rval = ::getpeerucred(socket, &data);

  if(rval == posix::success_response)
  {
    cred.pid = ucred_getpid (data);
    cred.uid = ucred_geteuid(data);
    cred.gid = ucred_getegid(data);
    ucred_free(data);
    if (cred.pid == pid_t(-1) ||
        cred.uid == uid_t(-1) ||
        cred.gid == gid_t(-1))
      rval = posix::error_response;
  }
  return rval;
}

int send_cred(int) noexcept
{ return posix::success_response; }

#elif defined (SO_PEERCRED) || defined (LOCAL_PEEREID) /* Linux/OpenBSD/Old NetBSD */

# if defined (SO_PEERCRED) && \
    (defined(__linux__)    /* Linux    */ || \
     defined(__kfreebsd__) /* kFreeBSD */ )
constexpr int socket_cred_option = SO_PEERCRED;
typedef ucred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.uid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.gid; }

# elif defined(SO_PEERCRED) && defined(__OpenBSD__)
constexpr int socket_cred_option = SO_PEERCRED;
typedef sockpeercred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.uid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.gid; }

# elif defined(LOCAL_PEEREID) && defined(__NetBSD__) /* legacy NetBSD */
constexpr int socket_cred_option = LOCAL_PEEREID;
typedef unpcbid cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.unp_pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.unp_euid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.unp_egid; }

# elif defined(SO_PEERCRED)
#  error SO_PEERCRED macro detected but platform is unrecognized.  Please submit a patch!
# elif defined(LOCAL_PEEREID)
#  error LOCAL_PEEREID macro detected but platform is unrecognized.  Please submit a patch!
# endif

int recv_cred(int socket, proccred_t& cred) noexcept
{
  cred_t data;
  socklen_t len = sizeof(data);

  int rval = ::getsockopt(socket, SOL_SOCKET, socket_cred_option, &data, &len);

  if(len != sizeof(data))
    rval = posix::error(std::errc::invalid_argument);

  if(rval == posix::success_response)
  {
    cred.pid = peer_pid(data);
    cred.uid = peer_uid(data);
    cred.gid = peer_gid(data);
  }
  return rval;
}

int send_cred(int) noexcept
{ return posix::success_response; }

#elif defined(SCM_CREDS) && defined(__darwin__) /* Darwin */

#pragma message("Warning: recv_cred/send_cred for Darwin is broken!")

int recv_cred(int, proccred_t&) noexcept
{ return posix::error_response; }

int send_cred(int) noexcept
{ return posix::error_response; }

#elif defined(SCM_CREDENTIALS) || defined(SCM_CREDS)

# if defined(SCM_CREDENTIALS) /* Linux / kFreeBSD */
constexpr int credential_message = SCM_CREDENTIALS;
typedef ucred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.uid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.gid; }

# elif defined(SCM_CREDS) && defined(__NetBSD__) /* NetBSD */
constexpr int credential_message = SCM_CREDS;
typedef cred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.sc_pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.sc_euid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.sc_egid; }

# elif defined(SCM_CREDS) && \
      (defined(__FreeBSD__)   /* FreeBSD      */ || \
       defined(__DragonFly__) /* DragonFlyBSD */ || \
       defined(__gnu_hurd__)  /* GNU/HURD     */ )
constexpr int credential_message = SCM_CREDS;
typedef cmsgcred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.cmcred_pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.cmcred_euid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.cmcred_groups[0]; }

# elif defined(SCM_CREDS)
#  error SCM_CREDS macro detected but platform is unrecognized.  Please submit a patch!
# endif

int recv_cred(int socket, proccred_t& cred) noexcept
{
  struct msghdr message;
  union
  {
    char    rawbuffer[CMSG_SPACE(sizeof(cred_t))];
    cmsghdr formatted;
  } cmsg_header;

  static_assert(sizeof(cmsg_header.rawbuffer) == CMSG_SPACE(sizeof(cred_t)), "sizeof() is acting improperly");
  std::memset(cmsg_header.rawbuffer, 0, sizeof(cmsg_header.rawbuffer)); // initialize memory

  char data = 0; // dummy data
  struct iovec iov = { &data, sizeof(data) };

  message.msg_iov = &iov;
  message.msg_iovlen = 1;
  message.msg_name = NULL;
  message.msg_namelen = 0;
  message.msg_control = cmsg_header.formatted;
  message.msg_controllen = sizeof(cmsg_header.rawbuffer);
  message.msg_flags = 0;

  int nr = ::recvmsg(socket, &message, 0);
  if(nr == posix::error_response)
    return posix::error_response;

  if(CMSG_FIRSTHDR(&message) == &cmsg_header.formatted &&
     cmsg_header.formatted.cmsg_len   <= sizeof(cmsg_header.rawbuffer) &&
     cmsg_header.formatted.cmsg_level == SOL_SOCKET &&
     cmsg_header.formatted.cmsg_type  == credential_message)
  {
    const cred_t& data = *CMSG_DATA(&cmsg_header.formatted);
    cred.pid = peer_pid(data);
    cred.uid = peer_uid(data);
    cred.gid = peer_gid(data);
    return posix::success_response;
  }
  return posix::error_response;
}

int send_cred(int socket) noexcept
{
  struct msghdr message;
  union
  {
    char    rawbuffer[CMSG_SPACE(sizeof(cred_t))];
    cmsghdr formatted;
  } cmsg_header;

  static_assert(sizeof(cmsg_header.rawbuffer) == CMSG_SPACE(sizeof(cred_t)), "sizeof() is acting improperly");
  std::memset(cmsg_header.rawbuffer, 0, sizeof(cmsg_header.rawbuffer)); // initialize memory

  cmsg_header.formatted.cmsg_len   = CMSG_LEN(sizeof(cred_t));
  cmsg_header.formatted.cmsg_level = SOL_SOCKET;
  cmsg_header.formatted.cmsg_type  = credential_message;

  char data = 0; // dummy data
  struct iovec iov = { &data, sizeof(data) };

  message.msg_iov = &iov;
  message.msg_iovlen = 1;
  message.msg_name = NULL;
  message.msg_namelen = 0;
  message.msg_control = cmsg_header.formatted;
  message.msg_controllen = sizeof(cmsg_header.rawbuffer);
  message.msg_flags = 0;

  return ::sendmsg(socket, &message, 0);
}

#else

#pragma message("Socket credentials are not supported on the platform.")

int recv_cred(int socket, proccred_t& cred) noexcept
{
  cred.pid = -1;
  cred.uid = -1;
  cred.gid = -1;
  return posix::error(ENOSYS);
}

int send_cred(int) noexcept
{ return posix::error(ENOSYS); }

#endif
<commit_msg>add Darwin code<commit_after>#include "peercred.h"

// POSIX
#include <sys/socket.h>
#include <sys/un.h>

// PUT
#include <specialized/osdetect.h>
#include <cxxutils/posix_helpers.h>

#if defined(__solaris__) // Solaris
#pragma message("Information: using Solaris code")

#include <ucred.h>

int recv_cred(int socket, proccred_t& cred) noexcept
{
  uproccred_t* data = nullptr;

  int rval = ::getpeerucred(socket, &data);

  if(rval == posix::success_response)
  {
    cred.pid = ucred_getpid (data);
    cred.uid = ucred_geteuid(data);
    cred.gid = ucred_getegid(data);
    ucred_free(data);
    if (cred.pid == pid_t(-1) ||
        cred.uid == uid_t(-1) ||
        cred.gid == gid_t(-1))
      rval = posix::error_response;
  }
  return rval;
}

int send_cred(int) noexcept
{ return posix::success_response; }

#elif defined (SO_PEERCRED) || defined (LOCAL_PEEREID) /* Linux/OpenBSD/Old NetBSD */

# if defined (SO_PEERCRED) && \
    (defined(__linux__)    /* Linux    */ || \
     defined(__kfreebsd__) /* kFreeBSD */ )
constexpr int socket_cred_option = SO_PEERCRED;
typedef ucred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.uid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.gid; }

# elif defined(SO_PEERCRED) && defined(__OpenBSD__)
constexpr int socket_cred_option = SO_PEERCRED;
typedef sockpeercred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.uid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.gid; }

# elif defined(LOCAL_PEEREID) && defined(__NetBSD__) /* legacy NetBSD */
constexpr int socket_cred_option = LOCAL_PEEREID;
typedef unpcbid cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.unp_pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.unp_euid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.unp_egid; }

# elif defined(SO_PEERCRED)
#  error SO_PEERCRED macro detected but platform is unrecognized.  Please submit a patch!
# elif defined(LOCAL_PEEREID)
#  error LOCAL_PEEREID macro detected but platform is unrecognized.  Please submit a patch!
# endif

int recv_cred(int socket, proccred_t& cred) noexcept
{
  cred_t data;
  socklen_t len = sizeof(data);

  int rval = ::getsockopt(socket, SOL_SOCKET, socket_cred_option, &data, &len);

  if(len != sizeof(data))
    rval = posix::error(std::errc::invalid_argument);

  if(rval == posix::success_response)
  {
    cred.pid = peer_pid(data);
    cred.uid = peer_uid(data);
    cred.gid = peer_gid(data);
  }
  return rval;
}

int send_cred(int) noexcept
{ return posix::success_response; }

#elif defined(SCM_CREDENTIALS) || defined(SCM_CREDS) || defined(LOCAL_PEERCRED)

# if defined(SCM_CREDENTIALS) /* Linux / kFreeBSD */
constexpr int credential_message = SCM_CREDENTIALS;
typedef ucred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.uid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.gid; }

# elif defined(SCM_CREDS) && defined(__NetBSD__) /* NetBSD */
constexpr int credential_message = SCM_CREDS;
typedef cred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.sc_pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.sc_euid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.sc_egid; }

# elif defined(SCM_CREDS) && \
      (defined(__FreeBSD__)   /* FreeBSD      */ || \
       defined(__DragonFly__) /* DragonFlyBSD */ || \
       defined(__gnu_hurd__)  /* GNU/HURD     */ )
constexpr int credential_message = SCM_CREDS;
typedef cmsgcred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return data.cmcred_pid; }
constexpr uid_t peer_uid(const cred_t& data) { return data.cmcred_euid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.cmcred_groups[0]; }

# elif defined(LOCAL_PEERCRED)  /* Darwin / Old FreeBSD */
#include <sys/ucred.h>
constexpr int credential_message = LOCAL_PEERCRED;
typedef xucred cred_t;
constexpr pid_t peer_pid(const cred_t& data) { return -1; }
constexpr uid_t peer_uid(const cred_t& data) { return data.cr_uid; }
constexpr gid_t peer_gid(const cred_t& data) { return data.cr_groups[0]; }

# elif defined(SCM_CREDS)
#  error SCM_CREDS macro detected but platform is unrecognized.  Please submit a patch!
# endif

int recv_cred(int socket, proccred_t& cred) noexcept
{
  struct msghdr message;
  union
  {
    char    rawbuffer[CMSG_SPACE(sizeof(cred_t))];
    cmsghdr formatted;
  } cmsg_header;

  static_assert(sizeof(cmsg_header.rawbuffer) == CMSG_SPACE(sizeof(cred_t)), "sizeof() is acting improperly");
  std::memset(cmsg_header.rawbuffer, 0, sizeof(cmsg_header.rawbuffer)); // initialize memory

  char data = 0; // dummy data
  struct iovec iov = { &data, sizeof(data) };

  message.msg_iov = &iov;
  message.msg_iovlen = 1;
  message.msg_name = NULL;
  message.msg_namelen = 0;
  message.msg_control = cmsg_header.formatted;
  message.msg_controllen = sizeof(cmsg_header.rawbuffer);
  message.msg_flags = 0;

  int nr = ::recvmsg(socket, &message, 0);
  if(nr == posix::error_response)
    return posix::error_response;

  if(CMSG_FIRSTHDR(&message) == &cmsg_header.formatted &&
     cmsg_header.formatted.cmsg_len   <= sizeof(cmsg_header.rawbuffer) &&
     cmsg_header.formatted.cmsg_level == SOL_SOCKET &&
     cmsg_header.formatted.cmsg_type  == credential_message)
  {
    const cred_t& data = *CMSG_DATA(&cmsg_header.formatted);
    cred.pid = peer_pid(data);
    cred.uid = peer_uid(data);
    cred.gid = peer_gid(data);
    return posix::success_response;
  }
  return posix::error_response;
}

int send_cred(int socket) noexcept
{
  struct msghdr message;
  union
  {
    char    rawbuffer[CMSG_SPACE(sizeof(cred_t))];
    cmsghdr formatted;
  } cmsg_header;

  static_assert(sizeof(cmsg_header.rawbuffer) == CMSG_SPACE(sizeof(cred_t)), "sizeof() is acting improperly");
  std::memset(cmsg_header.rawbuffer, 0, sizeof(cmsg_header.rawbuffer)); // initialize memory

  cmsg_header.formatted.cmsg_len   = CMSG_LEN(sizeof(cred_t));
  cmsg_header.formatted.cmsg_level = SOL_SOCKET;
  cmsg_header.formatted.cmsg_type  = credential_message;

  char data = 0; // dummy data
  struct iovec iov = { &data, sizeof(data) };

  message.msg_iov = &iov;
  message.msg_iovlen = 1;
  message.msg_name = NULL;
  message.msg_namelen = 0;
  message.msg_control = cmsg_header.formatted;
  message.msg_controllen = sizeof(cmsg_header.rawbuffer);
  message.msg_flags = 0;

  return ::sendmsg(socket, &message, 0);
}

#else

#pragma message("Socket credentials are not supported on the platform.")

int recv_cred(int socket, proccred_t& cred) noexcept
{
  cred.pid = -1;
  cred.uid = -1;
  cred.gid = -1;
  return posix::error(ENOSYS);
}

int send_cred(int) noexcept
{ return posix::error(ENOSYS); }

#endif
<|endoftext|>