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 // TODO remove this - temp fix for problem in 0.1.8
\r
30 db->Execute("DELETE FROM tblMessageBoard WHERE MessageID NOT IN (SELECT MessageID FROM tblMessage);");
\r
32 db->Execute("CREATE TABLE IF NOT EXISTS tblDBVersion(\
\r
37 SQLite3DB::Statement st=db->Prepare("SELECT Major,Minor FROM tblDBVersion;");
\r
39 if(st.RowReturned())
\r
43 st.ResultInt(0,major);
\r
44 st.ResultInt(1,minor);
\r
48 db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,0);");
\r
51 db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\
\r
52 Option TEXT UNIQUE,\
\r
53 OptionValue TEXT NOT NULL,\
\r
54 OptionDescription TEXT\
\r
57 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\
\r
58 LocalIdentityID INTEGER PRIMARY KEY,\
\r
62 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
63 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
64 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
65 InsertingIdentity BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\
\r
66 LastInsertedIdentity DATETIME,\
\r
67 InsertingPuzzle BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\
\r
68 LastInsertedPuzzle DATETIME,\
\r
69 InsertingTrustList BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\
\r
70 LastInsertedTrustList DATETIME,\
\r
71 InsertingBoardList BOOL CHECK(InsertingBoardList IN('true','false')) DEFAULT 'false',\
\r
72 LastInsertedBoardList DATETIME,\
\r
73 InsertingMessageList BOOL CHECK(InsertingMessageList IN('true','false')) DEFAULT 'false',\
\r
74 LastInsertedMessageList DATETIME\
\r
77 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentityInserts(\
\r
78 LocalIdentityID INTEGER,\
\r
80 InsertIndex INTEGER\
\r
83 db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListInserts(\
\r
84 LocalIdentityID INTEGER,\
\r
86 InsertIndex INTEGER\
\r
89 db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListRequests(\
\r
90 IdentityID INTEGER,\
\r
92 RequestIndex INTEGER,\
\r
93 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
96 db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleInserts(\
\r
98 LocalIdentityID INTEGER,\
\r
100 InsertIndex INTEGER,\
\r
104 PuzzleSolution TEXT,\
\r
105 FoundSolution BOOL CHECK(FoundSolution IN('true','false')) DEFAULT 'false'\
\r
108 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\
\r
109 IdentityID INTEGER PRIMARY KEY,\
\r
110 PublicKey TEXT UNIQUE,\
\r
112 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
113 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
114 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
115 DateAdded DATETIME,\
\r
116 LastSeen DATETIME,\
\r
117 LocalMessageTrust INTEGER CHECK(LocalMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
118 PeerMessageTrust INTEGER CHECK(PeerMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
119 LocalTrustListTrust INTEGER CHECK(LocalTrustListTrust BETWEEN 0 AND 100) DEFAULT 50,\
\r
120 PeerTrustListTrust INTEGER CHECK(PeerTrustListTrust BETWEEN 0 AND 100) DEFAULT 50\
\r
123 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityRequests(\
\r
124 IdentityID INTEGER,\
\r
126 RequestIndex INTEGER,\
\r
127 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
130 db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleRequests(\
\r
131 IdentityID INTEGER,\
\r
133 RequestIndex INTEGER,\
\r
134 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false',\
\r
141 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityIntroductionInserts(\
\r
142 LocalIdentityID INTEGER,\
\r
146 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
149 db->Execute("CREATE TABLE IF NOT EXISTS tblPeerTrust(\
\r
150 IdentityID INTEGER,\
\r
151 TargetIdentityID INTEGER,\
\r
152 MessageTrust INTEGER CHECK(MessageTrust BETWEEN 0 AND 100),\
\r
153 TrustListTrust INTEGER CHECK(TrustListTrust BETWEEN 0 AND 100)\
\r
156 db->Execute("CREATE TABLE IF NOT EXISTS tblBoard(\
\r
157 BoardID INTEGER PRIMARY KEY,\
\r
158 BoardName TEXT UNIQUE,\
\r
159 BoardDescription TEXT,\
\r
160 DateAdded DATETIME\
\r
163 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('fms','Freenet Message System','2007-12-01');");
\r
164 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('freenet','Discussion about Freenet','2007-12-01');");
\r
165 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('public','Public discussion','2007-12-01');");
\r
166 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('test','Test board','2007-12-01');");
\r
168 db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\
\r
169 MessageID INTEGER PRIMARY KEY,\
\r
170 IdentityID INTEGER,\
\r
175 MessageUUID TEXT UNIQUE,\
\r
176 ReplyBoardID INTEGER,\
\r
180 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageReplyTo(\
\r
181 MessageID INTEGER,\
\r
182 ReplyToMessageUUID TEXT,\
\r
183 ReplyOrder INTEGER\
\r
186 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageBoard(\
\r
187 MessageID INTEGER,\
\r
191 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListRequests(\
\r
192 IdentityID INTEGER,\
\r
194 RequestIndex INTEGER,\
\r
195 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
198 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageRequests(\
\r
199 IdentityID INTEGER,\
\r
201 RequestIndex INTEGER,\
\r
202 FromMessageList BOOL CHECK(FromMessageList IN('true','false')) DEFAULT 'false',\
\r
203 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
206 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageInserts(\
\r
207 LocalIdentityID INTEGER,\
\r
209 InsertIndex INTEGER,\
\r
210 MessageUUID TEXT UNIQUE,\
\r
212 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
215 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListInserts(\
\r
216 LocalIdentityID INTEGER,\
\r
218 InsertIndex INTEGER,\
\r
219 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
222 db->Execute("CREATE TABLE IF NOT EXISTS tblAdministrationBoard(\
\r
223 BoardID INTEGER UNIQUE,\
\r
224 ModifyLocalMessageTrust INTEGER,\
\r
225 ModifyLocalTrustListTrust INTEGER\
\r
228 // MessageInserter will insert a record into this temp table which the MessageListInserter will query for and insert a MessageList when needed
\r
229 db->Execute("CREATE TEMPORARY TABLE IF NOT EXISTS tmpMessageListInsert(\
\r
230 LocalIdentityID INTEGER,\
\r
234 // low / high / message count for each board
\r
235 db->Execute("CREATE VIEW IF NOT EXISTS vwBoardStats AS \
\r
236 SELECT tblBoard.BoardID AS 'BoardID', IFNULL(MIN(MessageID),0) AS 'LowMessageID', IFNULL(MAX(MessageID),0) AS 'HighMessageID', COUNT(MessageID) AS 'MessageCount' \
\r
237 FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID \
\r
238 WHERE MessageID>=0 OR MessageID IS NULL \
\r
239 GROUP BY tblBoard.BoardID;");
\r
241 // calculates peer trust
\r
242 db->Execute("CREATE VIEW IF NOT EXISTS vwCalculatedPeerTrust AS \
\r
243 SELECT TargetIdentityID, \
\r
244 ROUND(SUM(MessageTrust*(LocalMessageTrust/100.0))/SUM(LocalMessageTrust/100.0),0) AS 'PeerMessageTrust', \
\r
245 ROUND(SUM(TrustListTrust*(LocalTrustListTrust/100.0))/SUM(LocalTrustListTrust/100.0),0) AS 'PeerTrustListTrust' \
\r
246 FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID \
\r
247 WHERE LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') \
\r
248 AND ( PeerTrustListTrust IS NULL OR PeerTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerTrustListTrust') ) \
\r
249 GROUP BY TargetIdentityID;");
\r
252 These peer trust calculations are too CPU intensive to be triggers - they were called every time a new trust list was processed
\r
253 All trust levels will now be recalculated every hour in the PeriodicDBMaintenance class
\r
255 // drop existing triggers
\r
256 db->Execute("DROP TRIGGER IF EXISTS trgDeleteOntblPeerTrust;");
\r
257 db->Execute("DROP TRIGGER IF EXISTS trgInsertOntblPeerTrust;");
\r
258 db->Execute("DROP TRIGGER IF EXISTS trgUpdateOntblPeerTrust;");
\r
259 db->Execute("DROP TRIGGER IF EXISTS trgUpdateLocalTrustLevels;");
\r
261 // update PeerTrustLevel when deleting a record from tblPeerTrust
\r
262 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \
\r
265 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
268 // update PeerTrustLevel when inserting a record into tblPeerTrust
\r
269 db->Execute("CREATE TRIGGER IF NOT EXISTS trgInsertOntblPeerTrust AFTER INSERT ON tblPeerTrust \
\r
272 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
275 // update PeerTrustLevel when updating a record in tblPeerTrust
\r
276 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateOntblPeerTrust AFTER UPDATE ON tblPeerTrust \
\r
279 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
280 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
283 // 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
284 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateLocalTrustLevels AFTER UPDATE OF LocalMessageTrust,LocalTrustListTrust ON tblIdentity \
\r
287 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\
\r
291 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \
\r
294 DELETE FROM tblMessageBoard WHERE tblMessageBoard.MessageID=old.MessageID;\
\r
295 DELETE FROM tblMessageReplyTo WHERE tblMessageReplyTo.MessageID=old.MessageID;\
\r
298 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteIdentity AFTER DELETE ON tblIdentity \
\r
301 DELETE FROM tblIdentityRequests WHERE IdentityID=old.IdentityID;\
\r
302 DELETE FROM tblIntroductionPuzzleRequests WHERE IdentityID=old.IdentityID;\
\r
303 DELETE FROM tblMessageListRequests WHERE IdentityID=old.IdentityID;\
\r
304 DELETE FROM tblMessageRequests WHERE IdentityID=old.IdentityID;\
\r
305 DELETE FROM tblPeerTrust WHERE IdentityID=old.IdentityID;\
\r
306 DELETE FROM tblTrustListRequests WHERE IdentityID=old.IdentityID;\
\r
309 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteLocalIdentity AFTER DELETE ON tblLocalIdentity \
\r
312 DELETE FROM tblIdentityIntroductionInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
313 DELETE FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
314 DELETE FROM tblLocalIdentityInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
315 DELETE FROM tblMessageInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
316 DELETE FROM tblMessageListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
317 DELETE FROM tblTrustListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
320 // delete introduction puzzles that were half-way inserted
\r
321 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");
\r
323 // delete stale introduction puzzles (2 or more days old)
\r
324 date.SetToGMTime();
\r
325 date.Add(0,0,0,-2);
\r
326 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
327 db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
329 // insert SomeDude's public key
\r
330 date.SetToGMTime();
\r
331 db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw,iXez4j3qCpd596TxXiJgZyTq9o-CElEuJxm~jNNZAuA,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");
\r
335 void SetupDefaultOptions()
\r
337 // 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
339 std::ostringstream tempstr; // must set tempstr to "" between db inserts
\r
340 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
341 SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");
\r
345 tempstr << LogFile::LOGLEVEL_DEBUG;
\r
346 st.Bind(0,"LogLevel");
\r
347 st.Bind(1,tempstr.str());
\r
348 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
353 st.Bind(0,"NNTPListenPort");
\r
355 st.Bind(2,"The port that the NNTP service will listen for incoming connections.");
\r
359 // NNTPBindAddresses
\r
360 st.Bind(0,"NNTPBindAddresses");
\r
361 st.Bind(1,"localhost");
\r
362 st.Bind(2,"A comma separated list of valid IPv4 or IPv6 addresses/hostnames that the NNTP service will try to bind to.");
\r
366 st.Bind(0,"NNTPAllowPost");
\r
368 st.Bind(2,"Allow posting messages from NNTP. Setting to false will make the newsgroups read only.");
\r
373 st.Bind(0,"StartNNTP");
\r
375 st.Bind(2,"Start NNTP server.");
\r
379 st.Bind(0,"StartHTTP");
\r
381 st.Bind(2,"Start HTTP server.");
\r
385 st.Bind(0,"HTTPListenPort");
\r
387 st.Bind(2,"Port HTTP server will listen on.");
\r
391 // StartFreenetUpdater
\r
392 st.Bind(0,"StartFreenetUpdater");
\r
394 st.Bind(2,"Start Freenet Updater thread.");
\r
399 st.Bind(0,"FCPHost");
\r
400 st.Bind(1,"127.0.0.1");
\r
401 st.Bind(2,"Host name or address of Freenet node.");
\r
406 st.Bind(0,"FCPPort");
\r
408 st.Bind(2,"The port that Freenet is listening for FCP connections on.");
\r
412 st.Bind(0,"MessageBase");
\r
414 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
418 st.Bind(0,"MaxIdentityRequests");
\r
420 st.Bind(2,"Maximum number of concurrent requests for new Identity xml files");
\r
424 st.Bind(0,"MaxIdentityIntroductionRequests");
\r
426 st.Bind(2,"Maximum number of concurrent identities requesting IdentityIntroduction xml files. Each identity may have multiple requests pending.");
\r
430 st.Bind(0,"MaxIntroductionPuzzleRequests");
\r
432 st.Bind(2,"Maximum number of concurrent requests for new IntroductionPuzzle xml files");
\r
436 st.Bind(0,"MaxTrustListRequests");
\r
438 st.Bind(2,"Maximum number of concurrent requests for new Trust Lists");
\r
442 st.Bind(0,"MaxMessageListRequests");
\r
444 st.Bind(2,"Maximum number of concurrent requests for new Message Lists");
\r
448 st.Bind(0,"MaxMessageRequests");
\r
450 st.Bind(2,"Maximum number of concurrent requests for new Messages");
\r
454 st.Bind(0,"MinLocalMessageTrust");
\r
456 st.Bind(2,"Specifies a local message trust level that a peer must have before its messages will be downloaded.");
\r
460 st.Bind(0,"MinPeerMessageTrust");
\r
462 st.Bind(2,"Specifies a peer message trust level that a peer must have before its messages will be downloaded.");
\r
466 st.Bind(0,"MinLocalTrustListTrust");
\r
468 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
472 st.Bind(0,"MinPeerTrustListTrust");
\r
474 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
478 st.Bind(0,"MessageDownloadMaxDaysBackward");
\r
480 st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");
\r
484 st.Bind(0,"MessageListDaysBackward");
\r
486 st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");
\r
492 void SetupLogFile()
\r
495 std::string configval;
\r
498 date.SetToGMTime();
\r
500 LogFile::Instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");
\r
501 LogFile::Instance()->OpenFile();
\r
502 LogFile::Instance()->SetWriteNewLine(true);
\r
503 LogFile::Instance()->SetWriteDate(true);
\r
504 LogFile::Instance()->SetWriteLogLevel(true);
\r
506 if(Option::Instance()->Get("LogLevel",configval)==false)
\r
509 Option::Instance()->Set("LogLevel",configval);
\r
511 if(StringFunctions::Convert(configval,loglevel)==false)
\r
513 loglevel=LogFile::LOGLEVEL_DEBUG;
\r
514 Option::Instance()->Set("LogLevel",loglevel);
\r
516 LogFile::Instance()->SetLogLevel((LogFile::LogLevel)loglevel);
\r
519 void SetupNetwork()
\r
523 WSAStartup(MAKEWORD(2,2),&wsadata);
\r
527 void ShutdownNetwork()
\r
534 void ShutdownThreads(std::vector<PThread::Thread *> &threads)
\r
536 std::vector<PThread::Thread *>::iterator i;
\r
537 for(i=threads.begin(); i!=threads.end(); i++)
\r
539 /* if((*i)->wait(1)==false)
\r
553 for(i=threads.begin(); i!=threads.end(); i++)
\r
555 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");
\r
565 void StartThreads(std::vector<PThread::Thread *> &threads)
\r
567 std::string startfreenet;
\r
568 std::string startnntp;
\r
569 std::string starthttp;
\r
571 if(Option::Instance()->Get("StartFreenetUpdater",startfreenet)==false)
\r
573 startfreenet="true";
\r
574 Option::Instance()->Set("StartFreenetUpdater","true");
\r
577 if(Option::Instance()->Get("StartNNTP",startnntp)==false)
\r
580 Option::Instance()->Set("StartNNTP","true");
\r
583 if(Option::Instance()->Get("StartHTTP",starthttp)==false)
\r
586 Option::Instance()->Set("StartHTTP","true");
\r
589 if(startfreenet=="true")
\r
591 PThread::Thread *t=new PThread::Thread(new FreenetMasterThread());
\r
592 threads.push_back(t);
\r
595 if(startnntp=="true")
\r
597 PThread::Thread *t=new PThread::Thread(new NNTPListener());
\r
598 threads.push_back(t);
\r
601 if(starthttp=="true")
\r
603 PThread::Thread *t=new PThread::Thread(new HTTPThread());
\r
604 threads.push_back(t);
\r