version 0.1.9
authorSomeDude <SomeDude@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw>
Tue, 5 Feb 2008 16:56:00 +0000 (17:56 +0100)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Tue, 5 Feb 2008 16:56:00 +0000 (17:56 +0100)
47 files changed:
CMakeLists.txt
include/datetime.h
include/freenet/iindexrequester.h
include/freenet/introductionpuzzleremover.h [deleted file]
include/freenet/messagelistxml.h
include/freenet/periodicdbmaintenance.h [new file with mode: 0644]
include/freenet/trustlistxml.h
include/global.h
include/http/ipagehandler.h
include/http/pages/controlboardpage.h [new file with mode: 0644]
include/message.h
include/nntp/nntplistener.h
include/pthreadwrapper.h
include/pthreadwrapper/thread.h
include/pthreadwrapper/threadedexecutor.h [new file with mode: 0644]
include/threadcontroller.h [new file with mode: 0644]
src/base64.cpp
src/datetime.cpp
src/db/sqlite3statement.cpp
src/freenet/fcpv2.cpp
src/freenet/freenetmasterthread.cpp
src/freenet/identityintroductionxml.cpp
src/freenet/identityxml.cpp
src/freenet/introductionpuzzleremover.cpp [deleted file]
src/freenet/introductionpuzzlerequester.cpp
src/freenet/introductionpuzzlexml.cpp
src/freenet/messagerequester.cpp
src/freenet/messagexml.cpp
src/freenet/periodicdbmaintenance.cpp [new file with mode: 0644]
src/freenet/trustlistinserter.cpp
src/freenet/trustlistrequester.cpp
src/global.cpp
src/http/httpthread.cpp
src/http/ipagehandler.cpp
src/http/pages/announceidentitypage.cpp
src/http/pages/controlboardpage.cpp [new file with mode: 0644]
src/http/pages/localidentitiespage.cpp
src/http/pages/peertrustpage.cpp
src/main.cpp
src/message.cpp
src/nntp/mime/Mime.cpp
src/nntp/nntpconnection.cpp
src/nntp/nntplistener.cpp
src/pthreadwrapper/thread.cpp
src/pthreadwrapper/threadedexecutor.cpp [new file with mode: 0644]
src/threadcontroller.cpp [new file with mode: 0644]
template.htm

index 8c79cce..3135915 100644 (file)
@@ -15,6 +15,7 @@ src/messagelist.cpp
 src/option.cpp\r
 src/socketdefines.cpp\r
 src/stringfunctions.cpp\r
+src/threadcontroller.cpp\r
 src/uuidgenerator.cpp\r
 src/db/sqlite3db.cpp\r
 src/db/sqlite3recordset.cpp\r
@@ -29,7 +30,6 @@ src/freenet/identityintroductionxml.cpp
 src/freenet/identityrequester.cpp\r
 src/freenet/identityxml.cpp\r
 src/freenet/introductionpuzzleinserter.cpp\r
-src/freenet/introductionpuzzleremover.cpp\r
 src/freenet/introductionpuzzlerequester.cpp\r
 src/freenet/introductionpuzzlexml.cpp\r
 src/freenet/messageinserter.cpp\r
@@ -38,6 +38,7 @@ src/freenet/messagelistrequester.cpp
 src/freenet/messagelistxml.cpp\r
 src/freenet/messagerequester.cpp\r
 src/freenet/messagexml.cpp\r
+src/freenet/periodicdbmaintenance.cpp\r
 src/freenet/trustlistinserter.cpp\r
 src/freenet/trustlistrequester.cpp\r
 src/freenet/trustlistxml.cpp\r
@@ -50,6 +51,7 @@ src/http/httpthread.cpp
 src/http/ipagehandler.cpp\r
 src/http/pages/addpeerpage.cpp\r
 src/http/pages/announceidentitypage.cpp\r
+src/http/pages/controlboardpage.cpp\r
 src/http/pages/createidentitypage.cpp\r
 src/http/pages/homepage.cpp\r
 src/http/pages/localidentitiespage.cpp\r
@@ -67,6 +69,7 @@ src/pthreadwrapper/guard.cpp
 src/pthreadwrapper/mutex.cpp\r
 src/pthreadwrapper/runnable.cpp\r
 src/pthreadwrapper/thread.cpp\r
+src/pthreadwrapper/threadedexecutor.cpp\r
 src/xyssl/sha1.c\r
 )\r
 \r
index 032fe5d..c1f549f 100644 (file)
@@ -28,7 +28,7 @@ public:
        void Add(const int seconds=0, const int minutes=0, const int hours=0, const int days=0, const int months=0, const int years=0);\r
        \r
        void Set(const int year=1970, const int month=1, const int day=1, const int hour=0, const int minute=0, const int second=0);\r
-       void Set(const time_t &timet);\r
+       void SetT(const time_t &timet);\r
        void Set(const struct tm *stm);\r
        void Set(const std::string &datestring);        // method only will work with a select few basic input formats\r
        \r
index eeb8ccf..7f02763 100644 (file)
@@ -135,7 +135,7 @@ template <class IDTYPE>
 void IIndexRequester<IDTYPE>::Process()\r
 {\r
        // max is the smaller of the config value or the total number of ids we will request from\r
-       long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;\r
+       typename std::map<IDTYPE,bool>::size_type max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;\r
 \r
        // try to keep up to max requests going\r
        if(m_requesting.size()<max)\r
diff --git a/include/freenet/introductionpuzzleremover.h b/include/freenet/introductionpuzzleremover.h
deleted file mode 100644 (file)
index 65fa39d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef _introductionpuzzleremover_\r
-#define _introductionpuzzleremover_\r
-\r
-#include "../idatabase.h"\r
-#include "../ilogger.h"\r
-#include "../datetime.h"\r
-#include "ifreenetregistrable.h"\r
-#include "iperiodicprocessor.h"\r
-\r
-/**\r
-       \brief Removes stale IntroductionPuzzles from database\r
-*/\r
-class IntroductionPuzzleRemover:public IFreenetRegistrable,public IPeriodicProcessor,public IDatabase,public ILogger\r
-{\r
-public:\r
-       IntroductionPuzzleRemover();\r
-\r
-       void Process();\r
-\r
-       void RegisterWithThread(FreenetMasterThread *thread);\r
-\r
-private:\r
-\r
-       DateTime m_lastchecked;\r
-\r
-};\r
-\r
-#endif // _introductionpuzzleremover_\r
index 54d4998..3d3f993 100644 (file)
@@ -7,6 +7,14 @@
 \r
 class MessageListXML:public IFMSXMLDocument\r
 {\r
+private:\r
+       struct message\r
+       {\r
+               message(const std::string &date, const long index, const std::vector<std::string> &boards):m_date(date),m_index(index),m_boards(boards) {}\r
+               std::string m_date;\r
+               long m_index;\r
+               std::vector<std::string> m_boards;\r
+       };\r
 public:\r
        MessageListXML();\r
 \r
@@ -17,20 +25,12 @@ public:
 \r
        void AddMessage(const std::string &date, const long index, const std::vector<std::string> boards);\r
 \r
-       const long MessageCount()       { return m_messages.size(); }\r
+       const std::vector<message>::size_type MessageCount()    { return m_messages.size(); }\r
        std::string GetDate(const long index);\r
        const long GetIndex(const long index);\r
        std::vector<std::string> GetBoards(const long index);\r
 \r
 private:\r
-       struct message\r
-       {\r
-               message(const std::string &date, const long index, const std::vector<std::string> &boards):m_date(date),m_index(index),m_boards(boards) {}\r
-               std::string m_date;\r
-               long m_index;\r
-               std::vector<std::string> m_boards;\r
-       };\r
-\r
        void Initialize();\r
 \r
        std::vector<message> m_messages;\r
diff --git a/include/freenet/periodicdbmaintenance.h b/include/freenet/periodicdbmaintenance.h
new file mode 100644 (file)
index 0000000..cf80285
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _periodicdbmaintenance_\r
+#define _periodicdbmaintenance_\r
+\r
+#include "../idatabase.h"\r
+#include "../ilogger.h"\r
+#include "../datetime.h"\r
+#include "ifreenetregistrable.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+class PeriodicDBMaintenance:public IFreenetRegistrable,public IPeriodicProcessor,public IDatabase,public ILogger\r
+{\r
+public:\r
+       PeriodicDBMaintenance();\r
+\r
+       void Process();\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+\r
+private:\r
+       void Do10MinuteMaintenance();\r
+       void Do30MinuteMaintenance();\r
+       void Do1HourMaintenance();\r
+       void Do6HourMaintenance();\r
+       void Do1DayMaintenance();\r
+\r
+       DateTime m_check10mins;\r
+       DateTime m_check30mins;\r
+       DateTime m_check1hour;\r
+       DateTime m_check6hours;\r
+       DateTime m_check1day;\r
+       \r
+};\r
+\r
+#endif // _periodicdbmaintenance_\r
index bd66c02..ad09e60 100644 (file)
@@ -8,6 +8,14 @@
 \r
 class TrustListXML:public IFMSXMLDocument,public ILogger\r
 {\r
+private:\r
+       struct trust\r
+       {\r
+               trust(const std::string &identity, const long messagetrust, const long trustlisttrust):m_identity(identity),m_messagetrust(messagetrust),m_trustlisttrust(trustlisttrust) {}\r
+               std::string m_identity;\r
+               long m_messagetrust;\r
+               long m_trustlisttrust;\r
+       };\r
 public:\r
        TrustListXML();\r
 \r
@@ -19,20 +27,12 @@ public:
 \r
        void AddTrust(const std::string &identity, const long messagetrust, const long trustlisttrust);\r
 \r
-       const long TrustCount()         { return m_trust.size(); }\r
+       const std::vector<trust>::size_type TrustCount()                { return m_trust.size(); }\r
        std::string GetIdentity(const long index);\r
        long GetMessageTrust(const long index);\r
        long GetTrustListTrust(const long index);\r
 \r
 private:\r
-       struct trust\r
-       {\r
-               trust(const std::string &identity, const long messagetrust, const long trustlisttrust):m_identity(identity),m_messagetrust(messagetrust),m_trustlisttrust(trustlisttrust) {}\r
-               std::string m_identity;\r
-               long m_messagetrust;\r
-               long m_trustlisttrust;\r
-       };\r
-\r
        void Initialize();\r
 \r
        std::vector<trust> m_trust;\r
index 889530d..ba827c4 100644 (file)
@@ -5,7 +5,7 @@
 //#include <zthread/Thread.h>\r
 #include "pthreadwrapper/thread.h"\r
 \r
-#define FMS_VERSION    "0.1.8"\r
+#define FMS_VERSION    "0.1.9"\r
 \r
 // opens database and creates tables and initial inserts if necessary\r
 void SetupDB();\r
index 313aa56..be707e5 100644 (file)
@@ -22,8 +22,6 @@ public:
        const bool Handle(shttpd_arg *arg);\r
 \r
 private:\r
-       void HandlePost(shttpd_arg *arg);\r
-       void HadleGet(shttpd_arg *arg);\r
        virtual const bool WillHandleURI(const std::string &uri)=0;\r
        virtual const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)=0;\r
        \r
@@ -31,6 +29,9 @@ protected:
        // converts from basename[#] query args into a vector where the vector pos is the index pos #\r
        void CreateArgArray(const std::map<std::string,std::string> &vars, const std::string &basename, std::vector<std::string> &args);\r
 \r
+       // replaces html control characters with elements (i.e. < becomes &lt;)\r
+       const std::string SanitizeOutput(const std::string &input);\r
+\r
        std::string m_template;\r
 \r
 };\r
diff --git a/include/http/pages/controlboardpage.h b/include/http/pages/controlboardpage.h
new file mode 100644 (file)
index 0000000..6471ada
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _controlboardpage_\r
+#define _controlboardpage_\r
+\r
+#include "../ipagehandler.h"\r
+#include "../../idatabase.h"\r
+\r
+class ControlBoardPage:public IPageHandler,public IDatabase\r
+{\r
+public:\r
+       ControlBoardPage(const std::string &templatestr):IPageHandler(templatestr)      {}\r
+\r
+private:\r
+       const bool WillHandleURI(const std::string &uri);\r
+       const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
+};\r
+\r
+#endif // _controlboardpage_\r
index 1fe1216..f30f33b 100644 (file)
@@ -44,10 +44,15 @@ public:
        \r
        const bool ParseNNTPMessage(const std::string &nntpmessage);\r
 \r
+       const bool PostedToAdministrationBoard()                { return CheckForAdministrationBoard(m_boards); }\r
+\r
        void StartFreenetInsert();\r
+       void HandleAdministrationMessage();\r
 \r
 private:\r
        void Initialize();\r
+       // checks vector of boards for any special administration boards - if it finds one true is returned, otherwise false\r
+       const bool CheckForAdministrationBoard(const std::vector<std::string> &boards);\r
 \r
        long m_messageid;\r
        std::string m_messageuuid;\r
index e109137..4e4d1ca 100644 (file)
@@ -8,6 +8,7 @@
 //#include <zthread/ZThread.h>\r
 //#include <zthread/ThreadedExecutor.h>\r
 #include "../pthreadwrapper/runnable.h"\r
+#include "../pthreadwrapper/threadedexecutor.h"\r
 \r
 #include "../socketdefines.h"\r
 \r
@@ -28,7 +29,8 @@ private:
        unsigned short m_listenport;\r
        std::vector<SOCKET> m_listensockets;\r
        //ZThread::ThreadedExecutor m_connections;\r
-       std::vector<PThread::Thread *> m_connectionthreads;\r
+       //std::vector<PThread::Thread *> m_connectionthreads;\r
+       PThread::ThreadedExecutor m_connections;\r
 \r
 };\r
 \r
index 0fc6afe..76a9f09 100644 (file)
@@ -15,6 +15,7 @@ namespace PThread
        class Guard;\r
        class Runnable;\r
        class Thread;\r
+       class ThreadedExecutor;\r
 \r
 }      // namespace\r
 \r
@@ -24,5 +25,6 @@ namespace PThread
 #include "pthreadwrapper/runnable.h"\r
 #include "pthreadwrapper/thread.h"\r
 #include "pthreadwrapper/singleton.h"\r
+#include "pthreadwrapper/threadedexecutor.h"\r
 \r
 #endif // _pthread_wrapper_\r
index 18e731e..c1db10a 100644 (file)
@@ -29,6 +29,7 @@ private:
        static void *EntryPoint(void *pthis);\r
 \r
        pthread_t m_thread;\r
+       int m_threadnum;\r
        bool m_running;                         // thread (object) is currently running\r
        bool m_cancelled;\r
        Runnable *m_runnable;           // actual object that is being run\r
diff --git a/include/pthreadwrapper/threadedexecutor.h b/include/pthreadwrapper/threadedexecutor.h
new file mode 100644 (file)
index 0000000..ae488e9
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _pthread_threadedexecutor_\r
+#define _pthread_threadedexecutor_\r
+\r
+#include "noncopyable.h"\r
+#include "runnable.h"\r
+#include <vector>\r
+\r
+namespace PThread\r
+{\r
+\r
+class ThreadedExecutor:public NonCopyable\r
+{\r
+public:\r
+       ThreadedExecutor()              {}\r
+       ~ThreadedExecutor();\r
+\r
+       void Execute(Runnable *runnable);\r
+       \r
+       void Join();\r
+       void Cancel();\r
+\r
+private:\r
+       void CleanupFinished();\r
+       \r
+       std::vector<Thread *> m_threads;\r
+};\r
+\r
+}\r
+\r
+#endif // _pthread_threadedexecutor_\r
diff --git a/include/threadcontroller.h b/include/threadcontroller.h
new file mode 100644 (file)
index 0000000..d1190c8
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _threadcontroller_\r
+#define _threadcontroller_\r
+\r
+#include "pthreadwrapper/thread.h"\r
+#include "pthreadwrapper/singleton.h"\r
+\r
+class ThreadController:public PThread::Singleton<ThreadController>\r
+{\r
+public:\r
+       ThreadController():m_freenetthread(NULL),m_httpthread(NULL),m_nntpthread(NULL)          {}\r
+       ~ThreadController();\r
+\r
+       void StartThreads();\r
+       void ShutdownThreads();\r
+       void RestartThreads();\r
+\r
+       void StartFreenetThread();\r
+       void StartHTTPThread();\r
+       void StartNNTPThread();\r
+\r
+       void ShutdownFreenetThread();\r
+       void ShutdownHTTPThread();\r
+       void ShutdownNNTPThread();\r
+\r
+private:\r
+       void ReadConfig();\r
+\r
+       bool m_startfreenet;\r
+       bool m_starthttp;\r
+       bool m_startnntp;\r
+\r
+       PThread::Thread *m_freenetthread;\r
+       PThread::Thread *m_httpthread;\r
+       PThread::Thread *m_nntpthread;\r
+\r
+};\r
+\r
+#endif // _threadcontroller_\r
index 06491fc..a31a701 100644 (file)
@@ -13,6 +13,8 @@ const bool Encode(const std::vector<unsigned char> &data, std::string &encoded)
 {\r
        std::vector<unsigned char>::size_type currentdatapos=0;\r
 \r
+       //reserve space for encoded data 4*input/3\r
+       encoded.reserve((4L*data.size())/3L);\r
        while(currentdatapos<data.size())\r
        {\r
                encoded.push_back(base64chars[(data[currentdatapos]>>2 & 0x3F)]);\r
@@ -46,6 +48,12 @@ const bool Decode(const std::string &encoded, std::vector<unsigned char> &data)
        std::string::size_type encodedpos=0;\r
        unsigned char currentbyte=0;\r
 \r
+       // reserve space for decoded data (encoded size*3/4)\r
+       if(encoded.size()>1)\r
+       {\r
+               data.reserve((encoded.size()*3)/4);\r
+       }\r
+\r
        // loop while encoded pos fits in current size\r
        while(encodedpos+3<encoded.size())\r
        {\r
index 9e1a7f8..f2d85e9 100644 (file)
@@ -14,7 +14,7 @@ DateTime::DateTime()
 \r
 DateTime::DateTime(const time_t &timet)\r
 {\r
-       Set(timet);\r
+       SetT(timet);\r
 }\r
 \r
 DateTime::DateTime(const struct tm *stm)\r
@@ -199,7 +199,7 @@ void DateTime::Set(const int year, const int month, const int day, const int hou
        Normalize();\r
 }\r
 \r
-void DateTime::Set(const time_t &timet)\r
+void DateTime::SetT(const time_t &timet)\r
 {\r
        m_timet=timet;\r
 \r
@@ -218,7 +218,7 @@ void DateTime::Set(const std::string &datestring)
 {\r
        int year,month,day,hour,minute,second;\r
        std::vector<std::string> tokens;\r
-       int vecpos;\r
+       std::vector<std::string>::size_type vecpos;\r
        int tempint;\r
 \r
        year=month=day=hour=minute=second=-1;\r
index 60762f0..683e771 100644 (file)
@@ -15,6 +15,7 @@ Statement::Statement()
        m_parametercount=0;\r
        m_resultcolumncount=0;\r
        m_rowreturned=false;\r
+       m_lastinsertrowid=-1;\r
 }\r
 \r
 Statement::Statement(sqlite3_stmt *statement)\r
@@ -23,6 +24,7 @@ Statement::Statement(sqlite3_stmt *statement)
        m_parametercount=sqlite3_bind_parameter_count(m_statement);\r
        m_resultcolumncount=sqlite3_column_count(m_statement);\r
        m_rowreturned=false;\r
+       m_lastinsertrowid=-1;\r
        \r
        if(m_statement)\r
        {\r
@@ -36,6 +38,7 @@ Statement::Statement(const Statement &rhs)
        m_parametercount=0;\r
        m_resultcolumncount=0;\r
        m_rowreturned=false;\r
+       m_lastinsertrowid=-1;\r
        *this=rhs;\r
 }\r
 \r
index fdc83fb..81d706c 100644 (file)
@@ -127,7 +127,7 @@ const bool FCPv2::Disconnect()
 int FCPv2::FindOnReceiveBuffer(const char *text)\r
 {\r
        bool found;\r
-       int i,j;\r
+       std::vector<char>::size_type i,j;\r
        size_t tlen=strlen(text);\r
 \r
        if(m_receivebuffer.size()>=tlen)\r
@@ -292,9 +292,9 @@ const int FCPv2::SendMessage(const char *messagename, const int fieldcount, ...)
        va_list args;\r
        const char *field;\r
        const char *val;\r
-       int bytecount=0;\r
+       std::vector<char>::size_type bytecount=0;\r
        int i;\r
-       int startlen;\r
+       std::vector<char>::size_type startlen;\r
 \r
        startlen=m_sendbuffer.size();\r
 \r
@@ -325,8 +325,8 @@ const int FCPv2::SendMessage(const char *messagename, const int fieldcount, ...)
 \r
 const int FCPv2::SendMessage(FCPMessage &message)\r
 {\r
-       int bytecount=0;\r
-       int startlen;\r
+       std::vector<char>::size_type bytecount=0;\r
+       std::vector<char>::size_type startlen;\r
        FCPMessage::iterator i;\r
 \r
        startlen=m_sendbuffer.size();\r
index 9f127a0..a9f2391 100644 (file)
@@ -8,7 +8,6 @@
 #include "../../include/freenet/introductionpuzzleinserter.h"\r
 #include "../../include/freenet/identityintroductionrequester.h"\r
 #include "../../include/freenet/introductionpuzzlerequester.h"\r
-#include "../../include/freenet/introductionpuzzleremover.h"\r
 #include "../../include/freenet/identityintroductioninserter.h"\r
 #include "../../include/freenet/trustlistinserter.h"\r
 #include "../../include/freenet/trustlistrequester.h"\r
@@ -16,6 +15,7 @@
 #include "../../include/freenet/messagerequester.h"\r
 #include "../../include/freenet/messageinserter.h"\r
 #include "../../include/freenet/messagelistinserter.h"\r
+#include "../../include/freenet/periodicdbmaintenance.h"\r
 \r
 //#include <zthread/Thread.h>\r
 #include "../../include/pthreadwrapper/thread.h"\r
@@ -247,7 +247,6 @@ void FreenetMasterThread::Setup()
        m_registrables.push_back(new IntroductionPuzzleInserter(&m_fcp));\r
        m_registrables.push_back(new IdentityIntroductionRequester(&m_fcp));\r
        m_registrables.push_back(new IntroductionPuzzleRequester(&m_fcp));\r
-       m_registrables.push_back(new IntroductionPuzzleRemover());\r
        m_registrables.push_back(new IdentityIntroductionInserter(&m_fcp));\r
        m_registrables.push_back(new TrustListInserter(&m_fcp));\r
        m_registrables.push_back(new TrustListRequester(&m_fcp));\r
@@ -255,6 +254,7 @@ void FreenetMasterThread::Setup()
        m_registrables.push_back(new MessageRequester(&m_fcp));\r
        m_registrables.push_back(new MessageInserter(&m_fcp));\r
        m_registrables.push_back(new MessageListInserter(&m_fcp));\r
+       m_registrables.push_back(new PeriodicDBMaintenance());\r
 \r
        for(std::vector<IFreenetRegistrable *>::iterator i=m_registrables.begin(); i!=m_registrables.end(); i++)\r
        {\r
index c8594f0..29e1409 100644 (file)
@@ -40,7 +40,6 @@ const bool IdentityIntroductionXML::ParseXML(const std::string &xml)
 \r
        if(!td.Error())\r
        {\r
-               TiXmlElement *el;\r
                TiXmlText *txt;\r
                TiXmlHandle hnd(&td);\r
 \r
index b2b33c7..f4e8c54 100644 (file)
@@ -48,7 +48,6 @@ const bool IdentityXML::ParseXML(const std::string &xml)
 \r
        if(!td.Error())\r
        {\r
-               TiXmlElement *el;\r
                TiXmlText *txt;\r
                TiXmlHandle hnd(&td);\r
 \r
diff --git a/src/freenet/introductionpuzzleremover.cpp b/src/freenet/introductionpuzzleremover.cpp
deleted file mode 100644 (file)
index 5650a6f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "../../include/freenet/introductionpuzzleremover.h"\r
-\r
-#ifdef XMEM\r
-       #include <xmem.h>\r
-#endif\r
-\r
-IntroductionPuzzleRemover::IntroductionPuzzleRemover()\r
-{\r
-       m_lastchecked.SetToGMTime();\r
-}\r
-\r
-void IntroductionPuzzleRemover::Process()\r
-{\r
-       DateTime now;\r
-       DateTime date;\r
-       now.SetToGMTime();\r
-       date.SetToGMTime();\r
-\r
-       // check once a day\r
-       if(m_lastchecked<(now-1.0))\r
-       {\r
-\r
-               date.Add(0,0,0,-2);\r
-\r
-               // delete all puzzles 2 or more days old\r
-               m_db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
-               m_db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
-\r
-               m_lastchecked=now;\r
-       }\r
-}\r
-\r
-void IntroductionPuzzleRemover::RegisterWithThread(FreenetMasterThread *thread)\r
-{\r
-       thread->RegisterPeriodicProcessor(this);\r
-}\r
index 44c165a..4f85e7a 100644 (file)
@@ -188,11 +188,21 @@ void IntroductionPuzzleRequester::PopulateIDList()
 {\r
        DateTime now;\r
        int id;\r
+       std::string limitnum="30";\r
+\r
+       // if we don't have an identity that we haven't seen yet, then set limit to 5\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT tblLocalIdentity.LocalIdentityID FROM tblLocalIdentity LEFT JOIN tblIdentity ON tblLocalIdentity.PublicKey=tblIdentity.PublicKey WHERE tblIdentity.IdentityID IS NULL;");\r
+       st.Step();\r
+       if(!st.RowReturned())\r
+       {\r
+               limitnum="5";\r
+       }\r
+       st.Finalize();\r
 \r
        now.SetToGMTime();\r
 \r
-       // select identities that aren't single use and have been seen today\r
-       SQLite3DB::Statement 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")+"';");\r
+       // select identities that aren't single use and have been seen today ( order by trust DESC and limit to limitnum )\r
+       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+";");\r
        st.Step();\r
 \r
        m_ids.clear();\r
index b701305..348b7ca 100644 (file)
@@ -47,7 +47,6 @@ const bool IntroductionPuzzleXML::ParseXML(const std::string &xml)
 \r
        if(!td.Error())\r
        {\r
-               TiXmlElement *el;\r
                TiXmlText *txt;\r
                TiXmlHandle hnd(&td);\r
 \r
index c9908a5..980e688 100644 (file)
@@ -78,6 +78,7 @@ const bool MessageRequester::HandleAllData(FCPMessage &message)
        MessageXML xml;\r
        long identityid;\r
        long index;\r
+       bool inserted=false;\r
 \r
        StringFunctions::Split(message["Identifier"],"|",idparts);\r
        StringFunctions::Convert(message["DataLength"],datalength);\r
@@ -133,32 +134,41 @@ const bool MessageRequester::HandleAllData(FCPMessage &message)
                st.Bind(5,xml.GetMessageID());\r
                st.Bind(6,GetBoardID(xml.GetReplyBoard()));\r
                st.Bind(7,xml.GetBody());\r
-               st.Step(true);\r
+               inserted=st.Step(true);\r
                int messageid=st.GetLastInsertRowID();\r
 \r
-               st=m_db->Prepare("INSERT INTO tblMessageBoard(MessageID,BoardID) VALUES(?,?);");\r
-               for(std::vector<std::string>::iterator i=boards.begin(); i!=boards.end(); i++)\r
+               if(inserted==true)\r
                {\r
-                       st.Bind(0,messageid);\r
-                       st.Bind(1,GetBoardID((*i)));\r
-                       st.Step();\r
-                       st.Reset();\r
-               }\r
-               st.Finalize();\r
 \r
-               st=m_db->Prepare("INSERT INTO tblMessageReplyTo(MessageID,ReplyToMessageUUID,ReplyOrder) VALUES(?,?,?);");\r
-               std::map<long,std::string> replyto=xml.GetInReplyTo();\r
-               for(std::map<long,std::string>::iterator j=replyto.begin(); j!=replyto.end(); j++)\r
+                       st=m_db->Prepare("INSERT INTO tblMessageBoard(MessageID,BoardID) VALUES(?,?);");\r
+                       for(std::vector<std::string>::iterator i=boards.begin(); i!=boards.end(); i++)\r
+                       {\r
+                               st.Bind(0,messageid);\r
+                               st.Bind(1,GetBoardID((*i)));\r
+                               st.Step();\r
+                               st.Reset();\r
+                       }\r
+                       st.Finalize();\r
+\r
+                       st=m_db->Prepare("INSERT INTO tblMessageReplyTo(MessageID,ReplyToMessageUUID,ReplyOrder) VALUES(?,?,?);");\r
+                       std::map<long,std::string> replyto=xml.GetInReplyTo();\r
+                       for(std::map<long,std::string>::iterator j=replyto.begin(); j!=replyto.end(); j++)\r
+                       {\r
+                               st.Bind(0,messageid);\r
+                               st.Bind(1,(*j).second);\r
+                               st.Bind(2,(*j).first);\r
+                               st.Step();\r
+                               st.Reset();\r
+                       }\r
+                       st.Finalize();\r
+\r
+                       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"MessageRequester::HandleAllData parsed Message XML file : "+message["Identifier"]);\r
+\r
+               }\r
+               else    // couldn't insert - was already in database\r
                {\r
-                       st.Bind(0,messageid);\r
-                       st.Bind(1,(*j).second);\r
-                       st.Bind(2,(*j).first);\r
-                       st.Step();\r
-                       st.Reset();\r
+                       m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAddData could not insert message into database.  "+message["Identifier"]);\r
                }\r
-               st.Finalize();\r
-\r
-               m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"MessageRequester::HandleAllData parsed Message XML file : "+message["Identifier"]);\r
 \r
        }\r
        else\r
@@ -301,6 +311,8 @@ void MessageRequester::StartRequest(const std::string &requestid)
                m_fcp->SendMessage(message);\r
 \r
                m_requesting.push_back(requestid);\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"MessageRequester::StartRequest requesting "+message["Identifier"]);\r
        }\r
        \r
        m_ids[requestid]=true;\r
index 90bcca7..8de3077 100644 (file)
@@ -70,7 +70,6 @@ const bool MessageXML::ParseXML(const std::string &xml)
        if(!td.Error())\r
        {\r
                TiXmlHandle hnd(&td);\r
-               TiXmlNode *node1;\r
                TiXmlNode *node2;\r
                TiXmlText *txt;\r
 \r
diff --git a/src/freenet/periodicdbmaintenance.cpp b/src/freenet/periodicdbmaintenance.cpp
new file mode 100644 (file)
index 0000000..22a4ccf
--- /dev/null
@@ -0,0 +1,99 @@
+#include "../../include/freenet/periodicdbmaintenance.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+PeriodicDBMaintenance::PeriodicDBMaintenance()\r
+{\r
+       m_check10mins.SetToGMTime();\r
+       m_check30mins.SetToGMTime();\r
+       m_check1hour.SetToGMTime();\r
+       m_check6hours.SetToGMTime();\r
+       m_check1day.SetToGMTime();\r
+\r
+       // set back times so they will do their first maintenance soon ( within the next hour ) - stagger so not all run at once\r
+       m_check1hour.Add(0,-45);\r
+       m_check6hours.Add(0,0,-5);\r
+       m_check1day.Add(0,0,-23);\r
+\r
+}\r
+\r
+void PeriodicDBMaintenance::Do10MinuteMaintenance()\r
+{\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"PeriodicDBMaintenance::Do10MinuteMaintenance");\r
+}\r
+\r
+void PeriodicDBMaintenance::Do30MinuteMaintenance()\r
+{\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"PeriodicDBMaintenance::Do30MinuteMaintenance");\r
+}\r
+\r
+void PeriodicDBMaintenance::Do1HourMaintenance()\r
+{\r
+       // recalculate all trust levels - this is CPU instensive\r
+       // TODO - will probably have to change this to do 1 identity at a time as this locks that database for the duration\r
+       m_db->Execute("UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);");\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"PeriodicDBMaintenance::Do1HourMaintenance");\r
+}\r
+\r
+void PeriodicDBMaintenance::Do6HourMaintenance()\r
+{\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"PeriodicDBMaintenance::Do6HourMaintenance");\r
+}\r
+\r
+void PeriodicDBMaintenance::Do1DayMaintenance()\r
+{\r
+       DateTime date;\r
+\r
+       // delete all puzzles 2 or more days old\r
+       date.SetToGMTime();\r
+       date.Add(0,0,0,-2);\r
+       m_db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
+       m_db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"PeriodicDBMaintenance::Do1DayMaintenance");\r
+\r
+}\r
+\r
+void PeriodicDBMaintenance::Process()\r
+{\r
+       DateTime now;\r
+       now.SetToGMTime();\r
+       \r
+       if(m_check10mins<=(now-((1.0/1440.0)*10.0)))\r
+       {\r
+               Do10MinuteMaintenance();\r
+               m_check10mins=now;\r
+       }\r
+       if(m_check30mins<=(now-((1.0/1440.0)*30.0)))\r
+       {\r
+               Do30MinuteMaintenance();\r
+               m_check30mins=now;\r
+       }\r
+       if(m_check1hour<=(now-(1.0/24.0)))\r
+       {\r
+               Do1HourMaintenance();\r
+               m_check1hour=now;\r
+       }\r
+       if(m_check6hours<=(now-(1.0/4.0)))\r
+       {\r
+               Do6HourMaintenance();\r
+               m_check6hours=now;\r
+       }\r
+       if(m_check1day<=(now-(1.0)))\r
+       {\r
+               Do1DayMaintenance();\r
+               m_check1day=now;\r
+       }\r
+\r
+}\r
+\r
+void PeriodicDBMaintenance::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
index b22453d..5f2fbb8 100644 (file)
@@ -21,7 +21,13 @@ void TrustListInserter::CheckForNeededInsert()
 {\r
        DateTime date;\r
        date.SetToGMTime();\r
-       date.Add(0,0,-1);\r
+       int currentday=date.GetDay();\r
+       date.Add(0,0,-6);\r
+       // insert trust lists every 6 hours - if 6 hours ago was different day then set to midnight of current day to insert list today ASAP\r
+       if(currentday!=date.GetDay())\r
+       {\r
+               date.Set(date.GetYear(),date.GetMonth(),currentday);\r
+       }\r
        SQLite3DB::Recordset rs=m_db->Query("SELECT LocalIdentityID, PrivateKey FROM tblLocalIdentity WHERE PrivateKey IS NOT NULL AND PrivateKey <> '' AND PublishTrustList='true' AND InsertingTrustList='false' AND (LastInsertedTrustList<='"+date.Format("%Y-%m-%d %H:%M:%S")+"' OR LastInsertedTrustList IS NULL);");\r
 \r
        if(rs.Empty()==false)\r
index 4eeaf79..3fd5d99 100644 (file)
@@ -231,7 +231,7 @@ void TrustListRequester::PopulateIDList()
        // select identities we want to query (we've seen them today and they are publishing trust list) - sort by their trust level (descending) with secondary sort on how long ago we saw them (ascending)\r
        sql="SELECT IdentityID FROM tblIdentity ";\r
        sql+="WHERE Name IS NOT NULL AND Name <> '' AND PublicKey IS NOT NULL AND PublicKey <> '' AND LastSeen>='"+date.Format("%Y-%m-%d")+"' AND PublishTrustList='true' AND LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') AND ( PeerTrustListTrust IS NULL OR PeerTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerTrustListTrust') )";\r
-       sql+="ORDER BY LocalMessageTrust+LocalTrustListTrust DESC, LastSeen;";\r
+       sql+="ORDER BY LocalTrustListTrust DESC, LastSeen;";\r
 \r
        SQLite3DB::Statement st=m_db->Prepare(sql);\r
        st.Step();\r
index 0437eb4..a3c8111 100644 (file)
@@ -25,6 +25,28 @@ void SetupDB()
        db->Open("fms.db3");\r
        db->SetBusyTimeout(10000);              // set timeout to 10 seconds\r
        db->Execute("VACUUM;");\r
+       \r
+       // TODO remove this - temp fix for problem in 0.1.8\r
+       db->Execute("DELETE FROM tblMessageBoard WHERE MessageID NOT IN (SELECT MessageID FROM tblMessage);");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblDBVersion(\\r
+                               Major                           INTEGER,\\r
+                               Minor                           INTEGER\\r
+                               );");\r
+\r
+       SQLite3DB::Statement st=db->Prepare("SELECT Major,Minor FROM tblDBVersion;");\r
+       st.Step();\r
+       if(st.RowReturned())\r
+       {\r
+               int major;\r
+               int minor;\r
+               st.ResultInt(0,major);\r
+               st.ResultInt(1,minor);\r
+       }\r
+       else\r
+       {\r
+               db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,0);");\r
+       }\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\\r
                                Option                          TEXT UNIQUE,\\r
@@ -197,6 +219,12 @@ void SetupDB()
                                Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
                                );");\r
 \r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblAdministrationBoard(\\r
+                               BoardID                                         INTEGER UNIQUE,\\r
+                               ModifyLocalMessageTrust         INTEGER,\\r
+                               ModifyLocalTrustListTrust       INTEGER\\r
+                               );");\r
+\r
        // MessageInserter will insert a record into this temp table which the MessageListInserter will query for and insert a MessageList when needed\r
        db->Execute("CREATE TEMPORARY TABLE IF NOT EXISTS tmpMessageListInsert(\\r
                                LocalIdentityID         INTEGER,\\r
@@ -220,6 +248,16 @@ void SetupDB()
                                AND ( PeerTrustListTrust IS NULL OR PeerTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerTrustListTrust') ) \\r
                                GROUP BY TargetIdentityID;");\r
 \r
+       /*\r
+               These peer trust calculations are too CPU intensive to be triggers - they were called every time a new trust list was processed\r
+               All trust levels will now be recalculated every hour in the PeriodicDBMaintenance class\r
+       */\r
+       // drop existing triggers\r
+       db->Execute("DROP TRIGGER IF EXISTS trgDeleteOntblPeerTrust;");\r
+       db->Execute("DROP TRIGGER IF EXISTS trgInsertOntblPeerTrust;");\r
+       db->Execute("DROP TRIGGER IF EXISTS trgUpdateOntblPeerTrust;");\r
+       db->Execute("DROP TRIGGER IF EXISTS trgUpdateLocalTrustLevels;");\r
+/*\r
        // update PeerTrustLevel when deleting a record from tblPeerTrust\r
        db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \\r
                                FOR EACH ROW \\r
@@ -248,6 +286,7 @@ void SetupDB()
                                BEGIN \\r
                                        UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\\r
                                END;");\r
+*/\r
 \r
        db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \\r
                                FOR EACH ROW \\r
@@ -425,7 +464,7 @@ void SetupDefaultOptions()
        st.Reset();\r
 \r
        st.Bind(0,"MinLocalTrustListTrust");\r
-       st.Bind(1,"50");\r
+       st.Bind(1,"51");\r
        st.Bind(2,"Specifies a local trust list trust level that a peer must have before its trust list will be included in the weighted average.  Any peers below this number will be excluded from the results.");\r
        st.Step();\r
        st.Reset();\r
index 827ce28..f08ebe8 100644 (file)
@@ -9,6 +9,7 @@
 #include "../../include/http/pages/announceidentitypage.h"\r
 #include "../../include/http/pages/addpeerpage.h"\r
 #include "../../include/http/pages/peertrustpage.h"\r
+#include "../../include/http/pages/controlboardpage.h"\r
 \r
 #include <iostream>\r
 \r
@@ -50,6 +51,7 @@ HTTPThread::HTTPThread()
        m_pagehandlers.push_back(new AnnounceIdentityPage(templatestr));\r
        m_pagehandlers.push_back(new AddPeerPage(templatestr));\r
        m_pagehandlers.push_back(new PeerTrustPage(templatestr));\r
+       m_pagehandlers.push_back(new ControlBoardPage(templatestr));\r
        // homepage must be last - catch all page handler\r
        m_pagehandlers.push_back(new HomePage(templatestr));\r
 \r
index d90a927..c4ebbb9 100644 (file)
@@ -81,7 +81,7 @@ const bool IPageHandler::Handle(shttpd_arg *arg)
                // we have all POST data (or it was 0 to begin with) - generate the page\r
                if(mystate->m_indatalen==mystate->m_indatapos && mystate->m_outdata==NULL)\r
                {\r
-                       //TODO parse POST data and any QUERY_STRING before generating page\r
+                       //parse POST data and any QUERY_STRING before generating page\r
                        std::map<std::string,std::string> args;\r
                        std::vector<std::string> argparts;\r
                        \r
@@ -153,3 +153,14 @@ const bool IPageHandler::Handle(shttpd_arg *arg)
                return false;\r
        }\r
 }\r
+\r
+const std::string IPageHandler::SanitizeOutput(const std::string &input)\r
+{\r
+       // must do & first because all other elements have & in them!\r
+       std::string output=StringFunctions::Replace(input,"&","&amp;");\r
+       output=StringFunctions::Replace(output,"<","&lt;");\r
+       output=StringFunctions::Replace(output,">","&gt;");\r
+       output=StringFunctions::Replace(output,"\"","&quot;");\r
+       output=StringFunctions::Replace(output," ","&nbsp;");\r
+       return output;\r
+}\r
index 460302a..710904c 100644 (file)
@@ -84,6 +84,8 @@ const std::string AnnounceIdentityPage::GeneratePage(const std::string &method,
        content+="<tr><td colspan=\"4\"><center>Type the answers of a few puzzles</td></tr>";\r
        content+="<tr>";\r
 \r
+       //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\r
+\r
        date.SetToGMTime();\r
        date.Add(0,0,0,-1);\r
        SQLite3DB::Statement st=m_db->Prepare("SELECT UUID,Day,IdentityID FROM tblIntroductionPuzzleRequests WHERE UUID NOT IN (SELECT UUID FROM tblIdentityIntroductionInserts) AND UUID NOT IN (SELECT UUID FROM tblIntroductionPuzzleInserts) AND Day>='"+date.Format("%Y-%m-%d")+"' AND Found='true' ORDER BY IdentityID, Day DESC, RequestIndex DESC;");\r
diff --git a/src/http/pages/controlboardpage.cpp b/src/http/pages/controlboardpage.cpp
new file mode 100644 (file)
index 0000000..c50a37f
--- /dev/null
@@ -0,0 +1,130 @@
+#include "../../../include/http/pages/controlboardpage.h"\r
+#include "../../../include/stringfunctions.h"\r
+#include "../../../include/datetime.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const std::string ControlBoardPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
+{\r
+       std::string content="";\r
+       int boardid;\r
+       std::string boardidstr;\r
+       std::string boardname;\r
+       int changemessagetrust=0;\r
+       int changetrustlisttrust=0;\r
+       std::string changemessagetruststr;\r
+       std::string changetrustlisttruststr;\r
+\r
+       SQLite3DB::Statement st;\r
+\r
+       if(queryvars.find("formaction")!=queryvars.end())\r
+       {\r
+               if((*queryvars.find("formaction")).second=="remove" && queryvars.find("boardid")!=queryvars.end())\r
+               {\r
+                       int boardid=0;\r
+                       StringFunctions::Convert((*queryvars.find("boardid")).second,boardid);\r
+\r
+                       st=m_db->Prepare("DELETE FROM tblAdministrationBoard WHERE BoardID=?;");\r
+                       st.Bind(0,boardid);\r
+                       st.Step();\r
+\r
+                       st=m_db->Prepare("DELETE FROM tblBoard WHERE BoardID=?;");\r
+                       st.Bind(0,boardid);\r
+                       st.Step();\r
+\r
+                       st=m_db->Prepare("DELETE FROM tblMessage WHERE MessageUUID IN (SELECT MessageUUID FROM tblMessage INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID WHERE BoardID=?);");\r
+                       st.Bind(0,boardid);\r
+                       st.Step();\r
+\r
+                       st=m_db->Prepare("DELETE FROm tblMessageBoard WHERE BoardID=?;");\r
+                       st.Bind(0,boardid);\r
+                       st.Step();\r
+\r
+               }\r
+               if((*queryvars.find("formaction")).second=="addboard" && queryvars.find("boardname")!=queryvars.end() && (*queryvars.find("boardname")).second!="")\r
+               {\r
+                       DateTime date;\r
+                       date.SetToGMTime();\r
+                       st=m_db->Prepare("INSERT INTO tblBoard(BoardName,DateAdded) VALUES(?,?);");\r
+                       st.Bind(0,(*queryvars.find("boardname")).second);\r
+                       st.Bind(1,date.Format("%Y-%m-%d %H:%M:%S"));\r
+                       if(st.Step(true))\r
+                       {\r
+                               boardid=st.GetLastInsertRowID();\r
+                               StringFunctions::Convert((*queryvars.find("changemessagetrust")).second,changemessagetrust);\r
+                               StringFunctions::Convert((*queryvars.find("changetrustlisttrust")).second,changetrustlisttrust);\r
+\r
+                               st=m_db->Prepare("INSERT INTO tblAdministrationBoard(BoardID,ModifyLocalMessageTrust,ModifyLocalTrustListTrust) VALUES(?,?,?);");\r
+                               st.Bind(0,boardid);\r
+                               st.Bind(1,changemessagetrust);\r
+                               st.Bind(2,changetrustlisttrust);\r
+                               st.Step();\r
+\r
+                       }\r
+               }\r
+       }\r
+\r
+       content+="<h2>Control Boards</h2>";\r
+       content+="<p class=\"paragraph\">";\r
+       content+="These boards are special administration boards where sent messages will change the trust levels of the parent poster.  These boards can not be used as regular boards, so make the name unique.  The change in trust levels can be negative or positive, but keep in mind that the minimum trust level is 0 and the maximum trust level is 100.  After the boards are created here, you may use your newreader to reply to a message to one or more of these boards, and the previous poster will have his trust levels changed as per the settings for that board.";\r
+       content+="</p>";\r
+\r
+       st=m_db->Prepare("SELECT tblBoard.BoardID,BoardName,ModifyLocalMessageTrust,ModifyLocalTrustListTrust FROM tblBoard INNER JOIN tblAdministrationBoard ON tblBoard.BoardID=tblAdministrationBoard.BoardID ORDER BY BoardName COLLATE NOCASE;");\r
+       st.Step();\r
+\r
+       content+="<table>";\r
+       content+="<tr><th>Board Name</th><th>Change Message Trust</th><th>Change Trust List Trust</th></tr>\r\n";\r
+       while(st.RowReturned())\r
+       {\r
+               st.ResultText(0,boardidstr);\r
+               st.ResultText(1,boardname);\r
+               st.ResultText(2,changemessagetruststr);\r
+               st.ResultText(3,changetrustlisttruststr);\r
+\r
+               content+="<tr>";\r
+               content+="<td>"+boardname+"</td>\r\n";\r
+               content+="<td>"+changemessagetruststr+"</td>\r\n";\r
+               content+="<td>"+changetrustlisttruststr+"</td>\r\n";\r
+               content+="<td>";\r
+               content+="<form name=\"frmremove\" method=\"POST\">";\r
+               content+="<input type=\"hidden\" name=\"formaction\" value=\"remove\">";\r
+               content+="<input type=\"hidden\" name=\"boardid\" value=\""+boardidstr+"\">";\r
+               content+="<input type=\"submit\" value=\"Remove\">";\r
+               content+="</form>";\r
+               content+="</td>";\r
+               content+="</tr>\r\n";\r
+               st.Step();\r
+       }\r
+\r
+       content+="<tr>";\r
+       content+="<td>";\r
+       content+="<form name=\"frmaddboard\" method=\"POST\">";\r
+       content+="<input type=\"hidden\" name=\"formaction\" value=\"addboard\">";\r
+       content+="<input type=\"text\" name=\"boardname\">";\r
+       content+="</td>\r\n<td>";\r
+       content+="<input type=\"text\" name=\"changemessagetrust\" size=\"2\" maxlength=\"3\">";\r
+       content+="</td>\r\n<td>";\r
+       content+="<input type=\"text\" name=\"changetrustlisttrust\" size=\"2\" maxlength=\"3\">";\r
+       content+="</td>\r\n<td>";\r
+       content+="<input type=\"submit\" value=\"Add\">";\r
+       content+="</form>";\r
+       content+="</td>\r\n";\r
+       content+="</tr>";\r
+       content+="</table>";\r
+\r
+       return "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"+StringFunctions::Replace(m_template,"[CONTENT]",content);\r
+}\r
+\r
+const bool ControlBoardPage::WillHandleURI(const std::string &uri)\r
+{\r
+       if(uri.find("controlboard.")!=std::string::npos)\r
+       {\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
index 821339d..e926b2f 100644 (file)
@@ -94,6 +94,7 @@ const std::string LocalIdentitiesPage::GeneratePage(const std::string &method, c
                std::string publickey;\r
                std::string publishtrustlist;\r
                std::string singleuse;\r
+               std::string keypart;\r
 \r
                st.ResultText(0,id);\r
                st.ResultText(1,name);\r
@@ -101,9 +102,14 @@ const std::string LocalIdentitiesPage::GeneratePage(const std::string &method, c
                st.ResultText(3,publishtrustlist);\r
                st.ResultText(4,singleuse);\r
 \r
+               if(publickey.size()>8)\r
+               {\r
+                       keypart=publickey.substr(3,5);\r
+               }\r
+\r
                content+="<tr>";\r
                content+="<td><input type=\"checkbox\" name=\"chkidentityid["+countstr+"]\" value=\""+id+"\"></td>";\r
-               content+="<td title=\""+publickey+"\">"+name+"</td>";\r
+               content+="<td title=\""+publickey+"\">"+SanitizeOutput(name+keypart)+"...</td>";\r
                content+="<td>"+CreateTrueFalseDropDown("singleuse["+countstr+"]",singleuse)+"</td>";\r
                content+="<td>"+CreateTrueFalseDropDown("publishtrustlist["+countstr+"]",publishtrustlist)+"</td>";\r
                if(st.ResultNull(6))\r
index 4a451ed..b353243 100644 (file)
@@ -93,6 +93,7 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s
                std::string localtrustlisttrust;\r
                std::string peertrustlisttrust;\r
                std::string publickey;\r
+               std::string keypart="";\r
 \r
                StringFunctions::Convert(count,countstr);\r
 \r
@@ -104,12 +105,17 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s
                st.ResultText(5,peertrustlisttrust);\r
                st.ResultText(6,publickey);\r
 \r
+               if(publickey.size()>8)\r
+               {\r
+                       keypart=publickey.substr(3,5);\r
+               }\r
+\r
                content+="<tr>";\r
                content+="<td title=\""+publickey+"\">";\r
                content+="<input type=\"hidden\" name=\"identityid["+countstr+"]\" value=\""+identityid+"\">";\r
                if(name!="")\r
                {\r
-                       content+=name;\r
+                       content+=SanitizeOutput(name+keypart)+"...";\r
                }\r
                else\r
                {\r
@@ -133,7 +139,6 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s
        \r
        if(startrow>0 || startrow+rowsperpage<identitycount)\r
        {\r
-               int tempint;\r
                std::string tempstr;\r
                int cols=0;\r
 \r
index 3e135a0..8746da2 100644 (file)
@@ -21,7 +21,6 @@ int main()
        SetupDB();\r
        SetupDefaultOptions();\r
 \r
-\r
        SetupLogFile();\r
 \r
        SetupNetwork();\r
index 2cfb588..5861ef0 100644 (file)
@@ -20,6 +20,27 @@ Message::Message(const long messageid)
        Load(messageid);\r
 }\r
 \r
+const bool Message::CheckForAdministrationBoard(const std::vector<std::string> &boards)\r
+{\r
+       std::string name;\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT BoardName FROM tblBoard INNER JOIN tblAdministrationBoard ON tblBoard.BoardID=tblAdministrationBoard.BoardID;");\r
+       st.Step();\r
+       \r
+       while(st.RowReturned())\r
+       {\r
+               st.ResultText(0,name);\r
+\r
+               if(std::find(boards.begin(),boards.end(),name)!=boards.end())\r
+               {\r
+                       return true;\r
+               }\r
+               \r
+               st.Step();\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
 const std::string Message::GetNNTPArticleID() const\r
 {\r
        return "<"+m_messageuuid+"@freenetproject.org>";\r
@@ -69,6 +90,108 @@ const std::string Message::GetNNTPHeaders() const
        return rval;\r
 }\r
 \r
+void Message::HandleAdministrationMessage()\r
+{\r
+       // only continue if this message was actually a reply to another message\r
+       if(m_inreplyto.size()>0)\r
+       {\r
+               int boardid=0;\r
+               std::string boardname="";\r
+               std::string identityname="";\r
+               int identityid;\r
+               int changemessagetrust=0;\r
+               int changetrustlisttrust=0;\r
+               int origmessagetrust=0;\r
+               int origtrustlisttrust=0;\r
+               SQLite3DB::Statement st=m_db->Prepare("SELECT tblBoard.BoardID,BoardName,ModifyLocalMessageTrust,ModifyLocalTrustListTrust FROM tblBoard INNER JOIN tblAdministrationBoard ON tblBoard.BoardID=tblAdministrationBoard.BoardID;");\r
+               st.Step();\r
+\r
+               while(st.RowReturned())\r
+               {\r
+                       st.ResultInt(0,boardid);\r
+                       st.ResultText(1,boardname);\r
+                       st.ResultInt(2,changemessagetrust);\r
+                       st.ResultInt(3,changetrustlisttrust);\r
+\r
+                       if(std::find(m_boards.begin(),m_boards.end(),boardname)!=m_boards.end())\r
+                       {\r
+                               SQLite3DB::Statement origmess=m_db->Prepare("SELECT tblIdentity.IdentityID,tblIdentity.Name,tblIdentity.LocalMessageTrust,tblIdentity.LocalTrustListTrust FROM tblIdentity INNER JOIN tblMessage ON tblIdentity.IdentityID=tblMessage.IdentityID WHERE tblMessage.MessageUUID=?;");\r
+                               origmess.Bind(0,m_inreplyto[0]);\r
+                               origmess.Step();\r
+\r
+                               if(origmess.RowReturned())\r
+                               {\r
+                                       origmess.ResultInt(0,identityid);\r
+                                       origmess.ResultText(1,identityname);\r
+                                       origmess.ResultInt(2,origmessagetrust);\r
+                                       origmess.ResultInt(3,origtrustlisttrust);\r
+\r
+                                       origmessagetrust+=changemessagetrust;\r
+                                       origtrustlisttrust+=changetrustlisttrust;\r
+\r
+                                       if(origmessagetrust<0)\r
+                                       {\r
+                                               origmessagetrust=0;\r
+                                       }\r
+                                       if(origmessagetrust>100)\r
+                                       {\r
+                                               origmessagetrust=100;\r
+                                       }\r
+                                       if(origtrustlisttrust<0)\r
+                                       {\r
+                                               origtrustlisttrust=0;\r
+                                       }\r
+                                       if(origtrustlisttrust>100)\r
+                                       {\r
+                                               origtrustlisttrust=100;\r
+                                       }\r
+\r
+                                       // update new trust levels\r
+                                       SQLite3DB::Statement update=m_db->Prepare("UPDATE tblIdentity SET LocalMessageTrust=?, LocalTrustListTrust=? WHERE IdentityID=?;");\r
+                                       update.Bind(0,origmessagetrust);\r
+                                       update.Bind(1,origtrustlisttrust);\r
+                                       update.Bind(2,identityid);\r
+                                       update.Step();\r
+\r
+                                       // insert message to show what id was changed and what current levels are\r
+                                       int lastid=0;\r
+                                       std::string messagebody;\r
+                                       std::string messagetruststr="";\r
+                                       std::string trustlisttruststr="";\r
+                                       UUIDGenerator uuid;\r
+                                       DateTime now;\r
+                                       now.SetToGMTime();\r
+                                       StringFunctions::Convert(origmessagetrust,messagetruststr);\r
+                                       StringFunctions::Convert(origtrustlisttrust,trustlisttruststr);\r
+                                       messagebody="Trust Changed for "+identityname+"\r\n";\r
+                                       messagebody+="Local Message Trust : "+messagetruststr+"\r\n";\r
+                                       messagebody+="Local Trust List Trust : "+trustlisttruststr+"\r\n";\r
+                                       SQLite3DB::Statement insert=m_db->Prepare("INSERT INTO tblMessage(FromName,MessageDate,MessageTime,Subject,MessageUUID,ReplyBoardID,Body) VALUES('FMS',?,?,?,?,?,?);");\r
+                                       insert.Bind(0,now.Format("%Y-%m-%d"));\r
+                                       insert.Bind(1,now.Format("%H:%M:%S"));\r
+                                       insert.Bind(2,identityname+" Trust Changed");\r
+                                       insert.Bind(3,uuid.Generate());\r
+                                       insert.Bind(4,boardid);\r
+                                       insert.Bind(5,messagebody);\r
+                                       insert.Step(true);\r
+                                       lastid=insert.GetLastInsertRowID();\r
+\r
+                                       insert=m_db->Prepare("INSERT INTO tblMessageBoard(MessageID,BoardID) VALUES(?,?);");\r
+                                       insert.Bind(0,lastid);\r
+                                       insert.Bind(1,boardid);\r
+                                       insert.Step();\r
+\r
+                                       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"Message::HandleAdministrationMessage updated "+identityname+" to "+messagetruststr+" , "+trustlisttruststr);\r
+\r
+                               }\r
+                       }\r
+\r
+                       st.Step();\r
+               }\r
+       }\r
+\r
+}\r
+\r
 void Message::Initialize()\r
 {\r
        m_messageid=-1;\r
@@ -386,6 +509,7 @@ const bool Message::ParseNNTPMessage(const std::string &nntpmessage)
 \r
 void Message::StartFreenetInsert()\r
 {\r
+       //TODO if message was posted to one of the special administration boards - don't really insert it, but perform the action\r
        MessageXML xml;\r
        int localidentityid=-1;\r
 \r
index fa20dcc..0bf826d 100644 (file)
@@ -362,7 +362,7 @@ void CMimeHeader::SetBoundary(const char* pszBoundary/*=NULL*/)
        char buf[80];\r
        if (!pszBoundary)                               // generate a new boundary delimeter\r
        {\r
-               ::srand(((unsigned)::time(NULL)) ^ (unsigned)this);\r
+               ::srand(((unsigned)::time(NULL)) ^ reinterpret_cast<unsigned>(this));\r
                ::sprintf(buf, "__=_Part_Boundary_%03d_%06d.%06d", ++s_nPartNumber, rand(), rand());\r
                if (s_nPartNumber >= 9)\r
                        s_nPartNumber = 0;\r
index d7eaa70..3fffad7 100644 (file)
@@ -387,7 +387,6 @@ const bool NNTPConnection::HandleListGroupCommand(const NNTPCommand &command)
        std::ostringstream tempstr;\r
        Board board;\r
        bool validgroup=false;\r
-       int tempint;\r
        int lownum=-1;\r
        int highnum=-1;\r
 \r
@@ -779,7 +778,14 @@ void NNTPConnection::HandlePostedMessage(const std::string &message)
 \r
        if(mess.ParseNNTPMessage(message))\r
        {\r
-               mess.StartFreenetInsert();\r
+               if(mess.PostedToAdministrationBoard()==true)\r
+               {\r
+                       mess.HandleAdministrationMessage();\r
+               }\r
+               else\r
+               {\r
+                       mess.StartFreenetInsert();\r
+               }\r
                SendBufferedLine("240 Article received OK");\r
        }\r
        else\r
index cfb72d7..7f6e469 100644 (file)
@@ -75,11 +75,12 @@ void NNTPListener::Run()
                                        newsock=accept((*listeni),(struct sockaddr *)&addr,&addrlen);\r
                                        LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPListener::run NNTP client connected");\r
                                        //m_connections.execute(new NNTPConnection(newsock));\r
-                                       m_connectionthreads.push_back(new PThread::Thread(new NNTPConnection(newsock)));\r
+                                       //m_connectionthreads.push_back(new PThread::Thread(new NNTPConnection(newsock)));\r
+                                       m_connections.Execute(new NNTPConnection(newsock));\r
                                }\r
                        }\r
                }\r
-\r
+/*\r
                // check for any non-running connection threads that we can delete\r
                for(std::vector<PThread::Thread *>::iterator i=m_connectionthreads.begin(); i!=m_connectionthreads.end(); )\r
                {\r
@@ -93,6 +94,7 @@ void NNTPListener::Run()
                                i++;\r
                        }\r
                }\r
+*/\r
 \r
        //}while(!ZThread::Thread::interrupted() && m_listensockets.size()>0);\r
        }while(!IsCancelled() && m_listensockets.size()>0);\r
@@ -116,6 +118,7 @@ void NNTPListener::Run()
                }\r
        }\r
        */\r
+       /*\r
        for(std::vector<PThread::Thread *>::iterator i=m_connectionthreads.begin(); i!=m_connectionthreads.end(); i++)\r
        {\r
                if((*i)->IsRunning())\r
@@ -126,6 +129,9 @@ void NNTPListener::Run()
                }\r
                delete (*i);\r
        }\r
+       */\r
+       m_connections.Cancel();\r
+       m_connections.Join();\r
 \r
        for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
        {\r
index 466dd5c..7a4e972 100644 (file)
@@ -14,6 +14,7 @@ Thread::Thread()
        m_running=false;\r
        m_cancelled=false;\r
        m_runnable=0;\r
+       m_threadnum=0;\r
 }\r
 \r
 Thread::Thread(Runnable *runnable)\r
@@ -21,6 +22,7 @@ Thread::Thread(Runnable *runnable)
        m_running=false;\r
        m_cancelled=false;\r
        m_runnable=runnable;\r
+       m_threadnum=0;\r
        if(m_runnable)\r
        {\r
                m_runnable->m_thread=this;\r
@@ -54,6 +56,7 @@ void *Thread::EntryPoint(void *pthis)
                ((Thread *)pthis)->m_running=false;\r
                ((Thread *)pthis)->m_cancelled=false;\r
        }\r
+       ((Thread *)pthis)->m_threadnum=0;\r
        return NULL;\r
 }\r
 \r
@@ -91,7 +94,7 @@ void Thread::Sleep(const long ms)
 void Thread::Start()\r
 {\r
        m_running=true;\r
-       pthread_create(&m_thread,NULL,Thread::EntryPoint,this);\r
+       m_threadnum=pthread_create(&m_thread,NULL,Thread::EntryPoint,this);\r
 }\r
 \r
 }      // namespace\r
diff --git a/src/pthreadwrapper/threadedexecutor.cpp b/src/pthreadwrapper/threadedexecutor.cpp
new file mode 100644 (file)
index 0000000..52377b5
--- /dev/null
@@ -0,0 +1,59 @@
+#include "../../include/pthreadwrapper/threadedexecutor.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+namespace PThread\r
+{\r
+\r
+ThreadedExecutor::~ThreadedExecutor()\r
+{\r
+       for(std::vector<Thread *>::iterator i=m_threads.begin(); i!=m_threads.end(); i++)\r
+       {\r
+               (*i)->Cancel();\r
+               (*i)->Join();\r
+               delete (*i);\r
+       }\r
+}\r
+\r
+void ThreadedExecutor::Cancel()\r
+{\r
+       for(std::vector<Thread *>::iterator i=m_threads.begin(); i!=m_threads.end(); i++)\r
+       {\r
+               (*i)->Cancel(); \r
+       }\r
+}\r
+\r
+void ThreadedExecutor::CleanupFinished()\r
+{\r
+       for(std::vector<Thread *>::iterator i=m_threads.begin(); i!=m_threads.end(); )\r
+       {\r
+               if((*i)->IsRunning()==false)\r
+               {\r
+                       delete (*i);\r
+                       i=m_threads.erase(i);\r
+               }\r
+               else\r
+               {\r
+                       i++;\r
+               }\r
+       }\r
+}\r
+\r
+void ThreadedExecutor::Execute(Runnable *runnable)\r
+{\r
+       CleanupFinished();\r
+       m_threads.push_back(new Thread(runnable));      \r
+}\r
+\r
+void ThreadedExecutor::Join()\r
+{\r
+       for(std::vector<Thread *>::iterator     i=m_threads.begin(); i!=m_threads.end(); i++)\r
+       {\r
+               (*i)->Join();\r
+       }\r
+       CleanupFinished();\r
+}\r
+\r
+}      // namespace\r
diff --git a/src/threadcontroller.cpp b/src/threadcontroller.cpp
new file mode 100644 (file)
index 0000000..8bfb7b5
--- /dev/null
@@ -0,0 +1,132 @@
+#include "../include/threadcontroller.h"\r
+#include "../include/option.h"\r
+#include "../include/freenet/freenetmasterthread.h"\r
+#include "../include/nntp/nntplistener.h"\r
+#include "../include/http/httpthread.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+ThreadController::~ThreadController()\r
+{\r
+       ShutdownThreads();\r
+}\r
+\r
+void ThreadController::ReadConfig()\r
+{\r
+\r
+       std::string tempval="";\r
+       Option::Instance()->Get("StartFreenetUpdater",tempval);\r
+       if(tempval=="true")\r
+       {\r
+               m_startfreenet=true;\r
+       }\r
+       else\r
+       {\r
+               m_startfreenet=false;\r
+       }\r
+\r
+       tempval="";\r
+       Option::Instance()->Get("StartNNTP",tempval);\r
+       if(tempval=="true")\r
+       {\r
+               m_startnntp=true;\r
+       }\r
+       else\r
+       {\r
+               m_startnntp=false;\r
+       }\r
+\r
+       tempval="";\r
+       Option::Instance()->Get("StartHHTP",tempval);\r
+       if(tempval=="true")\r
+       {\r
+               m_starthttp=true;\r
+       }\r
+       else\r
+       {\r
+               m_starthttp=false;\r
+       }\r
+\r
+}\r
+\r
+void ThreadController::RestartThreads()\r
+{\r
+       ShutdownThreads();\r
+       StartThreads();\r
+}\r
+\r
+void ThreadController::ShutdownFreenetThread()\r
+{\r
+       if(m_freenetthread)\r
+       {\r
+               m_freenetthread->Cancel();\r
+               m_freenetthread->Join();\r
+               delete m_freenetthread;\r
+               m_freenetthread=NULL;\r
+       }\r
+}\r
+\r
+void ThreadController::ShutdownHTTPThread()\r
+{\r
+       if(m_httpthread)\r
+       {\r
+               m_httpthread->Cancel();\r
+               m_httpthread->Join();\r
+               delete m_httpthread;\r
+               m_httpthread=NULL;\r
+       }\r
+}\r
+\r
+void ThreadController::ShutdownNNTPThread()\r
+{\r
+       if(m_nntpthread)\r
+       {\r
+               m_nntpthread->Cancel();\r
+               m_nntpthread->Join();\r
+               delete m_nntpthread;\r
+               m_nntpthread=NULL;\r
+       }\r
+}\r
+\r
+void ThreadController::ShutdownThreads()\r
+{\r
+       ShutdownFreenetThread();\r
+       ShutdownNNTPThread();\r
+       ShutdownHTTPThread();\r
+}\r
+\r
+void ThreadController::StartFreenetThread()\r
+{\r
+       m_freenetthread=new PThread::Thread(new FreenetMasterThread());\r
+}\r
+\r
+void ThreadController::StartHTTPThread()\r
+{\r
+       m_httpthread=new PThread::Thread(new HTTPThread());\r
+}\r
+\r
+void ThreadController::StartNNTPThread()\r
+{\r
+       m_nntpthread=new PThread::Thread(new NNTPListener());\r
+}\r
+\r
+void ThreadController::StartThreads()\r
+{\r
+       ReadConfig();\r
+\r
+       if(m_startfreenet)\r
+       {\r
+               StartFreenetThread();\r
+       }\r
+       if(m_startnntp)\r
+       {\r
+               StartNNTPThread();\r
+       }\r
+       if(m_starthttp)\r
+       {\r
+               StartHTTPThread();\r
+       }\r
+}\r
+\r
index 387f576..e064576 100644 (file)
@@ -196,6 +196,8 @@ h1, h2, h3, h4, h5, h6 {
 .trust9 {background-color:#8aff97;}\r
 .trust10 {background-color:#6dff9d;}\r
 \r
+form   { display:inline; }\r
+\r
 </style>\r
 </head>\r
 \r
@@ -218,6 +220,7 @@ h1, h2, h3, h4, h5, h6 {
                        <li><a href="announceidentity.htm">Announce Identity</a></li>\r
                        <li><a href="addpeer.htm">Add Peer</a></li>\r
                        <li><a href="peertrust.htm">Peer Trust</a></li>\r
+                       <li><a href="controlboard.htm">Control Boards</a></li>\r
                </ul>\r
                </div>\r
        \r