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("CREATE VIEW IF NOT EXISTS vwBoardStats AS \
\r
208 SELECT tblBoard.BoardID AS 'BoardID', IFNULL(MIN(MessageID),0) AS 'LowMessageID', IFNULL(MAX(MessageID),0) AS 'HighMessageID', COUNT(MessageID) AS 'MessageCount' \
\r
209 FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID \
\r
210 WHERE MessageID>=0 OR MessageID IS NULL \
\r
211 GROUP BY tblBoard.BoardID;");
\r
213 // calculates peer trust
\r
214 db->Execute("CREATE VIEW IF NOT EXISTS vwCalculatedPeerTrust AS \
\r
215 SELECT TargetIdentityID, \
\r
216 ROUND(SUM(MessageTrust*(LocalMessageTrust/100.0))/SUM(LocalMessageTrust/100.0),0) AS 'PeerMessageTrust', \
\r
217 ROUND(SUM(TrustListTrust*(LocalTrustListTrust/100.0))/SUM(LocalTrustListTrust/100.0),0) AS 'PeerTrustListTrust' \
\r
218 FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID \
\r
219 WHERE LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') \
\r
220 AND ( PeerTrustListTrust IS NULL OR PeerTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerTrustListTrust') ) \
\r
221 GROUP BY TargetIdentityID;");
\r
223 // update PeerTrustLevel when deleting a record from tblPeerTrust
\r
224 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \
\r
227 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
230 // update PeerTrustLevel when inserting a record into tblPeerTrust
\r
231 db->Execute("CREATE TRIGGER IF NOT EXISTS trgInsertOntblPeerTrust AFTER INSERT ON tblPeerTrust \
\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 // update PeerTrustLevel when updating a record in tblPeerTrust
\r
238 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateOntblPeerTrust AFTER UPDATE ON tblPeerTrust \
\r
241 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
242 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
245 // 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
246 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateLocalTrustLevels AFTER UPDATE OF LocalMessageTrust,LocalTrustListTrust ON tblIdentity \
\r
249 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\
\r
252 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \
\r
255 DELETE FROM tblMessageBoard WHERE tblMessageBoard.MessageID=old.MessageID;\
\r
256 DELETE FROM tblMessageReplyTo WHERE tblMessageReplyTo.MessageID=old.MessageID;\
\r
259 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteIdentity AFTER DELETE ON tblIdentity \
\r
262 DELETE FROM tblIdentityRequests WHERE IdentityID=old.IdentityID;\
\r
263 DELETE FROM tblIntroductionPuzzleRequests WHERE IdentityID=old.IdentityID;\
\r
264 DELETE FROM tblMessageListRequests WHERE IdentityID=old.IdentityID;\
\r
265 DELETE FROM tblMessageRequests WHERE IdentityID=old.IdentityID;\
\r
266 DELETE FROM tblPeerTrust WHERE IdentityID=old.IdentityID;\
\r
267 DELETE FROM tblTrustListRequests WHERE IdentityID=old.IdentityID;\
\r
270 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteLocalIdentity AFTER DELETE ON tblLocalIdentity \
\r
273 DELETE FROM tblIdentityIntroductionInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
274 DELETE FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
275 DELETE FROM tblLocalIdentityInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
276 DELETE FROM tblMessageInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
277 DELETE FROM tblMessageListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
278 DELETE FROM tblTrustListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
281 // delete introduction puzzles that were half-way inserted
\r
282 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");
\r
284 // delete stale introduction puzzles (2 or more days old)
\r
285 date.SetToGMTime();
\r
286 date.Add(0,0,0,-2);
\r
287 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
288 db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
290 // insert SomeDude's public key
\r
291 date.SetToGMTime();
\r
292 db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw,iXez4j3qCpd596TxXiJgZyTq9o-CElEuJxm~jNNZAuA,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");
\r
296 void SetupDefaultOptions()
\r
298 // 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
300 std::ostringstream tempstr; // must set tempstr to "" between db inserts
\r
301 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
302 SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");
\r
306 tempstr << LogFile::LOGLEVEL_DEBUG;
\r
307 st.Bind(0,"LogLevel");
\r
308 st.Bind(1,tempstr.str());
\r
309 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
314 st.Bind(0,"NNTPListenPort");
\r
316 st.Bind(2,"The port that the NNTP service will listen for incoming connections.");
\r
320 // NNTPBindAddresses
\r
321 st.Bind(0,"NNTPBindAddresses");
\r
322 st.Bind(1,"localhost");
\r
323 st.Bind(2,"A comma separated list of valid IPv4 or IPv6 addresses/hostnames that the NNTP service will try to bind to.");
\r
327 st.Bind(0,"NNTPAllowPost");
\r
329 st.Bind(2,"Allow posting messages from NNTP. Setting to false will make the newsgroups read only.");
\r
334 st.Bind(0,"StartNNTP");
\r
336 st.Bind(2,"Start NNTP server.");
\r
340 st.Bind(0,"StartHTTP");
\r
342 st.Bind(2,"Start HTTP server.");
\r
346 st.Bind(0,"HTTPListenPort");
\r
348 st.Bind(2,"Port HTTP server will listen on.");
\r
352 // StartFreenetUpdater
\r
353 st.Bind(0,"StartFreenetUpdater");
\r
355 st.Bind(2,"Start Freenet Updater thread.");
\r
360 st.Bind(0,"FCPHost");
\r
361 st.Bind(1,"127.0.0.1");
\r
362 st.Bind(2,"Host name or address of Freenet node.");
\r
367 st.Bind(0,"FCPPort");
\r
369 st.Bind(2,"The port that Freenet is listening for FCP connections on.");
\r
373 st.Bind(0,"MessageBase");
\r
375 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
379 st.Bind(0,"MaxIdentityRequests");
\r
381 st.Bind(2,"Maximum number of concurrent requests for new Identity xml files");
\r
385 st.Bind(0,"MaxIdentityIntroductionRequests");
\r
387 st.Bind(2,"Maximum number of concurrent identities requesting IdentityIntroduction xml files. Each identity may have multiple requests pending.");
\r
391 st.Bind(0,"MaxIntroductionPuzzleRequests");
\r
393 st.Bind(2,"Maximum number of concurrent requests for new IntroductionPuzzle xml files");
\r
397 st.Bind(0,"MaxTrustListRequests");
\r
399 st.Bind(2,"Maximum number of concurrent requests for new Trust Lists");
\r
403 st.Bind(0,"MaxMessageListRequests");
\r
405 st.Bind(2,"Maximum number of concurrent requests for new Message Lists");
\r
409 st.Bind(0,"MaxMessageRequests");
\r
411 st.Bind(2,"Maximum number of concurrent requests for new Messages");
\r
415 st.Bind(0,"MinLocalMessageTrust");
\r
417 st.Bind(2,"Specifies a local message trust level that a peer must have before its messages will be downloaded.");
\r
421 st.Bind(0,"MinPeerMessageTrust");
\r
423 st.Bind(2,"Specifies a peer message trust level that a peer must have before its messages will be downloaded.");
\r
427 st.Bind(0,"MinLocalTrustListTrust");
\r
429 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
433 st.Bind(0,"MinPeerTrustListTrust");
\r
435 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
439 st.Bind(0,"MessageDownloadMaxDaysBackward");
\r
441 st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");
\r
445 st.Bind(0,"MessageListDaysBackward");
\r
447 st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");
\r
453 void SetupLogFile()
\r
456 std::string configval;
\r
459 date.SetToGMTime();
\r
461 LogFile::Instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");
\r
462 LogFile::Instance()->OpenFile();
\r
463 LogFile::Instance()->SetWriteNewLine(true);
\r
464 LogFile::Instance()->SetWriteDate(true);
\r
465 LogFile::Instance()->SetWriteLogLevel(true);
\r
467 if(Option::Instance()->Get("LogLevel",configval)==false)
\r
470 Option::Instance()->Set("LogLevel",configval);
\r
472 if(StringFunctions::Convert(configval,loglevel)==false)
\r
474 loglevel=LogFile::LOGLEVEL_DEBUG;
\r
475 Option::Instance()->Set("LogLevel",loglevel);
\r
477 LogFile::Instance()->SetLogLevel((LogFile::LogLevel)loglevel);
\r
480 void SetupNetwork()
\r
484 WSAStartup(MAKEWORD(2,2),&wsadata);
\r
488 void ShutdownNetwork()
\r
495 void ShutdownThreads(std::vector<PThread::Thread *> &threads)
\r
497 std::vector<PThread::Thread *>::iterator i;
\r
498 for(i=threads.begin(); i!=threads.end(); i++)
\r
500 /* if((*i)->wait(1)==false)
\r
514 for(i=threads.begin(); i!=threads.end(); i++)
\r
516 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");
\r
526 void StartThreads(std::vector<PThread::Thread *> &threads)
\r
528 std::string startfreenet;
\r
529 std::string startnntp;
\r
530 std::string starthttp;
\r
532 if(Option::Instance()->Get("StartFreenetUpdater",startfreenet)==false)
\r
534 startfreenet="true";
\r
535 Option::Instance()->Set("StartFreenetUpdater","true");
\r
538 if(Option::Instance()->Get("StartNNTP",startnntp)==false)
\r
541 Option::Instance()->Set("StartNNTP","true");
\r
544 if(Option::Instance()->Get("StartHTTP",starthttp)==false)
\r
547 Option::Instance()->Set("StartHTTP","true");
\r
550 if(startfreenet=="true")
\r
552 PThread::Thread *t=new PThread::Thread(new FreenetMasterThread());
\r
553 threads.push_back(t);
\r
556 if(startnntp=="true")
\r
558 PThread::Thread *t=new PThread::Thread(new NNTPListener());
\r
559 threads.push_back(t);
\r
562 if(starthttp=="true")
\r
564 PThread::Thread *t=new PThread::Thread(new HTTPThread());
\r
565 threads.push_back(t);
\r