version 0.1.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 \r
10 #ifdef _WIN32\r
11         #include <winsock2.h>\r
12 #endif\r
13 \r
14 #ifdef XMEM\r
15         #include <xmem.h>\r
16 #endif\r
17 \r
18 void SetupDB()\r
19 {\r
20 \r
21         SQLite3DB::DB *db=SQLite3DB::DB::instance();\r
22 \r
23         db->Open("fms.db3");\r
24         db->SetBusyTimeout(10000);              // set timeout to 10 seconds\r
25         db->Execute("VACUUM;");\r
26 \r
27         db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\\r
28                                 Option                          TEXT UNIQUE,\\r
29                                 OptionValue                     TEXT NOT NULL,\\r
30                                 OptionDescription       TEXT\\r
31                                 );");\r
32 \r
33         db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\\r
34                                 LocalIdentityID                 INTEGER PRIMARY KEY,\\r
35                                 Name                                    TEXT,\\r
36                                 PublicKey                               TEXT,\\r
37                                 PrivateKey                              TEXT,\\r
38                                 SingleUse                               BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
39                                 PublishTrustList                BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\\r
40                                 PublishBoardList                BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\\r
41                                 InsertingIdentity               BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\\r
42                                 LastInsertedIdentity    DATETIME,\\r
43                                 InsertingPuzzle                 BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\\r
44                                 LastInsertedPuzzle              DATETIME,\\r
45                                 InsertingTrustList              BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\\r
46                                 LastInsertedTrustList   DATETIME,\\r
47                                 InsertingBoardList              BOOL CHECK(InsertingBoardList IN('true','false')) DEFAULT 'false',\\r
48                                 LastInsertedBoardList   DATETIME,\\r
49                                 InsertingMessageList    BOOL CHECK(InsertingMessageList IN('true','false')) DEFAULT 'false',\\r
50                                 LastInsertedMessageList DATETIME\\r
51                                 );");\r
52 \r
53         db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentityInserts(\\r
54                                 LocalIdentityID         INTEGER,\\r
55                                 Day                                     DATE,\\r
56                                 InsertIndex                     INTEGER\\r
57                                 );");\r
58 \r
59         db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListInserts(\\r
60                                 LocalIdentityID         INTEGER,\\r
61                                 Day                                     DATE,\\r
62                                 InsertIndex                     INTEGER\\r
63                                 );");\r
64 \r
65         db->Execute("CREATE TABLE IF NOT EXISTS tblTrustListRequests(\\r
66                                 IdentityID                      INTEGER,\\r
67                                 Day                                     DATE,\\r
68                                 RequestIndex            INTEGER,\\r
69                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
70                                 );");\r
71 \r
72         db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleInserts(\\r
73                                 UUID                            TEXT UNIQUE,\\r
74                                 LocalIdentityID         INTEGER,\\r
75                                 Day                                     DATE,\\r
76                                 InsertIndex                     INTEGER,\\r
77                                 Type                            TEXT,\\r
78                                 MimeType                        TEXT,\\r
79                                 PuzzleData                      TEXT,\\r
80                                 PuzzleSolution          TEXT,\\r
81                                 FoundSolution           BOOL CHECK(FoundSolution IN('true','false')) DEFAULT 'false'\\r
82                                 );");\r
83 \r
84         db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\\r
85                                 IdentityID                      INTEGER PRIMARY KEY,\\r
86                                 PublicKey                       TEXT,\\r
87                                 Name                            TEXT,\\r
88                                 SingleUse                       BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
89                                 PublishTrustList        BOOL CHECK(PublishTrustList IN('true','false')) DEFAULT 'false',\\r
90                                 PublishBoardList        BOOL CHECK(PublishBoardList IN('true','false')) DEFAULT 'false',\\r
91                                 DateAdded                       DATETIME,\\r
92                                 LastSeen                        DATETIME,\\r
93                                 LocalMessageTrust       INTEGER CHECK(LocalMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\\r
94                                 PeerMessageTrust        INTEGER CHECK(PeerMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\\r
95                                 LocalTrustListTrust     INTEGER CHECK(LocalTrustListTrust BETWEEN 0 AND 100) DEFAULT 50,\\r
96                                 PeerTrustListTrust      INTEGER CHECK(PeerTrustListTrust BETWEEN 0 AND 100) DEFAULT 50\\r
97                                 );");\r
98 \r
99         db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityRequests(\\r
100                                 IdentityID                      INTEGER,\\r
101                                 Day                                     DATE,\\r
102                                 RequestIndex            INTEGER,\\r
103                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
104                                 );");\r
105 \r
106         db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleRequests(\\r
107                                 IdentityID                      INTEGER,\\r
108                                 Day                                     DATE,\\r
109                                 RequestIndex            INTEGER,\\r
110                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false',\\r
111                                 UUID                            TEXT UNIQUE,\\r
112                                 Type                            TEXT,\\r
113                                 MimeType                        TEXT,\\r
114                                 PuzzleData                      TEXT\\r
115                                 );");\r
116 \r
117         db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityIntroductionInserts(\\r
118                                 LocalIdentityID         INTEGER,\\r
119                                 Day                                     DATE,\\r
120                                 UUID                            TEXT UNIQUE,\\r
121                                 Solution                        TEXT,\\r
122                                 Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
123                                 );");\r
124 \r
125         db->Execute("CREATE TABLE IF NOT EXISTS tblPeerTrust(\\r
126                                 IdentityID                      INTEGER,\\r
127                                 TargetIdentityID        INTEGER,\\r
128                                 MessageTrust            INTEGER CHECK(MessageTrust BETWEEN 0 AND 100),\\r
129                                 TrustListTrust          INTEGER CHECK(TrustListTrust BETWEEN 0 AND 100)\\r
130                                 );");\r
131 \r
132         db->Execute("CREATE TABLE IF NOT EXISTS tblBoard(\\r
133                                 BoardID                         INTEGER PRIMARY KEY,\\r
134                                 BoardName                       TEXT UNIQUE,\\r
135                                 BoardDescription        TEXT,\\r
136                                 DateAdded                       DATETIME\\r
137                                 );");\r
138 \r
139         db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('fms','Freenet Message System','2007-12-01');");\r
140         db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('freenet','Discussion about Freenet','2007-12-01');");\r
141         db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('public','Public discussion','2007-12-01');");\r
142         db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded) VALUES('test','Test board','2007-12-01');");\r
143 \r
144         db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\\r
145                                 MessageID                       INTEGER PRIMARY KEY,\\r
146                                 IdentityID                      INTEGER,\\r
147                                 FromName                        TEXT,\\r
148                                 MessageDate                     DATE,\\r
149                                 MessageTime                     TIME,\\r
150                                 Subject                         TEXT,\\r
151                                 MessageUUID                     TEXT UNIQUE,\\r
152                                 ReplyBoardID            INTEGER,\\r
153                                 Body                            TEXT\\r
154                                 );");\r
155 \r
156         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageReplyTo(\\r
157                                 MessageID                       INTEGER,\\r
158                                 ReplyToMessageUUID      INTEGER,\\r
159                                 ReplyOrder                      INTEGER\\r
160                                 );");\r
161 \r
162         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageBoard(\\r
163                                 MessageID                       INTEGER,\\r
164                                 BoardID                         INTEGER\\r
165                                 );");\r
166 \r
167         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListRequests(\\r
168                                 IdentityID                      INTEGER,\\r
169                                 Day                                     DATE,\\r
170                                 RequestIndex            INTEGER,\\r
171                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
172                                 );");\r
173 \r
174         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageRequests(\\r
175                                 IdentityID                      INTEGER,\\r
176                                 Day                                     DATE,\\r
177                                 RequestIndex            INTEGER,\\r
178                                 FromMessageList         BOOL CHECK(FromMessageList IN('true','false')) DEFAULT 'false',\\r
179                                 Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
180                                 );");\r
181 \r
182         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageInserts(\\r
183                                 LocalIdentityID         INTEGER,\\r
184                                 Day                                     DATE,\\r
185                                 InsertIndex                     INTEGER,\\r
186                                 MessageUUID                     TEXT UNIQUE,\\r
187                                 MessageXML                      TEXT,\\r
188                                 Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
189                                 );");\r
190 \r
191         db->Execute("CREATE TABLE IF NOT EXISTS tblMessageListInserts(\\r
192                                 LocalIdentityID         INTEGER,\\r
193                                 Day                                     DATE,\\r
194                                 InsertIndex                     INTEGER,\\r
195                                 Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
196                                 );");\r
197 \r
198         // low / high / message count for each board\r
199         db->Execute("CREATE VIEW IF NOT EXISTS vwBoardStats AS \\r
200                                 SELECT tblBoard.BoardID AS 'BoardID', IFNULL(MIN(MessageID),0) AS 'LowMessageID', IFNULL(MAX(MessageID),0) AS 'HighMessageID', COUNT(MessageID) AS 'MessageCount' \\r
201                                 FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID \\r
202                                 WHERE MessageID>=0 \\r
203                                 GROUP BY tblBoard.BoardID;");\r
204 \r
205         // calculates peer trust\r
206         db->Execute("CREATE VIEW IF NOT EXISTS vwCalculatedPeerTrust AS \\r
207                                 SELECT TargetIdentityID, \\r
208                                 ROUND(SUM(MessageTrust*(LocalMessageTrust/100.0))/SUM(LocalMessageTrust/100.0),0) AS 'PeerMessageTrust', \\r
209                                 ROUND(SUM(TrustListTrust*(LocalTrustListTrust/100.0))/SUM(LocalTrustListTrust/100.0),0) AS 'PeerTrustListTrust' \\r
210                                 FROM tblPeerTrust INNER JOIN tblIdentity ON tblPeerTrust.IdentityID=tblIdentity.IdentityID \\r
211                                 WHERE LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') \\r
212                                 GROUP BY TargetIdentityID;");\r
213 \r
214         // update PeerTrustLevel when deleting a record from tblPeerTrust\r
215         db->Execute("CREATE TRIGGER trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \\r
216                                 FOR EACH ROW \\r
217                                 BEGIN \\r
218                                         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
219                                 END;");\r
220 \r
221         // update PeerTrustLevel when inserting a record into tblPeerTrust\r
222         db->Execute("CREATE TRIGGER trgInsertOntblPeerTrust AFTER INSERT ON tblPeerTrust \\r
223                                 FOR EACH ROW \\r
224                                 BEGIN \\r
225                                         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
226                                 END;");\r
227 \r
228         // update PeerTrustLevel when updating a record in tblPeerTrust\r
229         db->Execute("CREATE TRIGGER trgUpdateOntblPeerTrust AFTER UPDATE ON tblPeerTrust \\r
230                                 FOR EACH ROW \\r
231                                 BEGIN \\r
232                                         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
233                                         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
234                                 END;");\r
235 \r
236         // 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
237         db->Execute("CREATE TRIGGER trgUpdateLocalTrustLevels AFTER UPDATE OF LocalMessageTrust,LocalTrustListTrust ON tblIdentity \\r
238                                 FOR EACH ROW \\r
239                                 BEGIN \\r
240                                         UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\\r
241                                 END;");\r
242 \r
243         // delete introduction puzzles that were half-way inserted\r
244         db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");\r
245 \r
246 }\r
247 \r
248 void SetupDefaultOptions()\r
249 {\r
250         // 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
251 \r
252         std::ostringstream tempstr;     // must set tempstr to "" between db inserts\r
253         SQLite3DB::DB *db=SQLite3DB::DB::instance();\r
254         SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");\r
255 \r
256         // LogLevel\r
257         tempstr.str("");\r
258         tempstr << LogFile::LOGLEVEL_DEBUG;\r
259         st.Bind(0,"LogLevel");\r
260         st.Bind(1,tempstr.str());\r
261         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
262         st.Step();\r
263         st.Reset();\r
264 \r
265         // NNTPListenPort\r
266         st.Bind(0,"NNTPListenPort");\r
267         st.Bind(1,"1119");\r
268         st.Bind(2,"The port that the NNTP service will listen for incoming connections.");\r
269         st.Step();\r
270         st.Reset();\r
271 \r
272         // NNTPBindAddresses\r
273         st.Bind(0,"NNTPBindAddresses");\r
274         st.Bind(1,"localhost");\r
275         st.Bind(2,"A comma separated list of valid IPv4 or IPv6 addresses/hostnames that the NNTP service will try to bind to.");\r
276         st.Step();\r
277         st.Reset();\r
278 \r
279         st.Bind(0,"NNTPAllowPost");\r
280         st.Bind(1,"true");\r
281         st.Bind(2,"Allow posting messages from NNTP.  Setting to false will make the newsgroups read only.");\r
282         st.Step();\r
283         st.Reset();\r
284 \r
285         // StartNNTP\r
286         st.Bind(0,"StartNNTP");\r
287         st.Bind(1,"true");\r
288         st.Bind(2,"Start NNTP service.");\r
289         st.Step();\r
290         st.Reset();\r
291 \r
292         // StartFreenetUpdater\r
293         st.Bind(0,"StartFreenetUpdater");\r
294         st.Bind(1,"true");\r
295         st.Bind(2,"Start Freenet Updater thread.");\r
296         st.Step();\r
297         st.Reset();\r
298 \r
299         // FCPHost\r
300         st.Bind(0,"FCPHost");\r
301         st.Bind(1,"localhost");\r
302         st.Bind(2,"Host name or address of Freenet node.");\r
303         st.Step();\r
304         st.Reset();\r
305 \r
306         // FCPPort\r
307         st.Bind(0,"FCPPort");\r
308         st.Bind(1,"9481");\r
309         st.Bind(2,"The port that Freenet is listening for FCP connections on.");\r
310         st.Step();\r
311         st.Reset();\r
312 \r
313         st.Bind(0,"MessageBase");\r
314         st.Bind(1,"fms");\r
315         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
316         st.Step();\r
317         st.Reset();\r
318 \r
319         st.Bind(0,"MaxIdentityRequests");\r
320         st.Bind(1,"5");\r
321         st.Bind(2,"Maximum number of concurrent requests for new Identity xml files");\r
322         st.Step();\r
323         st.Reset();\r
324 \r
325         st.Bind(0,"MaxIdentityIntroductionRequests");\r
326         st.Bind(1,"5");\r
327         st.Bind(2,"Maximum number of concurrent identities requesting IdentityIntroduction xml files.  Each identity may have multiple requests pending.");\r
328         st.Step();\r
329         st.Reset();\r
330 \r
331         st.Bind(0,"MaxIntroductionPuzzleRequests");\r
332         st.Bind(1,"5");\r
333         st.Bind(2,"Maximum number of concurrent requests for new IntroductionPuzzle xml files");\r
334         st.Step();\r
335         st.Reset();\r
336 \r
337         st.Bind(0,"MaxTrustListRequests");\r
338         st.Bind(1,"5");\r
339         st.Bind(2,"Maximum number of concurrent requests for new Trust Lists");\r
340         st.Step();\r
341         st.Reset();\r
342 \r
343         st.Bind(0,"MaxMessageListRequests");\r
344         st.Bind(1,"5");\r
345         st.Bind(2,"Maximum number of concurrent requests for new Message Lists");\r
346         st.Step();\r
347         st.Reset();\r
348 \r
349         st.Bind(0,"MaxMessageRequests");\r
350         st.Bind(1,"20");\r
351         st.Bind(2,"Maximum number of concurrent requests for new Messages");\r
352         st.Step();\r
353         st.Reset();\r
354 \r
355         st.Bind(0,"MinLocalMessageTrust");\r
356         st.Bind(1,"50");\r
357         st.Bind(2,"Specifies a local message trust level that a peer must have before its messages will be downloaded.");\r
358         st.Step();\r
359         st.Reset();\r
360 \r
361         st.Bind(0,"MinLocalTrustListTrust");\r
362         st.Bind(1,"50");\r
363         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
364         st.Step();\r
365         st.Reset();\r
366 \r
367         st.Bind(0,"MessageDownloadMaxDaysBackward");\r
368         st.Bind(1,"3");\r
369         st.Bind(2,"The maximum number of days backward that messages will be downloaded from each identity");\r
370         st.Step();\r
371         st.Reset();\r
372 \r
373         st.Bind(0,"MessageListDaysBackward");\r
374         st.Bind(1,"3");\r
375         st.Bind(2,"The number of days backward that messages you have inserted will appear in your MessageLists");\r
376         st.Step();\r
377         st.Reset();\r
378 \r
379 }\r
380 \r
381 void SetupLogFile()\r
382 {\r
383         DateTime date;\r
384         std::string configval;\r
385         int loglevel;\r
386 \r
387         date.SetToGMTime();\r
388 \r
389         LogFile::instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");\r
390         LogFile::instance()->OpenFile();\r
391         LogFile::instance()->SetWriteNewLine(true);\r
392         LogFile::instance()->SetWriteDate(true);\r
393         LogFile::instance()->SetWriteLogLevel(true);\r
394 \r
395         if(Option::instance()->Get("LogLevel",configval)==false)\r
396         {\r
397                 configval="4";\r
398                 Option::instance()->Set("LogLevel",configval);\r
399         }\r
400         if(StringFunctions::Convert(configval,loglevel)==false)\r
401         {\r
402                 loglevel=LogFile::LOGLEVEL_DEBUG;\r
403                 Option::instance()->Set("LogLevel",loglevel);\r
404         }\r
405         LogFile::instance()->SetLogLevel((LogFile::LogLevel)loglevel);\r
406 }\r
407 \r
408 void SetupNetwork()\r
409 {\r
410 #ifdef _WIN32\r
411         WSAData wsadata;\r
412         WSAStartup(MAKEWORD(2,2),&wsadata);\r
413 #endif\r
414 }\r
415 \r
416 void ShutdownNetwork()\r
417 {\r
418 #ifdef _WIN32\r
419         WSACleanup();\r
420 #endif\r
421 }\r
422 \r
423 void ShutdownThreads(std::vector<ZThread::Thread *> &threads)\r
424 {\r
425         std::vector<ZThread::Thread *>::iterator i;\r
426         for(i=threads.begin(); i!=threads.end(); i++)\r
427         {\r
428                 if((*i)->wait(1)==false)\r
429                 {\r
430                         try\r
431                         {\r
432                                 (*i)->interrupt();\r
433                         }\r
434                         catch(...)\r
435                         {\r
436                         }\r
437                 }\r
438         }\r
439 \r
440         for(i=threads.begin(); i!=threads.end(); i++)\r
441         {\r
442                 (*i)->wait();\r
443                 delete (*i);\r
444         }\r
445 \r
446         threads.clear();\r
447 \r
448 }\r
449 \r
450 void StartThreads(std::vector<ZThread::Thread *> &threads)\r
451 {\r
452         std::string startfreenet;\r
453         std::string startnntp;\r
454 \r
455         if(Option::instance()->Get("StartFreenetUpdater",startfreenet)==false)\r
456         {\r
457                 startfreenet="true";\r
458                 Option::instance()->Set("StartFreenetUpdater","true");\r
459         }\r
460 \r
461         if(Option::instance()->Get("StartNNTP",startnntp)==false)\r
462         {\r
463                 startnntp="true";\r
464                 Option::instance()->Set("StartNNTP","true");\r
465         }\r
466 \r
467         if(startfreenet=="true")\r
468         {\r
469                 ZThread::Thread *t=new ZThread::Thread(new FreenetMasterThread());\r
470                 threads.push_back(t);\r
471         }\r
472 \r
473         if(startnntp=="true")\r
474         {\r
475                 ZThread::Thread *t=new ZThread::Thread(new NNTPListener());\r
476                 threads.push_back(t);\r
477         }\r
478 \r
479 }\r