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

 * 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 "TextFileManager.h"
//---------------------------------------------------------------------------
#include "ServerManager.h"
#include "SettingManager.h"
#include "User.h"
#include "utility.h"
//---------------------------------------------------------------------------
#ifdef _WIN32
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
TextFilesManager * TextFilesManager::m_Ptr = NULL;
//---------------------------------------------------------------------------

TextFilesManager::TextFile::TextFile() : m_pPrev(NULL), m_pNext(NULL), m_sCommand(NULL), m_sText(NULL)
{
	// ...
}
//---------------------------------------------------------------------------

TextFilesManager::TextFile::~TextFile()
{
	free(m_sCommand);
	free(m_sText);
}
//---------------------------------------------------------------------------

TextFilesManager::TextFilesManager() : m_pTextFiles(NULL)
{
	// ...
}
//---------------------------------------------------------------------------

TextFilesManager::~TextFilesManager()
{
	TextFile * cur = NULL,
	           * next = m_pTextFiles;

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

		delete cur;
	}
}
//---------------------------------------------------------------------------

bool TextFilesManager::ProcessTextFilesCmd(User * pUser, char * sCommand, const bool bFromPM/* = false*/) const
{
	TextFile * cur = NULL,
	           * next = m_pTextFiles;

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

		if (strcasecmp(cur->m_sCommand, sCommand) == 0)
		{
			bool bInPM = (SettingManager::m_Ptr->m_bBools[SETBOOL_SEND_TEXT_FILES_AS_PM] == true || bFromPM);
			size_t szHubSecLen = (size_t)SettingManager::m_Ptr->m_ui16PreTextsLens[SettingManager::SETPRETXT_HUB_SEC];
			size_t szChatLen = 0;

			// PPK ... to chat or to PM ???
			if (bInPM == true)
			{
				szChatLen = 18 + pUser->m_ui8NickLen + (2 * szHubSecLen) + strlen(cur->m_sText);
			}
			else
			{
				szChatLen = 4 + szHubSecLen + strlen(cur->m_sText);
			}

			char * sMSG = (char *)malloc(szChatLen);
			if (sMSG == NULL)
			{
				AppendDebugLogFormat("[MEM] Cannot allocate %zu bytes for sMsg in TextFilesManager::ProcessTextFilesCmd\n", szChatLen);

				return true;
			}

			if (bInPM == true)
			{
				int iRet = snprintf(sMSG, szChatLen, "$To: %s From: %s $<%s> %s", pUser->m_sNick, SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], cur->m_sText);
				if (iRet <= 0)
				{
					free(sMSG);
					return true;
				}
			}
			else
			{
				int iRet = snprintf(sMSG, szChatLen, "<%s> %s", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], cur->m_sText);
				if (iRet <= 0)
				{
					free(sMSG);
					return true;
				}
			}

			pUser->SendCharDelayed(sMSG, szChatLen - 1);

			free(sMSG);

			return true;
		}
	}

	return false;
}
//---------------------------------------------------------------------------

void TextFilesManager::RefreshTextFiles()
{
	if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_TEXT_FILES] == false)
		return;

	TextFile * cur = NULL,
	           * next = m_pTextFiles;

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

		delete cur;
	}

	m_pTextFiles = NULL;

#ifdef _WIN32
	struct _finddata_t textfile;
	intptr_t hFile = _findfirst((ServerManager::m_sPath + "\\texts\\*.txt").c_str(), &textfile);

	if (hFile != -1)
	{
		do
		{
			if ((textfile.attrib & _A_SUBDIR) != 0 ||
			        stricmp(textfile.name + (strlen(textfile.name) - 4), ".txt") != 0)
			{
				continue;
			}

			FILE *f = fopen((ServerManager::m_sPath + "\\texts\\" + textfile.name).c_str(), "rb");
			if (f != NULL)
			{
				if (textfile.size != 0)
				{
					TextFile * pNewTxtFile = new (std::nothrow) TextFile();
					if (pNewTxtFile == NULL)
					{
						AppendDebugLog("%s - [MEM] Cannot allocate pNewTxtFile in TextFilesManager::RefreshTextFiles\n");

						fclose(f);
						_findclose(hFile);

						return;
					}

					pNewTxtFile->m_sText = (char *)malloc(textfile.size + 2);

					if (pNewTxtFile->m_sText == NULL)
					{
						AppendDebugLogFormat("[MEM] Cannot allocate %" PRIu64 " bytes for m_sText in TextFilesManager::RefreshTextFiles\n", (uint64_t)(textfile.size + 2));

						fclose(f);
						_findclose(hFile);

						delete pNewTxtFile;

						return;
					}

					size_t size = fread(pNewTxtFile->m_sText, 1, textfile.size, f);

					pNewTxtFile->m_sText[size] = '|';
					pNewTxtFile->m_sText[size + 1] = '\0';

					size_t szFileName = strlen(textfile.name)-4;
					pNewTxtFile->m_sCommand = (char *)malloc(szFileName+1);
					if (pNewTxtFile->m_sCommand == NULL)
					{
						AppendDebugLogFormat("[MEM] Cannot allocate %zu bytes for m_sCommand in TextFilesManager::RefreshTextFiles\n", szFileName+1);

						fclose(f);
						_findclose(hFile);

						delete pNewTxtFile;

						return;
					}

					memcpy(pNewTxtFile->m_sCommand, textfile.name, szFileName);
					pNewTxtFile->m_sCommand[szFileName] = '\0';

					pNewTxtFile->m_pPrev = NULL;

					if (m_pTextFiles == NULL)
					{
						pNewTxtFile->m_pNext = NULL;
					}
					else
					{
						m_pTextFiles->m_pPrev = pNewTxtFile;
						pNewTxtFile->m_pNext = m_pTextFiles;
					}

					m_pTextFiles = pNewTxtFile;
				}

				fclose(f);
			}
		}
		while (_findnext(hFile, &textfile) == 0);

		_findclose(hFile);
	}
#else
	string txtdir = ServerManager::m_sPath + "/texts/";

	DIR * p_txtdir = opendir(txtdir.c_str());

	if (p_txtdir == NULL)
	{
		return;
	}

	struct dirent * p_dirent;
	struct stat s_buf;

	while ((p_dirent = readdir(p_txtdir)) != NULL)
	{
		string txtfile = txtdir + p_dirent->d_name;

		if (stat(txtfile.c_str(), &s_buf) != 0 ||
		        (s_buf.st_mode & S_IFDIR) != 0 ||
		        strcasecmp(p_dirent->d_name + (strlen(p_dirent->d_name) - 4), ".txt") != 0)
		{
			continue;
		}

		FILE *f = fopen(txtfile.c_str(), "rb");
		if (f != NULL)
		{
			if (s_buf.st_size != 0)
			{
				TextFile * pNewTxtFile = new (std::nothrow) TextFile();
				if (pNewTxtFile == NULL)
				{
					AppendDebugLog("%s - [MEM] Cannot allocate pNewTxtFile in TextFilesManager::RefreshTextFiles1\n");

					fclose(f);
					closedir(p_txtdir);

					return;
				}

				pNewTxtFile->m_sText = (char *)malloc(s_buf.st_size + 2);
				if (pNewTxtFile->m_sText == NULL)
				{
					AppendDebugLogFormat("[MEM] Cannot allocate %" PRIu64 " bytes for m_sText in TextFilesManager::RefreshTextFiles\n", (uint64_t)(s_buf.st_size + 2));

					fclose(f);
					closedir(p_txtdir);

					delete pNewTxtFile;

					return;
				}
				size_t size = fread(pNewTxtFile->m_sText, 1, s_buf.st_size, f);
				pNewTxtFile->m_sText[size] = '|';
				pNewTxtFile->m_sText[size + 1] = '\0';

				size_t szFileName = strlen(p_dirent->d_name)-4;
				pNewTxtFile->m_sCommand = (char *)malloc(szFileName+1);
				if (pNewTxtFile->m_sCommand == NULL)
				{
					AppendDebugLogFormat("[MEM] Cannot allocate %zu bytes for m_sCommand in TextFilesManager::RefreshTextFiles\n", szFileName+1);

					fclose(f);
					closedir(p_txtdir);

					delete pNewTxtFile;

					return;
				}

				memcpy(pNewTxtFile->m_sCommand, p_dirent->d_name, szFileName);
				pNewTxtFile->m_sCommand[szFileName] = '\0';

				pNewTxtFile->m_pPrev = NULL;

				if (m_pTextFiles == NULL)
				{
					pNewTxtFile->m_pNext = NULL;
				}
				else
				{
					m_pTextFiles->m_pPrev = pNewTxtFile;
					pNewTxtFile->m_pNext = m_pTextFiles;
				}

				m_pTextFiles = pNewTxtFile;
			}

			fclose(f);
		}
	}

	closedir(p_txtdir);
#endif
}
//---------------------------------------------------------------------------

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