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
10 #include "../include/threadcontroller.h"
\r
13 #include <winsock2.h>
\r
20 bool wantshutdown=false;
\r
26 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
28 db->Open("fms.db3");
\r
29 db->SetBusyTimeout(10000); // set timeout to 10 seconds
\r
30 db->Execute("VACUUM;");
\r
32 // TODO remove this - temp fix for problem in 0.1.8
\r
33 db->Execute("DELETE FROM tblMessageBoard WHERE MessageID NOT IN (SELECT MessageID FROM tblMessage);");
\r
35 db->Execute("CREATE TABLE IF NOT EXISTS tblDBVersion(\
\r
40 SQLite3DB::Statement st=db->Prepare("SELECT Major,Minor FROM tblDBVersion;");
\r
42 if(st.RowReturned())
\r
46 st.ResultInt(0,major);
\r
47 st.ResultInt(1,minor);
\r
49 if(major==1 && minor==0)
\r
51 ConvertDB0100To0101();
\r
55 if(major==1 && (minor==1 || minor==2))
\r
57 ConvertDB0101To0103();
\r
61 if(major==1 && minor==3)
\r
63 ConvertDB0103To0104();
\r
70 db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,4);");
\r
73 db->Execute("UPDATE tblDBVersion SET Major=1, Minor=4;");
\r
75 db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\
\r
76 Option TEXT UNIQUE,\
\r
77 OptionValue TEXT NOT NULL,\
\r
78 OptionDescription TEXT\
\r
81 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\
\r
82 LocalIdentityID INTEGER PRIMARY KEY,\
\r
84 PublicKey TEXT UNIQUE,\
\r
85 PrivateKey TEXT UNIQUE,\
\r
86 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
87 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
88 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
89 InsertingIdentity BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\
\r
90 LastInsertedIdentity DATETIME,\
\r
91 InsertingPuzzle BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\
\r
92 LastInsertedPuzzle DATETIME,\
\r
93 InsertingTrustList BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\
\r
94 LastInsertedTrustList DATETIME,\
\r
95 InsertingBoardList BOOL CHECK(InsertingBoardList IN('true','false')) DEFAULT 'false',\
\r
96 LastInsertedBoardList DATETIME,\
\r
97 InsertingMessageList BOOL CHECK(InsertingMessageList IN('true','false')) DEFAULT 'false',\
\r
98 LastInsertedMessageList DATETIME,\
\r
99 DateCreated DATETIME\
\r
102 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentityInserts(\
\r
103 LocalIdentityID INTEGER,\
\r
105 InsertIndex INTEGER\
\r
108 db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListInserts(\
\r
109 LocalIdentityID INTEGER,\
\r
111 InsertIndex INTEGER\
\r
114 db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListRequests(\
\r
115 IdentityID INTEGER,\
\r
117 RequestIndex INTEGER,\
\r
118 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
121 db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleInserts(\
\r
123 LocalIdentityID INTEGER,\
\r
125 InsertIndex INTEGER,\
\r
129 PuzzleSolution TEXT,\
\r
130 FoundSolution BOOL CHECK(FoundSolution IN('true','false')) DEFAULT 'false'\
\r
133 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\
\r
134 IdentityID INTEGER PRIMARY KEY,\
\r
135 PublicKey TEXT UNIQUE,\
\r
137 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
138 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
139 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
140 DateAdded DATETIME,\
\r
141 LastSeen DATETIME,\
\r
142 LocalMessageTrust INTEGER CHECK(LocalMessageTrust BETWEEN 0 AND 100) DEFAULT NULL,\
\r
143 PeerMessageTrust INTEGER CHECK(PeerMessageTrust BETWEEN 0 AND 100) DEFAULT NULL,\
\r
144 LocalTrustListTrust INTEGER CHECK(LocalTrustListTrust BETWEEN 0 AND 100) DEFAULT NULL,\
\r
145 PeerTrustListTrust INTEGER CHECK(PeerTrustListTrust BETWEEN 0 AND 100) DEFAULT NULL\
\r
148 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityRequests(\
\r
149 IdentityID INTEGER,\
\r
151 RequestIndex INTEGER,\
\r
152 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
155 db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleRequests(\
\r
156 IdentityID INTEGER,\
\r
158 RequestIndex INTEGER,\
\r
159 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false',\
\r
166 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityIntroductionInserts(\
\r
167 LocalIdentityID INTEGER,\
\r
171 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
174 db->Execute("CREATE TABLE IF NOT EXISTS tblPeerTrust(\
\r
175 IdentityID INTEGER,\
\r
176 TargetIdentityID INTEGER,\
\r
177 MessageTrust INTEGER CHECK(MessageTrust BETWEEN 0 AND 100),\
\r
178 TrustListTrust INTEGER CHECK(TrustListTrust BETWEEN 0 AND 100)\
\r
181 db->Execute("CREATE TABLE IF NOT EXISTS tblBoard(\
\r
182 BoardID INTEGER PRIMARY KEY,\
\r
183 BoardName TEXT UNIQUE,\
\r
184 BoardDescription TEXT,\
\r
185 DateAdded DATETIME,\
\r
186 SaveReceivedMessages BOOL CHECK(SaveReceivedMessages IN('true','false')) DEFAULT 'true'\
\r
189 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('fms','Freenet Message System','2007-12-01 12:00:00');");
\r
190 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('freenet','Discussion about Freenet','2007-12-01 12:00:00');");
\r
191 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('public','Public discussion','2007-12-01 12:00:00');");
\r
192 db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('test','Test board','2007-12-01 12:00:00');");
\r
194 db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\
\r
195 MessageID INTEGER PRIMARY KEY,\
\r
196 IdentityID INTEGER,\
\r
201 MessageUUID TEXT UNIQUE,\
\r
202 ReplyBoardID INTEGER,\
\r
204 MessageIndex INTEGER\
\r
207 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageReplyTo(\
\r
208 MessageID INTEGER,\
\r
209 ReplyToMessageUUID TEXT,\
\r
210 ReplyOrder INTEGER\
\r
213 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageBoard(\
\r
214 MessageID INTEGER,\
\r
218 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListRequests(\
\r
219 IdentityID INTEGER,\
\r
221 RequestIndex INTEGER,\
\r
222 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
225 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageRequests(\
\r
226 IdentityID INTEGER,\
\r
228 RequestIndex INTEGER,\
\r
229 FromMessageList BOOL CHECK(FromMessageList IN('true','false')) DEFAULT 'false',\
\r
230 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
233 db->Execute("CREATE UNIQUE INDEX IF NOT EXISTS idxMessageRequest ON tblMessageRequests(IdentityID,Day,RequestIndex);");
\r
235 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageInserts(\
\r
236 LocalIdentityID INTEGER,\
\r
238 InsertIndex INTEGER,\
\r
239 MessageUUID TEXT UNIQUE,\
\r
241 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
244 db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListInserts(\
\r
245 LocalIdentityID INTEGER,\
\r
247 InsertIndex INTEGER,\
\r
248 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
251 db->Execute("CREATE TABLE IF NOT EXISTS tblAdministrationBoard(\
\r
252 BoardID INTEGER UNIQUE,\
\r
253 ModifyLocalMessageTrust INTEGER,\
\r
254 ModifyLocalTrustListTrust INTEGER\
\r
257 db->Execute("CREATE TABLE IF NOT EXISTS tblBoardListInserts(\
\r
258 LocalIdentityID INTEGER,\
\r
260 InsertIndex INTEGER,\
\r
261 Inserted BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\
\r
264 db->Execute("CREATE TABLE IF NOT EXISTS tblBoardListRequests(\
\r
265 IdentityID INTEGER,\
\r
267 RequestIndex INTEGER,\
\r
268 Found BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\
\r
271 // MessageInserter will insert a record into this temp table which the MessageListInserter will query for and insert a MessageList when needed
\r
272 db->Execute("CREATE TEMPORARY TABLE IF NOT EXISTS tmpMessageListInsert(\
\r
273 LocalIdentityID INTEGER,\
\r
277 // low / high / message count for each board
\r
278 db->Execute("CREATE VIEW IF NOT EXISTS vwBoardStats AS \
\r
279 SELECT tblBoard.BoardID AS 'BoardID', IFNULL(MIN(MessageID),0) AS 'LowMessageID', IFNULL(MAX(MessageID),0) AS 'HighMessageID', COUNT(MessageID) AS 'MessageCount' \
\r
280 FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID \
\r
281 WHERE MessageID>=0 OR MessageID IS NULL \
\r
282 GROUP BY tblBoard.BoardID;");
\r
284 // calculates peer trust
\r
285 // do the (MessageTrust+1)*LocalTrustListTrust/(MessageTrust+1)/100.0 - so it MessageTrust or TrustListTrust is NULL, the calc will be NULL and it won't be included at all in the average
\r
286 // need the +1 so that when the values are 0 the result is not 0
\r
287 db->Execute("DROP VIEW IF EXISTS vwCalculatedPeerTrust;");
\r
288 db->Execute("CREATE VIEW IF NOT EXISTS vwCalculatedPeerTrust AS \
\r
289 SELECT TargetIdentityID, \
\r
290 ROUND(SUM(MessageTrust*(LocalTrustListTrust/100.0))/SUM(((MessageTrust+1)*LocalTrustListTrust/(MessageTrust+1))/100.0),0) AS 'PeerMessageTrust', \
\r
291 ROUND(SUM(TrustListTrust*(LocalTrustListTrust/100.0))/SUM(((TrustListTrust+1)*LocalTrustListTrust/(TrustListTrust+1))/100.0),0) AS 'PeerTrustListTrust' \
\r
292 FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID \
\r
293 WHERE LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') \
\r
294 AND ( PeerTrustListTrust IS NULL OR PeerTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerTrustListTrust') ) \
\r
295 GROUP BY TargetIdentityID;");
\r
298 These peer trust calculations are too CPU intensive to be triggers - they were called every time a new trust list was processed
\r
299 All trust levels will now be recalculated every hour in the PeriodicDBMaintenance class
\r
301 // drop existing triggers
\r
302 db->Execute("DROP TRIGGER IF EXISTS trgDeleteOntblPeerTrust;");
\r
303 db->Execute("DROP TRIGGER IF EXISTS trgInsertOntblPeerTrust;");
\r
304 db->Execute("DROP TRIGGER IF EXISTS trgUpdateOntblPeerTrust;");
\r
305 db->Execute("DROP TRIGGER IF EXISTS trgUpdateLocalTrustLevels;");
\r
307 // update PeerTrustLevel when deleting a record from tblPeerTrust
\r
308 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \
\r
311 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
314 // update PeerTrustLevel when inserting a record into tblPeerTrust
\r
315 db->Execute("CREATE TRIGGER IF NOT EXISTS trgInsertOntblPeerTrust AFTER INSERT ON tblPeerTrust \
\r
318 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
321 // update PeerTrustLevel when updating a record in tblPeerTrust
\r
322 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateOntblPeerTrust AFTER UPDATE ON tblPeerTrust \
\r
325 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
326 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
329 // 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
330 db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateLocalTrustLevels AFTER UPDATE OF LocalMessageTrust,LocalTrustListTrust ON tblIdentity \
\r
333 UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\
\r
337 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \
\r
340 DELETE FROM tblMessageBoard WHERE tblMessageBoard.MessageID=old.MessageID;\
\r
341 DELETE FROM tblMessageReplyTo WHERE tblMessageReplyTo.MessageID=old.MessageID;\
\r
344 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteIdentity AFTER DELETE ON tblIdentity \
\r
347 DELETE FROM tblIdentityRequests WHERE IdentityID=old.IdentityID;\
\r
348 DELETE FROM tblIntroductionPuzzleRequests WHERE IdentityID=old.IdentityID;\
\r
349 DELETE FROM tblMessageListRequests WHERE IdentityID=old.IdentityID;\
\r
350 DELETE FROM tblMessageRequests WHERE IdentityID=old.IdentityID;\
\r
351 DELETE FROM tblPeerTrust WHERE IdentityID=old.IdentityID;\
\r
352 DELETE FROM tblTrustListRequests WHERE IdentityID=old.IdentityID;\
\r
355 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteLocalIdentity AFTER DELETE ON tblLocalIdentity \
\r
358 DELETE FROM tblIdentityIntroductionInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
359 DELETE FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
360 DELETE FROM tblLocalIdentityInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
361 DELETE FROM tblMessageInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
362 DELETE FROM tblMessageListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
363 DELETE FROM tblTrustListInserts WHERE LocalIdentityID=old.LocalIdentityID;\
\r
366 db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteBoard AFTER DELETE ON tblBoard \
\r
369 DELETE FROM tblMessageBoard WHERE BoardID=old.BoardID;\
\r
372 // delete introduction puzzles that were half-way inserted
\r
373 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");
\r
375 // delete stale introduction puzzles (2 or more days old)
\r
376 date.SetToGMTime();
\r
377 date.Add(0,0,0,-2);
\r
378 db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
379 db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");
\r
381 date.SetToGMTime();
\r
382 // insert SomeDude's public key
\r
383 db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded,LocalTrustListTrust) VALUES('SSK@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw,iXez4j3qCpd596TxXiJgZyTq9o-CElEuJxm~jNNZAuA,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"',51);");
\r
384 // insert Shadow Panther's public key
\r
385 db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@~mimyB1kmH4f7Cgsd2wM2Qv2NxrZHRMM6IY8~7EWRVQ,fxTKkR0TYhgMYb-vEGAv55sMOxCGD2xhE4ZxWHxdPz4,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");
\r
386 // insert garfield's public key
\r
387 db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@T8l1IEGU4-PoASFzgc2GYhIgRzUvZsKdoQWeuLHuTmM,QLxAPfkGis8l5NafNpSCdbxzXhBlu9WL8svcqJw9Mpo,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");
\r
389 // TODO remove sometime after 0.1.17
\r
390 FixCapitalBoardNames();
\r
394 void ConvertDB0100To0101()
\r
396 // added unique constraint to public and private key
\r
397 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
398 db->Execute("CREATE TEMPORARY TABLE tblLocalIdentityTemp AS SELECT * FROM tblLocalIdentity;");
\r
399 db->Execute("DROP TABLE IF EXISTS tblLocalIdentity;");
\r
400 db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\
\r
401 LocalIdentityID INTEGER PRIMARY KEY,\
\r
403 PublicKey TEXT UNIQUE,\
\r
404 PrivateKey TEXT UNIQUE,\
\r
405 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
406 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
407 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
408 InsertingIdentity BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\
\r
409 LastInsertedIdentity DATETIME,\
\r
410 InsertingPuzzle BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\
\r
411 LastInsertedPuzzle DATETIME,\
\r
412 InsertingTrustList BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\
\r
413 LastInsertedTrustList DATETIME,\
\r
414 InsertingBoardList BOOL CHECK(InsertingBoardList IN('true','false')) DEFAULT 'false',\
\r
415 LastInsertedBoardList DATETIME,\
\r
416 InsertingMessageList BOOL CHECK(InsertingMessageList IN('true','false')) DEFAULT 'false',\
\r
417 LastInsertedMessageList DATETIME\
\r
419 db->Execute("INSERT INTO tblLocalIdentity SELECT * FROM tblLocalIdentityTemp;");
\r
420 db->Execute("DROP TABLE IF EXISTS tblLocalIdentityTemp;");
\r
421 db->Execute("UPDATE tblDBVersion SET Major=1, Minor=1;");
\r
424 void ConvertDB0101To0103()
\r
426 // remove default 50 from trust fields and set default to NULL
\r
427 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
428 db->Execute("CREATE TEMPORARY TABLE tblIdentityTemp AS SELECT * FROM tblIdentity;");
\r
429 db->Execute("DROP TABLE IF EXISTS tblIdentity;");
\r
430 db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\
\r
431 IdentityID INTEGER PRIMARY KEY,\
\r
432 PublicKey TEXT UNIQUE,\
\r
434 SingleUse BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\
\r
435 PublishTrustList BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\
\r
436 PublishBoardList BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\
\r
437 DateAdded DATETIME,\
\r
438 LastSeen DATETIME,\
\r
439 LocalMessageTrust INTEGER CHECK(LocalMessageTrust BETWEEN 0 AND 100) DEFAULT NULL,\
\r
440 PeerMessageTrust INTEGER CHECK(PeerMessageTrust BETWEEN 0 AND 100) DEFAULT NULL,\
\r
441 LocalTrustListTrust INTEGER CHECK(LocalTrustListTrust BETWEEN 0 AND 100) DEFAULT NULL,\
\r
442 PeerTrustListTrust INTEGER CHECK(PeerTrustListTrust BETWEEN 0 AND 100) DEFAULT NULL\
\r
444 db->Execute("INSERT INTO tblIdentity SELECT * FROM tblIdentityTemp;");
\r
445 db->Execute("DROP TABLE IF EXISTS tblIdentityTemp;");
\r
447 // add SaveReceivedMessages field to tblBoard
\r
448 db->Execute("ALTER TABLE tblBoard ADD COLUMN SaveReceivedMessages BOOL CHECK(SaveReceivedMessages IN('true','false')) DEFAULT 'true';");
\r
450 db->Execute("UPDATE tblDBVersion SET Major=1, Minor=3;");
\r
453 void ConvertDB0103To0104()
\r
455 // add MessageIndex to tblMessage
\r
457 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
458 db->Execute("ALTER TABLE tblMessage ADD COLUMN MessageIndex INTEGER;");
\r
459 db->Execute("CREATE UNIQUE INDEX IF NOT EXISTS idxMessageRequest ON tblMessageRequests(IdentityID,Day,RequestIndex);");
\r
460 db->Execute("ALTER TABLE tblLocalIdentity ADD COLUMN DateCreated DATETIME;");
\r
461 date.SetToGMTime();
\r
462 db->Execute("UPDATE tblLocalIdentity SET DateCreated='"+date.Format("%Y-%m-%d %H:%M:%S")+"' WHERE DateCreated IS NULL;");
\r
463 db->Execute("UPDATE tblDBVersion SET Major=1, Minor=4;");
\r
466 void SetupDefaultOptions()
\r
468 // 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
470 std::ostringstream tempstr; // must set tempstr to "" between db inserts
\r
471 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
472 SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");
\r
476 tempstr << LogFile::LOGLEVEL_DEBUG;
\r
477 st.Bind(0,"LogLevel");
\r
478 st.Bind(1,tempstr.str());
\r
479 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
484 st.Bind(0,"NNTPListenPort");
\r
486 st.Bind(2,"The port that the NNTP service will listen for incoming connections.");
\r
490 // NNTPBindAddresses
\r
491 st.Bind(0,"NNTPBindAddresses");
\r
492 st.Bind(1,"localhost");
\r
493 st.Bind(2,"A comma separated list of valid IPv4 or IPv6 addresses/hostnames that the NNTP service will try to bind to.");
\r
497 st.Bind(0,"NNTPAllowPost");
\r
499 st.Bind(2,"Allow posting messages from NNTP. Setting to false will make the newsgroups read only.");
\r
504 st.Bind(0,"StartNNTP");
\r
506 st.Bind(2,"Start NNTP server.");
\r
510 st.Bind(0,"StartHTTP");
\r
512 st.Bind(2,"Start HTTP server.");
\r
516 st.Bind(0,"HTTPListenPort");
\r
518 st.Bind(2,"Port HTTP server will listen on.");
\r
522 // StartFreenetUpdater
\r
523 st.Bind(0,"StartFreenetUpdater");
\r
525 st.Bind(2,"Start Freenet Updater thread.");
\r
530 st.Bind(0,"FCPHost");
\r
531 st.Bind(1,"127.0.0.1");
\r
532 st.Bind(2,"Host name or address of Freenet node.");
\r
537 st.Bind(0,"FCPPort");
\r
539 st.Bind(2,"The port that Freenet is listening for FCP connections on.");
\r
543 st.Bind(0,"MessageBase");
\r
545 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
549 st.Bind(0,"MaxIdentityRequests");
\r
551 st.Bind(2,"Maximum number of concurrent requests for new Identity xml files");
\r
555 st.Bind(0,"MaxIdentityIntroductionRequests");
\r
557 st.Bind(2,"Maximum number of concurrent identities requesting IdentityIntroduction xml files. Each identity may have multiple requests pending.");
\r
561 st.Bind(0,"MaxIntroductionPuzzleRequests");
\r
563 st.Bind(2,"Maximum number of concurrent requests for new IntroductionPuzzle xml files");
\r
567 st.Bind(0,"MaxTrustListRequests");
\r
569 st.Bind(2,"Maximum number of concurrent requests for new Trust Lists");
\r
573 st.Bind(0,"MaxMessageListRequests");
\r
575 st.Bind(2,"Maximum number of concurrent requests for new Message Lists");
\r
579 st.Bind(0,"MaxMessageRequests");
\r
581 st.Bind(2,"Maximum number of concurrent requests for new Messages");
\r
585 st.Bind(0,"MinLocalMessageTrust");
\r
587 st.Bind(2,"Specifies a local message trust level that a peer must have before its messages will be downloaded.");
\r
591 st.Bind(0,"MinPeerMessageTrust");
\r
593 st.Bind(2,"Specifies a peer message trust level that a peer must have before its messages will be downloaded.");
\r
597 st.Bind(0,"MinLocalTrustListTrust");
\r
599 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
603 st.Bind(0,"MinPeerTrustListTrust");
\r
605 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
609 st.Bind(0,"MessageDownloadMaxDaysBackward");
\r
611 st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");
\r
615 st.Bind(0,"MessageListDaysBackward");
\r
617 st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");
\r
621 st.Bind(0,"MaxPeerMessagesPerDay");
\r
623 st.Bind(2,"The maximum number of messages you will download from each peer on a given day.");
\r
627 st.Bind(0,"MaxBoardListRequests");
\r
629 st.Bind(2,"The maximum number of concurrent requests for new Board Lists. Set to 0 to disable.");
\r
633 st.Bind(0,"MaxBoardsPerMessage");
\r
635 st.Bind(2,"The maximum number of boards a received message may be sent to. Boards over this limit will be ignored.");
\r
639 st.Bind(0,"ChangeMessageTrustOnReply");
\r
641 st.Bind(2,"How much the local message trust level of an identity should change when you reply to one of their messages.");
\r
645 st.Bind(0,"AddNewPostFromIdentities");
\r
646 st.Bind(1,"false");
\r
647 st.Bind(2,"Set to true to automatically create new identities when you send a message using a new name. If you set this to false, posting messages will fail until you manually create the identity.");
\r
651 st.Bind(0,"DeleteMessagesOlderThan");
\r
653 st.Bind(2,"Automatically delete messages older than this many days.");
\r
659 void SetupLogFile()
\r
662 std::string configval;
\r
665 date.SetToGMTime();
\r
667 LogFile::Instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");
\r
668 LogFile::Instance()->OpenFile();
\r
669 LogFile::Instance()->SetWriteNewLine(true);
\r
670 LogFile::Instance()->SetWriteDate(true);
\r
671 LogFile::Instance()->SetWriteLogLevel(true);
\r
673 if(Option::Instance()->Get("LogLevel",configval)==false)
\r
676 Option::Instance()->Set("LogLevel",configval);
\r
678 if(StringFunctions::Convert(configval,loglevel)==false)
\r
680 loglevel=LogFile::LOGLEVEL_DEBUG;
\r
681 Option::Instance()->Set("LogLevel",loglevel);
\r
683 LogFile::Instance()->SetLogLevel((LogFile::LogLevel)loglevel);
\r
686 void SetupNetwork()
\r
690 WSAStartup(MAKEWORD(2,2),&wsadata);
\r
696 ThreadController::Instance()->ShutdownThreads();
\r
700 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"FMS shutdown");
\r
701 LogFile::Instance()->WriteNewLine();
\r
704 void ShutdownNetwork()
\r
711 void SigHandler(int signum)
\r
718 void ShutdownThreads(std::vector<PThread::Thread *> &threads)
\r
720 std::vector<PThread::Thread *>::iterator i;
\r
721 for(i=threads.begin(); i!=threads.end(); i++)
\r
726 for(i=threads.begin(); i!=threads.end(); i++)
\r
728 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");
\r
738 void StartThreads(std::vector<PThread::Thread *> &threads)
\r
740 std::string startfreenet;
\r
741 std::string startnntp;
\r
742 std::string starthttp;
\r
744 if(Option::Instance()->Get("StartFreenetUpdater",startfreenet)==false)
\r
746 startfreenet="true";
\r
747 Option::Instance()->Set("StartFreenetUpdater","true");
\r
750 if(Option::Instance()->Get("StartNNTP",startnntp)==false)
\r
753 Option::Instance()->Set("StartNNTP","true");
\r
756 if(Option::Instance()->Get("StartHTTP",starthttp)==false)
\r
759 Option::Instance()->Set("StartHTTP","true");
\r
762 if(startfreenet=="true")
\r
764 PThread::Thread *t=new PThread::Thread(new FreenetMasterThread());
\r
765 threads.push_back(t);
\r
768 if(startnntp=="true")
\r
770 PThread::Thread *t=new PThread::Thread(new NNTPListener());
\r
771 threads.push_back(t);
\r
774 if(starthttp=="true")
\r
776 PThread::Thread *t=new PThread::Thread(new HTTPThread());
\r
777 threads.push_back(t);
\r
783 void FixCapitalBoardNames()
\r
785 SQLite3DB::DB *db=SQLite3DB::DB::Instance();
\r
787 SQLite3DB::Statement st=db->Prepare("SELECT BoardID,BoardName FROM tblBoard WHERE BoardID NOT IN (SELECT BoardID FROM tblAdministrationBoard);");
\r
788 SQLite3DB::Statement st2=db->Prepare("SELECT BoardID FROM tblBoard WHERE BoardName=?;");
\r
789 SQLite3DB::Statement del=db->Prepare("DELTE FROM tblBoard WHERE BoardID=?;");
\r
790 SQLite3DB::Statement upd=db->Prepare("UPDATE tblBoard SET BoardName=? WHERE BoardID=?;");
\r
791 SQLite3DB::Statement upd2=db->Prepare("UPDATE tblMessage SET ReplyBoardID=? WHERE ReplyBoardID=?;");
\r
792 SQLite3DB::Statement upd3=db->Prepare("UPDATE tblMessageBoard SET BoardID=? WHERE BoardID=?;");
\r
795 while(st.RowReturned())
\r
799 std::string name="";
\r
800 std::string lowername="";
\r
802 st.ResultInt(0,boardid);
\r
803 st.ResultText(1,name);
\r
806 StringFunctions::LowerCase(lowername,lowername);
\r
808 if(name!=lowername)
\r
810 st2.Bind(0,lowername);
\r
813 if(st2.RowReturned())
\r
815 st2.ResultInt(0,newboardid);
\r
817 upd2.Bind(0,newboardid);
\r
818 upd2.Bind(1,boardid);
\r
822 upd3.Bind(0,newboardid);
\r
823 upd3.Bind(1,boardid);
\r
827 del.Bind(0,boardid);
\r
833 upd.Bind(0,lowername);
\r
834 upd.Bind(1,boardid);
\r