\r
ADD_DEFINITIONS(-DTIXML_USE_STL)\r
\r
+IF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)\r
+ ADD_DEFINITIONS(-fpermissive)\r
+ENDIF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)\r
+\r
ADD_EXECUTABLE(fms ${FMS_SRC})\r
\r
INCLUDE_DIRECTORIES(libs/sqlite3 libs/tinyxml)\r
}\r
}\r
\r
- $st=$db->prepare("SELECT IdentityID,Name,LocalMessageTrust,PeerMessageTrust,LocalTrustListTrust,PeerTrustListTrust FROM tblIdentity ORDER BY Name;");\r
+ $st=$db->prepare("SELECT IdentityID,Name,LocalMessageTrust,PeerMessageTrust,LocalTrustListTrust,PeerTrustListTrust,PublicKey FROM tblIdentity ORDER BY Name;");\r
$st->execute();\r
?>\r
<h2>Identity Trust</h2>\r
+ Message Trust is how much you trust the identity to post good messages. Trust List Trust is how much weight you want the trust list of that identity to have when calculating the total. The local trust levels are set by you, and the peer trust levels are calculated by a weighted average using other identities trust lists.\r
<form name="frmtrust" method="post">\r
<input type="hidden" name="formaction" value="updatetrust">\r
<table>\r
{\r
?>\r
<tr>\r
- <td>\r
- <?php print($record[1]) ?>\r
- <input type="hidden" name="identityid[]" value="<?php print($record[0]) ?>">\r
+ <td title="<?php print($record[6]); ?>">\r
+ <?php print($record[1]); ?>\r
+ <input type="hidden" name="identityid[]" value="<?php print($record[0]); ?>">\r
</td>\r
<td>\r
- <input type="hidden" name="oldlocalmessagetrust[]" value="<?php print($record[2]) ?>">\r
- <input type="text" name="newlocalmessagetrust[]" size="2" maxlength="3" value="<?php print($record[2]) ?>">\r
+ <input type="hidden" name="oldlocalmessagetrust[]" value="<?php print($record[2]); ?>">\r
+ <input type="text" name="newlocalmessagetrust[]" size="2" maxlength="3" value="<?php print($record[2]); ?>">\r
</td>\r
- <td><?php print($record[3]) ?></td>\r
+ <td><?php print($record[3]); ?></td>\r
<td>\r
- <input type="hidden" name="oldlocaltrustlisttrust[]" value="<?php print($record[4]) ?>">\r
- <input type="text" name="newlocaltrustlisttrust[]" size="2" maxlength="3" value="<?php print($record[4]) ?>">\r
+ <input type="hidden" name="oldlocaltrustlisttrust[]" value="<?php print($record[4]); ?>">\r
+ <input type="text" name="newlocaltrustlisttrust[]" size="2" maxlength="3" value="<?php print($record[4]); ?>">\r
</td>\r
<td><?php print($record[5]) ?></td>\r
</tr>\r
\r
$db=new PDO('sqlite:'.$dblocation);\r
\r
- $st=$db->prepare("SELECT LocalIdentityID, Name FROM tblLocalIdentity ORDER BY Name;"); \r
+ $st=$db->prepare("SELECT LocalIdentityID, Name, PublicKey FROM tblLocalIdentity ORDER BY Name;"); \r
$st->execute();\r
\r
print "<select name=\"".$name."\">";\r
while($record=$st->fetch())\r
{\r
- print "<option value=\"".$record[0]."\">".$record[1]."</option>";\r
+ print "<option value=\"".$record[0]."\" title=\"".$record[2]."\">".$record[1]."</option>";\r
}\r
print "</select>";\r
}\r
\r
// only show latest captcha for each known identity\r
$lastid='';\r
- while($record=$st->fetch())\r
+ $shown=0;\r
+ while(($record=$st->fetch()) && $shown<30)\r
{\r
if($lastid!=$record[2])\r
{\r
print "<input type=\"hidden\" name=\"day[]\" value=\"".$record[1]."\">";\r
print "<input type=\"text\" name=\"solution[]\">";\r
print "<br>";\r
+ $shown++;\r
}\r
}\r
+ \r
+ if($shown>0)\r
+ {\r
?>\r
<input type="submit" value="Announce">\r
+ <?php\r
+ }\r
+ else\r
+ {\r
+ print "You must wait for some puzzles to be downloaded. Check back later.";\r
+ }\r
+ ?>\r
</form> \r
<?php \r
}\r
global $dblocation;\r
\r
$db=new PDO('sqlite:'.$dblocation);\r
- $st=$db->prepare("SELECT tblLocalIdentity.Name, COUNT(Inserted) FROM tblLocalIdentity LEFT JOIN tblIdentityIntroductionInserts ON tblLocalIdentity.LocalIdentityID=tblIdentityIntroductionInserts.LocalIdentityID WHERE (Inserted='true' OR Inserted IS NULL) GROUP BY tblLocalIdentity.LocalIdentityID;");\r
+ $st=$db->prepare("SELECT tblLocalIdentity.Name, COUNT(Inserted), tblLocalIdentity.PublicKey FROM tblLocalIdentity LEFT JOIN tblIdentityIntroductionInserts ON tblLocalIdentity.LocalIdentityID=tblIdentityIntroductionInserts.LocalIdentityID WHERE (Inserted='true' OR Inserted IS NULL) GROUP BY tblLocalIdentity.LocalIdentityID;");\r
$st->execute();\r
\r
?>\r
{\r
?>\r
<tr>\r
- <td>\r
+ <td title="<?php print $record[2]; ?>">\r
<?php print $record[0]; ?>\r
</td>\r
<td>\r
<li><a href="index.php">Home</a></li>\r
<li><a href="options.php">Options</a></li>\r
<li><a href="createidentity.php">Create Identity</a></li>\r
+ <li><a href="localidentities.php">Local Identities</a></li>\r
<li><a href="introduce.php">Introduce Identity</a></li>\r
<li><a href="introductionstatus.php">Introduction Status</a></li>\r
<li><a href="addpeeridentity.php">Manually Add Peer</a></li>\r
--- /dev/null
+<?php\r
+ \r
+ include_once('config.php');\r
+ include_once('linkbar.php');\r
+\r
+function truefalsedropdown($name,$currentval)\r
+{\r
+ ?>\r
+ <select name="<?php print($name); ?>">\r
+ <option value="true" <?php if($currentval=="true") print("SELECTED"); ?>>true</option>\r
+ <option value="false" <?php if($currentval=="false") print("SELECTED"); ?>>false</option>\r
+ </select>\r
+ <?php\r
+}\r
+\r
+function content()\r
+{\r
+ global $dblocation;\r
+ $db=new PDO('sqlite:'.$dblocation);\r
+ \r
+ if(isset($_REQUEST['formaction']))\r
+ {\r
+ if($_REQUEST['formaction']=='update' && isset($_REQUEST['update']))\r
+ {\r
+ $st=$db->prepare("UPDATE tblLocalIdentity SET SingleUse=?, PublishTrustList=? WHERE LocalIdentityID=?;");\r
+ for($i=0; $i<count($_REQUEST['update']); $i++)\r
+ {\r
+ if($_REQUEST['update'][$i]!='')\r
+ {\r
+ $st->bindParam(1,$_REQUEST['singleuse'][$_REQUEST['update'][$i]]);\r
+ $st->bindParam(2,$_REQUEST['publishtrustlist'][$_REQUEST['update'][$i]]);\r
+ $st->bindParam(3,$_REQUEST['localidentityid'][$_REQUEST['update'][$i]]);\r
+ $st->execute();\r
+ }\r
+ }\r
+ }\r
+ if($_REQUEST['formaction']=='delete' && isset($_REQUEST['update']))\r
+ {\r
+ $st=$db->prepare("DELETE FROM tblLocalIdentity WHERE LocalIdentityID=?;");\r
+\r
+ for($i=0; $i<count($_REQUEST['update']); $i++)\r
+ {\r
+ if($_REQUEST['update'][$i]!='')\r
+ {\r
+ $st->bindParam(1,$_REQUEST['localidentityid'][$_REQUEST['update'][$i]]);\r
+ $st->execute();\r
+ } \r
+ } \r
+ }\r
+ }\r
+ \r
+ $st=$db->prepare("SELECT LocalIdentityID,Name,PublicKey,PublishTrustList,SingleUse,PublishBoardList FROM tblLocalIdentity ORDER BY Name;");\r
+ $st->execute();\r
+ ?>\r
+ <h2>Local Identities</h2>\r
+ <form name="frmlocalidentity" method="post">\r
+ <input type="hidden" name="formaction" value="update">\r
+ <table>\r
+ <tr>\r
+ <td></td>\r
+ <th>Name</th>\r
+ <th>Single Use</th>\r
+ <th>Publish Trust List</th>\r
+ </tr>\r
+ <?php\r
+ $row=0;\r
+ while($record=$st->fetch())\r
+ {\r
+ ?>\r
+ <tr>\r
+ <td>\r
+ <input type="checkbox" name="update[]" value="<?php print($row); ?>">\r
+ </td>\r
+ <td title="<?php print($record[2]); ?>">\r
+ <input type="hidden" name="localidentityid[]" value="<?php print($record[0]); ?>">\r
+ <?php print($record[1]); ?>\r
+ </td>\r
+ <td>\r
+ <?php\r
+ truefalsedropdown("singleuse[]",$record[4]);\r
+ ?>\r
+ </td>\r
+ <td>\r
+ <?php\r
+ truefalsedropdown("publishtrustlist[]",$record[3]);\r
+ ?>\r
+ </td>\r
+ </tr>\r
+ <?php\r
+ $row++;\r
+ }\r
+ ?>\r
+ </table>\r
+ <input type="submit" value="Update Selected">\r
+ <input type="submit" value="Delete Selected" onClick="if(confirm('Delete Selected Identities?')){frmlocalidentity.formaction.value='delete';}else{return false;}">\r
+ </form>\r
+ <?php\r
+}\r
+\r
+ include_once('template.php');\r
+\r
+?>
\ No newline at end of file
#include <vector>\r
#include <zthread/Thread.h>\r
\r
-#define FMS_VERSION "0.1.1"\r
+#define FMS_VERSION "0.1.2"\r
\r
// opens database and creates tables and initial inserts if necessary\r
void SetupDB();\r
\r
#include <list>\r
#include <vector>\r
+#include <zthread/Thread.h>\r
#include <zthread/Task.h>\r
#include <zthread/ZThread.h>\r
#include <zthread/ThreadedExecutor.h>\r
\r
if(message.GetName()=="PutSuccessful")\r
{\r
- m_db->Execute("UPDATE tblLocalIdentity SET InsertingIdentity='false', LastInsertedIdentity='"+now.Format("%Y-%m-%d %H:%M:%S")+"' WHERE LocalIdentityID="+idparts[1]+";");\r
+ // a little hack here - if we just inserted index yesterday and it is now the next day - we would have inserted todays date not yesterdays as LastInsertedIdentity.\r
+ // If this is the case, we will skip updating LastInsertedIdentity so that we can insert this identity again for today\r
+ DateTime lastdate;\r
+ lastdate.Set(idparts[4]);\r
+ if(lastdate.GetDay()!=now.GetDay())\r
+ {\r
+ m_db->Execute("UPDATE tblLocalIdentity SET InsertingIdentity='false', LastInsertedIdentity='"+now.Format("%Y-%m-%d %H:%M:%S")+"' WHERE LocalIdentityID="+idparts[1]+";");\r
+ }\r
m_db->Execute("INSERT INTO tblLocalIdentityInserts(LocalIdentityID,Day,InsertIndex) VALUES("+idparts[1]+",'"+idparts[4]+"',"+idparts[2]+");");\r
m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IdentityInserter::HandleMessage inserted Identity xml");\r
return true;\r
st.Step();\r
}\r
st.Finalize();\r
+\r
+ m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IdentityIntroductionRequester::HandleAddData parsed a valid identity.");\r
}\r
else\r
{\r
- m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"IdentityIntroductionRequester::HandleAllData parsed public SSK key was not valid.");\r
+ m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"IdentityIntroductionRequester::HandleAllData parsed, public SSK key was not valid.");\r
}\r
\r
m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IdentityIntroductionRequester::HandleAllData parsed IdentityIntroduction XML file : "+message["Identifier"]);\r
\r
while(!rs.AtEnd())\r
{\r
+ std::string localidentityidstr;\r
DateTime now;\r
now.SetToGMTime();\r
\r
+ if(rs.GetField(0))\r
+ {\r
+ localidentityidstr=rs.GetField(0);\r
+ }\r
+\r
// if this identity has any non-solved puzzles for today, we don't need to insert a new puzzle\r
- SQLite3DB::Recordset rs2=m_db->Query("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE Day='"+now.Format("%Y-%m-%d")+"' AND FoundSolution='false';");\r
+ SQLite3DB::Recordset rs2=m_db->Query("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE Day='"+now.Format("%Y-%m-%d")+"' AND FoundSolution='false' AND LocalIdentityID="+localidentityidstr+";");\r
\r
// identity doesn't have any non-solved puzzles for today - start a new insert\r
if(rs2.Empty()==true)\r
\r
previous.Add(0,0,0,-m_daysbackward);\r
\r
- // query for identities that have messages in the past X days and we haven't inserted lists for in the past hour\r
+ // query for identities that have messages in the past X days and we haven't inserted lists for in the past 30 minutes\r
SQLite3DB::Statement st=m_db->Prepare("SELECT tblLocalIdentity.LocalIdentityID FROM tblLocalIdentity INNER JOIN tblMessageInserts ON tblLocalIdentity.LocalIdentityID=tblMessageInserts.LocalIdentityID WHERE tblMessageInserts.Day>=? AND (tblLocalIdentity.LastInsertedMessageList<=? OR tblLocalIdentity.LastInsertedMessageList IS NULL OR tblLocalIdentity.LastInsertedMessageList='');");\r
st.Bind(0,previous.Format("%Y-%m-%d"));\r
- st.Bind(1,(now-(1.0/24.0)).Format("%Y-%m-%d %H:%M:%S"));\r
+ st.Bind(1,(now-(1.0/48.0)).Format("%Y-%m-%d %H:%M:%S"));\r
st.Step();\r
\r
if(st.RowReturned())\r
st.Step();\r
st.Finalize();\r
\r
- m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"MessageListRequester::HandleAllData parsed TrustList XML file : "+message["Identifier"]);\r
+ m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"MessageListRequester::HandleAllData parsed MessageList XML file : "+message["Identifier"]);\r
}\r
else\r
{\r
std::string publickey;\r
int messagetrust;\r
int trustlisttrust;\r
- DateTime now;\r
+ DateTime now,date;\r
int index;\r
std::string indexstr;\r
std::string localidentityidstr;\r
\r
now.SetToGMTime();\r
- \r
- // build the xml file\r
- SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey, LocalMessageTrust, LocalTrustListTrust FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey<>'';");\r
+ date.SetToGMTime();\r
+\r
+ // build the xml file - we only want to add identities that we recently saw, otherwise we could be inserting a ton of identities\r
+ date.Add(0,0,0,-20); // identities seen in last 20 days\r
+ SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey, LocalMessageTrust, LocalTrustListTrust FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey<>'' AND LastSeen>=?;");\r
+ st.Bind(0,date.Format("%Y-%m-%d"));\r
st.Step();\r
while(st.RowReturned())\r
{\r
void SetupDB()\r
{\r
\r
+ DateTime date;\r
SQLite3DB::DB *db=SQLite3DB::DB::instance();\r
\r
db->Open("fms.db3");\r
GROUP BY TargetIdentityID;");\r
\r
// update PeerTrustLevel when deleting a record from tblPeerTrust\r
- db->Execute("CREATE TRIGGER trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \\r
+ db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteOntblPeerTrust AFTER DELETE ON tblPeerTrust \\r
FOR EACH ROW \\r
BEGIN \\r
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
END;");\r
\r
// update PeerTrustLevel when inserting a record into tblPeerTrust\r
- db->Execute("CREATE TRIGGER trgInsertOntblPeerTrust AFTER INSERT ON tblPeerTrust \\r
+ db->Execute("CREATE TRIGGER IF NOT EXISTS trgInsertOntblPeerTrust AFTER INSERT ON tblPeerTrust \\r
FOR EACH ROW \\r
BEGIN \\r
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
END;");\r
\r
// update PeerTrustLevel when updating a record in tblPeerTrust\r
- db->Execute("CREATE TRIGGER trgUpdateOntblPeerTrust AFTER UPDATE ON tblPeerTrust \\r
+ db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateOntblPeerTrust AFTER UPDATE ON tblPeerTrust \\r
FOR EACH ROW \\r
BEGIN \\r
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
END;");\r
\r
// 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
- db->Execute("CREATE TRIGGER trgUpdateLocalTrustLevels AFTER UPDATE OF LocalMessageTrust,LocalTrustListTrust ON tblIdentity \\r
+ db->Execute("CREATE TRIGGER IF NOT EXISTS trgUpdateLocalTrustLevels AFTER UPDATE OF LocalMessageTrust,LocalTrustListTrust ON tblIdentity \\r
FOR EACH ROW \\r
BEGIN \\r
UPDATE tblIdentity SET PeerMessageTrust=(SELECT PeerMessageTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID), PeerTrustListTrust=(SELECT PeerTrustListTrust FROM vwCalculatedPeerTrust WHERE TargetIdentityID=IdentityID);\\r
END;");\r
\r
+ db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteMessage AFTER DELETE ON tblMessage \\r
+ FOR EACH ROW \\r
+ BEGIN \\r
+ DELETE FROM tblMessageBoard WHERE tblMessageBoard.MessageID=old.MessageID;\\r
+ DELETE FROM tblMessageReplyTo WHERE tblMessageReplyTo.MessageID=old.MessageID;\\r
+ END;");\r
+\r
+ db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteIdentity AFTER DELETE ON tblIdentity \\r
+ FOR EACH ROW \\r
+ BEGIN \\r
+ DELETE FROM tblIdentityRequests WHERE IdentityID=old.IdentityID;\\r
+ DELETE FROM tblIntroductionPuzzleRequests WHERE IdentityID=old.IdentityID;\\r
+ DELETE FROM tblMessageListRequests WHERE IdentityID=old.IdentityID;\\r
+ DELETE FROM tblMessageRequests WHERE IdentityID=old.IdentityID;\\r
+ DELETE FROM tblPeerTrust WHERE IdentityID=old.IdentityID;\\r
+ DELETE FROM tblTrustListRequests WHERE IdentityID=old.IdentityID;\\r
+ END;");\r
+\r
+ db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteLocalIdentity AFTER DELETE ON tblLocalIdentity \\r
+ FOR EACH ROW \\r
+ BEGIN \\r
+ DELETE FROM tblIdentityIntroductionInserts WHERE LocalIdentityID=old.LocalIdentityID;\\r
+ DELETE FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID=old.LocalIdentityID;\\r
+ DELETE FROM tblLocalIdentityInserts WHERE LocalIdentityID=old.LocalIdentityID;\\r
+ DELETE FROM tblMessageInserts WHERE LocalIdentityID=old.LocalIdentityID;\\r
+ DELETE FROM tblMessageListInserts WHERE LocalIdentityID=old.LocalIdentityID;\\r
+ DELETE FROM tblTrustListInserts WHERE LocalIdentityID=old.LocalIdentityID;\\r
+ END;");\r
+\r
// delete introduction puzzles that were half-way inserted\r
db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day IS NULL AND InsertIndex IS NULL;");\r
\r
+ // delete stale introduction puzzles (2 or more days old)\r
+ date.SetToGMTime();\r
+ date.Add(0,0,0,-2);\r
+ db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
+ db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
+\r
}\r
\r
void SetupDefaultOptions()\r
\r
for(i=threads.begin(); i!=threads.end(); i++)\r
{\r
+ LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"ShutdownThreads waiting for thread to exit.");\r
(*i)->wait();\r
delete (*i);\r
}\r
}\r
else if(rval==-1)\r
{\r
+ std::string errnostr;\r
+ StringFunctions::Convert(GetSocketErrorNumber(),errnostr);\r
// error on receive - close the connection\r
Disconnect();\r
- m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketReceive recv returned -1 : "+GetSocketErrorMessage());\r
+ m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketReceive recv returned -1 : "+errnostr+" - "+GetSocketErrorMessage());\r
}\r
}\r
\r
}\r
else if(rval==-1)\r
{\r
- m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketSend returned -1 : "+GetSocketErrorMessage());\r
+ std::string errnostr;\r
+ StringFunctions::Convert(GetSocketErrorNumber(),errnostr);\r
+ m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketSend returned -1 : "+errnostr+" - "+GetSocketErrorMessage());\r
}\r
}\r
}\r
// see if any threads are still running - just calling interrupt without check would cause assert in debug mode\r
if(m_connections.wait(1)==false)\r
{\r
+ LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run interrupting connection threads and waiting 60 seconds for exit.");\r
try\r
{\r
m_connections.interrupt();\r
}\r
catch(...)\r
{\r
+ LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run caught unhandled exception.");\r
}\r
- m_connections.wait();\r
+ if(m_connections.wait(60)==false)\r
+ {\r
+ LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run connection threads did not exit after 60 seconds.");\r
+ }\r
+ }\r
+\r
+ for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
+ {\r
+ #ifdef _WIN32\r
+ closesocket((*listeni));\r
+ #else\r
+ close((*listeni));\r
+ #endif\r
}\r
+ m_listensockets.clear();\r
\r
}\r
\r