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
9 #include "../include/http/httpthread.h"
\r
12 #include <winsock2.h>
\r
23 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
25 db->Open("fms.db3");
\r
26 db->SetBusyTimeout(10000); // set timeout to 10 seconds
\r
27 db->Execute("VACUUM;");
\r
29 db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\
\r
30 Option TEXT UNIQUE,\
\r
31 OptionValue TEXT NOT NULL,\
\r
32 OptionDescription TEXT\
\r
35 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\
\r
36 LocalIdentityID INTEGER PRIMARY KEY,\
\r
40 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
41 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
42 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
43 InsertingIdentity BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\
\r
44 LastInsertedIdentity DATETIME,\
\r
45 InsertingPuzzle BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\
\r
46 LastInsertedPuzzle DATETIME,\
\r
47 InsertingTrustList BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\
\r
48 LastInsertedTrustList DATETIME,\
\r
49 InsertingBoardList BOOL CHECK(InsertingBoardList IN('true','false')) DEFAULT 'false',\
\r
50 LastInsertedBoardList DATETIME,\
\r
51 InsertingMessageList BOOL CHECK(InsertingMessageList IN('true','false')) DEFAULT 'false',\
\r
52 LastInsertedMessageList DATETIME\
\r
55 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentityInserts(\
\r
56 LocalIdentityID INTEGER,\
\r
58 InsertIndex INTEGER\
\r
61 db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListInserts(\
\r
62 LocalIdentityID INTEGER,\
\r
64 InsertIndex INTEGER\
\r
67 db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListRequests(\
\r
68 IdentityID INTEGER,\
\r
70 RequestIndex INTEGER,\
\r
71 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
74 db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleInserts(\
\r
76 LocalIdentityID INTEGER,\
\r
78 InsertIndex INTEGER,\
\r
82 PuzzleSolution TEXT,\
\r
83 FoundSolution BOOL CHECK(FoundSolution IN('true','false')) DEFAULT 'false'\
\r
86 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\
\r
87 IdentityID INTEGER PRIMARY KEY,\
\r
88 PublicKey TEXT UNIQUE,\
\r
90 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
91 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
92 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
93 DateAdded DATETIME,\
\r
95 LocalMessageTrust INTEGER CHECK(LocalMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
96 PeerMessageTrust INTEGER CHECK(PeerMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
97 LocalTrustListTrust INTEGER CHECK(LocalTrustListTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
98 PeerTrustListTrust INTEGER CHECK(PeerTrustListTrust BETWEEN 0 AND 100) DEFAULT 50\
\r
101 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityRequests(\
\r
102 IdentityID INTEGER,\
\r
104 RequestIndex INTEGER,\
\r
105 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
108 db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleRequests(\
\r
109 IdentityID INTEGER,\
\r
111 RequestIndex INTEGER,\
\r
112 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false',\
\r
119 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityIntroductionInserts(\
\r
120 LocalIdentityID INTEGER,\
\r
124 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
127 db->Execute("CREATE TABLE IF NOT EXISTS tblPeerTrust(\
\r
128 IdentityID INTEGER,\
\r
129 TargetIdentityID INTEGER,\
\r
130 MessageTrust INTEGER CHECK(MessageTrust BETWEEN 0 AND 100),\
\r
131 TrustListTrust INTEGER CHECK(TrustListTrust BETWEEN 0 AND 100)\
\r
134 db->Execute("CREATE TABLE IF NOT EXISTS tblBoard(\
\r
135 BoardID INTEGER PRIMARY KEY,\
\r
136 BoardName TEXT UNIQUE,\
\r
137 BoardDescription TEXT,\
\r
138 DateAdded DATETIME\
\r
141 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('fms','Freenet Message System','2007-12-01');");
\r
142 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('freenet','Discussion about Freenet','2007-12-01');");
\r
143 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('public','Public discussion','2007-12-01');");
\r
144 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('test','Test board','2007-12-01');");
\r
146 db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\
\r
147 MessageID INTEGER PRIMARY KEY,\
\r
148 IdentityID INTEGER,\
\r
153 MessageUUID TEXT UNIQUE,\
\r
154 ReplyBoardID INTEGER,\
\r
158 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageReplyTo(\
\r
159 MessageID INTEGER,\
\r
160 ReplyToMessageUUID TEXT,\
\r
161 ReplyOrder INTEGER\
\r
164 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageBoard(\
\r
165 MessageID INTEGER,\
\r
169 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListRequests(\
\r
170 IdentityID INTEGER,\
\r
172 RequestIndex INTEGER,\
\r
173 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
176 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageRequests(\
\r
177 IdentityID INTEGER,\
\r
179 RequestIndex INTEGER,\
\r
180 FromMessageList BOOL CHECK(FromMessageList IN('true','false')) DEFAULT 'false',\
\r
181 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
184 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageInserts(\
\r
185 LocalIdentityID INTEGER,\
\r
187 InsertIndex INTEGER,\
\r
188 MessageUUID TEXT UNIQUE,\
\r
190 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
193 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListInserts(\
\r
194 LocalIdentityID INTEGER,\
\r
196 InsertIndex INTEGER,\
\r
197 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
200 // MessageInserter will insert a record into this temp table which the MessageListInserter will query for and insert a MessageList when needed
\r
201 db->Execute("CREATE TEMPORARY TABLE IF NOT EXISTS tmpMessageListInsert(\
\r
202 LocalIdentityID INTEGER,\
\r
206 // low / high / message count for each board
\r
207 db->Execute("DROP VIEW IF EXISTS vwBoardStats; \
\r
208 CREATE VIEW IF NOT EXISTS vwBoardStats AS \
\r
209 SELECT tblBoard.BoardID AS 'BoardID', IFNULL(MIN(MessageID),0) AS 'LowMessageID', IFNULL(MAX(MessageID),0) AS 'HighMessageID', COUNT(MessageID) AS 'MessageCount' \
\r
210 FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID \
\r
211 WHERE MessageID>=0 OR MessageID IS NULL \
\r
212 GROUP BY tblBoard.BoardID;");
\r
214 // calculates peer trust
\r
215 db->Execute("DROP VIEW IF EXISTS vwCalculatedPeerTrust; \
\r
216 CREATE VIEW IF NOT EXISTS vwCalculatedPeerTrust AS \
\r
217 SELECT TargetIdentityID, \
\r
218 ROUND(SUM(MessageTrust*(LocalMessageTrust/100.0))/SUM(LocalMessageTrust/100.0),0) AS 'PeerMessageTrust', \
\r
219 ROUND(SUM(TrustListTrust*(LocalTrustListTrust/100.0))/SUM(LocalTrustListTrust/100.0),0) AS 'PeerTrustListTrust' \
\r
220 FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID \
\r
221 WHERE LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') \
\r
222 AND ( PeerTrustListTrust IS NULL OR PeerTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerTrustListTrust') ) \
\r
223 GROUP BY TargetIdentityID;");
\r
225 // update PeerTrustLevel when deleting a record from tblPeerTrust
\r
226 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \
\r
229 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
232 // update PeerTrustLevel when inserting a record into tblPeerTrust
\r
233 db->Execute("CREATE TRIGGER IF NOT EXISTS trgInsertOntblPeerTrust AFTER INSERT ON tblPeerTrust \
\r
236 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
239 // update PeerTrustLevel when updating a record in tblPeerTrust
\r
240 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateOntblPeerTrust AFTER UPDATE ON tblPeerTrust \
\r
243 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
244 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
247 // 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
248 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateLocalTrustLevels AFTER UPDATE OF LocalMessageTrust,LocalTrustListTrust ON tblIdentity \
\r
251 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\
\r
254 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \
\r
257 DELETE FROM tblMessageBoard WHERE tblMessageBoard.MessageID=old.MessageID;\
\r
258 DELETE FROM tblMessageReplyTo WHERE tblMessageReplyTo.MessageID=old.MessageID;\
\r
261 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteIdentity AFTER DELETE ON tblIdentity \
\r
264 DELETE FROM tblIdentityRequests WHERE IdentityID=old.IdentityID;\
\r
265 DELETE FROM tblIntroductionPuzzleRequests WHERE IdentityID=old.IdentityID;\
\r
266 DELETE FROM tblMessageListRequests WHERE IdentityID=old.IdentityID;\
\r
267 DELETE FROM tblMessageRequests WHERE IdentityID=old.IdentityID;\
\r
268 DELETE FROM tblPeerTrust WHERE IdentityID=old.IdentityID;\
\r
269 DELETE FROM tblTrustListRequests WHERE IdentityID=old.IdentityID;\
\r
272 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteLocalIdentity AFTER DELETE ON tblLocalIdentity \
\r
275 DELETE FROM tblIdentityIntroductionInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
276 DELETE FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
277 DELETE FROM tblLocalIdentityInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
278 DELETE FROM tblMessageInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
279 DELETE FROM tblMessageListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
280 DELETE FROM tblTrustListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
283 // delete introduction puzzles that were half-way inserted
\r
284 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");
\r
286 // delete stale introduction puzzles (2 or more days old)
\r
287 date.SetToGMTime();
\r
288 date.Add(0,0,0,-2);
\r
289 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
290 db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
292 // insert SomeDude's public key
\r
293 date.SetToGMTime();
\r
294 //db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw,iXez4j3qCpd596TxXiJgZyTq9o-CElEuJxm~jNNZAuA,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");
\r
298 void SetupDefaultOptions()
\r
300 // 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
302 std::ostringstream tempstr; // must set tempstr to "" between db inserts
\r
303 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
304 SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");
\r
308 tempstr << LogFile::LOGLEVEL_DEBUG;
\r
309 st.Bind(0,"LogLevel");
\r
310 st.Bind(1,tempstr.str());
\r
311 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
316 st.Bind(0,"NNTPListenPort");
\r
318 st.Bind(2,"The port that the NNTP service will listen for incoming connections.");
\r
322 // NNTPBindAddresses
\r
323 st.Bind(0,"NNTPBindAddresses");
\r
324 st.Bind(1,"localhost");
\r
325 st.Bind(2,"A comma separated list of valid IPv4 or IPv6 addresses/hostnames that the NNTP service will try to bind to.");
\r
329 st.Bind(0,"NNTPAllowPost");
\r
331 st.Bind(2,"Allow posting messages from NNTP. Setting to false will make the newsgroups read only.");
\r
336 st.Bind(0,"StartNNTP");
\r
338 st.Bind(2,"Start NNTP server.");
\r
342 st.Bind(0,"StartHTTP");
\r
344 st.Bind(2,"Start HTTP server.");
\r
348 st.Bind(0,"HTTPListenPort");
\r
350 st.Bind(2,"Port HTTP server will listen on.");
\r
354 // StartFreenetUpdater
\r
355 st.Bind(0,"StartFreenetUpdater");
\r
357 st.Bind(2,"Start Freenet Updater thread.");
\r
362 st.Bind(0,"FCPHost");
\r
363 st.Bind(1,"localhost");
\r
364 st.Bind(2,"Host name or address of Freenet node.");
\r
369 st.Bind(0,"FCPPort");
\r
371 st.Bind(2,"The port that Freenet is listening for FCP connections on.");
\r
375 st.Bind(0,"MessageBase");
\r
377 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
381 st.Bind(0,"MaxIdentityRequests");
\r
383 st.Bind(2,"Maximum number of concurrent requests for new Identity xml files");
\r
387 st.Bind(0,"MaxIdentityIntroductionRequests");
\r
389 st.Bind(2,"Maximum number of concurrent identities requesting IdentityIntroduction xml files. Each identity may have multiple requests pending.");
\r
393 st.Bind(0,"MaxIntroductionPuzzleRequests");
\r
395 st.Bind(2,"Maximum number of concurrent requests for new IntroductionPuzzle xml files");
\r
399 st.Bind(0,"MaxTrustListRequests");
\r
401 st.Bind(2,"Maximum number of concurrent requests for new Trust Lists");
\r
405 st.Bind(0,"MaxMessageListRequests");
\r
407 st.Bind(2,"Maximum number of concurrent requests for new Message Lists");
\r
411 st.Bind(0,"MaxMessageRequests");
\r
413 st.Bind(2,"Maximum number of concurrent requests for new Messages");
\r
417 st.Bind(0,"MinLocalMessageTrust");
\r
419 st.Bind(2,"Specifies a local message trust level that a peer must have before its messages will be downloaded.");
\r
423 st.Bind(0,"MinPeerMessageTrust");
\r
425 st.Bind(2,"Specifies a peer message trust level that a peer must have before its messages will be downloaded.");
\r
429 st.Bind(0,"MinLocalTrustListTrust");
\r
431 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
435 st.Bind(0,"MinPeerTrustListTrust");
\r
437 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
441 st.Bind(0,"MessageDownloadMaxDaysBackward");
\r
443 st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");
\r
447 st.Bind(0,"MessageListDaysBackward");
\r
449 st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");
\r
455 void SetupLogFile()
\r
458 std::string configval;
\r
461 date.SetToGMTime();
\r
463 LogFile::Instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");
\r
464 LogFile::Instance()->OpenFile();
\r
465 LogFile::Instance()->SetWriteNewLine(true);
\r
466 LogFile::Instance()->SetWriteDate(true);
\r
467 LogFile::Instance()->SetWriteLogLevel(true);
\r
469 if(Option::Instance()->Get("LogLevel",configval)==false)
\r
472 Option::Instance()->Set("LogLevel",configval);
\r
474 if(StringFunctions::Convert(configval,loglevel)==false)
\r
476 loglevel=LogFile::LOGLEVEL_DEBUG;
\r
477 Option::Instance()->Set("LogLevel",loglevel);
\r
479 LogFile::Instance()->SetLogLevel((LogFile::LogLevel)loglevel);
\r
482 void SetupNetwork()
\r
486 WSAStartup(MAKEWORD(2,2),&wsadata);
\r
490 void ShutdownNetwork()
\r
497 void ShutdownThreads(std::vector<PThread::Thread *> &threads)
\r
499 std::vector<PThread::Thread *>::iterator i;
\r
500 for(i=threads.begin(); i!=threads.end(); i++)
\r
502 /* if((*i)->wait(1)==false)
\r
516 for(i=threads.begin(); i!=threads.end(); i++)
\r
518 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");
\r
528 void StartThreads(std::vector<PThread::Thread *> &threads)
\r
530 std::string startfreenet;
\r
531 std::string startnntp;
\r
532 std::string starthttp;
\r
534 if(Option::Instance()->Get("StartFreenetUpdater",startfreenet)==false)
\r
536 startfreenet="true";
\r
537 Option::Instance()->Set("StartFreenetUpdater","true");
\r
540 if(Option::Instance()->Get("StartNNTP",startnntp)==false)
\r
543 Option::Instance()->Set("StartNNTP","true");
\r
546 if(Option::Instance()->Get("StartHTTP",starthttp)==false)
\r
549 Option::Instance()->Set("StartHTTP","true");
\r
552 if(startfreenet=="true")
\r
554 PThread::Thread *t=new PThread::Thread(new FreenetMasterThread());
\r
555 threads.push_back(t);
\r
558 if(startnntp=="true")
\r
560 PThread::Thread *t=new PThread::Thread(new NNTPListener());
\r
561 threads.push_back(t);
\r
564 if(starthttp=="true")
\r
566 PThread::Thread *t=new PThread::Thread(new HTTPThread());
\r
567 threads.push_back(t);
\r