PROJECT(fms)\r
\r
+OPTION(USE_BUNDLED_SQLITE "Use the bundled SQLite3 library" OFF)\r
+\r
SET(FMS_SRC \r
src/base64.cpp\r
src/board.cpp\r
TARGET_LINK_LIBRARIES(fms socket)\r
ENDIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")\r
\r
-FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3 sqlite3_s)\r
+IF(NOT USE_BUNDLED_SQLITE)\r
+ FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3 sqlite3_s)\r
+ENDIF(NOT USE_BUNDLED_SQLITE)\r
FIND_LIBRARY(TINYXML_LIBRARY NAMES tinyxml tinyxml_s)\r
FIND_LIBRARY(PTHREADS_LIBRARY NAMES pthread pthreads pthreadvc2)\r
FIND_LIBRARY(SHTTPD_LIBRARY NAMES shttpd)\r
IF(SQLITE3_LIBRARY)\r
TARGET_LINK_LIBRARIES(fms ${SQLITE3_LIBRARY})\r
ELSE(SQLITE3_LIBRARY)\r
- MESSAGE(STATUS "Could not find system SQLite library. Will compile from included source.")\r
+ IF(NOT USE_BUNDLED_SQLITE)\r
+ MESSAGE(STATUS "Could not find system SQLite library. Will compile from included source.")\r
+ ENDIF(NOT USE_BUNDLED_SQLITE)\r
ADD_LIBRARY(sqlite3 libs/sqlite3/sqlite3.c)\r
TARGET_LINK_LIBRARIES(fms sqlite3)\r
INCLUDE_DIRECTORIES(libs/sqlite3)\r
DateTime m_check1hour;\r
DateTime m_check6hours;\r
DateTime m_check1day;\r
+\r
+ long m_deletemessagesolderthan;\r
\r
};\r
\r
//#include <zthread/Thread.h>\r
#include "pthreadwrapper/thread.h"\r
\r
-#define FMS_VERSION "0.1.15"\r
+#define FMS_VERSION "0.2.0"\r
\r
// opens database and creates tables and initial inserts if necessary\r
void SetupDB();\r
// opens logfile and sets it up\r
void SetupLogFile();\r
\r
+// TODO remove sometime after 0.1.17\r
+void FixCapitalBoardNames();\r
+\r
void SigHandler(int signum);\r
\r
void MainFunction();\r
std::vector<std::string> m_boards;\r
std::map<long,std::string> m_inreplyto;\r
long m_changemessagetrustonreply;\r
+ long m_minlocalmessagetrust;\r
+ long m_minlocaltrustlisttrust;\r
\r
};\r
\r
--- /dev/null
+COMPILING\r
+---------\r
+Compiling FMS requires CMake, and pthreads. Other required libraries are\r
+bundled with FMS.\r
+\r
+To compile, run these commands from the source directory:\r
+cmake .\r
+make\r
+\r
+If you want to use the bundled SQLite3 library, add a -D USE_BUNDLED_SQLITE=ON\r
+to the cmake command.\r
+\r
+UPGRADING\r
+---------\r
+It is always a good idea to make copies of your current FMS installation before\r
+continuing. First shut down FMS and then replace the binary and template.htm\r
+with those from the new version. You may keep the same database unless\r
+otherwise noted.\r
+\r
+INSTALLATION\r
+------------\r
+Place the binary and template.htm in a directory of your choice. On the first\r
+run, a database file will also be created in this directory. Make sure the\r
+user that runs FMS has read/write access to this directory.\r
+\r
+RUNNING\r
+-------\r
+You may run FMS in console mode by running the binary directly. If you are\r
+running *nix and would like to run as a daemon, use the -d argument. On\r
+Windows, -i will install FMS as a service, and -u will uninstall the service.\r
+\r
+EXITING\r
+-------\r
+To exist FMS running in console mode, press CTRL+C while at the console. You\r
+can also use the shutdown button on the web interface to close FMS. As a last\r
+resort, you may kill the process.\r
+\r
+WEB INTERFACE\r
+-------------\r
+By default, a web interface for administration will be running at http://\r
+localhost:8888. You can use the interface to configure and administer FMS.\r
+\r
+NNTP CONFIGURATION\r
+------------------\r
+By default, the NNTP server will listen on port 1119. Configure your\r
+newsreader to connect to the machine running FMS on this port. Use the web\r
+interface to create an identity and use the name of the identity as the\r
+username for the newsgroup account. The email address may be anything, as it\r
+is discarded when posting messages.\r
+\r
+Posting Messages\r
+----------------\r
+Use must set your newsreader to use UTF-8 when posting messages. Any non-text\r
+attachment to the message will be stripped. Text attachments will be inlined\r
+with the message body. Cross posting is fine, but remember that each identity\r
+can set a limit to the number of boards each message may be cross posted to.\r
+\r
+CONTROL BOARDS\r
+--------------\r
+Control boards are special boards that will add/remove trust from an identity.\r
+Create control boards in the web interface, and then reply to an identity's\r
+message to a control board to change the trust of the identity as per the\r
+settings for the board. You may cross post to a regular board and a control\r
+board with the same message. The control boards will be stripped from the\r
+message before inserting into Freenet.\r
+\r
+TRUST\r
+-----\r
+Trust is the most important element of FMS. It determines which identities you\r
+will download messages from and thus your overall experience. Do not give\r
+trust to arbitrary identities. Pick whom you trust wisely. There settings for\r
+minimum trust before downloading messages and trust lists can be changed on the\r
+web interface.\r
+\r
+A note on NULL trust: If you neither trust or distrust an identity, they will\r
+have NULL trust (no trust at all). You will download messages and trust lists\r
+from identities with NULL peer trust as long as the local trust level is above\r
+your configured minimum. You will also download messages from identities with\r
+NULL local message trust (the peer message trust must be NULL or > your\r
+configured minimum as well), but you will not download trust lists from\r
+identities with NULL local trust list trust.\r
}\r
}\r
\r
-const bool Board::Load(const std::string &boardname)\r
+const bool Board::Load(const std::string &boardname) // same as loading form boardid - but using name\r
{\r
+ /*\r
SQLite3DB::Statement st=m_db->Prepare("SELECT BoardID FROM tblBoard WHERE BoardName=?;");\r
st.Bind(0,boardname);\r
st.Step();\r
{\r
return false;\r
}\r
+ */\r
+\r
+ // clear current values\r
+ m_boardid=-1;\r
+ m_boardname="";\r
+ m_boarddescription="";\r
+ m_datecreated.Set(1970,1,1);\r
+ m_lowmessageid=0;\r
+ m_highmessageid=0;\r
+ m_messagecount=0;\r
+ int tempint=-1;\r
+\r
+ SQLite3DB::Statement st=m_db->Prepare("SELECT BoardName, BoardDescription, DateAdded, HighMessageID, LowMessageID, MessageCount, SaveReceivedMessages, tblBoard.BoardID FROM tblBoard LEFT JOIN vwBoardStats ON tblBoard.BoardID=vwBoardStats.BoardID WHERE tblBoard.BoardName=?;");\r
+ st.Bind(0,boardname);\r
+ st.Step();\r
+\r
+ if(st.RowReturned())\r
+ {\r
+ int tempint;\r
+ std::string tempstr;\r
+ std::vector<std::string> dateparts;\r
+\r
+ st.ResultText(0,m_boardname);\r
+ st.ResultText(1,m_boarddescription);\r
+ st.ResultText(2,tempstr);\r
+ st.ResultInt(7,tempint); // boardid\r
+ m_boardid=tempint;\r
+\r
+ SetDateFromString(tempstr);\r
+\r
+ tempint=0;\r
+ st.ResultInt(3,tempint);\r
+ m_highmessageid=tempint;\r
+ tempint=0;\r
+ st.ResultInt(4,tempint);\r
+ m_lowmessageid=tempint;\r
+ tempint=0;\r
+ st.ResultInt(5,tempint);\r
+ m_messagecount=tempint;\r
+ st.ResultText(6,tempstr);\r
+ if(tempstr=="true")\r
+ {\r
+ m_savereceivedmessages=true;\r
+ }\r
+ else\r
+ {\r
+ m_savereceivedmessages=false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+ else\r
+ {\r
+ return false;\r
+ }\r
+\r
}\r
\r
void Board::SetDateFromString(const std::string &datestring)\r
{\r
if(node2->FirstChild())\r
{\r
- boards.push_back(node2->FirstChild()->ValueStr());\r
+ std::string boardname=node2->FirstChild()->ValueStr();\r
+ StringFunctions::LowerCase(boardname,boardname);\r
+ boards.push_back(boardname);\r
}\r
node2=node2->NextSibling("Board");\r
}\r
\r
const long MessageRequester::GetBoardID(const std::string &boardname)\r
{\r
+ std::string lowerboard=boardname;\r
+ StringFunctions::LowerCase(lowerboard,lowerboard);\r
SQLite3DB::Statement st=m_db->Prepare("SELECT BoardID FROM tblBoard WHERE BoardName=?;");\r
- st.Bind(0,boardname);\r
+ st.Bind(0,lowerboard);\r
st.Step();\r
\r
if(st.RowReturned())\r
if(txt)\r
{\r
m_replyboard=txt->ValueStr();\r
+ StringFunctions::LowerCase(m_replyboard,m_replyboard);\r
}\r
txt=hnd.FirstChild("Message").FirstChild("Body").FirstChild().ToText();\r
if(txt)\r
#include "../../include/freenet/periodicdbmaintenance.h"\r
#include "../../include/stringfunctions.h"\r
+#include "../../include/option.h"\r
\r
#ifdef XMEM\r
#include <xmem.h>\r
\r
PeriodicDBMaintenance::PeriodicDBMaintenance()\r
{\r
+ std::string tempval;\r
+\r
m_check10mins.SetToGMTime();\r
m_check30mins.SetToGMTime();\r
m_check1hour.SetToGMTime();\r
m_check6hours.Add(0,-1,-5);\r
m_check1day.Add(0,0,-23);\r
\r
+ tempval="180";\r
+ Option::Instance()->Get("DeleteMessagesOlderThan",tempval);\r
+ StringFunctions::Convert(tempval,m_deletemessagesolderthan);\r
+\r
}\r
\r
void PeriodicDBMaintenance::Do10MinuteMaintenance()\r
st.Bind(0,date.Format("%Y-%m-%d %H:%M:%S"));\r
st.Step();\r
\r
+ // delete old messages\r
+ date.SetToGMTime();\r
+ date.Add(0,0,0,-m_deletemessagesolderthan);\r
+ st=m_db->Prepare("DELETE FROM tblMessage WHERE MessageDate<?;");\r
+ st.Bind(0,date.Format("%Y-%m-%d"));\r
+ st.Step();\r
+\r
}\r
\r
void PeriodicDBMaintenance::Process()\r
// insert garfield's public key\r
db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('SSK@T8l1IEGU4-PoASFzgc2GYhIgRzUvZsKdoQWeuLHuTmM,QLxAPfkGis8l5NafNpSCdbxzXhBlu9WL8svcqJw9Mpo,AQACAAE/','"+date.Format("%Y-%m-%d %H:%M:%S")+"');");\r
\r
+ // TODO remove sometime after 0.1.17\r
+ FixCapitalBoardNames();\r
+\r
}\r
\r
void ConvertDB0100To0101()\r
st.Step();\r
st.Reset();\r
\r
+ st.Bind(0,"DeleteMessagesOlderThan");\r
+ st.Bind(1,"180");\r
+ st.Bind(2,"Automatically delete messages older than this many days.");\r
+ st.Step();\r
+ st.Reset();\r
+\r
}\r
\r
void SetupLogFile()\r
\r
}\r
*/\r
+\r
+void FixCapitalBoardNames()\r
+{\r
+ SQLite3DB::DB *db=SQLite3DB::DB::Instance();\r
+\r
+ SQLite3DB::Statement st=db->Prepare("SELECT BoardID,BoardName FROM tblBoard WHERE BoardID NOT IN (SELECT BoardID FROM tblAdministrationBoard);");\r
+ SQLite3DB::Statement st2=db->Prepare("SELECT BoardID FROM tblBoard WHERE BoardName=?;");\r
+ SQLite3DB::Statement del=db->Prepare("DELTE FROM tblBoard WHERE BoardID=?;");\r
+ SQLite3DB::Statement upd=db->Prepare("UPDATE tblBoard SET BoardName=? WHERE BoardID=?;");\r
+ SQLite3DB::Statement upd2=db->Prepare("UPDATE tblMessage SET ReplyBoardID=? WHERE ReplyBoardID=?;");\r
+ SQLite3DB::Statement upd3=db->Prepare("UPDATE tblMessageBoard SET BoardID=? WHERE BoardID=?;");\r
+\r
+ st.Step();\r
+ while(st.RowReturned())\r
+ {\r
+ int boardid=0;\r
+ int newboardid=0;\r
+ std::string name="";\r
+ std::string lowername="";\r
+\r
+ st.ResultInt(0,boardid);\r
+ st.ResultText(1,name);\r
+\r
+ lowername=name;\r
+ StringFunctions::LowerCase(lowername,lowername);\r
+ \r
+ if(name!=lowername)\r
+ {\r
+ st2.Bind(0,lowername);\r
+ st2.Step();\r
+\r
+ if(st2.RowReturned())\r
+ {\r
+ st2.ResultInt(0,newboardid);\r
+\r
+ upd2.Bind(0,newboardid);\r
+ upd2.Bind(1,boardid);\r
+ upd2.Step();\r
+ upd2.Reset();\r
+\r
+ upd3.Bind(0,newboardid);\r
+ upd3.Bind(1,boardid);\r
+ upd3.Step();\r
+ upd3.Reset();\r
+\r
+ del.Bind(0,boardid);\r
+ del.Step();\r
+ del.Reset();\r
+ }\r
+ else\r
+ {\r
+ upd.Bind(0,lowername);\r
+ upd.Bind(1,boardid);\r
+ upd.Step();\r
+ upd.Reset();\r
+ }\r
+\r
+ st2.Reset();\r
+ }\r
+ \r
+ st.Step();\r
+ }\r
+\r
+}\r
content+="<input type=\"hidden\" name=\"formaction\" value=\"addboard\">";\r
content+="<input type=\"text\" name=\"boardname\">";\r
content+="</td>\r\n<td>";\r
- content+="<input type=\"text\" name=\"changemessagetrust\" size=\"2\" maxlength=\"3\">";\r
+ content+="<input type=\"text\" name=\"changemessagetrust\" size=\"2\" maxlength=\"4\">";\r
content+="</td>\r\n<td>";\r
- content+="<input type=\"text\" name=\"changetrustlisttrust\" size=\"2\" maxlength=\"3\">";\r
+ content+="<input type=\"text\" name=\"changetrustlisttrust\" size=\"2\" maxlength=\"4\">";\r
content+="</td>\r\n<td>";\r
content+="<input type=\"submit\" value=\"Add\">";\r
content+="</form>";\r
const std::string ExecQueryPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
{\r
std::string content="";\r
+ std::string query="";\r
\r
if(queryvars.find("formaction")!=queryvars.end() && (*queryvars.find("formaction")).second=="execute" && queryvars.find("query")!=queryvars.end() && (*queryvars.find("query")).second!="")\r
{\r
- SQLite3DB::Recordset rs=m_db->Query((*queryvars.find("query")).second);\r
+ query=(*queryvars.find("query")).second;\r
+ SQLite3DB::Recordset rs=m_db->Query(query);\r
\r
content+="<table>";\r
if(rs.Count()>0)\r
content+="<h2>Execute Query</h2>";\r
content+="<form name=\"frmquery\" method=\"POST\">";\r
content+="<input type=\"hidden\" name=\"formaction\" value=\"execute\">";\r
- content+="<textarea name=\"query\" rows=\"10\" cols=\"80\"></textarea>";\r
+ content+="<textarea name=\"query\" rows=\"10\" cols=\"80\">"+SanitizeOutput(query)+"</textarea>";\r
content+="<input type=\"submit\" value=\"Execute Query\">";\r
content+="</form>";\r
\r
content+="<form name=\"frmtrust\" method=\"POST\">";\r
content+="<input type=\"hidden\" name=\"formaction\" value=\"update\">";\r
content+="<input type=\"hidden\" name=\"startrow\" value=\""+startrowstr+"\">";\r
+ if(namesearch!="")\r
+ {\r
+ content+="<input type=\"hidden\" name=\"namesearch\" value=\""+SanitizeOutput(namesearch)+"\">";\r
+ }\r
content+="<table>";\r
content+="<tr><th><a href=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,"Name",ReverseSort("Name",sortby,sortorder))+"\">Name</a></th>";\r
content+="<th><a href=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,"LocalMessageTrust",ReverseSort("LocalMessageTrust",sortby,sortorder))+"\">Local Message Trust</a></th>";\r
}\r
else\r
{\r
- origmessagetrust=50;\r
+ origmessagetrust=m_minlocalmessagetrust;\r
}\r
if(origmess.ResultNull(3)==false)\r
{\r
}\r
else\r
{\r
- origtrustlisttrust=50;\r
+ origtrustlisttrust=m_minlocaltrustlisttrust;\r
}\r
\r
origmessagetrust+=changemessagetrust;\r
}\r
else\r
{\r
- localmessagetrust=50;\r
+ localmessagetrust=m_minlocalmessagetrust;\r
}\r
\r
localmessagetrust+=m_changemessagetrustonreply;\r
{\r
m_addnewpostfromidentities=false;\r
}\r
+ tempval="50";\r
+ Option::Instance()->Get("MinLocalMessageTrust",tempval);\r
+ StringFunctions::Convert(tempval,m_minlocalmessagetrust);\r
+ tempval="51";\r
+ Option::Instance()->Get("MinLocalTrustListTrust",tempval);\r
+ StringFunctions::Convert(tempval,m_minlocaltrustlisttrust);\r
}\r
\r
const bool Message::Load(const long messageid, const long boardid)\r