/*
 * PtokaX - hub server for Direct Connect peer to peer network.

 * Copyright (C) 2002-2005  Ptaczek, Ptaczek at PtokaX dot org
 * Copyright (C) 2004-2022  Petr Kozelka, PPK at PtokaX dot org

 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3
 * as published by the Free Software Foundation.

 * 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, see <http://www.gnu.org/licenses/>.
 */

//---------------------------------------------------------------------------
#include "stdinc.h"
//---------------------------------------------------------------------------
#include "ProfileManager.h"
//---------------------------------------------------------------------------
#include "colUsers.h"
#include "hashRegManager.h"
#include "LanguageManager.h"
#include "PXBReader.h"
#include "ServerManager.h"
#include "UdpDebug.h"
#include "User.h"
#include "utility.h"
#include "tinyxml.h"
//---------------------------------------------------------------------------
#ifdef _WIN32
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
#ifdef _BUILD_GUI
#include "../gui.win/ProfilesDialog.h"
#include "../gui.win/RegisteredUserDialog.h"
#include "../gui.win/RegisteredUsersDialog.h"
#endif
//---------------------------------------------------------------------------
ProfileManager * ProfileManager::m_Ptr = nullptr;
//---------------------------------------------------------------------------
static const char sPtokaXProfiles[] = "PtokaX Profiles";
static const size_t szPtokaXProfilesLen = sizeof(sPtokaXProfiles) - 1;
static const char sProfilePermissionIds[] = // PN reserved for profile name!
    "OP" // HASKEYICON
    "DG" // NODEFLOODGETNICKLIST
    "DM" // NODEFLOODMYINFO
    "DS" // NODEFLOODSEARCH
    "DP" // NODEFLOODPM
    "DN" // NODEFLOODMAINCHAT
    "MM" // MASSMSG
    "TO" // TOPIC
    "TB" // TEMP_BAN
    "RT" // REFRESHTXT
    "NT" // NOTAGCHECK
    "TU" // TEMP_UNBAN
    "DR" // DELREGUSER
    "AR" // ADDREGUSER
    "NC" // NOCHATLIMITS
    "NH" // NOMAXHUBCHECK
    "NR" // NOSLOTHUBRATIO
    "NS" // NOSLOTCHECK
    "NA" // NOSHARELIMIT
    "CP" // CLRPERMBAN
    "CT" // CLRTEMPBAN
    "GI" // GETINFO
    "GB" // GETBANLIST
    "RS" // RSTSCRIPTS
    "RH" // RSTHUB
    "TP" // TEMPOP
    "GG" // GAG
    "RE" // REDIRECT
    "BN" // BAN
    "KI" // KICK
    "DR" // DROP
    "EF" // ENTERFULLHUB
    "EB" // ENTERIFIPBAN
    "AO" // ALLOWEDOPCHAT
    "UI" // SENDALLUSERIP
    "RB" // RANGE_BAN
    "RU" // RANGE_UNBAN
    "RT" // RANGE_TBAN
    "RV" // RANGE_TUNBAN
    "GR" // GET_RANGE_BANS
    "CR" // CLR_RANGE_BANS
    "CU" // CLR_RANGE_TBANS
    "UN" // UNBAN
    "NT" // NOSEARCHLIMITS
    "SM" // SENDFULLMYINFOS
    "NI" // NOIPCHECK
    "CL" // CLOSE
    "DC" // NODEFLOODCTM
    "DR" // NODEFLOODRCTM
    "DT" // NODEFLOODSR
    "DU" // NODEFLOODRECV
    "CI" // NOCHATINTERVAL
    "PI" // NOPMINTERVAL
    "SI" // NOSEARCHINTERVAL
    "UI" // NOUSRSAMEIP
    "RT" // NORECONNTIME
    ;
static const size_t szProfilePermissionIdsLen = sizeof(sProfilePermissionIds) - 1;
//---------------------------------------------------------------------------

ProfileItem::ProfileItem() : m_sName(NULL)
{
	for (uint16_t ui16i = 0; ui16i < 256; ui16i++)
	{
		m_bPermissions[ui16i] = false;
	}
}
//---------------------------------------------------------------------------

ProfileItem::~ProfileItem()
{
	free(m_sName);
}
//---------------------------------------------------------------------------
void ProfileManager::Load()
{
	PXBReader pxbProfiles;

	// Open profiles file
#ifdef _WIN32
	if (pxbProfiles.OpenFileRead((ServerManager::m_sPath + "\\cfg\\Profiles.pxb").c_str(), NORECONNTIME + 2) == false)
	{
#else
	if (pxbProfiles.OpenFileRead((ServerManager::m_sPath + "/cfg/Profiles.pxb").c_str(), NORECONNTIME + 2) == false)
	{
#endif
		AppendDebugLog("%s - [ERR] Cannot open Profiles.pxb in ProfileManager::Load\n");
		return;
	}

	// Read file header
	uint16_t ui16Identificators[NORECONNTIME + 2];
	ui16Identificators[0] = *((uint16_t *)"FI");
	ui16Identificators[1] = *((uint16_t *)"FV");

	if (pxbProfiles.ReadNextItem(ui16Identificators, 2) == false)
	{
		return;
	}

	// Check header if we have correct file
	if (pxbProfiles.m_ui16ItemLengths[0] != szPtokaXProfilesLen || strncmp((char *)pxbProfiles.m_pItemDatas[0], sPtokaXProfiles, szPtokaXProfilesLen) != 0)
	{
		return;
	}

	{
		uint32_t ui32FileVersion = ntohl(*((uint32_t *)(pxbProfiles.m_pItemDatas[1])));

		if (ui32FileVersion < 1)
		{
			return;
		}
	}

	// Read settings =)
	ui16Identificators[0] = *((uint16_t *)"PN");
	memcpy(ui16Identificators + 1, sProfilePermissionIds, szProfilePermissionIdsLen);

	bool bSuccess = pxbProfiles.ReadNextItem(ui16Identificators, NORECONNTIME + 2);

	while (bSuccess == true)
	{
		ProfileItem * pNewProfile = CreateProfile((char *)pxbProfiles.m_pItemDatas[0]);

		for (uint16_t ui16i = 0; ui16i <= NORECONNTIME; ui16i++)
		{
			if (((char *)pxbProfiles.m_pItemDatas[ui16i + 1])[0] == '0')
			{
				pNewProfile->m_bPermissions[ui16i] = false;
			}
			else
			{
				pNewProfile->m_bPermissions[ui16i] = true;
			}
		}

		bSuccess = pxbProfiles.ReadNextItem(ui16Identificators, NORECONNTIME + 2);
	}
}
//---------------------------------------------------------------------------

void ProfileManager::LoadXML()
{
#ifdef _WIN32
	TiXmlDocument doc((ServerManager::m_sPath + "\\cfg\\Profiles.xml").c_str());
#else
	TiXmlDocument doc((ServerManager::m_sPath + "/cfg/Profiles.xml").c_str());
#endif
	if (doc.LoadFile() == false)
	{
		if (doc.ErrorId() != TiXmlBase::TIXML_ERROR_OPENING_FILE && doc.ErrorId() != TiXmlBase::TIXML_ERROR_DOCUMENT_EMPTY)
		{
			int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "Error loading file Profiles.xml. %s (Col: %d, Row: %d)", doc.ErrorDesc(), doc.Column(), doc.Row());
			if (iMsgLen > 0)
			{
#ifdef _BUILD_GUI
				::MessageBox(NULL, ServerManager::m_pGlobalBuffer, g_sPtokaXTitle, MB_OK | MB_ICONERROR);
#else
				AppendLog(ServerManager::m_pGlobalBuffer);
#endif
			}

			exit(EXIT_FAILURE);
		}
	}

	TiXmlHandle cfg(&doc);
	TiXmlNode *profiles = cfg.FirstChild("Profiles").Node();
	if (profiles != NULL)
	{
		TiXmlNode *child = nullptr;
		while ((child = profiles->IterateChildren(child)) != NULL)
		{
			TiXmlNode *profile = child->FirstChild("Name");

			if (profile == NULL || (profile = profile->FirstChild()) == NULL)
			{
				continue;
			}

			const char *sName = profile->Value();

			if ((profile = child->FirstChildElement("Permissions")) == NULL ||
			        (profile = profile->FirstChild()) == NULL)
			{
				continue;
			}

			const char *sRights = profile->Value();

			ProfileItem * pNewProfile = CreateProfile(sName);

			if (strlen(sRights) == 32)
			{
				for (uint8_t ui8i = 0; ui8i < 32; ui8i++)
				{
					if (sRights[ui8i] == '1')
					{
						pNewProfile->m_bPermissions[ui8i] = true;
					}
					else
					{
						pNewProfile->m_bPermissions[ui8i] = false;
					}
				}
			}
			else if (strlen(sRights) == 256)
			{
				for (uint16_t ui8i = 0; ui8i < 256; ui8i++)
				{
					if (sRights[ui8i] == '1')
					{
						pNewProfile->m_bPermissions[ui8i] = true;
					}
					else
					{
						pNewProfile->m_bPermissions[ui8i] = false;
					}
				}
			}
			else
			{
				delete pNewProfile;
				continue;
			}
		}
	}
	else
	{
#ifdef _BUILD_GUI
		::MessageBox(NULL, LanguageManager::m_Ptr->m_sTexts[LAN_PROFILES_LOAD_FAIL], g_sPtokaXTitle, MB_OK | MB_ICONERROR);
#else
		AppendLog(LanguageManager::m_Ptr->m_sTexts[LAN_PROFILES_LOAD_FAIL]);
#endif
		exit(EXIT_FAILURE);
	}
}
//---------------------------------------------------------------------------

ProfileManager::ProfileManager() : m_ppProfilesTable(NULL), m_ui16ProfileCount(0)
{
#ifdef _WIN32
	if (FileExist((ServerManager::m_sPath + "\\cfg\\Profiles.pxb").c_str()) == true)
	{
#else
	if (FileExist((ServerManager::m_sPath + "/cfg/Profiles.pxb").c_str()) == true)
	{
#endif
		Load();
		return;
#ifdef _WIN32
	}
	else if (FileExist((ServerManager::m_sPath + "\\cfg\\Profiles.xml").c_str()) == true)
	{
#else
	}
	else if (FileExist((ServerManager::m_sPath + "/cfg/Profiles.xml").c_str()) == true)
	{
#endif
		LoadXML();
		return;
	}
	else
	{
		const char * sProfileNames[] = { "Master", "Operator", "VIP", "Reg" };
		const char * sProfilePermisions[] =
		{
			"10011111111111111111111111111111111111111111101000111111",
			"10011111101111111110011000111111111000000011101000111111",
			"00000000000000011110000000000001100000000000000000000111",
			"00000000000000000000000000000001100000000000000000000000"
		};

		for (uint8_t ui8i = 0; ui8i < 4; ui8i++)
		{
			ProfileItem * pNewProfile = CreateProfile(sProfileNames[ui8i]);
			const size_t szProfilePermissionsLen = strlen(sProfilePermisions[ui8i]);
			for (uint8_t ui8j = 0; ui8j < szProfilePermissionsLen; ui8j++)
			{
				if (sProfilePermisions[ui8i][ui8j] == '1')
				{
					pNewProfile->m_bPermissions[ui8j] = true;
				}
				else
				{
					pNewProfile->m_bPermissions[ui8j] = false;
				}
			}
		}

		SaveProfiles();
	}

}
//---------------------------------------------------------------------------

ProfileManager::~ProfileManager()
{
	SaveProfiles();

	for (uint16_t ui16i = 0; ui16i < m_ui16ProfileCount; ui16i++)
	{
		delete m_ppProfilesTable[ui16i];
	}

	safe_free(m_ppProfilesTable);
}
//---------------------------------------------------------------------------

void ProfileManager::SaveProfiles()
{
	PXBReader pxbProfiles;

	// Open profiles file
#ifdef _WIN32
	if (pxbProfiles.OpenFileSave((ServerManager::m_sPath + "\\cfg\\Profiles.pxb").c_str(), NORECONNTIME + 2) == false)
	{
#else
	if (pxbProfiles.OpenFileSave((ServerManager::m_sPath + "/cfg/Profiles.pxb").c_str(), NORECONNTIME + 2) == false)
	{
#endif
		AppendDebugLog("%s - [ERR] Cannot open Profiles.pxb in ProfileManager::SaveProfiles\n");
		return;
	}

	// Write file header
	pxbProfiles.m_sItemIdentifiers[0] = 'F';
	pxbProfiles.m_sItemIdentifiers[1] = 'I';
	pxbProfiles.m_ui16ItemLengths[0] = (uint16_t)szPtokaXProfilesLen;
	pxbProfiles.m_pItemDatas[0] = (void *)sPtokaXProfiles;
	pxbProfiles.m_ui8ItemValues[0] = PXBReader::PXB_STRING;

	pxbProfiles.m_sItemIdentifiers[2] = 'F';
	pxbProfiles.m_sItemIdentifiers[3] = 'V';
	pxbProfiles.m_ui16ItemLengths[1] = 4;
	uint32_t ui32Version = 1;
	pxbProfiles.m_pItemDatas[1] = (void *)&ui32Version;
	pxbProfiles.m_ui8ItemValues[1] = PXBReader::PXB_FOUR_BYTES;

	if (pxbProfiles.WriteNextItem(szPtokaXProfilesLen + 4, 2) == false)
	{
		return;
	}

	pxbProfiles.m_sItemIdentifiers[0] = 'P';
	pxbProfiles.m_sItemIdentifiers[1] = 'N';
	pxbProfiles.m_ui8ItemValues[0] = PXBReader::PXB_STRING;

	memcpy(pxbProfiles.m_sItemIdentifiers + 2, sProfilePermissionIds, szProfilePermissionIdsLen);
	memset(pxbProfiles.m_ui8ItemValues + 1, PXBReader::PXB_BYTE, NORECONNTIME + 1);

	for (uint16_t ui16i = 0; ui16i < m_ui16ProfileCount; ui16i++)
	{
		pxbProfiles.m_ui16ItemLengths[0] = (uint16_t)strlen(m_ppProfilesTable[ui16i]->m_sName);
		pxbProfiles.m_pItemDatas[0] = (void *)m_ppProfilesTable[ui16i]->m_sName;
		pxbProfiles.m_ui8ItemValues[0] = PXBReader::PXB_STRING;

		for (uint16_t ui16j = 0; ui16j <= NORECONNTIME; ui16j++)
		{
			pxbProfiles.m_ui16ItemLengths[ui16j + 1] = 1;
			pxbProfiles.m_pItemDatas[ui16j + 1] = (m_ppProfilesTable[ui16i]->m_bPermissions[ui16j] == true ? (void *)1 : 0);
			pxbProfiles.m_ui8ItemValues[ui16j + 1] = PXBReader::PXB_BYTE;
		}

		if (pxbProfiles.WriteNextItem(pxbProfiles.m_ui16ItemLengths[0] + NORECONNTIME + 1, NORECONNTIME + 2) == false)
		{
			break;
		}
	}

	pxbProfiles.WriteRemaining();
}
//---------------------------------------------------------------------------

bool ProfileManager::IsAllowed(const User * pUser, const uint32_t ui32Option) const
{
	// profile number -1 = normal user/no profile assigned
	if (pUser->m_i32Profile == -1)
		return false;

	// return right of the profile
	return m_ppProfilesTable[pUser->m_i32Profile]->m_bPermissions[ui32Option];
}
//---------------------------------------------------------------------------

bool ProfileManager::IsProfileAllowed(const int32_t i32Profile, const uint32_t ui32Option) const
{
	// profile number -1 = normal user/no profile assigned
	if (i32Profile == -1)
		return false;

	// return right of the profile
	return m_ppProfilesTable[i32Profile]->m_bPermissions[ui32Option];
}
//---------------------------------------------------------------------------

int32_t ProfileManager::AddProfile(const char * sName)
{
	for (uint16_t ui16i = 0; ui16i < m_ui16ProfileCount; ui16i++)
	{
		if (strcasecmp(m_ppProfilesTable[ui16i]->m_sName, sName) == 0)
		{
			return -1;
		}
	}

	uint32_t ui32j = 0;
	while (true)
	{
		switch (sName[ui32j])
		{
		case '\0':
			break;
		case '|':
			return -2;
		default:
			if (sName[ui32j] < 33)
			{
				return -2;
			}

			ui32j++;
			continue;
		}

		break;
	}

	CreateProfile(sName);

#ifdef _BUILD_GUI
	if (ProfilesDialog::m_Ptr != NULL)
	{
		ProfilesDialog::m_Ptr->AddProfile();
	}
#endif

#ifdef _BUILD_GUI
	if (RegisteredUserDialog::m_Ptr != NULL)
	{
		RegisteredUserDialog::m_Ptr->UpdateProfiles();
	}
#endif

	return (int32_t)(m_ui16ProfileCount - 1);
}
//---------------------------------------------------------------------------

int32_t ProfileManager::GetProfileIndex(const char * sName)
{
	for (uint16_t ui16i = 0; ui16i < m_ui16ProfileCount; ui16i++)
	{
		if (strcasecmp(m_ppProfilesTable[ui16i]->m_sName, sName) == 0)
		{
			return ui16i;
		}
	}

	return -1;
}
//---------------------------------------------------------------------------

// RemoveProfileByName(name)
// returns: 0 if the name doesnot exists or is a default profile idx 0-3
//          -1 if the profile is in use
//          1 on success
int32_t ProfileManager::RemoveProfileByName(const char * sName)
{
	for (uint16_t ui16i = 0; ui16i < m_ui16ProfileCount; ui16i++)
	{
		if (strcasecmp(m_ppProfilesTable[ui16i]->m_sName, sName) == 0)
		{
			return (RemoveProfile(ui16i) == true ? 1 : -1);
		}
	}

	return 0;
}

//---------------------------------------------------------------------------

bool ProfileManager::RemoveProfile(const uint16_t ui16Profile)
{
	RegUser * curReg = NULL,
	          * next = RegManager::m_Ptr->m_pRegListS;

	while (next != NULL)
	{
		curReg = next;
		next = curReg->m_pNext;

		if (curReg->m_ui16Profile == ui16Profile)
		{
			//Profile in use can't be deleted!
			return false;
		}
	}

	m_ui16ProfileCount--;

#ifdef _BUILD_GUI
	if (ProfilesDialog::m_Ptr != NULL)
	{
		ProfilesDialog::m_Ptr->RemoveProfile(ui16Profile);
	}
#endif

	delete m_ppProfilesTable[ui16Profile];

	for (uint16_t ui16i = ui16Profile; ui16i < m_ui16ProfileCount; ui16i++)
	{
		m_ppProfilesTable[ui16i] = m_ppProfilesTable[ui16i + 1];
	}

	// Update profiles for online users
	if (ServerManager::m_bServerRunning == true)
	{
		User * curUser = NULL,
		       * nextUser = Users::m_Ptr->m_pUserListS;

		while (nextUser != NULL)
		{
			curUser = nextUser;
			nextUser = curUser->m_pNext;

			if (curUser->m_i32Profile > ui16Profile)
			{
				curUser->m_i32Profile--;
			}
		}
	}

	// Update profiles for registered users
	next = RegManager::m_Ptr->m_pRegListS;
	while (next != NULL)
	{
		curReg = next;
		next = curReg->m_pNext;
		if (curReg->m_ui16Profile > ui16Profile)
		{
			curReg->m_ui16Profile--;
		}
	}

	ProfileItem ** pOldTable = m_ppProfilesTable;
	m_ppProfilesTable = (ProfileItem **)realloc(pOldTable, m_ui16ProfileCount * sizeof(ProfileItem *));
	if (m_ppProfilesTable == NULL)
	{
		m_ppProfilesTable = pOldTable;

		AppendDebugLog("%s - [MEM] Cannot reallocate m_ppProfilesTable in ProfileManager::RemoveProfile\n");
	}

#ifdef _BUILD_GUI
	if (RegisteredUserDialog::m_Ptr != NULL)
	{
		RegisteredUserDialog::m_Ptr->UpdateProfiles();
	}

	if (RegisteredUsersDialog::m_Ptr != NULL)
	{
		RegisteredUsersDialog::m_Ptr->UpdateProfiles();
	}
#endif

	return true;
}
//---------------------------------------------------------------------------

ProfileItem * ProfileManager::CreateProfile(const char * sName)
{
	ProfileItem ** pOldTable = m_ppProfilesTable;
	m_ppProfilesTable = (ProfileItem **)realloc(pOldTable, (m_ui16ProfileCount + 1) * sizeof(ProfileItem *));
	if (m_ppProfilesTable == NULL)
	{
		free(pOldTable);
		AppendDebugLog("%s - [MEM] Cannot (re)allocate ProfilesTable in ProfileManager::CreateProfile\n");
		exit(EXIT_FAILURE);
	}

	ProfileItem * pNewProfile = new (std::nothrow) ProfileItem();
	if (pNewProfile == NULL)
	{
		AppendDebugLog("%s - [MEM] Cannot allocate pNewProfile in ProfileManager::CreateProfile\n");
		exit(EXIT_FAILURE);
	}

	const size_t szLen = strlen(sName);
	pNewProfile->m_sName = (char *)malloc(szLen + 1);
	if (pNewProfile->m_sName == NULL)
	{
		AppendDebugLogFormat("[MEM] Cannot allocate %zu bytes in ProfileManager::CreateProfile for pNewProfile->m_sName\n", szLen);

		exit(EXIT_FAILURE);
	}
	memcpy(pNewProfile->m_sName, sName, szLen);
	pNewProfile->m_sName[szLen] = '\0';

	for (uint16_t ui16i = 0; ui16i < 256; ui16i++)
	{
		pNewProfile->m_bPermissions[ui16i] = false;
	}

	m_ui16ProfileCount++;

	m_ppProfilesTable[m_ui16ProfileCount - 1] = pNewProfile;

	return pNewProfile;
}
//---------------------------------------------------------------------------

void ProfileManager::MoveProfileDown(const uint16_t ui16Profile)
{
	ProfileItem *first = m_ppProfilesTable[ui16Profile];
	ProfileItem *second = m_ppProfilesTable[ui16Profile + 1];

	m_ppProfilesTable[ui16Profile + 1] = first;
	m_ppProfilesTable[ui16Profile] = second;

	RegUser * curReg = NULL,
	          * nextReg = RegManager::m_Ptr->m_pRegListS;

	while (nextReg != NULL)
	{
		curReg = nextReg;
		nextReg = curReg->m_pNext;

		if (curReg->m_ui16Profile == ui16Profile)
		{
			curReg->m_ui16Profile++;
		}
		else if (curReg->m_ui16Profile == ui16Profile + 1)
		{
			curReg->m_ui16Profile--;
		}
	}

#ifdef _BUILD_GUI
	if (ProfilesDialog::m_Ptr != NULL)
	{
		ProfilesDialog::m_Ptr->MoveDown(ui16Profile);
	}

	if (RegisteredUserDialog::m_Ptr != NULL)
	{
		RegisteredUserDialog::m_Ptr->UpdateProfiles();
	}

	if (RegisteredUsersDialog::m_Ptr != NULL)
	{
		RegisteredUsersDialog::m_Ptr->UpdateProfiles();
	}
#endif

	if (Users::m_Ptr == NULL)
	{
		return;
	}

	User * curUser = NULL,
	       * nextUser = Users::m_Ptr->m_pUserListS;

	while (nextUser != NULL)
	{
		curUser = nextUser;
		nextUser = curUser->m_pNext;

		if (curUser->m_i32Profile == (int32_t)ui16Profile)
		{
			curUser->m_i32Profile++;
		}
		else if (curUser->m_i32Profile == (int32_t)(ui16Profile + 1))
		{
			curUser->m_i32Profile--;
		}
	}
}
//---------------------------------------------------------------------------

void ProfileManager::MoveProfileUp(const uint16_t ui16Profile)
{
	ProfileItem *first = m_ppProfilesTable[ui16Profile];
	ProfileItem *second = m_ppProfilesTable[ui16Profile - 1];

	m_ppProfilesTable[ui16Profile - 1] = first;
	m_ppProfilesTable[ui16Profile] = second;

	RegUser * curReg = NULL,
	          * nextReg = RegManager::m_Ptr->m_pRegListS;

	while (nextReg != NULL)
	{
		curReg = nextReg;
		nextReg = curReg->m_pNext;

		if (curReg->m_ui16Profile == ui16Profile)
		{
			curReg->m_ui16Profile--;
		}
		else if (curReg->m_ui16Profile == ui16Profile - 1)
		{
			curReg->m_ui16Profile++;
		}
	}

#ifdef _BUILD_GUI
	if (ProfilesDialog::m_Ptr != NULL)
	{
		ProfilesDialog::m_Ptr->MoveUp(ui16Profile);
	}

	if (RegisteredUserDialog::m_Ptr != NULL)
	{
		RegisteredUserDialog::m_Ptr->UpdateProfiles();
	}

	if (RegisteredUsersDialog::m_Ptr != NULL)
	{
		RegisteredUsersDialog::m_Ptr->UpdateProfiles();
	}
#endif

	if (Users::m_Ptr == NULL)
	{
		return;
	}

	User * curUser = NULL,
	       * nextUser = Users::m_Ptr->m_pUserListS;

	while (nextUser != NULL)
	{
		curUser = nextUser;
		nextUser = curUser->m_pNext;

		if (curUser->m_i32Profile == (int32_t)ui16Profile)
		{
			curUser->m_i32Profile--;
		}
		else if (curUser->m_i32Profile == (int32_t)(ui16Profile - 1))
		{
			curUser->m_i32Profile++;
		}
	}
}
//---------------------------------------------------------------------------

void ProfileManager::ChangeProfileName(const uint16_t ui16Profile, const char * sName, const size_t szLen)
{
	char * sOldName = m_ppProfilesTable[ui16Profile]->m_sName;

	m_ppProfilesTable[ui16Profile]->m_sName = (char *)realloc(sOldName, szLen + 1);
	if (m_ppProfilesTable[ui16Profile]->m_sName == NULL)
	{
		m_ppProfilesTable[ui16Profile]->m_sName = sOldName;

		AppendDebugLogFormat("[MEM] Cannot reallocate %zu bytes in ProfileManager::ChangeProfileName for m_ppProfilesTable[ui16Profile]->m_sName\n", szLen);

		return;
	}
	memcpy(m_ppProfilesTable[ui16Profile]->m_sName, sName, szLen);
	m_ppProfilesTable[ui16Profile]->m_sName[szLen] = '\0';

#ifdef _BUILD_GUI
	if (RegisteredUserDialog::m_Ptr != NULL)
	{
		RegisteredUserDialog::m_Ptr->UpdateProfiles();
	}

	if (RegisteredUsersDialog::m_Ptr != NULL)
	{
		RegisteredUsersDialog::m_Ptr->UpdateProfiles();
	}
#endif
}
//---------------------------------------------------------------------------

void ProfileManager::ChangeProfilePermission(const uint16_t ui16Profile, const size_t szId, const bool bValue)
{
	m_ppProfilesTable[ui16Profile]->m_bPermissions[szId] = bValue;
}
//---------------------------------------------------------------------------

V1042 This file is marked with copyleft license, which requires you to open the derived source code.

V1032 The pointer '"FI"' is cast to a more strictly aligned pointer type.

V1032 The pointer '"FV"' is cast to a more strictly aligned pointer type.

V1032 The pointer '"PN"' is cast to a more strictly aligned pointer type.