1 #include "../include/global.h"
\r
2 #include "../include/datetime.h"
\r
3 #include "../include/logfile.h"
\r
4 #include "../include/option.h"
\r
5 #include "../include/stringfunctions.h"
\r
6 #include "../include/db/sqlite3db.h"
\r
7 #include "../include/freenet/freenetmasterthread.h"
\r
8 #include "../include/nntp/nntplistener.h"
\r
11 #include <winsock2.h>
\r
22 SQLite3DB::DB *db=SQLite3DB::DB::instance();
\r
24 db->Open("fms.db3");
\r
25 db->SetBusyTimeout(10000); // set timeout to 10 seconds
\r
26 db->Execute("VACUUM;");
\r
28 db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\
\r
29 Option TEXT UNIQUE,\
\r
30 OptionValue TEXT NOT NULL,\
\r
31 OptionDescription TEXT\
\r
34 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\
\r
35 LocalIdentityID INTEGER PRIMARY KEY,\
\r
39 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
40 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
41 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
42 InsertingIdentity BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\
\r
43 LastInsertedIdentity DATETIME,\
\r
44 InsertingPuzzle BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\
\r
45 LastInsertedPuzzle DATETIME,\
\r
46 InsertingTrustList BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\
\r
47 LastInsertedTrustList DATETIME,\
\r
48 InsertingBoardList BOOL CHECK(InsertingBoardList IN('true','false')) DEFAULT 'false',\
\r
49 LastInsertedBoardList DATETIME,\
\r
50 InsertingMessageList BOOL CHECK(InsertingMessageList IN('true','false')) DEFAULT 'false',\
\r
51 LastInsertedMessageList DATETIME\
\r
54 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentityInserts(\
\r
55 LocalIdentityID INTEGER,\
\r
57 InsertIndex INTEGER\
\r
60 db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListInserts(\
\r
61 LocalIdentityID INTEGER,\
\r
63 InsertIndex INTEGER\
\r
66 db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListRequests(\
\r
67 IdentityID INTEGER,\
\r
69 RequestIndex INTEGER,\
\r
70 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
73 db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleInserts(\
\r
75 LocalIdentityID INTEGER,\
\r
77 InsertIndex INTEGER,\
\r
81 PuzzleSolution TEXT,\
\r
82 FoundSolution BOOL CHECK(FoundSolution IN('true','false')) DEFAULT 'false'\
\r
85 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\
\r
86 IdentityID INTEGER PRIMARY KEY,\
\r
89 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
90 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
91 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
92 DateAdded DATETIME,\
\r
94 LocalMessageTrust INTEGER CHECK(LocalMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
95 PeerMessageTrust INTEGER CHECK(PeerMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
96 LocalTrustListTrust INTEGER CHECK(LocalTrustListTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
97 PeerTrustListTrust INTEGER CHECK(PeerTrustListTrust BETWEEN 0 AND 100) DEFAULT 50\
\r
100 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityRequests(\
\r
101 IdentityID INTEGER,\
\r
103 RequestIndex INTEGER,\
\r
104 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
107 db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleRequests(\
\r
108 IdentityID INTEGER,\
\r
110 RequestIndex INTEGER,\
\r
111 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false',\
\r
118 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityIntroductionInserts(\
\r
119 LocalIdentityID INTEGER,\
\r
123 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
126 db->Execute("CREATE TABLE IF NOT EXISTS tblPeerTrust(\
\r
127 IdentityID INTEGER,\
\r
128 TargetIdentityID INTEGER,\
\r
129 MessageTrust INTEGER CHECK(MessageTrust BETWEEN 0 AND 100),\
\r
130 TrustListTrust INTEGER CHECK(TrustListTrust BETWEEN 0 AND 100)\
\r
133 db->Execute("CREATE TABLE IF NOT EXISTS tblBoard(\
\r
134 BoardID INTEGER PRIMARY KEY,\
\r
135 BoardName TEXT UNIQUE,\
\r
136 BoardDescription TEXT,\
\r
137 DateAdded DATETIME\
\r
140 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('fms','Freenet Message System','2007-12-01');");
\r
141 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('freenet','Discussion about Freenet','2007-12-01');");
\r
142 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('public','Public discussion','2007-12-01');");
\r
143 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('test','Test board','2007-12-01');");
\r
145 db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\
\r
146 MessageID INTEGER PRIMARY KEY,\
\r
147 IdentityID INTEGER,\
\r
152 MessageUUID TEXT UNIQUE,\
\r
153 ReplyBoardID INTEGER,\
\r
157 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageReplyTo(\
\r
158 MessageID INTEGER,\
\r
159 ReplyToMessageUUID INTEGER,\
\r
160 ReplyOrder INTEGER\
\r
163 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageBoard(\
\r
164 MessageID INTEGER,\
\r
168 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListRequests(\
\r
169 IdentityID INTEGER,\
\r
171 RequestIndex INTEGER,\
\r
172 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
175 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageRequests(\
\r
176 IdentityID INTEGER,\
\r
178 RequestIndex INTEGER,\
\r
179 FromMessageList BOOL CHECK(FromMessageList IN('true','false')) DEFAULT 'false',\
\r
180 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
183 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageInserts(\
\r
184 LocalIdentityID INTEGER,\
\r
186 InsertIndex INTEGER,\
\r
187 MessageUUID TEXT UNIQUE,\
\r
189 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
192 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListInserts(\
\r
193 LocalIdentityID INTEGER,\
\r
195 InsertIndex INTEGER,\
\r
196 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
199 // low / high / message count for each board
\r
200 db->Execute("CREATE VIEW IF NOT EXISTS vwBoardStats AS \
\r
201 SELECT tblBoard.BoardID AS 'BoardID', IFNULL(MIN(MessageID),0) AS 'LowMessageID', IFNULL(MAX(MessageID),0) AS 'HighMessageID', COUNT(MessageID) AS 'MessageCount' \
\r
202 FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID \
\r
203 WHERE MessageID>=0 \
\r
204 GROUP BY tblBoard.BoardID;");
\r
206 // calculates peer trust
\r
207 db->Execute("CREATE VIEW IF NOT EXISTS vwCalculatedPeerTrust AS \
\r
208 SELECT TargetIdentityID, \
\r
209 ROUND(SUM(MessageTrust*(LocalMessageTrust/100.0))/SUM(LocalMessageTrust/100.0),0) AS 'PeerMessageTrust', \
\r
210 ROUND(SUM(TrustListTrust*(LocalTrustListTrust/100.0))/SUM(LocalTrustListTrust/100.0),0) AS 'PeerTrustListTrust' \
\r
211 FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID \
\r
212 WHERE LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') \
\r
213 GROUP BY TargetIdentityID;");
\r
215 // update PeerTrustLevel when deleting a record from tblPeerTrust
\r
216 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \
\r
219 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=old.TargetIdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=old.TargetIdentityID) WHERE IdentityID=old.TargetIdentityID;\
\r
222 // update PeerTrustLevel when inserting a record into tblPeerTrust
\r
223 db->Execute("CREATE TRIGGER IF NOT EXISTS trgInsertOntblPeerTrust AFTER INSERT ON tblPeerTrust \
\r
226 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=new.TargetIdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=new.TargetIdentityID) WHERE IdentityID=new.TargetIdentityID;\
\r
229 // update PeerTrustLevel when updating a record in tblPeerTrust
\r
230 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateOntblPeerTrust AFTER UPDATE ON tblPeerTrust \
\r
233 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=old.TargetIdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=old.TargetIdentityID) WHERE IdentityID=old.TargetIdentityID;\
\r
234 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=new.TargetIdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=new.TargetIdentityID) WHERE IdentityID=new.TargetIdentityID;\
\r
237 // recalculate all Peer TrustLevels when updating Local TrustLevels on tblIdentity - doesn't really need to be all, but rather all identities the updated identity has a trust level for. It's easier to update everyone for now.
\r
238 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateLocalTrustLevels AFTER UPDATE OF LocalMessageTrust,LocalTrustListTrust ON tblIdentity \
\r
241 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\
\r
244 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \
\r
247 DELETE FROM tblMessageBoard WHERE tblMessageBoard.MessageID=old.MessageID;\
\r
248 DELETE FROM tblMessageReplyTo WHERE tblMessageReplyTo.MessageID=old.MessageID;\
\r
251 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteIdentity AFTER DELETE ON tblIdentity \
\r
254 DELETE FROM tblIdentityRequests WHERE IdentityID=old.IdentityID;\
\r
255 DELETE FROM tblIntroductionPuzzleRequests WHERE IdentityID=old.IdentityID;\
\r
256 DELETE FROM tblMessageListRequests WHERE IdentityID=old.IdentityID;\
\r
257 DELETE FROM tblMessageRequests WHERE IdentityID=old.IdentityID;\
\r
258 DELETE FROM tblPeerTrust WHERE IdentityID=old.IdentityID;\
\r
259 DELETE FROM tblTrustListRequests WHERE IdentityID=old.IdentityID;\
\r
262 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteLocalIdentity AFTER DELETE ON tblLocalIdentity \
\r
265 DELETE FROM tblIdentityIntroductionInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
266 DELETE FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
267 DELETE FROM tblLocalIdentityInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
268 DELETE FROM tblMessageInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
269 DELETE FROM tblMessageListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
270 DELETE FROM tblTrustListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
273 // delete introduction puzzles that were half-way inserted
\r
274 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");
\r
276 // delete stale introduction puzzles (2 or more days old)
\r
277 date.SetToGMTime();
\r
278 date.Add(0,0,0,-2);
\r
279 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
280 db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
284 void SetupDefaultOptions()
\r
286 // 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
288 std::ostringstream tempstr; // must set tempstr to "" between db inserts
\r
289 SQLite3DB::DB *db=SQLite3DB::DB::instance();
\r
290 SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");
\r
294 tempstr << LogFile::LOGLEVEL_DEBUG;
\r
295 st.Bind(0,"LogLevel");
\r
296 st.Bind(1,tempstr.str());
\r
297 st.Bind(2,"The maximum logging level that will be written to file. 0=Fatal Errors, 1=Errors, 2=Warnings, 3=Informational Messages, 4=Debug Messages. Higher levels will include all messages from the previous levels.");
\r
302 st.Bind(0,"NNTPListenPort");
\r
304 st.Bind(2,"The port that the NNTP service will listen for incoming connections.");
\r
308 // NNTPBindAddresses
\r
309 st.Bind(0,"NNTPBindAddresses");
\r
310 st.Bind(1,"localhost");
\r
311 st.Bind(2,"A comma separated list of valid IPv4 or IPv6 addresses/hostnames that the NNTP service will try to bind to.");
\r
315 st.Bind(0,"NNTPAllowPost");
\r
317 st.Bind(2,"Allow posting messages from NNTP. Setting to false will make the newsgroups read only.");
\r
322 st.Bind(0,"StartNNTP");
\r
324 st.Bind(2,"Start NNTP service.");
\r
328 // StartFreenetUpdater
\r
329 st.Bind(0,"StartFreenetUpdater");
\r
331 st.Bind(2,"Start Freenet Updater thread.");
\r
336 st.Bind(0,"FCPHost");
\r
337 st.Bind(1,"localhost");
\r
338 st.Bind(2,"Host name or address of Freenet node.");
\r
343 st.Bind(0,"FCPPort");
\r
345 st.Bind(2,"The port that Freenet is listening for FCP connections on.");
\r
349 st.Bind(0,"MessageBase");
\r
351 st.Bind(2,"A unique string shared by all clients who want to communicate with each other. This should not be changed unless you want to create your own separate communications network.");
\r
355 st.Bind(0,"MaxIdentityRequests");
\r
357 st.Bind(2,"Maximum number of concurrent requests for new Identity xml files");
\r
361 st.Bind(0,"MaxIdentityIntroductionRequests");
\r
363 st.Bind(2,"Maximum number of concurrent identities requesting IdentityIntroduction xml files. Each identity may have multiple requests pending.");
\r
367 st.Bind(0,"MaxIntroductionPuzzleRequests");
\r
369 st.Bind(2,"Maximum number of concurrent requests for new IntroductionPuzzle xml files");
\r
373 st.Bind(0,"MaxTrustListRequests");
\r
375 st.Bind(2,"Maximum number of concurrent requests for new Trust Lists");
\r
379 st.Bind(0,"MaxMessageListRequests");
\r
381 st.Bind(2,"Maximum number of concurrent requests for new Message Lists");
\r
385 st.Bind(0,"MaxMessageRequests");
\r
387 st.Bind(2,"Maximum number of concurrent requests for new Messages");
\r
391 st.Bind(0,"MinLocalMessageTrust");
\r
393 st.Bind(2,"Specifies a local message trust level that a peer must have before its messages will be downloaded.");
\r
397 st.Bind(0,"MinLocalTrustListTrust");
\r
399 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
403 st.Bind(0,"MessageDownloadMaxDaysBackward");
\r
405 st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");
\r
409 st.Bind(0,"MessageListDaysBackward");
\r
411 st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");
\r
417 void SetupLogFile()
\r
420 std::string configval;
\r
423 date.SetToGMTime();
\r
425 LogFile::instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");
\r
426 LogFile::instance()->OpenFile();
\r
427 LogFile::instance()->SetWriteNewLine(true);
\r
428 LogFile::instance()->SetWriteDate(true);
\r
429 LogFile::instance()->SetWriteLogLevel(true);
\r
431 if(Option::instance()->Get("LogLevel",configval)==false)
\r
434 Option::instance()->Set("LogLevel",configval);
\r
436 if(StringFunctions::Convert(configval,loglevel)==false)
\r
438 loglevel=LogFile::LOGLEVEL_DEBUG;
\r
439 Option::instance()->Set("LogLevel",loglevel);
\r
441 LogFile::instance()->SetLogLevel((LogFile::LogLevel)loglevel);
\r
444 void SetupNetwork()
\r
448 WSAStartup(MAKEWORD(2,2),&wsadata);
\r
452 void ShutdownNetwork()
\r
459 void ShutdownThreads(std::vector<ZThread::Thread *> &threads)
\r
461 std::vector<ZThread::Thread *>::iterator i;
\r
462 for(i=threads.begin(); i!=threads.end(); i++)
\r
464 if((*i)->wait(1)==false)
\r
476 for(i=threads.begin(); i!=threads.end(); i++)
\r
478 LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");
\r
487 void StartThreads(std::vector<ZThread::Thread *> &threads)
\r
489 std::string startfreenet;
\r
490 std::string startnntp;
\r
492 if(Option::instance()->Get("StartFreenetUpdater",startfreenet)==false)
\r
494 startfreenet="true";
\r
495 Option::instance()->Set("StartFreenetUpdater","true");
\r
498 if(Option::instance()->Get("StartNNTP",startnntp)==false)
\r
501 Option::instance()->Set("StartNNTP","true");
\r
504 if(startfreenet=="true")
\r
506 ZThread::Thread *t=new ZThread::Thread(new FreenetMasterThread());
\r
507 threads.push_back(t);
\r
510 if(startnntp=="true")
\r
512 ZThread::Thread *t=new ZThread::Thread(new NNTPListener());
\r
513 threads.push_back(t);
\r