From f60495a029c54358f82956482fe203fe2b7b5b23 Mon Sep 17 00:00:00 2001 From: SomeDude Date: Fri, 8 Feb 2008 17:41:00 +0100 Subject: [PATCH] version 0.1.10 --- CMakeLists.txt | 10 +- include/fmsdaemon.h | 9 ++ include/fmsservice.h | 22 +++ include/freenet/messagerequester.h | 1 + include/global.h | 14 +- include/http/identityexportxml.h | 43 ++++++ include/http/ipagehandler.h | 2 + include/http/pages/peerdetailspage.h | 20 +++ include/pthreadwrapper/thread.h | 2 + include/threadcontroller.h | 3 +- src/db/sqlite3statement.cpp | 28 ++-- src/fmsdaemon.cpp | 52 +++++++ src/fmsservice.cpp | 222 ++++++++++++++++++++++++++++ src/freenet/introductionpuzzleinserter.cpp | 2 +- src/freenet/introductionpuzzlerequester.cpp | 2 +- src/freenet/messagerequester.cpp | 27 +++- src/freenet/periodicdbmaintenance.cpp | 27 ++++ src/freenet/trustlistxml.cpp | 10 +- src/global.cpp | 85 +++++++++-- src/http/httpthread.cpp | 2 + src/http/identityexportxml.cpp | 185 +++++++++++++++++++++++ src/http/ipagehandler.cpp | 133 +++++++++++++++-- src/http/pages/announceidentitypage.cpp | 10 +- src/http/pages/homepage.cpp | 13 ++ src/http/pages/localidentitiespage.cpp | 104 ++++++++++++- src/http/pages/peerdetailspage.cpp | 139 +++++++++++++++++ src/http/pages/peertrustpage.cpp | 45 +++++- src/http/pages/showcaptchapage.cpp | 12 +- src/main.cpp | 117 ++++++++++++--- src/message.cpp | 2 +- src/nntp/mime/Mime.cpp | 8 +- src/pthreadwrapper/thread.cpp | 20 +++ src/threadcontroller.cpp | 9 +- 33 files changed, 1290 insertions(+), 90 deletions(-) create mode 100644 include/fmsdaemon.h create mode 100644 include/fmsservice.h create mode 100644 include/http/identityexportxml.h create mode 100644 include/http/pages/peerdetailspage.h create mode 100644 src/fmsdaemon.cpp create mode 100644 src/fmsservice.cpp create mode 100644 src/http/identityexportxml.cpp create mode 100644 src/http/pages/peerdetailspage.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3135915..024be6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ src/freenet/captcha/easybmp/EasyBMP.cpp src/freenet/captcha/easybmp/EasyBMP_Font.cpp src/freenet/captcha/easybmp/EasyBMP_Geometry.cpp src/http/httpthread.cpp +src/http/identityexportxml.cpp src/http/ipagehandler.cpp src/http/pages/addpeerpage.cpp src/http/pages/announceidentitypage.cpp @@ -56,6 +57,7 @@ src/http/pages/createidentitypage.cpp src/http/pages/homepage.cpp src/http/pages/localidentitiespage.cpp src/http/pages/optionspage.cpp +src/http/pages/peerdetailspage.cpp src/http/pages/peertrustpage.cpp src/http/pages/showcaptchapage.cpp src/nntp/nntpconnection.cpp @@ -73,6 +75,12 @@ src/pthreadwrapper/threadedexecutor.cpp src/xyssl/sha1.c ) +IF(WIN32) + SET(FMS_PLATFORM_SRC src/fmsservice.cpp) +ELSE(WIN32) + SET(FMS_PLATFORM_SRC src/fmsdaemon.cpp) +ENDIF(WIN32) + ADD_DEFINITIONS(-DTIXML_USE_STL) # was for ZThreads @@ -81,7 +89,7 @@ ADD_DEFINITIONS(-DTIXML_USE_STL) # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") #ENDIF(CMAKE_COMPILER_IS_GNUCXX) -ADD_EXECUTABLE(fms ${FMS_SRC}) +ADD_EXECUTABLE(fms ${FMS_SRC} ${FMS_PLATFORM_SRC}) # For SQLite3 and shttpd IF(CMAKE_COMPILER_IS_GNUCC) diff --git a/include/fmsdaemon.h b/include/fmsdaemon.h new file mode 100644 index 0000000..50ff86c --- /dev/null +++ b/include/fmsdaemon.h @@ -0,0 +1,9 @@ +#ifndef _fmsdaemon_ +#define _fmsdaemon_ + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +void Daemonize(); + +#endif // _fmsdaemon_ diff --git a/include/fmsservice.h b/include/fmsservice.h new file mode 100644 index 0000000..5a08fbb --- /dev/null +++ b/include/fmsservice.h @@ -0,0 +1,22 @@ +#ifndef _fmsservice_ +#define _fmsservice_ + +#ifdef _WIN32 + +#include + +#define FMS_SERVICE_NAME "FMS - Freenet Message System" + +extern SERVICE_STATUS ServiceStatus; +extern SERVICE_STATUS_HANDLE hStatus; + +BOOL ServiceIsInstalled(); +BOOL ServiceInstall(); +BOOL ServiceUninstall(); +BOOL ServiceStart(); +void ServiceMain(int argc, char** argv); +void ControlHandler(DWORD request); + +#endif + +#endif // _fmsservice_ diff --git a/include/freenet/messagerequester.h b/include/freenet/messagerequester.h index d40710f..c4cdb92 100644 --- a/include/freenet/messagerequester.h +++ b/include/freenet/messagerequester.h @@ -20,6 +20,7 @@ private: const std::string GetIdentityName(const long identityid); long m_maxdaysbackward; + long m_maxpeermessages; }; diff --git a/include/global.h b/include/global.h index ba827c4..cb75d5a 100644 --- a/include/global.h +++ b/include/global.h @@ -5,21 +5,29 @@ //#include #include "pthreadwrapper/thread.h" -#define FMS_VERSION "0.1.9" +#define FMS_VERSION "0.1.10" // opens database and creates tables and initial inserts if necessary void SetupDB(); +void ConvertDB0100To0101(); // inserts default options into the database void SetupDefaultOptions(); // opens logfile and sets it up void SetupLogFile(); -void StartThreads(std::vector &threads); -void ShutdownThreads(std::vector &threads); +void SigHandler(int signum); + +void MainFunction(); +void Shutdown(); + +//void StartThreads(std::vector &threads); +//void ShutdownThreads(std::vector &threads); // needed for Windows to setup network void SetupNetwork(); // cleanup network on Windows void ShutdownNetwork(); +extern bool wantshutdown; + #endif // _global_ diff --git a/include/http/identityexportxml.h b/include/http/identityexportxml.h new file mode 100644 index 0000000..6d6db3a --- /dev/null +++ b/include/http/identityexportxml.h @@ -0,0 +1,43 @@ +#ifndef _identityexportxml_ +#define _identityexportxml_ + +#include "../ifmsxmldocument.h" + +class IdentityExportXML:public IFMSXMLDocument +{ +public: + IdentityExportXML(); + + std::string GetXML(); + const bool ParseXML(const std::string &xml); + + void AddIdentity(const std::string &name, const std::string &publickey, const std::string &privatekey, const bool singleuse=false, const bool publishtrustlist=false, const bool publishboardlist=false); + + const long GetCount() { return m_identities.size(); } + + const std::string GetName(const long index); + const std::string GetPublicKey(const long index); + const std::string GetPrivateKey(const long index); + const bool GetSingleUse(const long index); + const bool GetPublishTrustList(const long index); + const bool GetPublishBoardList(const long index); + +private: + void Initialize(); + + struct identity + { + identity(const std::string &name, const std::string &publickey, const std::string &privatekey, const bool singleuse, const bool publishtrustlist, const bool publishboardlist):m_name(name),m_publickey(publickey),m_privatekey(privatekey),m_singleuse(singleuse),m_publishtrustlist(publishtrustlist),m_publishboardlist(publishboardlist) {} + std::string m_name; + std::string m_publickey; + std::string m_privatekey; + bool m_singleuse; + bool m_publishtrustlist; + bool m_publishboardlist; + }; + + std::vector m_identities; + +}; + +#endif // _identityexportxml_ diff --git a/include/http/ipagehandler.h b/include/http/ipagehandler.h index be707e5..6cd3052 100644 --- a/include/http/ipagehandler.h +++ b/include/http/ipagehandler.h @@ -26,6 +26,8 @@ private: virtual const std::string GeneratePage(const std::string &method, const std::map &queryvars)=0; protected: + // splits apart data into name,data pairs in args map + void HandleMultiPartData(const std::string &contenttypeheader, char *data, const long datalen, std::map &args); // converts from basename[#] query args into a vector where the vector pos is the index pos # void CreateArgArray(const std::map &vars, const std::string &basename, std::vector &args); diff --git a/include/http/pages/peerdetailspage.h b/include/http/pages/peerdetailspage.h new file mode 100644 index 0000000..5a2b79f --- /dev/null +++ b/include/http/pages/peerdetailspage.h @@ -0,0 +1,20 @@ +#ifndef _peerdetailspage_ +#define _peerdetailspage_ + +#include "../ipagehandler.h" +#include "../../idatabase.h" + +class PeerDetailsPage:public IPageHandler,public IDatabase +{ +public: + PeerDetailsPage(const std::string templatestr):IPageHandler(templatestr) {} + +private: + const bool WillHandleURI(const std::string &uri); + const std::string GeneratePage(const std::string &method, const std::map &queryvars); + + const std::string GetClassString(const std::string &trustlevel); + +}; + +#endif // _peerdetailspage_ diff --git a/include/pthreadwrapper/thread.h b/include/pthreadwrapper/thread.h index c1db10a..6e51f73 100644 --- a/include/pthreadwrapper/thread.h +++ b/include/pthreadwrapper/thread.h @@ -8,6 +8,8 @@ namespace PThread { +void Sleep(const long ms); + class Runnable; class Thread:public NonCopyable diff --git a/include/threadcontroller.h b/include/threadcontroller.h index d1190c8..47cb63a 100644 --- a/include/threadcontroller.h +++ b/include/threadcontroller.h @@ -1,10 +1,11 @@ #ifndef _threadcontroller_ #define _threadcontroller_ +#include "ilogger.h" #include "pthreadwrapper/thread.h" #include "pthreadwrapper/singleton.h" -class ThreadController:public PThread::Singleton +class ThreadController:public PThread::Singleton,public ILogger { public: ThreadController():m_freenetthread(NULL),m_httpthread(NULL),m_nntpthread(NULL) {} diff --git a/src/db/sqlite3statement.cpp b/src/db/sqlite3statement.cpp index 683e771..81df27a 100644 --- a/src/db/sqlite3statement.cpp +++ b/src/db/sqlite3statement.cpp @@ -65,7 +65,7 @@ const bool Statement::Bind(const int column) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); if(sqlite3_bind_null(m_statement,column+1)==SQLITE_OK) { return true; @@ -86,7 +86,7 @@ const bool Statement::Bind(const int column, const int value) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); if(sqlite3_bind_int(m_statement,column+1,value)==SQLITE_OK) { return true; @@ -107,7 +107,7 @@ const bool Statement::Bind(const int column, const double value) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); if(sqlite3_bind_double(m_statement,column+1,value)==SQLITE_OK) { return true; @@ -127,16 +127,8 @@ const bool Statement::Bind(const int column, const std::string &value) { if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); - //m_boundtext.push_back(std::vector(value.begin(),value.end())); - //if(sqlite3_bind_text(m_statement,column+1,text,value.size(),NULL)==SQLITE_OK) - //if(sqlite3_bind_text(m_statement,column+1,&(m_boundtext[m_boundtext.size()-1][0]),(m_boundtext[m_boundtext.size()-1]).size(),NULL)==SQLITE_OK) + //PThread::Guard g(DB::Instance()->m_mutex); if(sqlite3_bind_text(m_statement,column+1,value.c_str(),value.size(),SQLITE_TRANSIENT)==SQLITE_OK) { return true; @@ -157,7 +149,7 @@ const bool Statement::Bind(const int column, const void *data, const int length) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); if(sqlite3_bind_blob(m_statement,column+1,data,length,SQLITE_TRANSIENT)==SQLITE_OK) { return true; @@ -236,7 +228,7 @@ const bool Statement::ResultBlob(const int column, void *data, int &length) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); data=(void *)sqlite3_column_blob(m_statement,column); length=sqlite3_column_bytes(m_statement,column); return true; @@ -252,7 +244,7 @@ const bool Statement::ResultDouble(const int column, double &result) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); result=sqlite3_column_double(m_statement,column); return true; } @@ -267,7 +259,7 @@ const bool Statement::ResultInt(const int column, int &result) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); result=sqlite3_column_int(m_statement,column); return true; } @@ -282,7 +274,7 @@ const bool Statement::ResultNull(const int column) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); if(sqlite3_column_type(m_statement,column)==SQLITE_NULL) { return true; @@ -303,7 +295,7 @@ const bool Statement::ResultText(const int column, std::string &result) if(Valid() && column>=0 && column g(DB::instance()->m_mutex); - PThread::Guard g(DB::Instance()->m_mutex); + //PThread::Guard g(DB::Instance()->m_mutex); const unsigned char *cresult=sqlite3_column_text(m_statement,column); if(cresult) { diff --git a/src/fmsdaemon.cpp b/src/fmsdaemon.cpp new file mode 100644 index 0000000..0086a02 --- /dev/null +++ b/src/fmsdaemon.cpp @@ -0,0 +1,52 @@ +#include "../include/fmsdaemon.h" + +#include +#include +#include +#ifndef _WIN32 + #include + #include +#endif + +#ifdef XMEM + #include +#endif + +/* + modified from http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize +*/ +void Daemonize() +{ +#ifndef _WIN32 + pid_t pid, sid; + + /* already a daemon */ + if ( getppid() == 1 ) return; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + /* If we got a good PID, then we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* At this point we are executing as the child process */ + + /* Change the file mode mask */ + umask(0); + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) { + exit(EXIT_FAILURE); + } + + /* Redirect standard files to /dev/null */ + freopen( "/dev/null", "r", stdin); + freopen( "/dev/null", "w", stdout); + freopen( "/dev/null", "w", stderr); +#endif +} diff --git a/src/fmsservice.cpp b/src/fmsservice.cpp new file mode 100644 index 0000000..e24a53f --- /dev/null +++ b/src/fmsservice.cpp @@ -0,0 +1,222 @@ +#include "../include/fmsservice.h" +#include "../include/global.h" + +#include + +#ifdef _WIN32 + +#include + +#ifdef XMEM + #include +#endif + +SERVICE_STATUS ServiceStatus; +SERVICE_STATUS_HANDLE hStatus; + +void ControlHandler(DWORD request) +{ + switch(request) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + wantshutdown=true; + break; + + default: + break; + } + + /* Report current status */ + SetServiceStatus (hStatus, &ServiceStatus); + + return; +} + +BOOL ServiceInstall() +{ + SC_HANDLE hSCM, hService; + char szFilePath[FILENAME_MAX], szKey[256]; + HKEY hKey; + DWORD dwData; + + hSCM = OpenSCManager(NULL, /* local machine */ + NULL, /* ServicesActive database */ + SC_MANAGER_ALL_ACCESS); /* full access */ + + if (!hSCM) return FALSE; + + GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); + std::string commandline(szFilePath); + commandline+=" -s"; + + hService = CreateService(hSCM, + FMS_SERVICE_NAME, + FMS_SERVICE_NAME, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, /* start condition */ + SERVICE_ERROR_NORMAL, + commandline.c_str(), + NULL, + NULL, + NULL, + NULL, + NULL); + + if (!hService) { + CloseServiceHandle(hSCM); + return FALSE; + } + + hKey = NULL; + strcpy(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"); + strcat(szKey, FMS_SERVICE_NAME); + if (RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) { + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return FALSE; + } + + RegSetValueEx(hKey, + "EventMessageFile", + 0, + REG_EXPAND_SZ, + (CONST BYTE*)szFilePath, + (int) strlen(szFilePath) + 1); + + dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; + RegSetValueEx(hKey, + "TypesSupported", + 0, + REG_DWORD, + (CONST BYTE*)&dwData, + sizeof(DWORD)); + RegCloseKey(hKey); + + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + + return TRUE; +} + +BOOL ServiceIsInstalled() +{ + BOOL bResult; + SC_HANDLE hSCM, hService; + + hSCM = OpenSCManager(NULL, /* local machine */ + NULL, /* ServicesActive database */ + SC_MANAGER_ALL_ACCESS); /* full access */ + + bResult = FALSE; + + if (hSCM) { + hService = OpenService(hSCM, + FMS_SERVICE_NAME, + SERVICE_QUERY_CONFIG); + + if (hService) { + bResult = TRUE; + CloseServiceHandle(hService); + } + CloseServiceHandle(hSCM); + } + + return bResult; +} + +void ServiceMain(int argc, char** argv) +{ + char szDocumentRoot[MAX_PATH]; + + ServiceStatus.dwServiceType = SERVICE_WIN32; + ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 0; + ServiceStatus.dwWaitHint = 0; + + hStatus = RegisterServiceCtrlHandler(FMS_SERVICE_NAME, (LPHANDLER_FUNCTION)ControlHandler); + + if (hStatus == (SERVICE_STATUS_HANDLE)0) { + /* Registering Control Handler failed */ + return; + } + + /* Initialize Service */ + + /* + Construct default paths & filenames and make sure we serve documents from the folder containing the executable. + If left without a default value, we will be serving from C:\WINDOWS\SYSTEM32 (we start there as a service)! + */ + GetModuleFileName(NULL, szDocumentRoot, MAX_PATH); + std::string path(szDocumentRoot); + std::string::size_type slashpos=path.rfind("\\"); + if(slashpos==std::string::npos) + { + slashpos=path.rfind("/"); + } + if(slashpos!=std::string::npos) + { + path.erase(slashpos); + } + chdir(path.c_str()); + + /* We report the running status to SCM. */ + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus (hStatus, &ServiceStatus); + + MainFunction(); + + ServiceStatus.dwCurrentState=SERVICE_STOPPED; + SetServiceStatus(hStatus,&ServiceStatus); + + return; +} + +BOOL ServiceStart() +{ + SERVICE_TABLE_ENTRY ServiceTable[2]; + + ServiceTable[0].lpServiceName = FMS_SERVICE_NAME; + ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; + + ServiceTable[1].lpServiceName = NULL; + ServiceTable[1].lpServiceProc = NULL; + + /* Start the control dispatcher thread for our service */ + return StartServiceCtrlDispatcher(ServiceTable); +} + +BOOL ServiceUninstall() +{ + SC_HANDLE hSCM, hService; + BOOL bResult; + + hSCM = OpenSCManager(NULL, /* local machine */ + NULL, /* ServicesActive database */ + SC_MANAGER_ALL_ACCESS); /* full access */ + + if (!hSCM) return 0; + + bResult = FALSE; + + hService = OpenService(hSCM, + FMS_SERVICE_NAME, + DELETE); + + if (hService) { + if (DeleteService(hService)) bResult = TRUE; + CloseServiceHandle(hService); + } + + CloseServiceHandle(hSCM); + + return bResult; +} + +#endif // _WIN32 diff --git a/src/freenet/introductionpuzzleinserter.cpp b/src/freenet/introductionpuzzleinserter.cpp index 1b5b64f..fef42f1 100644 --- a/src/freenet/introductionpuzzleinserter.cpp +++ b/src/freenet/introductionpuzzleinserter.cpp @@ -230,7 +230,7 @@ void IntroductionPuzzleInserter::StartInsert(const long localidentityid) xml.SetType("captcha"); xml.SetUUID(uuid.Generate()); xml.SetPuzzleData(encodedpuzzle); - xml.SetMimeType("bitmap/image"); + xml.SetMimeType("image/bmp"); xmldata=xml.GetXML(); StringFunctions::Convert(xmldata.size(),xmldatasizestr); diff --git a/src/freenet/introductionpuzzlerequester.cpp b/src/freenet/introductionpuzzlerequester.cpp index 4f85e7a..830bdb3 100644 --- a/src/freenet/introductionpuzzlerequester.cpp +++ b/src/freenet/introductionpuzzlerequester.cpp @@ -202,7 +202,7 @@ void IntroductionPuzzleRequester::PopulateIDList() now.SetToGMTime(); // select identities that aren't single use and have been seen today ( order by trust DESC and limit to limitnum ) - st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey <> '' AND SingleUse='false' AND LastSeen>='"+now.Format("%Y-%m-%d")+"' ORDER BY LocalMessageTrust LIMIT 0,"+limitnum+";"); + st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey <> '' AND SingleUse='false' AND LastSeen>='"+now.Format("%Y-%m-%d")+"' ORDER BY LocalMessageTrust DESC LIMIT 0,"+limitnum+";"); st.Step(); m_ids.clear(); diff --git a/src/freenet/messagerequester.cpp b/src/freenet/messagerequester.cpp index 980e688..d58494b 100644 --- a/src/freenet/messagerequester.cpp +++ b/src/freenet/messagerequester.cpp @@ -167,7 +167,7 @@ const bool MessageRequester::HandleAllData(FCPMessage &message) } else // couldn't insert - was already in database { - m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAddData could not insert message into database. "+message["Identifier"]); + //m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAddData could not insert message into database. "+message["Identifier"]); } } @@ -241,6 +241,17 @@ void MessageRequester::Initialize() { m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MessageDownloadMaxDaysBackward is currently set at "+tempval+". This value might be incorrectly configured."); } + Option::Instance()->Get("MaxPeerMessagesPerDay",tempval); + StringFunctions::Convert(tempval,m_maxpeermessages); + if(m_maxpeermessages<1) + { + m_maxpeermessages=1; + m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxPeerMessagesPerDay is currently set at "+tempval+". It must be 1 or greater."); + } + if(m_maxpeermessages<20 || m_maxpeermessages>1000) + { + m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxPeerMessagesPerDay is currently set at "+tempval+". This value might be incorrectly configured. The suggested value is 200."); + } } void MessageRequester::PopulateIDList() @@ -250,6 +261,7 @@ void MessageRequester::PopulateIDList() std::string val2; std::string val3; std::string sql; + long requestindex; date.SetToGMTime(); date.Add(0,0,0,-m_maxdaysbackward); @@ -270,9 +282,17 @@ void MessageRequester::PopulateIDList() st.ResultText(0,val1); st.ResultText(1,val2); st.ResultText(2,val3); - if(m_ids.find(val1+"*"+val2+"*"+val3)==m_ids.end()) + + requestindex=0; + StringFunctions::Convert(val3,requestindex); + + // only continue if index is < max messages we will accept from a peer + if(requestindexSendMessage(message); diff --git a/src/freenet/periodicdbmaintenance.cpp b/src/freenet/periodicdbmaintenance.cpp index 22a4ccf..0febbbd 100644 --- a/src/freenet/periodicdbmaintenance.cpp +++ b/src/freenet/periodicdbmaintenance.cpp @@ -58,6 +58,33 @@ void PeriodicDBMaintenance::Do1DayMaintenance() m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"PeriodicDBMaintenance::Do1DayMaintenance"); + // delete all identities we've never seen and were added more than 20 days ago + date.SetToGMTime(); + date.Add(0,0,0,-20); + m_db->Execute("DELETE FROM tblIdentity WHERE LastSeen IS NULL AND DateAdded<'"+date.Format("%Y-%m-%d")+"';"); + + // delete old identity requests - we don't need them anymore + date.SetToGMTime(); + date.Add(0,0,0,-2); + m_db->Execute("DELETE FROM tblIdentityRequests WHERE Day<'"+date.Format("%Y-%m-%d")+"';"); + + // delete old local identity inserts - we don't need them anymore + date.SetToGMTime(); + date.Add(0,0,0,-2); + m_db->Execute("DELETE FROM tblLocalIdentityInserts WHERE Day<'"+date.Format("%Y-%m-%d")+"';"); + + // delete old message list inserts/requests - we don't need them anymore + date.SetToGMTime(); + date.Add(0,0,0,-2); + m_db->Execute("DELETE FROM tblMessageListInserts WHERE Day<'"+date.Format("%Y-%m-%d")+"';"); + m_db->Execute("DELETE FROM tblMessageListRequests WHERE Day<'"+date.Format("%Y-%m-%d")+"';"); + + // delete old trust list inserts/requests - we don't need them anymore + date.SetToGMTime(); + date.Add(0,0,0,-2); + m_db->Execute("DELETE FROM tblTrustListInserts WHERE Day<'"+date.Format("%Y-%m-%d")+"';"); + m_db->Execute("DELETE FROM tblTrustListRequests WHERE Day<'"+date.Format("%Y-%m-%d")+"';"); + } void PeriodicDBMaintenance::Process() diff --git a/src/freenet/trustlistxml.cpp b/src/freenet/trustlistxml.cpp index 0d0df5c..c3e71db 100644 --- a/src/freenet/trustlistxml.cpp +++ b/src/freenet/trustlistxml.cpp @@ -1,6 +1,8 @@ #include "../../include/freenet/trustlistxml.h" #include "../../include/stringfunctions.h" +#include + #ifdef XMEM #include #endif @@ -99,6 +101,7 @@ const bool TrustListXML::ParseXML(const std::string &xml) TiXmlText *txt; TiXmlHandle hnd(&td); TiXmlNode *node; + std::vector m_foundkeys; Initialize(); @@ -130,7 +133,12 @@ const bool TrustListXML::ParseXML(const std::string &xml) if(identity!="" && messagetrust>=0 && messagetrust<=100 && trustlisttrust>=0 && trustlisttrust<=100) { - m_trust.push_back(trust(identity,messagetrust,trustlisttrust)); + // check so we don't add the same identity multiple times from a trust list + if(std::find(m_foundkeys.begin(),m_foundkeys.end(),identity)==m_foundkeys.end()) + { + m_foundkeys.push_back(identity); + m_trust.push_back(trust(identity,messagetrust,trustlisttrust)); + } } else { diff --git a/src/global.cpp b/src/global.cpp index a3c8111..42a4726 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -7,6 +7,7 @@ #include "../include/freenet/freenetmasterthread.h" #include "../include/nntp/nntplistener.h" #include "../include/http/httpthread.h" +#include "../include/threadcontroller.h" #ifdef _WIN32 #include @@ -16,6 +17,8 @@ #include #endif +bool wantshutdown=false; + void SetupDB() { @@ -42,10 +45,15 @@ void SetupDB() int minor; st.ResultInt(0,major); st.ResultInt(1,minor); + st.Finalize(); + if(major==1 && minor==0) + { + ConvertDB0100To0101(); + } } else { - db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,0);"); + db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,1);"); } db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\ @@ -57,8 +65,8 @@ void SetupDB() db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\ LocalIdentityID INTEGER PRIMARY KEY,\ Name TEXT,\ - PublicKey TEXT,\ - PrivateKey TEXT,\ + PublicKey TEXT UNIQUE,\ + PrivateKey TEXT UNIQUE,\ SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\ PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\ PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\ @@ -326,12 +334,46 @@ void SetupDB() db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';"); db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';"); - // insert SomeDude's public key date.SetToGMTime(); + // insert SomeDude's public key db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw,iXez4j3qCpd596TxXiJgZyTq9o-CElEuJxm~jNNZAuA,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');"); + // insert Shadow Panther's public key + db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@~mimyB1kmH4f7Cgsd2wM2Qv2NxrZHRMM6IY8~7EWRVQ,fxTKkR0TYhgMYb-vEGAv55sMOxCGD2xhE4ZxWHxdPz4,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');"); + // insert garfield's public key + db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@T8l1IEGU4-PoASFzgc2GYhIgRzUvZsKdoQWeuLHuTmM,QLxAPfkGis8l5NafNpSCdbxzXhBlu9WL8svcqJw9Mpo,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');"); } +void ConvertDB0100To0101() +{ + // added unique constraint to public and private key + SQLite3DB::DB *db=SQLite3DB::DB::Instance(); + db->Execute("CREATE TEMPORARY TABLE tblLocalIdentityTemp AS SELECT * FROM tblLocalIdentity;"); + db->Execute("DROP TABLE IF EXISTS tblLocalIdentity;"); + db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\ + LocalIdentityID INTEGER PRIMARY KEY,\ + Name TEXT,\ + PublicKey TEXT UNIQUE,\ + PrivateKey TEXT UNIQUE,\ + SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\ + PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\ + PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\ + InsertingIdentity BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\ + LastInsertedIdentity DATETIME,\ + InsertingPuzzle BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\ + LastInsertedPuzzle DATETIME,\ + InsertingTrustList BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\ + LastInsertedTrustList DATETIME,\ + InsertingBoardList BOOL CHECK(InsertingBoardList IN('true','false')) DEFAULT 'false',\ + LastInsertedBoardList DATETIME,\ + InsertingMessageList BOOL CHECK(InsertingMessageList IN('true','false')) DEFAULT 'false',\ + LastInsertedMessageList DATETIME\ + );"); + db->Execute("INSERT INTO tblLocalIdentity SELECT * FROM tblLocalIdentityTemp;"); + db->Execute("DROP TABLE IF EXISTS tblLocalIdentityTemp;"); + db->Execute("UPDATE tblDBVersion SET Major=1, Minor=1;"); +} + void SetupDefaultOptions() { // OptionValue should always be inserted as a string, even if the option really isn't a string - just to keep the field data type consistent @@ -487,6 +529,12 @@ void SetupDefaultOptions() st.Step(); st.Reset(); + st.Bind(0,"MaxPeerMessagesPerDay"); + st.Bind(1,"200"); + st.Bind(2,"The maximum number of messages you will download from each peer on a given day."); + st.Step(); + st.Reset(); + } void SetupLogFile() @@ -524,6 +572,16 @@ void SetupNetwork() #endif } +void Shutdown() +{ + ThreadController::Instance()->ShutdownThreads(); + + ShutdownNetwork(); + + LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"FMS shutdown"); + LogFile::Instance()->WriteNewLine(); +} + void ShutdownNetwork() { #ifdef _WIN32 @@ -531,22 +589,18 @@ void ShutdownNetwork() #endif } +void SigHandler(int signum) +{ + Shutdown(); + exit(0); +} + +/* void ShutdownThreads(std::vector &threads) { std::vector::iterator i; for(i=threads.begin(); i!=threads.end(); i++) { -/* if((*i)->wait(1)==false) - { - try - { - (*i)->interrupt(); - } - catch(...) - { - } - } - */ (*i)->Cancel(); } @@ -605,3 +659,4 @@ void StartThreads(std::vector &threads) } } +*/ diff --git a/src/http/httpthread.cpp b/src/http/httpthread.cpp index f08ebe8..a1f51c7 100644 --- a/src/http/httpthread.cpp +++ b/src/http/httpthread.cpp @@ -10,6 +10,7 @@ #include "../../include/http/pages/addpeerpage.h" #include "../../include/http/pages/peertrustpage.h" #include "../../include/http/pages/controlboardpage.h" +#include "../../include/http/pages/peerdetailspage.h" #include @@ -52,6 +53,7 @@ HTTPThread::HTTPThread() m_pagehandlers.push_back(new AddPeerPage(templatestr)); m_pagehandlers.push_back(new PeerTrustPage(templatestr)); m_pagehandlers.push_back(new ControlBoardPage(templatestr)); + m_pagehandlers.push_back(new PeerDetailsPage(templatestr)); // homepage must be last - catch all page handler m_pagehandlers.push_back(new HomePage(templatestr)); diff --git a/src/http/identityexportxml.cpp b/src/http/identityexportxml.cpp new file mode 100644 index 0000000..b2609bf --- /dev/null +++ b/src/http/identityexportxml.cpp @@ -0,0 +1,185 @@ +#include "../../include/http/identityexportxml.h" + +#ifdef XMEM + #include +#endif + +IdentityExportXML::IdentityExportXML() +{ + Initialize(); +} + +void IdentityExportXML::AddIdentity(const std::string &name, const std::string &publickey, const std::string &privatekey, const bool singleuse, const bool publishtrustlist, const bool publishboardlist) +{ + m_identities.push_back(identity(name,publickey,privatekey,singleuse,publishtrustlist,publishboardlist)); +} + +const std::string IdentityExportXML::GetName(const long index) +{ + if(index>=0 && index=0 && index=0 && index=0 && index=0 && index=0 && index::iterator i=m_identities.begin(); i!=m_identities.end(); i++) + { + TiXmlElement *tr=new TiXmlElement("Identity"); + tid->LinkEndChild(tr); + tr->LinkEndChild(XMLCreateCDATAElement("Name",(*i).m_name)); + tr->LinkEndChild(XMLCreateTextElement("PublicKey",(*i).m_publickey)); + tr->LinkEndChild(XMLCreateTextElement("PrivateKey",(*i).m_privatekey)); + tr->LinkEndChild(XMLCreateBooleanElement("SingleUse",(*i).m_singleuse)); + tr->LinkEndChild(XMLCreateBooleanElement("PublishTrustList",(*i).m_publishtrustlist)); + tr->LinkEndChild(XMLCreateBooleanElement("PublishBoardList",(*i).m_publishboardlist)); + } + + td.Accept(&tp); + return std::string(tp.CStr()); +} + +void IdentityExportXML::Initialize() +{ + m_identities.clear(); +} + +const bool IdentityExportXML::ParseXML(const std::string &xml) +{ + TiXmlDocument td; + td.Parse(xml.c_str()); + + if(!td.Error()) + { + std::string name; + std::string publickey; + std::string privatekey; + bool singleuse=false; + bool publishtrustlist=false; + bool publishboardlist=false; + TiXmlText *txt; + TiXmlHandle hnd(&td); + TiXmlNode *node; + + Initialize(); + + node=hnd.FirstChild("IdentityExport").FirstChild("Identity").ToElement(); + while(node) + { + name=""; + publickey=""; + privatekey=""; + singleuse=false; + publishtrustlist=false; + publishboardlist=false; + + TiXmlHandle hnd2(node); + txt=hnd2.FirstChild("Name").FirstChild().ToText(); + if(txt) + { + name=txt->ValueStr(); + } + txt=hnd2.FirstChild("PublicKey").FirstChild().ToText(); + if(txt) + { + publickey=txt->ValueStr(); + } + txt=hnd2.FirstChild("PrivateKey").FirstChild().ToText(); + if(txt) + { + privatekey=txt->ValueStr(); + } + + singleuse=XMLGetBooleanElement(node->ToElement(),"SingleUse"); + publishtrustlist=XMLGetBooleanElement(node->ToElement(),"PublishTrustList"); + publishboardlist=XMLGetBooleanElement(node->ToElement(),"PublishBoardList"); + + if(name!="" && publickey!="" && privatekey!="") + { + m_identities.push_back(identity(name,publickey,privatekey,singleuse,publishtrustlist,publishboardlist)); + } + + node=node->NextSibling("Identity"); + } + return true; + + } + else + { + return false; + } +} \ No newline at end of file diff --git a/src/http/ipagehandler.cpp b/src/http/ipagehandler.cpp index c4ebbb9..f4ac20f 100644 --- a/src/http/ipagehandler.cpp +++ b/src/http/ipagehandler.cpp @@ -44,6 +44,28 @@ const bool IPageHandler::Handle(shttpd_arg *arg) if(uri && WillHandleURI(std::string(uri))) { httpstate *mystate=(httpstate *)arg->state; + + // first check if there was a connection error - if so delete the input/output and state buffers and return immediately + if((arg->flags & SHTTPD_CONNECTION_ERROR)==SHTTPD_CONNECTION_ERROR) + { + if(mystate && mystate->m_indata) + { + delete mystate->m_indata; + mystate->m_indata=NULL; + } + if(mystate && mystate->m_outdata) + { + delete mystate->m_outdata; + mystate->m_outdata=NULL; + } + if(mystate) + { + delete mystate; + mystate=NULL; + } + return true; + } + // this is a new request - create a new arg object if(arg->state==NULL) { @@ -84,29 +106,45 @@ const bool IPageHandler::Handle(shttpd_arg *arg) //parse POST data and any QUERY_STRING before generating page std::map args; std::vector argparts; + std::string contenttype=""; - if(mystate->m_indata) + if(shttpd_get_header(arg,"Content-Type")) { - StringFunctions::Split(mystate->m_indata,"&",argparts); + contenttype=shttpd_get_header(arg,"Content-Type"); } - if(shttpd_get_env(arg,"QUERY_STRING")) + + if(contenttype.find("multipart/form-data")!=std::string::npos) { - StringFunctions::Split(shttpd_get_env(arg,"QUERY_STRING"),"&",argparts); + HandleMultiPartData(contenttype,mystate->m_indata,mystate->m_indatalen,args); } - for(std::vector::iterator argi=argparts.begin(); argi!=argparts.end(); argi++) + else { - std::vector parts; - StringFunctions::Split((*argi),"=",parts); - if(parts.size()>0) + // split apart non-multipart POST + if(mystate->m_indata) { - // replace + with space before UriDecoding - parts[0]=StringFunctions::Replace(parts[0],"+"," "); - args[StringFunctions::UriDecode(parts[0])]; - if(parts.size()>1) + StringFunctions::Split(mystate->m_indata,"&",argparts); + } + // split apart query string + if(shttpd_get_env(arg,"QUERY_STRING")) + { + StringFunctions::Split(shttpd_get_env(arg,"QUERY_STRING"),"&",argparts); + } + + for(std::vector::iterator argi=argparts.begin(); argi!=argparts.end(); argi++) + { + std::vector parts; + StringFunctions::Split((*argi),"=",parts); + if(parts.size()>0) { // replace + with space before UriDecoding - parts[1]=StringFunctions::Replace(parts[1],"+"," "); - args[StringFunctions::UriDecode(parts[0])]=StringFunctions::UriDecode(parts[1]); + parts[0]=StringFunctions::Replace(parts[0],"+"," "); + args[StringFunctions::UriDecode(parts[0])]; + if(parts.size()>1) + { + // replace + with space before UriDecoding + parts[1]=StringFunctions::Replace(parts[1],"+"," "); + args[StringFunctions::UriDecode(parts[0])]=StringFunctions::UriDecode(parts[1]); + } } } } @@ -154,6 +192,73 @@ const bool IPageHandler::Handle(shttpd_arg *arg) } } +void IPageHandler::HandleMultiPartData(const std::string &contenttypeheader, char *data, const long datalen, std::map &args) +{ + if(data) + { + std::string datastr(data,data+datalen); + std::vector parts; + std::string boundary=""; + std::string::size_type pos=contenttypeheader.find("boundary="); + + // find boundary + if(pos!=std::string::npos) + { + boundary=contenttypeheader.substr(pos+9); + // strip off any " and ; + boundary=StringFunctions::Replace(boundary,"\"",""); + boundary=StringFunctions::Replace(boundary,";",""); + } + + // split into parts separated by boundary + StringFunctions::Split(datastr,"--"+boundary+"\r\n",parts); + + // go through each part and get name=value + for(std::vector::iterator i=parts.begin(); i!=parts.end(); i++) + { + std::string data=""; + std::string name=""; + + // find name + pos=(*i).find("name="); + if(pos!=std::string::npos) + { + std::string::size_type pos2=(*i).find(";",pos); + if(pos2!=std::string::npos) + { + name=(*i).substr(pos+5,pos2-(pos+5)); + } + else + { + pos2=(*i).find("\r\n",pos); + if(pos2!=std::string::npos) + { + name=(*i).substr(pos+5,pos2-(pos+5)); + } + } + + name=StringFunctions::Replace(name,"\"",""); + } + + // find header boundary + pos=(*i).find("\r\n\r\n"); + if(pos!=std::string::npos) + { + data=(*i).substr(pos+4); + // strip off final \r\n from data + if(data.size()>2 && data.rfind("\r\n")==data.size()-2) + { + data.erase(data.size()-2); + } + } + if(name!="" && data!="") + { + args[name]=data; + } + } + } +} + const std::string IPageHandler::SanitizeOutput(const std::string &input) { // must do & first because all other elements have & in them! diff --git a/src/http/pages/announceidentitypage.cpp b/src/http/pages/announceidentitypage.cpp index 710904c..b67f16f 100644 --- a/src/http/pages/announceidentitypage.cpp +++ b/src/http/pages/announceidentitypage.cpp @@ -18,12 +18,18 @@ const std::string AnnounceIdentityPage::CreateLocalIdentityDropDown(const std::s std::string id; std::string name; std::string pubkey; + std::string keypart=""; st.ResultText(0,id); st.ResultText(1,name); st.ResultText(2,pubkey); - rval+=""; + if(pubkey.size()>8) + { + keypart=pubkey.substr(3,5); + } + + rval+=""; st.Step(); } rval+=""; @@ -81,7 +87,7 @@ const std::string AnnounceIdentityPage::GeneratePage(const std::string &method, content+="
Select Identity : "; content+=CreateLocalIdentityDropDown("localidentityid",""); content+=""; - content+="
Type the answers of a few puzzles"; + content+="
Type the answers of a few puzzles. The puzzles are case sensitive."; content+=""; //TODO if we are already inserting a solution for an identity - we shouldn't select any puzzles that are older than the one we are inserting diff --git a/src/http/pages/homepage.cpp b/src/http/pages/homepage.cpp index cbc57e4..c89d92c 100644 --- a/src/http/pages/homepage.cpp +++ b/src/http/pages/homepage.cpp @@ -1,5 +1,6 @@ #include "../../../include/http/pages/homepage.h" #include "../../../include/stringfunctions.h" +#include "../../../include/global.h" #ifdef XMEM #include @@ -7,10 +8,22 @@ const std::string HomePage::GeneratePage(const std::string &method, const std::map &queryvars) { + + if(queryvars.find("formaction")!=queryvars.end() && (*queryvars.find("formaction")).second=="shutdown") + { + wantshutdown=true; + } + std::string content="

Home

"; content+="

"; content+="Use these pages to administer your FMS installation."; content+="

"; + content+="

"; + content+="

"; + content+=""; + content+=""; + content+="
"; + content+="

"; return "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"+StringFunctions::Replace(m_template,"[CONTENT]",content); } diff --git a/src/http/pages/localidentitiespage.cpp b/src/http/pages/localidentitiespage.cpp index e926b2f..84c28b3 100644 --- a/src/http/pages/localidentitiespage.cpp +++ b/src/http/pages/localidentitiespage.cpp @@ -1,5 +1,6 @@ #include "../../../include/http/pages/localidentitiespage.h" #include "../../../include/stringfunctions.h" +#include "../../../include/http/identityexportxml.h" #ifdef XMEM #include @@ -33,7 +34,6 @@ const std::string LocalIdentitiesPage::GeneratePage(const std::string &method, c std::string countstr; std::string content=""; - if(queryvars.find("formaction")!=queryvars.end()) { int id; @@ -75,9 +75,111 @@ const std::string LocalIdentitiesPage::GeneratePage(const std::string &method, c } } } + if((*queryvars.find("formaction")).second=="export") + { + IdentityExportXML xml; + SQLite3DB::Statement exp=m_db->Prepare("SELECT Name,PublicKey,PrivateKey,SingleUse,PublishTrustList,PublishBoardList FROM tblLocalIdentity WHERE PublicKey IS NOT NULL AND PrivateKey IS NOT NULL;"); + exp.Step(); + while(exp.RowReturned()) + { + std::string name=""; + std::string publickey=""; + std::string privatekey=""; + std::string tempval=""; + bool singleuse=false; + bool publishtrustlist=false; + bool publishboardlist=false; + + exp.ResultText(0,name); + exp.ResultText(1,publickey); + exp.ResultText(2,privatekey); + exp.ResultText(3,tempval); + if(tempval=="true") + { + singleuse=true; + } + exp.ResultText(4,tempval); + if(tempval=="true") + { + publishtrustlist=true; + } + exp.ResultText(5,tempval); + if(tempval=="true") + { + publishboardlist=true; + } + + xml.AddIdentity(name,publickey,privatekey,singleuse,publishtrustlist,publishboardlist); + + exp.Step(); + } + return "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\nContent-Disposition: attachment; filename=identities.xml\r\n\r\n"+xml.GetXML(); + } + if((*queryvars.find("formaction")).second=="import") + { + if(queryvars.find("file")!=queryvars.end()) + { + IdentityExportXML xml; + if(xml.ParseXML((*queryvars.find("file")).second)) + { + SQLite3DB::Statement imp=m_db->Prepare("INSERT INTO tblLocalIdentity(Name,PublicKey,PrivateKey,SingleUse,PublishTrustList,PublishBoardList) VALUES(?,?,?,?,?,?);"); + for(int i=0; i"; + content+=""; + content+=""; + content+=""; + content+=""; + content+="
"; + content+=""; + content+=""; + content+=""; + content+="
"; + content+=""; + content+="
"; content+=""; content+=""; diff --git a/src/http/pages/peerdetailspage.cpp b/src/http/pages/peerdetailspage.cpp new file mode 100644 index 0000000..83b1b34 --- /dev/null +++ b/src/http/pages/peerdetailspage.cpp @@ -0,0 +1,139 @@ +#include "../../../include/http/pages/peerdetailspage.h" +#include "../../../include/stringfunctions.h" + +#ifdef XMEM + #include +#endif + +const std::string PeerDetailsPage::GeneratePage(const std::string &method, const std::map &queryvars) +{ + std::string content=""; + int identityid=0; + std::string name; + std::string publickey; + std::string messagetrust; + std::string trustlisttrust; + std::string keypart=""; + std::string lastseen=""; + + if(queryvars.find("identityid")!=queryvars.end() && (*queryvars.find("identityid")).second!="") + { + StringFunctions::Convert((*queryvars.find("identityid")).second,identityid); + } + + SQLite3DB::Statement st=m_db->Prepare("SELECT Name,PublicKey,LastSeen FROM tblIdentity WHERE IdentityID=?;"); + st.Bind(0,identityid); + st.Step(); + + if(st.RowReturned()) + { + st.ResultText(0,name); + st.ResultText(1,publickey); + st.ResultText(2,lastseen); + + content+="
NameSingle UsePublish Trust ListAnnounced? *
"; + content+=""; + content+=""; + content+=""; + content+="
Name"+SanitizeOutput(name)+"
Public Key"+SanitizeOutput(publickey)+"
Last Seen"+lastseen+"
"; + } + + st=m_db->Prepare("SELECT Name,PublicKey,MessageTrust,TrustListTrust,tblIdentity.IdentityID FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.TargetIdentityID=tblIdentity.IdentityID WHERE tblPeerTrust.IdentityID=? ORDER BY Name COLLATE NOCASE;"); + st.Bind(0,identityid); + st.Step(); + + content+=""; + content+=""; + content+=""; + while(st.RowReturned()) + { + std::string thisid=""; + + st.ResultText(0,name); + st.ResultText(1,publickey); + st.ResultText(2,messagetrust); + st.ResultText(3,trustlisttrust); + st.ResultText(4,thisid); + + if(publickey.size()>8) + { + keypart=publickey.substr(3,5); + } + + content+=""; + content+=""; + content+=""; + content+=""; + content+="\r\n"; + + st.Step(); + } + + st=m_db->Prepare("SELECT Name,PublicKey,MessageTrust,TrustListTrust,tblIdentity.IdentityID FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID WHERE tblPeerTrust.TargetIdentityID=? ORDER BY Name COLLATE NOCASE;"); + st.Bind(0,identityid); + st.Step(); + + content+=""; + content+=""; + while(st.RowReturned()) + { + std::string thisid=""; + + st.ResultText(0,name); + st.ResultText(1,publickey); + st.ResultText(2,messagetrust); + st.ResultText(3,trustlisttrust); + st.ResultText(4,thisid); + + if(publickey.size()>8) + { + keypart=publickey.substr(3,5); + } + + content+=""; + content+=""; + content+=""; + content+=""; + content+=""; + + st.Step(); + } + content+="
"; + content+="Trust List of this identity"; + content+="
Message TrustTrust List Trust
"+SanitizeOutput(name+keypart)+"..."+messagetrust+""+trustlisttrust+"
"; + content+="Trust of this identity from other identities"; + content+="
Message TrustTrust List Trust
"+SanitizeOutput(name+keypart)+"..."+messagetrust+""+trustlisttrust+"
"; + + return "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"+StringFunctions::Replace(m_template,"[CONTENT]",content); +} + +const std::string PeerDetailsPage::GetClassString(const std::string &trustlevel) +{ + int tempint=0; + std::string tempstr; + + StringFunctions::Convert(trustlevel,tempint); + tempint/=10; + StringFunctions::Convert(tempint,tempstr); + + if(trustlevel!="") + { + return "class=\"trust"+tempstr+"\""; + } + else + { + return ""; + } +} + +const bool PeerDetailsPage::WillHandleURI(const std::string &uri) +{ + if(uri.find("peerdetails.")!=std::string::npos) + { + return true; + } + else + { + return false; + } +} diff --git a/src/http/pages/peertrustpage.cpp b/src/http/pages/peertrustpage.cpp index b353243..38bddbf 100644 --- a/src/http/pages/peertrustpage.cpp +++ b/src/http/pages/peertrustpage.cpp @@ -15,6 +15,8 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s std::string rowsperpagestr; int startrow=0; std::string startrowstr="0"; + std::string namesearch=""; + std::string sql; StringFunctions::Convert(rowsperpage,rowsperpagestr); @@ -68,20 +70,53 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s StringFunctions::Convert(startrow,startrowstr); } + // if we are searching by name + if(queryvars.find("namesearch")!=queryvars.end()) + { + namesearch=(*queryvars.find("namesearch")).second; + } + content+="

Peer Trust

"; content+="Message Trust is how much you trust the identity to post good messages. Trust List Trust is how much weight you want the trust list of that identity to have when calculating the total. The local trust levels are set by you, and the peer trust levels are calculated by a weighted average using other identities trust lists."; + content+="
"; + content+=""; + content+=""; + content+=""; + content+=""; + content+="
"; content+="
"; content+=""; content+=""; content+=""; content+=""; - SQLite3DB::Statement st=m_db->Prepare("SELECT COUNT(*) FROM tblIdentity;"); + // get count of identities we are showing + sql="SELECT COUNT(*) FROM tblIdentity"; + if(namesearch!="") + { + sql+=" WHERE Name LIKE '%' || ? || '%'"; + } + sql+=";"; + SQLite3DB::Statement st=m_db->Prepare(sql); + if(namesearch!="") + { + st.Bind(0,namesearch); + } st.Step(); st.ResultInt(0,identitycount); st.Finalize(); - st=m_db->Prepare("SELECT IdentityID,Name,LocalMessageTrust,PeerMessageTrust,LocalTrustListTrust,PeerTrustListTrust,PublicKey FROM tblIdentity ORDER BY Name COLLATE NOCASE LIMIT "+startrowstr+","+rowsperpagestr+";"); + sql="SELECT IdentityID,Name,LocalMessageTrust,PeerMessageTrust,LocalTrustListTrust,PeerTrustListTrust,PublicKey FROM tblIdentity"; + if(namesearch!="") + { + sql+=" WHERE Name LIKE '%' || ? || '%'"; + } + sql+=" ORDER BY Name COLLATE NOCASE LIMIT "+startrowstr+","+rowsperpagestr+";"; + st=m_db->Prepare(sql); + if(namesearch!="") + { + st.Bind(0,namesearch); + } st.Step(); while(st.RowReturned()) @@ -113,6 +148,7 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s content+=""; content+=""; content+=""; + content+=""; cols+=2; } if(startrow+rowsperpageNext Page -->"; + content+=""; } content+=""; } diff --git a/src/http/pages/showcaptchapage.cpp b/src/http/pages/showcaptchapage.cpp index abd65b3..46a4d3d 100644 --- a/src/http/pages/showcaptchapage.cpp +++ b/src/http/pages/showcaptchapage.cpp @@ -11,7 +11,7 @@ const std::string ShowCaptchaPage::GeneratePage(const std::string &method, const std::string content="HTTP/1.1 200 OK\r\n"; if(queryvars.find("UUID")!=queryvars.end()) { - SQLite3DB::Statement st=m_db->Prepare("SELECT MimeType,PuzzleData FROM tblIntroductionPuzzleRequests WHERE UUID=?;"); + SQLite3DB::Statement st=m_db->Prepare("SELECT MimeType,PuzzleData FROM tblIntroductionPuzzleRequests WHERE Type='captcha' AND UUID=?;"); st.Bind(0,(*queryvars.find("UUID")).second); st.Step(); @@ -27,9 +27,13 @@ const std::string ShowCaptchaPage::GeneratePage(const std::string &method, const Base64::Decode(b64data,data); StringFunctions::Convert(data.size(),lenstr); - content+="Content-Type: "+mime+"\r\n"; - content+="Content-Length: "+lenstr+"\r\n\r\n"; - content+=std::string(data.begin(),data.end()); + // mime type should be short and have a / in it - otherwise skip + if(mime.size()<50 && mime.find("/")!=std::string::npos) + { + content+="Content-Type: "+mime+"\r\n"; + content+="Content-Length: "+lenstr+"\r\n\r\n"; + content+=std::string(data.begin(),data.end()); + } } } return content; diff --git a/src/main.cpp b/src/main.cpp index 8746da2..17d6b67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,21 +1,113 @@ #include "../include/global.h" #include "../include/commandthread.h" +#include "../include/threadcontroller.h" #include +#include +#include + +#ifdef _WIN32 + #include "../include/fmsservice.h" +#else + #include "../include/fmsdaemon.h" +#endif #ifdef XMEM #include #endif -int main() +int main(int argc, char *argv[]) { #ifdef XMEM xmem_disable_print(); #endif - std::vector threads; + // check arguments + if(argc>1) + { + #ifndef _WIN32 + if(argv[1] && strncmp(argv[1],"-d",2)==0) + { + Daemonize(); + } + #else + if(argv[1] && strncmp(argv[1],"-i",2)==0) + { + if(ServiceIsInstalled()) + { + std::cout << "FMS Service is already installed" << std::endl; + } + else + { + if(ServiceInstall()) + { + std::cout << "FMS Service Installed" << std::endl; + } + else + { + std::cout << "Error installing FMS Service" << std::endl; + } + } + return 0; + } + else if(argv[1] && strncmp(argv[1],"-u",2)==0) + { + if(ServiceIsInstalled()) + { + if(ServiceUninstall()) + { + std::cout << "FMS Service uninstalled" << std::endl; + } + else + { + std::cout << "There was a problem uninstalling the service" << std::endl; + } + } + else + { + std::cout << "FMS Service is not currently installed" << std::endl; + } + return 0; + } + else if(argv[1] && strncmp(argv[1],"-s",2)==0) + { + if(ServiceStart()) + { + } + else + { + std::cout << "FMS Service could not be started at this time" << std::endl; + } + return 0; + } + #endif + } + + signal(SIGINT,SigHandler); + signal(SIGTERM,SigHandler); + signal(SIGABRT,SigHandler); +#ifdef _WIN32 + signal(SIGBREAK,SigHandler); +#endif + + std::cout << "FMS Running in console mode." << std::endl; + std::cout << "Use the administration pages, or CTRL+C to exit" << std::endl << std::endl; + std::cout << "Available command line arguments:" << std::endl; +#ifdef _WIN32 + std::cout << "-i\tinstall service" << std::endl; + std::cout << "-u\tuninstall service" << std::endl; +#else + std::cout << "-d\trun as daemon" << std::endl; +#endif + + MainFunction(); + + return 0; +} +void MainFunction() +{ srand(time(NULL)); SetupDB(); @@ -27,21 +119,12 @@ int main() LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"FMS startup v"FMS_VERSION); + ThreadController::Instance()->StartThreads(); - StartThreads(threads); - - - //ZThread::Thread commandthread(new CommandThread()); - PThread::Thread commandthread(new CommandThread()); - commandthread.Join(); - + do + { + PThread::Sleep(1000); + }while(!wantshutdown); - ShutdownThreads(threads); - - ShutdownNetwork(); - - LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"FMS shutdown"); - LogFile::Instance()->WriteNewLine(); - - return 0; + Shutdown(); } diff --git a/src/message.cpp b/src/message.cpp index 5861ef0..123d370 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -509,7 +509,7 @@ const bool Message::ParseNNTPMessage(const std::string &nntpmessage) void Message::StartFreenetInsert() { - //TODO if message was posted to one of the special administration boards - don't really insert it, but perform the action + MessageXML xml; int localidentityid=-1; diff --git a/src/nntp/mime/Mime.cpp b/src/nntp/mime/Mime.cpp index 0bf826d..89de9f1 100644 --- a/src/nntp/mime/Mime.cpp +++ b/src/nntp/mime/Mime.cpp @@ -362,7 +362,7 @@ void CMimeHeader::SetBoundary(const char* pszBoundary/*=NULL*/) char buf[80]; if (!pszBoundary) // generate a new boundary delimeter { - ::srand(((unsigned)::time(NULL)) ^ reinterpret_cast(this)); + ::srand(((unsigned)::time(NULL)));// ^ reinterpret_cast(this)); ::sprintf(buf, "__=_Part_Boundary_%03d_%06d.%06d", ++s_nPartNumber, rand(), rand()); if (s_nPartNumber >= 9) s_nPartNumber = 0; @@ -475,7 +475,11 @@ list::iterator CMimeHeader::FindField(const char* pszFieldName) #include #else #if !defined(__APPLE__) && !defined(__DARWIN__) - #include + #ifndef __FreeBSD__ + #include + #else + #include + #endif #endif #endif diff --git a/src/pthreadwrapper/thread.cpp b/src/pthreadwrapper/thread.cpp index 7a4e972..d08cf33 100644 --- a/src/pthreadwrapper/thread.cpp +++ b/src/pthreadwrapper/thread.cpp @@ -9,6 +9,26 @@ namespace PThread { +void Sleep(const long ms) +{ + pthread_cond_t c; + pthread_mutex_t m; + timespec t; + timeb tb; + + pthread_mutex_init(&m,NULL); + pthread_cond_init(&c,NULL); + + ftime(&tb); + + t.tv_sec=tb.time+(ms/1000); + t.tv_nsec=((1000000L)*(long)tb.millitm)+((1000000L)*(ms%1000)); + + pthread_mutex_lock(&m); + pthread_cond_timedwait(&c,&m,&t); + pthread_mutex_unlock(&m); +} + Thread::Thread() { m_running=false; diff --git a/src/threadcontroller.cpp b/src/threadcontroller.cpp index 8bfb7b5..48984e8 100644 --- a/src/threadcontroller.cpp +++ b/src/threadcontroller.cpp @@ -39,7 +39,7 @@ void ThreadController::ReadConfig() } tempval=""; - Option::Instance()->Get("StartHHTP",tempval); + Option::Instance()->Get("StartHTTP",tempval); if(tempval=="true") { m_starthttp=true; @@ -53,6 +53,7 @@ void ThreadController::ReadConfig() void ThreadController::RestartThreads() { + m_log->WriteLog(LogFile::LOGLEVEL_INFO,"ThreadController::RestartThreads restarting threads."); ShutdownThreads(); StartThreads(); } @@ -61,6 +62,7 @@ void ThreadController::ShutdownFreenetThread() { if(m_freenetthread) { + m_log->WriteLog(LogFile::LOGLEVEL_INFO,"ThreadController::ShutdownFreenetThread shutting down Freenet thread."); m_freenetthread->Cancel(); m_freenetthread->Join(); delete m_freenetthread; @@ -72,6 +74,7 @@ void ThreadController::ShutdownHTTPThread() { if(m_httpthread) { + m_log->WriteLog(LogFile::LOGLEVEL_INFO,"ThreadController::ShutdownHTTPThread shutting down HTTP thread."); m_httpthread->Cancel(); m_httpthread->Join(); delete m_httpthread; @@ -83,6 +86,7 @@ void ThreadController::ShutdownNNTPThread() { if(m_nntpthread) { + m_log->WriteLog(LogFile::LOGLEVEL_INFO,"ThreadController::ShutdownNNTPThread shutting down NNTP thread."); m_nntpthread->Cancel(); m_nntpthread->Join(); delete m_nntpthread; @@ -99,16 +103,19 @@ void ThreadController::ShutdownThreads() void ThreadController::StartFreenetThread() { + m_log->WriteLog(LogFile::LOGLEVEL_INFO,"ThreadController::StartFreenetThread starting Freenet thread."); m_freenetthread=new PThread::Thread(new FreenetMasterThread()); } void ThreadController::StartHTTPThread() { + m_log->WriteLog(LogFile::LOGLEVEL_INFO,"ThreadController::StartHTTPThread starting HTTP thread."); m_httpthread=new PThread::Thread(new HTTPThread()); } void ThreadController::StartNNTPThread() { + m_log->WriteLog(LogFile::LOGLEVEL_INFO,"ThreadController::StartNNTPThread starting NNTP thread."); m_nntpthread=new PThread::Thread(new NNTPListener()); } -- 2.7.4
NameLocal Message TrustPeer Message TrustLocal Trust List TrustPeer Trust List Trust
"; content+=""; + content+=""; if(name!="") { content+=SanitizeOutput(name+keypart)+"..."; @@ -121,6 +157,7 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s { content+="[Unknown Name]"; } + content+=""; content+=""; content+=""; @@ -146,7 +183,7 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s if(startrow>0) { StringFunctions::Convert(startrow-rowsperpage,tempstr); - content+="<-- Previous Page<-- Previous PageNext Page -->