/*
 * 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 "DcCommands.h"
//---------------------------------------------------------------------------
#include "colUsers.h"
#include "GlobalDataQueue.h"
#include "hashBanManager.h"
#include "hashRegManager.h"
#include "hashUsrManager.h"
#include "LanguageManager.h"
#include "LuaScriptManager.h"
#include "ProfileManager.h"
#include "ServerManager.h"
#include "SettingManager.h"
#include "UdpDebug.h"
#include "User.h"
#include "utility.h"
#include "ZlibUtility.h"
#ifdef USE_FLYLINKDC_EXT_JSON
#include "../json/json.hpp"
#include <algorithm>
#endif

//---------------------------------------------------------------------------
#ifdef _WIN32
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
#include "DeFlood.h"
#include "HubCommands.h"
#include "IP2Country.h"
#include "ResNickManager.h"
#include "TextFileManager.h"
//---------------------------------------------------------------------------
#ifdef _BUILD_GUI
#include "../gui.win/GuiUtil.h"
#include "../gui.win/MainWindowPageUsersChat.h"
#endif

#ifdef _WITH_SQLITE
#include "DB-SQLite.h"
#elif _WITH_POSTGRES
#include "DB-PostgreSQL.h"
#elif _WITH_MYSQL
#include "DB-MySQL.h"
#endif

//---------------------------------------------------------------------------
DcCommands * DcCommands::m_Ptr = NULL;
//---------------------------------------------------------------------------

DcCommands::PassBf::PassBf(const uint8_t * ui128Hash) : m_pPrev(NULL), m_pNext(NULL), m_iCount(1)
{
	m_ui128IpHash.init(ui128Hash);
}
//---------------------------------------------------------------------------

DcCommands::DcCommands() : m_pPasswdBfCheck(NULL), m_ui32StatChat(0), m_ui32StatCmdUnknown(0), m_ui32StatCmdTo(0), m_ui32StatCmdMyInfo(0), m_ui32StatCmdSearch(0), m_ui32StatCmdSR(0), m_ui32StatCmdRevCTM(0), m_ui32StatCmdOpForceMove(0), m_ui32StatCmdMyPass(0),
	m_ui32StatCmdValidate(0), m_ui32StatCmdKey(0), m_ui32StatCmdGetInfo(0), m_ui32StatCmdGetNickList(0), m_ui32StatCmdConnectToMe(0), m_ui32StatCmdVersion(0), m_ui32StatCmdKick(0), m_ui32StatCmdSupports(0), m_ui32StatBotINFO(0), m_ui32StatZPipe(0), m_ui32StatCmdMultiSearch(0),
	m_ui32StatCmdMultiConnectToMe(0), m_ui32StatCmdClose(0)
{
	// ...
#ifdef USE_FLYLINKDC_EXT_JSON
	m_iStatCmdExtJSON = 0;
#endif
}
//---------------------------------------------------------------------------

DcCommands::~DcCommands()
{
	PassBf * cur = NULL,
	         * next = m_pPasswdBfCheck;

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

		delete cur;
	}

	m_pPasswdBfCheck = NULL;
}
//---------------------------------------------------------------------------

// Process DC data form User
void DcCommands::PreProcessData(DcCommand * pDcCommand)
{
#ifdef USE_FLYLINKDC_EXT_JSON
	bool bCheck = true; // TODO
#endif
#ifdef _BUILD_GUI
	// Full raw data trace for better logging
	if (::SendMessage(MainWindowPageUsersChat::m_Ptr->m_hWndPageItems[MainWindowPageUsersChat::BTN_SHOW_COMMANDS], BM_GETCHECK, 0, 0) == BST_CHECKED)
	{
		int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "%s (%s) > ", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);
		if (iMsgLen > 0)
		{
			RichEditAppendText(MainWindowPageUsersChat::m_Ptr->m_hWndPageItems[MainWindowPageUsersChat::REDT_CHAT], (ServerManager::m_pGlobalBuffer + string(pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen)).c_str());
		}
	}
#endif

	// micro spam
	if (pDcCommand->m_ui32CommandLen < 5)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Garbage DATA from %s (%s) -> %s", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (pDcCommand->m_sCommand[0] == '$')
		{
			if(const auto l_end_command = strchr(pDcCommand->m_sCommand,' '))
			{
			   const auto c = *l_end_command;
			   *l_end_command = 0x00;
			   GlobalDataQueue::m_Ptr->m_flylinkdc_hub_dc_commands_counter.Add({{"command", pDcCommand->m_sCommand}}).Increment();
			   *l_end_command = c;
			}
	}

	static const uint32_t ui32ulti = *((uint32_t *)"ulti");
	static const uint32_t ui32ick = *((uint32_t *)"ick ");

	switch (pDcCommand->m_pUser->m_ui8State)
	{
	case User::STATE_SOCKET_ACCEPTED:
		if (pDcCommand->m_sCommand[0] == '$')
		{
			if (memcmp(pDcCommand->m_sCommand + 1, "MyNick ", 7) == 0)
			{
				MyNick(pDcCommand);
				return;
			}
		}
		break;
	case User::STATE_KEY_OR_SUP:
		if (pDcCommand->m_sCommand[0] == '$')
		{
			if (memcmp(pDcCommand->m_sCommand + 1, "Supports ", 9) == 0)
			{
				m_ui32StatCmdSupports++;
				Supports(pDcCommand);
				return;
			}
			else if (*((uint32_t *)(pDcCommand->m_sCommand + 1)) == *((uint32_t *)"Key "))
			{
				m_ui32StatCmdKey++;
				Key(pDcCommand);
				return;
			}
			else if (memcmp(pDcCommand->m_sCommand + 1, "MyNick ", 7) == 0)
			{
				MyNick(pDcCommand);
				return;
			}
		}
		break;
	case User::STATE_VALIDATE:
	{
		if (pDcCommand->m_sCommand[0] == '$')
		{
			switch (pDcCommand->m_sCommand[1])
			{
			case 'K':
				if (memcmp(pDcCommand->m_sCommand + 2, "ey ", 3) == 0)
				{
					m_ui32StatCmdKey++;
					if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HAVE_SUPPORTS) == User::BIT_HAVE_SUPPORTS) == false)
					{
						Key(pDcCommand);
					}
					else
					{
						pDcCommand->m_pUser->FreeBuffer();
					}

					return;
				}
				break;
			case 'V':
				if (memcmp(pDcCommand->m_sCommand + 2, "alidateNick ", 12) == 0)
				{
					m_ui32StatCmdValidate++;
					ValidateNick(pDcCommand);
					return;
				}
				break;
#ifdef USE_FLYLINKDC_EXT_JSON
			case 'E':
				if (memcmp(pDcCommand->m_sCommand + 2, "xtJSON ", 7) == 0)
				{
					m_iStatCmdExtJSON++;
				}
				break;
#endif // USE_FLYLINKDC_EXT_JSON

			case 'M':
				if (memcmp(pDcCommand->m_sCommand + 2, "yINFO $ALL ", 11) == 0)
				{
					m_ui32StatCmdMyInfo++;
					if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == false)
					{
						// bad state
						UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $MyINFO %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

						pDcCommand->m_pUser->Close();
						return;
					}

					if (MyINFODeflood(pDcCommand) == false)
					{
						return;
					}

					// PPK [ Strikes back ;) ] ... get nick from MyINFO
					char *cTemp;
					if ((cTemp = strchr(pDcCommand->m_sCommand + 13, ' ')) == NULL)
					{
						UdpDebug::m_Ptr->BroadcastFormat("[SYS] Attempt to validate empty nick  from %s (%s) - user closed. (QuickList -> %s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

						pDcCommand->m_pUser->Close();
						return;
					}
					// PPK ... one null please :)
					cTemp[0] = '\0';

					if (ValidateUserNick(pDcCommand, pDcCommand->m_pUser, pDcCommand->m_sCommand + 13, (cTemp - pDcCommand->m_sCommand) - 13, false) == false) return;

					cTemp[0] = ' ';

					// 1st time MyINFO, user is being added to nicklist
					if (MyINFO(pDcCommand) == false || (pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_WAITING_FOR_PASS) == User::BIT_WAITING_FOR_PASS ||
					        ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == true)
						return;

					pDcCommand->m_pUser->AddMeOrIPv4Check();

					return;
				}
				break;
			case 'G':
				if (pDcCommand->m_ui32CommandLen == 13 && memcmp(pDcCommand->m_sCommand + 2, "etNickList", 10) == 0)
				{
					m_ui32StatCmdGetNickList++;
					if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == false &&
					        ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == false)
					{
						// bad state
						UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $GetNickList %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

						pDcCommand->m_pUser->Close();
						return;
					}
					GetNickList(pDcCommand);
					return;
				}
				break;
			default:
				break;
			}
		}
		break;
	}
	case User::STATE_VERSION_OR_MYPASS:
	{
		if (pDcCommand->m_sCommand[0] == '$')
		{
			switch (pDcCommand->m_sCommand[1])
			{
			case 'V':
				if (memcmp(pDcCommand->m_sCommand + 2, "ersion ", 7) == 0)
				{
					m_ui32StatCmdVersion++;
					Version(pDcCommand);
					return;
				}
				break;
			case 'G':
				if (pDcCommand->m_ui32CommandLen == 13 && memcmp(pDcCommand->m_sCommand + 2, "etNickList", 10) == 0)
				{
					m_ui32StatCmdGetNickList++;
					if (GetNickList(pDcCommand) == true && ((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == false)
					{
						pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_GETNICKLIST;
					}
					return;
				}
				break;
#ifdef USE_FLYLINKDC_EXT_JSON
			case 'E':
				if (memcmp(pDcCommand->m_sCommand + 2, "xtJSON ", 7) == 0)
				{
					m_iStatCmdExtJSON++;
				}
				break;
#endif // USE_FLYLINKDC_EXT_JSON
			case 'M':
				if (pDcCommand->m_sCommand[2] == 'y')
				{
					if (memcmp(pDcCommand->m_sCommand + 3, "INFO $ALL ", 10) == 0)
					{
						m_ui32StatCmdMyInfo++;
						if (MyINFODeflood(pDcCommand) == false)
						{
							return;
						}

						// Am I sending MyINFO of someone other ?
						// OR i try to fuck up hub with some chars after my nick ??? ... PPK
						if ((pDcCommand->m_sCommand[13 + pDcCommand->m_pUser->m_ui8NickLen] != ' ') || (memcmp(pDcCommand->m_pUser->m_sNick, pDcCommand->m_sCommand + 13, pDcCommand->m_pUser->m_ui8NickLen) != 0))
						{
							UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in myinfo from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

							pDcCommand->m_pUser->Close();
							return;
						}

						if (MyINFO(pDcCommand) == false || (pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_WAITING_FOR_PASS) == User::BIT_WAITING_FOR_PASS || ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == true)
						{
							return;
						}

						pDcCommand->m_pUser->AddMeOrIPv4Check();

						return;
					}
					else if (memcmp(pDcCommand->m_sCommand + 3, "Pass ", 5) == 0)
					{
						m_ui32StatCmdMyPass++;
						MyPass(pDcCommand);
						return;
					}
				}
				break;
			default:
				break;
			}
		}
		break;
	}
	case User::STATE_GETNICKLIST_OR_MYINFO:
	{
		if (pDcCommand->m_sCommand[0] == '$')
		{
			if (pDcCommand->m_ui32CommandLen == 13 && memcmp(pDcCommand->m_sCommand + 1, "GetNickList", 11) == 0)
			{
				m_ui32StatCmdGetNickList++;
				if (GetNickList(pDcCommand) == true)
				{
					pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_GETNICKLIST;
				}
				return;
			}
			else if (memcmp(pDcCommand->m_sCommand + 1, "MyINFO $ALL ", 12) == 0)
			{
				m_ui32StatCmdMyInfo++;
				if (MyINFODeflood(pDcCommand) == false)
				{
					return;
				}

				// Am I sending MyINFO of someone other ?
				// OR i try to fuck up hub with some chars after my nick ??? ... PPK
				if ((pDcCommand->m_sCommand[13 + pDcCommand->m_pUser->m_ui8NickLen] != ' ') || (memcmp(pDcCommand->m_pUser->m_sNick, pDcCommand->m_sCommand + 13, pDcCommand->m_pUser->m_ui8NickLen) != 0))
				{
					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in myinfo from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

					pDcCommand->m_pUser->Close();
					return;
				}

				if (MyINFO(pDcCommand) == false || (pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_WAITING_FOR_PASS) == User::BIT_WAITING_FOR_PASS ||
				        ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == true)
					return;

				pDcCommand->m_pUser->AddMeOrIPv4Check();

				return;
			}
#ifdef USE_FLYLINKDC_EXT_JSON
			else if (memcmp(pDcCommand->m_sCommand + 1, "ExtJSON ", 8) == 0)
			{
				m_iStatCmdExtJSON++;
			}
#endif // USE_FLYLINKDC_EXT_JSON
		}
		break;
	}
	case User::STATE_IPV4_CHECK:
	case User::STATE_ADDME:
	case User::STATE_ADDME_1LOOP:
	{
		if (pDcCommand->m_sCommand[0] == '$')
		{
			if(const auto l_end_command = strchr(pDcCommand->m_sCommand,' '))
			{
			   const auto c = *l_end_command;
			   *l_end_command = 0x00;
			   GlobalDataQueue::m_Ptr->m_flylinkdc_hub_dc_commands_counter.Add({{"command", pDcCommand->m_sCommand}}).Increment();
			   *l_end_command = c;
			}

			switch (pDcCommand->m_sCommand[1])
			{
			case 'G':
				if (pDcCommand->m_ui32CommandLen == 13 && memcmp(pDcCommand->m_sCommand + 2, "etNickList", 10) == 0)
				{
					m_ui32StatCmdGetNickList++;
					if (GetNickList(pDcCommand) == true)
					{
						pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_GETNICKLIST;
					}
					return;
				}
				break;
#ifdef USE_FLYLINKDC_EXT_JSON
			case 'E':
				if (memcmp(pDcCommand->m_sCommand + 2, "xtJSON ", 7) == 0)
				{
					m_iStatCmdExtJSON++; // ExtJSON Step 1 First Login
					if (ExtJSONDeflood(pDcCommand->m_pUser, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, bCheck) == false)
					{
						return;
					}
					{
						//using json = nlohmann::json;
						const auto l_pos_json = strchr(pDcCommand->m_sCommand + 10, ' ');
						std::string l_json_str;
						std::string l_nick;
						if (l_pos_json)
						{
							const int l_len_header = l_pos_json - pDcCommand->m_sCommand;
							l_json_str = std::string(l_pos_json, pDcCommand->m_ui32CommandLen - l_len_header);
							l_nick = std::string(pDcCommand->m_sCommand, l_len_header);
							if (l_json_str.size() > 3 && l_json_str[l_json_str.size() - 1] == '|' && l_json_str[l_json_str.size() - 2] == '}')
							{
								l_json_str = l_json_str.substr(0, l_json_str.size() - 1);
								for (auto i = l_json_str.begin(); i != l_json_str.end(); ++i)
								{
									if ((unsigned char)(*i) >= 0x80)
									{
										*i = '.';
									}
								}
							}
						}
						try
						{
							auto l_json = nlohmann::json::parse(l_json_str);
						}
						catch (const std::exception& e)
						{
							pDcCommand->m_pUser->m_is_invalid_json = true;
							pDcCommand->m_pUser->logInvalidUser(-1, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, false);
							printf("Error parse JSON: IP = %s JSON: %s Len = %u error = %s\r\n",
							       pDcCommand->m_pUser->m_sIP, l_nick.c_str(), pDcCommand->m_ui32CommandLen, e.what());
#ifndef _WIN32
							syslog(LOG_NOTICE, "Error parse JSON: IP = %s JSON: %s Len = %u error = %s", pDcCommand->m_pUser->m_sIP, l_nick.c_str(), pDcCommand->m_ui32CommandLen, e.what());
#endif
							UdpDebug::m_Ptr->BroadcastFormat("Error parse JSON: IP = %s JSON: %s Len = %u error = %s\r\n", pDcCommand->m_pUser->m_sIP, l_nick.c_str(), pDcCommand->m_ui32CommandLen, e.what());

							pDcCommand->m_pUser->Close();
							return;
						}
					}
					pDcCommand->m_pUser->initExtJSON(pDcCommand->m_sCommand);
#ifdef USE_FLYLINKDC_EXT_JSON
					ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::EXTJSON_ARRIVAL);
#endif
				}
				break;
#endif // USE_FLYLINKDC_EXT_JSON
			case 'M':
			{
				if (memcmp(pDcCommand->m_sCommand + 2, "yINFO $ALL ", 11) == 0)
				{
					m_ui32StatCmdMyInfo++;
					if (MyINFODeflood(pDcCommand) == false)
					{
						return;
					}

					// Am I sending MyINFO of someone other ?
					// OR i try to fuck up hub with some chars after my nick ??? ... PPK
					if ((pDcCommand->m_sCommand[13 + pDcCommand->m_pUser->m_ui8NickLen] != ' ') || (memcmp(pDcCommand->m_pUser->m_sNick, pDcCommand->m_sCommand + 13, pDcCommand->m_pUser->m_ui8NickLen) != 0))
					{
						UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in myinfo from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

						pDcCommand->m_pUser->Close();
						return;
					}

					MyINFO(pDcCommand);

					return;
				}
				else if (memcmp(pDcCommand->m_sCommand + 2, "ultiSearch ", 11) == 0)
				{
					m_ui32StatCmdMultiSearch++;
					SearchDeflood(pDcCommand, true);
					return;
				}
				break;
			}
			case 'S':
				if (memcmp(pDcCommand->m_sCommand + 2, "earch ", 6) == 0)
				{
					m_ui32StatCmdSearch++;
					SearchDeflood(pDcCommand, false);
					return;
				}
				break;
			default:
				break;
			}
		}
		else if (pDcCommand->m_sCommand[0] == '<')
		{
			m_ui32StatChat++;
			ChatDeflood(pDcCommand);
			return;
		}
		break;
	}
	case User::STATE_ADDED:
	{
		if (pDcCommand->m_sCommand[0] == '$')
		{
			switch (pDcCommand->m_sCommand[1])
			{
			case 'S':
			{
				if (memcmp(pDcCommand->m_sCommand + 2, "earch ", 6) == 0)
				{
					m_ui32StatCmdSearch++;
					if (SearchDeflood(pDcCommand, false) == true)
					{
						Search(pDcCommand, false);
					}
					return;
				}
				else if (*((uint16_t *)(pDcCommand->m_sCommand + 2)) == *((uint16_t *)"R "))
				{
					m_ui32StatCmdSR++;
					SR(pDcCommand);
					return;
				}
				break;
			}
			case 'C':
				if (memcmp(pDcCommand->m_sCommand + 2, "onnectToMe ", 11) == 0)
				{
					m_ui32StatCmdConnectToMe++;
					ConnectToMe(pDcCommand, false);
					return;
				}
				else if (memcmp(pDcCommand->m_sCommand + 2, "lose ", 5) == 0)
				{
					m_ui32StatCmdClose++;
					Close(pDcCommand);
					return;
				}
				break;
			case 'R':
				if (memcmp(pDcCommand->m_sCommand + 2, "evConnectToMe ", 14) == 0)
				{
					m_ui32StatCmdRevCTM++;
					RevConnectToMe(pDcCommand);
					return;
				}
				break;
#ifdef USE_FLYLINKDC_EXT_JSON
			case 'E':
				if (memcmp(pDcCommand->m_sCommand + 2, "xtJSON ", 7) == 0)
				{
					m_iStatCmdExtJSON++; // ExtJSON Step 3 - Change ExtJSON
					if (ExtJSONDeflood(pDcCommand->m_pUser, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, bCheck) == false)
					{
						return;
					}

					SetExtJSON(pDcCommand->m_pUser, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen);
					return;
				}
				break;
#endif // USE_FLYLINKDC_EXT_JSON

			case 'M':
				if (memcmp(pDcCommand->m_sCommand + 2, "yINFO $ALL ", 11) == 0)
				{
					m_ui32StatCmdMyInfo++;
					if (MyINFODeflood(pDcCommand) == false)
					{
						return;
					}

					// Am I sending MyINFO of someone other ?
					// OR i try to fuck up hub with some chars after my nick ??? ... PPK
					if ((pDcCommand->m_sCommand[13 + pDcCommand->m_pUser->m_ui8NickLen] != ' ') || (memcmp(pDcCommand->m_pUser->m_sNick, pDcCommand->m_sCommand + 13, pDcCommand->m_pUser->m_ui8NickLen) != 0))
					{
						UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in myinfo from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

						pDcCommand->m_pUser->Close();
						return;
					}

					if (MyINFO(pDcCommand) == true)
					{
						pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_PRCSD_MYINFO;
					}
					return;
				}
				else if (*((uint32_t *)(pDcCommand->m_sCommand + 2)) == ui32ulti)
				{
					if (memcmp(pDcCommand->m_sCommand + 6, "Search ", 7) == 0)
					{
						m_ui32StatCmdMultiSearch++;
						if (SearchDeflood(pDcCommand, true) == true)
						{
							Search(pDcCommand, true);
						}
						return;
					}
					else if (memcmp(pDcCommand->m_sCommand + 6, "ConnectToMe ", 12) == 0)
					{
						m_ui32StatCmdMultiConnectToMe++;
						ConnectToMe(pDcCommand, true);
						return;
					}
				}
				else if (memcmp(pDcCommand->m_sCommand + 2, "yPass ", 6) == 0)
				{
					m_ui32StatCmdMyPass++;
					//MyPass(pUser, sData, ui32Len);
					if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_WAITING_FOR_PASS) == User::BIT_WAITING_FOR_PASS)
					{
						pDcCommand->m_pUser->m_ui32BoolBits &= ~User::BIT_WAITING_FOR_PASS;

						if (pDcCommand->m_pUser->m_LogInOut.m_pBuffer != NULL)
						{
							int iProfile = ProfileManager::m_Ptr->GetProfileIndex(pDcCommand->m_pUser->m_LogInOut.m_pBuffer);
							if (iProfile == -1)
							{
								pDcCommand->m_pUser->SendFormat("DcCommands::PreProcessData::MyPass->RegUser1", true, "<%s> %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_ERR_NO_PROFILE_GIVEN_NAME_EXIST]);

								delete pDcCommand->m_pUser->m_LogInOut.m_pBuffer;
								pDcCommand->m_pUser->m_LogInOut.m_pBuffer = NULL;

								return;
							}

							if (pDcCommand->m_ui32CommandLen < 10)
							{
								pDcCommand->m_pUser->SendFormat("DcCommands::PreProcessData::MyPass->RegUser2", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_PASS_MUST_SPECIFIED]);

								pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_WAITING_FOR_PASS;
								return;
							}

							if (pDcCommand->m_ui32CommandLen > 73)
							{
								pDcCommand->m_pUser->SendFormat("DcCommands::PreProcessData::MyPass->RegUser2-1", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_MAX_ALWD_PASS_LEN_64_CHARS]);

								pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_WAITING_FOR_PASS;
								return;
							}

							pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

							if (RegManager::m_Ptr->AddNew(pDcCommand->m_pUser->m_sNick, pDcCommand->m_sCommand + 8, (uint16_t)iProfile) == false)
							{
								pDcCommand->m_pUser->SendFormat("DcCommands::PreProcessData::MyPass->RegUser3", true, "<%s> %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SORRY_YOU_ARE_ALREADY_REGISTERED]);
							}
							else
							{
								pDcCommand->m_pUser->SendFormat("DcCommands::PreProcessData::MyPass->RegUser4", true, "<%s> %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_THANK_YOU_FOR_PASSWORD_YOU_ARE_NOW_REGISTERED_AS],
								                                pDcCommand->m_pUser->m_LogInOut.m_pBuffer);
							}

							delete pDcCommand->m_pUser->m_LogInOut.m_pBuffer;
							pDcCommand->m_pUser->m_LogInOut.m_pBuffer = NULL;

							pDcCommand->m_pUser->m_i32Profile = iProfile;

							if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
							{
								if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::HASKEYICON) == false)
								{
									return;
								}

								pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_OPERATOR;

								// alex82 ... HideUserKey / ������ ���� �����
								if (((pDcCommand->m_pUser->m_ui32InfoBits & User::INFOBIT_HIDE_KEY) == User::INFOBIT_HIDE_KEY) == false)
								{
									Users::m_Ptr->Add2OpList(pDcCommand->m_pUser);
									GlobalDataQueue::m_Ptr->OpListStore(pDcCommand->m_pUser->m_sNick);
								}
								if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::ALLOWEDOPCHAT) == true)
								{
									if (SettingManager::m_Ptr->m_bBools[SETBOOL_REG_OP_CHAT] == true &&
									        (SettingManager::m_Ptr->m_bBools[SETBOOL_REG_BOT] == false || SettingManager::m_Ptr->m_bBotsSameNick == false))
									{
										if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_NOHELLO) == User::SUPPORTBIT_NOHELLO) == false)
										{
											pDcCommand->m_pUser->SendCharDelayed(SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_OP_CHAT_HELLO],
											                                     SettingManager::m_Ptr->m_ui16PreTextsLens[SettingManager::SETPRETXT_OP_CHAT_HELLO]);
										}

										pDcCommand->m_pUser->SendCharDelayed(SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_OP_CHAT_MYINFO], SettingManager::m_Ptr->m_ui16PreTextsLens[SettingManager::SETPRETXT_OP_CHAT_MYINFO]);
										pDcCommand->m_pUser->SendFormat("DcCommands::PreProcessData::MyPass->RegUser5", true, "$OpList %s$$|", SettingManager::m_Ptr->m_sTexts[SETTXT_OP_CHAT_NICK]);
									}
								}
							}
						}

						return;
					}
				}
				break;
			case 'G':
			{
				if (pDcCommand->m_ui32CommandLen == 13 && memcmp(pDcCommand->m_sCommand + 2, "etNickList", 10) == 0)
				{
					m_ui32StatCmdGetNickList++;
					if (GetNickList(pDcCommand) == true)
					{
						pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_GETNICKLIST;
					}
					return;
				}
				else if (memcmp(pDcCommand->m_sCommand + 2, "etINFO ", 7) == 0)
				{
					m_ui32StatCmdGetInfo++;
					GetINFO(pDcCommand);
					return;
				}
				break;
			}
			case 'T':
				if (memcmp(pDcCommand->m_sCommand + 2, "o: ", 3) == 0)
				{
					m_ui32StatCmdTo++;
					To(pDcCommand);
					return;
				}
				break;
			case 'K':
				if (*((uint32_t *)(pDcCommand->m_sCommand + 2)) == ui32ick)
				{
					m_ui32StatCmdKick++;
					Kick(pDcCommand);
					return;
				}
				break;
			case 'O':
				if (memcmp(pDcCommand->m_sCommand + 2, "pForceMove $Who:", 16) == 0)
				{
					m_ui32StatCmdOpForceMove++;
					OpForceMove(pDcCommand);
					return;
				}
				break;
			default:
				break;
			}
		}
		else if (pDcCommand->m_sCommand[0] == '<')
		{
			m_ui32StatChat++;
			if (ChatDeflood(pDcCommand) == true)
			{
				Chat(pDcCommand);
			}

			return;
		}
		break;
	}
	case User::STATE_CLOSING:
	case User::STATE_REMME:
		return;
	}

	// PPK ... fallback to full command identification and disconnect on bad state or unknown command not handled by script
	switch (pDcCommand->m_sCommand[0])
	{
	case '$':
		switch (pDcCommand->m_sCommand[1])
		{
		case 'B':
		{
			if (memcmp(pDcCommand->m_sCommand + 2, "otINFO", 6) == 0)
			{
				m_ui32StatBotINFO++;
				BotINFO(pDcCommand);
				return;
			}
			break;
		}
		case 'C':
			if (memcmp(pDcCommand->m_sCommand + 2, "onnectToMe ", 11) == 0)
			{
				m_ui32StatCmdConnectToMe++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $ConnectToMe %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			else if (memcmp(pDcCommand->m_sCommand + 2, "lose ", 5) == 0)
			{
				m_ui32StatCmdClose++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $Close %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			break;
		case 'G':
		{
			if (*((uint16_t *)(pDcCommand->m_sCommand + 2)) == *((uint16_t *)"et"))
			{
				if (memcmp(pDcCommand->m_sCommand + 4, "INFO ", 5) == 0)
				{
					m_ui32StatCmdGetInfo++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $GetINFO %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
				else if (pDcCommand->m_ui32CommandLen == 13 && *((uint64_t *)(pDcCommand->m_sCommand + 4)) == *((uint64_t *)"NickList"))
				{
					m_ui32StatCmdGetNickList++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $GetNickList %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
			}
			break;
		}
		case 'K':
			if (memcmp(pDcCommand->m_sCommand + 2, "ey ", 3) == 0)
			{
				m_ui32StatCmdKey++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $Key %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			else if (*((uint32_t *)(pDcCommand->m_sCommand + 2)) == ui32ick)
			{
				m_ui32StatCmdKick++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $Kick %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			break;
#ifdef USE_FLYLINKDC_EXT_JSON
		case 'E':
			if (memcmp(pDcCommand->m_sCommand + 2, "xtJSON ", 7) == 0)
			{
#ifdef _DBG
				int iret = sprintf(msg, "%s (%s) bad state in case $ExtJSON: %d", pUser->Nick, pUser->IP, pUser->m_iState);
				if (CheckSprintf(iret, 1024, "DcCommands::PreProcessData56") == true)
				{
					Memo(msg);
				}

#endif
				// pUser->m_ui32BoolBits |= User::BIT_PRCSD_EXT_JSON;
				m_iStatCmdExtJSON++; // ExtJSON Step 2 (After Login)
				// TODO ExtJSON ?? UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%d) in $ExtJSON %s (%s) - user closed.", (int)pUser->m_ui8State, pUser->m_sNick, pUser->m_sIP);
				// curUser->Close();
				return;
			}
			break;
#endif // USE_FLYLINKDC_EXT_JSON
		case 'M':
			if (*((uint32_t *)(pDcCommand->m_sCommand + 2)) == ui32ulti)
			{
				if (memcmp(pDcCommand->m_sCommand + 6, "ConnectToMe ", 12) == 0)
				{
					m_ui32StatCmdMultiConnectToMe++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $MultiConnectToMe %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
				else if (memcmp(pDcCommand->m_sCommand + 6, "Search ", 7) == 0)
				{
					m_ui32StatCmdMultiSearch++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $MultiSearch %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
			}
			else if (pDcCommand->m_sCommand[2] == 'y')
			{
				if (memcmp(pDcCommand->m_sCommand + 3, "INFO $ALL ", 10) == 0)
				{
					m_ui32StatCmdMyInfo++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $MyINFO %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
				else if (memcmp(pDcCommand->m_sCommand + 3, "Pass ", 5) == 0)
				{
					m_ui32StatCmdMyPass++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $MyPass %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
			}
			break;
		case 'O':
			if (memcmp(pDcCommand->m_sCommand + 2, "pForceMove $Who:", 16) == 0)
			{
				m_ui32StatCmdOpForceMove++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $OpForceMove %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			break;
		case 'R':
			if (memcmp(pDcCommand->m_sCommand + 2, "evConnectToMe ", 14) == 0)
			{
				m_ui32StatCmdRevCTM++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $RevConnectToMe %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			break;
		case 'S':
			switch (pDcCommand->m_sCommand[2])
			{
			case 'e':
			{
				if (memcmp(pDcCommand->m_sCommand + 3, "arch ", 5) == 0)
				{
					m_ui32StatCmdSearch++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $Search %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
				break;
			}
			case 'R':
				if (pDcCommand->m_sCommand[3] == ' ')
				{
					m_ui32StatCmdSR++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $SR %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
				break;
			case 'u':
			{
				if (memcmp(pDcCommand->m_sCommand + 3, "pports ", 7) == 0)
				{
					m_ui32StatCmdSupports++;

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $Supports %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

					pDcCommand->m_pUser->Close();
					return;
				}
				break;
			}
			default:
				break;
			}
			break;
		case 'T':
			if (memcmp(pDcCommand->m_sCommand + 2, "o: ", 3) == 0)
			{
				m_ui32StatCmdTo++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $To %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			break;
		case 'V':
			if (memcmp(pDcCommand->m_sCommand + 2, "alidateNick ", 12) == 0)
			{
				m_ui32StatCmdValidate++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $ValidateNick %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			else if (memcmp(pDcCommand->m_sCommand + 2, "ersion ", 7) == 0)
			{
				m_ui32StatCmdVersion++;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in $Version %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

				pDcCommand->m_pUser->Close();
				return;
			}
			break;
		default:
			break;
		}
		break;
	case '<':
	{
		m_ui32StatChat++;

		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad state (%hhu) in Chat %s (%s) - user closed.", pDcCommand->m_pUser->m_ui8State, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}
	default:
		break;
	}


	Unknown(pDcCommand);
}
//---------------------------------------------------------------------------

// $BotINFO pinger identification|
void DcCommands::BotINFO(DcCommand * pDcCommand)
{
	if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == false || ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HAVE_BOTINFO) == User::BIT_HAVE_BOTINFO) == true)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Not pinger $BotINFO or $BotINFO flood from %s (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (pDcCommand->m_ui32CommandLen < 9)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $BotINFO (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_HAVE_BOTINFO;

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::BOTINFO_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pDcCommand->m_pUser->SendFormat("DcCommands::BotINFO", true, "$HubINFO %s$%s:%hu$%s.px.$%hd$%" PRIu64 "$%hd$%hd$PtokaX$%s|", SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_NAME], SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS], SettingManager::m_Ptr->m_ui16PortNumbers[0],
	                                SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_DESCRIPTION] == NULL ? "" : SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_DESCRIPTION], SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_USERS], SettingManager::m_Ptr->m_ui64MinShare, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_SLOTS_LIMIT],
	                                SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_HUBS_LIMIT], SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_OWNER_EMAIL] == NULL ? "" : SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_OWNER_EMAIL]);

	if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HAVE_GETNICKLIST) == User::BIT_HAVE_GETNICKLIST) == true)
	{
		pDcCommand->m_pUser->Close();
	}
}
//---------------------------------------------------------------------------

// $ConnectToMe <nickname> <ownip>:<ownlistenport>
// $MultiConnectToMe <nick> <ownip:port> <hub[:port]>
void DcCommands::ConnectToMe(DcCommand * pDcCommand, const bool bMulti)
{
	if ((bMulti == false && pDcCommand->m_ui32CommandLen < 23) || (bMulti == true && pDcCommand->m_ui32CommandLen < 28))
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $%sConnectToMe (%s) from %s (%s) - user closed.", bMulti == false ? "" : "Multi", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	// PPK ... check flood ...
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODCTM) == false)
	{
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CTM_ACTION] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_CTM, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CTM_ACTION],
			                         pDcCommand->m_pUser->m_ui16CTMs, pDcCommand->m_pUser->m_ui64CTMsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CTM_MESSAGES],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CTM_TIME]) == true)
			{
				return;
			}
		}

		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CTM_ACTION2] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_CTM, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CTM_ACTION2],
			                         pDcCommand->m_pUser->m_ui16CTMs2, pDcCommand->m_pUser->m_ui64CTMsTick2, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CTM_MESSAGES2],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CTM_TIME2]) == true)
			{
				return;
			}
		}
	}

	if (pDcCommand->m_ui32CommandLen > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_CTM_LEN])
	{
		pDcCommand->m_pUser->SendFormat("DcCommands::ConnectToMe", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_CTM_TOO_LONG]);

		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Long $ConnectToMe from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	// PPK ... $CTM means user is active ?!? Probably yes, let set it active and use on another places ;)
	if (pDcCommand->m_pUser->m_sTag == NULL)
	{
		pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_IPV4_ACTIVE;
	}

	// full data only and allow blocking
	if (ScriptManager::m_Ptr->Arrival(pDcCommand, (uint8_t)(bMulti == false ? ScriptManager::CONNECTTOME_ARRIVAL : ScriptManager::MULTICONNECTTOME_ARRIVAL)) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	char * pSpace = strchr(pDcCommand->m_sCommand + (bMulti == false ? 13 : 18), ' ');
	if (pSpace == NULL)
	{
		return;
	}

	pSpace[0] = '\0';

	User * pOtherUser = HashManager::m_Ptr->FindUser(pDcCommand->m_sCommand + (bMulti == false ? 13 : 18), pSpace - (pDcCommand->m_sCommand + (bMulti == false ? 13 : 18)));
	// PPK ... no connection to yourself !!!
	if (pOtherUser == NULL || pOtherUser == pDcCommand->m_pUser || pOtherUser->m_ui8State != User::STATE_ADDED)
	{
		return;
	}

	pSpace[0] = ' ';

	// IP check
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOIPCHECK) == false)
	{
		// At end of sData is | and we need to remove it.
		pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0';

		// Now between pSpace+1 and end of string is something that should be IP:Port .. let's check that and start with length.
		uint32_t ui32IpPortLen = (uint32_t)((pDcCommand->m_ui32CommandLen - 1) - ((pSpace + 1) - pDcCommand->m_sCommand));

		// Check minimal (shortest ip:port can be [::1]:1) and maximal (longest ip:port can be [1234:1234:1234:1234:1234:1234:1234:1234]:12345S) length.
		if (ui32IpPortLen < 7 || ui32IpPortLen > 48)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::ConnectToMe bad IP:Port len", true, "<%s> %s '%s'!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_CLIENT_SEND_INCORRECT_IPPORT_IN_COMMAND], pSpace + 1);

			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad IP:Port length in %sCTM from %s (%s). (%s)", bMulti == false ? "" : "M", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);
			pDcCommand->m_pUser->m_is_bad_len_port = true; // FlylinkDC++
			//pDcCommand->m_pUser->Close(); // FlylinkDC++
			return;
		}

		// Check if Port is valid. Here can be S (as secure [what a joke lol]) to indicate TLS connection request after port ...
		uint32_t ui32PortLen = 0;
		uint16_t ui16Port = 0; // Zero == invalid port ...
		bool bSecure = false; // To restore secure status after checks

		if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_TLS2) == User::SUPPORTBIT_TLS2) == true && pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 2] == 'S')
		{
			// Remove S character and set secure to true
			pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 2] = '\0';
			bSecure = true;

			// Check for port validity and get Port when valid
			ui16Port = CheckAndGetPort(pSpace + 1 + (ui32IpPortLen - 7), (uint8_t)(ui32IpPortLen - ((pSpace + (ui32IpPortLen - 6)) - pSpace)), ui32PortLen);
		}
		else
		{
			// Check for port validity and get Port when valid
			ui16Port = CheckAndGetPort(pSpace + 1 + (ui32IpPortLen - 6), (uint8_t)(ui32IpPortLen - ((pSpace + (ui32IpPortLen - 6)) - pSpace)), ui32PortLen);
		}

		// Check if we get valid port number
		if (ui16Port == 0)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::ConnectToMe invalid Port", true, "<%s> %s '%s'!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_CLIENT_SEND_INCORRECT_PORT_IN_CTM], pSpace + 1);

			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad Port in %sCTM from %s (%s). (%s)", bMulti == false ? "" : "M", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

			pDcCommand->m_pUser->Close();
			return;
		}

		uint32_t ui32IpLen = (ui32IpPortLen - ui32PortLen) - 1;
		if (bSecure == true)
		{
			ui32IpLen--;
		}

		bool bInvalidIP = true;
		char * pIP = pSpace + 1;

		// Check if we get valid IP address
		if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6)
		{
			if ((pDcCommand->m_pUser->m_ui8IpLen + 2U) == ui32IpLen && pIP[0] == '[' && pIP[1 + pDcCommand->m_pUser->m_ui8IpLen] == ']' && strncmp(pIP + 1, pDcCommand->m_pUser->m_sIP, pDcCommand->m_pUser->m_ui8IpLen) == 0)
			{
				bInvalidIP = false;
			}
			else if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4) && pDcCommand->m_pUser->m_ui8IPv4Len == ui32IpLen &&  strncmp(pIP, pDcCommand->m_pUser->m_sIPv4, pDcCommand->m_pUser->m_ui8IPv4Len) == 0)
			{
				bInvalidIP = false;
			}
		}
		else if (pDcCommand->m_pUser->m_ui8IpLen == ui32IpLen && strncmp(pIP, pDcCommand->m_pUser->m_sIP, pDcCommand->m_pUser->m_ui8IpLen) == 0)
		{
			bInvalidIP = false;
		}

		if (bInvalidIP == true)
		{
			if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_WARNED_WRONG_IP) == User::BIT_WARNED_WRONG_IP) == false)
			{
				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad Ip in %sCTM from %s (%s/%s). (%s)", bMulti == false ? "" : "M", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_pUser->m_sIPv4, pDcCommand->m_sCommand);
			}

			if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6 && (pOtherUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6)
			{
				int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$ConnectToMe %s [%s]:%hu%s|", pOtherUser->m_sNick, pDcCommand->m_pUser->m_sIP, ui16Port, bSecure == true ? "S" : "");
				if (iMsgLen > 0)
				{
					pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::CTM_MCTM_RCTM_SR_TO, ServerManager::m_pGlobalBuffer, iMsgLen, pOtherUser);
				}
			}
			else if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4 && (pOtherUser->m_ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4)
			{
				char * sIP = pDcCommand->m_pUser->m_ui8IPv4Len == 0 ? pDcCommand->m_pUser->m_sIP : pDcCommand->m_pUser->m_sIPv4;

				int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$ConnectToMe %s %s:%hu%s|", pOtherUser->m_sNick, sIP, ui16Port, bSecure == true ? "S" : "");
				if (iMsgLen > 0)
				{
					pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::CTM_MCTM_RCTM_SR_TO, ServerManager::m_pGlobalBuffer, iMsgLen, pOtherUser);
				}
			}

			if (ui32IpLen != 0 && pIP[ui32IpLen - 1] == ']')
			{
				pIP[ui32IpLen - 1] = '\0';
			}
			else
			{
				pIP[ui32IpLen] = '\0';
			}

			if (pIP[0] == '[')
			{
				pIP++;
			}

			SendIPFixedMsg(pDcCommand->m_pUser, pIP, pDcCommand->m_pUser->m_sIP);
			return;
		}
		else
		{
			if (bSecure == true)
			{
				pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 2] = 'S';
			}
			pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '|';
		}
	}

	if (bMulti == true)
	{
		pDcCommand->m_sCommand[5] = '$';
	}

	pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::CTM_MCTM_RCTM_SR_TO, bMulti == false ? pDcCommand->m_sCommand : pDcCommand->m_sCommand + 5, bMulti == false ? pDcCommand->m_ui32CommandLen : pDcCommand->m_ui32CommandLen - 5, pOtherUser);
}
//---------------------------------------------------------------------------

// $GetINFO <nickname> <ownnickname>
void DcCommands::GetINFO(DcCommand * pDcCommand)
{
	if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_NOGETINFO) == User::SUPPORTBIT_NOGETINFO) == true || ((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_NOHELLO) == User::SUPPORTBIT_NOHELLO) == true || ((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == true)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Not allowed user %s (%s) send $GetINFO - user closed.", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	// PPK ... code change, added own nick and space on right place check
	if (pDcCommand->m_ui32CommandLen < (12u + pDcCommand->m_pUser->m_ui8NickLen) || pDcCommand->m_ui32CommandLen > (75u + pDcCommand->m_pUser->m_ui8NickLen) || pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - pDcCommand->m_pUser->m_ui8NickLen - 2] != ' ' ||
	        memcmp(pDcCommand->m_sCommand + (pDcCommand->m_ui32CommandLen - pDcCommand->m_pUser->m_ui8NickLen - 1), pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_ui8NickLen) != 0)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $GetINFO from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::GETINFO_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}
}
//---------------------------------------------------------------------------

// $GetNickList
bool DcCommands::GetNickList(DcCommand * pDcCommand)
{
	if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == true &&
	        ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HAVE_GETNICKLIST) == User::BIT_HAVE_GETNICKLIST) == true)
	{
		// PPK ... refresh not allowed !
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $GetNickList request %s (%s) - user closed.", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return false;
	}
	else if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == true)
	{
		if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HAVE_GETNICKLIST) == User::BIT_HAVE_GETNICKLIST) == false)
		{
			pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_BIG_SEND_BUFFER;
			if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_NOHELLO) == User::SUPPORTBIT_NOHELLO) == false && Users::m_Ptr->m_ui32NickListLen > 11)
			{
				if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_ZPIPE) == User::SUPPORTBIT_ZPIPE) == false)
				{
					pDcCommand->m_pUser->SendCharDelayed(Users::m_Ptr->m_pNickList, Users::m_Ptr->m_ui32NickListLen);
				}
				else
				{
					if (Users::m_Ptr->m_ui32ZNickListLen == 0)
					{
						Users::m_Ptr->m_pZNickList = ZlibUtility::m_Ptr->CreateZPipe(Users::m_Ptr->m_pNickList, Users::m_Ptr->m_ui32NickListLen, Users::m_Ptr->m_pZNickList,
						                             Users::m_Ptr->m_ui32ZNickListLen, Users::m_Ptr->m_ui32ZNickListSize);
						if (Users::m_Ptr->m_ui32ZNickListLen == 0)
						{
							pDcCommand->m_pUser->SendCharDelayed(Users::m_Ptr->m_pNickList, Users::m_Ptr->m_ui32NickListLen);
						}
						else
						{
							pDcCommand->m_pUser->PutInSendBuf(Users::m_Ptr->m_pZNickList, Users::m_Ptr->m_ui32ZNickListLen);
							ServerManager::m_ui64BytesSentSaved += Users::m_Ptr->m_ui32NickListLen - Users::m_Ptr->m_ui32ZNickListLen;
						}
					}
					else
					{
						pDcCommand->m_pUser->PutInSendBuf(Users::m_Ptr->m_pZNickList, Users::m_Ptr->m_ui32ZNickListLen);
						ServerManager::m_ui64BytesSentSaved += Users::m_Ptr->m_ui32NickListLen - Users::m_Ptr->m_ui32ZNickListLen;
					}
				}
			}

			if (SettingManager::m_Ptr->m_ui8FullMyINFOOption == 2)
			{
				if (Users::m_Ptr->m_ui32MyInfosLen != 0)
				{
					if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_ZPIPE) == User::SUPPORTBIT_ZPIPE) == false)
					{
						pDcCommand->m_pUser->SendCharDelayed(Users::m_Ptr->m_pMyInfos, Users::m_Ptr->m_ui32MyInfosLen);
					}
					else
					{
						if (Users::m_Ptr->m_ui32ZMyInfosLen == 0)
						{
							Users::m_Ptr->m_pZMyInfos = ZlibUtility::m_Ptr->CreateZPipe(Users::m_Ptr->m_pMyInfos, Users::m_Ptr->m_ui32MyInfosLen, Users::m_Ptr->m_pZMyInfos,
							                            Users::m_Ptr->m_ui32ZMyInfosLen, Users::m_Ptr->m_ui32ZMyInfosSize);
							if (Users::m_Ptr->m_ui32ZMyInfosLen == 0)
							{
								pDcCommand->m_pUser->SendCharDelayed(Users::m_Ptr->m_pMyInfos, Users::m_Ptr->m_ui32MyInfosLen);
							}
							else
							{
								pDcCommand->m_pUser->PutInSendBuf(Users::m_Ptr->m_pZMyInfos, Users::m_Ptr->m_ui32ZMyInfosLen);
								ServerManager::m_ui64BytesSentSaved += Users::m_Ptr->m_ui32MyInfosLen - Users::m_Ptr->m_ui32ZMyInfosLen;
							}
						}
						else
						{
							pDcCommand->m_pUser->PutInSendBuf(Users::m_Ptr->m_pZMyInfos, Users::m_Ptr->m_ui32ZMyInfosLen);
							ServerManager::m_ui64BytesSentSaved += Users::m_Ptr->m_ui32MyInfosLen - Users::m_Ptr->m_ui32ZMyInfosLen;
						}
					}
				}
			}
			else if (Users::m_Ptr->m_ui32MyInfosTagLen != 0)
			{
				if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_ZPIPE) == User::SUPPORTBIT_ZPIPE) == false)
				{
					pDcCommand->m_pUser->SendCharDelayed(Users::m_Ptr->m_pMyInfosTag, Users::m_Ptr->m_ui32MyInfosTagLen);
				}
				else
				{
					if (Users::m_Ptr->m_ui32ZMyInfosTagLen == 0)
					{
						Users::m_Ptr->m_pZMyInfosTag = ZlibUtility::m_Ptr->CreateZPipe(Users::m_Ptr->m_pMyInfosTag, Users::m_Ptr->m_ui32MyInfosTagLen, Users::m_Ptr->m_pZMyInfosTag,
						                               Users::m_Ptr->m_ui32ZMyInfosTagLen, Users::m_Ptr->m_ui32ZMyInfosTagSize);
						if (Users::m_Ptr->m_ui32ZMyInfosTagLen == 0)
						{
							pDcCommand->m_pUser->SendCharDelayed(Users::m_Ptr->m_pMyInfosTag, Users::m_Ptr->m_ui32MyInfosTagLen);
						}
						else
						{
							pDcCommand->m_pUser->PutInSendBuf(Users::m_Ptr->m_pZMyInfosTag, Users::m_Ptr->m_ui32ZMyInfosTagLen);
							ServerManager::m_ui64BytesSentSaved += Users::m_Ptr->m_ui32MyInfosTagLen - Users::m_Ptr->m_ui32ZMyInfosTagLen;
						}
					}
					else
					{
						pDcCommand->m_pUser->PutInSendBuf(Users::m_Ptr->m_pZMyInfosTag, Users::m_Ptr->m_ui32ZMyInfosTagLen);
						ServerManager::m_ui64BytesSentSaved += Users::m_Ptr->m_ui32MyInfosTagLen - Users::m_Ptr->m_ui32ZMyInfosTagLen;
					}
				}
			}

			if (Users::m_Ptr->m_ui32OpListLen > 9)
			{
				if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_ZPIPE) == User::SUPPORTBIT_ZPIPE) == false)
				{
					pDcCommand->m_pUser->SendCharDelayed(Users::m_Ptr->m_pOpList, Users::m_Ptr->m_ui32OpListLen);
				}
				else
				{
					if (Users::m_Ptr->m_ui32ZOpListLen == 0)
					{
						Users::m_Ptr->m_pZOpList = ZlibUtility::m_Ptr->CreateZPipe(Users::m_Ptr->m_pOpList, Users::m_Ptr->m_ui32OpListLen, Users::m_Ptr->m_pZOpList,
						                           Users::m_Ptr->m_ui32ZOpListLen, Users::m_Ptr->m_ui32ZOpListSize);
						if (Users::m_Ptr->m_ui32ZOpListLen == 0)
						{
							pDcCommand->m_pUser->SendCharDelayed(Users::m_Ptr->m_pOpList, Users::m_Ptr->m_ui32OpListLen);
						}
						else
						{
							pDcCommand->m_pUser->PutInSendBuf(Users::m_Ptr->m_pZOpList, Users::m_Ptr->m_ui32ZOpListLen);
							ServerManager::m_ui64BytesSentSaved += Users::m_Ptr->m_ui32OpListLen - Users::m_Ptr->m_ui32ZOpListLen;
						}
					}
					else
					{
						pDcCommand->m_pUser->PutInSendBuf(Users::m_Ptr->m_pZOpList, Users::m_Ptr->m_ui32ZOpListLen);
						ServerManager::m_ui64BytesSentSaved += Users::m_Ptr->m_ui32OpListLen - Users::m_Ptr->m_ui32ZOpListLen;
					}
				}
			}

			if (pDcCommand->m_pUser->m_ui32SendBufDataLen != 0)
			{
				pDcCommand->m_pUser->Try2Send();
			}

			pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_HAVE_GETNICKLIST;

			if (SettingManager::m_Ptr->m_bBools[SETBOOL_REPORT_PINGERS] == true)
			{
				GlobalDataQueue::m_Ptr->StatusMessageFormat("DcCommands::GetNickList", "<%s> *** %s: %s %s: %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_PINGER_FROM_IP], pDcCommand->m_pUser->m_sIP,
				        LanguageManager::m_Ptr->m_sTexts[LAN_WITH_NICK], pDcCommand->m_pUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_DETECTED_LWR]);
			}

			if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HAVE_BOTINFO) == User::BIT_HAVE_BOTINFO) == true)
			{
				pDcCommand->m_pUser->Close();
			}
			return false;
		}
		else
		{
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] $GetNickList flood from pinger %s (%s) - user closed.", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

			pDcCommand->m_pUser->Close();
			return false;
		}
	}

	pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_HAVE_GETNICKLIST;

	// PPK ... check flood...
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODGETNICKLIST) == false &&
	        SettingManager::m_Ptr->m_i16Shorts[SETSHORT_GETNICKLIST_ACTION] != 0)
	{
		if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_GETNICKLIST, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_GETNICKLIST_ACTION],
		                         pDcCommand->m_pUser->m_ui16GetNickLists, pDcCommand->m_pUser->m_ui64GetNickListsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_GETNICKLIST_MESSAGES],
		                         ((uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_GETNICKLIST_TIME]) * 60) == true)
		{
			return false;
		}
	}

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::GETNICKLIST_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING ||
	        ((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == true)
	{
		return false;
	}

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

// $Key
void DcCommands::Key(DcCommand * pDcCommand)
{
	if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HAVE_KEY) == User::BIT_HAVE_KEY) == true)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] $Key flood from %s (%s) - user closed.", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_HAVE_KEY;

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

	if (pDcCommand->m_ui32CommandLen < 6 || strcmp(Lock2Key(pDcCommand->m_pUser->m_LogInOut.m_pBuffer), pDcCommand->m_sCommand + 5) != 0)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $Key from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	pDcCommand->m_pUser->FreeBuffer();

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '|'; // add back pipe

	ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::KEY_ARRIVAL);

	if (pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pDcCommand->m_pUser->m_ui8State = User::STATE_VALIDATE;
}
//---------------------------------------------------------------------------

// $Kick <name>
void DcCommands::Kick(DcCommand * pDcCommand)
{
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::KICK) == false)
	{
		pDcCommand->m_pUser->SendFormat("DcCommands::Kick1", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_NOT_ALWD_TO_USE_THIS_CMD]);
		return;
	}

	if (pDcCommand->m_ui32CommandLen < 8)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $Kick (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::KICK_ARRIVAL) == true || pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

	User *OtherUser = HashManager::m_Ptr->FindUser(pDcCommand->m_sCommand + 6, pDcCommand->m_ui32CommandLen - 7);
	if (OtherUser != NULL)
	{
		// Self-kick
		if (OtherUser == pDcCommand->m_pUser)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Kick2", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_CANT_KICK_YOURSELF]);
			return;
		}

		if (OtherUser->m_i32Profile != -1 && pDcCommand->m_pUser->m_i32Profile > OtherUser->m_i32Profile)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Kick3", true, "<%s> %s %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_NOT_ALLOWED_TO_KICK], OtherUser->m_sNick);
			return;
		}

		if (pDcCommand->m_pUser->m_pCmdToUserStrt != NULL)
		{
			PrcsdToUsrCmd * cur = NULL, * prev = NULL,
			                * next = pDcCommand->m_pUser->m_pCmdToUserStrt;

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

				if (OtherUser == cur->m_pToUser)
				{
					cur->m_pToUser->SendChar(cur->m_sCommand, cur->m_ui32Len);

					if (prev == NULL)
					{
						if (cur->m_pNext == NULL)
						{
							pDcCommand->m_pUser->m_pCmdToUserStrt = NULL;
							pDcCommand->m_pUser->m_pCmdToUserEnd = NULL;
						}
						else
						{
							pDcCommand->m_pUser->m_pCmdToUserStrt = cur->m_pNext;
						}
					}
					else if (cur->m_pNext == NULL)
					{
						prev->m_pNext = NULL;
						pDcCommand->m_pUser->m_pCmdToUserEnd = prev;
					}
					else
					{
						prev->m_pNext = cur->m_pNext;
					}

					safe_free(cur->m_sCommand);

					delete cur;
					break;
				}
				prev = cur;
			}
		}

		char * sBanTime;
		if (OtherUser->m_LogInOut.m_pBuffer != NULL &&
		        (sBanTime = stristr(OtherUser->m_LogInOut.m_pBuffer, "_BAN_")) != NULL)
		{
			sBanTime[0] = '\0';

			if (sBanTime[5] == '\0' || sBanTime[5] == ' ')  // permban
			{
				if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::BAN) == false)
				{
					pDcCommand->m_pUser->SendFormat("DcCommands::Kick4", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_NOT_ALWD_TO_USE_THIS_CMD]);
					return;
				}

				BanManager::m_Ptr->Ban(OtherUser, OtherUser->m_LogInOut.m_pBuffer, pDcCommand->m_pUser->m_sNick, false);

				GlobalDataQueue::m_Ptr->StatusMessageFormat("DcCommands::Kick1", "<%s> *** %s %s %s %s %s %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], OtherUser->m_sIP, LanguageManager::m_Ptr->m_sTexts[LAN_HAS_BEEN],
				        LanguageManager::m_Ptr->m_sTexts[LAN_BANNED_LWR], LanguageManager::m_Ptr->m_sTexts[LAN_BY_LWR], pDcCommand->m_pUser->m_sNick);

				if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_STATUS_MESSAGES] == false || ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
				{
					pDcCommand->m_pUser->SendFormat("DcCommands::Kick5", true, "<%s> *** %s %s %s %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], OtherUser->m_sIP, LanguageManager::m_Ptr->m_sTexts[LAN_HAS_BEEN],
					                                LanguageManager::m_Ptr->m_sTexts[LAN_BANNED_LWR]);
				}

				// disconnect the user
				UdpDebug::m_Ptr->BroadcastFormat("[SYS] User %s (%s) kicked by %s", OtherUser->m_sNick, OtherUser->m_sIP, pDcCommand->m_pUser->m_sNick);

				OtherUser->Close();

				return;
			}
			else if (isdigit(sBanTime[5]) != 0)    // tempban
			{
				if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::TEMP_BAN) == false)
				{
					pDcCommand->m_pUser->SendFormat("DcCommands::Kick6", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_NOT_ALWD_TO_USE_THIS_CMD]);
					return;
				}

				uint32_t i = 6;
				while (sBanTime[i] != '\0' && isdigit(sBanTime[i]) != 0)
				{
					i++;
				}

				char cTime = sBanTime[i];
				sBanTime[i] = '\0';
				int iTime = atoi(sBanTime + 5);
				time_t acc_time, ban_time;

				if (cTime != '\0' && iTime > 0 && GenerateTempBanTime(cTime, iTime, acc_time, ban_time) == true)
				{
					BanManager::m_Ptr->TempBan(OtherUser, OtherUser->m_LogInOut.m_pBuffer, pDcCommand->m_pUser->m_sNick, 0, ban_time, false);

					static char sTime[256];
					strcpy(sTime, formatTime((ban_time - acc_time) / 60));

					GlobalDataQueue::m_Ptr->StatusMessageFormat("DcCommands::Kick2", "<%s> *** %s %s %s %s %s %s %s %s: %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], OtherUser->m_sIP, LanguageManager::m_Ptr->m_sTexts[LAN_HAS_BEEN],
					        LanguageManager::m_Ptr->m_sTexts[LAN_TEMP_BANNED], LanguageManager::m_Ptr->m_sTexts[LAN_BY_LWR], pDcCommand->m_pUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_TO_LWR], sTime);

					if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_STATUS_MESSAGES] == false || ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
					{
						pDcCommand->m_pUser->SendFormat("DcCommands::Kick7", true, "<%s> *** %s %s %s %s %s %s: %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], OtherUser->m_sIP, LanguageManager::m_Ptr->m_sTexts[LAN_HAS_BEEN],
						                                LanguageManager::m_Ptr->m_sTexts[LAN_TEMP_BANNED], LanguageManager::m_Ptr->m_sTexts[LAN_TO_LWR], sTime);
					}

					// disconnect the user
					UdpDebug::m_Ptr->BroadcastFormat("[SYS] User %s (%s) kicked by %s", OtherUser->m_sNick, OtherUser->m_sIP, pDcCommand->m_pUser->m_sNick);

					OtherUser->Close();

					return;
				}
			}
		}

		BanManager::m_Ptr->TempBan(OtherUser, OtherUser->m_LogInOut.m_pBuffer != NULL ? OtherUser->m_LogInOut.m_pBuffer : NULL, pDcCommand->m_pUser->m_sNick, 0, 0, false);

		GlobalDataQueue::m_Ptr->StatusMessageFormat("DcCommands::Kick3", "<%s> *** %s %s %s %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], OtherUser->m_sIP,
		        LanguageManager::m_Ptr->m_sTexts[LAN_WAS_KICKED_BY], pDcCommand->m_pUser->m_sNick);

		if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_STATUS_MESSAGES] == false || ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Kick8", true, "<%s> *** %s %s %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], OtherUser->m_sIP, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_KICKED]);
		}

		// disconnect the user
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] User %s (%s) kicked by %s", OtherUser->m_sNick, OtherUser->m_sIP, pDcCommand->m_pUser->m_sNick);

		OtherUser->Close();
	}
}
//---------------------------------------------------------------------------

// $Search $MultiSearch
bool DcCommands::SearchDeflood(DcCommand * pDcCommand, const bool bMulti)
{
	// search flood protection ... modified by PPK ;-)
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODSEARCH) == false)
	{
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_ACTION] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_SEARCH, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_ACTION],
			                         pDcCommand->m_pUser->m_ui16Searchs, pDcCommand->m_pUser->m_ui64SearchsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_MESSAGES],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_TIME]) == true)
			{
				return false;
			}
		}

		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_ACTION2] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_SEARCH, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_ACTION2],
			                         pDcCommand->m_pUser->m_ui16Searchs2, pDcCommand->m_pUser->m_ui64SearchsTick2, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_MESSAGES2],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_TIME2]) == true)
			{
				return false;
			}
		}

		// 2nd check for same search flood
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_SEARCH_ACTION] != 0)
		{
			bool bNewData = false;
			if (DeFloodCheckForSameFlood(pDcCommand->m_pUser, DEFLOOD_SAME_SEARCH, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_SEARCH_ACTION],
			                             pDcCommand->m_pUser->m_ui16SameSearchs, pDcCommand->m_pUser->m_ui64SameSearchsTick,
			                             SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_SEARCH_MESSAGES], SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_SEARCH_TIME],
			                             pDcCommand->m_sCommand + (bMulti == true ? 13 : 8), pDcCommand->m_ui32CommandLen - (bMulti == true ? 13 : 8),
			                             pDcCommand->m_pUser->m_sLastSearch, pDcCommand->m_pUser->m_ui16LastSearchLen, bNewData) == true)
			{
				return false;
			}

			if (bNewData == true)
			{
				pDcCommand->m_pUser->SetLastSearch(pDcCommand->m_sCommand + (bMulti == true ? 13 : 8), pDcCommand->m_ui32CommandLen - (bMulti == true ? 13 : 8));
			}
		}
	}

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

// $Search $MultiSearch
void DcCommands::Search(DcCommand * pDcCommand, const bool bMulti)
{
#ifdef _WIN32
#ifdef _PtokaX_TESTING_
	//  std::string l_ddos = "$Search :000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ????MNBFJPTUDG|";
	//    std::string l_ddos = "$Search 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064185F?F?0?1?0431765961|";
	//std::string l_ddos = "$Search 127.0.0.1:\\://185.61.138.193:411 F?F?0?1?M|";
	//sData = (char *) l_ddos.data();
	//ui32Len = strlen(sData);
#endif
#endif

	uint32_t iAfterCmd;
	if (bMulti == false)
	{
		if (pDcCommand->m_ui32CommandLen < 10
		        || pDcCommand->m_ui32CommandLen > 512) // FlylinkDC++
		{
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $Search (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

			pDcCommand->m_pUser->Close();
			return;
		}
		iAfterCmd = 8;
	}
	else
	{
		if (pDcCommand->m_ui32CommandLen < 15
		        || pDcCommand->m_ui32CommandLen > 512) // FlylinkDC++
		{
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $MultiSearch (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

			pDcCommand->m_pUser->Close();
			return;
		}
		iAfterCmd = 13;
	}

	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOSEARCHINTERVAL) == false)
	{
		if (DeFloodCheckInterval(pDcCommand->m_pUser, INTERVAL_SEARCH, pDcCommand->m_pUser->m_ui16SearchsInt,
		                         pDcCommand->m_pUser->m_ui64SearchsIntTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_INTERVAL_MESSAGES],
		                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SEARCH_INTERVAL_TIME]) == true)
		{
			return;
		}
	}

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::SEARCH_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	// send search from actives to all, from passives to actives only
	// PPK ... optimization ;o)
	if (bMulti == false && *((uint32_t *)(pDcCommand->m_sCommand + iAfterCmd)) == *((uint32_t *)"Hub:"))
	{
		if (pDcCommand->m_pUser->m_sTag == NULL)
		{
			pDcCommand->m_pUser->m_ui32BoolBits &= ~User::BIT_IPV4_ACTIVE;
		}

		// PPK ... check nick !!!
		if ((pDcCommand->m_sCommand[iAfterCmd + 4 + pDcCommand->m_pUser->m_ui8NickLen] != ' ') || (memcmp(pDcCommand->m_sCommand + iAfterCmd + 4, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_ui8NickLen) != 0))
		{
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in search from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

			pDcCommand->m_pUser->Close();
			return;
		}

		if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOSEARCHLIMITS) == false &&
		        (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_SEARCH_LEN] != 0 || SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SEARCH_LEN] != 0))
		{
			// PPK ... search string len check
			// $Search Hub:PPK F?T?0?2?test|
			uint32_t iChar = iAfterCmd + 8 + pDcCommand->m_pUser->m_ui8NickLen + 1;
			uint32_t iCount = 0;
			for (; iChar < pDcCommand->m_ui32CommandLen; iChar++)
			{
				if (pDcCommand->m_sCommand[iChar] == '?')
				{
					iCount++;
					if (iCount == 2)
						break;
				}
			}

			iCount = pDcCommand->m_ui32CommandLen - 2 - iChar;

			if (iCount < (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_SEARCH_LEN])
			{
				pDcCommand->m_pUser->SendFormat("DcCommands::Search1", true, "<%s> %s %hd.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SORRY_MIN_SEARCH_LEN_IS], SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_SEARCH_LEN]);
				return;
			}
			if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SEARCH_LEN] != 0 && iCount > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SEARCH_LEN])
			{
				pDcCommand->m_pUser->SendFormat("DcCommands::Search2", true, "<%s> %s %hd.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SORRY_MAX_SEARCH_LEN_IS], SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SEARCH_LEN]);
				return;
			}
		}

		pDcCommand->m_pUser->m_ui32SR = 0;

		pDcCommand->m_pUser->m_pCmdPassiveSearch = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdPassiveSearch, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, false);
	}
	else
	{
		if (pDcCommand->m_pUser->m_sTag == NULL)
		{
			pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_IPV4_ACTIVE;
		}

		if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOSEARCHLIMITS) == false && (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_SEARCH_LEN] != 0 || SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SEARCH_LEN] != 0))
		{
			// PPK ... search string len check
			// $Search 1.2.3.4:1 F?F?0?2?test| / $Search [::1]:1 F?F?0?2?test|
			uint32_t ui32Char = iAfterCmd + 9;
			uint32_t ui32QCount = 0;

			for (; ui32Char < pDcCommand->m_ui32CommandLen; ui32Char++)
			{
				if (pDcCommand->m_sCommand[ui32Char] == '?')
				{
					ui32QCount++;
					if (ui32QCount == 4)
						break;
				}
			}

			uint32_t ui32Count = pDcCommand->m_ui32CommandLen - 2 - ui32Char;

			if (ui32QCount != 4 || ui32Count < (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_SEARCH_LEN])
			{
				pDcCommand->m_pUser->SendFormat("DcCommands::Search3", true, "<%s> %s %hd.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SORRY_MIN_SEARCH_LEN_IS], SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_SEARCH_LEN]);
				return;
			}
			if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SEARCH_LEN] != 0 && ui32Count > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SEARCH_LEN])
			{
				pDcCommand->m_pUser->SendFormat("DcCommands::Search4", true, "<%s> %s %hd.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SORRY_MAX_SEARCH_LEN_IS], SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SEARCH_LEN]);
				return;
			}
		}

		// Get space after IP:Port
		char * pSpace = strchr(pDcCommand->m_sCommand + iAfterCmd, ' ');
		if (pSpace == NULL)
		{
			return;
		}

		pSpace[0] = '\0';

		// Now we have between sData+iAfterCmd and pSpace IP:Port ... or we should have. Let's check that and start with length.
		uint32_t ui32IpPortLen = (uint32_t)(pSpace - (pDcCommand->m_sCommand + iAfterCmd));

		// Check minimal (shortest ip:port can be [::1]:1) and maximal (longest ip:port can be [1234:1234:1234:1234:1234:1234:1234:1234]:12345S) length.
		if (ui32IpPortLen < 7 || ui32IpPortLen > 48)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Search bad IP:Port len", true, "<%s> %s '%s'!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_CLIENT_SEND_INCORRECT_IPPORT_IN_COMMAND], pDcCommand->m_sCommand + iAfterCmd);

			pSpace[0] = ' ';
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad IP:Port length in %sSearch from %s (%s). (%s)", bMulti == false ? "" : "M", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);
			pDcCommand->m_pUser->m_is_bad_port = true; // FlylinkDC++
			//pDcCommand->m_pUser->Close();

			return;
		}

		// Check if Port is valid.
		uint32_t ui32PortLen = 0;
		uint16_t ui16Port = 0; // Zero == invalid port ...

		// Check for port validity and get Port when valid
		ui16Port = CheckAndGetPort(pDcCommand->m_sCommand + iAfterCmd + (ui32IpPortLen - 6), (uint8_t)(ui32IpPortLen - (((pDcCommand->m_sCommand + iAfterCmd) + (ui32IpPortLen - 6)) - (pDcCommand->m_sCommand + iAfterCmd))), ui32PortLen);

		// Check if we get valid port number
		if (ui16Port == 0)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Search invalid Port", true, "<%s> %s '%s'!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_CLIENT_SEND_INCORRECT_PORT_IN_SEARCH], pDcCommand->m_sCommand + iAfterCmd);

			pSpace[0] = ' ';
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad Port in %sSearch from %s (%s). (%s)", bMulti == false ? "" : "M", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

			pDcCommand->m_pUser->Close();
			return;
		}

		uint32_t ui32IpLen = (ui32IpPortLen - ui32PortLen) - 1;
		bool bInvalidIP = true;
		char * pIP = pDcCommand->m_sCommand + iAfterCmd;

		// Check if we get valid IP address
		if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6)
		{
			if ((pDcCommand->m_pUser->m_ui8IpLen + 2U) == ui32IpLen && pIP[0] == '[' && pIP[1 + pDcCommand->m_pUser->m_ui8IpLen] == ']' && strncmp(pIP + 1, pDcCommand->m_pUser->m_sIP, pDcCommand->m_pUser->m_ui8IpLen) == 0)
			{
				bInvalidIP = false;
			}
			else if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4) && pDcCommand->m_pUser->m_ui8IPv4Len == ui32IpLen &&  strncmp(pIP, pDcCommand->m_pUser->m_sIPv4, pDcCommand->m_pUser->m_ui8IPv4Len) == 0)
			{
				bInvalidIP = false;
			}
		}
		else if (pDcCommand->m_pUser->m_ui8IpLen == ui32IpLen && strncmp(pIP, pDcCommand->m_pUser->m_sIP, pDcCommand->m_pUser->m_ui8IpLen) == 0)
		{
			bInvalidIP = false;
		}

		// IP check
		if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOIPCHECK) == false && bInvalidIP == true)
		{
			if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_WARNED_WRONG_IP) == User::BIT_WARNED_WRONG_IP) == false)
			{
				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad Ip in %sSearch from %s (%s/%s). (%s)", bMulti == false ? "" : "M", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_pUser->m_sIPv4, pDcCommand->m_sCommand);
			}

			if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6)
			{
				if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV6_ACTIVE) == User::BIT_IPV6_ACTIVE)
				{
					int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$Search [%s]:%hu %s", pDcCommand->m_pUser->m_sIP, ui16Port, pSpace + 1);
					if (iMsgLen > 0)
					{
						pDcCommand->m_pUser->m_pCmdActive6Search = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdActive6Search, ServerManager::m_pGlobalBuffer, iMsgLen, true);
					}
				}
				else
				{
					int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$Search Hub:%s %s", pDcCommand->m_pUser->m_sNick, pSpace + 1);
					if (iMsgLen > 0)
					{
						pDcCommand->m_pUser->m_pCmdPassiveSearch = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdPassiveSearch, ServerManager::m_pGlobalBuffer, iMsgLen, false);
					}
				}

				if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4)
				{
					if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV4_ACTIVE) == User::BIT_IPV4_ACTIVE)
					{
						int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$Search %s:%hu %s", pDcCommand->m_pUser->m_sIPv4, ui16Port, pSpace + 1);
						if (iMsgLen > 0)
						{
							pDcCommand->m_pUser->m_pCmdActive4Search = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdActive4Search, ServerManager::m_pGlobalBuffer, iMsgLen, true);
						}
					}
					else
					{
						int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$Search Hub:%s %s", pDcCommand->m_pUser->m_sNick, pSpace + 1);
						if (iMsgLen > 0)
						{
							pDcCommand->m_pUser->m_pCmdPassiveSearch = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdPassiveSearch, ServerManager::m_pGlobalBuffer, iMsgLen, false);
						}
					}
				}
			}
			else if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4)
			{
				char * sIP = pDcCommand->m_pUser->m_ui8IPv4Len == 0 ? pDcCommand->m_pUser->m_sIP : pDcCommand->m_pUser->m_sIPv4;

				int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$Search %s:%hu %s", sIP, ui16Port, pSpace + 1);
				if (iMsgLen > 0)
				{
					pDcCommand->m_pUser->m_pCmdActive4Search = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdActive4Search, ServerManager::m_pGlobalBuffer, iMsgLen, true);
				}
			}

			if (ui32IpLen != 0 && pIP[ui32IpLen - 1] == ']')
			{
				pIP[ui32IpLen - 1] = '\0';
			}
			else
			{
				pIP[ui32IpLen] = '\0';
			}

			if (pIP[0] == '[')
			{
				pIP++;
			}

			SendIPFixedMsg(pDcCommand->m_pUser, pIP, pDcCommand->m_pUser->m_sIP);
			return;
		}

		// Restore space after IP:Port
		pSpace[0] = ' ';

		if (bMulti == true)
		{
			pDcCommand->m_sCommand[5] = '$';
			pDcCommand->m_sCommand += 5;
			pDcCommand->m_ui32CommandLen -= 5;
		}

		if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6)
		{
			if (pDcCommand->m_sCommand[8] == '[')
			{
				pDcCommand->m_pUser->m_pCmdActive6Search = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdActive6Search, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, true);

				// IPv6 user sent active request.. when he have available IPv4 then create proper IPv4 request too.
				if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4)
				{
					if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV4_ACTIVE) == User::BIT_IPV4_ACTIVE)
					{
						int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$Search %s:%hu %s", pDcCommand->m_pUser->m_sIPv4, ui16Port, pSpace + 1);
						if (iMsgLen > 0)
						{
							pDcCommand->m_pUser->m_pCmdActive4Search = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdActive4Search, ServerManager::m_pGlobalBuffer, iMsgLen, true);
						}
					}
					else
					{
						int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$Search Hub:%s %s", pDcCommand->m_pUser->m_sNick, pSpace + 1);
						if (iMsgLen > 0)
						{
							pDcCommand->m_pUser->m_pCmdPassiveSearch = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdPassiveSearch, ServerManager::m_pGlobalBuffer, iMsgLen, false);
						}
					}
				}
			}
			else
			{
				// When IPv6 user sent active search request with IPv4 address (he should't do that) then just send this request...
				pDcCommand->m_pUser->m_pCmdActive4Search = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdActive4Search, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, true);
			}
		}
		else
		{
			pDcCommand->m_pUser->m_pCmdActive4Search = AddSearch(pDcCommand->m_pUser, pDcCommand->m_pUser->m_pCmdActive4Search, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, true);
		}
	}
}
//---------------------------------------------------------------------------
#ifdef USE_FLYLINKDC_EXT_JSON
//---------------------------------------------------------------------------
// $ExtJSON |
bool DcCommands::ExtJSONDeflood(User * pUser, const char * sData, const uint32_t ui32Len, const bool /* bCheck */)
{
	if (CheckExtJSON(pUser, sData, ui32Len) == false)
	{
		return false;
	}
	/* TODO
	// PPK ... check flood ...
	if (bCheck == true && ProfileManager::m_Ptr->IsAllowed(pUser, ProfileManager::NODEFLOODMYINFO) == false) {
	    if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_ACTION] != 0) {
	        if (DeFloodCheckForFlood(pUser, DEFLOOD_MYINFO, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_ACTION],
	            pUser->m_ui16MyINFOs, pUser->m_ui64MyINFOsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_MESSAGES],
	            (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_TIME]) == true) {
	            return false;
	        }
	    }

	    if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_ACTION2] != 0) {
	        if (DeFloodCheckForFlood(pUser, DEFLOOD_MYINFO, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_ACTION2],
	            pUser->m_ui16MyINFOs2, pUser->m_ui64MyINFOsTick2, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_MESSAGES2],
	            (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_TIME2]) == true) {
	            return false;
	        }
	    }
	}

	if (ui32Len > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_MYINFO_LEN]) {
	    pUser->SendFormat("DcCommands::ExtJSONDeflood", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_MYINFO_TOO_LONG]);

	    UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $ExtJSON from %s (%s) - user closed. (%s)", pUser->m_sNick, pUser->m_sIP, sData);

	    pUser->Close();
	    return false;
	}
	*/
	return true;
}
//---------------------------------------------------------------------------
bool DcCommands::CheckExtJSON(User * pUser, const char * sData, const uint32_t ui32Len)
{
	if (pUser->m_sNick && pUser->m_ui8NickLen)
	{
		if (ui32Len > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_MYINFO_LEN] * 10)
		{
			pUser->SendFormat("DcCommands::CheckExtJSON", true, "<%s> %s!|", "Error", "strlen(ExtJSON) > (MaxMyINFOLen * 10)");
			//SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_MYINFO_TOO_LONG]
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $ExtJSON len (%u) from %s (%s) - user closed. (%s)", ui32Len, pUser->m_sNick, pUser->m_sIP, sData);
			pUser->Close();
			return false;
		}
		if (ui32Len <  pUser->m_ui8NickLen + unsigned(9))
		{
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $ExtJSON [1] (%s) from %s (%s) - user closed.", sData, pUser->m_sNick, pUser->m_sIP);
			pUser->Close();
			return false;
		}
		if ((ui32Len > pUser->m_ui8NickLen + unsigned(9)) && memcmp(sData + 9, pUser->m_sNick, pUser->m_ui8NickLen) != 0)
		{
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $ExtJSON [2] (%s) from %s (%s) - user closed.", sData, pUser->m_sNick, pUser->m_sIP);
			pUser->Close();
			return false;
		}
	}
	return true;
}
//---------------------------------------------------------------------------
// $ExtJSON |
bool DcCommands::SetExtJSON(User * pUser, const char * sData, const uint32_t ui32Len)
{
	if (CheckExtJSON(pUser, sData, ui32Len) == false)
	{
		return false;
	}
	if (pUser->ComparExtJSON(sData, ui32Len))
	{
		return false;
	}

	pUser->SetExtJSONOriginal(sData, (uint16_t)ui32Len);

	if (pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return false;
	}

	if (pUser->ProcessRules() == false)
	{
		pUser->Close();
		return false;
	}
	/*
	// PPK ... moved lua here -> another "optimization" ;o)
	ScriptManager::m_Ptr->Arrival(pUser, sData, ui32Len, ScriptManager::MYINFO_ARRIVAL);

	if (pUser->m_ui8State >= User::STATE_CLOSING) {
	    return false;
	}
	*/
	pUser->m_ui32BoolBits |= User::BIT_PRCSD_EXT_JSON;
	return true;
}

#endif

// $MyINFO $ALL  $ $$$$|
bool DcCommands::MyINFODeflood(DcCommand * pDcCommand)
{
	if (pDcCommand->m_ui32CommandLen < (22u + pDcCommand->m_pUser->m_ui8NickLen))
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $MyINFO (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return false;
	}

	// PPK ... check flood ...
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODMYINFO) == false)
	{
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_ACTION] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_MYINFO, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_ACTION],
			                         pDcCommand->m_pUser->m_ui16MyINFOs, pDcCommand->m_pUser->m_ui64MyINFOsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_MESSAGES],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_TIME]) == true)
			{
				return false;
			}
		}

		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_ACTION2] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_MYINFO, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_ACTION2],
			                         pDcCommand->m_pUser->m_ui16MyINFOs2, pDcCommand->m_pUser->m_ui64MyINFOsTick2, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_MESSAGES2],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_TIME2]) == true)
			{
				return false;
			}
		}
	}

	if (pDcCommand->m_ui32CommandLen > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_MYINFO_LEN])
	{
		pDcCommand->m_pUser->SendFormat("DcCommands::MyINFODeflood", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_MYINFO_TOO_LONG]);

		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $MyINFO from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return false;
	}

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

// $MyINFO $ALL  $ $$$$|
bool DcCommands::MyINFO(DcCommand * pDcCommand)
{
	// if no change, just return
	// else store MyINFO and perform all checks again
	if (pDcCommand->m_pUser->m_sMyInfoOriginal != NULL)  // PPK ... optimizations
	{
		if (pDcCommand->m_ui32CommandLen == pDcCommand->m_pUser->m_ui16MyInfoOriginalLen && memcmp(pDcCommand->m_pUser->m_sMyInfoOriginal + 14 + pDcCommand->m_pUser->m_ui8NickLen, pDcCommand->m_sCommand + 14 + pDcCommand->m_pUser->m_ui8NickLen, pDcCommand->m_pUser->m_ui16MyInfoOriginalLen - 14 - pDcCommand->m_pUser->m_ui8NickLen) == 0)
		{
			return false;
		}
	}

	pDcCommand->m_pUser->SetMyInfoOriginal(pDcCommand->m_sCommand, (uint16_t)pDcCommand->m_ui32CommandLen);

	if (pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return false;
	}

	if (pDcCommand->m_pUser->ProcessRules() == false)
	{
		pDcCommand->m_pUser->Close();
		return false;
	}

	// TODO 3 -oPTA -ccheckers: Slots fetching for no tag users
	//search command for slots fetch for users without tag
	//if(pDcCommand->m_pUser->Tag == NULL)
	//{
	//    pDcCommand->m_pUser->SendText("$Search "+HubAddress->Text+":411 F?F?0?1?.|");
	//}

	// SEND myinfo to others (including me) only if this is
	// a refresh MyINFO event. Else dispatch it in addMe condition
	// of service loop

	// PPK ... moved lua here -> another "optimization" ;o)
	ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::MYINFO_ARRIVAL);

	if (pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return false;
	}

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

// $MyPass
void DcCommands::MyPass(DcCommand * pDcCommand)
{
	RegUser * pReg = RegManager::m_Ptr->Find(pDcCommand->m_pUser);
	if (pReg != NULL && (pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_WAITING_FOR_PASS) == User::BIT_WAITING_FOR_PASS)
	{
		pDcCommand->m_pUser->m_ui32BoolBits &= ~User::BIT_WAITING_FOR_PASS;
	}
	else
	{
		// We don't send $GetPass!
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] $MyPass without request from %s (%s) - user closed.", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (pDcCommand->m_ui32CommandLen < 10 || pDcCommand->m_ui32CommandLen > 73)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $MyPass from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

	bool bBadPass = false;

	if (pReg->m_bPassHash == true)
	{
		uint8_t ui8Hash[64];

		size_t szLen = pDcCommand->m_ui32CommandLen - 9;

		if (HashPassword(pDcCommand->m_sCommand + 8, szLen, ui8Hash) == false || memcmp(pReg->m_ui8PassHash, ui8Hash, 64) != 0)
		{
			bBadPass = true;
		}
	}
	else
	{
		if (strcmp(pReg->m_sPass, pDcCommand->m_sCommand + 8) != 0)
		{
			bBadPass = true;
		}
	}

	// if password is wrong, close the connection
	if (bBadPass == true)
	{
		if (SettingManager::m_Ptr->m_bBools[SETBOOL_ADVANCED_PASS_PROTECTION] == true)
		{
			time(&pReg->m_tLastBadPass);
			if (pReg->m_ui8BadPassCount < 255)
				pReg->m_ui8BadPassCount++;
		}

		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_BRUTE_FORCE_PASS_PROTECT_BAN_TYPE] != 0)
		{
			// brute force password protection
			PassBf * PassBfItem = Find(pDcCommand->m_pUser->m_ui128IpHash);
			if (PassBfItem == NULL)
			{
				PassBfItem = new (std::nothrow) PassBf(pDcCommand->m_pUser->m_ui128IpHash);
				if (PassBfItem == NULL)
				{
					AppendDebugLog("%s - [MEM] Cannot allocate new PassBfItem in DcCommands::MyPass\n");
					return;
				}

				if (m_pPasswdBfCheck != NULL)
				{
					m_pPasswdBfCheck->m_pPrev = PassBfItem;
					PassBfItem->m_pNext = m_pPasswdBfCheck;
				}
				
				m_pPasswdBfCheck = PassBfItem;
			}
			else
			{
				if (PassBfItem->m_iCount == 2)
				{
					BanItem * pBan = BanManager::m_Ptr->FindFull(pDcCommand->m_pUser->m_ui128IpHash);
					if (pBan == NULL || ((pBan->m_ui8Bits & BanManager::FULL) == BanManager::FULL) == false)
					{
						int iRet = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "3x bad password for nick %s", pDcCommand->m_pUser->m_sNick);
						if (iRet <= 0)
						{
							ServerManager::m_pGlobalBuffer[0] = '\0';
						}

						if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_BRUTE_FORCE_PASS_PROTECT_BAN_TYPE] == 1)
						{
							BanManager::m_Ptr->BanIp(pDcCommand->m_pUser, NULL, ServerManager::m_pGlobalBuffer, NULL, true);
						}
						else
						{
							BanManager::m_Ptr->TempBanIp(pDcCommand->m_pUser, NULL, ServerManager::m_pGlobalBuffer, NULL, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_BRUTE_FORCE_PASS_PROTECT_TEMP_BAN_TIME] * 60, 0, true);
						}
						Remove(PassBfItem);

						pDcCommand->m_pUser->SendFormat("DcCommands::MyPass1", false, "<%s> %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_IP_BANNED_BRUTE_FORCE_ATTACK]);
					}
					else
					{
						pDcCommand->m_pUser->SendFormat("DcCommands::MyPass2", false, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_IS_BANNED]);
					}
					if (SettingManager::m_Ptr->m_bBools[SETBOOL_REPORT_3X_BAD_PASS] == true)
					{
						GlobalDataQueue::m_Ptr->StatusMessageFormat("DcCommands::MyPass", "<%s> *** %s %s %s %s|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_IP], pDcCommand->m_pUser->m_sIP,
						        LanguageManager::m_Ptr->m_sTexts[LAN_BANNED_BECAUSE_3X_BAD_PASS_FOR_NICK], pDcCommand->m_pUser->m_sNick);
					}

					UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad 3x password from %s (%s) - user banned. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

					pDcCommand->m_pUser->Close();
					return;
				}
				else
				{
					PassBfItem->m_iCount++;
				}
			}
		}

		pDcCommand->m_pUser->SendFormat("DcCommands::MyPass3", false, "$BadPass|<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_INCORRECT_PASSWORD]);

		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad password from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}
	else
	{
		pDcCommand->m_pUser->m_i32Profile = (int32_t)pReg->m_ui16Profile;

		pReg->m_ui8BadPassCount = 0;

		PassBf * PassBfItem = Find(pDcCommand->m_pUser->m_ui128IpHash);
		if (PassBfItem != NULL)
		{
			Remove(PassBfItem);
		}

		pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '|'; // add back pipe

		// PPK ... Lua DataArrival only if pass is ok
		ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::PASSWORD_ARRIVAL);

		if (pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
		{
			return;
		}

		if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::HASKEYICON) == true)
		{
			pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_OPERATOR;
		}
		else
		{
			pDcCommand->m_pUser->m_ui32BoolBits &= ~User::BIT_OPERATOR;
		}

		// PPK ... addition for registered users, kill your own ghost >:-]
		if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HASHED) == User::BIT_HASHED) == false)
		{
			User *OtherUser = HashManager::m_Ptr->FindUser(pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_ui8NickLen);
			if (OtherUser != NULL)
			{
				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Ghost %s (%s) closed.", OtherUser->m_sNick, OtherUser->m_sIP);

				if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == false)
				{
					OtherUser->Close();
				}
				else
				{
					OtherUser->Close(true);
				}
			}
			if (HashManager::m_Ptr->Add(pDcCommand->m_pUser) == false)
			{
				return;
			}
			pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_HASHED;
		}
		if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == false)
		{
			// welcome the new user
			// PPK ... fixed bad DC protocol implementation, $LogedIn is only for OPs !!!
			// registered DC1 users have enabled OP menu :)))))))))
			if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == true)
			{
				pDcCommand->m_pUser->SendFormat("DcCommands::MyPass4", true, "$Hello %s|$LogedIn %s|", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sNick);
			}
			else
			{
				pDcCommand->m_pUser->SendFormat("DcCommands::MyPass5", true, "$Hello %s|", pDcCommand->m_pUser->m_sNick);
			}

			return;
		}
		else
		{
			if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == false)
			{
				pDcCommand->m_pUser->AddMeOrIPv4Check();
			}
		}
	}
}
//---------------------------------------------------------------------------

// $OpForceMove $Who:<nickname>$Where:<iptoredirect>$Msg:<a message>
void DcCommands::OpForceMove(DcCommand * pDcCommand)
{
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::REDIRECT) == false)
	{
		pDcCommand->m_pUser->SendFormat("DcCommands::OpForceMove1", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_NOT_ALWD_TO_USE_THIS_CMD]);
		return;
	}

	if (pDcCommand->m_ui32CommandLen < 31)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $OpForceMove (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::OPFORCEMOVE_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

	char *sCmdParts[] = { NULL, NULL, NULL };
	uint16_t iCmdPartsLen[] = { 0, 0, 0 };

	uint8_t cPart = 0;

	sCmdParts[cPart] = pDcCommand->m_sCommand + 18; // nick start

	for (uint32_t ui32i = 18; ui32i < pDcCommand->m_ui32CommandLen; ui32i++)
	{
		if (pDcCommand->m_sCommand[ui32i] == '$')
		{
			pDcCommand->m_sCommand[ui32i] = '\0';
			iCmdPartsLen[cPart] = (uint16_t)((pDcCommand->m_sCommand + ui32i) - sCmdParts[cPart]);

			// are we on last $ ???
			if (cPart == 1)
			{
				sCmdParts[2] = pDcCommand->m_sCommand + ui32i + 1;
				iCmdPartsLen[2] = (uint16_t)(pDcCommand->m_ui32CommandLen - ui32i - 1);
				break;
			}

			cPart++;
			sCmdParts[cPart] = pDcCommand->m_sCommand + ui32i + 1;
		}
	}

	if (iCmdPartsLen[0] == 0 || iCmdPartsLen[1] < 7 || iCmdPartsLen[2] < 5 || iCmdPartsLen[1] > 4096 || iCmdPartsLen[2] > 16384)
	{
		return;
	}

	User *OtherUser = HashManager::m_Ptr->FindUser(sCmdParts[0], iCmdPartsLen[0]);
	if(OtherUser)
	{
		// Self redirect
		if(OtherUser == pDcCommand->m_pUser)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::OpForceMove2", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_CANT_REDIRECT_YOURSELF]);
			return;
		}

		if(OtherUser->m_i32Profile != -1 && pDcCommand->m_pUser->m_i32Profile > OtherUser->m_i32Profile)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::OpForceMove3", true, "<%s> %s %s|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_NOT_ALLOWED_TO_REDIRECT], OtherUser->m_sNick);
			return;
		}

		OtherUser->SendFormat("DcCommands::OpForceMove4", false, "<%s> %s %s %s %s. %s: %s|$ForceMove %s|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_REDIRECTED_TO], sCmdParts[1]+6,
		                      LanguageManager::m_Ptr->m_sTexts[LAN_BY_LWR], pDcCommand->m_pUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_MESSAGE], sCmdParts[2] + 4, sCmdParts[1] + 6);

		// PPK ... close user !!!
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] User %s (%s) redirected by %s", OtherUser->m_sNick, OtherUser->m_sIP, pDcCommand->m_pUser->m_sNick);

		OtherUser->Close();

		if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_STATUS_MESSAGES] == true)
		{
			GlobalDataQueue::m_Ptr->StatusMessageFormat("DcCommands::OpForceMove", "<%s> *** %s %s %s %s %s. %s: %s|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_IS_REDIRECTED_TO], sCmdParts[1] + 6,
			        LanguageManager::m_Ptr->m_sTexts[LAN_BY_LWR], pDcCommand->m_pUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_MESSAGE], sCmdParts[2] + 4);
		}

		if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_STATUS_MESSAGES] == false || ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::OpForceMove4", true, "<%s> *** %s %s %s. %s: %s|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_IS_REDIRECTED_TO], sCmdParts[1] + 6, LanguageManager::m_Ptr->m_sTexts[LAN_MESSAGE], sCmdParts[2] + 4);
		}
	}
}
//---------------------------------------------------------------------------

// $RevConnectToMe <ownnick> <nickname>
void DcCommands::RevConnectToMe(DcCommand * pDcCommand)
{
	if (pDcCommand->m_ui32CommandLen < 19)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $RevConnectToMe (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	// PPK ... optimizations
	if ((pDcCommand->m_sCommand[16 + pDcCommand->m_pUser->m_ui8NickLen] != ' ') || (memcmp(pDcCommand->m_sCommand + 16, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_ui8NickLen) != 0))
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in RCTM from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	// PPK ... check flood ...
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODRCTM) == false)
	{
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_RCTM_ACTION] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_RCTM, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_RCTM_ACTION],
			                         pDcCommand->m_pUser->m_ui16RCTMs, pDcCommand->m_pUser->m_ui64RCTMsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_RCTM_MESSAGES],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_RCTM_TIME]) == true)
			{
				return;
			}
		}

		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_RCTM_ACTION2] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_RCTM, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_RCTM_ACTION2],
			                         pDcCommand->m_pUser->m_ui16RCTMs2, pDcCommand->m_pUser->m_ui64RCTMsTick2, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_RCTM_MESSAGES2],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_RCTM_TIME2]) == true)
			{
				return;
			}
		}
	}

	if (pDcCommand->m_ui32CommandLen > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_RCTM_LEN])
	{
		pDcCommand->m_pUser->SendFormat("DcCommands::RevConnectToMe", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_RCTM_TOO_LONG]);

		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Long $RevConnectToMe from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	// PPK ... $RCTM means user is pasive ?!? Probably yes, let set it not active and use on another places ;)
	if (pDcCommand->m_pUser->m_sTag == NULL)
	{
		pDcCommand->m_pUser->m_ui32BoolBits &= ~User::BIT_IPV4_ACTIVE;
	}

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::REVCONNECTTOME_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

	User *OtherUser = HashManager::m_Ptr->FindUser(pDcCommand->m_sCommand + 17 + pDcCommand->m_pUser->m_ui8NickLen, pDcCommand->m_ui32CommandLen - (18 + pDcCommand->m_pUser->m_ui8NickLen));
	// PPK ... no connection to yourself !!!
	if (OtherUser != NULL && OtherUser != pDcCommand->m_pUser && OtherUser->m_ui8State == User::STATE_ADDED)
	{
		pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '|'; // add back pipe
		pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::CTM_MCTM_RCTM_SR_TO, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, OtherUser);
	}
}
//---------------------------------------------------------------------------

// $SR <nickname> - Search Respond for passive users
void DcCommands::SR(DcCommand * pDcCommand)
{
	if (pDcCommand->m_ui32CommandLen < 6u + pDcCommand->m_pUser->m_ui8NickLen)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $SR (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	// PPK ... check flood ...
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODSR) == false)
	{
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SR_ACTION] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_SR, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SR_ACTION],
			                         pDcCommand->m_pUser->m_ui16SRs, pDcCommand->m_pUser->m_ui64SRsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SR_MESSAGES],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SR_TIME]) == true)
			{
				return;
			}
		}

		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SR_ACTION2] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_SR, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SR_ACTION2],
			                         pDcCommand->m_pUser->m_ui16SRs2, pDcCommand->m_pUser->m_ui64SRsTick2, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SR_MESSAGES2],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SR_TIME2]) == true)
			{
				return;
			}
		}
	}

	if (pDcCommand->m_ui32CommandLen > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SR_LEN])
	{
		pDcCommand->m_pUser->SendFormat("DcCommands::SR", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SR_TOO_LONG]);

		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Long $SR from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);


		pDcCommand->m_pUser->Close();
		return;
	}

	// check $SR spoofing (thanx Fusbar)
	// PPK... added checking for empty space after nick
	if (pDcCommand->m_sCommand[4 + pDcCommand->m_pUser->m_ui8NickLen] != ' ' || memcmp(pDcCommand->m_sCommand + 4, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_ui8NickLen) != 0)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in SR from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	// past SR to script only if it's not a data for SlotFetcher
	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::SR_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

	char * pToNick = strrchr(pDcCommand->m_sCommand, '\5');
	if (pToNick == NULL) return;

	User *OtherUser = HashManager::m_Ptr->FindUser(pToNick + 1, pDcCommand->m_ui32CommandLen - 2 - (pToNick - pDcCommand->m_sCommand));
	// PPK ... no $SR to yourself !!!
	if (OtherUser != NULL && OtherUser != pDcCommand->m_pUser && OtherUser->m_ui8State == User::STATE_ADDED)
	{
		// PPK ... search replies limiting
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PASIVE_SR] != 0)
		{
			if (OtherUser->m_ui32SR >= (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PASIVE_SR])
				return;

			OtherUser->m_ui32SR++;
		}

		// cutoff the last part // PPK ... and do it fast ;)
		pToNick[0] = '|';
		pToNick[1] = '\0';
		pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::CTM_MCTM_RCTM_SR_TO, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen - OtherUser->m_ui8NickLen - 1, OtherUser);
	}
}

//---------------------------------------------------------------------------
#ifdef FLYLINKDC_USE_UDP_THREAD
// $SR <nickname> - Search Respond for active users from UDP
void DcCommands::SRFromUDP(DcCommand * pDcCommand)
{
	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::UDP_SR_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}
}
#endif
//---------------------------------------------------------------------------

// $Supports item item item... PPK $Supports UserCommand NoGetINFO NoHello UserIP2 QuickList|
void DcCommands::Supports(DcCommand * pDcCommand)
{
	if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_HAVE_SUPPORTS) == User::BIT_HAVE_SUPPORTS) == true)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] $Supports flood from %s (%s) - user closed.", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_HAVE_SUPPORTS;

	if (pDcCommand->m_ui32CommandLen < 13)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $Supports (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 2] == ' ')
	{
		if (SettingManager::m_Ptr->m_bBools[SETBOOL_NO_QUACK_SUPPORTS] == false)
		{
			pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_QUACK_SUPPORTS;
		}
		else
		{
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Quack $Supports from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

			pDcCommand->m_pUser->SendFormat("DcCommands::Supports1", false, "<%s> %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_QUACK_SUPPORTS]);

			pDcCommand->m_pUser->Close();
			return;
		}
	}

	ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::SUPPORTS_ARRIVAL);

	if (pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	char * sSupport = pDcCommand->m_sCommand + 10;
	size_t szDataLen;

	for (uint32_t ui32i = 10; ui32i < pDcCommand->m_ui32CommandLen - 1; ui32i++)
	{
		if (pDcCommand->m_sCommand[ui32i] == ' ')
		{
			pDcCommand->m_sCommand[ui32i] = '\0';
		}
		else if (ui32i != pDcCommand->m_ui32CommandLen - 2)
		{
			continue;
		}
		else
		{
			ui32i++;
		}

		szDataLen = (pDcCommand->m_sCommand + ui32i) - sSupport;

		switch (sSupport[0])
		{
		case 'N':
			if (sSupport[1] == 'o')
			{
				if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_NOHELLO) == User::SUPPORTBIT_NOHELLO) == false && szDataLen == 7 && memcmp(sSupport + 2, "Hello", 5) == 0)
				{
					pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_NOHELLO;
				}
				else if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_NOGETINFO) == User::SUPPORTBIT_NOGETINFO) == false && szDataLen == 9 && memcmp(sSupport + 2, "GetINFO", 7) == 0)
				{
					pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_NOGETINFO;
				}
			}
			break;
		case 'Q':
		{
			if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == false && szDataLen == 9 && *((uint64_t *)(sSupport + 1)) == *((uint64_t *)"uickList"))
			{
				pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_QUICKLIST;
				// PPK ... in fact NoHello is only not fully implemented Quicklist (without diferent login sequency)
				// That's why i overide NoHello here and use bQuicklist only for login, on other places is same as NoHello ;)
				pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_NOHELLO;
			}
			break;
		}
		case 'H':
		{
			if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_HUBURL) == User::SUPPORTBIT_HUBURL) == false && szDataLen == 6 && memcmp(sSupport + 1, "ubURL", 5) == 0)
			{
				pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_HUBURL;
			}
			break; // fix PVS Studio
		}
		case 'U':
		{
			if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_USERCOMMAND) == User::SUPPORTBIT_USERCOMMAND) == false && szDataLen == 11 && memcmp(sSupport + 1, "serCommand", 10) == 0)
			{
				pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_USERCOMMAND;
			}
			else if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_USERIP2) == User::SUPPORTBIT_USERIP2) == false && szDataLen == 7 && memcmp(sSupport + 1, "serIP2", 6) == 0)
			{
				pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_USERIP2;
			}
			break;
		}
		case 'B':
		{
			if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == false && szDataLen == 7 && memcmp(sSupport + 1, "otINFO", 6) == 0)
			{
				if (SettingManager::m_Ptr->m_bBools[SETBOOL_DONT_ALLOW_PINGERS] == true)
				{
					pDcCommand->m_pUser->SendFormat("DcCommands::Supports2", false, "<%s> %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SORRY_THIS_HUB_NOT_ALLOW_PINGERS]);
					pDcCommand->m_pUser->Close();
					return;
				}
				else
				{
					pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_PINGER;
					pDcCommand->m_pUser->SendFormat("DcCommands::Supports4", true, "%s%" PRIu64 " %s, %" PRIu64 " %s, %" PRIu64 " %s / %s: %u)|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_NAME_WLCM], ServerManager::m_ui64Days, LanguageManager::m_Ptr->m_sTexts[LAN_DAYS_LWR],
					                                ServerManager::m_ui64Hours, LanguageManager::m_Ptr->m_sTexts[LAN_HOURS_LWR], ServerManager::m_ui64Mins, LanguageManager::m_Ptr->m_sTexts[LAN_MINUTES_LWR], LanguageManager::m_Ptr->m_sTexts[LAN_USERS], ServerManager::m_ui32Logged);
				}
			}
			break;
		}
		case 'Z':
		{
			if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_ZPIPE) == User::SUPPORTBIT_ZPIPE) == false)
			{
				if (szDataLen == 6 && memcmp(sSupport + 1, "Pipe0", 5) == 0)
				{
					pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_ZPIPE0;
					pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_ZPIPE;
					m_ui32StatZPipe++;
				}
				else if (szDataLen == 5 && *((uint32_t *)(sSupport + 1)) == *((uint32_t *)"Pipe"))
				{
					pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_ZPIPE;
					m_ui32StatZPipe++;
				}
			}
			break;
		}
		case 'I':
		{
			if (szDataLen == 4)
			{
				if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_IP64) == User::SUPPORTBIT_IP64) == false && *((uint32_t *)sSupport) == *((uint32_t *)"IP64"))
				{
					pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_IP64;
				}
				else if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_IPV4) == User::SUPPORTBIT_IPV4) == false && *((uint32_t *)sSupport) == *((uint32_t *)"IPv4"))
				{
					pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_IPV4;
				}
			}
			break;
		}
		case 'T':
		{
			if (szDataLen == 4)
			{
				if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_TLS2) == User::SUPPORTBIT_TLS2) == false && *((uint32_t *)sSupport) == *((uint32_t *)"TLS2"))
				{
					pDcCommand->m_pUser->m_ui32SupportBits |= User::SUPPORTBIT_TLS2;
				}
			}
			break;
		}
#ifdef USE_FLYLINKDC_EXT_JSON
		case 'E':
		{
			if (szDataLen == 8)
			{
				if (pDcCommand->m_pUser->isSupportExtJSON() == false && memcmp(sSupport + 1, "xtJSON2", 7) == 0)
				{
					pDcCommand->m_pUser->m_is_json_user = true; // |= User::SUPPORTBIT_EXTJSON2;
				}
			}
			break;
		}
#endif
		case '\0':
		{
			// PPK ... corrupted $Supports ???
			UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $Supports from %s (%s) - user closed.", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

			pDcCommand->m_pUser->Close();
			return;
		}
		default:
			// PPK ... unknown supports
			break;
		}

		sSupport = pDcCommand->m_sCommand + ui32i + 1;
	}

	pDcCommand->m_pUser->m_ui8State = User::STATE_VALIDATE;

	pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::SUPPORTS, NULL, 0, NULL);
}
//---------------------------------------------------------------------------

// $To: nickname From: ownnickname $<ownnickname> <message>
void DcCommands::To(DcCommand * pDcCommand)
{
	char * pTemp = strchr(pDcCommand->m_sCommand + 5, ' ');

	if (pDcCommand->m_ui32CommandLen < 19 || pTemp == NULL)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad To from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	size_t szNickLen = pTemp - (pDcCommand->m_sCommand + 5);

	if (szNickLen > 64)
	{
		pDcCommand->m_pUser->SendFormat("DcCommands::To1", true, "<%s> *** %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_MAX_ALWD_NICK_LEN_64_CHARS]);
		return;
	}

	// is the mesg really from us ?
	// PPK ... replaced by better and faster code ;)
	int iRet = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "From: %s $<%s> ", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sNick);
	if (iRet <= 0 || strncmp(pTemp + 1, ServerManager::m_pGlobalBuffer, iRet) != 0)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in To from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return;
	}

	//FloodCheck
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODPM) == false)
	{
		// PPK ... pm antiflood
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_ACTION] != 0)
		{
			pTemp[0] = '\0';
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_PM, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_ACTION],
			                         pDcCommand->m_pUser->m_ui16PMs, pDcCommand->m_pUser->m_ui64PMsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_MESSAGES],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_TIME], pDcCommand->m_sCommand + 5) == true)
			{
				return;
			}
			pTemp[0] = ' ';
		}

		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_ACTION2] != 0)
		{
			pTemp[0] = '\0';
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_PM, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_ACTION2],
			                         pDcCommand->m_pUser->m_ui16PMs2, pDcCommand->m_pUser->m_ui64PMsTick2, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_MESSAGES2],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_TIME2], pDcCommand->m_sCommand + 5) == true)
			{
				return;
			}
			pTemp[0] = ' ';
		}

		// 2nd check for PM flooding
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_PM_ACTION] != 0)
		{
			bool bNewData = false;
			pTemp[0] = '\0';
			if (DeFloodCheckForSameFlood(pDcCommand->m_pUser, DEFLOOD_SAME_PM, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_PM_ACTION],
			                             pDcCommand->m_pUser->m_ui16SamePMs, pDcCommand->m_pUser->m_ui64SamePMsTick,
			                             SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_PM_MESSAGES], SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_PM_TIME],
			                             pTemp + (12 + (2 * pDcCommand->m_pUser->m_ui8NickLen)), (pDcCommand->m_ui32CommandLen - (pTemp - pDcCommand->m_sCommand)) - (12 + (2 * pDcCommand->m_pUser->m_ui8NickLen)),
			                             pDcCommand->m_pUser->m_sLastPM, pDcCommand->m_pUser->m_ui16LastPMLen, bNewData, pDcCommand->m_sCommand + 5) == true)
			{
				return;
			}
			pTemp[0] = ' ';

			if (bNewData == true)
			{
				pDcCommand->m_pUser->SetLastPM(pTemp + (12 + (2 * pDcCommand->m_pUser->m_ui8NickLen)), (pDcCommand->m_ui32CommandLen - (pTemp - pDcCommand->m_sCommand)) - (12 + (2 * pDcCommand->m_pUser->m_ui8NickLen)));
			}
		}
	}

	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOCHATLIMITS) == false)
	{
		// 1st check for length limit for PM message
		size_t szMessLen = pDcCommand->m_ui32CommandLen - (2 * pDcCommand->m_pUser->m_ui8NickLen) - (pTemp - pDcCommand->m_sCommand) - 13;
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PM_LEN] != 0 && szMessLen > (size_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PM_LEN])
		{
			// PPK ... hubsec alias
			pTemp[0] = '\0';
			pDcCommand->m_pUser->SendFormat("DcCommands::To2", true, "$To: %s From: %s $<%s> %s!|", pDcCommand->m_pUser->m_sNick, pDcCommand->m_sCommand + 5, SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_THE_MESSAGE_WAS_TOO_LONG]);
			return;
		}

		// PPK ... check for message lines limit
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PM_LINES] != 0 || SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_PM_ACTION] != 0)
		{
			if (pDcCommand->m_pUser->m_ui16SamePMs < 2)
			{
				uint16_t iLines = 1;
				for (uint32_t ui32i = 9 + pDcCommand->m_pUser->m_ui8NickLen; ui32i < pDcCommand->m_ui32CommandLen - (pTemp - pDcCommand->m_sCommand) - 1; ui32i++)
				{
					if (pTemp[ui32i] == '\n')
					{
						iLines++;
					}
				}
				pDcCommand->m_pUser->m_ui16LastPmLines = iLines;
				if (pDcCommand->m_pUser->m_ui16LastPmLines > 1)
				{
					pDcCommand->m_pUser->m_ui16SameMultiPms++;
				}
			}
			else if (pDcCommand->m_pUser->m_ui16LastPmLines > 1)
			{
				pDcCommand->m_pUser->m_ui16SameMultiPms++;
			}

			if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODPM) == false && SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_PM_ACTION] != 0)
			{
				if (pDcCommand->m_pUser->m_ui16SameMultiPms > SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_PM_MESSAGES] &&
				        pDcCommand->m_pUser->m_ui16LastPmLines >= SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_PM_LINES])
				{
					pTemp[0] = '\0';
					uint16_t lines = 0;
					DeFloodDoAction(pDcCommand->m_pUser, DEFLOOD_SAME_MULTI_PM, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_PM_ACTION], lines, pDcCommand->m_sCommand + 5);
					return;
				}
			}

			if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PM_LINES] != 0 && pDcCommand->m_pUser->m_ui16LastPmLines > SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PM_LINES])
			{
				pTemp[0] = '\0';
				pDcCommand->m_pUser->SendFormat("DcCommands::To3", true, "$To: %s From: %s $<%s> %s!|", pDcCommand->m_pUser->m_sNick, pDcCommand->m_sCommand + 5, SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_THE_MESSAGE_WAS_TOO_LONG]);
				return;
			}
		}
	}

	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOPMINTERVAL) == false)
	{
		pTemp[0] = '\0';
		if (DeFloodCheckInterval(pDcCommand->m_pUser, INTERVAL_PM, pDcCommand->m_pUser->m_ui16PMsInt,
		                         pDcCommand->m_pUser->m_ui64PMsIntTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_INTERVAL_MESSAGES],
		                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_PM_INTERVAL_TIME], pDcCommand->m_sCommand + 5) == true)
		{
			return;
		}
		pTemp[0] = ' ';
	}

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::TO_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pTemp[0] = '\0';

	// ignore the silly debug messages !!!
	if (memcmp(pDcCommand->m_sCommand + 5, "Vandel\\Debug", 12) == 0)
	{
		return;
	}

	// Everything's ok lets chat
	// if this is a PM to OpChat or Hub bot, process the message
	if (SettingManager::m_Ptr->m_bBools[SETBOOL_REG_BOT] == true && strcmp(pDcCommand->m_sCommand + 5, SettingManager::m_Ptr->m_sTexts[SETTXT_BOT_NICK]) == 0)
	{
		pTemp += 9 + pDcCommand->m_pUser->m_ui8NickLen;
		// PPK ... check message length, return if no mess found
		uint32_t ui32Len1 = (uint32_t)((pDcCommand->m_ui32CommandLen - (pTemp - pDcCommand->m_sCommand)) + 1);
		if (ui32Len1 <= pDcCommand->m_pUser->m_ui8NickLen + 4u)
			return;

		// find chat message data
		char *sBuff = pTemp + pDcCommand->m_pUser->m_ui8NickLen + 3;

		// non-command chat msg
		for (uint8_t ui8i = 0; ui8i < (uint8_t)SettingManager::m_Ptr->m_ui16TextsLens[SETTXT_CHAT_COMMANDS_PREFIXES]; ui8i++)
		{
			if (sBuff[0] == SettingManager::m_Ptr->m_sTexts[SETTXT_CHAT_COMMANDS_PREFIXES][ui8i])
			{
				pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe
				// built-in commands
				if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_TEXT_FILES] == true &&
				        TextFilesManager::m_Ptr->ProcessTextFilesCmd(pDcCommand->m_pUser, sBuff + 1, true))
				{
					return;
				}

				// HubCommands
				if (ui32Len1 - pDcCommand->m_pUser->m_ui8NickLen >= 10)
				{
					if (HubCommands::DoCommand(pDcCommand->m_pUser, sBuff, ui32Len1, true)) return;
				}

				pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '|'; // add back pipe
				break;
			}
		}
		// PPK ... if i am here is not textfile request or hub command, try opchat
		if (SettingManager::m_Ptr->m_bBools[SETBOOL_REG_OP_CHAT] == true && ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::ALLOWEDOPCHAT) == true &&
		        SettingManager::m_Ptr->m_bBotsSameNick == true)
		{
			uint32_t iOpChatLen = SettingManager::m_Ptr->m_ui16TextsLens[SETTXT_OP_CHAT_NICK];
			memcpy(pTemp - iOpChatLen - 2, SettingManager::m_Ptr->m_sTexts[SETTXT_OP_CHAT_NICK], iOpChatLen);
			pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::TO_OP_CHAT, pTemp - iOpChatLen - 2, pDcCommand->m_ui32CommandLen - ((pTemp - iOpChatLen - 2) - pDcCommand->m_sCommand), NULL);
		}
	}
	else if (SettingManager::m_Ptr->m_bBools[SETBOOL_REG_OP_CHAT] == true &&
	         ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::ALLOWEDOPCHAT) == true &&
	         strcmp(pDcCommand->m_sCommand + 5, SettingManager::m_Ptr->m_sTexts[SETTXT_OP_CHAT_NICK]) == 0)
	{
		pTemp += 9 + pDcCommand->m_pUser->m_ui8NickLen;
		uint32_t iOpChatLen = SettingManager::m_Ptr->m_ui16TextsLens[SETTXT_OP_CHAT_NICK];
		memcpy(pTemp - iOpChatLen - 2, SettingManager::m_Ptr->m_sTexts[SETTXT_OP_CHAT_NICK], iOpChatLen);
		pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::TO_OP_CHAT, pTemp - iOpChatLen - 2, (pDcCommand->m_ui32CommandLen - (pTemp - pDcCommand->m_sCommand)) + iOpChatLen + 2, NULL);
	}
	else
	{
		User *OtherUser = HashManager::m_Ptr->FindUser(pDcCommand->m_sCommand + 5, szNickLen);
		// PPK ... pm to yourself ?!? NO!
		if (OtherUser != NULL && OtherUser != pDcCommand->m_pUser && OtherUser->m_ui8State == User::STATE_ADDED)
		{
			pTemp[0] = ' ';
			pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::CTM_MCTM_RCTM_SR_TO, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, OtherUser, true);
		}
	}
}
//---------------------------------------------------------------------------

// $ValidateNick
void DcCommands::ValidateNick(DcCommand * pDcCommand)
{
	if (((pDcCommand->m_pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == true)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] $ValidateNick with QuickList support from %s (%s) - user closed.", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (pDcCommand->m_ui32CommandLen < 16)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Attempt to Validate empty nick (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe
	if (ValidateUserNick(pDcCommand,pDcCommand->m_pUser, pDcCommand->m_sCommand + 14, pDcCommand->m_ui32CommandLen - 15, true) == false) return;

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '|'; // add back pipe

	ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::VALIDATENICK_ARRIVAL);
}
//---------------------------------------------------------------------------

// $Version
void DcCommands::Version(DcCommand * pDcCommand)
{
	if (pDcCommand->m_ui32CommandLen < 11)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $Version (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	pDcCommand->m_pUser->m_ui8State = User::STATE_GETNICKLIST_OR_MYINFO;

	ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::VERSION_ARRIVAL);

	if (pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe
	pDcCommand->m_pUser->SetVersion(pDcCommand->m_sCommand + 9);
}
//---------------------------------------------------------------------------

// Chat message
bool DcCommands::ChatDeflood(DcCommand * pDcCommand)
{
#ifdef _BUILD_GUI
	if (::SendMessage(MainWindowPageUsersChat::m_Ptr->m_hWndPageItems[MainWindowPageUsersChat::BTN_SHOW_CHAT], BM_GETCHECK, 0, 0) == BST_CHECKED)
	{
		pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0';
		RichEditAppendText(MainWindowPageUsersChat::m_Ptr->m_hWndPageItems[MainWindowPageUsersChat::REDT_CHAT], pDcCommand->m_sCommand);
		pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '|';
	}
#endif

	// if the user is sending chat as other user, kick him
	if (pDcCommand->m_sCommand[1 + pDcCommand->m_pUser->m_ui8NickLen] != '>' || pDcCommand->m_sCommand[2 + pDcCommand->m_pUser->m_ui8NickLen] != ' ' || memcmp(pDcCommand->m_pUser->m_sNick, pDcCommand->m_sCommand + 1, pDcCommand->m_pUser->m_ui8NickLen) != 0)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick spoofing in chat from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		pDcCommand->m_pUser->Close();
		return false;
	}

	// PPK ... check flood...
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODMAINCHAT) == false)
	{
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAIN_CHAT_ACTION] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_CHAT, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAIN_CHAT_ACTION],
			                         pDcCommand->m_pUser->m_ui16ChatMsgs, pDcCommand->m_pUser->m_ui64ChatMsgsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAIN_CHAT_MESSAGES],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAIN_CHAT_TIME]) == true)
			{
				return false;
			}
		}

		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAIN_CHAT_ACTION2] != 0)
		{
			if (DeFloodCheckForFlood(pDcCommand->m_pUser, DEFLOOD_CHAT, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAIN_CHAT_ACTION2],
			                         pDcCommand->m_pUser->m_ui16ChatMsgs2, pDcCommand->m_pUser->m_ui64ChatMsgsTick2, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAIN_CHAT_MESSAGES2],
			                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAIN_CHAT_TIME2]) == true)
			{
				return false;
			}
		}

		// 2nd check for chatmessage flood
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MAIN_CHAT_ACTION] != 0)
		{
			bool bNewData = false;
			if (DeFloodCheckForSameFlood(pDcCommand->m_pUser, DEFLOOD_SAME_CHAT, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MAIN_CHAT_ACTION],
			                             pDcCommand->m_pUser->m_ui16SameChatMsgs, pDcCommand->m_pUser->m_ui64SameChatsTick,
			                             SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MAIN_CHAT_MESSAGES], SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MAIN_CHAT_TIME],
			                             pDcCommand->m_sCommand + pDcCommand->m_pUser->m_ui8NickLen + 3, pDcCommand->m_ui32CommandLen - (pDcCommand->m_pUser->m_ui8NickLen + 3), pDcCommand->m_pUser->m_sLastChat, pDcCommand->m_pUser->m_ui16LastChatLen, bNewData) == true)
			{
				return false;
			}

			if (bNewData == true)
			{
				pDcCommand->m_pUser->SetLastChat(pDcCommand->m_sCommand + pDcCommand->m_pUser->m_ui8NickLen + 3, pDcCommand->m_ui32CommandLen - (pDcCommand->m_pUser->m_ui8NickLen + 3));
			}
		}
	}

	// PPK ... ignore empty chat ;)
	if (pDcCommand->m_ui32CommandLen < pDcCommand->m_pUser->m_ui8NickLen + 5u)
	{
		return false;
	}

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

// Chat message
void DcCommands::Chat(DcCommand * pDcCommand)
{
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOCHATLIMITS) == false)
	{
		// PPK ... check for message limit length
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_CHAT_LEN] != 0 && (pDcCommand->m_ui32CommandLen - pDcCommand->m_pUser->m_ui8NickLen - 4) > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_CHAT_LEN])
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Chat1", true, "<%s> %s !|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_THE_MESSAGE_WAS_TOO_LONG]);
			return;
		}

		// PPK ... check for message lines limit
		if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_CHAT_LINES] != 0 || SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_MAIN_CHAT_ACTION] != 0)
		{
			if (pDcCommand->m_pUser->m_ui16SameChatMsgs < 2)
			{
				uint16_t iLines = 1;

				for (uint32_t ui32i = pDcCommand->m_pUser->m_ui8NickLen + 3; ui32i < pDcCommand->m_ui32CommandLen - 1; ui32i++)
				{
					if (pDcCommand->m_sCommand[ui32i] == '\n')
					{
						iLines++;
					}
				}

				pDcCommand->m_pUser->m_ui16LastChatLines = iLines;

				if (pDcCommand->m_pUser->m_ui16LastChatLines > 1)
				{
					pDcCommand->m_pUser->m_ui16SameMultiChats++;
				}
			}
			else if (pDcCommand->m_pUser->m_ui16LastChatLines > 1)
			{
				pDcCommand->m_pUser->m_ui16SameMultiChats++;
			}

			if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NODEFLOODMAINCHAT) == false && SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_MAIN_CHAT_ACTION] != 0)
			{
				if (pDcCommand->m_pUser->m_ui16SameMultiChats > SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_MAIN_CHAT_MESSAGES] &&
				        pDcCommand->m_pUser->m_ui16LastChatLines >= SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_MAIN_CHAT_LINES])
				{
					uint16_t lines = 0;
					DeFloodDoAction(pDcCommand->m_pUser, DEFLOOD_SAME_MULTI_CHAT, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MULTI_MAIN_CHAT_ACTION], lines, NULL);
					return;
				}
			}

			if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_CHAT_LINES] != 0 && pDcCommand->m_pUser->m_ui16LastChatLines > SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_CHAT_LINES])
			{
				pDcCommand->m_pUser->SendFormat("DcCommands::Chat2", true, "<%s> %s !|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_THE_MESSAGE_WAS_TOO_LONG]);
				return;
			}
		}
	}

	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::NOCHATINTERVAL) == false)
	{
		if (DeFloodCheckInterval(pDcCommand->m_pUser, INTERVAL_CHAT, pDcCommand->m_pUser->m_ui16ChatIntMsgs,
		                         pDcCommand->m_pUser->m_ui64ChatIntMsgsTick, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CHAT_INTERVAL_MESSAGES],
		                         (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_CHAT_INTERVAL_TIME]) == true)
		{
			return;
		}
	}

	if (((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_GAGGED) == User::BIT_GAGGED) == true)
		return;

	void * pQueueItem1 = GlobalDataQueue::m_Ptr->GetLastQueueItem();

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::CHAT_ARRIVAL) == true ||
	        pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	void * pQueueItem = NULL;
	void * pQueueItem2 = GlobalDataQueue::m_Ptr->GetLastQueueItem();

	if (pQueueItem1 != pQueueItem2)
	{
		if (pQueueItem1 == NULL)
		{
			pQueueItem = GlobalDataQueue::m_Ptr->InsertBlankQueueItem(GlobalDataQueue::m_Ptr->GetFirstQueueItem(), GlobalDataQueue::CMD_CHAT);
		}
		else
		{
			pQueueItem = GlobalDataQueue::m_Ptr->InsertBlankQueueItem(pQueueItem1, GlobalDataQueue::CMD_CHAT);
		}

		if (pQueueItem != NULL)
		{
			pDcCommand->m_pUser->m_ui32BoolBits |= User::BIT_CHAT_INSERT;
		}
	}
	else if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_CHAT_INSERT) == User::BIT_CHAT_INSERT)
	{
		pQueueItem = GlobalDataQueue::m_Ptr->InsertBlankQueueItem(pQueueItem1, GlobalDataQueue::CMD_CHAT);
	}

	// PPK ... filtering kick messages
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::KICK) == true)
	{
		if (pDcCommand->m_ui32CommandLen > pDcCommand->m_pUser->m_ui8NickLen + 21u)
		{
			char * pTemp = strchr(pDcCommand->m_sCommand + pDcCommand->m_pUser->m_ui8NickLen + 3, '\n');
			if (pTemp != NULL)
			{
				pTemp[0] = '\0';
			}

			char * pIsKicking = stristr(pDcCommand->m_sCommand + pDcCommand->m_pUser->m_ui8NickLen + 3, "is kicking ");
			if (pIsKicking != NULL)
			{
				char * pBecause = stristr(pIsKicking + 12, " because: ");
				if (pBecause != NULL)
				{
					// PPK ... catch kick message and store for later use in $Kick for tempban reason
					pBecause[0] = '\0';
					User * KickedUser = HashManager::m_Ptr->FindUser(pIsKicking + 11, pBecause - (pIsKicking + 11));
					pBecause[0] = ' ';
					if (KickedUser != NULL)
					{
						// PPK ... valid kick messages for existing user, remove this message from deflood ;)
						if (pDcCommand->m_pUser->m_ui16ChatMsgs != 0)
						{
							pDcCommand->m_pUser->m_ui16ChatMsgs--;
							pDcCommand->m_pUser->m_ui16ChatMsgs2--;
						}
						if (pBecause[10] != '|')
						{
							pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // get rid of the pipe
							KickedUser->SetBuffer(pBecause + 10, pDcCommand->m_ui32CommandLen - (pBecause - pDcCommand->m_sCommand) - 11);
							pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '|'; // add back pipe
						}
					}

					if (pTemp != NULL)
					{
						pTemp[0] = '\n';
					}

					// PPK ... kick messages filtering
					if (SettingManager::m_Ptr->m_bBools[SETBOOL_FILTER_KICK_MESSAGES] == true)
					{
						if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_KICK_MESSAGES_TO_OPS] == true)
						{
							if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_STATUS_MESSAGES_AS_PM] == true)
							{
								int iRet = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "%s $%s", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], pDcCommand->m_sCommand);
								if (iRet > 0)
								{
									GlobalDataQueue::m_Ptr->SingleItemStore(ServerManager::m_pGlobalBuffer, iRet, NULL, 0, GlobalDataQueue::SI_PM2OPS);
								}
							}
							else
							{
								GlobalDataQueue::m_Ptr->AddQueueItem(pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, NULL, 0, GlobalDataQueue::CMD_OPS);
							}
						}
						else
						{
							pDcCommand->m_pUser->SendCharDelayed(pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen);
						}
						return;
					}
				}
			}

			if (pTemp != NULL)
			{
				pTemp[0] = '\n';
			}
		}
	}

	pDcCommand->m_pUser->AddPrcsdCmd(PrcsdUsrCmd::CHAT, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen, reinterpret_cast<User *>(pQueueItem));
#ifdef FLYLINKDC_USE_DB
#ifdef _WITH_SQLITE
	DBSQLite::m_Ptr->IncMessageCount(pDcCommand->m_pUser);
#endif
#endif
}
//---------------------------------------------------------------------------

// $Close nick|
void DcCommands::Close(DcCommand * pDcCommand)
{
	if (ProfileManager::m_Ptr->IsAllowed(pDcCommand->m_pUser, ProfileManager::CLOSE) == false)
	{
		pDcCommand->m_pUser->SendFormat("DcCommands::Close1", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_NOT_ALWD_TO_USE_THIS_CMD]);
		return;
	}

	if (pDcCommand->m_ui32CommandLen < 9)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $Close (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		pDcCommand->m_pUser->Close();
		return;
	}

	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::CLOSE_ARRIVAL) == true || pDcCommand->m_pUser->m_ui8State >= User::STATE_CLOSING)
	{
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

	User *OtherUser = HashManager::m_Ptr->FindUser(pDcCommand->m_sCommand + 7, pDcCommand->m_ui32CommandLen - 8);
	if (OtherUser != NULL)
	{
		// Self-kick
		if (OtherUser == pDcCommand->m_pUser)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Close2", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_CANT_CLOSE_YOURSELF]);
			return;
		}

		if (OtherUser->m_i32Profile != -1 && pDcCommand->m_pUser->m_i32Profile > OtherUser->m_i32Profile)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Close3", true, "<%s> %s %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_NOT_ALLOWED_TO_CLOSE], OtherUser->m_sNick);
			return;
		}

		// disconnect the user
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] User %s (%s) closed by %s", OtherUser->m_sNick, OtherUser->m_sIP, pDcCommand->m_pUser->m_sNick);

		OtherUser->Close();

		if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_STATUS_MESSAGES] == true)
		{
			GlobalDataQueue::m_Ptr->StatusMessageFormat("DcCommands::Close", "<%s> *** %s %s %s %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], OtherUser->m_sIP,
			        LanguageManager::m_Ptr->m_sTexts[LAN_WAS_CLOSED_BY], pDcCommand->m_pUser->m_sNick);
		}

		if (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_STATUS_MESSAGES] == false || ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
		{
			pDcCommand->m_pUser->SendFormat("DcCommands::Close4", true, "<%s> *** %s %s %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], OtherUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], OtherUser->m_sIP, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_CLOSED]);
		}
	}
}
//---------------------------------------------------------------------------

void DcCommands::Unknown(DcCommand * pDcCommand, const bool bMyNick/* = false*/)
{
	m_ui32StatCmdUnknown++;

#ifdef _DBG
	Memo(">>> Unimplemented Cmd " + pUser->Nick + " [" + pUser->IP + "]: " + sData);
#endif

	// if we got unknown command sooner than full login finished
	// PPK ... fixed posibility to send (or flood !!!) hub with unknown command before full login
	// Give him chance with script...
	// if this is unkncwn command and script dont clarify that it's ok, disconnect the user
	if (ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::UNKNOWN_ARRIVAL) == false)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Unknown command from %s (%s) - user closed. (%s)", pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP, pDcCommand->m_sCommand);

		if (bMyNick == true)
		{
			pDcCommand->m_pUser->SendCharDelayed("$Error CTM2HUB|", 15);
		}

		pDcCommand->m_pUser->Close();
	}
}
//---------------------------------------------------------------------------

bool DcCommands::ValidateUserNick(DcCommand * pDcCommand,User * pUser, char * sNick, const size_t szNickLen, const bool ValidateNick)
{
	// illegal characters in nick?
	for (uint32_t ui32i = 0; ui32i < szNickLen; ui32i++)
	{
		switch (sNick[ui32i])
		{
		case ' ':
		case '$':
		case '|':
		{
			pUser->SendFormat("DcCommands::ValidateUserNick1", false, "<%s> %s '%c' ! %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_NICK_CONTAINS_ILLEGAL_CHARACTER], sNick[ui32i], LanguageManager::m_Ptr->m_sTexts[LAN_PLS_CORRECT_IT_AND_GET_BACK_AGAIN]);

//              UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick with bad chars (%s) from %s (%s) - user closed.", Nick, pUser->m_sNick, pUser->m_sIP);

			pUser->Close();
			return false;
		}
		default:
			if ((unsigned char)sNick[ui32i] < 32)
			{
				pUser->SendFormat("DcCommands::ValidateUserNick2", false, "<%s> %s! %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_NICK_CONTAINS_ILLEGAL_WHITE_CHARACTER], LanguageManager::m_Ptr->m_sTexts[LAN_PLS_CORRECT_IT_AND_GET_BACK_AGAIN]);

//                  UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick with white chars (%s) from %s (%s) - user closed.", Nick, pUser->m_sNick, pUser->m_sIP);

				pUser->Close();
				return false;
			}

			continue;
		}
	}

	pUser->SetNick(sNick, (uint8_t)szNickLen);

	// check for reserved nicks
	if (ReservedNicksManager::m_Ptr->CheckReserved(pUser->m_sNick, pUser->m_ui32NickHash) == true)
	{
		pUser->SendFormat("DcCommands::ValidateUserNick3", false, "<%s> %s. %s.|$ValidateDenide %s|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_THE_NICK_IS_RESERVED_FOR_SOMEONE_OTHER], LanguageManager::m_Ptr->m_sTexts[LAN_CHANGE_YOUR_NICK_AND_GET_BACK_AGAIN], sNick);

//      UdpDebug::m_Ptr->BroadcastFormat("[SYS] Reserved nick (%s) from %s (%s) - user closed.", Nick, pUser->m_sNick, pUser->m_sIP);

		pUser->Close();
		return false;
	}

	// PPK ... check if we already have ban for this user
	if (pUser->m_LogInOut.m_pBan != NULL && pUser->m_ui32NickHash == pUser->m_LogInOut.m_pBan->m_ui32NickHash)
	{
		pUser->SendChar(pUser->m_LogInOut.m_pBan->m_sMessage, pUser->m_LogInOut.m_pBan->m_ui32Len);
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Banned user %s (%s) - user closed.", pUser->m_sNick, pUser->m_sIP);

		pUser->Close();
		return false;
	}

	time_t tmAccTime;
	time(&tmAccTime);

	// check for banned nicks
	BanItem * pBan = BanManager::m_Ptr->FindNick(pUser);
	if (pBan != NULL)
	{
		int iMsgLen = GenerateBanMessage(pBan, tmAccTime);
		if (iMsgLen != 0)
		{
			pUser->SendChar(ServerManager::m_pGlobalBuffer, iMsgLen);
		}

		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Banned user %s (%s) - user closed.", pUser->m_sNick, pUser->m_sIP);

		pUser->Close();
		return false;
	}

	int32_t i32Profile = -1;

	// Nick is ok, check for registered nick
	RegUser *Reg = RegManager::m_Ptr->Find(pUser);
	if (Reg != NULL)
	{
		if (SettingManager::m_Ptr->m_bBools[SETBOOL_ADVANCED_PASS_PROTECTION] == true && Reg->m_ui8BadPassCount != 0)
		{
			uint32_t iMinutes2Wait = (uint32_t)pow(2.0, (double)Reg->m_ui8BadPassCount - 1);

			if (tmAccTime < (time_t)(Reg->m_tLastBadPass + (60 * iMinutes2Wait)))
			{
				pUser->SendFormat("DcCommands::ValidateUserNick4", false, "<%s> %s %s %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_LAST_PASS_WAS_WRONG_YOU_NEED_WAIT], formatSecTime((Reg->m_tLastBadPass + (60 * iMinutes2Wait)) - tmAccTime),
				                  LanguageManager::m_Ptr->m_sTexts[LAN_BEFORE_YOU_TRY_AGAIN]);

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] User %s (%s) not allowed to send password (%" PRIu64 ") - user closed.", pUser->m_sNick, pUser->m_sIP, (uint64_t)((Reg->m_tLastBadPass + (60 * iMinutes2Wait)) - tmAccTime));

				pUser->Close();
				return false;
			}
		}

		i32Profile = (int32_t)Reg->m_ui16Profile;
	}

	// PPK ... moved IP ban check here, we need to allow registered users on shared IP to log in if not have banned nick, but only IP.
	if (ProfileManager::m_Ptr->IsProfileAllowed(i32Profile, ProfileManager::ENTERIFIPBAN) == false)
	{
		// PPK ... check if we already have ban for this user
		if (pUser->m_LogInOut.m_pBan != NULL)
		{
			pUser->SendChar(pUser->m_LogInOut.m_pBan->m_sMessage, pUser->m_LogInOut.m_pBan->m_ui32Len);

			// UdpDebug::m_Ptr->BroadcastFormat("[SYS] uBanned user %s (%s) - user closed.", pUser->m_sNick, pUser->m_sIP);

			pUser->Close();
			return false;
		}
	}

	// PPK ... delete user ban if we have it
	if (pUser->m_LogInOut.m_pBan != NULL)
	{
		delete pUser->m_LogInOut.m_pBan;
		pUser->m_LogInOut.m_pBan = NULL;
	}

	// first check for user limit ! PPK ... allow hublist pinger to check hub any time ;)
	if (ProfileManager::m_Ptr->IsProfileAllowed(i32Profile, ProfileManager::ENTERFULLHUB) == false && ((pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == false)
	{
		// user is NOT allowed enter full hub, check for maxClients
		if (ServerManager::m_ui32Joins - ServerManager::m_ui32Parts > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_USERS])
		{
			pUser->SendFormat("DcCommands::ValidateUserNick5", false, "$HubIsFull|<%s> %s. %u %s.|%s", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_THIS_HUB_IS_FULL], ServerManager::m_ui32Logged, LanguageManager::m_Ptr->m_sTexts[LAN_USERS_ONLINE_LWR],
			                  (SettingManager::m_Ptr->m_bBools[SETBOOL_REDIRECT_WHEN_HUB_FULL] == true && SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_REDIRECT_ADDRESS] != NULL) ? SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_REDIRECT_ADDRESS] : "");
//          UdpDebug::m_Ptr->BroadcastFormat("[SYS] Hub full for %s (%s) - user closed.", pUser->m_sNick, pUser->m_sIP);

			pUser->Close();
			return false;
		}
	}

	// Check for maximum connections from same IP
	if (ProfileManager::m_Ptr->IsProfileAllowed(i32Profile, ProfileManager::NOUSRSAMEIP) == false)
	{
		uint32_t ui32Count = HashManager::m_Ptr->GetUserIpCount(pUser);
		if (ui32Count >= (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_CONN_SAME_IP])
		{
			pUser->SendFormat("DcCommands::ValidateUserNick6", false, "<%s> %s.|%s", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SORRY_ALREADY_MAX_IP_CONNS],
			                  (SettingManager::m_Ptr->m_bBools[SETBOOL_REDIRECT_WHEN_HUB_FULL] == true && SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_REDIRECT_ADDRESS] != NULL) ? SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_REDIRECT_ADDRESS] : "");

			int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "[SYS] Max connections from same IP (%u) for %s (%s) - user closed. ", ui32Count, pUser->m_sNick, pUser->m_sIP);
			if (iMsgLen <= 0)
			{
				pUser->Close();
				return false;
			}

			//UdpDebug::m_Ptr->Broadcast(ServerManager::m_pGlobalBuffer, iMsgLen);
			string tmp(ServerManager::m_pGlobalBuffer, iMsgLen);

			User * cur = NULL,
			       * nxt = HashManager::m_Ptr->FindUser(pUser->m_ui128IpHash);

			while (nxt != NULL)
			{
				cur = nxt;
				nxt = cur->m_pHashIpTableNext;

				tmp += " " + string(cur->m_sNick, cur->m_ui8NickLen);
			}

			UdpDebug::m_Ptr->Broadcast(tmp.c_str(), tmp.size());

			pUser->Close();
			return false;
		}
	}

	// Check for reconnect time
	if (ProfileManager::m_Ptr->IsProfileAllowed(i32Profile, ProfileManager::NORECONNTIME) == false && Users::m_Ptr->CheckRecTime(pUser) == true)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Fast reconnect from %s (%s) - user closed.", pUser->m_sNick, pUser->m_sIP);

		pUser->Close();
		return false;
	}

	pUser->m_ui8Country = IpP2Country::m_Ptr->Find(pUser->m_ui128IpHash);

	// check for nick in userlist. If taken, check for dupe's socket state
	// if still active, send $ValidateDenide and close()
	User *OtherUser = HashManager::m_Ptr->FindUser(pUser);

	if (OtherUser != NULL)
	{
		if (OtherUser->m_ui8State < User::STATE_CLOSING)
		{
			// check for socket error, or if user closed connection
			int iRet = recv(OtherUser->m_Socket, ServerManager::m_pGlobalBuffer, 16, MSG_PEEK);
	 	    //GlobalDataQueue::m_Ptr->PrometheusRecvBytes("dccommand",recvlen);

			// if socket error or user closed connection then allow new user to log in
#ifdef _WIN32
			if ((iRet == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) || iRet == 0)
			{
#else
			if ((iRet == -1 && errno != EAGAIN) || iRet == 0)
			{
#endif
				OtherUser->m_ui32BoolBits |= User::BIT_ERROR;

				UdpDebug::m_Ptr->BroadcastFormat("[SYS] Detected clone of yourself, byebye! Nick %s (%s) - user closed. Please close the second DC++ client! ", OtherUser->m_sNick, OtherUser->m_sIP);

				OtherUser->Close();
				return false;
			}
			else
			{

				if (Reg == NULL)
				{
					// alex82 ... �������� ValidateDenideArrival
					ScriptManager::m_Ptr->Arrival(pDcCommand, ScriptManager::VALIDATE_DENIDE_ARRIVAL);
#ifdef FLYLINKDC_USE_REMOVE_CLONE // ���� ��������. ��������
					if (// TODO OtherUser->m_ui64SharedSize == pUser->m_ui64SharedSize &&
					    strcmp(OtherUser->m_sNick, pUser->m_sNick) == 0 && strcmp(OtherUser->m_sIP, pUser->m_sIP) == 0) //[+] FlylinkDC++
					{
						OtherUser->SendFormat("DcCommands::ValidateUserNick8", false, "Detected clone of yourself, byebye!Nick %s(%s) - user closed.Please close the second DC++ client!|",
						                      SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC],
						                      sNick);
						OtherUser->m_ui32BoolBits |= User::BIT_ERROR;
						UdpDebug::m_Ptr->BroadcastFormat("[SYS] Remove clone user nick %s (%s) - user closed.", OtherUser->m_sNick, OtherUser->m_sIP);
						OtherUser->Close();
						return ValidateUserNickFinally(Reg == NULL, pUser, szNickLen, ValidateNick); // [+] FlylinkDC++
					}
					else
#endif // FLYLINKDC_USE_REMOVE_CLONE 
					{
						pUser->SendFormat("DcCommands::ValidateUserNick7", false, "$ValidateDenide %s|", sNick);

						if (strcmp(OtherUser->m_sIP, pUser->m_sIP) != 0 || strcmp(OtherUser->m_sNick, pUser->m_sNick) != 0)
						{
							UdpDebug::m_Ptr->BroadcastFormat("[SYS] Nick taken [%s (%s)] %s (%s) - user closed.", OtherUser->m_sNick, OtherUser->m_sIP, pUser->m_sNick, pUser->m_sIP);
						}

						pUser->Close();
						return false;
					}
				}
				else
				{
					// PPK ... addition for registered users, kill your own ghost >:-]
					pUser->m_ui8State = User::STATE_VERSION_OR_MYPASS;
					pUser->m_ui32BoolBits |= User::BIT_WAITING_FOR_PASS;
					pUser->AddPrcsdCmd(PrcsdUsrCmd::GETPASS, NULL, 0, NULL);
					return true;
				}
			}
		}
	}
	return ValidateUserNickFinally(Reg == NULL, pUser, szNickLen, ValidateNick); // [+] FlylinkDC++
}
// [+] FlylinkDC++
//---------------------------------------------------------------------------
bool DcCommands::ValidateUserNickFinally(bool pIsNotReg, User * pUser, const size_t szNickLen, const bool ValidateNick)
{
	if (pIsNotReg)
	{
		// user is NOT registered

		// nick length check
		if ((SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_NICK_LEN] != 0 && szNickLen < (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MIN_NICK_LEN]) ||
		        (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_NICK_LEN] != 0 && szNickLen > (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_NICK_LEN]))
		{
			pUser->SendChar(SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_NICK_LIMIT_MSG], SettingManager::m_Ptr->m_ui16PreTextsLens[SettingManager::SETPRETXT_NICK_LIMIT_MSG]);
			// UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad nick length (%d) from %s (%s) - user closed.", (int)szNickLen, pUser->m_sNick, pUser->m_sIP);

			pUser->Close();
			return false;
		}

		if (SettingManager::m_Ptr->m_bBools[SETBOOL_REG_ONLY] == true && ((pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == false)
		{
			pUser->SendChar(SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_REG_ONLY_MSG], SettingManager::m_Ptr->m_ui16PreTextsLens[SettingManager::SETPRETXT_REG_ONLY_MSG]);

//          UdpDebug::m_Ptr->BroadcastFormat("[SYS] Hub for reg only %s (%s) - user closed.", pUser->m_sNick, pUser->m_sIP);

			pUser->Close();
			return false;
		}
		else
		{
			// hub is public, proceed to Hello
			if (HashManager::m_Ptr->Add(pUser) == false)
			{
				return false;
			}

			pUser->m_ui32BoolBits |= User::BIT_HASHED;

			if (ValidateNick == true)
			{
				pUser->m_ui8State = User::STATE_VERSION_OR_MYPASS; // waiting for $Version
				pUser->AddPrcsdCmd(PrcsdUsrCmd::LOGINHELLO, NULL, 0, NULL);
			}
			return true;
		}
	}
	else
	{
		// user is registered, wait for password
		if (HashManager::m_Ptr->Add(pUser) == false)
		{
			return false;
		}

		pUser->m_ui32BoolBits |= User::BIT_HASHED;
		pUser->m_ui8State = User::STATE_VERSION_OR_MYPASS;
		pUser->m_ui32BoolBits |= User::BIT_WAITING_FOR_PASS;
		pUser->AddPrcsdCmd(PrcsdUsrCmd::GETPASS, NULL, 0, NULL);
		return true;
	}
	return false;
}
//---------------------------------------------------------------------------

DcCommands::PassBf * DcCommands::Find(const uint8_t * ui128IpHash)
{
	PassBf * cur = NULL,
	         * next = m_pPasswdBfCheck;

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

		if (memcmp(cur->m_ui128IpHash, ui128IpHash, 16) == 0)
		{
			return cur;
		}
	}
	return NULL;
}
//---------------------------------------------------------------------------

void DcCommands::Remove(PassBf * pPassBfItem)
{
	if (pPassBfItem->m_pPrev == NULL)
	{
		if (pPassBfItem->m_pNext == NULL)
		{
			m_pPasswdBfCheck = NULL;
		}
		else
		{
			pPassBfItem->m_pNext->m_pPrev = NULL;
			m_pPasswdBfCheck = pPassBfItem->m_pNext;
		}
	}
	else if (pPassBfItem->m_pNext == NULL)
	{
		pPassBfItem->m_pPrev->m_pNext = NULL;
	}
	else
	{
		pPassBfItem->m_pPrev->m_pNext = pPassBfItem->m_pNext;
		pPassBfItem->m_pNext->m_pPrev = pPassBfItem->m_pPrev;
	}
	delete pPassBfItem;
}
//---------------------------------------------------------------------------

void DcCommands::ProcessCmds(User * pUser)
{
	pUser->m_ui32BoolBits &= ~User::BIT_CHAT_INSERT;

	PrcsdUsrCmd * cur = NULL,
	              * next = pUser->m_pCmdStrt;

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

		switch (cur->m_ui8Type)
		{
		case PrcsdUsrCmd::SUPPORTS:
		{
			memcpy(ServerManager::m_pGlobalBuffer, "$Supports", 9);
			uint32_t iSupportsLen = 9;

			// PPK ... why dc++ have that 0 on end ? that was not in original documentation.. stupid duck...
			if (((pUser->m_ui32SupportBits & User::SUPPORTBIT_ZPIPE0) == User::SUPPORTBIT_ZPIPE0) == true)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " ZPipe0", 7);
				iSupportsLen += 7;
			}
			else if (((pUser->m_ui32SupportBits & User::SUPPORTBIT_ZPIPE) == User::SUPPORTBIT_ZPIPE) == true)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " ZPipe", 6);
				iSupportsLen += 6;
			}

			// PPK ... yes yes yes finally QuickList support in PtokaX !!! ;))
			if ((pUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " QuickList", 10);
				iSupportsLen += 10;
			}
			else if ((pUser->m_ui32SupportBits & User::SUPPORTBIT_NOHELLO) == User::SUPPORTBIT_NOHELLO)
			{
				// PPK ... Hmmm Client not really need it, but for now send it ;-)
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " NoHello", 8);
				iSupportsLen += 8;
			}
			else if ((pUser->m_ui32SupportBits & User::SUPPORTBIT_NOGETINFO) == User::SUPPORTBIT_NOGETINFO)
			{
				// PPK ... if client support NoHello automatically supports NoGetINFO another badwith wasting !
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " NoGetINFO", 10);
				iSupportsLen += 10;
			}
#ifdef USE_FLYLINKDC_EXT_JSON
			if (pUser->isSupportExtJSON())
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " ExtJSON2", 9);
				iSupportsLen += 9;
			}
#endif
			if ((pUser->m_ui32SupportBits & User::SUPPORTBIT_HUBURL) == User::SUPPORTBIT_HUBURL)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " HubURL", 7);
				iSupportsLen += 7;
			}

			if ((pUser->m_ui32SupportBits & User::SUPPORTBIT_IP64) == User::SUPPORTBIT_IP64)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " IP64", 5);
				iSupportsLen += 5;
			}

			if (((pUser->m_ui32SupportBits & User::SUPPORTBIT_IPV4) == User::SUPPORTBIT_IPV4) && ((pUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6))
			{
				// Only client connected with IPv6 sending this, so only that client is getting reply
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " IPv4", 5);
				iSupportsLen += 5;
			}

			if ((pUser->m_ui32SupportBits & User::SUPPORTBIT_USERCOMMAND) == User::SUPPORTBIT_USERCOMMAND)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " UserCommand", 12);
				iSupportsLen += 12;
			}

			if ((pUser->m_ui32SupportBits & User::SUPPORTBIT_USERIP2) == User::SUPPORTBIT_USERIP2 && ((pUser->m_ui32BoolBits & User::BIT_QUACK_SUPPORTS) == User::BIT_QUACK_SUPPORTS) == false)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " UserIP2", 8);
				iSupportsLen += 8;
			}

			if ((pUser->m_ui32SupportBits & User::SUPPORTBIT_TLS2) == User::SUPPORTBIT_TLS2)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " TLS2", 5);
				iSupportsLen += 5;
			}

			if ((pUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER)
			{
				memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, " BotINFO HubINFO", 16);
				iSupportsLen += 16;
			}

			memcpy(ServerManager::m_pGlobalBuffer + iSupportsLen, "|\0", 2);
			pUser->SendCharDelayed(ServerManager::m_pGlobalBuffer, iSupportsLen + 1);
			break;
		}
		case PrcsdUsrCmd::LOGINHELLO:
		{
			pUser->SendFormat("DcCommands::ProcessCmds", true, "$Hello %s|", pUser->m_sNick);
			break;
		}
		case PrcsdUsrCmd::GETPASS:
		{
			uint32_t ui32Len = 9;
			pUser->SendCharDelayed("$GetPass|", ui32Len); // query user for password
			break;
		}
		case PrcsdUsrCmd::CHAT:
		{
			// find chat message data
			char *sBuff = cur->m_sCommand + pUser->m_ui8NickLen + 3;

			// non-command chat msg
			bool bNonChat = false;
			for (uint8_t ui8i = 0; ui8i < (uint8_t)SettingManager::m_Ptr->m_ui16TextsLens[SETTXT_CHAT_COMMANDS_PREFIXES]; ui8i++)
			{
				if (sBuff[0] == SettingManager::m_Ptr->m_sTexts[SETTXT_CHAT_COMMANDS_PREFIXES][ui8i])
				{
					bNonChat = true;
					break;
				}
			}

			if (bNonChat == true)
			{
				// text files...
				if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_TEXT_FILES] == true)
				{
					cur->m_sCommand[cur->m_ui32Len - 1] = '\0'; // get rid of the pipe

					if (TextFilesManager::m_Ptr->ProcessTextFilesCmd(pUser, sBuff + 1))
					{
						break;
					}

					cur->m_sCommand[cur->m_ui32Len - 1] = '|'; // add back pipe
				}

				// built-in commands
				// alex82 ... ��������� ����������� ����� �������
				if (cur->m_ui32Len - pUser->m_ui8NickLen >= 6)
				{
					if (HubCommands::DoCommand(pUser, sBuff - (pUser->m_ui8NickLen - 1), cur->m_ui32Len))
						break;

					cur->m_sCommand[cur->m_ui32Len - 1] = '|'; // add back pipe
				}
			}

			// everything's ok, let's chat
			Users::m_Ptr->SendChat2All(pUser, cur->m_sCommand, cur->m_ui32Len, cur->m_pPtr);

			break;
		}
		case PrcsdUsrCmd::TO_OP_CHAT:
		{
			GlobalDataQueue::m_Ptr->SingleItemStore(cur->m_sCommand, cur->m_ui32Len, pUser, 0, GlobalDataQueue::SI_OPCHAT);
			break;
		}
		}

		safe_free(cur->m_sCommand);

		delete cur;
	}

	pUser->m_pCmdStrt = NULL;
	pUser->m_pCmdEnd = NULL;

	if ((pUser->m_ui32BoolBits & User::BIT_PRCSD_MYINFO) == User::BIT_PRCSD_MYINFO)
	{
		pUser->m_ui32BoolBits &= ~User::BIT_PRCSD_MYINFO;

		if (((pUser->m_ui32BoolBits & User::BIT_HAVE_BADTAG) == User::BIT_HAVE_BADTAG) == true)
		{
			pUser->HasSuspiciousTag();
		}
		// alex82 ... HideUser / ������� �����
		if (((pUser->m_ui32InfoBits & User::INFOBIT_HIDDEN) == User::INFOBIT_HIDDEN) == false)
		{
			if (SettingManager::m_Ptr->m_ui8FullMyINFOOption == 0)
			{
				if (pUser->GenerateMyInfoLong() == false)
				{
					return;
				}

				Users::m_Ptr->Add2MyInfosTag(pUser);

				if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY] == 0 || ServerManager::m_ui64ActualTick > ((60 * SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY]) + pUser->m_ui64LastMyINFOSendTick))
				{
					GlobalDataQueue::m_Ptr->AddQueueItem(pUser->m_sMyInfoLong, pUser->m_ui16MyInfoLongLen, NULL, 0, GlobalDataQueue::CMD_MYINFO);
					pUser->m_ui64LastMyINFOSendTick = ServerManager::m_ui64ActualTick;
				}
				else
				{
					GlobalDataQueue::m_Ptr->AddQueueItem(pUser->m_sMyInfoLong, pUser->m_ui16MyInfoLongLen, NULL, 0, GlobalDataQueue::CMD_OPS);
				}
				return;
			}
			else if (SettingManager::m_Ptr->m_ui8FullMyINFOOption == 2)
			{
				if (pUser->GenerateMyInfoShort() == false)
				{
					return;
				}

				Users::m_Ptr->Add2MyInfos(pUser);

				if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY] == 0 || ServerManager::m_ui64ActualTick > ((60 * SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY]) + pUser->m_ui64LastMyINFOSendTick))
				{
					GlobalDataQueue::m_Ptr->AddQueueItem(pUser->m_sMyInfoShort, pUser->m_ui16MyInfoShortLen, NULL, 0, GlobalDataQueue::CMD_MYINFO);
					pUser->m_ui64LastMyINFOSendTick = ServerManager::m_ui64ActualTick;
				}
				else
				{
					GlobalDataQueue::m_Ptr->AddQueueItem(pUser->m_sMyInfoShort, pUser->m_ui16MyInfoShortLen, NULL, 0, GlobalDataQueue::CMD_OPS);
				}
				return;
			}

			if (pUser->GenerateMyInfoLong() == false)
			{
				return;
			}

			Users::m_Ptr->Add2MyInfosTag(pUser);

			char * sShortMyINFO = NULL;
			size_t szShortMyINFOLen = 0;

			if (pUser->GenerateMyInfoShort() == true)
			{
				Users::m_Ptr->Add2MyInfos(pUser);

				if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY] == 0 || ServerManager::m_ui64ActualTick > ((60 * SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY]) + pUser->m_ui64LastMyINFOSendTick))
				{
					sShortMyINFO = pUser->m_sMyInfoShort;
					szShortMyINFOLen = pUser->m_ui16MyInfoShortLen;
					pUser->m_ui64LastMyINFOSendTick = ServerManager::m_ui64ActualTick;
				}
			}

			GlobalDataQueue::m_Ptr->AddQueueItem(sShortMyINFO, szShortMyINFOLen, pUser->m_sMyInfoLong, pUser->m_ui16MyInfoLongLen, GlobalDataQueue::CMD_MYINFO);

#ifdef USE_FLYLINKDC_EXT_JSON
			if ((pUser->m_ui32BoolBits & User::BIT_PRCSD_EXT_JSON) == User::BIT_PRCSD_EXT_JSON)
			{
				pUser->m_ui32BoolBits &= ~User::BIT_PRCSD_EXT_JSON;
				// TODO ExtJSON - ????? Users::m_Ptr->Add2MyInfosTag(pUser);
				if (pUser->isSupportExtJSON())
				{
					if (pUser->m_user_ext_info)
					{
						const std::string l_ext_json_info = pUser->m_user_ext_info->GetExtJSONCommand();
						if (!l_ext_json_info.empty())
						{
							// TODO ExtJSON if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY] == 0 || ServerManager::m_ui64ActualTick > ((60 * SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY]) + pUser->getLastExtJSONSendTick()))
							if (pUser->getLastExtJSONSendTick() || ServerManager::m_ui64ActualTick > pUser->getLastExtJSONSendTick() + 60)
							{
								GlobalDataQueue::m_Ptr->AddQueueItem(l_ext_json_info.c_str(), l_ext_json_info.size(), NULL, 0, GlobalDataQueue::CMD_EXTJSON);
								pUser->setLastExtJSONSendTick(ServerManager::m_ui64ActualTick);
							}
							else
							{
								GlobalDataQueue::m_Ptr->AddQueueItem(l_ext_json_info.c_str(), l_ext_json_info.size(), NULL, 0, GlobalDataQueue::CMD_OPS);
							}
						}
					}
				}
			}
#endif // USE_FLYLINKDC_EXT_JSON    
		}   // HideUser
	}   // MyINFO
}
//---------------------------------------------------------------------------

static bool CheckPort(char * sData, char cPortEnd)
{
	for (uint8_t ui8i = 0; ui8i < 6; ui8i++)
	{
		if (isdigit(sData[ui8i]) != 0)
		{
			continue;
			// alex82 ... NAT Traversal fix by Pavel Pimenov
		}
		else if (sData[ui8i] == cPortEnd ||
		         (cPortEnd == '|' && sData[ui8i] == 'S' && sData[ui8i + 1] == cPortEnd) ||
		         (sData[ui8i] == 'N' && (sData[ui8i + 1] == 'S' || sData[ui8i + 1] == ' ')) ||
		         (sData[ui8i] == 'R' && (sData[ui8i + 1] == 'S' || sData[ui8i + 1] == '|')))
		{
			const char cEnd = sData[ui8i];
			sData[ui8i] = '\0';

			const int iPort = atoi(sData);
			if (ui8i != 0 && iPort > 0 && iPort < 65536)
			{
				sData[ui8i] = cEnd;

				return false;
			}
			else
			{
				sData[ui8i] = cEnd;
			}
		}

		break;
	}

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

void DcCommands::MyNick(DcCommand * pDcCommand)
{
	if ((pDcCommand->m_pUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] IPv6 $MyNick (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		Unknown(pDcCommand, true);
		return;
	}

	if (pDcCommand->m_ui32CommandLen < 10)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Short $MyNick (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		Unknown(pDcCommand, true);
		return;
	}

	pDcCommand->m_sCommand[pDcCommand->m_ui32CommandLen - 1] = '\0'; // cutoff pipe

	User * pOtherUser = HashManager::m_Ptr->FindUser(pDcCommand->m_sCommand + 8, pDcCommand->m_ui32CommandLen - 9);

	if (pOtherUser == NULL || pOtherUser->m_ui8State != User::STATE_IPV4_CHECK)
	{
		UdpDebug::m_Ptr->BroadcastFormat("[SYS] Bad $MyNick (%s) from %s (%s) - user closed.", pDcCommand->m_sCommand, pDcCommand->m_pUser->m_sNick, pDcCommand->m_pUser->m_sIP);

		Unknown(pDcCommand, true);
		return;
	}

	strncpy(pOtherUser->m_sIPv4, pDcCommand->m_pUser->m_sIP,sizeof(pOtherUser->m_sIPv4));
	pOtherUser->m_sIPv4[sizeof(pOtherUser->m_sIPv4)-1] = 0;
	pOtherUser->m_ui8IPv4Len = pDcCommand->m_pUser->m_ui8IpLen;
	pOtherUser->m_ui32BoolBits |= User::BIT_IPV4;

	pOtherUser->m_ui8State = User::STATE_ADDME;

	pDcCommand->m_pUser->Close();
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

uint16_t DcCommands::CheckAndGetPort(char * pPort, const uint8_t ui8PortLen, uint32_t &ui32PortLen)
{
	uint8_t ui8Index = ui8PortLen - 1;
	while (true)
	{
		if (pPort[ui8Index] == ':')
		{
			// We have something which looks like port.. return values
			ui32PortLen = (ui8PortLen - ui8Index) - 1;
			return (uint16_t)atoi((pPort + ui8Index) + 1);
		}
		else if (isdigit(pPort[ui8Index]) == 0)
		{
			// It is not : and it is not number... this port is not valid
			return 0;
		}

		if (ui8Index == 0)
		{
			break;
		}

		ui8Index--;
	}

	// Valid port not found
	return 0;
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void DcCommands::SendIPFixedMsg(User * pUser, char * pBadIP, char * pRealIP)
{
	if ((pUser->m_ui32BoolBits & User::BIT_WARNED_WRONG_IP) == User::BIT_WARNED_WRONG_IP)
	{
		return;
	}

	pUser->SendFormat("DcCommands::SendIPFixedMsg", true, "<%s> %s '%s' %s %s !|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOUR_CLIENT_SEND_INCORRECT_IP], pBadIP,
	                  LanguageManager::m_Ptr->m_sTexts[LAN_IN_COMMAND_HUB_REPLACED_IT_WITH_YOUR_REAL_IP], pRealIP);

	pUser->m_ui32BoolBits |= User::BIT_WARNED_WRONG_IP;
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

PrcsdUsrCmd * DcCommands::AddSearch(User * pUser, PrcsdUsrCmd * pCmdSearch, char * sSearch, const size_t szLen, const bool bActive)
{
	if (pCmdSearch != NULL)
	{
		char * pOldBuf = pCmdSearch->m_sCommand;
		pCmdSearch->m_sCommand = (char *)realloc(pOldBuf, pCmdSearch->m_ui32Len + szLen + 1);
		if (pCmdSearch->m_sCommand == NULL)
		{
			pCmdSearch->m_sCommand = pOldBuf;
			pUser->m_ui32BoolBits |= User::BIT_ERROR;
			pUser->Close();

			AppendDebugLogFormat("[MEM] Cannot reallocate %zu bytes for DcCommands::AddSearch1\n", pCmdSearch->m_ui32Len+szLen+1);

			return pCmdSearch;
		}
		memcpy(pCmdSearch->m_sCommand + pCmdSearch->m_ui32Len, sSearch, szLen);
		pCmdSearch->m_ui32Len += (uint32_t)szLen;
		pCmdSearch->m_sCommand[pCmdSearch->m_ui32Len] = '\0';

		if (bActive == true)
		{
			Users::m_Ptr->m_ui16ActSearchs++;
		}
		else
		{
			Users::m_Ptr->m_ui16PasSearchs++;
		}
	}
	else
	{
		pCmdSearch = new (std::nothrow) PrcsdUsrCmd();
		if (pCmdSearch == NULL)
		{
			pUser->m_ui32BoolBits |= User::BIT_ERROR;
			pUser->Close();

			AppendDebugLog("%s - [MEM] Cannot allocate new pCmdSearch in DcCommands::AddSearch1\n");
			return pCmdSearch;
		}

		pCmdSearch->m_sCommand = (char *)malloc(szLen + 1);
		if (pCmdSearch->m_sCommand == NULL)
		{
			delete pCmdSearch;

			pUser->m_ui32BoolBits |= User::BIT_ERROR;
			pUser->Close();

			AppendDebugLogFormat("[MEM] Cannot allocate %zu bytes for DcCommands::Search5\n", szLen+1);

			return NULL;
		}

		memcpy(pCmdSearch->m_sCommand, sSearch, szLen);
		pCmdSearch->m_sCommand[szLen] = '\0';

		pCmdSearch->m_ui32Len = (uint32_t)szLen;

		if (bActive == true)
		{
			Users::m_Ptr->m_ui16ActSearchs++;
		}
		else
		{
			Users::m_Ptr->m_ui16PasSearchs++;
		}
	}

	return pCmdSearch;
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

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

V1065 Expression can be simplified, check 'ui32IpPortLen' and similar operands.

V1065 Expression can be simplified, check 'ui32IpPortLen' and similar operands.

V1065 Expression can be simplified, check 'iAfterCmd' and similar operands.

V1065 Expression can be simplified, check 'ui32IpPortLen' and similar operands.

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

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

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

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

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

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

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

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

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

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

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

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