version 0.1.12
[fms.git] / src / global.cpp
index 48c3842..0c6f913 100644 (file)
@@ -6,6 +6,8 @@
 #include "../include/db/sqlite3db.h"\r
 #include "../include/freenet/freenetmasterthread.h"\r
 #include "../include/nntp/nntplistener.h"\r
 #include "../include/db/sqlite3db.h"\r
 #include "../include/freenet/freenetmasterthread.h"\r
 #include "../include/nntp/nntplistener.h"\r
+#include "../include/http/httpthread.h"\r
+#include "../include/threadcontroller.h"\r
 \r
 #ifdef _WIN32\r
        #include <winsock2.h>\r
 \r
 #ifdef _WIN32\r
        #include <winsock2.h>\r
        #include <xmem.h>\r
 #endif\r
 \r
        #include <xmem.h>\r
 #endif\r
 \r
+bool wantshutdown=false;\r
+\r
 void SetupDB()\r
 {\r
 \r
        DateTime date;\r
 void SetupDB()\r
 {\r
 \r
        DateTime date;\r
-       SQLite3DB::DB *db=SQLite3DB::DB::instance();\r
+       SQLite3DB::DB *db=SQLite3DB::DB::Instance();\r
 \r
        db->Open("fms.db3");\r
        db->SetBusyTimeout(10000);              // set timeout to 10 seconds\r
        db->Execute("VACUUM;");\r
 \r
        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
+               st.Finalize();\r
+               if(major==1 && minor==0)\r
+               {\r
+                       ConvertDB0100To0101();\r
+                       major=1;\r
+                       minor=1;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,1);");\r
+       }\r
+\r
+       db->Execute("UPDATE tblDBVersion SET Major=1, Minor=2;");\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\\r
                                Option                          TEXT UNIQUE,\\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\\r
                                Option                          TEXT UNIQUE,\\r
@@ -34,8 +69,8 @@ void SetupDB()
        db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\\r
                                LocalIdentityID                 INTEGER PRIMARY KEY,\\r
                                Name                                    TEXT,\\r
        db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\\r
                                LocalIdentityID                 INTEGER PRIMARY KEY,\\r
                                Name                                    TEXT,\\r
-                               PublicKey                               TEXT,\\r
-                               PrivateKey                              TEXT,\\r
+                               PublicKey                               TEXT UNIQUE,\\r
+                               PrivateKey                              TEXT UNIQUE,\\r
                                SingleUse                               BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
                                PublishTrustList                BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\\r
                                PublishBoardList                BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\\r
                                SingleUse                               BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
                                PublishTrustList                BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\\r
                                PublishBoardList                BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\\r
@@ -84,7 +119,7 @@ void SetupDB()
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\\r
                                IdentityID                      INTEGER PRIMARY KEY,\\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\\r
                                IdentityID                      INTEGER PRIMARY KEY,\\r
-                               PublicKey                       TEXT,\\r
+                               PublicKey                       TEXT UNIQUE,\\r
                                Name                            TEXT,\\r
                                SingleUse                       BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
                                PublishTrustList        BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\\r
                                Name                            TEXT,\\r
                                SingleUse                       BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
                                PublishTrustList        BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\\r
@@ -137,10 +172,10 @@ void SetupDB()
                                DateAdded                       DATETIME\\r
                                );");\r
 \r
                                DateAdded                       DATETIME\\r
                                );");\r
 \r
-       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('fms','Freenet Message System','2007-12-01');");\r
-       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('freenet','Discussion about Freenet','2007-12-01');");\r
-       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('public','Public discussion','2007-12-01');");\r
-       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('test','Test board','2007-12-01');");\r
+       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('fms','Freenet Message System','2007-12-01 12:00:00');");\r
+       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('freenet','Discussion about Freenet','2007-12-01 12:00:00');");\r
+       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('public','Public discussion','2007-12-01 12:00:00');");\r
+       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('test','Test board','2007-12-01 12:00:00');");\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\\r
                                MessageID                       INTEGER PRIMARY KEY,\\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\\r
                                MessageID                       INTEGER PRIMARY KEY,\\r
@@ -156,7 +191,7 @@ void SetupDB()
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblMessageReplyTo(\\r
                                MessageID                       INTEGER,\\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblMessageReplyTo(\\r
                                MessageID                       INTEGER,\\r
-                               ReplyToMessageUUID      INTEGER,\\r
+                               ReplyToMessageUUID      TEXT,\\r
                                ReplyOrder                      INTEGER\\r
                                );");\r
 \r
                                ReplyOrder                      INTEGER\\r
                                );");\r
 \r
@@ -196,11 +231,37 @@ void SetupDB()
                                Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
                                );");\r
 \r
                                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
+       db->Execute("CREATE TABLE IF NOT EXISTS tblBoardListInserts(\\r
+                               LocalIdentityID         INTEGER,\\r
+                               Day                                     DATE,\\r
+                               InsertIndex                     INTEGER,\\r
+                               Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
+                               );");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblBoardListRequests(\\r
+                               IdentityID                      INTEGER,\\r
+                               Day                                     DATE,\\r
+                               RequestIndex            INTEGER,\\r
+                               Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\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
+                               Date                            DATETIME\\r
+                               );");\r
+\r
        // low / high / message count for each board\r
        db->Execute("CREATE VIEW IF NOT EXISTS vwBoardStats AS \\r
                                SELECT tblBoard.BoardID AS 'BoardID', IFNULL(MIN(MessageID),0) AS 'LowMessageID', IFNULL(MAX(MessageID),0) AS 'HighMessageID', COUNT(MessageID) AS 'MessageCount' \\r
                                FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID \\r
        // low / high / message count for each board\r
        db->Execute("CREATE VIEW IF NOT EXISTS vwBoardStats AS \\r
                                SELECT tblBoard.BoardID AS 'BoardID', IFNULL(MIN(MessageID),0) AS 'LowMessageID', IFNULL(MAX(MessageID),0) AS 'HighMessageID', COUNT(MessageID) AS 'MessageCount' \\r
                                FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID \\r
-                               WHERE MessageID>=0 \\r
+                               WHERE MessageID>=0 OR MessageID IS NULL \\r
                                GROUP BY tblBoard.BoardID;");\r
 \r
        // calculates peer trust\r
                                GROUP BY tblBoard.BoardID;");\r
 \r
        // calculates peer trust\r
@@ -210,8 +271,19 @@ void SetupDB()
                                ROUND(SUM(TrustListTrust*(LocalTrustListTrust/100.0))/SUM(LocalTrustListTrust/100.0),0) AS 'PeerTrustListTrust' \\r
                                FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID \\r
                                WHERE LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') \\r
                                ROUND(SUM(TrustListTrust*(LocalTrustListTrust/100.0))/SUM(LocalTrustListTrust/100.0),0) AS 'PeerTrustListTrust' \\r
                                FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID \\r
                                WHERE LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') \\r
+                               AND ( PeerTrustListTrust IS NULL OR PeerTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerTrustListTrust') ) \\r
                                GROUP BY TargetIdentityID;");\r
 \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
        // 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
@@ -240,6 +312,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
                                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
 \r
        db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \\r
                                FOR EACH ROW \\r
@@ -270,6 +343,12 @@ void SetupDB()
                                        DELETE FROM tblTrustListInserts WHERE LocalIdentityID=old.LocalIdentityID;\\r
                                END;");\r
 \r
                                        DELETE FROM tblTrustListInserts WHERE LocalIdentityID=old.LocalIdentityID;\\r
                                END;");\r
 \r
+       db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteBoard AFTER DELETE ON tblBoard \\r
+                               FOR EACH ROW \\r
+                               BEGIN \\r
+                                       DELETE FROM tblMessageBoard WHERE BoardID=old.BoardID;\\r
+                               END;");\r
+\r
        // delete introduction puzzles that were half-way inserted\r
        db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");\r
 \r
        // delete introduction puzzles that were half-way inserted\r
        db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");\r
 \r
@@ -279,6 +358,44 @@ void SetupDB()
        db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
        db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
 \r
        db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
        db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
 \r
+       date.SetToGMTime();\r
+       // insert SomeDude's public key\r
+       db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw,iXez4j3qCpd596TxXiJgZyTq9o-CElEuJxm~jNNZAuA,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");\r
+       // insert Shadow Panther's public key\r
+       db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@~mimyB1kmH4f7Cgsd2wM2Qv2NxrZHRMM6IY8~7EWRVQ,fxTKkR0TYhgMYb-vEGAv55sMOxCGD2xhE4ZxWHxdPz4,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");\r
+       // insert garfield's public key\r
+       db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@T8l1IEGU4-PoASFzgc2GYhIgRzUvZsKdoQWeuLHuTmM,QLxAPfkGis8l5NafNpSCdbxzXhBlu9WL8svcqJw9Mpo,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");\r
+\r
+}\r
+\r
+void ConvertDB0100To0101()\r
+{\r
+       // added unique constraint to public and private key\r
+       SQLite3DB::DB *db=SQLite3DB::DB::Instance();\r
+       db->Execute("CREATE TEMPORARY TABLE tblLocalIdentityTemp AS SELECT * FROM tblLocalIdentity;");\r
+       db->Execute("DROP TABLE IF EXISTS tblLocalIdentity;");\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\\r
+                               LocalIdentityID                 INTEGER PRIMARY KEY,\\r
+                               Name                                    TEXT,\\r
+                               PublicKey                               TEXT UNIQUE,\\r
+                               PrivateKey                              TEXT UNIQUE,\\r
+                               SingleUse                               BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
+                               PublishTrustList                BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\\r
+                               PublishBoardList                BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\\r
+                               InsertingIdentity               BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\\r
+                               LastInsertedIdentity    DATETIME,\\r
+                               InsertingPuzzle                 BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\\r
+                               LastInsertedPuzzle              DATETIME,\\r
+                               InsertingTrustList              BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\\r
+                               LastInsertedTrustList   DATETIME,\\r
+                               InsertingBoardList              BOOL CHECK(InsertingBoardList IN('true','false')) DEFAULT 'false',\\r
+                               LastInsertedBoardList   DATETIME,\\r
+                               InsertingMessageList    BOOL CHECK(InsertingMessageList IN('true','false')) DEFAULT 'false',\\r
+                               LastInsertedMessageList DATETIME\\r
+                               );");\r
+       db->Execute("INSERT INTO tblLocalIdentity SELECT * FROM tblLocalIdentityTemp;");\r
+       db->Execute("DROP TABLE IF EXISTS tblLocalIdentityTemp;");\r
+       db->Execute("UPDATE tblDBVersion SET Major=1, Minor=1;");\r
 }\r
 \r
 void SetupDefaultOptions()\r
 }\r
 \r
 void SetupDefaultOptions()\r
@@ -286,7 +403,7 @@ 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\r
 \r
        std::ostringstream tempstr;     // must set tempstr to "" between db inserts\r
        // 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\r
 \r
        std::ostringstream tempstr;     // must set tempstr to "" between db inserts\r
-       SQLite3DB::DB *db=SQLite3DB::DB::instance();\r
+       SQLite3DB::DB *db=SQLite3DB::DB::Instance();\r
        SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");\r
 \r
        // LogLevel\r
        SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");\r
 \r
        // LogLevel\r
@@ -321,7 +438,19 @@ void SetupDefaultOptions()
        // StartNNTP\r
        st.Bind(0,"StartNNTP");\r
        st.Bind(1,"true");\r
        // StartNNTP\r
        st.Bind(0,"StartNNTP");\r
        st.Bind(1,"true");\r
-       st.Bind(2,"Start NNTP service.");\r
+       st.Bind(2,"Start NNTP server.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"StartHTTP");\r
+       st.Bind(1,"true");\r
+       st.Bind(2,"Start HTTP server.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"HTTPListenPort");\r
+       st.Bind(1,"8080");\r
+       st.Bind(2,"Port HTTP server will listen on.");\r
        st.Step();\r
        st.Reset();\r
 \r
        st.Step();\r
        st.Reset();\r
 \r
@@ -334,7 +463,7 @@ void SetupDefaultOptions()
 \r
        // FCPHost\r
        st.Bind(0,"FCPHost");\r
 \r
        // FCPHost\r
        st.Bind(0,"FCPHost");\r
-       st.Bind(1,"localhost");\r
+       st.Bind(1,"127.0.0.1");\r
        st.Bind(2,"Host name or address of Freenet node.");\r
        st.Step();\r
        st.Reset();\r
        st.Bind(2,"Host name or address of Freenet node.");\r
        st.Step();\r
        st.Reset();\r
@@ -394,24 +523,60 @@ void SetupDefaultOptions()
        st.Step();\r
        st.Reset();\r
 \r
        st.Step();\r
        st.Reset();\r
 \r
+       st.Bind(0,"MinPeerMessageTrust");\r
+       st.Bind(1,"30");\r
+       st.Bind(2,"Specifies a peer message trust level that a peer must have before its messages will be downloaded.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
        st.Bind(0,"MinLocalTrustListTrust");\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
 \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
 \r
+       st.Bind(0,"MinPeerTrustListTrust");\r
+       st.Bind(1,"30");\r
+       st.Bind(2,"Specifies a peer 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
+\r
        st.Bind(0,"MessageDownloadMaxDaysBackward");\r
        st.Bind(0,"MessageDownloadMaxDaysBackward");\r
-       st.Bind(1,"3");\r
+       st.Bind(1,"5");\r
        st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");\r
        st.Step();\r
        st.Reset();\r
 \r
        st.Bind(0,"MessageListDaysBackward");\r
        st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");\r
        st.Step();\r
        st.Reset();\r
 \r
        st.Bind(0,"MessageListDaysBackward");\r
-       st.Bind(1,"3");\r
+       st.Bind(1,"5");\r
        st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");\r
        st.Step();\r
        st.Reset();\r
 \r
        st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");\r
        st.Step();\r
        st.Reset();\r
 \r
+       st.Bind(0,"MaxPeerMessagesPerDay");\r
+       st.Bind(1,"200");\r
+       st.Bind(2,"The maximum number of messages you will download from each peer on a given day.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"MaxBoardListRequests");\r
+       st.Bind(1,"5");\r
+       st.Bind(2,"The maximum number of concurrent requests for new Board Lists.  Set to 0 to disable.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"MaxBoardsPerMessage");\r
+       st.Bind(1,"8");\r
+       st.Bind(2,"The maximum number of boards a received message may be sent to.  Boards over this limit will be ignored.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"ChangeMessageTrustOnReply");\r
+       st.Bind(1,"0");\r
+       st.Bind(2,"How much the local message trust level of an identity should change when you reply to one of their messages.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
 }\r
 \r
 void SetupLogFile()\r
 }\r
 \r
 void SetupLogFile()\r
@@ -422,23 +587,23 @@ void SetupLogFile()
 \r
        date.SetToGMTime();\r
 \r
 \r
        date.SetToGMTime();\r
 \r
-       LogFile::instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");\r
-       LogFile::instance()->OpenFile();\r
-       LogFile::instance()->SetWriteNewLine(true);\r
-       LogFile::instance()->SetWriteDate(true);\r
-       LogFile::instance()->SetWriteLogLevel(true);\r
+       LogFile::Instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");\r
+       LogFile::Instance()->OpenFile();\r
+       LogFile::Instance()->SetWriteNewLine(true);\r
+       LogFile::Instance()->SetWriteDate(true);\r
+       LogFile::Instance()->SetWriteLogLevel(true);\r
 \r
 \r
-       if(Option::instance()->Get("LogLevel",configval)==false)\r
+       if(Option::Instance()->Get("LogLevel",configval)==false)\r
        {\r
                configval="4";\r
        {\r
                configval="4";\r
-               Option::instance()->Set("LogLevel",configval);\r
+               Option::Instance()->Set("LogLevel",configval);\r
        }\r
        if(StringFunctions::Convert(configval,loglevel)==false)\r
        {\r
                loglevel=LogFile::LOGLEVEL_DEBUG;\r
        }\r
        if(StringFunctions::Convert(configval,loglevel)==false)\r
        {\r
                loglevel=LogFile::LOGLEVEL_DEBUG;\r
-               Option::instance()->Set("LogLevel",loglevel);\r
+               Option::Instance()->Set("LogLevel",loglevel);\r
        }\r
        }\r
-       LogFile::instance()->SetLogLevel((LogFile::LogLevel)loglevel);\r
+       LogFile::Instance()->SetLogLevel((LogFile::LogLevel)loglevel);\r
 }\r
 \r
 void SetupNetwork()\r
 }\r
 \r
 void SetupNetwork()\r
@@ -449,6 +614,16 @@ void SetupNetwork()
 #endif\r
 }\r
 \r
 #endif\r
 }\r
 \r
+void Shutdown()\r
+{\r
+       ThreadController::Instance()->ShutdownThreads();\r
+\r
+       ShutdownNetwork();\r
+\r
+       LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"FMS shutdown");\r
+       LogFile::Instance()->WriteNewLine();\r
+}\r
+\r
 void ShutdownNetwork()\r
 {\r
 #ifdef _WIN32\r
 void ShutdownNetwork()\r
 {\r
 #ifdef _WIN32\r
@@ -456,27 +631,26 @@ void ShutdownNetwork()
 #endif\r
 }\r
 \r
 #endif\r
 }\r
 \r
-void ShutdownThreads(std::vector<ZThread::Thread *> &threads)\r
+void SigHandler(int signum)\r
 {\r
 {\r
-       std::vector<ZThread::Thread *>::iterator i;\r
+       Shutdown();\r
+       exit(0);\r
+}\r
+\r
+/*\r
+void ShutdownThreads(std::vector<PThread::Thread *> &threads)\r
+{\r
+       std::vector<PThread::Thread *>::iterator i;\r
        for(i=threads.begin(); i!=threads.end(); i++)\r
        {\r
        for(i=threads.begin(); i!=threads.end(); i++)\r
        {\r
-               if((*i)->wait(1)==false)\r
-               {\r
-                       try\r
-                       {\r
-                               (*i)->interrupt();\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                       }\r
-               }\r
+               (*i)->Cancel();\r
        }\r
 \r
        for(i=threads.begin(); i!=threads.end(); i++)\r
        {\r
        }\r
 \r
        for(i=threads.begin(); i!=threads.end(); i++)\r
        {\r
-               LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");\r
-               (*i)->wait();\r
+               LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");\r
+               //(*i)->wait();\r
+               (*i)->Join();\r
                delete (*i);\r
        }\r
 \r
                delete (*i);\r
        }\r
 \r
@@ -484,33 +658,47 @@ void ShutdownThreads(std::vector<ZThread::Thread *> &threads)
 \r
 }\r
 \r
 \r
 }\r
 \r
-void StartThreads(std::vector<ZThread::Thread *> &threads)\r
+void StartThreads(std::vector<PThread::Thread *> &threads)\r
 {\r
        std::string startfreenet;\r
        std::string startnntp;\r
 {\r
        std::string startfreenet;\r
        std::string startnntp;\r
+       std::string starthttp;\r
 \r
 \r
-       if(Option::instance()->Get("StartFreenetUpdater",startfreenet)==false)\r
+       if(Option::Instance()->Get("StartFreenetUpdater",startfreenet)==false)\r
        {\r
                startfreenet="true";\r
        {\r
                startfreenet="true";\r
-               Option::instance()->Set("StartFreenetUpdater","true");\r
+               Option::Instance()->Set("StartFreenetUpdater","true");\r
        }\r
 \r
        }\r
 \r
-       if(Option::instance()->Get("StartNNTP",startnntp)==false)\r
+       if(Option::Instance()->Get("StartNNTP",startnntp)==false)\r
        {\r
                startnntp="true";\r
        {\r
                startnntp="true";\r
-               Option::instance()->Set("StartNNTP","true");\r
+               Option::Instance()->Set("StartNNTP","true");\r
+       }\r
+\r
+       if(Option::Instance()->Get("StartHTTP",starthttp)==false)\r
+       {\r
+               starthttp="true";\r
+               Option::Instance()->Set("StartHTTP","true");\r
        }\r
 \r
        if(startfreenet=="true")\r
        {\r
        }\r
 \r
        if(startfreenet=="true")\r
        {\r
-               ZThread::Thread *t=new ZThread::Thread(new FreenetMasterThread());\r
+               PThread::Thread *t=new PThread::Thread(new FreenetMasterThread());\r
                threads.push_back(t);\r
        }\r
 \r
        if(startnntp=="true")\r
        {\r
                threads.push_back(t);\r
        }\r
 \r
        if(startnntp=="true")\r
        {\r
-               ZThread::Thread *t=new ZThread::Thread(new NNTPListener());\r
+               PThread::Thread *t=new PThread::Thread(new NNTPListener());\r
+               threads.push_back(t);\r
+       }\r
+\r
+       if(starthttp=="true")\r
+       {\r
+               PThread::Thread *t=new PThread::Thread(new HTTPThread());\r
                threads.push_back(t);\r
        }\r
 \r
 }\r
                threads.push_back(t);\r
        }\r
 \r
 }\r
+*/\r