version 0.2.0
[fms.git] / src / global.cpp
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
11 \r
12 #ifdef _WIN32\r
13         #include <winsock2.h>\r
14 #endif\r
15 \r
16 #ifdef XMEM\r
17         #include <xmem.h>\r
18 #endif\r
19 \r
20 bool wantshutdown=false;\r
21 \r
22 void SetupDB()\r
23 {\r
24 \r
25         DateTime date;\r
26         SQLite3DB::DB *db=SQLite3DB::DB::Instance();\r
27 \r
28         db->Open("fms.db3");\r
29         db->SetBusyTimeout(10000);              // set timeout to 10 seconds\r
30         db->Execute("VACUUM;");\r
31         \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
34 \r
35         db->Execute("CREATE TABLE IF NOT EXISTS tblDBVersion(\\r
36                                 Major                           INTEGER,\\r
37                                 Minor                           INTEGER\\r
38                                 );");\r
39 \r
40         SQLite3DB::Statement st=db->Prepare("SELECT Major,Minor FROM tblDBVersion;");\r
41         st.Step();\r
42         if(st.RowReturned())\r
43         {\r
44                 int major;\r
45                 int minor;\r
46                 st.ResultInt(0,major);\r
47                 st.ResultInt(1,minor);\r
48                 st.Finalize();\r
49                 if(major==1 && minor==0)\r
50                 {\r
51                         ConvertDB0100To0101();\r
52                         major=1;\r
53                         minor=1;\r
54                 }\r
55                 if(major==1 && (minor==1 || minor==2))\r
56                 {\r
57                         ConvertDB0101To0103();\r
58                         major=1;\r
59                         minor=3;\r
60                 }\r
61                 if(major==1 && minor==3)\r
62                 {\r
63                         ConvertDB0103To0104();\r
64                         major=1;\r
65                         minor=4;\r
66                 }\r
67         }\r
68         else\r
69         {\r
70                 db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,4);");\r
71         }\r
72 \r
73         db->Execute("UPDATE tblDBVersion SET Major=1, Minor=4;");\r
74 \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
79                                 );");\r
80 \r
81         db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\\r
82                                 LocalIdentityID                 INTEGER PRIMARY KEY,\\r
83                                 Name                                    TEXT,\\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
100                                 );");\r
101 \r
102         db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentityInserts(\\r
103                                 LocalIdentityID         INTEGER,\\r
104                                 Day                                     DATE,\\r
105                                 InsertIndex                     INTEGER\\r
106                                 );");\r
107 \r
108         db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListInserts(\\r
109                                 LocalIdentityID         INTEGER,\\r
110                                 Day                                     DATE,\\r
111                                 InsertIndex                     INTEGER\\r
112                                 );");\r
113 \r
114         db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListRequests(\\r
115                                 IdentityID                      INTEGER,\\r
116                                 Day                                     DATE,\\r
117                                 RequestIndex            INTEGER,\\r
118                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
119                                 );");\r
120 \r
121         db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleInserts(\\r
122                                 UUID                            TEXT UNIQUE,\\r
123                                 LocalIdentityID         INTEGER,\\r
124                                 Day                                     DATE,\\r
125                                 InsertIndex                     INTEGER,\\r
126                                 Type                            TEXT,\\r
127                                 MimeType                        TEXT,\\r
128                                 PuzzleData                      TEXT,\\r
129                                 PuzzleSolution          TEXT,\\r
130                                 FoundSolution           BOOL CHECK(FoundSolution IN('true','false')) DEFAULT 'false'\\r
131                                 );");\r
132 \r
133         db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\\r
134                                 IdentityID                      INTEGER PRIMARY KEY,\\r
135                                 PublicKey                       TEXT UNIQUE,\\r
136                                 Name                            TEXT,\\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
146                                 );");\r
147 \r
148         db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityRequests(\\r
149                                 IdentityID                      INTEGER,\\r
150                                 Day                                     DATE,\\r
151                                 RequestIndex            INTEGER,\\r
152                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
153                                 );");\r
154 \r
155         db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleRequests(\\r
156                                 IdentityID                      INTEGER,\\r
157                                 Day                                     DATE,\\r
158                                 RequestIndex            INTEGER,\\r
159                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false',\\r
160                                 UUID                            TEXT UNIQUE,\\r
161                                 Type                            TEXT,\\r
162                                 MimeType                        TEXT,\\r
163                                 PuzzleData                      TEXT\\r
164                                 );");\r
165 \r
166         db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityIntroductionInserts(\\r
167                                 LocalIdentityID         INTEGER,\\r
168                                 Day                                     DATE,\\r
169                                 UUID                            TEXT UNIQUE,\\r
170                                 Solution                        TEXT,\\r
171                                 Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
172                                 );");\r
173 \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
179                                 );");\r
180 \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
187                                 );");\r
188 \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
193 \r
194         db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\\r
195                                 MessageID                       INTEGER PRIMARY KEY,\\r
196                                 IdentityID                      INTEGER,\\r
197                                 FromName                        TEXT,\\r
198                                 MessageDate                     DATE,\\r
199                                 MessageTime                     TIME,\\r
200                                 Subject                         TEXT,\\r
201                                 MessageUUID                     TEXT UNIQUE,\\r
202                                 ReplyBoardID            INTEGER,\\r
203                                 Body                            TEXT,\\r
204                                 MessageIndex            INTEGER\\r
205                                 );");\r
206 \r
207         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageReplyTo(\\r
208                                 MessageID                       INTEGER,\\r
209                                 ReplyToMessageUUID      TEXT,\\r
210                                 ReplyOrder                      INTEGER\\r
211                                 );");\r
212 \r
213         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageBoard(\\r
214                                 MessageID                       INTEGER,\\r
215                                 BoardID                         INTEGER\\r
216                                 );");\r
217 \r
218         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListRequests(\\r
219                                 IdentityID                      INTEGER,\\r
220                                 Day                                     DATE,\\r
221                                 RequestIndex            INTEGER,\\r
222                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
223                                 );");\r
224 \r
225         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageRequests(\\r
226                                 IdentityID                      INTEGER,\\r
227                                 Day                                     DATE,\\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
231                                 );");\r
232 \r
233         db->Execute("CREATE UNIQUE INDEX IF NOT EXISTS idxMessageRequest ON tblMessageRequests(IdentityID,Day,RequestIndex);");\r
234 \r
235         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageInserts(\\r
236                                 LocalIdentityID         INTEGER,\\r
237                                 Day                                     DATE,\\r
238                                 InsertIndex                     INTEGER,\\r
239                                 MessageUUID                     TEXT UNIQUE,\\r
240                                 MessageXML                      TEXT,\\r
241                                 Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
242                                 );");\r
243 \r
244         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListInserts(\\r
245                                 LocalIdentityID         INTEGER,\\r
246                                 Day                                     DATE,\\r
247                                 InsertIndex                     INTEGER,\\r
248                                 Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
249                                 );");\r
250 \r
251         db->Execute("CREATE TABLE IF NOT EXISTS tblAdministrationBoard(\\r
252                                 BoardID                                         INTEGER UNIQUE,\\r
253                                 ModifyLocalMessageTrust         INTEGER,\\r
254                                 ModifyLocalTrustListTrust       INTEGER\\r
255                                 );");\r
256 \r
257         db->Execute("CREATE TABLE IF NOT EXISTS tblBoardListInserts(\\r
258                                 LocalIdentityID         INTEGER,\\r
259                                 Day                                     DATE,\\r
260                                 InsertIndex                     INTEGER,\\r
261                                 Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
262                                 );");\r
263 \r
264         db->Execute("CREATE TABLE IF NOT EXISTS tblBoardListRequests(\\r
265                                 IdentityID                      INTEGER,\\r
266                                 Day                                     DATE,\\r
267                                 RequestIndex            INTEGER,\\r
268                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
269                                 );");   \r
270 \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
274                                 Date                            DATETIME\\r
275                                 );");\r
276 \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
283 \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
296 \r
297         /*\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
300         */\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
306 /*\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
309                                 FOR EACH ROW \\r
310                                 BEGIN \\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
312                                 END;");\r
313 \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
316                                 FOR EACH ROW \\r
317                                 BEGIN \\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
319                                 END;");\r
320 \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
323                                 FOR EACH ROW \\r
324                                 BEGIN \\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
327                                 END;");\r
328 \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
331                                 FOR EACH ROW \\r
332                                 BEGIN \\r
333                                         UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\\r
334                                 END;");\r
335 */\r
336 \r
337         db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \\r
338                                 FOR EACH ROW \\r
339                                 BEGIN \\r
340                                         DELETE FROM tblMessageBoard WHERE tblMessageBoard.MessageID=old.MessageID;\\r
341                                         DELETE FROM tblMessageReplyTo WHERE tblMessageReplyTo.MessageID=old.MessageID;\\r
342                                 END;");\r
343 \r
344         db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteIdentity AFTER DELETE ON tblIdentity \\r
345                                 FOR EACH ROW \\r
346                                 BEGIN \\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
353                                 END;");\r
354 \r
355         db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteLocalIdentity AFTER DELETE ON tblLocalIdentity \\r
356                                 FOR EACH ROW \\r
357                                 BEGIN \\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
364                                 END;");\r
365 \r
366         db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteBoard AFTER DELETE ON tblBoard \\r
367                                 FOR EACH ROW \\r
368                                 BEGIN \\r
369                                         DELETE FROM tblMessageBoard WHERE BoardID=old.BoardID;\\r
370                                 END;");\r
371 \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
374 \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
380 \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
388 \r
389         // TODO remove sometime after 0.1.17\r
390         FixCapitalBoardNames();\r
391 \r
392 }\r
393 \r
394 void ConvertDB0100To0101()\r
395 {\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
402                                 Name                                    TEXT,\\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
418                                 );");\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
422 }\r
423 \r
424 void ConvertDB0101To0103()\r
425 {\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
433                                 Name                            TEXT,\\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
443                                 );");\r
444         db->Execute("INSERT INTO tblIdentity SELECT * FROM tblIdentityTemp;");\r
445         db->Execute("DROP TABLE IF EXISTS tblIdentityTemp;");\r
446 \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
449 \r
450         db->Execute("UPDATE tblDBVersion SET Major=1, Minor=3;");\r
451 }\r
452 \r
453 void ConvertDB0103To0104()\r
454 {\r
455         // add MessageIndex to tblMessage\r
456         DateTime date;\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
464 }\r
465 \r
466 void SetupDefaultOptions()\r
467 {\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
469 \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
473 \r
474         // LogLevel\r
475         tempstr.str("");\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
480         st.Step();\r
481         st.Reset();\r
482 \r
483         // NNTPListenPort\r
484         st.Bind(0,"NNTPListenPort");\r
485         st.Bind(1,"1119");\r
486         st.Bind(2,"The port that the NNTP service will listen for incoming connections.");\r
487         st.Step();\r
488         st.Reset();\r
489 \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
494         st.Step();\r
495         st.Reset();\r
496 \r
497         st.Bind(0,"NNTPAllowPost");\r
498         st.Bind(1,"true");\r
499         st.Bind(2,"Allow posting messages from NNTP.  Setting to false will make the newsgroups read only.");\r
500         st.Step();\r
501         st.Reset();\r
502 \r
503         // StartNNTP\r
504         st.Bind(0,"StartNNTP");\r
505         st.Bind(1,"true");\r
506         st.Bind(2,"Start NNTP server.");\r
507         st.Step();\r
508         st.Reset();\r
509 \r
510         st.Bind(0,"StartHTTP");\r
511         st.Bind(1,"true");\r
512         st.Bind(2,"Start HTTP server.");\r
513         st.Step();\r
514         st.Reset();\r
515 \r
516         st.Bind(0,"HTTPListenPort");\r
517         st.Bind(1,"8080");\r
518         st.Bind(2,"Port HTTP server will listen on.");\r
519         st.Step();\r
520         st.Reset();\r
521 \r
522         // StartFreenetUpdater\r
523         st.Bind(0,"StartFreenetUpdater");\r
524         st.Bind(1,"true");\r
525         st.Bind(2,"Start Freenet Updater thread.");\r
526         st.Step();\r
527         st.Reset();\r
528 \r
529         // FCPHost\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
533         st.Step();\r
534         st.Reset();\r
535 \r
536         // FCPPort\r
537         st.Bind(0,"FCPPort");\r
538         st.Bind(1,"9481");\r
539         st.Bind(2,"The port that Freenet is listening for FCP connections on.");\r
540         st.Step();\r
541         st.Reset();\r
542 \r
543         st.Bind(0,"MessageBase");\r
544         st.Bind(1,"fms");\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
546         st.Step();\r
547         st.Reset();\r
548 \r
549         st.Bind(0,"MaxIdentityRequests");\r
550         st.Bind(1,"5");\r
551         st.Bind(2,"Maximum number of concurrent requests for new Identity xml files");\r
552         st.Step();\r
553         st.Reset();\r
554 \r
555         st.Bind(0,"MaxIdentityIntroductionRequests");\r
556         st.Bind(1,"5");\r
557         st.Bind(2,"Maximum number of concurrent identities requesting IdentityIntroduction xml files.  Each identity may have multiple requests pending.");\r
558         st.Step();\r
559         st.Reset();\r
560 \r
561         st.Bind(0,"MaxIntroductionPuzzleRequests");\r
562         st.Bind(1,"5");\r
563         st.Bind(2,"Maximum number of concurrent requests for new IntroductionPuzzle xml files");\r
564         st.Step();\r
565         st.Reset();\r
566 \r
567         st.Bind(0,"MaxTrustListRequests");\r
568         st.Bind(1,"5");\r
569         st.Bind(2,"Maximum number of concurrent requests for new Trust Lists");\r
570         st.Step();\r
571         st.Reset();\r
572 \r
573         st.Bind(0,"MaxMessageListRequests");\r
574         st.Bind(1,"5");\r
575         st.Bind(2,"Maximum number of concurrent requests for new Message Lists");\r
576         st.Step();\r
577         st.Reset();\r
578 \r
579         st.Bind(0,"MaxMessageRequests");\r
580         st.Bind(1,"20");\r
581         st.Bind(2,"Maximum number of concurrent requests for new Messages");\r
582         st.Step();\r
583         st.Reset();\r
584 \r
585         st.Bind(0,"MinLocalMessageTrust");\r
586         st.Bind(1,"50");\r
587         st.Bind(2,"Specifies a local message trust level that a peer must have before its messages will be downloaded.");\r
588         st.Step();\r
589         st.Reset();\r
590 \r
591         st.Bind(0,"MinPeerMessageTrust");\r
592         st.Bind(1,"30");\r
593         st.Bind(2,"Specifies a peer message trust level that a peer must have before its messages will be downloaded.");\r
594         st.Step();\r
595         st.Reset();\r
596 \r
597         st.Bind(0,"MinLocalTrustListTrust");\r
598         st.Bind(1,"51");\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
600         st.Step();\r
601         st.Reset();\r
602 \r
603         st.Bind(0,"MinPeerTrustListTrust");\r
604         st.Bind(1,"30");\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
606         st.Step();\r
607         st.Reset();\r
608 \r
609         st.Bind(0,"MessageDownloadMaxDaysBackward");\r
610         st.Bind(1,"5");\r
611         st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");\r
612         st.Step();\r
613         st.Reset();\r
614 \r
615         st.Bind(0,"MessageListDaysBackward");\r
616         st.Bind(1,"5");\r
617         st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");\r
618         st.Step();\r
619         st.Reset();\r
620 \r
621         st.Bind(0,"MaxPeerMessagesPerDay");\r
622         st.Bind(1,"200");\r
623         st.Bind(2,"The maximum number of messages you will download from each peer on a given day.");\r
624         st.Step();\r
625         st.Reset();\r
626 \r
627         st.Bind(0,"MaxBoardListRequests");\r
628         st.Bind(1,"5");\r
629         st.Bind(2,"The maximum number of concurrent requests for new Board Lists.  Set to 0 to disable.");\r
630         st.Step();\r
631         st.Reset();\r
632 \r
633         st.Bind(0,"MaxBoardsPerMessage");\r
634         st.Bind(1,"8");\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
636         st.Step();\r
637         st.Reset();\r
638 \r
639         st.Bind(0,"ChangeMessageTrustOnReply");\r
640         st.Bind(1,"0");\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
642         st.Step();\r
643         st.Reset();\r
644 \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
648         st.Step();\r
649         st.Reset();\r
650 \r
651         st.Bind(0,"DeleteMessagesOlderThan");\r
652         st.Bind(1,"180");\r
653         st.Bind(2,"Automatically delete messages older than this many days.");\r
654         st.Step();\r
655         st.Reset();\r
656 \r
657 }\r
658 \r
659 void SetupLogFile()\r
660 {\r
661         DateTime date;\r
662         std::string configval;\r
663         int loglevel;\r
664 \r
665         date.SetToGMTime();\r
666 \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
672 \r
673         if(Option::Instance()->Get("LogLevel",configval)==false)\r
674         {\r
675                 configval="4";\r
676                 Option::Instance()->Set("LogLevel",configval);\r
677         }\r
678         if(StringFunctions::Convert(configval,loglevel)==false)\r
679         {\r
680                 loglevel=LogFile::LOGLEVEL_DEBUG;\r
681                 Option::Instance()->Set("LogLevel",loglevel);\r
682         }\r
683         LogFile::Instance()->SetLogLevel((LogFile::LogLevel)loglevel);\r
684 }\r
685 \r
686 void SetupNetwork()\r
687 {\r
688 #ifdef _WIN32\r
689         WSAData wsadata;\r
690         WSAStartup(MAKEWORD(2,2),&wsadata);\r
691 #endif\r
692 }\r
693 \r
694 void Shutdown()\r
695 {\r
696         ThreadController::Instance()->ShutdownThreads();\r
697 \r
698         ShutdownNetwork();\r
699 \r
700         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"FMS shutdown");\r
701         LogFile::Instance()->WriteNewLine();\r
702 }\r
703 \r
704 void ShutdownNetwork()\r
705 {\r
706 #ifdef _WIN32\r
707         WSACleanup();\r
708 #endif\r
709 }\r
710 \r
711 void SigHandler(int signum)\r
712 {\r
713         Shutdown();\r
714         exit(0);\r
715 }\r
716 \r
717 /*\r
718 void ShutdownThreads(std::vector<PThread::Thread *> &threads)\r
719 {\r
720         std::vector<PThread::Thread *>::iterator i;\r
721         for(i=threads.begin(); i!=threads.end(); i++)\r
722         {\r
723                 (*i)->Cancel();\r
724         }\r
725 \r
726         for(i=threads.begin(); i!=threads.end(); i++)\r
727         {\r
728                 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");\r
729                 //(*i)->wait();\r
730                 (*i)->Join();\r
731                 delete (*i);\r
732         }\r
733 \r
734         threads.clear();\r
735 \r
736 }\r
737 \r
738 void StartThreads(std::vector<PThread::Thread *> &threads)\r
739 {\r
740         std::string startfreenet;\r
741         std::string startnntp;\r
742         std::string starthttp;\r
743 \r
744         if(Option::Instance()->Get("StartFreenetUpdater",startfreenet)==false)\r
745         {\r
746                 startfreenet="true";\r
747                 Option::Instance()->Set("StartFreenetUpdater","true");\r
748         }\r
749 \r
750         if(Option::Instance()->Get("StartNNTP",startnntp)==false)\r
751         {\r
752                 startnntp="true";\r
753                 Option::Instance()->Set("StartNNTP","true");\r
754         }\r
755 \r
756         if(Option::Instance()->Get("StartHTTP",starthttp)==false)\r
757         {\r
758                 starthttp="true";\r
759                 Option::Instance()->Set("StartHTTP","true");\r
760         }\r
761 \r
762         if(startfreenet=="true")\r
763         {\r
764                 PThread::Thread *t=new PThread::Thread(new FreenetMasterThread());\r
765                 threads.push_back(t);\r
766         }\r
767 \r
768         if(startnntp=="true")\r
769         {\r
770                 PThread::Thread *t=new PThread::Thread(new NNTPListener());\r
771                 threads.push_back(t);\r
772         }\r
773 \r
774         if(starthttp=="true")\r
775         {\r
776                 PThread::Thread *t=new PThread::Thread(new HTTPThread());\r
777                 threads.push_back(t);\r
778         }\r
779 \r
780 }\r
781 */\r
782 \r
783 void FixCapitalBoardNames()\r
784 {\r
785         SQLite3DB::DB *db=SQLite3DB::DB::Instance();\r
786 \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
793 \r
794         st.Step();\r
795         while(st.RowReturned())\r
796         {\r
797                 int boardid=0;\r
798                 int newboardid=0;\r
799                 std::string name="";\r
800                 std::string lowername="";\r
801 \r
802                 st.ResultInt(0,boardid);\r
803                 st.ResultText(1,name);\r
804 \r
805                 lowername=name;\r
806                 StringFunctions::LowerCase(lowername,lowername);\r
807        \r
808                 if(name!=lowername)\r
809                 {\r
810                         st2.Bind(0,lowername);\r
811                         st2.Step();\r
812 \r
813                         if(st2.RowReturned())\r
814                         {\r
815                                 st2.ResultInt(0,newboardid);\r
816 \r
817                                 upd2.Bind(0,newboardid);\r
818                                 upd2.Bind(1,boardid);\r
819                                 upd2.Step();\r
820                                 upd2.Reset();\r
821 \r
822                                 upd3.Bind(0,newboardid);\r
823                                 upd3.Bind(1,boardid);\r
824                                 upd3.Step();\r
825                                 upd3.Reset();\r
826 \r
827                                 del.Bind(0,boardid);\r
828                                 del.Step();\r
829                                 del.Reset();\r
830                         }\r
831                         else\r
832                         {\r
833                                 upd.Bind(0,lowername);\r
834                                 upd.Bind(1,boardid);\r
835                                 upd.Step();\r
836                                 upd.Reset();\r
837                         }\r
838 \r
839                         st2.Reset();\r
840                 }\r
841        \r
842                 st.Step();\r
843         }\r
844 \r
845 }\r